Compare commits

...

2 commits

4 changed files with 95 additions and 41 deletions

View file

@ -4,6 +4,8 @@
"": { "": {
"name": "packwizjs", "name": "packwizjs",
"dependencies": { "dependencies": {
"@types/semver": "^7.5.8",
"semver": "^7.7.1",
"toml": "^3.0.0", "toml": "^3.0.0",
}, },
"devDependencies": { "devDependencies": {
@ -53,6 +55,8 @@
"@types/node": ["@types/node@22.13.1", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="], "@types/node": ["@types/node@22.13.1", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="],
"@types/semver": ["@types/semver@7.5.8", "", {}, "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="],
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
"acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="],
@ -365,7 +369,7 @@
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
@ -443,18 +447,14 @@
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], "@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"builtins/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"eslint-compat-utils/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-plugin-n/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="], "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"eslint-plugin-n/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], "eslint-plugin-n/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="],
} }
} }

View file

@ -11,6 +11,8 @@
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
"dependencies": { "dependencies": {
"@types/semver": "^7.5.8",
"semver": "^7.7.1",
"toml": "^3.0.0" "toml": "^3.0.0"
} }
} }

View file

@ -10,6 +10,6 @@ export function isValidHashFormat(hashFormat: string): HashFormat {
if (hashFormat in HashFormat) { if (hashFormat in HashFormat) {
return HashFormat[hashFormat as keyof typeof HashFormat]; return HashFormat[hashFormat as keyof typeof HashFormat];
} else { } else {
throw new Error("Invalid index file hash format!"); throw new Error(`Invalid index file hash format: ${hashFormat}`);
} }
} }

View file

@ -8,6 +8,7 @@ import {
} from "./provider"; } from "./provider";
import { HashFormat, isValidHashFormat } from "./enums/hash-format"; import { HashFormat, isValidHashFormat } from "./enums/hash-format";
import { isValidSide, type Side } from "./enums/side"; import { isValidSide, type Side } from "./enums/side";
import * as semver from "semver";
export interface Metafile { export interface Metafile {
name: string; name: string;
@ -112,46 +113,97 @@ export class IndexFileEntry {
*/ */
export interface PackwizIndex { export interface PackwizIndex {
location: Resource; location: Resource;
hash: string;
hashFormat: HashFormat; hashFormat: HashFormat;
files: IndexFileEntry[]; files: IndexFileEntry[];
} }
// TODO: parse pack.toml too instead of just the index file export interface PackwizVersions {
// This is because pack.toml contains important information like modloader versions minecraft: string;
fabric?: string;
forge?: string;
neoforge?: string;
quilt?: string;
liteloader?: string;
}
export class Packwiz {
constructor(
readonly location: Resource,
readonly index: PackwizIndex,
readonly name: string,
readonly packFormat: string = "packwiz:1.0.0",
readonly authors: Array<string>,
readonly description: string,
readonly version: string,
readonly versions: PackwizVersions,
) {
const packwizJsMaxSupportedVersion = "1.1.0";
const packFormatSemver = semver.clean(packFormat.split(":")[1]);
if (!packFormat.startsWith("packwiz:")) {
throw new Error("Invalid packwiz pack format!");
} else if (!packFormatSemver) {
throw new Error("Unable to parse pack format!");
} else if (semver.gt(packFormatSemver, packwizJsMaxSupportedVersion)) {
throw new Error(
`Pack format of ${packFormat} is higher than what PackwizJS supports! Please report this upstream at https://www.coastalcommits.com/GalacticFactory/PackwizJS/issues`,
);
}
}
}
/** /**
* Parses a Packwiz index file and returns its contents. * Parses a packwiz.toml file and returns its contents.
* *
* @param indexFilePath - The path of the TOML file. * @param indexFilePath - The path of the TOML file.
* @returns The parsed index as a structured object. * @returns The parsed file as a structured class.
*/ */
export async function parsePackwizIndex( export async function parsePackwiz(filePath: string): Promise<Packwiz> {
indexFilePath: string, const packwizFile = new Resource(filePath);
): Promise<PackwizIndex> { const parsedPackwizFile = toml.parse(await packwizFile.fetchContents());
const indexFile = new Resource(indexFilePath);
const parsed = toml.parse(await indexFile.fetchContents()); const indexFile = packwizFile.parent.join(parsedPackwizFile.index.file);
const hashFormat = isValidHashFormat(parsed["hash-format"]); const parsedIndexFile = toml.parse(await indexFile.fetchContents());
return { const indexHashFormat = isValidHashFormat(parsedIndexFile["hash-format"]);
location: indexFile,
hashFormat: hashFormat, return new Packwiz(
files: parsed.files.map( packwizFile,
(file: { {
file: string; location: indexFile,
hash: string; hash: parsedPackwizFile.index.hash,
hashFormat: HashFormat; hashFormat: indexHashFormat,
alias?: string; files: parsedIndexFile.files.map(
metafile?: boolean; (file: {
preserve?: boolean; file: string;
}) => { hash: string;
return new IndexFileEntry( hashFormat: HashFormat;
indexFile.parent.join(file.file), alias?: string;
file.hash, metafile?: boolean;
file.hashFormat || hashFormat, preserve?: boolean;
file.alias, }) => {
file.metafile ?? false, return new IndexFileEntry(
file.preserve ?? false, packwizFile.parent.join(file.file),
); file.hash,
}, file.hashFormat ?? indexHashFormat,
), file.alias,
}; file.metafile ?? false,
file.preserve ?? false,
);
},
),
},
parsedPackwizFile.name,
parsedPackwizFile["pack-format"],
parsedPackwizFile.author?.split(",").map((s: string) => s.trim()),
parsedPackwizFile.description,
parsedPackwizFile.version,
{
minecraft: parsedPackwizFile.versions.minecraft,
fabric: parsedPackwizFile.versions.fabric,
forge: parsedPackwizFile.versions.forge,
neoforge: parsedPackwizFile.versions.neoforge,
quilt: parsedPackwizFile.versions.quilt,
liteloader: parsedPackwizFile.versions.liteloader,
},
);
} }