mirror of
https://github.com/Kir-Antipov/mc-publish.git
synced 2024-11-25 09:51:01 -05:00
Implemented logic to work with Quilt dependencies
This commit is contained in:
parent
258fcd856c
commit
0fec2613dd
2 changed files with 250 additions and 0 deletions
177
src/loaders/quilt/quilt-dependency.ts
Normal file
177
src/loaders/quilt/quilt-dependency.ts
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
import { ACTION_NAME } from "@/action";
|
||||||
|
import { Dependency, DependencyType, createDependency } from "@/dependencies";
|
||||||
|
import { PlatformType } from "@/platforms";
|
||||||
|
import { $i } from "@/utils/collections";
|
||||||
|
import { asString } from "@/utils/string-utils";
|
||||||
|
import { PartialRecord } from "@/utils/types";
|
||||||
|
import { RawQuiltMetadata } from "./raw-quilt-metadata";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single dependency for a Quilt mod project.
|
||||||
|
*/
|
||||||
|
export interface QuiltDependency {
|
||||||
|
/**
|
||||||
|
* A mod identifier in the form of either `mavenGroup:modId` or `modId`.
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of the dependency.
|
||||||
|
*/
|
||||||
|
version?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version range for the dependency.
|
||||||
|
*
|
||||||
|
* Can be a single version or an array of version ranges.
|
||||||
|
*/
|
||||||
|
versions?: string | string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short, human-readable reason for the dependency object to exist.
|
||||||
|
*/
|
||||||
|
reason?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependencies marked as `optional` will only be checked if the mod/plugin specified by the `id` field is present.
|
||||||
|
*/
|
||||||
|
optional?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this dependency is embedded into the mod.
|
||||||
|
*
|
||||||
|
* @custom
|
||||||
|
*/
|
||||||
|
provided?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this dependency is incompatible with the mod.
|
||||||
|
*
|
||||||
|
* @custom
|
||||||
|
*/
|
||||||
|
breaking?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes situations where this dependency can be ignored.
|
||||||
|
*/
|
||||||
|
unless?: string | QuiltDependency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom action payload.
|
||||||
|
*
|
||||||
|
* @custom
|
||||||
|
*/
|
||||||
|
[ACTION_NAME]?: QuiltDependencyCustomPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom payload attached to a Quilt dependency.
|
||||||
|
*/
|
||||||
|
type QuiltDependencyCustomPayload = {
|
||||||
|
/**
|
||||||
|
* Indicates whether the dependency should be ignored globally,
|
||||||
|
* or by the platforms specified in the given array.
|
||||||
|
*/
|
||||||
|
ignore?: boolean | PlatformType[];
|
||||||
|
} & PartialRecord<PlatformType, string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of special dependencies that should be ignored.
|
||||||
|
*/
|
||||||
|
const IGNORED_DEPENDENCIES: readonly string[] = [
|
||||||
|
"minecraft",
|
||||||
|
"java",
|
||||||
|
"quilt_loader",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of aliases for special dependencies for different platforms.
|
||||||
|
*/
|
||||||
|
const DEPENDENCY_ALIASES: ReadonlyMap<string, ReadonlyMap<PlatformType, string>> = $i([
|
||||||
|
["fabric", "fabric-api"],
|
||||||
|
["quilt_base", "qsl"],
|
||||||
|
["quilted_fabric_api", "qsl"],
|
||||||
|
].map(([k, v]) =>
|
||||||
|
[k, typeof v === "string" ? $i(PlatformType.values()).map(x => [x, v] as const).toMap() : v] as const,
|
||||||
|
)).toMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Quilt dependencies from the metadata.
|
||||||
|
*
|
||||||
|
* @param metadata - The raw Quilt metadata.
|
||||||
|
*
|
||||||
|
* @returns An array of Quilt dependencies.
|
||||||
|
*/
|
||||||
|
export function getQuiltDependencies(metadata: RawQuiltMetadata): QuiltDependency[] {
|
||||||
|
const dependencyMap = $i(mapQuiltDependencies(metadata?.quilt_loader?.depends))
|
||||||
|
.concat(mapQuiltDependencies(metadata?.quilt_loader?.breaks, { breaking: true }))
|
||||||
|
.concat(mapQuiltDependencies(metadata?.quilt_loader?.provides, { provided: true }))
|
||||||
|
.filter(x => x.id)
|
||||||
|
.map(x => [x.id, x] as const)
|
||||||
|
.toMap();
|
||||||
|
|
||||||
|
return [...dependencyMap.values()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a dependency field presented in raw Quilt metadata into the array of Quilt dependencies.
|
||||||
|
*
|
||||||
|
* @param dependencies - The dependency field to be mapped.
|
||||||
|
* @param customFields - Custom fields to attach to the dependencies.
|
||||||
|
*
|
||||||
|
* @returns The array of Quilt dependencies represented by the given field.
|
||||||
|
*/
|
||||||
|
function mapQuiltDependencies(dependencies: (string | QuiltDependency)[], customFields?: Partial<QuiltDependency>): Iterable<QuiltDependency> {
|
||||||
|
if (!dependencies) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $i(dependencies).map(x => typeof x === "string" ? { id: x, ...customFields } : { ...x, ...customFields });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts {@link QuiltDependency} to a {@link Dependency} object.
|
||||||
|
*
|
||||||
|
* @returns A Dependency object representing the given Quilt dependency.
|
||||||
|
*/
|
||||||
|
export function normalizeQuiltDependency(dependency: QuiltDependency): Dependency {
|
||||||
|
const payload = getQuiltDependencyCustomPayload(dependency);
|
||||||
|
|
||||||
|
const id = dependency?.id?.includes(":") ? dependency.id.substring(dependency.id.indexOf(":") + 1) : dependency?.id;
|
||||||
|
const versions = dependency?.version || dependency?.versions;
|
||||||
|
const ignore = IGNORED_DEPENDENCIES.includes(id) || typeof payload.ignore === "boolean" && payload.ignore;
|
||||||
|
const ignoredPlatforms = typeof payload.ignore === "boolean" ? undefined : payload.ignore;
|
||||||
|
const type = (
|
||||||
|
dependency?.breaking && dependency?.unless && DependencyType.CONFLICTING ||
|
||||||
|
dependency?.breaking && DependencyType.INCOMPATIBLE ||
|
||||||
|
dependency?.provided && DependencyType.EMBEDDED ||
|
||||||
|
(dependency?.optional || dependency?.unless) && DependencyType.OPTIONAL ||
|
||||||
|
DependencyType.REQUIRED
|
||||||
|
);
|
||||||
|
const aliases = $i(DEPENDENCY_ALIASES.get(id) as Iterable<readonly [PlatformType, string]> || [])
|
||||||
|
.concat(
|
||||||
|
$i(PlatformType.values()).map(type => [type, payload[type] ? asString(payload[type]) : undefined] as const)
|
||||||
|
)
|
||||||
|
.filter(([, id]) => id)
|
||||||
|
.toMap();
|
||||||
|
|
||||||
|
return createDependency({
|
||||||
|
id,
|
||||||
|
versions,
|
||||||
|
type,
|
||||||
|
ignore,
|
||||||
|
ignoredPlatforms,
|
||||||
|
aliases,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the custom payload from the Quilt dependency.
|
||||||
|
*
|
||||||
|
* @param dependency - The Quilt dependency.
|
||||||
|
*
|
||||||
|
* @returns The custom payload object.
|
||||||
|
*/
|
||||||
|
function getQuiltDependencyCustomPayload(dependency: QuiltDependency): QuiltDependencyCustomPayload {
|
||||||
|
return dependency?.[ACTION_NAME] || {};
|
||||||
|
}
|
73
tests/unit/loaders/quilt/quilt-dependency.spec.ts
Normal file
73
tests/unit/loaders/quilt/quilt-dependency.spec.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import { DependencyType } from "@/dependencies/dependency-type";
|
||||||
|
import { RawQuiltMetadata } from "@/loaders/quilt/raw-quilt-metadata";
|
||||||
|
import { getQuiltDependencies, normalizeQuiltDependency } from "@/loaders/quilt/quilt-dependency";
|
||||||
|
|
||||||
|
describe("getQuiltDependencies", () => {
|
||||||
|
test("returns an array of dependencies specified in the given metadata", () => {
|
||||||
|
const metadata = {
|
||||||
|
quilt_loader: {
|
||||||
|
depends: [
|
||||||
|
{
|
||||||
|
id: "depends-id",
|
||||||
|
versions: "1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "suggests-id",
|
||||||
|
versions: "3.0.0",
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
breaks: [
|
||||||
|
{
|
||||||
|
id: "breaks-id",
|
||||||
|
versions: ["4.0.0", "5.0.0"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "conflicts-id-1",
|
||||||
|
versions: "6.0.0",
|
||||||
|
unless: "fixes-conflicts-id-1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "conflicts-id-2",
|
||||||
|
versions: "7.0.0",
|
||||||
|
unless: "fixes-conflicts-id-2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
} as RawQuiltMetadata;
|
||||||
|
|
||||||
|
const dependencies = getQuiltDependencies(metadata);
|
||||||
|
|
||||||
|
expect(dependencies).toEqual([
|
||||||
|
{ id: "depends-id", versions: "1.0.0" },
|
||||||
|
{ id: "suggests-id", versions: "3.0.0", optional: true },
|
||||||
|
{ id: "breaks-id", versions: ["4.0.0", "5.0.0"], breaking: true },
|
||||||
|
{ id: "conflicts-id-1", versions: "6.0.0", breaking: true, unless: "fixes-conflicts-id-1" },
|
||||||
|
{ id: "conflicts-id-2", versions: "7.0.0", breaking: true, unless: "fixes-conflicts-id-2" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns an empty array if no dependencies were specified", () => {
|
||||||
|
expect(getQuiltDependencies({} as RawQuiltMetadata)).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns an empty array if metadata was null or undefined", () => {
|
||||||
|
expect(getQuiltDependencies(null)).toEqual([]);
|
||||||
|
expect(getQuiltDependencies(undefined)).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("normalizeQuiltDependency", () => {
|
||||||
|
test("converts Quilt dependency to a more abstract Dependency object", () => {
|
||||||
|
const quiltDependency = { id: "suggested:suggests-id", versions: "2.0.0", optional: true };
|
||||||
|
|
||||||
|
const dependency = normalizeQuiltDependency(quiltDependency);
|
||||||
|
|
||||||
|
expect(dependency).toMatchObject({ id: "suggests-id", versions: ["2.0.0"], type: DependencyType.OPTIONAL });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("returns undefined if dependency was null or undefined", () => {
|
||||||
|
expect(normalizeQuiltDependency(null)).toBeUndefined();
|
||||||
|
expect(normalizeQuiltDependency(undefined)).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue