diff --git a/README.md b/README.md index 084bdf0..ec3061b 100644 --- a/README.md +++ b/README.md @@ -193,21 +193,9 @@ Can be automatically retrieved from the config file of your mod: - `mods.toml` (Forge) - - Custom `mc-publish` field *(recommended)*: + - Custom `mc-publish` field: ```toml - [custom.mc-publish] - modrinth="AANobbMI" - ``` - - - Custom `projects` field: - ```toml - [custom.projects] - modrinth="AANobbMI" - ``` - - - `projects` field: - ```toml - [projects] + [mc-publish] modrinth="AANobbMI" ``` @@ -311,21 +299,9 @@ Can be automatically retrieved from the config file of your mod: - `mods.toml` (Forge) - - Custom `mc-publish` field *(recommended)*: + - Custom `mc-publish` field: ```toml - [custom.mc-publish] - curseforge=394468 - ``` - - - Custom `projects` field: - ```toml - [custom.projects] - curseforge=394468 - ``` - - - `projects` field: - ```toml - [projects] + [mc-publish] curseforge=394468 ``` @@ -617,7 +593,7 @@ Can be automatically retrieved from the config file of your mod: versionRange="0.3.0" ordering="NONE" side="BOTH" - [dependencies.mod-id.custom.mc-publish] + [dependencies.mod-id.mc-publish] ignore=false # `mc-publish` will ignore this dependency, if `ignore` is set to true modrinth="included-dependency-forge" # Modrinth's project slug curseforge="included-dependency-forge" # CurseForge's project slug diff --git a/src/metadata/forge/forge-mod-config.ts b/src/metadata/forge/forge-mod-config.ts new file mode 100644 index 0000000..3608d46 --- /dev/null +++ b/src/metadata/forge/forge-mod-config.ts @@ -0,0 +1,44 @@ +// https://forge.gemwire.uk/wiki/Mods.toml +type ForgeModConfig = { + // Non-Mod-Specific Properties + modLoader: string; + loaderVersion: string; + license: string; + showAsResourcePack?: boolean; + properties?: Record; + issueTrackerURL?: string; + + // Mod Properties + mods: { + modId: string; + namespace?: string; + version?: string; + displayName?: string; + description?: string; + logoFile?: string; + logoBlur?: boolean; + updateJSONURL?: string; + modproperties?: Record; + credits?: string; + authors?: string; + displayURL?: string; + displayTest?: "MATCH_VERSION" | "IGNORE_SERVER_VERSION" | "IGNORE_ALL_VERSION" | "NONE"; + }[]; + + // Dependency Configurations + dependencies?: Record)[]>; +} & Record; + +namespace ForgeModConfig { + export const FILENAME = "META-INF/mods.toml"; +} + +export default ForgeModConfig; diff --git a/src/metadata/forge/forge-mod-metadata-reader.ts b/src/metadata/forge/forge-mod-metadata-reader.ts index d4af1c7..cf3f751 100644 --- a/src/metadata/forge/forge-mod-metadata-reader.ts +++ b/src/metadata/forge/forge-mod-metadata-reader.ts @@ -1,18 +1,21 @@ -import ModMetadata from "../../metadata/mod-metadata"; +import ModMetadata from "../mod-metadata"; import toml from "toml"; -import ZippedModMetadataReader from "../../metadata/zipped-mod-metadata-reader"; +import ZippedModMetadataReader from "../zipped-mod-metadata-reader"; import ForgeModMetadata from "./forge-mod-metadata"; +import ForgeModConfig from "./forge-mod-config"; -export default class ForgeModMetadataReader extends ZippedModMetadataReader { +class ForgeModMetadataReader extends ZippedModMetadataReader { constructor() { - super("META-INF/mods.toml"); + super(ForgeModConfig.FILENAME); } - protected loadConfig(buffer: Buffer): Record { + protected loadConfig(buffer: Buffer): ForgeModConfig { return toml.parse(buffer.toString("utf8")); } - protected createMetadataFromConfig(config: Record): ModMetadata { + protected createMetadataFromConfig(config: ForgeModConfig): ModMetadata { return new ForgeModMetadata(config); } } + +export default ForgeModMetadataReader; diff --git a/src/metadata/forge/forge-mod-metadata.ts b/src/metadata/forge/forge-mod-metadata.ts index 23ed705..3791b62 100644 --- a/src/metadata/forge/forge-mod-metadata.ts +++ b/src/metadata/forge/forge-mod-metadata.ts @@ -1,29 +1,74 @@ -import ModConfig from "../../metadata/mod-config"; -import ModConfigDependency from "../../metadata/mod-config-dependency"; -import Dependency from "../../metadata/dependency"; -import DependencyKind from "../../metadata/dependency-kind"; +import action from "../../../package.json"; +import Dependency from "../dependency"; +import DependencyKind from "../dependency-kind"; +import ForgeModConfig from "./forge-mod-config"; +import ModMetadata from "../mod-metadata"; +import PublisherTarget from "../../publishing/publisher-target"; -const ignoredByDefault = ["minecraft", "java", "forge"]; -function createDependency(body: any): Dependency { - return new ModConfigDependency({ - ignore: ignoredByDefault.includes(body.modId), - ...body, - id: body.modId, - version: body.versionRange, - kind: body.incompatible && DependencyKind.Breaks || body.embedded && DependencyKind.Includes || body.mandatory && DependencyKind.Depends || DependencyKind.Recommends - }); +type ForgeDependency = ForgeModConfig["dependencies"][string][number]; + +function getDependencies(config: ForgeModConfig): Dependency[] { + return Object + .values(config.dependencies || {}) + .filter(x => Array.isArray(x)) + .flatMap(x => x) + .map(parseDependency) + .filter((x, i, self) => self.findIndex(y => x.id === y.id && x.kind === y.kind) === i); } -export default class ForgeModMetadata extends ModConfig { - public readonly id: string; - public readonly name: string; - public readonly version: string; - public readonly loaders: string[]; - public readonly dependencies: Dependency[]; +function parseDependency(body: ForgeDependency): Dependency { + const id = body.modId; + const kind = body.incompatible && DependencyKind.Breaks || body.embedded && DependencyKind.Includes || body.mandatory && DependencyKind.Depends || DependencyKind.Recommends; + const version = body.versionRange; + const ignore = body[action.name]?.ignore ?? body.custom?.[action.name]?.ignore ?? body.ignore ?? isDependencyIgnoredByDefault(id); + const aliases = new Map(); + for (const target of PublisherTarget.getValues()) { + const targetName = PublisherTarget.toString(target).toLowerCase(); + const alias = body[action.name]?.[targetName] ?? body.custom?.[action.name]?.[targetName]; + if (alias) { + aliases.set(target, String(alias)); + } + } - constructor(config: Record) { - super(config); - const mods = Array.isArray(this.config.mods) && this.config.mods || []; + return Dependency.create({ id, kind, version, ignore, aliases }); +} + +const ignoredByDefault = [ + "minecraft", + "java", + "forge", +]; +function isDependencyIgnoredByDefault(id: string): boolean { + return ignoredByDefault.includes(id); +} + +function getProjects(config: ForgeModConfig): Map { + const projects = new Map(); + for (const target of PublisherTarget.getValues()) { + const targetName = PublisherTarget.toString(target).toLowerCase(); + const projectId = config[action.name]?.[targetName] + ?? config.custom?.[action.name]?.[targetName] + ?? config.projects?.[targetName] + ?? config.custom?.projects?.[targetName]; + + if (projectId) { + projects.set(target, String(projectId)); + } + } + return projects; +} + +class ForgeModMetadata implements ModMetadata { + readonly id: string; + readonly name: string; + readonly version: string; + readonly loaders: string[]; + readonly dependencies: Dependency[]; + + private readonly _projects: Map; + + constructor(config: ForgeModConfig) { + const mods = Array.isArray(config.mods) && config.mods || []; const mod = mods[0]; if (!mod) { throw new Error("At least one mod should be specified"); @@ -33,11 +78,14 @@ export default class ForgeModMetadata extends ModConfig { this.name = mod.displayName || this.id; this.version = mod.version || "*"; this.loaders = ["forge"]; - this.dependencies = Object - .values(this.config.dependencies || {}) - .filter(Array.isArray) - .flatMap(x => x) - .map(createDependency) - .filter((x, i, self) => self.findIndex(y => x.id === y.id && x.kind === y.kind) === i); + this.dependencies = getDependencies(config); + + this._projects = getProjects(config); + } + + getProjectId(project: PublisherTarget): string | undefined { + return this._projects.get(project); } } + +export default ForgeModMetadata; diff --git a/test/content/forge/mods.toml b/test/content/forge/mods.toml index 124c7ae..01c3140 100644 --- a/test/content/forge/mods.toml +++ b/test/content/forge/mods.toml @@ -13,7 +13,7 @@ license="MIT" Example mod ''' -[projects] +[mc-publish] modrinth="AANobbMI" [custom.projects] curseforge=394468 @@ -46,13 +46,12 @@ license="MIT" versionRange="0.2.0" ordering="NONE" side="BOTH" - [dependencies.example-mod.projects] + [dependencies.example-mod.mc-publish] modrinth="AAAA" - [dependencies.example-mod.custom.projects] curseforge=42 + ignore=true [dependencies.example-mod.custom.mc-publish] github="v0.2.0" - ignore=true [[dependencies.example-mod]]