From 03306d8dc85c9ac4f1e48e4c6003b087a09ba5b0 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 15:38:55 -0500 Subject: [PATCH 001/110] nevermind maybe? --- eslint.config.js | 7 -- package-lock.json | 210 ---------------------------------------------- package.json | 1 - 3 files changed, 218 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 4e750d6..c072828 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,5 +1,4 @@ import js from "@eslint/js"; -import jsdoc from "eslint-plugin-jsdoc"; import globals from "globals"; import {defineConfig} from "eslint/config"; @@ -9,11 +8,5 @@ export default defineConfig([ plugins: {js}, extends: ["js/recommended"], languageOptions: {globals: globals.node}, - ignores: ["dist/**/*.js", "coverage/**/*.js", "node_modules/**/*.js", "docs/**/*"], - }, - { - files: ["**/*.{js,mjs,cjs}"], - ...jsdoc.configs["flat/recommended"], - ignores: ["dist/**/*.js", "coverage/**/*.js", "node_modules/**/*.js", "docs/**/*"], }, ]); diff --git a/package-lock.json b/package-lock.json index 48f469c..99d3710 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,6 @@ "@eslint/js": "^10.0.1", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", - "eslint-plugin-jsdoc": "^62.7.1", "globals": "^17.3.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", @@ -91,33 +90,6 @@ "node": ">=18" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.84.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.84.0.tgz", - "integrity": "sha512-0xew1CxOam0gV5OMjh2KjFQZsKL2bByX1+q4j3E73MpYIdyUxcZb/xQct9ccUb+ve5KGUYbCUxyPnYB7RbuP+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.8", - "@typescript-eslint/types": "^8.54.0", - "comment-parser": "1.4.5", - "esquery": "^1.7.0", - "jsdoc-type-pratt-parser": "~7.1.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@es-joy/resolve.exports": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@es-joy/resolve.exports/-/resolve.exports-1.2.0.tgz", - "integrity": "sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", @@ -1233,19 +1205,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@sindresorhus/base62": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/base62/-/base62-1.0.0.tgz", - "integrity": "sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -1309,20 +1268,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@vitest/coverage-v8": { "version": "4.0.18", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", @@ -1505,16 +1450,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1587,16 +1522,6 @@ "node": ">=20" } }, - "node_modules/comment-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.5.tgz", - "integrity": "sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -1785,35 +1710,6 @@ } } }, - "node_modules/eslint-plugin-jsdoc": { - "version": "62.7.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.7.1.tgz", - "integrity": "sha512-4Zvx99Q7d1uggYBUX/AIjvoyqXhluGbbKrRmG8SQTLprPFg6fa293tVJH1o1GQwNe3lUydd8ZHzn37OaSncgSQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@es-joy/jsdoccomment": "~0.84.0", - "@es-joy/resolve.exports": "1.2.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.5", - "debug": "^4.4.3", - "escape-string-regexp": "^4.0.0", - "espree": "^11.1.0", - "esquery": "^1.7.0", - "html-entities": "^2.6.0", - "object-deep-merge": "^2.0.0", - "parse-imports-exports": "^0.2.4", - "semver": "^7.7.4", - "spdx-expression-parse": "^4.0.0", - "to-valid-identifier": "^1.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" - } - }, "node_modules/eslint-scope": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.0.tgz", @@ -2135,23 +2031,6 @@ "node": ">=8" } }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -2285,16 +2164,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.1.1.tgz", - "integrity": "sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -2514,13 +2383,6 @@ "dev": true, "license": "MIT" }, - "node_modules/object-deep-merge": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.0.tgz", - "integrity": "sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==", - "dev": true, - "license": "MIT" - }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -2582,23 +2444,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parse-statements": "1.0.11" - } - }, - "node_modules/parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true, - "license": "MIT" - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2741,19 +2586,6 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/reserved-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz", - "integrity": "sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", @@ -2874,31 +2706,6 @@ "node": ">=0.10.0" } }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -2980,23 +2787,6 @@ "node": ">=14.0.0" } }, - "node_modules/to-valid-identifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-valid-identifier/-/to-valid-identifier-1.0.0.tgz", - "integrity": "sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/base62": "^1.0.0", - "reserved-identifiers": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 42ef4b6..9cf4220 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@eslint/js": "^10.0.1", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", - "eslint-plugin-jsdoc": "^62.7.1", "globals": "^17.3.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", From 38b7ff555c11ae8587ebacb3bbf809fbb9868011 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 15:41:39 -0500 Subject: [PATCH 002/110] add typescript support refs #21 --- package-lock.json | 20 ++++++++++++++++++- package.json | 2 ++ tsconfig.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 99d3710..aa65099 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,13 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@types/node": "^25.3.3", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", + "typescript": "^5.9.3", "unzipper": "^0.12.3", "vitest": "^4.0.16" }, @@ -1261,6 +1263,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "25.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", + "integrity": "sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -2843,7 +2855,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2859,6 +2870,13 @@ "dev": true, "license": "MIT" }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/package.json b/package.json index 9cf4220..ddb1441 100644 --- a/package.json +++ b/package.json @@ -45,11 +45,13 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@types/node": "^25.3.3", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", + "typescript": "^5.9.3", "unzipper": "^0.12.3", "vitest": "^4.0.16" } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..55bb838 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,49 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./build", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "nodenext", + "target": "esnext", + "allowJs": true, + "checkJs": true, + //"types": [], + // For nodejs: + "lib": ["esnext"], + "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + }, + "include": [ + "src/**/*.js" + ] +} From 1ed83ecab0fb94abe13c58a8c54266ad93f28418 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 15:43:05 -0500 Subject: [PATCH 003/110] update source files to typescript files --- src/{cli.js => cli.ts} | 0 src/config/{api.js => api.ts} | 0 src/config/{constants.js => constants.ts} | 0 src/config/{defaults.js => defaults.ts} | 0 src/config/{files.js => files.ts} | 0 src/config/{index.js => index.ts} | 0 src/config/{options.js => options.ts} | 0 src/config/{strings.js => strings.ts} | 0 src/config/{types.js => types.ts} | 0 src/{directory_scanning.js => directory_scanning.ts} | 0 src/{generate_gitignore.js => generate_gitignore.ts} | 0 src/{generate_json.js => generate_json.ts} | 0 src/{generate_license.js => generate_license.ts} | 0 src/{generate_lockfile.js => generate_lockfile.ts} | 0 src/{generate_readme.js => generate_readme.ts} | 0 src/{github_interactions.js => github_interactions.ts} | 0 src/{logger.js => logger.ts} | 0 src/{modpack-lock.js => modpack-lock.ts} | 0 src/{modpack_info.js => modpack_info.ts} | 0 src/{modrinth_interactions.js => modrinth_interactions.ts} | 0 tsconfig.json | 2 +- 21 files changed, 1 insertion(+), 1 deletion(-) rename src/{cli.js => cli.ts} (100%) rename src/config/{api.js => api.ts} (100%) rename src/config/{constants.js => constants.ts} (100%) rename src/config/{defaults.js => defaults.ts} (100%) rename src/config/{files.js => files.ts} (100%) rename src/config/{index.js => index.ts} (100%) rename src/config/{options.js => options.ts} (100%) rename src/config/{strings.js => strings.ts} (100%) rename src/config/{types.js => types.ts} (100%) rename src/{directory_scanning.js => directory_scanning.ts} (100%) rename src/{generate_gitignore.js => generate_gitignore.ts} (100%) rename src/{generate_json.js => generate_json.ts} (100%) rename src/{generate_license.js => generate_license.ts} (100%) rename src/{generate_lockfile.js => generate_lockfile.ts} (100%) rename src/{generate_readme.js => generate_readme.ts} (100%) rename src/{github_interactions.js => github_interactions.ts} (100%) rename src/{logger.js => logger.ts} (100%) rename src/{modpack-lock.js => modpack-lock.ts} (100%) rename src/{modpack_info.js => modpack_info.ts} (100%) rename src/{modrinth_interactions.js => modrinth_interactions.ts} (100%) diff --git a/src/cli.js b/src/cli.ts similarity index 100% rename from src/cli.js rename to src/cli.ts diff --git a/src/config/api.js b/src/config/api.ts similarity index 100% rename from src/config/api.js rename to src/config/api.ts diff --git a/src/config/constants.js b/src/config/constants.ts similarity index 100% rename from src/config/constants.js rename to src/config/constants.ts diff --git a/src/config/defaults.js b/src/config/defaults.ts similarity index 100% rename from src/config/defaults.js rename to src/config/defaults.ts diff --git a/src/config/files.js b/src/config/files.ts similarity index 100% rename from src/config/files.js rename to src/config/files.ts diff --git a/src/config/index.js b/src/config/index.ts similarity index 100% rename from src/config/index.js rename to src/config/index.ts diff --git a/src/config/options.js b/src/config/options.ts similarity index 100% rename from src/config/options.js rename to src/config/options.ts diff --git a/src/config/strings.js b/src/config/strings.ts similarity index 100% rename from src/config/strings.js rename to src/config/strings.ts diff --git a/src/config/types.js b/src/config/types.ts similarity index 100% rename from src/config/types.js rename to src/config/types.ts diff --git a/src/directory_scanning.js b/src/directory_scanning.ts similarity index 100% rename from src/directory_scanning.js rename to src/directory_scanning.ts diff --git a/src/generate_gitignore.js b/src/generate_gitignore.ts similarity index 100% rename from src/generate_gitignore.js rename to src/generate_gitignore.ts diff --git a/src/generate_json.js b/src/generate_json.ts similarity index 100% rename from src/generate_json.js rename to src/generate_json.ts diff --git a/src/generate_license.js b/src/generate_license.ts similarity index 100% rename from src/generate_license.js rename to src/generate_license.ts diff --git a/src/generate_lockfile.js b/src/generate_lockfile.ts similarity index 100% rename from src/generate_lockfile.js rename to src/generate_lockfile.ts diff --git a/src/generate_readme.js b/src/generate_readme.ts similarity index 100% rename from src/generate_readme.js rename to src/generate_readme.ts diff --git a/src/github_interactions.js b/src/github_interactions.ts similarity index 100% rename from src/github_interactions.js rename to src/github_interactions.ts diff --git a/src/logger.js b/src/logger.ts similarity index 100% rename from src/logger.js rename to src/logger.ts diff --git a/src/modpack-lock.js b/src/modpack-lock.ts similarity index 100% rename from src/modpack-lock.js rename to src/modpack-lock.ts diff --git a/src/modpack_info.js b/src/modpack_info.ts similarity index 100% rename from src/modpack_info.js rename to src/modpack_info.ts diff --git a/src/modrinth_interactions.js b/src/modrinth_interactions.ts similarity index 100% rename from src/modrinth_interactions.js rename to src/modrinth_interactions.ts diff --git a/tsconfig.json b/tsconfig.json index 55bb838..8c31fb6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,6 +44,6 @@ "skipLibCheck": true, }, "include": [ - "src/**/*.js" + "src/**/*.ts" ] } From 8c33da7d10642bde8d81fdd382c613cc86f029fa Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 15:46:52 -0500 Subject: [PATCH 004/110] install prompts types --- package-lock.json | 12 ++++++++++++ package.json | 1 + 2 files changed, 13 insertions(+) diff --git a/package-lock.json b/package-lock.json index aa65099..3b1e54f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/node": "^25.3.3", + "@types/prompts": "^2.4.9", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", @@ -1273,6 +1274,17 @@ "undici-types": "~7.18.0" } }, + "node_modules/@types/prompts": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", + "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "kleur": "^3.0.3" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", diff --git a/package.json b/package.json index ddb1441..627354e 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "devDependencies": { "@eslint/js": "^10.0.1", "@types/node": "^25.3.3", + "@types/prompts": "^2.4.9", "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", From 893782cf593e517d2ca6d7f5b407ad867b78444c Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 16:05:57 -0500 Subject: [PATCH 005/110] update configs with types --- src/config/api.ts | 26 +++++++++++++------------- src/config/constants.ts | 16 ++++++++-------- src/config/defaults.ts | 20 +++++++++++--------- src/config/files.ts | 10 +++++----- src/config/strings.ts | 15 ++++++++++----- 5 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/config/api.ts b/src/config/api.ts index 49b5f16..c0ebc54 100644 --- a/src/config/api.ts +++ b/src/config/api.ts @@ -2,40 +2,40 @@ import pkg from "../../package.json" with {type: "json"}; import * as constants from "./constants.js"; /** User-Agent header for Modrinth API requests */ -export const PACKAGE_USER_AGENT = `${constants.AUTHOR_USERNAME}/${pkg.name}/${pkg.version}`; +export const PACKAGE_USER_AGENT: string = `${constants.AUTHOR_USERNAME}/${pkg.name}/${pkg.version}`; /** Modrinth API base URL */ -export const MODRINTH_API_BASE = "https://api.modrinth.com/v2"; +export const MODRINTH_API_BASE: string = "https://api.modrinth.com/v2"; /** Modrinth version files endpoint */ -export const MODRINTH_VERSION_FILES_ENDPOINT = `${MODRINTH_API_BASE}/version_files`; +export const MODRINTH_VERSION_FILES_ENDPOINT: string = `${MODRINTH_API_BASE}/version_files`; /** Modrinth projects endpoint */ -export const MODRINTH_PROJECTS_ENDPOINT = `${MODRINTH_API_BASE}/projects`; +export const MODRINTH_PROJECTS_ENDPOINT: string = `${MODRINTH_API_BASE}/projects`; /** Modrinth users endpoint */ -export const MODRINTH_USERS_ENDPOINT = `${MODRINTH_API_BASE}/users`; +export const MODRINTH_USERS_ENDPOINT: string = `${MODRINTH_API_BASE}/users`; /** Modrinth Minecraft versions endpoint */ -export const MODRINTH_MINECRAFT_VERSIONS_ENDPOINT = `${MODRINTH_API_BASE}/tag/game_version`; +export const MODRINTH_MINECRAFT_VERSIONS_ENDPOINT: string = `${MODRINTH_API_BASE}/tag/game_version`; /** Modrinth Modloaders endpoint */ -export const MODRINTH_MODLOADERS_ENDPOINT = `${MODRINTH_API_BASE}/tag/loader`; +export const MODRINTH_MODLOADERS_ENDPOINT: string = `${MODRINTH_API_BASE}/tag/loader`; /** Batch size for Modrinth API requests */ -export const BATCH_SIZE = 100; +export const BATCH_SIZE: number = 100; /** GitHub API base URL */ -export const GITHUB_API_BASE = "https://api.github.com"; +export const GITHUB_API_BASE: string = "https://api.github.com"; /** GitHub licenses endpoint */ -export const GITHUB_LICENSES_ENDPOINT = `${GITHUB_API_BASE}/licenses`; +export const GITHUB_LICENSES_ENDPOINT: string = `${GITHUB_API_BASE}/licenses`; /** GitHub featured licenses endpoint */ -export const GITHUB_FEATURED_LICENSES_ENDPOINT = `${GITHUB_LICENSES_ENDPOINT}?featured=true`; +export const GITHUB_FEATURED_LICENSES_ENDPOINT: string = `${GITHUB_LICENSES_ENDPOINT}?featured=true`; /** GitHub license endpoint */ -export const GITHUB_LICENSE_ENDPOINT = (license) => `${GITHUB_API_BASE}/licenses/${license}`; +export const GITHUB_LICENSE_ENDPOINT: (license: string) => string = (license) => `${GITHUB_API_BASE}/licenses/${license}`; /** GitHub Accept request header */ -export const GITHUB_ACCEPT_HEADER = "application/vnd.github+json"; +export const GITHUB_ACCEPT_HEADER: string = "application/vnd.github+json"; diff --git a/src/config/constants.ts b/src/config/constants.ts index 001e391..4dceb7d 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,13 +1,13 @@ import pkg from "../../package.json" with {type: "json"}; /** Author username */ -export const AUTHOR_USERNAME = "nickesc"; +export const AUTHOR_USERNAME: string = "nickesc"; /** Lockfile format version -- increment on changes to the format */ -export const LOCKFILE_VERSION = "1.0.1"; +export const LOCKFILE_VERSION: string = "1.0.1"; /** Required fields for the modpack information */ -export const MODPACK_INFO_REQUIRED_FIELDS = [ +export const MODPACK_INFO_REQUIRED_FIELDS: string[] = [ "name", // "version", "id", @@ -17,7 +17,7 @@ export const MODPACK_INFO_REQUIRED_FIELDS = [ ]; /** Dependency categories, corresponds to folders in Minecraft profile */ -export const DEPENDENCY_CATEGORIES = [ +export const DEPENDENCY_CATEGORIES: string[] = [ "mods", // "resourcepacks", "shaderpacks", @@ -25,17 +25,17 @@ export const DEPENDENCY_CATEGORIES = [ ]; /** Minecraft version types */ -export const MINECRAFT_VERSION_TYPES = [ +export const MINECRAFT_VERSION_TYPES: string[] = [ "release", // "alpha", "beta", "snapshot", ]; -const gitignoreMarker = (mode) => `# ${pkg.name}:${mode}`; +const gitignoreMarker: (mode: string) => string = (mode) => `# ${pkg.name}:${mode}`; /** Gitignore section start marker */ -export const GITIGNORE_START_MARKER = gitignoreMarker("start"); +export const GITIGNORE_START_MARKER: string = gitignoreMarker("start"); /** Gitignore section end marker */ -export const GITIGNORE_END_MARKER = gitignoreMarker("end"); +export const GITIGNORE_END_MARKER: string = gitignoreMarker("end"); diff --git a/src/config/defaults.ts b/src/config/defaults.ts index ea2d1bf..ef65875 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -1,22 +1,24 @@ -export const DEFAULT_MODPACK_VERSION = "1.0.0"; +import type { Choice } from "prompts" -export const DEFAULT_MODPACK_LICENSE = "mit"; +export const DEFAULT_MODPACK_VERSION: string = "1.0.0"; -export const DEFAULT_PROJECT_URL = (id) => { +export const DEFAULT_MODPACK_LICENSE: string = "mit"; + +export const DEFAULT_PROJECT_URL: (id: string) => string = (id) => { return `https://modrinth.com/modpack/${id}`; }; -export const DEFAULT_SOURCE_URL = (id, author) => { +export const DEFAULT_SOURCE_URL: (id: string, author: string) => string = (id, author) => { return `https://github.com/${author}/${id}`; }; /** All-Rights-Reserved license option */ -export const ALL_RIGHTS_RESERVED_LICENSE = {title: "All-Rights-Reserved", value: "all-rights-reserved"}; +export const ALL_RIGHTS_RESERVED_LICENSE: Choice = {title: "All-Rights-Reserved", value: "all-rights-reserved"}; /** Other option */ -export const OTHER_OPTION = {title: "Other", value: "other"}; +export const OTHER_OPTION: Choice = {title: "Other", value: "other"}; /** Fallback licenses */ -export const FALLBACK_LICENSES = [ +export const FALLBACK_LICENSES: Choice[] = [ {title: "MIT", value: "mit"}, {title: "Apache-2.0", value: "apache-2.0"}, {title: "GPL-3.0", value: "gpl-3.0"}, @@ -24,7 +26,7 @@ export const FALLBACK_LICENSES = [ ]; /** Fallback modloaders */ -export const FALLBACK_MODLOADERS = [ +export const FALLBACK_MODLOADERS: Choice[] = [ {title: "fabric", value: "fabric"}, {title: "forge", value: "forge"}, {title: "neoforge", value: "neoforge"}, @@ -37,7 +39,7 @@ export const FALLBACK_MODLOADERS = [ ]; /** Fallback target Minecraft versions */ -export const FALLBACK_TARGET_MINECRAFT_VERSIONS = [ +export const FALLBACK_TARGET_MINECRAFT_VERSIONS: Choice[] = [ {title: "1.21.x", value: "1.21.x"}, {title: "1.20.x", value: "1.20.x"}, {title: "1.19.x", value: "1.19.x"}, diff --git a/src/config/files.ts b/src/config/files.ts index 0913f2b..2bb76e5 100644 --- a/src/config/files.ts +++ b/src/config/files.ts @@ -1,14 +1,14 @@ /** Machine-readable/lockfile name */ -export const MODPACK_LOCKFILE_NAME = "modpack.lock"; +export const MODPACK_LOCKFILE_NAME: string = "modpack.lock"; /** Human-readable/JSON file name */ -export const MODPACK_JSON_NAME = "modpack.json"; +export const MODPACK_JSON_NAME: string = "modpack.json"; /** License file name */ -export const MODPACK_LICENSE_NAME = "LICENSE"; +export const MODPACK_LICENSE_NAME: string = "LICENSE"; /** Gitignore file name */ -export const GITIGNORE_NAME = ".gitignore"; +export const GITIGNORE_NAME: string = ".gitignore"; /** README.md file name */ -export const README_NAME = "README.md"; +export const README_NAME: string = "README.md"; diff --git a/src/config/strings.ts b/src/config/strings.ts index 55abbc9..7b63126 100644 --- a/src/config/strings.ts +++ b/src/config/strings.ts @@ -2,7 +2,12 @@ import * as defaults from "./defaults.js"; import * as files from "./files.js"; import pkg from "../../package.json" with {type: "json"}; -export const infoFields = { +interface InfoField { + prompt: string; + option: string; +} + +export const infoFields: Record = { name: { prompt: "modpack name", option: "Modpack name; defaults to the directory name", @@ -49,7 +54,7 @@ export const infoFields = { }, }; -export const fileFields = { +export const fileFields: Record = { addLicense: { prompt: `Add the ${files.MODPACK_LICENSE_NAME} file`, option: `Add the ${files.MODPACK_LICENSE_NAME} file to the modpack`, @@ -64,7 +69,7 @@ export const fileFields = { }, }; -export const headings = { +export const headings: Record = { options: "Options:", generation: "GENERATION", logging: "LOGGING", @@ -72,11 +77,11 @@ export const headings = { information: "INFORMATION", }; -export const dryRunText = (filename, location) => { +export const dryRunText: (filename: string, location: string) => string = (filename, location) => { return `[DRY RUN] Would write ${filename} to: ${location}`; }; /** All-Rights-Reserved license text */ -export const ARR_LICENSE_TEXT = "Copyright (c) [year] [fullname]\n" + "\n" + "All rights reserved.\n"; +export const ARR_LICENSE_TEXT: string = "Copyright (c) [year] [fullname]\n" + "\n" + "All rights reserved.\n"; export {pkg}; From 259cd6dc9ca688c2cba026807cf6b3a4280709f0 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 16:27:43 -0500 Subject: [PATCH 006/110] updated logger to use typescript --- src/logger.ts | 74 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index d365497..a531247 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,13 +1,25 @@ -import {styleText} from "node:util"; +import { styleText } from "node:util"; +import type { InspectColor } from "node:util"; class Logger { /** * The styles to apply to the console output. - * @type {Object} */ - styles = { - log: null, - info: null, + styles: { + log: InspectColor[]; + info: InspectColor[]; + debug: InspectColor[]; + warn: InspectColor[]; + error: InspectColor[]; + generated: InspectColor[]; + label: InspectColor[]; + labelDebug: InspectColor[]; + labelWarn: InspectColor[]; + labelError: InspectColor[]; + labelGenerated: InspectColor[]; + } = { + log: [], + info: [], debug: ["magenta"], warn: ["yellow"], error: ["red"], @@ -23,12 +35,12 @@ class Logger { silentConsole = false; lastLogWasNewline = false; - quiet(silent = false) { + quiet(silent: boolean = false) { this.quietConsole = true; this.silentConsole = silent; } - quietFromOptions(options) { + quietFromOptions(options: { silent: boolean, quiet: boolean }) { if (options.silent) { this.quietConsole = true; this.silentConsole = true; @@ -37,31 +49,31 @@ class Logger { } } - styleArgs(style, args) { + styleArgs(style: InspectColor[] | null, args: any[]) { if (!style) { return args; } if (args.length === 0) { return ""; } - return args.map((arg) => (typeof arg === "string" ? styleText(style, arg) : arg)); + return args.map((arg: any) => (typeof arg === "string" ? styleText(style, arg) : arg)); } /** * Style the text as a label. - * @param {string} text - The text to style. - * @param {string[]} style - The style to apply to the text. - * @returns {string} The styled text. + * @param text - The text to style. + * @param style - The style to apply to the text. + * @returns The styled text. */ - label(text, style = this.styles.label) { + label(text: string, style: InspectColor[] = this.styles.label) { return styleText(style, String(text).toUpperCase()); } /** * Log a header. - * @param {string} text - The text to log. + * @param text - The text to log. */ - header(text) { + header(text: string) { if (this.quietConsole) { return; } @@ -73,7 +85,7 @@ class Logger { this.lastLogWasNewline = true; } - generated(desc, outputPath) { + generated(desc: string, outputPath: string) { if (this.quietConsole) { return; } @@ -100,10 +112,10 @@ class Logger { /** * Log a message. - * @param {string} message - The message to log. - * @param {...any} otherMessages - The other messages to log. + * @param message - The message to log. + * @param otherMessages - The other messages to log. */ - log(message, ...otherMessages) { + log(message: any, ...otherMessages: any[]) { if (this.quietConsole) { return; } @@ -113,10 +125,10 @@ class Logger { /** * Log an info message. - * @param {string} message - The message to log. - * @param {...any} otherMessages - The other messages to log. + * @param message - The message to log. + * @param otherMessages - The other messages to log. */ - info(message, ...otherMessages) { + info(message: any, ...otherMessages: any[]) { if (this.quietConsole) { return; } @@ -126,10 +138,10 @@ class Logger { /** * Log a debug message. - * @param {string} message - The message to log. - * @param {...any} otherMessages - The other messages to log. + * @param message - The message to log. + * @param otherMessages - The other messages to log. */ - debug(message, ...otherMessages) { + debug(message: any, ...otherMessages: any[]) { if (this.silentConsole) { return; } @@ -142,10 +154,10 @@ class Logger { /** * Log a warning message. - * @param {string} message - The message to log. - * @param {...any} otherMessages - The other messages to log. + * @param message - The message to log. + * @param otherMessages - The other messages to log. */ - warn(message, ...otherMessages) { + warn(message: any, ...otherMessages: any[]) { if (this.silentConsole) { return; } @@ -158,10 +170,10 @@ class Logger { /** * Log an error message. - * @param {string} message - The message to log. - * @param {...any} otherMessages - The other messages to log. + * @param message - The message to log. + * @param otherMessages - The other messages to log. */ - error(message, ...otherMessages) { + error(message: any, ...otherMessages: any[]) { if (this.silentConsole) { return; } From 2fb07b5a15a96d4d25413cfb63f10a955903a7e3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 17:36:39 -0500 Subject: [PATCH 007/110] add types as ts types --- src/types/Lockfile.ts | 33 +++++++++++++++++++ src/types/ModpackInfo.ts | 26 +++++++++++++++ src/types/Options.ts | 71 ++++++++++++++++++++++++++++++++++++++++ src/types/index.ts | 5 +++ 4 files changed, 135 insertions(+) create mode 100644 src/types/Lockfile.ts create mode 100644 src/types/ModpackInfo.ts create mode 100644 src/types/Options.ts create mode 100644 src/types/index.ts diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts new file mode 100644 index 0000000..0dd041a --- /dev/null +++ b/src/types/Lockfile.ts @@ -0,0 +1,33 @@ +/** + * Contains information about the modpack dependencies and their versions. + * @property version - The version of the modpack + * @property generated - The date and time the lockfile was generated + * @property total - The total number of files in the modpack + * @property counts - The counts object + * @property counts.mods - The mods count + * @property counts.resourcepacks - The resourcepacks count + * @property counts.datapacks - The datapacks count + * @property counts.shaderpacks - The shaderpacks count + * @property dependencies - The dependencies object + * @property dependencies.mods - The mods array + * @property dependencies.resourcepacks - The resourcepacks array + * @property dependencies.datapacks - The datapacks array + * @property dependencies.shaderpacks - The shaderpacks array + */ +export type Lockfile = { + version: string; + generated: string; + total: number; + counts: { + mods: number; + resourcepacks: number; + datapacks: number; + shaderpacks: number; + }; + dependencies: { + mods: string[]; + resourcepacks: string[]; + datapacks: string[]; + shaderpacks: string[]; + }; +}; diff --git a/src/types/ModpackInfo.ts b/src/types/ModpackInfo.ts new file mode 100644 index 0000000..7492cfa --- /dev/null +++ b/src/types/ModpackInfo.ts @@ -0,0 +1,26 @@ +/** + * @typedef {Object} ModpackInfo + * Contains information about the modpack that is not dependent on the lockfile. + * @property {string} name - The name of the modpack (Required) + * @property {string} version - The version of the modpack (Required) + * @property {string} description - The description of the modpack + * @property {string} id - The slug/ID of the modpack (Required) + * @property {string} author - The author of the modpack (Required) + * @property {string} projectUrl - The project URL of the modpack + * @property {string} sourceUrl - The source code URL of the modpack + * @property {string} license - The license of the modpack + * @property {string} modloader - The modloader of the modpack (Required) + * @property {string} targetModloaderVersion - The target modloader version of the modpack + * @property {string} targetMinecraftVersion - The target Minecraft version of the modpack (Required) + */ +export type ModpackInfo = { + name: string; + version: string; + description: string; + id: string; + author: string; + projectUrl: string; + sourceUrl: string; + license: string; + modloader: string; +}; diff --git a/src/types/Options.ts b/src/types/Options.ts new file mode 100644 index 0000000..efc78b5 --- /dev/null +++ b/src/types/Options.ts @@ -0,0 +1,71 @@ +/** + * Contains options for the generation of the modpack files. + * @property {boolean} dryRun - Whether to dry run the generation + * @property {boolean} quiet - Whether to quiet the console output + * @property {boolean} silent - Whether to silent the console output + * @property {boolean} gitignore - Whether to generate a .gitignore file + * @property {boolean} readme - Whether to generate README.md files + * @property {boolean} licenseFile - Whether to generate a license file + */ + +export interface Options { + dryRun: boolean; + quiet: boolean; + silent: boolean; + gitignore: boolean; + readme: boolean; + licenseFile: boolean; +} +/** + * Contains options for the initialization of the modpack files. + * @property {string} folder - The folder to generate the modpack files in + * @property {boolean} noninteractive - Whether to run the interactive mode + * @property {boolean} addLicense - Whether to add the license file to the modpack + * @property {boolean} addGitignore - Whether to generate .gitignore rules + * @property {boolean} addReadme - Whether to generate README.md files + * @property {string} name - The name of the modpack + * @property {string} version - The version of the modpack + * @property {string} id - The slug/ID of the modpack + * @property {string} description - The description of the modpack + * @property {string} author - The author of the modpack + * @property {string} projectUrl - The modpack's project URL + * @property {string} sourceUrl - The modpack's source code URL + * @property {string} license - The modpack's license + * @property {string} modloader - The modpack's modloader + * @property {string} targetModloaderVersion - The target modloader version + * @property {string} targetMinecraftVersion - The target Minecraft version + * @property {boolean} _init - Internal boolean added to indicate options come from the `init` command. + */ + +export interface InitOptions { + folder: string; + noninteractive: boolean; + addLicense: boolean; + addGitignore: boolean; + addReadme: boolean; + name: string; + version: string; + id: string; + description: string; + author: string; + projectUrl: string; + sourceUrl: string; + license: string; + modloader: string; + targetModloaderVersion: string; + targetMinecraftVersion: string; + _init: boolean; +} + +/** + * Contains options for the running scripts defined in modpack.json. + * @property {string} folder - The folder to look for modpack.json in + * @property {boolean} debug - Whether to print debug information about the executed script + * @property {boolean} _run - Internal boolean added to indicate options come from the `run` command. + */ + +export interface RunOptions { + folder: string; + debug: boolean; + _run: boolean; +} diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..68504de --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,5 @@ +import type { Lockfile } from "./Lockfile.js"; +import type { ModpackInfo } from "./ModpackInfo.js"; +import type { Options, InitOptions, RunOptions } from "./Options.js"; + +export type { InitOptions, Lockfile, ModpackInfo, Options, RunOptions }; From b01b82ab7f2ba9d9f3048b6ff46fccce932837e8 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 18:51:39 -0500 Subject: [PATCH 008/110] add explicit fields for config objects --- src/config/options.ts | 12 ++++++++++-- src/config/strings.ts | 28 +++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/config/options.ts b/src/config/options.ts index bdf515b..96336b7 100644 --- a/src/config/options.ts +++ b/src/config/options.ts @@ -1,7 +1,13 @@ import {logm} from "../logger.js"; /** Options for slugify */ -export const SLUGIFY_OPTIONS = { +export const SLUGIFY_OPTIONS: { + lower: boolean; + strict: boolean; + separator: string; + locale: string; + trim: boolean; +} = { lower: true, strict: true, separator: "-", @@ -10,7 +16,9 @@ export const SLUGIFY_OPTIONS = { }; /** Options for prompts */ -export const PROMPTS_OPTIONS = { +export const PROMPTS_OPTIONS: { + onCancel: () => void; +} = { onCancel: () => { logm.warn("Modpack initialization was interrupted"); process.exit(1); diff --git a/src/config/strings.ts b/src/config/strings.ts index 7b63126..e5cbf11 100644 --- a/src/config/strings.ts +++ b/src/config/strings.ts @@ -7,7 +7,19 @@ interface InfoField { option: string; } -export const infoFields: Record = { +export const infoFields: { + name: InfoField; + version: InfoField; + id: InfoField; + description: InfoField; + author: InfoField; + projectUrl: InfoField; + sourceUrl: InfoField; + license: InfoField; + modloader: InfoField; + targetModloaderVersion: InfoField; + targetMinecraftVersion: InfoField; +} = { name: { prompt: "modpack name", option: "Modpack name; defaults to the directory name", @@ -54,7 +66,11 @@ export const infoFields: Record = { }, }; -export const fileFields: Record = { +export const fileFields: { + addLicense: InfoField; + addGitignore: InfoField; + addReadme: InfoField; +} = { addLicense: { prompt: `Add the ${files.MODPACK_LICENSE_NAME} file`, option: `Add the ${files.MODPACK_LICENSE_NAME} file to the modpack`, @@ -69,7 +85,13 @@ export const fileFields: Record = { }, }; -export const headings: Record = { +export const headings: { + options: string; + generation: string; + logging: string; + packInfo: string; + information: string; +} = { options: "Options:", generation: "GENERATION", logging: "LOGGING", From aaf1b99b7af830e818c3e5a37593e0baeb27c0e4 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 28 Feb 2026 18:51:53 -0500 Subject: [PATCH 009/110] fix modpack info type --- src/types/ModpackInfo.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/ModpackInfo.ts b/src/types/ModpackInfo.ts index 7492cfa..ecf9134 100644 --- a/src/types/ModpackInfo.ts +++ b/src/types/ModpackInfo.ts @@ -23,4 +23,6 @@ export type ModpackInfo = { sourceUrl: string; license: string; modloader: string; + targetModloaderVersion: string; + targetMinecraftVersion: string; }; From 807dd3859225a9ce1dbda0a5c33e1e1702fbfece Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 1 Mar 2026 00:17:00 -0500 Subject: [PATCH 010/110] support typescript in modpack info prompting --- src/modpack_info.ts | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/modpack_info.ts b/src/modpack_info.ts index a2a96e7..4006491 100644 --- a/src/modpack_info.ts +++ b/src/modpack_info.ts @@ -1,8 +1,9 @@ -import prompts from "prompts"; +import prompts, { type Choice, type InitialReturnValue, type PromptObject } from "prompts"; import slugify from "slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; +import type { InitOptions, ModpackInfo } from "./types/index.js"; /** * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo @@ -11,14 +12,14 @@ import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; /** * Capitalizes a string */ -function capitalize(string) { +function capitalize(string: string) { return `${string.charAt(0).toUpperCase()}${string.slice(1)}`; } /** * Validate that a value is not empty */ -function validateNotEmpty(value, field) { +function validateNotEmpty(value: string, field: string) { if (value === undefined || value?.trim().length === 0) { return `${field} cannot be empty`; } @@ -28,13 +29,13 @@ function validateNotEmpty(value, field) { /** * Returns a required text prompt */ -function requiredText(name, message, initial) { +function requiredText(name: string, message: string, initial: PromptObject["initial"]): PromptObject { return { type: "text", name: name, message: `${capitalize(message)}`, initial: initial, - validate: (value) => { + validate: (value: string) => { return validateNotEmpty(value, name); }, }; @@ -43,7 +44,7 @@ function requiredText(name, message, initial) { /** * Returns an optional text prompt */ -function optionalText(name, message, initial) { +function optionalText(name: string, message: string, initial: PromptObject["initial"]): PromptObject { return { type: "text", name: name, @@ -55,7 +56,7 @@ function optionalText(name, message, initial) { /** * Get an other answer from the user */ -async function getOtherAnswer(value, message, initial) { +async function getOtherAnswer(value: string, message: string, initial: PromptObject["initial"]) { if (value && value !== config.OTHER_OPTION.value) { return value; } @@ -67,10 +68,10 @@ async function getOtherAnswer(value, message, initial) { /** * Returns a required autocomplete prompt with a fallback to the other option */ -function requiredAutocomplete(name, message, initial, choices, defaultValue) { +function requiredAutocomplete(name: string, message: string, initial: PromptObject["initial"], choices: Choice[], defaultValue: string): PromptObject { initial = initial || defaultValue || config.OTHER_OPTION.value; if (initial && !choices.some((choice) => choice.value === initial)) { - choices.push({title: initial, value: initial}); + choices.push({title: initial as string, value: initial as string}); } return { @@ -79,9 +80,9 @@ function requiredAutocomplete(name, message, initial, choices, defaultValue) { message: `${capitalize(message)}`, initial: initial, choices: choices, - fallback: config.OTHER_OPTION.value, - format: async (value) => { - return await getOtherAnswer(value, ` └─𜰙 Other ${message}`, initial); + //fallback: config.OTHER_OPTION.value, + format: async (value: string) => { + return await getOtherAnswer(value, ` └─𜰙 Other ${message}`, initial as string); }, }; } @@ -89,7 +90,7 @@ function requiredAutocomplete(name, message, initial, choices, defaultValue) { /** * Returns an confirmation prompt to generate an optional file */ -function fileGenerationConfirm(name, message, showPrompt) { +function fileGenerationConfirm(name: string, message: string, showPrompt: boolean): PromptObject { return { type: showPrompt ? "confirm" : null, name: name, @@ -103,7 +104,7 @@ function fileGenerationConfirm(name, message, showPrompt) { * @param {ModpackInfo} defaults - The initial/default modpack information * @returns {Promise} The modpack information from the user */ -export async function promptUserForInfo(defaults = {}) { +export async function promptUserForInfo(defaults: ModpackInfo) { const licenseList = await getLicenseList(); const minecraftVersions = await getMinecraftVersions(); const modloaders = await getModloaders(); @@ -115,8 +116,12 @@ export async function promptUserForInfo(defaults = {}) { config.infoFields.version.prompt, defaults.version || config.DEFAULT_MODPACK_VERSION, ), - requiredText("id", config.infoFields.id.prompt, (prev, values) => - slugify(defaults.id || values.name, config.SLUGIFY_OPTIONS), + requiredText( + "id", + config.infoFields.id.prompt, + (prev: string, values: any) => { + return slugify(defaults.id || values.name, config.SLUGIFY_OPTIONS) + }, ), optionalText("description", config.infoFields.description.prompt, defaults.description), requiredText("author", config.infoFields.author.prompt, defaults.author), @@ -142,7 +147,7 @@ export async function promptUserForInfo(defaults = {}) { config.infoFields.modloader.prompt, defaults.modloader, modloaders, - config.FALLBACK_MODLOADERS[0].value, + config.FALLBACK_MODLOADERS[0] ? config.FALLBACK_MODLOADERS[0].value : "", ), optionalText( "targetModloaderVersion", @@ -166,9 +171,10 @@ export async function promptUserForInfo(defaults = {}) { /** * Prompt the user about adding the license text to the modpack * @param {ModpackInfo} modpackInfo - The modpack information + * @param {InitOptions} defaults - The default options * @returns {Promise} The answers from the user */ -export async function promptUserAboutOptionalFiles(modpackInfo, defaults = {}) { +export async function promptUserAboutOptionalFiles(modpackInfo: ModpackInfo, defaults: InitOptions) { const licenseText = await getLicenseText(modpackInfo.license); const answers = await prompts( [ From 7f3e49c452add908a9e15d674c133a3ba00c7c72 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 1 Mar 2026 00:30:53 -0500 Subject: [PATCH 011/110] add type support to getLicenseList --- src/github_interactions.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/github_interactions.ts b/src/github_interactions.ts index 98be871..66f71c2 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -1,14 +1,20 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; +import type { Choice } from "prompts"; + +type LicenseResponse = { + spdx_id: string; + key: string; +}; /** * Fetch a list of the most popular licenses from GitHub - * @param {boolean} featured - If the fetch should be limited to featured licenses - * @returns {Promise>} The list of licenses for use in a prompt + * @param featured - If the fetch should be limited to featured licenses + * @returns The list of licenses for use in a prompt */ -export async function getLicenseList(featured = false) { +export async function getLicenseList(featured: boolean = false) { try { - const url = featured ? config.GITHUB_FEATURED_LICENSES_ENDPOINT : config.GITHUB_LICENSES_ENDPOINT; + const url: string = featured ? config.GITHUB_FEATURED_LICENSES_ENDPOINT : config.GITHUB_LICENSES_ENDPOINT; const response = await fetch(url, { headers: { Accept: config.GITHUB_ACCEPT_HEADER, @@ -19,9 +25,9 @@ export async function getLicenseList(featured = false) { const errorText = await response.text(); throw new Error(`GitHub API error (${response.status}): ${errorText}`); } - let licenseList = await response.json(); + const licenseList: LicenseResponse[] = (await response.json()) as LicenseResponse[]; - let licenseSpdxIds = licenseList.map((license) => ({title: license.spdx_id, value: license.key})); + let licenseSpdxIds: Choice[] = licenseList.map((license: LicenseResponse): Choice => ({title: license.spdx_id, value: license.key})); if (!featured) { // get featured licenses and place them at the beginning of the list, removing them from the original list @@ -37,8 +43,7 @@ export async function getLicenseList(featured = false) { return licenseSpdxIds; } catch { logm.warn(`Could not fetch license list. Using fallbacks.`); - const licenses = config.FALLBACK_LICENSES.push(config.ALL_RIGHTS_RESERVED_LICENSE); - licenses.push(config.OTHER_OPTION); + const licenses = [...config.FALLBACK_LICENSES, config.ALL_RIGHTS_RESERVED_LICENSE, config.OTHER_OPTION]; return licenses; } } From d6e20dda9ee1a96288a018692a0a89038806f1a7 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 1 Mar 2026 00:33:43 -0500 Subject: [PATCH 012/110] add type support for getLicenseText --- src/github_interactions.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/github_interactions.ts b/src/github_interactions.ts index 66f71c2..4c0a350 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -2,11 +2,15 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; import type { Choice } from "prompts"; -type LicenseResponse = { +type LicenseResponseItem = { spdx_id: string; key: string; }; +type LicenseTextResponse = { + body: string; +}; + /** * Fetch a list of the most popular licenses from GitHub * @param featured - If the fetch should be limited to featured licenses @@ -25,9 +29,9 @@ export async function getLicenseList(featured: boolean = false) { const errorText = await response.text(); throw new Error(`GitHub API error (${response.status}): ${errorText}`); } - const licenseList: LicenseResponse[] = (await response.json()) as LicenseResponse[]; + const licenseList: LicenseResponseItem[] = (await response.json()) as LicenseResponseItem[]; - let licenseSpdxIds: Choice[] = licenseList.map((license: LicenseResponse): Choice => ({title: license.spdx_id, value: license.key})); + let licenseSpdxIds: Choice[] = licenseList.map((license: LicenseResponseItem): Choice => ({title: license.spdx_id, value: license.key})); if (!featured) { // get featured licenses and place them at the beginning of the list, removing them from the original list @@ -50,15 +54,15 @@ export async function getLicenseList(featured: boolean = false) { /** * Fetch specific license information from GitHub - * @param {string} spdxId - The SPDX ID of the license - * @returns {Promise | null} The license text + * @param spdxId - The SPDX ID of the license + * @returns The license text */ -export async function getLicenseText(spdxId) { +export async function getLicenseText(spdxId: string): Promise { if (spdxId === "all-rights-reserved") { return config.ARR_LICENSE_TEXT; } try { - const url = config.GITHUB_LICENSE_ENDPOINT(spdxId.toLowerCase()); + const url: string = config.GITHUB_LICENSE_ENDPOINT(spdxId.toLowerCase()); const response = await fetch(url, { headers: { Accept: config.GITHUB_ACCEPT_HEADER, @@ -70,7 +74,7 @@ export async function getLicenseText(spdxId) { throw new Error(`GitHub API error (${response.status}): ${errorText}`); } - const json = await response.json(); + const json: LicenseTextResponse = (await response.json()) as LicenseTextResponse; if (json.body) { return json.body; } else { From 8aa85cd702ac9f30e660da0d176d7d5608d61909 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 1 Mar 2026 01:11:37 -0500 Subject: [PATCH 013/110] update prettierrc --- .prettierrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierrc b/.prettierrc index 0d8e632..0e17c3e 100644 --- a/.prettierrc +++ b/.prettierrc @@ -14,7 +14,7 @@ "objectWrap": "preserve", "bracketSameLine": false, "singleAttributePerLine": false, - "parser": "babel", + "parser": "typescript", "overrides": [ { "files": [ From c3b92bbc5dd867665d84006026a869cfefb0815a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 1 Mar 2026 01:11:58 -0500 Subject: [PATCH 014/110] update license text logic --- src/modpack_info.ts | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/modpack_info.ts b/src/modpack_info.ts index 4006491..2c95592 100644 --- a/src/modpack_info.ts +++ b/src/modpack_info.ts @@ -1,9 +1,9 @@ -import prompts, { type Choice, type InitialReturnValue, type PromptObject } from "prompts"; +import prompts, {type Choice, type InitialReturnValue, type PromptObject} from "prompts"; import slugify from "slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; -import type { InitOptions, ModpackInfo } from "./types/index.js"; +import type {InitOptions, ModpackInfo} from "./types/index.js"; /** * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo @@ -68,7 +68,13 @@ async function getOtherAnswer(value: string, message: string, initial: PromptObj /** * Returns a required autocomplete prompt with a fallback to the other option */ -function requiredAutocomplete(name: string, message: string, initial: PromptObject["initial"], choices: Choice[], defaultValue: string): PromptObject { +function requiredAutocomplete( + name: string, + message: string, + initial: PromptObject["initial"], + choices: Choice[], + defaultValue: string, +): PromptObject { initial = initial || defaultValue || config.OTHER_OPTION.value; if (initial && !choices.some((choice) => choice.value === initial)) { choices.push({title: initial as string, value: initial as string}); @@ -116,13 +122,9 @@ export async function promptUserForInfo(defaults: ModpackInfo) { config.infoFields.version.prompt, defaults.version || config.DEFAULT_MODPACK_VERSION, ), - requiredText( - "id", - config.infoFields.id.prompt, - (prev: string, values: any) => { - return slugify(defaults.id || values.name, config.SLUGIFY_OPTIONS) - }, - ), + requiredText("id", config.infoFields.id.prompt, (prev: string, values: any) => { + return slugify(defaults.id || values.name, config.SLUGIFY_OPTIONS); + }), optionalText("description", config.infoFields.description.prompt, defaults.description), requiredText("author", config.infoFields.author.prompt, defaults.author), optionalText( @@ -181,7 +183,7 @@ export async function promptUserAboutOptionalFiles(modpackInfo: ModpackInfo, def fileGenerationConfirm( "addLicense", `${config.fileFields.addLicense.prompt}?`, - licenseText && defaults.addLicense === undefined, + licenseText && defaults.addLicense === undefined ? true : false, ), fileGenerationConfirm( "addReadme", From 75f3eb08fb412a2c7c076a73cf21db4e28042c2c Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 00:40:35 -0500 Subject: [PATCH 015/110] add modrinth response types and update type index --- src/types/index.ts | 9 ++-- src/types/modrinthResponses.ts | 89 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 src/types/modrinthResponses.ts diff --git a/src/types/index.ts b/src/types/index.ts index 68504de..b91a694 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,5 +1,4 @@ -import type { Lockfile } from "./Lockfile.js"; -import type { ModpackInfo } from "./ModpackInfo.js"; -import type { Options, InitOptions, RunOptions } from "./Options.js"; - -export type { InitOptions, Lockfile, ModpackInfo, Options, RunOptions }; +export type * from "./Lockfile.js"; +export type * from "./ModpackInfo.js"; +export type * from "./Options.js"; +export type * from "./modrinthResponses.js"; diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts new file mode 100644 index 0000000..84a7401 --- /dev/null +++ b/src/types/modrinthResponses.ts @@ -0,0 +1,89 @@ +export type VersionResponseItem = { + id: string; + project_id: string; + author_id: string; + date_published: string; + downloads: number; + files: any[]; + game_versions?: string[]; + loaders?: string[]; + featured?: boolean; + name?: string; + version_number?: string; + changelog?: string; + changelog_url?: string | null; + version_type?: string; + status?: string; + requested_status?: string | null; + dependencies?: any[]; +}; + +export type ProjectResponseItem = { + id: string; // + project_type: string; // + team: string; // + published: string; // + updated: string; // + downloads: number; // + followers: number; // + slug?: string; + client_side?: string; + server_side?: string; + game_versions?: string[]; + organization?: string | null; + title?: string; + description?: string; + body?: string; + body_url?: string | null; + approved?: string; + queued?: string | null; + status?: string; + requested_status?: string | null; + moderator_message?: string | null; + license?: any; + categories?: string[]; + additional_categories?: string[]; + loaders?: string[]; + versions?: string[]; + icon_url?: string; + issues_url?: string; + source_url?: string; + wiki_url?: string; + discord_url?: string; + donation_urls?: string[]; + gallery?: string[]; + color?: number; + thread_id?: string; + monetization_status?: string; +}; + +export type MinecraftVersionResponseItem = { + version: string; + version_type: string; + date: string; + major: boolean; +}; + +export type ModloaderResponseItem = { + icon: string; + name: string; + supported_project_types: string[]; +}; + +export type UserResponseItem = { + username: string; // + id: string; // + created: string; // + role: "admin" | "moderator" | "developer"; // + name?: string; + email?: string | null; + bio?: string; + payout_data?: any; + avatar_url?: string; + badges?: number; + auth_providers?: string[]; + email_verified?: boolean | null; + has_password?: boolean | null; + has_totp?: boolean | null; + github_id?: number | null; +}; From e3ae26c606f258d1f6290e673b0c5fc46af9852a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 00:40:56 -0500 Subject: [PATCH 016/110] add type support for modrinth interactions --- src/modrinth_interactions.ts | 84 +++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/src/modrinth_interactions.ts b/src/modrinth_interactions.ts index 8394905..5476373 100644 --- a/src/modrinth_interactions.ts +++ b/src/modrinth_interactions.ts @@ -1,10 +1,18 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; +import type {Choice} from "prompts"; +import type { + VersionResponseItem, + ProjectResponseItem, + MinecraftVersionResponseItem, + ModloaderResponseItem, + UserResponseItem, +} from "./types/index.js"; /** * Split an array into chunks of specified size */ -function chunkArray(array, size) { +function chunkArray(array: any[], size: number) { const chunks = []; for (let i = 0; i < array.length; i += size) { chunks.push(array.slice(i, i + size)); @@ -15,7 +23,7 @@ function chunkArray(array, size) { /** * Query Modrinth API for version information from hashes */ -export async function getVersionsFromHashes(hashes) { +export async function getVersionsFromHashes(hashes: string[]): Promise> { if (hashes.length === 0) { return {}; } @@ -38,23 +46,27 @@ export async function getVersionsFromHashes(hashes) { throw new Error(`Modrinth API error (${response.status}): ${errorText}`); } - return await response.json(); - } catch (error) { - logm.error(`Error fetching version information from hashes: ${error.message}`); - throw error; + return (await response.json()) as Record; + } catch (error: unknown) { + if (error instanceof Error) { + logm.error(`Error fetching version information from hashes: ${error.message}`); + throw error; + } else { + throw new Error(`Unknown error fetching version information from hashes`); + } } } /** * Fetch multiple projects by their IDs in batches */ -export async function getProjects(projectIds) { +export async function getProjects(projectIds: string[]): Promise { if (projectIds.length === 0) { return []; } - const chunks = chunkArray(projectIds, config.BATCH_SIZE); - const results = []; + const chunks: string[][] = chunkArray(projectIds, config.BATCH_SIZE); + const results: ProjectResponseItem[] = []; for (const chunk of chunks) { try { @@ -70,11 +82,15 @@ export async function getProjects(projectIds) { throw new Error(`Modrinth API error (${response.status}): ${errorText}`); } - const data = await response.json(); + const data = (await response.json()) as ProjectResponseItem[]; results.push(...data); - } catch (error) { - logm.error(`Error fetching projects: ${error.message}`); - throw error; + } catch (error: any) { + if (error instanceof Error) { + logm.error(`Error fetching projects: ${error.message}`); + throw error; + } else { + throw new Error(`Unknown error fetching projects`); + } } } @@ -84,13 +100,13 @@ export async function getProjects(projectIds) { /** * Fetch multiple users by their IDs in batches */ -export async function getUsers(userIds) { +export async function getUsers(userIds: string[]): Promise { if (userIds.length === 0) { return []; } - const chunks = chunkArray(userIds, config.BATCH_SIZE); - const results = []; + const chunks: string[][] = chunkArray(userIds, config.BATCH_SIZE); + const results: UserResponseItem[] = []; for (const chunk of chunks) { try { @@ -106,11 +122,15 @@ export async function getUsers(userIds) { throw new Error(`Modrinth API error (${response.status}): ${errorText}`); } - const data = await response.json(); + const data = (await response.json()) as UserResponseItem[]; results.push(...data); - } catch (error) { - logm.error(`Error fetching users: ${error.message}`); - throw error; + } catch (error: any) { + if (error instanceof Error) { + logm.error(`Error fetching users: ${error.message}`); + throw error; + } else { + throw new Error(`Unknown error fetching users`); + } } } @@ -121,7 +141,7 @@ export async function getUsers(userIds) { * Fetch Minecraft versions from Modrinth * @returns {Promise>} The Minecraft versions */ -export async function getMinecraftVersions() { +export async function getMinecraftVersions(): Promise { try { const url = config.MODRINTH_MINECRAFT_VERSIONS_ENDPOINT; const response = await fetch(url, { @@ -134,7 +154,7 @@ export async function getMinecraftVersions() { throw new Error(`Modrinth API error (${response.status}): ${errorText}`); } - const json = await response.json(); + const json = (await response.json()) as MinecraftVersionResponseItem[]; if (json) { //sort by version type (in the order of the MINECRAFT_VERSION_TYPES array) json.sort((a, b) => { @@ -143,9 +163,12 @@ export async function getMinecraftVersions() { config.MINECRAFT_VERSION_TYPES.indexOf(b.version_type) ); }); - return json.map((version) => ({title: version.version, value: version.version})); + return json.map((version) => ({ + title: version.version, + value: version.version, + })) as Choice[]; } else { - throw new Error(); + throw new Error("Could not fetch Minecraft versions"); } } catch { logm.warn(`Could not fetch Minecraft versions. Using fallbacks.`); @@ -155,9 +178,9 @@ export async function getMinecraftVersions() { /** * Fetch Modloaders from Modrinth - * @returns {Promise>} The Modloaders + * @returns the modloaders */ -export async function getModloaders() { +export async function getModloaders(): Promise { try { const url = config.MODRINTH_MODLOADERS_ENDPOINT; const response = await fetch(url, { @@ -170,11 +193,14 @@ export async function getModloaders() { throw new Error(`Modrinth API error (${response.status}): ${errorText}`); } - const json = await response.json(); + const json = (await response.json()) as ModloaderResponseItem[]; if (json) { - return json.map((loader) => ({title: loader.name, value: loader.name})); + return json.map((loader) => ({ + title: loader.name, + value: loader.name, + })); } else { - throw new Error(); + throw new Error("Could not fetch Modloaders"); } } catch { logm.warn(`Could not fetch Modloaders. Using fallbacks.`); From 2c27233f809d49819736d221c95afb2a30fa44d3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 00:43:54 -0500 Subject: [PATCH 017/110] move github license responses to own file --- src/github_interactions.ts | 16 +++++----------- src/types/githubResponses.ts | 8 ++++++++ src/types/index.ts | 1 + 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 src/types/githubResponses.ts diff --git a/src/github_interactions.ts b/src/github_interactions.ts index 4c0a350..0c78ed0 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -1,15 +1,7 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; -import type { Choice } from "prompts"; - -type LicenseResponseItem = { - spdx_id: string; - key: string; -}; - -type LicenseTextResponse = { - body: string; -}; +import type {Choice} from "prompts"; +import type {LicenseResponseItem, LicenseTextResponse} from "./types/githubResponses.js"; /** * Fetch a list of the most popular licenses from GitHub @@ -31,7 +23,9 @@ export async function getLicenseList(featured: boolean = false) { } const licenseList: LicenseResponseItem[] = (await response.json()) as LicenseResponseItem[]; - let licenseSpdxIds: Choice[] = licenseList.map((license: LicenseResponseItem): Choice => ({title: license.spdx_id, value: license.key})); + let licenseSpdxIds: Choice[] = licenseList.map( + (license: LicenseResponseItem): Choice => ({title: license.spdx_id, value: license.key}), + ); if (!featured) { // get featured licenses and place them at the beginning of the list, removing them from the original list diff --git a/src/types/githubResponses.ts b/src/types/githubResponses.ts new file mode 100644 index 0000000..6da8533 --- /dev/null +++ b/src/types/githubResponses.ts @@ -0,0 +1,8 @@ +export type LicenseResponseItem = { + spdx_id: string; + key: string; +}; + +export type LicenseTextResponse = { + body: string; +}; diff --git a/src/types/index.ts b/src/types/index.ts index b91a694..5f483b8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,3 +2,4 @@ export type * from "./Lockfile.js"; export type * from "./ModpackInfo.js"; export type * from "./Options.js"; export type * from "./modrinthResponses.js"; +export type * from "./githubResponses.js"; From 8a61d0c01437d14f1baa9aecef5797600caf0d1a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:02:13 -0500 Subject: [PATCH 018/110] add FileEntry and ContentDirectory types --- src/types/ContentDirectory.ts | 4 ++++ src/types/FileEntry.ts | 6 ++++++ src/types/index.ts | 2 ++ 3 files changed, 12 insertions(+) create mode 100644 src/types/ContentDirectory.ts create mode 100644 src/types/FileEntry.ts diff --git a/src/types/ContentDirectory.ts b/src/types/ContentDirectory.ts new file mode 100644 index 0000000..d53533d --- /dev/null +++ b/src/types/ContentDirectory.ts @@ -0,0 +1,4 @@ +export type ContentDirectory = { + name: string; + path: string; +}; diff --git a/src/types/FileEntry.ts b/src/types/FileEntry.ts new file mode 100644 index 0000000..3021b8b --- /dev/null +++ b/src/types/FileEntry.ts @@ -0,0 +1,6 @@ +export type FileEntry = { + path: string; + fullPath: string; + hash: string; + category: string; +}; diff --git a/src/types/index.ts b/src/types/index.ts index 5f483b8..460be6b 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,3 +3,5 @@ export type * from "./ModpackInfo.js"; export type * from "./Options.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; +export type * from "./FileEntry.js"; +export type * from "./ContentDirectory.js"; From df468362b5c3da4d1d06612349fff6d77f69f265 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:02:23 -0500 Subject: [PATCH 019/110] fix import --- src/github_interactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github_interactions.ts b/src/github_interactions.ts index 0c78ed0..c7243ff 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -1,7 +1,7 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; import type {Choice} from "prompts"; -import type {LicenseResponseItem, LicenseTextResponse} from "./types/githubResponses.js"; +import type {LicenseResponseItem, LicenseTextResponse} from "./types/index.js"; /** * Fetch a list of the most popular licenses from GitHub From d7d79e4bd310de55ef3a35d8e0542ff985e646b8 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:03:00 -0500 Subject: [PATCH 020/110] add type support for directory scanning --- src/directory_scanning.ts | 46 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index a7656c1..4367b5b 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -3,19 +3,17 @@ import crypto from "crypto"; import path from "path"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; - -/** - * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type {ModpackInfo, Lockfile} from "./types/index.js"; +import type {ContentDirectory} from "./types/index.js"; +import type {FileEntry} from "./types/index.js"; /** * Get the directories to scan for modpack files * @param {string} directoryPath - The path to the directory to scan - * @returns {Array} The directories to scan + * @returns {ContentDirectory[]} The directories to scan */ -export function getScanDirectories(directoryPath) { - const scanDirectories = []; +export function getScanDirectories(directoryPath: string): ContentDirectory[] { + const scanDirectories: ContentDirectory[] = []; for (const category of config.DEPENDENCY_CATEGORIES) { scanDirectories.push({name: category, path: path.join(directoryPath, category)}); } @@ -25,7 +23,7 @@ export function getScanDirectories(directoryPath) { /** * Calculate SHA1 hash of a file */ -async function calculateSHA1(filePath) { +async function calculateSHA1(filePath: string): Promise { const fileBuffer = await fs.readFile(filePath); return crypto.createHash("sha1").update(fileBuffer).digest("hex"); } @@ -33,8 +31,8 @@ async function calculateSHA1(filePath) { /** * Find all files in a directory */ -async function findFiles(dirPath) { - const files = []; +async function findFiles(dirPath: string): Promise { + const files: string[] = []; try { const entries = await fs.readdir(dirPath, {withFileTypes: true}); @@ -45,8 +43,8 @@ async function findFiles(dirPath) { files.push(fullPath); } } - } catch (error) { - if (error.code !== "ENOENT") { + } catch (error: any) { + if (error?.code !== "ENOENT") { logm.warn(`Could not read directory ${dirPath}: ${error.message}`); } } @@ -58,9 +56,9 @@ async function findFiles(dirPath) { /** * Scan a directory and return file info with hashes */ -export async function scanDirectory(dirInfo, workspaceRoot) { +export async function scanDirectory(dirInfo: ContentDirectory, workspaceRoot: string): Promise { const files = await findFiles(dirInfo.path); - const fileEntries = []; + const fileEntries: FileEntry[] = []; for (const filePath of files) { try { @@ -73,8 +71,8 @@ export async function scanDirectory(dirInfo, workspaceRoot) { hash: hash, category: dirInfo.name, }); - } catch (error) { - logm.warn(`Could not hash file ${filePath}: ${error.message}`); + } catch (error: any) { + logm.error(`Could not hash file ${filePath}: ${error.message}`); } } @@ -84,14 +82,14 @@ export async function scanDirectory(dirInfo, workspaceRoot) { /** * Scan for existing JSON file and return the JSON object if it exists */ -async function getJsonFile(directoryPath, filename) { +async function getJsonFile(directoryPath: string, filename: string): Promise { const jsonPath = path.join(directoryPath, filename); // try to read the file try { const fileContent = await fs.readFile(jsonPath, "utf-8"); return JSON.parse(fileContent); - } catch (error) { - if (error.code !== "ENOENT") { + } catch (error: any) { + if (error?.code !== "ENOENT") { throw new Error(`Error: Could not read file ${jsonPath}: ${error.message}`, {cause: error}); } else { return null; @@ -102,17 +100,17 @@ async function getJsonFile(directoryPath, filename) { /** * Get the modpack info from the JSON file if it exists * @param {string} directoryPath - The path to the directory to scan - * @returns {Promise} The modpack info JSON object if the file exists, otherwise null + * @returns {Promise} The modpack info JSON object if the file exists, otherwise null */ -export async function getModpackInfo(directoryPath) { +export async function getModpackInfo(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_JSON_NAME); } /** * Get the lockfile file if it exists * @param {string} directoryPath - The path to the directory to scan - * @returns {Lockfile|null} The JSON object if the file exists, otherwise null + * @returns {Promise} The JSON object if the file exists, otherwise null */ -export async function getLockfile(directoryPath) { +export async function getLockfile(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_LOCKFILE_NAME); } From 8e18285d701e1c1d153b59f77c136f4d4c620b88 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:11:20 -0500 Subject: [PATCH 021/110] update options interfaces to have all optional fields --- src/types/Options.ts | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/types/Options.ts b/src/types/Options.ts index efc78b5..0798464 100644 --- a/src/types/Options.ts +++ b/src/types/Options.ts @@ -9,12 +9,12 @@ */ export interface Options { - dryRun: boolean; - quiet: boolean; - silent: boolean; - gitignore: boolean; - readme: boolean; - licenseFile: boolean; + dryRun?: boolean; + quiet?: boolean; + silent?: boolean; + gitignore?: boolean; + readme?: boolean; + licenseFile?: boolean; } /** * Contains options for the initialization of the modpack files. @@ -37,24 +37,24 @@ export interface Options { * @property {boolean} _init - Internal boolean added to indicate options come from the `init` command. */ -export interface InitOptions { - folder: string; - noninteractive: boolean; - addLicense: boolean; - addGitignore: boolean; - addReadme: boolean; - name: string; - version: string; - id: string; - description: string; - author: string; - projectUrl: string; - sourceUrl: string; - license: string; - modloader: string; - targetModloaderVersion: string; - targetMinecraftVersion: string; - _init: boolean; +export interface InitOptions extends Options { + folder?: string; + noninteractive?: boolean; + addLicense?: boolean; + addGitignore?: boolean; + addReadme?: boolean; + name?: string; + version?: string; + id?: string; + description?: string; + author?: string; + projectUrl?: string; + sourceUrl?: string; + license?: string; + modloader?: string; + targetModloaderVersion?: string; + targetMinecraftVersion?: string; + _init?: boolean; } /** @@ -64,8 +64,8 @@ export interface InitOptions { * @property {boolean} _run - Internal boolean added to indicate options come from the `run` command. */ -export interface RunOptions { - folder: string; - debug: boolean; - _run: boolean; +export interface RunOptions extends Options { + folder?: string; + debug?: boolean; + _run?: boolean; } From 615632d205a42a427cda0f7e11dd216f1e826635 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:12:02 -0500 Subject: [PATCH 022/110] fix logger options object --- src/logger.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index a531247..d4ba896 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,5 +1,6 @@ -import { styleText } from "node:util"; -import type { InspectColor } from "node:util"; +import {styleText} from "node:util"; +import type {InspectColor} from "node:util"; +import type {InitOptions, Options} from "./types/index.js"; class Logger { /** @@ -40,7 +41,7 @@ class Logger { this.silentConsole = silent; } - quietFromOptions(options: { silent: boolean, quiet: boolean }) { + quietFromOptions(options: InitOptions | Options) { if (options.silent) { this.quietConsole = true; this.silentConsole = true; From dfc675cb51aca1178a8260e53c506bdd3b36d13d Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:21:14 -0500 Subject: [PATCH 023/110] fix prompt version default --- src/modpack_info.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modpack_info.ts b/src/modpack_info.ts index 2c95592..99f60b9 100644 --- a/src/modpack_info.ts +++ b/src/modpack_info.ts @@ -161,7 +161,7 @@ export async function promptUserForInfo(defaults: ModpackInfo) { config.infoFields.targetMinecraftVersion.prompt, defaults.targetMinecraftVersion, minecraftVersions, - minecraftVersions[0].value, + minecraftVersions[0]?.value || "", ), ], config.PROMPTS_OPTIONS, From 606300478b20743367decd462da89b1c1bce828b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 01:21:45 -0500 Subject: [PATCH 024/110] add type support to generateLicense --- src/generate_license.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/generate_license.ts b/src/generate_license.ts index 96ce9b6..ebaf6c6 100644 --- a/src/generate_license.ts +++ b/src/generate_license.ts @@ -3,14 +3,9 @@ import path from "path"; import {getLicenseText} from "./github_interactions.js"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; +import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; -/** - * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - */ - -async function writeLicense(licenseText, outputPath) { +async function writeLicense(licenseText: string, outputPath: string) { await fs.writeFile(path.join(outputPath, config.MODPACK_LICENSE_NAME), licenseText, "utf-8"); logm.generated(config.MODPACK_LICENSE_NAME, path.join(outputPath, config.MODPACK_LICENSE_NAME)); } @@ -23,15 +18,24 @@ async function writeLicense(licenseText, outputPath) { * @param {string} licenseTextOverride - The license text to override the default license text with * @returns {Promise | null} The license text or null if the license text could not be generated */ -export default async function generateLicense(modpackInfo, workingDir, options = {}, licenseTextOverride = null) { +export default async function generateLicense( + modpackInfo: ModpackInfo, + workingDir: string, + options: Options | InitOptions = {}, + licenseTextOverride: string | null = null, +): Promise { logm.quietFromOptions(options); try { const spdxId = modpackInfo.license; let licenseText = licenseTextOverride || (await getLicenseText(spdxId)); - licenseText = licenseText.replace("[year]", new Date().getFullYear()); - licenseText = licenseText.replace("{{year}}", new Date().getFullYear()); + if (!licenseText) { + throw new Error(`License text could not be generated for: ${spdxId}`); + } + + licenseText = licenseText.replace("[year]", String(new Date().getFullYear())); + licenseText = licenseText.replace("{{year}}", String(new Date().getFullYear())); licenseText = licenseText.replace("[fullname]", modpackInfo.author); licenseText = licenseText.replace("{{fullname}}", modpackInfo.author); licenseText = licenseText.replace("[organization]", modpackInfo.author); From 0904fe4fa035a9295c8b26e85e6b60cbaf533df2 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 02:09:01 -0500 Subject: [PATCH 025/110] rename/combine fileentry with contentdirectory to contentfile --- src/directory_scanning.ts | 6 +++--- src/types/ContentDirectory.ts | 4 ---- src/types/FileEntry.ts | 6 ------ src/types/contentFiles.ts | 11 +++++++++++ src/types/index.ts | 3 +-- 5 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 src/types/ContentDirectory.ts delete mode 100644 src/types/FileEntry.ts create mode 100644 src/types/contentFiles.ts diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index 4367b5b..ab2d66a 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -5,7 +5,7 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; import type {ModpackInfo, Lockfile} from "./types/index.js"; import type {ContentDirectory} from "./types/index.js"; -import type {FileEntry} from "./types/index.js"; +import type {ContentFile} from "./types/index.js"; /** * Get the directories to scan for modpack files @@ -56,9 +56,9 @@ async function findFiles(dirPath: string): Promise { /** * Scan a directory and return file info with hashes */ -export async function scanDirectory(dirInfo: ContentDirectory, workspaceRoot: string): Promise { +export async function scanDirectory(dirInfo: ContentDirectory, workspaceRoot: string): Promise { const files = await findFiles(dirInfo.path); - const fileEntries: FileEntry[] = []; + const fileEntries: ContentFile[] = []; for (const filePath of files) { try { diff --git a/src/types/ContentDirectory.ts b/src/types/ContentDirectory.ts deleted file mode 100644 index d53533d..0000000 --- a/src/types/ContentDirectory.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type ContentDirectory = { - name: string; - path: string; -}; diff --git a/src/types/FileEntry.ts b/src/types/FileEntry.ts deleted file mode 100644 index 3021b8b..0000000 --- a/src/types/FileEntry.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type FileEntry = { - path: string; - fullPath: string; - hash: string; - category: string; -}; diff --git a/src/types/contentFiles.ts b/src/types/contentFiles.ts new file mode 100644 index 0000000..0360fb2 --- /dev/null +++ b/src/types/contentFiles.ts @@ -0,0 +1,11 @@ +export type ContentDirectory = { + name: string; + path: string; +}; + +export type ContentFile = { + path: string; + fullPath: string; + hash: string; + category: string; +}; diff --git a/src/types/index.ts b/src/types/index.ts index 460be6b..574243e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,5 +3,4 @@ export type * from "./ModpackInfo.js"; export type * from "./Options.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; -export type * from "./FileEntry.js"; -export type * from "./ContentDirectory.js"; +export type * from "./contentFiles.js"; From 627fd5be7b49ffb4dcf187f2acbdd5bc09a187c1 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 02:09:18 -0500 Subject: [PATCH 026/110] fix lockfile dep types --- src/types/Lockfile.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 0dd041a..4c4abf9 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -1,3 +1,5 @@ +import type {VersionResponseItem} from "./index.js"; + /** * Contains information about the modpack dependencies and their versions. * @property version - The version of the modpack @@ -25,9 +27,14 @@ export type Lockfile = { shaderpacks: number; }; dependencies: { - mods: string[]; - resourcepacks: string[]; - datapacks: string[]; - shaderpacks: string[]; + mods: DependencyCategory[]; + resourcepacks: DependencyCategory[]; + datapacks: DependencyCategory[]; + shaderpacks: DependencyCategory[]; }; }; + +export type DependencyCategory = { + path: string; + version: VersionResponseItem | null; +}; From 3cc96ce190066f730df8a4678cbacffb24bea8a6 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 02:29:32 -0500 Subject: [PATCH 027/110] update dependencies file to use new type --- src/types/modrinthResponses.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 84a7401..6a9121f 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -1,3 +1,10 @@ +export type DependencyResponseItem = { + version_id: string; + project_id: string; + file_name: string; + dependency_type: string; +}; + export type VersionResponseItem = { id: string; project_id: string; @@ -15,7 +22,7 @@ export type VersionResponseItem = { version_type?: string; status?: string; requested_status?: string | null; - dependencies?: any[]; + dependencies?: DependencyResponseItem[]; }; export type ProjectResponseItem = { From 209731aa15620733c754425e3e6eaa2913773ba3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 02:36:09 -0500 Subject: [PATCH 028/110] add type support to readme generation --- src/generate_readme.ts | 102 ++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 57ab603..3520a0c 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -4,29 +4,43 @@ import {getProjects, getUsers} from "./modrinth_interactions.js"; import {getScanDirectories} from "./directory_scanning.js"; import * as config from "./config/index.js"; import {logm, styleText} from "./logger.js"; - -/** - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type { + Options, + InitOptions, + Lockfile, + ProjectResponseItem, + UserResponseItem, + DependencyCategory, + ContentDirectory, +} from "./types/index.js"; /** * Generate README.md content for a category */ -function generateCategoryReadme(category, entries, projectsMap, usersMap) { - const categoryTitle = category.charAt(0).toUpperCase() + category.slice(1); - const lines = [`# ${categoryTitle}`, "", "| Name | Author | Version | Dependencies | Dependants |", "|-|-|-|-|-|"]; +function generateCategoryReadme( + category: string, + entries: DependencyCategory[], + projectsMap: Record, + usersMap: Record, +): string { + const categoryTitle: string = category.charAt(0).toUpperCase() + category.slice(1); + const lines: string[] = [ + `# ${categoryTitle}`, + "", + "| Name | Author | Version | Dependencies | Dependents |", + "|-|-|-|-|-|", + ]; // Map category to Modrinth URL path segment - const categoryPathMap = {}; + const categoryPathMap: Record = {}; for (const cat of config.DEPENDENCY_CATEGORIES) { categoryPathMap[cat] = cat === "shaderpacks" ? "shader" : cat.toLowerCase().slice(0, -1); } - const categoryPath = categoryPathMap[category] || "project"; + const categoryPath: string = categoryPathMap[category] || "project"; // Build a set of project_ids present in this category for filtering dependencies - const categoryProjectIds = new Set(); + const categoryProjectIds: Set = new Set(); + for (const entry of entries) { if (entry.version && entry.version.project_id) { categoryProjectIds.add(entry.version.project_id); @@ -35,11 +49,11 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { for (const entry of entries) { const version = entry.version; - let nameCell; - let authorCell; - let versionCell; - let dependenciesCell; - let dependantsCell; + let nameCell: string; + let authorCell: string; + let versionCell: string; + let dependenciesCell: string; + let dependentsCell: string; if (version && version.project_id) { const project = projectsMap[version.project_id]; @@ -47,8 +61,8 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { // Name column with icon and link if (project) { - const projectName = project.title || project.slug || "Unknown"; - const projectSlug = project.slug || project.id; + const projectName: string = project.title || project.slug || "Unknown"; + const projectSlug: string = project.slug || project.id; const projectUrl = `https://modrinth.com/${categoryPath}/${projectSlug}`; if (project.icon_url) { @@ -58,13 +72,13 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { } } else { // Project not found, use filename - const fileName = path.basename(entry.path); + const fileName: string = path.basename(entry.path); nameCell = fileName; } // Author column with avatar and link if (author) { - const authorName = author.username || "Unknown"; + const authorName: string = author.username || "Unknown"; const authorUrl = `https://modrinth.com/user/${authorName}`; if (author.avatar_url) { @@ -81,13 +95,13 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { // Dependencies column - only show dependencies that are present in this category if (version.dependencies && Array.isArray(version.dependencies) && version.dependencies.length > 0) { - const dependencyLinks = []; + const dependencyLinks: string[] = []; for (const dep of version.dependencies) { if (dep.project_id && categoryProjectIds.has(dep.project_id)) { const depProject = projectsMap[dep.project_id]; if (depProject) { - const depProjectName = depProject.title || depProject.slug || "Unknown"; - const depProjectSlug = depProject.slug || depProject.id; + const depProjectName: string = depProject.title || depProject.slug || "Unknown"; + const depProjectSlug: string = depProject.slug || depProject.id; const depUrl = `https://modrinth.com/${categoryPath}/${depProjectSlug}`; if (depProject.icon_url) { dependencyLinks.push( @@ -104,8 +118,8 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { dependenciesCell = "-"; } - // Dependants column - find all entries in the same category that depend on this project - const dependants = []; + // Dependents column - find all entries in the same category that depend on this project + const dependents: string[] = []; for (const catEntry of entries) { // Skip if this is the same entry (same project_id) if (catEntry.version && catEntry.version.project_id === version.project_id) { @@ -118,32 +132,32 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { if (hasDependency) { const depProject = projectsMap[catEntry.version.project_id]; if (depProject) { - const depProjectName = depProject.title || depProject.slug || "Unknown"; - const depProjectSlug = depProject.slug || depProject.id; + const depProjectName: string = depProject.title || depProject.slug || "Unknown"; + const depProjectSlug: string = depProject.slug || depProject.id; const depUrl = `https://modrinth.com/${categoryPath}/${depProjectSlug}`; if (depProject.icon_url) { - dependants.push( + dependents.push( `${depProjectName}`, ); } else { - dependants.push(`[${depProjectName}](${depUrl})`); + dependents.push(`[${depProjectName}](${depUrl})`); } } } } } - dependantsCell = dependants.length > 0 ? dependants.join(" ") : "-"; + dependentsCell = dependents.length > 0 ? dependents.join(" ") : "-"; } else { // File not found on Modrinth - const fileName = path.basename(entry.path); + const fileName: string = path.basename(entry.path); nameCell = fileName; authorCell = "Unknown"; versionCell = "-"; dependenciesCell = "-"; - dependantsCell = "-"; + dependentsCell = "-"; } - lines.push(`| ${nameCell} | ${authorCell} | ${versionCell} | ${dependenciesCell} | ${dependantsCell} |`); + lines.push(`| ${nameCell} | ${authorCell} | ${versionCell} | ${dependenciesCell} | ${dependentsCell} |`); } return lines.join("\n") + "\n"; @@ -155,14 +169,14 @@ function generateCategoryReadme(category, entries, projectsMap, usersMap) { * @param {string} workingDir - The working directory * @param {Options | InitOptions} options - The options object */ -export async function generateReadmeFiles(lockfile, workingDir, options = {}) { +export async function generateReadmeFiles(lockfile: Lockfile, workingDir: string, options: Options | InitOptions = {}) { logm.quietFromOptions(options); // Collect unique project IDs and author IDs from version data - const projectIds = new Set(); - const authorIds = new Set(); + const projectIds = new Set(); + const authorIds = new Set(); - for (const [, entries] of Object.entries(lockfile.dependencies)) { + for (const entries of Object.values(lockfile.dependencies)) { for (const entry of entries) { if (entry.version && entry.version.project_id) { projectIds.add(entry.version.project_id); @@ -187,12 +201,12 @@ export async function generateReadmeFiles(lockfile, workingDir, options = {}) { const [projects, users] = await Promise.all([getProjects(Array.from(projectIds)), getUsers(Array.from(authorIds))]); // Map projects and users to their IDs - const projectsMap = {}; + const projectsMap: Record = {}; for (const project of projects) { projectsMap[project.id] = project; } - const usersMap = {}; + const usersMap: Record = {}; for (const user of users) { usersMap[user.id] = user; } @@ -203,8 +217,10 @@ export async function generateReadmeFiles(lockfile, workingDir, options = {}) { continue; } - const readmeContent = generateCategoryReadme(category, entries, projectsMap, usersMap); - const categoryDir = getScanDirectories(workingDir).find((d) => d.name === category); + const readmeContent: string = generateCategoryReadme(category, entries, projectsMap, usersMap); + const categoryDir: ContentDirectory | undefined = getScanDirectories(workingDir).find( + (d) => d.name === category, + ); if (categoryDir) { const readmePath = path.join(categoryDir.path, config.README_NAME); @@ -215,7 +231,7 @@ export async function generateReadmeFiles(lockfile, workingDir, options = {}) { try { await fs.writeFile(readmePath, readmeContent, "utf-8"); logm.generated(config.README_NAME, readmePath); - } catch (error) { + } catch (error: any) { logm.warn(`Could not write ${config.README_NAME} file to ${readmePath}: ${error.message}`); } } From c652c6fb95c3dc7c1c591380862e183d2698ed27 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 11:59:09 -0500 Subject: [PATCH 029/110] add type support to license generation --- src/generate_gitignore.ts | 49 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/generate_gitignore.ts b/src/generate_gitignore.ts index 870218f..2b4ee62 100644 --- a/src/generate_gitignore.ts +++ b/src/generate_gitignore.ts @@ -2,12 +2,7 @@ import fs from "fs/promises"; import path from "path"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; - -/** - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type {Lockfile, Options, InitOptions} from "./types/index.js"; /** * Generate .gitignore rules for files not hosted on Modrinth and write them to .gitignore file @@ -15,11 +10,15 @@ import {logm} from "./logger.js"; * @param {string} workingDir - The working directory * @param {Options | InitOptions} options - The options object */ -export async function generateGitignoreRules(lockfile, workingDir, options = {}) { +export async function generateGitignoreRules( + lockfile: Lockfile, + workingDir: string, + options: Options | InitOptions = {}, +) { logm.quietFromOptions(options); - const rules = []; - const exceptions = []; + const rules: string[] = []; + const exceptions: string[] = []; // Base ignore patterns for each category for (const category of config.DEPENDENCY_CATEGORIES) { @@ -42,37 +41,37 @@ export async function generateGitignoreRules(lockfile, workingDir, options = {}) rules.push(...exceptions); } - const rulesContent = rules.join("\n"); - const gitignorePath = path.join(workingDir, config.GITIGNORE_NAME); + const rulesContent: string = rules.join("\n"); + const gitignorePath: string = path.join(workingDir, config.GITIGNORE_NAME); // Read existing .gitignore file if it exists - let existingContent = ""; + let existingContent: string = ""; try { existingContent = await fs.readFile(gitignorePath, "utf-8"); - } catch (error) { + } catch (error: any) { // File doesn't exist, that's okay - we'll create it - if (error.code !== "ENOENT") { + if (error?.code !== "ENOENT") { logm.warn(`Could not read ${config.GITIGNORE_NAME} file: ${error.message}`); return; } } // Find markers in existing content - const startMarkerIndex = existingContent.indexOf(config.GITIGNORE_START_MARKER); - const endMarkerIndex = existingContent.indexOf(config.GITIGNORE_END_MARKER); + const startMarkerIndex: number = existingContent.indexOf(config.GITIGNORE_START_MARKER); + const endMarkerIndex: number = existingContent.indexOf(config.GITIGNORE_END_MARKER); - let newContent; + let newContent: string; if (startMarkerIndex !== -1 && endMarkerIndex !== -1 && endMarkerIndex > startMarkerIndex) { // Both markers exist, replace content between them - const beforeSection = existingContent.substring(0, startMarkerIndex); - const afterSection = existingContent.substring(endMarkerIndex + config.GITIGNORE_END_MARKER.length); + const beforeSection: string = existingContent.substring(0, startMarkerIndex); + const afterSection: string = existingContent.substring(endMarkerIndex + config.GITIGNORE_END_MARKER.length); // Remove trailing newlines from before section and leading newlines from after section - const beforeTrimmed = beforeSection.replace(/\n+$/, ""); - const afterTrimmed = afterSection.replace(/^\n+/, ""); + const beforeTrimmed: string = beforeSection.replace(/\n+$/, ""); + const afterTrimmed: string = afterSection.replace(/^\n+/, ""); - const parts = [beforeTrimmed]; + const parts: string[] = [beforeTrimmed]; if (beforeTrimmed) parts.push(""); // Add separator if there's content before parts.push(config.GITIGNORE_START_MARKER, rulesContent, config.GITIGNORE_END_MARKER); if (afterTrimmed) { @@ -83,7 +82,7 @@ export async function generateGitignoreRules(lockfile, workingDir, options = {}) newContent = parts.join("\n"); } else if (startMarkerIndex !== -1 || endMarkerIndex !== -1) { // Only one marker exists, append to end - const trimmed = existingContent.replace(/\n+$/, ""); + const trimmed: string = existingContent.replace(/\n+$/, ""); newContent = [trimmed, "", config.GITIGNORE_START_MARKER, rulesContent, config.GITIGNORE_END_MARKER].join("\n"); } else { // No markers exist, append to end @@ -92,7 +91,7 @@ export async function generateGitignoreRules(lockfile, workingDir, options = {}) newContent = [config.GITIGNORE_START_MARKER, rulesContent, config.GITIGNORE_END_MARKER].join("\n"); } else { // File has content, append with newline - const trimmed = existingContent.replace(/\n+$/, ""); + const trimmed: string = existingContent.replace(/\n+$/, ""); newContent = [trimmed, "", config.GITIGNORE_START_MARKER, rulesContent, config.GITIGNORE_END_MARKER].join( "\n", ); @@ -106,7 +105,7 @@ export async function generateGitignoreRules(lockfile, workingDir, options = {}) try { await fs.writeFile(gitignorePath, newContent, "utf-8"); logm.generated(config.GITIGNORE_NAME, gitignorePath); - } catch (error) { + } catch (error: any) { logm.warn(`Could not write ${config.GITIGNORE_NAME} file: ${error.message}`); } } From b3d3ddd000c46b4ab3cc5ad333f9d4d00d511adf Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 13:44:41 -0500 Subject: [PATCH 030/110] fix Lockfile dependency types --- src/types/Lockfile.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 4c4abf9..0861b35 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -21,20 +21,22 @@ export type Lockfile = { generated: string; total: number; counts: { - mods: number; - resourcepacks: number; - datapacks: number; - shaderpacks: number; + mods?: number; + resourcepacks?: number; + datapacks?: number; + shaderpacks?: number; }; dependencies: { - mods: DependencyCategory[]; - resourcepacks: DependencyCategory[]; - datapacks: DependencyCategory[]; - shaderpacks: DependencyCategory[]; + mods?: LockfileDependencyEntry[]; + resourcepacks?: LockfileDependencyEntry[]; + datapacks?: LockfileDependencyEntry[]; + shaderpacks?: LockfileDependencyEntry[]; }; }; -export type DependencyCategory = { +export type LockfileDependencyCategory = keyof Lockfile["dependencies"]; + +export type LockfileDependencyEntry = { path: string; version: VersionResponseItem | null; }; From 083d2a0d2edf54dbdaf8dcda493b00a8b54ccf38 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 13:45:15 -0500 Subject: [PATCH 031/110] update readme generation dep category var name --- src/generate_readme.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 3520a0c..63c1462 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -10,7 +10,7 @@ import type { Lockfile, ProjectResponseItem, UserResponseItem, - DependencyCategory, + LockfileDependencyEntry, ContentDirectory, } from "./types/index.js"; @@ -19,7 +19,7 @@ import type { */ function generateCategoryReadme( category: string, - entries: DependencyCategory[], + entries: LockfileDependencyEntry[], projectsMap: Record, usersMap: Record, ): string { From b90228d7a8464ac105532a2b474a3687d7c2cd7f Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 13:59:48 -0500 Subject: [PATCH 032/110] add void returns for generateGitignoreRules and generateReadmeFiles --- src/generate_gitignore.ts | 2 +- src/generate_readme.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/generate_gitignore.ts b/src/generate_gitignore.ts index 2b4ee62..09c97d0 100644 --- a/src/generate_gitignore.ts +++ b/src/generate_gitignore.ts @@ -14,7 +14,7 @@ export async function generateGitignoreRules( lockfile: Lockfile, workingDir: string, options: Options | InitOptions = {}, -) { +): Promise { logm.quietFromOptions(options); const rules: string[] = []; diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 63c1462..94e37cb 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -169,7 +169,11 @@ function generateCategoryReadme( * @param {string} workingDir - The working directory * @param {Options | InitOptions} options - The options object */ -export async function generateReadmeFiles(lockfile: Lockfile, workingDir: string, options: Options | InitOptions = {}) { +export async function generateReadmeFiles( + lockfile: Lockfile, + workingDir: string, + options: Options | InitOptions = {}, +): Promise { logm.quietFromOptions(options); // Collect unique project IDs and author IDs from version data From f99eee9d2604105c436332579bc4e1179299f2f3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:01:01 -0500 Subject: [PATCH 033/110] update DEPENDENCY_CATEGORIES and MODPACK_INFO... constant types --- src/config/constants.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/config/constants.ts b/src/config/constants.ts index 4dceb7d..d8534ee 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,4 +1,5 @@ import pkg from "../../package.json" with {type: "json"}; +import type {LockfileDependencyCategory, ModpackInfo} from "../types/index.js"; /** Author username */ export const AUTHOR_USERNAME: string = "nickesc"; @@ -7,7 +8,7 @@ export const AUTHOR_USERNAME: string = "nickesc"; export const LOCKFILE_VERSION: string = "1.0.1"; /** Required fields for the modpack information */ -export const MODPACK_INFO_REQUIRED_FIELDS: string[] = [ +export const MODPACK_INFO_REQUIRED_FIELDS: (keyof ModpackInfo)[] = [ "name", // "version", "id", @@ -17,7 +18,7 @@ export const MODPACK_INFO_REQUIRED_FIELDS: string[] = [ ]; /** Dependency categories, corresponds to folders in Minecraft profile */ -export const DEPENDENCY_CATEGORIES: string[] = [ +export const DEPENDENCY_CATEGORIES: LockfileDependencyCategory[] = [ "mods", // "resourcepacks", "shaderpacks", From 18cc53c506a68e0aedbe84c27591713dec41cd65 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:01:17 -0500 Subject: [PATCH 034/110] add jsonfile type --- src/types/Jsonfile.ts | 20 ++++++++++++++++++++ src/types/index.ts | 1 + 2 files changed, 21 insertions(+) create mode 100644 src/types/Jsonfile.ts diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts new file mode 100644 index 0000000..35cb610 --- /dev/null +++ b/src/types/Jsonfile.ts @@ -0,0 +1,20 @@ +import type {LockfileDependencyCategory} from "./Lockfile.js"; + +export type Jsonfile = { + name: string; + version: string; + id: string; + description: string; + author: string; + projectUrl: string; + sourceUrl: string; + license: string; + modloader: string; + targetModloaderVersion: string; + targetMinecraftVersion: string; + dependencies: Record; + scripts?: { + [key: string]: string; + }; + [key: string]: unknown; +}; diff --git a/src/types/index.ts b/src/types/index.ts index 574243e..4d6a3c5 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,5 @@ export type * from "./Lockfile.js"; +export type * from "./Jsonfile.js"; export type * from "./ModpackInfo.js"; export type * from "./Options.js"; export type * from "./modrinthResponses.js"; From 8e6493f81632e556dfdd9a857f71fc33155228c5 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:01:58 -0500 Subject: [PATCH 035/110] add type support for jsonfile generation --- src/generate_json.ts | 72 ++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/src/generate_json.ts b/src/generate_json.ts index bd38ad4..d2e63f5 100644 --- a/src/generate_json.ts +++ b/src/generate_json.ts @@ -3,18 +3,15 @@ import path from "path"; import {getProjects} from "./modrinth_interactions.js"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; - -/** - * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type {ModpackInfo, Lockfile, Jsonfile, Options, InitOptions, LockfileDependencyCategory} from "./types/index.js"; /** * Create a JSON object from the modpack information and dependencies */ -function createModpackJson(modpackInfo, dependencies) { +function createModpackJson( + modpackInfo: ModpackInfo, + dependencies: Record, +): Jsonfile { return { ...modpackInfo, dependencies: dependencies, @@ -24,8 +21,8 @@ function createModpackJson(modpackInfo, dependencies) { /** * Write modpack.json to disk */ -async function writeJson(jsonObject, outputPath) { - const content = JSON.stringify(jsonObject, null, 2); +async function writeJson(jsonObject: Jsonfile, outputPath: string): Promise { + const content: string = JSON.stringify(jsonObject, null, 2); await fs.writeFile(path.join(outputPath, config.MODPACK_JSON_NAME), content, "utf-8"); logm.generated(config.MODPACK_JSON_NAME, path.join(outputPath, config.MODPACK_JSON_NAME)); } @@ -38,36 +35,51 @@ async function writeJson(jsonObject, outputPath) { * @param {Options | InitOptions} options - The options object * @returns {Promise} The JSON file's object */ -export default async function generateJson(modpackInfo, lockfile, workingDir, options = {}) { +export default async function generateJson( + modpackInfo: ModpackInfo, + lockfile: Lockfile, + workingDir: string, + options: Options | InitOptions = {}, +): Promise { logm.quietFromOptions(options); // Validate modpack info for (const field of config.MODPACK_INFO_REQUIRED_FIELDS) { - if (!modpackInfo[field]) { + if (!modpackInfo[field as keyof ModpackInfo]) { throw new Error(`Modpack info is missing required field: ${field}`); } } - const projectIds = {}; - const packDependencies = {}; - for (const category of config.DEPENDENCY_CATEGORIES) { - projectIds[category] = new Set(); - packDependencies[category] = []; - } + //TODO: consider changing these to partial records and only initializing the categories that are present in the lockfile + const projectIds: Record> = { + mods: new Set(), + resourcepacks: new Set(), + datapacks: new Set(), + shaderpacks: new Set(), + }; + const packDependencies: Record = { + mods: [], + resourcepacks: [], + datapacks: [], + shaderpacks: [], + }; // Collect project IDs from lockfile if (lockfile) if (lockfile.dependencies) { - for (const [category, entries] of Object.entries(lockfile.dependencies)) { - for (const entry of entries) { - if (entry.version && entry.version.project_id) { - projectIds[category].add(entry.version.project_id); - } else { - packDependencies[category].push(entry.path); + for (const category of config.DEPENDENCY_CATEGORIES) { + if (lockfile.dependencies[category]) { + // TODO: consider initializing the categories with an empty array/set here + for (const entry of lockfile.dependencies[category]) { + if (entry.version && entry.version.project_id) { + projectIds[category].add(entry.version.project_id); + } else { + packDependencies[category].push(entry.path); + } } } } - const allProjectIds = new Set(); + const allProjectIds: Set = new Set(); for (const category of config.DEPENDENCY_CATEGORIES) { for (const projectId of projectIds[category]) { allProjectIds.add(projectId); @@ -76,15 +88,17 @@ export default async function generateJson(modpackInfo, lockfile, workingDir, op // Fetch projects from Modrinth const projects = await getProjects(Array.from(allProjectIds)); - const projectsMap = {}; + const projectsMap: Record = {}; for (const project of projects) { - projectsMap[project.id] = project.slug; + if (project.id || project.slug) { + projectsMap[project.id] = project.slug || project.id; + } } // Add projects to dependencies by category for (const category of config.DEPENDENCY_CATEGORIES) { for (const projectId of projectIds[category]) { - const projectSlug = projectsMap[projectId]; + const projectSlug: string | undefined = projectsMap[projectId]; if (projectSlug) { packDependencies[category].push(projectSlug); } @@ -93,7 +107,7 @@ export default async function generateJson(modpackInfo, lockfile, workingDir, op } // Create modpack JSON object - const jsonObject = createModpackJson(modpackInfo, packDependencies); + const jsonObject: Jsonfile = createModpackJson(modpackInfo, packDependencies); // Write modpack JSON object to disk if (options.dryRun) { From 9dfa06790513337f0bb008709552025340c918e1 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:07:52 -0500 Subject: [PATCH 036/110] retype counts to be tied to dep categories --- src/types/Lockfile.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 0861b35..5105e0c 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -20,12 +20,7 @@ export type Lockfile = { version: string; generated: string; total: number; - counts: { - mods?: number; - resourcepacks?: number; - datapacks?: number; - shaderpacks?: number; - }; + counts: Partial>; dependencies: { mods?: LockfileDependencyEntry[]; resourcepacks?: LockfileDependencyEntry[]; From 845130def3f41b35110dc09b958f6dc9e6200886 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:18:14 -0500 Subject: [PATCH 037/110] rename LockfileDependencyCategory to DependencyCategory --- src/config/constants.ts | 4 ++-- src/generate_json.ts | 10 +++++----- src/types/Jsonfile.ts | 4 ++-- src/types/Lockfile.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/config/constants.ts b/src/config/constants.ts index d8534ee..4bf2fb7 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,5 +1,5 @@ import pkg from "../../package.json" with {type: "json"}; -import type {LockfileDependencyCategory, ModpackInfo} from "../types/index.js"; +import type {DependencyCategory, ModpackInfo} from "../types/index.js"; /** Author username */ export const AUTHOR_USERNAME: string = "nickesc"; @@ -18,7 +18,7 @@ export const MODPACK_INFO_REQUIRED_FIELDS: (keyof ModpackInfo)[] = [ ]; /** Dependency categories, corresponds to folders in Minecraft profile */ -export const DEPENDENCY_CATEGORIES: LockfileDependencyCategory[] = [ +export const DEPENDENCY_CATEGORIES: DependencyCategory[] = [ "mods", // "resourcepacks", "shaderpacks", diff --git a/src/generate_json.ts b/src/generate_json.ts index d2e63f5..86eb643 100644 --- a/src/generate_json.ts +++ b/src/generate_json.ts @@ -3,14 +3,14 @@ import path from "path"; import {getProjects} from "./modrinth_interactions.js"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; -import type {ModpackInfo, Lockfile, Jsonfile, Options, InitOptions, LockfileDependencyCategory} from "./types/index.js"; +import type {ModpackInfo, Lockfile, Jsonfile, Options, InitOptions, DependencyCategory} from "./types/index.js"; /** * Create a JSON object from the modpack information and dependencies */ function createModpackJson( - modpackInfo: ModpackInfo, - dependencies: Record, + modpackInfo: ModpackInfo, // + dependencies: Record, ): Jsonfile { return { ...modpackInfo, @@ -51,13 +51,13 @@ export default async function generateJson( } //TODO: consider changing these to partial records and only initializing the categories that are present in the lockfile - const projectIds: Record> = { + const projectIds: Record> = { mods: new Set(), resourcepacks: new Set(), datapacks: new Set(), shaderpacks: new Set(), }; - const packDependencies: Record = { + const packDependencies: Record = { mods: [], resourcepacks: [], datapacks: [], diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index 35cb610..a3d936f 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,4 +1,4 @@ -import type {LockfileDependencyCategory} from "./Lockfile.js"; +import type {DependencyCategory} from "./Lockfile.js"; export type Jsonfile = { name: string; @@ -12,7 +12,7 @@ export type Jsonfile = { modloader: string; targetModloaderVersion: string; targetMinecraftVersion: string; - dependencies: Record; + dependencies: Record; scripts?: { [key: string]: string; }; diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 5105e0c..97362ff 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -20,7 +20,7 @@ export type Lockfile = { version: string; generated: string; total: number; - counts: Partial>; + counts: Partial>; dependencies: { mods?: LockfileDependencyEntry[]; resourcepacks?: LockfileDependencyEntry[]; @@ -29,7 +29,7 @@ export type Lockfile = { }; }; -export type LockfileDependencyCategory = keyof Lockfile["dependencies"]; +export type DependencyCategory = keyof Lockfile["dependencies"]; export type LockfileDependencyEntry = { path: string; From cfaef00ad3654f48eb9f2ba7828bbff98d758950 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:20:34 -0500 Subject: [PATCH 038/110] add explicit MinecraftVersionType type and swap constant to only order --- src/config/constants.ts | 4 ++-- src/modrinth_interactions.ts | 4 ++-- src/types/modrinthResponses.ts | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/config/constants.ts b/src/config/constants.ts index 4bf2fb7..d9d58f3 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -1,5 +1,5 @@ import pkg from "../../package.json" with {type: "json"}; -import type {DependencyCategory, ModpackInfo} from "../types/index.js"; +import type {DependencyCategory, MinecraftVersionType, ModpackInfo} from "../types/index.js"; /** Author username */ export const AUTHOR_USERNAME: string = "nickesc"; @@ -26,7 +26,7 @@ export const DEPENDENCY_CATEGORIES: DependencyCategory[] = [ ]; /** Minecraft version types */ -export const MINECRAFT_VERSION_TYPES: string[] = [ +export const MINECRAFT_VERSION_TYPE_ORDER: MinecraftVersionType[] = [ "release", // "alpha", "beta", diff --git a/src/modrinth_interactions.ts b/src/modrinth_interactions.ts index 5476373..22674de 100644 --- a/src/modrinth_interactions.ts +++ b/src/modrinth_interactions.ts @@ -159,8 +159,8 @@ export async function getMinecraftVersions(): Promise { //sort by version type (in the order of the MINECRAFT_VERSION_TYPES array) json.sort((a, b) => { return ( - config.MINECRAFT_VERSION_TYPES.indexOf(a.version_type) - - config.MINECRAFT_VERSION_TYPES.indexOf(b.version_type) + config.MINECRAFT_VERSION_TYPE_ORDER.indexOf(a.version_type) - + config.MINECRAFT_VERSION_TYPE_ORDER.indexOf(b.version_type) ); }); return json.map((version) => ({ diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 6a9121f..931fc66 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -64,9 +64,11 @@ export type ProjectResponseItem = { monetization_status?: string; }; +export type MinecraftVersionType = "release" | "alpha" | "beta" | "snapshot"; + export type MinecraftVersionResponseItem = { version: string; - version_type: string; + version_type: MinecraftVersionType; date: string; major: boolean; }; From 944c4a932eea78750cde15798168c93b87b00977 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:28:56 -0500 Subject: [PATCH 039/110] add type support to generateLockfile --- src/generate_lockfile.ts | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index 1120bbc..d956401 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -4,17 +4,12 @@ import {getVersionsFromHashes} from "./modrinth_interactions.js"; import {getScanDirectories, scanDirectory} from "./directory_scanning.js"; import * as config from "./config/index.js"; import {logm, styleText} from "./logger.js"; - -/** - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type {ContentFile, Lockfile, Options, InitOptions, VersionResponseItem} from "./types/index.js"; /** * Create empty lockfile structure */ -function createEmptyLockfile() { +function createEmptyLockfile(): Lockfile { return { version: config.LOCKFILE_VERSION, generated: new Date().toISOString(), @@ -73,19 +68,19 @@ async function writeLockfile(lockfile, outputPath) { /** * Generate the lockfile * @param {string} workingDir - The working directory - * @param {Options} options - The options object + * @param {Options | InitOptions} options - The options object * @returns {Lockfile} The lockfile object */ -export async function generateLockfile(workingDir, options = {}) { +export async function generateLockfile(workingDir: string, options: Options | InitOptions = {}): Promise { logm.quietFromOptions(options); logm.header("Scanning Directories"); // Scan all directories - const allFileEntries = []; + const allFileEntries: ContentFile[] = []; for (const dirInfo of getScanDirectories(workingDir)) { logm.info(styleText(["cyan"], `${dirInfo.name}/`)); - const fileEntries = await scanDirectory(dirInfo, workingDir); + const fileEntries: ContentFile[] = await scanDirectory(dirInfo, workingDir); logm.info( styleText(["dim"], ` └─ Found`), styleText(["yellow"], `${fileEntries.length}`), @@ -105,8 +100,8 @@ export async function generateLockfile(workingDir, options = {}) { if (allFileEntries.length === 0) { logm.header("GENERATING LOCKFILE"); logm.warn("No files found. Creating empty lockfile."); - const emptyLockfile = createEmptyLockfile(); - const outputPath = path.join(workingDir, config.MODPACK_LOCKFILE_NAME); + const emptyLockfile: Lockfile = createEmptyLockfile(); + const outputPath: string = path.join(workingDir, config.MODPACK_LOCKFILE_NAME); if (options.dryRun) { logm.debug(config.dryRunText(config.MODPACK_LOCKFILE_NAME, outputPath)); } else { @@ -119,10 +114,10 @@ export async function generateLockfile(workingDir, options = {}) { logm.header("Querying Modrinth API"); // Extract all hashes - const hashes = allFileEntries.map((info) => info.hash); + const hashes: string[] = allFileEntries.map((info) => info.hash); // Query Modrinth API - const versionData = await getVersionsFromHashes(hashes); + const versionData: Record = await getVersionsFromHashes(hashes); logm.info(styleText(["dim"], "Found version information for:")); logm.info( @@ -134,10 +129,10 @@ export async function generateLockfile(workingDir, options = {}) { ); // Create lockfile - const lockfile = createLockfile(allFileEntries, versionData); + const lockfile: Lockfile = createLockfile(allFileEntries, versionData); // Write lockfile - const outputPath = path.join(workingDir, config.MODPACK_LOCKFILE_NAME); + const outputPath: string = path.join(workingDir, config.MODPACK_LOCKFILE_NAME); if (options.dryRun) { logm.debug(config.dryRunText(config.MODPACK_LOCKFILE_NAME, outputPath)); } else { From b951a84749e6051b04b547e4df799d5e3e177b47 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:44:19 -0500 Subject: [PATCH 040/110] updated contentfile types --- src/types/contentFiles.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/types/contentFiles.ts b/src/types/contentFiles.ts index 0360fb2..45c582d 100644 --- a/src/types/contentFiles.ts +++ b/src/types/contentFiles.ts @@ -1,5 +1,7 @@ +import type {DependencyCategory} from "./Lockfile.js"; + export type ContentDirectory = { - name: string; + name: DependencyCategory; path: string; }; @@ -7,5 +9,5 @@ export type ContentFile = { path: string; fullPath: string; hash: string; - category: string; + category: DependencyCategory; }; From 824379c239a52f85fbf93e863a7ba1ab83679aa5 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:45:11 -0500 Subject: [PATCH 041/110] update type on generateCategoryReadme category field --- src/generate_readme.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 94e37cb..aae7aeb 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -12,13 +12,14 @@ import type { UserResponseItem, LockfileDependencyEntry, ContentDirectory, + DependencyCategory, } from "./types/index.js"; /** * Generate README.md content for a category */ function generateCategoryReadme( - category: string, + category: DependencyCategory, entries: LockfileDependencyEntry[], projectsMap: Record, usersMap: Record, From 9a97aeb4dbdb3655cf51cf5abe41bd4b4b2d31a0 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:46:46 -0500 Subject: [PATCH 042/110] add type support to createLockfile --- src/generate_lockfile.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index d956401..41c2875 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -4,7 +4,14 @@ import {getVersionsFromHashes} from "./modrinth_interactions.js"; import {getScanDirectories, scanDirectory} from "./directory_scanning.js"; import * as config from "./config/index.js"; import {logm, styleText} from "./logger.js"; -import type {ContentFile, Lockfile, Options, InitOptions, VersionResponseItem} from "./types/index.js"; +import type { + ContentFile, + Lockfile, + Options, + InitOptions, + VersionResponseItem, + DependencyCategory, +} from "./types/index.js"; /** * Create empty lockfile structure @@ -22,13 +29,13 @@ function createEmptyLockfile(): Lockfile { /** * Create lockfile structure from file info and version data */ -function createLockfile(fileEntries, versionData) { - const lockfile = createEmptyLockfile(); +function createLockfile(fileEntries: ContentFile[], versionData: Record): Lockfile { + const lockfile: Lockfile = createEmptyLockfile(); logm.newline(); // Organize by category for (const fileInfo of fileEntries) { - const version = versionData[fileInfo.hash]; + const version: VersionResponseItem | undefined = versionData[fileInfo.hash]; lockfile.dependencies[fileInfo.category] ||= []; @@ -41,14 +48,14 @@ function createLockfile(fileEntries, versionData) { logm.warn(`File ${fileInfo.path} not found on Modrinth`); } - lockfile.dependencies[fileInfo.category].push(entry); + lockfile.dependencies[fileInfo.category]?.push(entry); } logm.header("Generating Lockfile"); // Calculate counts for each category for (const [category, entries] of Object.entries(lockfile.dependencies)) { - lockfile.counts[category] = entries.length; + lockfile.counts[category as DependencyCategory] = entries.length; } lockfile.total = fileEntries.length; From 10ab25dd8b7ac1749ffe7ade785531ce2c634d7b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:57:16 -0500 Subject: [PATCH 043/110] fix type issue where category was read as just a string --- src/generate_readme.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/generate_readme.ts b/src/generate_readme.ts index aae7aeb..1e4b70a 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -217,7 +217,10 @@ export async function generateReadmeFiles( } // Generate README for each category - for (const [category, entries] of Object.entries(lockfile.dependencies)) { + for (const [category, entries] of Object.entries(lockfile.dependencies) as [ + DependencyCategory, + LockfileDependencyEntry[], + ][]) { if (entries.length === 0) { continue; } From 388af8a8585c597a2024358fa2473ccd7b760f38 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:58:20 -0500 Subject: [PATCH 044/110] add type support to writeLockfile and printLockfileSummary --- src/generate_lockfile.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index 41c2875..c9e6023 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -11,6 +11,7 @@ import type { InitOptions, VersionResponseItem, DependencyCategory, + LockfileDependencyEntry, } from "./types/index.js"; /** @@ -66,8 +67,8 @@ function createLockfile(fileEntries: ContentFile[], versionData: Record { + const content: string = JSON.stringify(lockfile, null, 2); await fs.writeFile(outputPath, content, "utf-8"); logm.generated(config.MODPACK_LOCKFILE_NAME, outputPath); } @@ -153,7 +154,7 @@ export async function generateLockfile(workingDir: string, options: Options | In * Print a summary of the lockfile contents * @param {Lockfile} lockfile - The lockfile object */ -export function printLockfileSummary(lockfile) { +export function printLockfileSummary(lockfile: Lockfile): void { logm.header("Lockfile Summary"); if (lockfile.total === 0) { @@ -161,9 +162,12 @@ export function printLockfileSummary(lockfile) { return; } - for (const [category, entries] of Object.entries(lockfile.dependencies)) { - const withVersion = entries.filter((e) => e.version !== null).length; - const withoutVersion = entries.length - withVersion; + for (const [category, entries] of Object.entries(lockfile.dependencies) as [ + DependencyCategory, + LockfileDependencyEntry[], + ][]) { + const withVersion: number = entries.filter((e) => e.version !== null).length; + const withoutVersion: number = entries.length - withVersion; logm.info( styleText(["bold"], `${category}:`), entries.length, From 87ee79a8174383d3784a68631c72ded6477de948 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 14:59:29 -0500 Subject: [PATCH 045/110] add type support to generateModpackFiles --- src/modpack-lock.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 2394330..1cbe0fb 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -6,13 +6,7 @@ import generateLicense from "./generate_license.js"; import {logm} from "./logger.js"; import {promptUserForInfo} from "./modpack_info.js"; import {getModpackInfo, getLockfile} from "./directory_scanning.js"; - -/** - * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo - * @typedef {import('./config/types.js').Options} Options - * @typedef {import('./config/types.js').InitOptions} InitOptions - * @typedef {import('./config/types.js').Lockfile} Lockfile - */ +import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; /** * @license MIT @@ -27,10 +21,14 @@ import {getModpackInfo, getLockfile} from "./directory_scanning.js"; * @param {Options | InitOptions } options - The options object * @returns {Promise} The lockfile object */ -async function generateModpackFiles(modpackInfo, workingDir, options = {}) { +async function generateModpackFiles( + modpackInfo: ModpackInfo, + workingDir: string, + options: Options | InitOptions = {}, +): Promise { logm.quietFromOptions(options); - const lockfile = await generateLockfile(workingDir, options); + const lockfile: Lockfile = await generateLockfile(workingDir, options); await generateJson(modpackInfo, lockfile, workingDir, options); From 41436ba25c9c00d0529ef2e7afba48c00e4ad0b5 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 15:26:06 -0500 Subject: [PATCH 046/110] update mergeModpackInfo function to support typing properly --- src/cli.ts | 40 ++++++++++++++++++---------------------- src/config/defaults.ts | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 412e379..160c71a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -13,6 +13,7 @@ import {getModpackInfo} from "./directory_scanning.js"; import * as config from "./config/index.js"; import pkg from "../package.json" with {type: "json"}; import {logm, styleText} from "./logger.js"; +import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; const modpackLock = new Command("modpack-lock"); @@ -20,22 +21,17 @@ const modpackLock = new Command("modpack-lock"); * Merge modpack info with priority: options > existingInfo > defaults * Preserves all fields from existingInfo */ -function mergeModpackInfo(existingInfo, options, defaults) { - const result = {}; - for (const [key, defaultValue] of Object.entries(defaults)) { - result[key] = options[key] || existingInfo?.[key] || defaultValue; +function mergeModpackInfo(existingInfo: ModpackInfo | null, options: InitOptions, defaults: ModpackInfo): ModpackInfo { + const mergedInfo: ModpackInfo = { + ...defaults, + ...(existingInfo ?? {}), + }; + + for (const [key, defaultValue] of Object.entries(defaults) as [keyof ModpackInfo, string][]) { + mergedInfo[key] = options[key] || existingInfo?.[key] || defaultValue; } - // Then, add any fields from existingInfo that aren't in defaults - if (existingInfo) { - for (const [key, value] of Object.entries(existingInfo)) { - if (!(key in defaults)) { - result[key] = value; - } - } - } - - return result; + return mergedInfo; } modpackLock @@ -200,15 +196,15 @@ modpackLock const defaults = { name: path.basename(currDir), version: config.DEFAULT_MODPACK_VERSION, - id: undefined, - description: undefined, - author: undefined, - projectUrl: undefined, - sourceUrl: undefined, + id: "", + description: "", + author: "", + projectUrl: "", + sourceUrl: "", license: config.DEFAULT_MODPACK_LICENSE, - modloader: undefined, - targetModloaderVersion: undefined, - targetMinecraftVersion: undefined, + modloader: "", + targetModloaderVersion: "", + targetMinecraftVersion: "", }; const mergedDefaults = mergeModpackInfo(existingInfo, options, defaults); diff --git a/src/config/defaults.ts b/src/config/defaults.ts index ef65875..9e030af 100644 --- a/src/config/defaults.ts +++ b/src/config/defaults.ts @@ -1,4 +1,4 @@ -import type { Choice } from "prompts" +import type {Choice} from "prompts"; export const DEFAULT_MODPACK_VERSION: string = "1.0.0"; From cdcdebb675ac9cbc6bb3f9c4280da7cf1c278b8a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 21:17:16 -0500 Subject: [PATCH 047/110] update jsonfile to extend modpackinfo --- src/types/Jsonfile.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index a3d936f..db606e2 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,17 +1,7 @@ import type {DependencyCategory} from "./Lockfile.js"; +import type {ModpackInfo} from "./index.js"; -export type Jsonfile = { - name: string; - version: string; - id: string; - description: string; - author: string; - projectUrl: string; - sourceUrl: string; - license: string; - modloader: string; - targetModloaderVersion: string; - targetMinecraftVersion: string; +export type Jsonfile = ModpackInfo & { dependencies: Record; scripts?: { [key: string]: string; From be2bf92738fc61496e3cd452c34fb68d57f964aa Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 21:47:44 -0500 Subject: [PATCH 048/110] update type imports to index --- src/types/Jsonfile.ts | 3 +-- src/types/contentFiles.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index db606e2..947b1a9 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,5 +1,4 @@ -import type {DependencyCategory} from "./Lockfile.js"; -import type {ModpackInfo} from "./index.js"; +import type {DependencyCategory, ModpackInfo} from "./index.js"; export type Jsonfile = ModpackInfo & { dependencies: Record; diff --git a/src/types/contentFiles.ts b/src/types/contentFiles.ts index 45c582d..601ad54 100644 --- a/src/types/contentFiles.ts +++ b/src/types/contentFiles.ts @@ -1,4 +1,4 @@ -import type {DependencyCategory} from "./Lockfile.js"; +import type {DependencyCategory} from "./index.js"; export type ContentDirectory = { name: DependencyCategory; From 86662bb113fc4d6953a9bacb3f975dd28d745687 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 23:07:17 -0500 Subject: [PATCH 049/110] correct exit and error cli types --- src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 160c71a..4bdb96c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -288,13 +288,13 @@ modpackLock }); // preserve exit code on completion - const exitCode = await new Promise((resolve) => { + const exitCode = await new Promise((resolve) => { child.on("close", (code) => { resolve(code || 0); }); }); process.exitCode = exitCode; - } catch (error) { + } catch (error: any) { logm.error(error.message); process.exitCode = 1; } From 102487eae81372c7d811abab3a4d70b3ae2151b2 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 23:08:45 -0500 Subject: [PATCH 050/110] make dependencies optional in jsonfile --- src/types/Jsonfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index 947b1a9..1c4e37a 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,7 +1,7 @@ import type {DependencyCategory, ModpackInfo} from "./index.js"; export type Jsonfile = ModpackInfo & { - dependencies: Record; + dependencies?: Record; scripts?: { [key: string]: string; }; From da0ede87eea8e0830da8bfc3ecfe14b4e34bb62f Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 23:16:42 -0500 Subject: [PATCH 051/110] add all info fields constant --- src/config/constants.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/config/constants.ts b/src/config/constants.ts index d9d58f3..d785f19 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -17,6 +17,14 @@ export const MODPACK_INFO_REQUIRED_FIELDS: (keyof ModpackInfo)[] = [ "targetMinecraftVersion", ]; +export const MODPACK_INFO_FIELDS: (keyof ModpackInfo)[] = [ + ...MODPACK_INFO_REQUIRED_FIELDS, // + "projectUrl", + "sourceUrl", + "license", + "targetModloaderVersion", +]; + /** Dependency categories, corresponds to folders in Minecraft profile */ export const DEPENDENCY_CATEGORIES: DependencyCategory[] = [ "mods", // From 3d8d8e327cd79cc367bed0400331a1722d7361dc Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Mon, 2 Mar 2026 23:19:02 -0500 Subject: [PATCH 052/110] convert modpackinfo to jsonfile wherever possible --- src/cli.ts | 9 +++++---- src/directory_scanning.ts | 6 +++--- src/generate_json.ts | 10 +++++----- src/generate_license.ts | 6 +++--- src/modpack-lock.ts | 6 +++--- src/modpack_info.ts | 16 ++++++---------- 6 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 4bdb96c..42c6b0f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -13,7 +13,7 @@ import {getModpackInfo} from "./directory_scanning.js"; import * as config from "./config/index.js"; import pkg from "../package.json" with {type: "json"}; import {logm, styleText} from "./logger.js"; -import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; +import type {Jsonfile, Options, InitOptions, Lockfile, ModpackInfo} from "./types/index.js"; const modpackLock = new Command("modpack-lock"); @@ -21,13 +21,14 @@ const modpackLock = new Command("modpack-lock"); * Merge modpack info with priority: options > existingInfo > defaults * Preserves all fields from existingInfo */ -function mergeModpackInfo(existingInfo: ModpackInfo | null, options: InitOptions, defaults: ModpackInfo): ModpackInfo { - const mergedInfo: ModpackInfo = { +function mergeModpackInfo(existingInfo: Jsonfile | null, options: InitOptions, defaults: ModpackInfo): Jsonfile { + const mergedInfo: Jsonfile = { ...defaults, ...(existingInfo ?? {}), }; - for (const [key, defaultValue] of Object.entries(defaults) as [keyof ModpackInfo, string][]) { + for (const key of config.MODPACK_INFO_FIELDS) { + const defaultValue = defaults[key]; mergedInfo[key] = options[key] || existingInfo?.[key] || defaultValue; } diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index ab2d66a..80c9ba0 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -3,7 +3,7 @@ import crypto from "crypto"; import path from "path"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; -import type {ModpackInfo, Lockfile} from "./types/index.js"; +import type {Lockfile, Jsonfile} from "./types/index.js"; import type {ContentDirectory} from "./types/index.js"; import type {ContentFile} from "./types/index.js"; @@ -100,9 +100,9 @@ async function getJsonFile(directoryPath: string, filename: string): Promise} The modpack info JSON object if the file exists, otherwise null + * @returns {Promise} The modpack info JSON object if the file exists, otherwise null */ -export async function getModpackInfo(directoryPath: string): Promise { +export async function getModpackInfo(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_JSON_NAME); } diff --git a/src/generate_json.ts b/src/generate_json.ts index 86eb643..ad6b49d 100644 --- a/src/generate_json.ts +++ b/src/generate_json.ts @@ -3,13 +3,13 @@ import path from "path"; import {getProjects} from "./modrinth_interactions.js"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; -import type {ModpackInfo, Lockfile, Jsonfile, Options, InitOptions, DependencyCategory} from "./types/index.js"; +import type {Lockfile, Jsonfile, Options, InitOptions, DependencyCategory} from "./types/index.js"; /** * Create a JSON object from the modpack information and dependencies */ function createModpackJson( - modpackInfo: ModpackInfo, // + modpackInfo: Jsonfile, dependencies: Record, ): Jsonfile { return { @@ -29,14 +29,14 @@ async function writeJson(jsonObject: Jsonfile, outputPath: string): Promise} The JSON file's object */ export default async function generateJson( - modpackInfo: ModpackInfo, + modpackInfo: Jsonfile, lockfile: Lockfile, workingDir: string, options: Options | InitOptions = {}, @@ -45,7 +45,7 @@ export default async function generateJson( // Validate modpack info for (const field of config.MODPACK_INFO_REQUIRED_FIELDS) { - if (!modpackInfo[field as keyof ModpackInfo]) { + if (!modpackInfo[field]) { throw new Error(`Modpack info is missing required field: ${field}`); } } diff --git a/src/generate_license.ts b/src/generate_license.ts index ebaf6c6..488d489 100644 --- a/src/generate_license.ts +++ b/src/generate_license.ts @@ -3,7 +3,7 @@ import path from "path"; import {getLicenseText} from "./github_interactions.js"; import * as config from "./config/index.js"; import {logm} from "./logger.js"; -import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; +import type {Jsonfile, Options, InitOptions} from "./types/index.js"; async function writeLicense(licenseText: string, outputPath: string) { await fs.writeFile(path.join(outputPath, config.MODPACK_LICENSE_NAME), licenseText, "utf-8"); @@ -12,14 +12,14 @@ async function writeLicense(licenseText: string, outputPath: string) { /** * Write a license to a file - * @param {ModpackInfo} modpackInfo - The modpack information + * @param {Jsonfile} modpackInfo - The modpack information * @param {string} workingDir - The path to write the license to * @param {InitOptions} options - The initialization options object * @param {string} licenseTextOverride - The license text to override the default license text with * @returns {Promise | null} The license text or null if the license text could not be generated */ export default async function generateLicense( - modpackInfo: ModpackInfo, + modpackInfo: Jsonfile, workingDir: string, options: Options | InitOptions = {}, licenseTextOverride: string | null = null, diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 1cbe0fb..8a1c7e6 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -6,7 +6,7 @@ import generateLicense from "./generate_license.js"; import {logm} from "./logger.js"; import {promptUserForInfo} from "./modpack_info.js"; import {getModpackInfo, getLockfile} from "./directory_scanning.js"; -import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js"; +import type {Jsonfile, Options, InitOptions, Lockfile} from "./types/index.js"; /** * @license MIT @@ -16,13 +16,13 @@ import type {ModpackInfo, Options, InitOptions, Lockfile} from "./types/index.js /** * Generate the modpack files (lockfile, JSON, and optionally license, gitignore, and readme) - * @param {ModpackInfo} modpackInfo - The modpack information + * @param {Jsonfile} modpackInfo - The modpack information * @param {string} workingDir - The directory to generate the files in * @param {Options | InitOptions } options - The options object * @returns {Promise} The lockfile object */ async function generateModpackFiles( - modpackInfo: ModpackInfo, + modpackInfo: Jsonfile, workingDir: string, options: Options | InitOptions = {}, ): Promise { diff --git a/src/modpack_info.ts b/src/modpack_info.ts index 99f60b9..c86349d 100644 --- a/src/modpack_info.ts +++ b/src/modpack_info.ts @@ -3,11 +3,7 @@ import slugify from "slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; -import type {InitOptions, ModpackInfo} from "./types/index.js"; - -/** - * @typedef {import('./config/types.js').ModpackInfo} ModpackInfo - */ +import type {InitOptions, Jsonfile} from "./types/index.js"; /** * Capitalizes a string @@ -107,10 +103,10 @@ function fileGenerationConfirm(name: string, message: string, showPrompt: boolea /** * Get user input for modpack information - * @param {ModpackInfo} defaults - The initial/default modpack information - * @returns {Promise} The modpack information from the user + * @param {Jsonfile} defaults - The initial/default modpack information + * @returns {Promise} The modpack information from the user */ -export async function promptUserForInfo(defaults: ModpackInfo) { +export async function promptUserForInfo(defaults: Jsonfile) { const licenseList = await getLicenseList(); const minecraftVersions = await getMinecraftVersions(); const modloaders = await getModloaders(); @@ -172,11 +168,11 @@ export async function promptUserForInfo(defaults: ModpackInfo) { /** * Prompt the user about adding the license text to the modpack - * @param {ModpackInfo} modpackInfo - The modpack information + * @param {Jsonfile} modpackInfo - The modpack information * @param {InitOptions} defaults - The default options * @returns {Promise} The answers from the user */ -export async function promptUserAboutOptionalFiles(modpackInfo: ModpackInfo, defaults: InitOptions) { +export async function promptUserAboutOptionalFiles(modpackInfo: Jsonfile, defaults: InitOptions) { const licenseText = await getLicenseText(modpackInfo.license); const answers = await prompts( [ From 3595832dd853562fafaf6f9770f37e40736c1237 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:03:34 -0500 Subject: [PATCH 053/110] ignore build folder --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 00cd25f..d846dcf 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ modpack.lock modpack.json coverage/ + +build/ From 23d1d46b5636b2e9bfe8da955b5683242b414273 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:04:47 -0500 Subject: [PATCH 054/110] update build in package.json --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 627354e..87981e7 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,9 @@ "license": "MIT", "author": "N. Escobar (https://nickesc.github.io/)", "type": "module", - "main": "src/modpack-lock.js", + "main": "build/modpack-lock.js", "bin": { - "modpack-lock": "src/cli.js" + "modpack-lock": "build/cli.js" }, "keywords": [ "modrinth", @@ -27,6 +27,7 @@ "node": ">=22.0.0" }, "scripts": { + "build": "tsc", "test": "vitest --run", "start": "node src/cli.js", "docs": "typedoc", @@ -36,7 +37,7 @@ "README.md", "LICENSE", "package.json", - "src/**/*.js" + "build/**/*" ], "dependencies": { "commander": "^14.0.3", From 0ffc0ee6aeaf1c48f9b686841468bfbe48d2851b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:28:27 -0500 Subject: [PATCH 055/110] install tsx for dev runs --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 87981e7..507d997 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ "scripts": { "build": "tsc", "test": "vitest --run", - "start": "node src/cli.js", + "start": "tsx src/cli.ts", "docs": "typedoc", - "modpack-lock": "node src/cli.js" + "modpack-lock": "tsx src/cli.ts", }, "files": [ "README.md", @@ -51,6 +51,7 @@ "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", + "tsx": "^4.21.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", "typescript": "^5.9.3", From f4d9b17a7e69792971725f0052a5ef23d07c43a7 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:29:22 -0500 Subject: [PATCH 056/110] add prepare script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 507d997..9952e3b 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "start": "tsx src/cli.ts", "docs": "typedoc", "modpack-lock": "tsx src/cli.ts", + "prepare": "npm run build" }, "files": [ "README.md", From 571deab94401e25d49f5cb49347016fcdf52896e Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:44:07 -0500 Subject: [PATCH 057/110] update tests to use tsx instead of node --- test/modpack-lock.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/modpack-lock.test.js b/test/modpack-lock.test.js index 73ae06d..a04d926 100644 --- a/test/modpack-lock.test.js +++ b/test/modpack-lock.test.js @@ -29,7 +29,7 @@ const __dirname = path.dirname(__filename); const WORKSPACE_ZIP = path.resolve(__dirname, "workspace.zip"); const LOCKFILE_NAME = "modpack.lock"; const JSON_NAME = "modpack.json"; -const CLI_PATH = path.resolve(__dirname, "../src/cli.js"); +const CLI_PATH = path.resolve(__dirname, "../src/cli.ts"); const DEPENDENCY_CATEGORIES = ["mods", "resourcepacks", "shaderpacks", "datapacks"]; @@ -123,7 +123,7 @@ async function scanWorkspaceFiles(workspaceDir) { */ async function runCli(args = [], options = {}) { try { - const {stdout, stderr} = await execFileAsync("node", [CLI_PATH, ...args], options); + const {stdout, stderr} = await execFileAsync("tsx", [CLI_PATH, ...args], options); return {stdout, stderr, exitCode: 0}; } catch (error) { return { From cadd42a48e191f010c9269f2c8d1114004298637 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:44:52 -0500 Subject: [PATCH 058/110] updated typedoc config to point to real tsconfig --- typedoc.json | 4 ++-- typedoc.ts.json | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 typedoc.ts.json diff --git a/typedoc.json b/typedoc.json index 638c195..aa56e8f 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,6 +1,6 @@ { - "tsconfig": "typedoc.ts.json", - "entryPoints": ["src/modpack-lock.js"], + "tsconfig": "tsconfig.json", + "entryPoints": ["src/modpack-lock.ts"], "readme": "README.md", "out": "docs", "darkHighlightTheme": "github-dark", diff --git a/typedoc.ts.json b/typedoc.ts.json deleted file mode 100644 index d852856..0000000 --- a/typedoc.ts.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "module": "NodeNext", - "target": "ES6" - }, - "include": [ - "src/**/*.js" - ] -} From db4252c9e96022ced1f31a60c258f36ea8a12b35 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 00:47:36 -0500 Subject: [PATCH 059/110] add path to options type oops --- src/types/Options.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/Options.ts b/src/types/Options.ts index 0798464..71659eb 100644 --- a/src/types/Options.ts +++ b/src/types/Options.ts @@ -15,6 +15,7 @@ export interface Options { gitignore?: boolean; readme?: boolean; licenseFile?: boolean; + path?: string; } /** * Contains options for the initialization of the modpack files. From 5305fdbfca62c429bdbe9747adf15991516f6864 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 01:36:38 -0500 Subject: [PATCH 060/110] add type support for base command --- src/cli.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 42c6b0f..8ecb16a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -52,15 +52,15 @@ modpackLock .optionsGroup(config.headings.information) .helpOption("-h, --help", `display help for ${pkg.name}`) .version(pkg.version, "-V") - .action(async (options) => { + .action(async (options: Options) => { try { - const currDir = options.path || process.cwd(); + const currDir: string = options.path || process.cwd(); logm.quietFromOptions(options); - const modpackInfo = await getModpackInfo(currDir); + const modpackInfo: Jsonfile | null = await getModpackInfo(currDir); if (modpackInfo) { - const lockfile = await generateModpackFiles(modpackInfo, currDir, options); + const lockfile: Lockfile = await generateModpackFiles(modpackInfo, currDir, options); printLockfileSummary(lockfile); } else { // Warn if license option is passed but no modpack.json exists @@ -71,7 +71,7 @@ modpackLock } // Generate lockfile - const lockfile = await generateLockfile(currDir, options); + const lockfile: Lockfile = await generateLockfile(currDir, options); if (options.gitignore || options.readme) { logm.header("Generating Optional Files"); From da745caf23741205b13988ed351f195d8f1d5f12 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 01:40:05 -0500 Subject: [PATCH 061/110] add type support for noninteractive init changed method to find missing required fields --- src/cli.ts | 84 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 8ecb16a..f284008 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -120,52 +120,60 @@ modpackLock .option("--targetMinecraftVersion ", config.infoFields.targetMinecraftVersion.option) .optionsGroup(config.headings.information) .helpOption("-h, --help", `display help for ${pkg.name} init`) - .action(async (options) => { + .action(async (options: InitOptions) => { options._init = true; - const currDir = options.folder || process.cwd(); + const currDir: string = options.folder || process.cwd(); - let existingInfo = await getModpackInfo(currDir); + let existingInfo: Jsonfile | null = await getModpackInfo(currDir); if (options.noninteractive) { logm.quiet(); - if ( - (!options.author && !existingInfo?.author) || - (!options.modloader && !existingInfo?.modloader) || - (!options.targetMinecraftVersion && !existingInfo?.targetMinecraftVersion) - ) { - logm.error("Must provide options for required fields"); + const defaultName: string = path.basename(currDir); + + const author: string = options.author || existingInfo?.author || ""; + const modloader: string = options.modloader || existingInfo?.modloader || ""; + const targetMinecraftVersion: string = + options.targetMinecraftVersion || existingInfo?.targetMinecraftVersion || ""; + + if (!author || !modloader || !targetMinecraftVersion) { + logm.error( + `Must provide options for required fields:`, + styleText( + ["bold"], + `${author ? "" : "author"}$ {modloader ? "" : "modloader"} ${targetMinecraftVersion ? "" : "targetMinecraftVersion"}`, + ), + ); process.exitCode = 1; return; - } else { - const defaultName = path.basename(currDir); - const defaults = { - name: defaultName, - version: config.DEFAULT_MODPACK_VERSION, - id: defaultName, - description: "", - author: options.author, // Required, no default - projectUrl: "", - sourceUrl: "", - license: "", - modloader: options.modloader, // Required, no default - targetModloaderVersion: "", - targetMinecraftVersion: options.targetMinecraftVersion, // Required, no default - }; - - const modpackInfo = mergeModpackInfo(existingInfo, options, defaults); - modpackInfo.id = slugify(modpackInfo.id, config.SLUGIFY_OPTIONS); - - options.readme = options.addReadme; - options.gitignore = options.addGitignore; - options.licenseFile = options.addLicense; + } - // generate the modpack files - try { - await generateModpackFiles(modpackInfo, currDir, options); - } catch (error) { - logm.error(error); - process.exitCode = 1; - } + const defaults: ModpackInfo = { + name: defaultName, + version: config.DEFAULT_MODPACK_VERSION, + id: defaultName, + description: "", + author: author, // Required, no default + projectUrl: "", + sourceUrl: "", + license: "", + modloader: modloader, // Required, no default + targetModloaderVersion: "", + targetMinecraftVersion: targetMinecraftVersion, // Required, no default + }; + + const modpackInfo: Jsonfile = mergeModpackInfo(existingInfo, options, defaults); + modpackInfo.id = slugify(modpackInfo.id, config.SLUGIFY_OPTIONS); + + options.readme = options.addReadme || false; + options.gitignore = options.addGitignore || false; + options.licenseFile = options.addLicense || false; + + // generate the modpack files + try { + await generateModpackFiles(modpackInfo, currDir, options); + } catch (error) { + logm.error(error); + process.exitCode = 1; } } else { logm.info(logm.label("modpack-lock"), styleText(["bold", "italic", "blueBright"], "init")); From 705f63297396abe9d5c469bc082e182463515c3b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 01:41:36 -0500 Subject: [PATCH 062/110] add test for incomplete json --- test/modpack-lock.test.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/modpack-lock.test.js b/test/modpack-lock.test.js index a04d926..ba0f2c2 100644 --- a/test/modpack-lock.test.js +++ b/test/modpack-lock.test.js @@ -973,5 +973,25 @@ describe("CLI", () => { const json = await readModpackJson(existingJsonWorkspace); expect(json.name).toBe("Existing Pack"); }); + + it("fails with an informative error when existing modpack.json is missing required fields", async () => { + const existingJsonWorkspace = await extractWorkspaceFixture(); + + // Missing author, modloader, targetMinecraftVersion + const modpackInfo = { + name: "Incomplete Pack", + version: "1.0.0", + id: "incomplete-pack", + }; + + await fs.writeFile(path.join(existingJsonWorkspace, JSON_NAME), JSON.stringify(modpackInfo, null, 2)); + + const result = await runCli(["--path", existingJsonWorkspace]); + + expect(result.exitCode).toBe(1); + expect(result.stderr).toContain("author"); + expect(result.stderr).toContain("modloader"); + expect(result.stderr).toContain("targetMinecraftVersion"); + }); }); }); From 9a49f5e77350d72416eff8b6331626320f5cdb01 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 01:49:26 -0500 Subject: [PATCH 063/110] update error to include all missing fields in json generation --- src/generate_json.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/generate_json.ts b/src/generate_json.ts index ad6b49d..720b7ac 100644 --- a/src/generate_json.ts +++ b/src/generate_json.ts @@ -8,10 +8,7 @@ import type {Lockfile, Jsonfile, Options, InitOptions, DependencyCategory} from /** * Create a JSON object from the modpack information and dependencies */ -function createModpackJson( - modpackInfo: Jsonfile, - dependencies: Record, -): Jsonfile { +function createModpackJson(modpackInfo: Jsonfile, dependencies: Record): Jsonfile { return { ...modpackInfo, dependencies: dependencies, @@ -44,12 +41,17 @@ export default async function generateJson( logm.quietFromOptions(options); // Validate modpack info + const missingFields: string[] = []; for (const field of config.MODPACK_INFO_REQUIRED_FIELDS) { if (!modpackInfo[field]) { - throw new Error(`Modpack info is missing required field: ${field}`); + missingFields.push(field); } } + if (missingFields.length > 0) { + throw new Error(`Modpack info is missing required fields: ${missingFields.join(", ")}`); + } + //TODO: consider changing these to partial records and only initializing the categories that are present in the lockfile const projectIds: Record> = { mods: new Set(), From dee46da8f686a372be648250383604fc540f697e Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 01:50:12 -0500 Subject: [PATCH 064/110] add tests for missing fields and options --- test/modpack-lock.test.js | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/modpack-lock.test.js b/test/modpack-lock.test.js index ba0f2c2..f0439ea 100644 --- a/test/modpack-lock.test.js +++ b/test/modpack-lock.test.js @@ -993,5 +993,59 @@ describe("CLI", () => { expect(result.stderr).toContain("modloader"); expect(result.stderr).toContain("targetMinecraftVersion"); }); + it("succeeds when existing modpack.json is missing required fields but provided in options during init", async () => { + const existingJsonWorkspace = await extractWorkspaceFixture(); + + // Missing author, modloader, targetMinecraftVersion + const modpackInfo = { + name: "Incomplete Pack", + version: "1.0.0", + id: "incomplete-pack", + }; + + await fs.writeFile(path.join(existingJsonWorkspace, JSON_NAME), JSON.stringify(modpackInfo, null, 2)); + + const result = await runCli([ + "init", + "--noninteractive", + "--folder", + existingJsonWorkspace, + "--author", + "Test Author", + "--modloader", + "fabric", + "--targetMinecraftVersion", + "1.21.1", + ]); + + expect(result.exitCode).toBe(0); + expect(result.stderr).not.toContain("author"); + expect(result.stderr).not.toContain("modloader"); + expect(result.stderr).not.toContain("targetMinecraftVersion"); + expect(result.stderr).not.toContain("targetMinecraftVersion"); + }); + it("succeeds when options are missing but provided in existing modpack.json during init", async () => { + const existingJsonWorkspace = await extractWorkspaceFixture(); + + // Missing author, modloader, targetMinecraftVersion + const modpackInfo = { + name: "Incomplete Pack", + version: "1.0.0", + id: "incomplete-pack", + author: "Test Author", + modloader: "fabric", + targetMinecraftVersion: "1.21.1", + }; + + await fs.writeFile(path.join(existingJsonWorkspace, JSON_NAME), JSON.stringify(modpackInfo, null, 2)); + + const result = await runCli(["init", "--noninteractive", "--folder", existingJsonWorkspace]); + + expect(result.exitCode).toBe(0); + expect(result.stderr).not.toContain("author"); + expect(result.stderr).not.toContain("modloader"); + expect(result.stderr).not.toContain("targetMinecraftVersion"); + expect(result.stderr).not.toContain("targetMinecraftVersion"); + }); }); }); From 6fd04114ce0d085b35447e03748dbe65de126752 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:18:05 -0500 Subject: [PATCH 065/110] add FileOptionPrompts type for optional file prompts --- src/types/FileOptionPrompts.ts | 3 +++ src/types/index.ts | 1 + 2 files changed, 4 insertions(+) create mode 100644 src/types/FileOptionPrompts.ts diff --git a/src/types/FileOptionPrompts.ts b/src/types/FileOptionPrompts.ts new file mode 100644 index 0000000..26de686 --- /dev/null +++ b/src/types/FileOptionPrompts.ts @@ -0,0 +1,3 @@ +import type {InitOptions} from "./index.js"; + +export type FileOptionPrompts = keyof InitOptions & ("addLicense" | "addReadme" | "addGitignore"); diff --git a/src/types/index.ts b/src/types/index.ts index 4d6a3c5..00d25b2 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -5,3 +5,4 @@ export type * from "./Options.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; export type * from "./contentFiles.js"; +export type * from "./FileOptionPrompts.js"; From 64b1fca3d74f88ba65c096373918cd3280121fc3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:19:05 -0500 Subject: [PATCH 066/110] add requirements for field names in prompts with types --- src/modpack_info.ts | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/modpack_info.ts b/src/modpack_info.ts index c86349d..f138dd7 100644 --- a/src/modpack_info.ts +++ b/src/modpack_info.ts @@ -3,7 +3,7 @@ import slugify from "slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; -import type {InitOptions, Jsonfile} from "./types/index.js"; +import type {FileOptionPrompts, InitOptions, Jsonfile, ModpackInfo} from "./types/index.js"; /** * Capitalizes a string @@ -25,7 +25,11 @@ function validateNotEmpty(value: string, field: string) { /** * Returns a required text prompt */ -function requiredText(name: string, message: string, initial: PromptObject["initial"]): PromptObject { +function requiredText( + name: keyof ModpackInfo | "other", + message: string, + initial: PromptObject["initial"], +): PromptObject { return { type: "text", name: name, @@ -40,7 +44,11 @@ function requiredText(name: string, message: string, initial: PromptObject["init /** * Returns an optional text prompt */ -function optionalText(name: string, message: string, initial: PromptObject["initial"]): PromptObject { +function optionalText( + name: keyof ModpackInfo | "other", + message: string, + initial: PromptObject["initial"], +): PromptObject { return { type: "text", name: name, @@ -65,7 +73,7 @@ async function getOtherAnswer(value: string, message: string, initial: PromptObj * Returns a required autocomplete prompt with a fallback to the other option */ function requiredAutocomplete( - name: string, + name: keyof ModpackInfo | "other", message: string, initial: PromptObject["initial"], choices: Choice[], @@ -92,7 +100,7 @@ function requiredAutocomplete( /** * Returns an confirmation prompt to generate an optional file */ -function fileGenerationConfirm(name: string, message: string, showPrompt: boolean): PromptObject { +function fileGenerationConfirm(name: FileOptionPrompts | "other", message: string, showPrompt: boolean): PromptObject { return { type: showPrompt ? "confirm" : null, name: name, @@ -106,11 +114,11 @@ function fileGenerationConfirm(name: string, message: string, showPrompt: boolea * @param {Jsonfile} defaults - The initial/default modpack information * @returns {Promise} The modpack information from the user */ -export async function promptUserForInfo(defaults: Jsonfile) { +export async function promptUserForInfo(defaults: Jsonfile): Promise> { const licenseList = await getLicenseList(); const minecraftVersions = await getMinecraftVersions(); const modloaders = await getModloaders(); - let answers = await prompts( + let answers: prompts.Answers = await prompts( [ requiredText("name", config.infoFields.name.prompt, defaults.name), requiredText( @@ -172,9 +180,12 @@ export async function promptUserForInfo(defaults: Jsonfile) { * @param {InitOptions} defaults - The default options * @returns {Promise} The answers from the user */ -export async function promptUserAboutOptionalFiles(modpackInfo: Jsonfile, defaults: InitOptions) { +export async function promptUserAboutOptionalFiles( + modpackInfo: Jsonfile, + defaults: InitOptions, +): Promise> { const licenseText = await getLicenseText(modpackInfo.license); - const answers = await prompts( + const answers: prompts.Answers = await prompts( [ fileGenerationConfirm( "addLicense", From 296bba2c463def301325c16e0b2f3194058141ed Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:21:24 -0500 Subject: [PATCH 067/110] add type support for interactive init --- src/cli.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index f284008..3bad272 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -13,7 +13,8 @@ import {getModpackInfo} from "./directory_scanning.js"; import * as config from "./config/index.js"; import pkg from "../package.json" with {type: "json"}; import {logm, styleText} from "./logger.js"; -import type {Jsonfile, Options, InitOptions, Lockfile, ModpackInfo} from "./types/index.js"; +import type {Jsonfile, Options, InitOptions, Lockfile, ModpackInfo, FileOptionPrompts} from "./types/index.js"; +import type prompts from "prompts"; const modpackLock = new Command("modpack-lock"); @@ -202,7 +203,7 @@ modpackLock ); logm.newline(); try { - const defaults = { + const defaults: ModpackInfo = { name: path.basename(currDir), version: config.DEFAULT_MODPACK_VERSION, id: "", @@ -218,13 +219,16 @@ modpackLock const mergedDefaults = mergeModpackInfo(existingInfo, options, defaults); // prompt user for modpack information - const userAnswers = await promptUserForInfo(mergedDefaults); + const userAnswers: prompts.Answers = await promptUserForInfo(mergedDefaults); // Preserve extra fields (e.g. scripts) from existing modpack.json - const modpackInfo = {...mergedDefaults, ...userAnswers}; + const modpackInfo: Jsonfile = {...mergedDefaults, ...userAnswers}; // prompt user if they want to add the license text - const optionalFiles = await promptUserAboutOptionalFiles(modpackInfo, options); + const optionalFiles: prompts.Answers = await promptUserAboutOptionalFiles( + modpackInfo, + options, + ); logm.newline(); @@ -232,7 +236,7 @@ modpackLock options.readme = optionalFiles.addReadme; options.gitignore = optionalFiles.addGitignore; options.licenseFile = optionalFiles.addLicense; - const lockfile = await generateModpackFiles(modpackInfo, currDir, options); + const lockfile: Lockfile = await generateModpackFiles(modpackInfo, currDir, options); printLockfileSummary(lockfile); } catch (error) { From ed22008f85c39118fdf9f943c7b51652bebf08ba Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:31:06 -0500 Subject: [PATCH 068/110] add type support to run --- src/cli.ts | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 3bad272..427eff0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,7 +3,7 @@ import {Command} from "commander"; import slugify from "slugify"; import path from "path"; -import {spawn} from "child_process"; +import {ChildProcess, spawn} from "child_process"; import {generateLockfile, printLockfileSummary} from "./generate_lockfile.js"; import {generateReadmeFiles} from "./generate_readme.js"; import {generateGitignoreRules} from "./generate_gitignore.js"; @@ -13,7 +13,15 @@ import {getModpackInfo} from "./directory_scanning.js"; import * as config from "./config/index.js"; import pkg from "../package.json" with {type: "json"}; import {logm, styleText} from "./logger.js"; -import type {Jsonfile, Options, InitOptions, Lockfile, ModpackInfo, FileOptionPrompts} from "./types/index.js"; +import type { + Jsonfile, + Options, + InitOptions, + Lockfile, + ModpackInfo, + FileOptionPrompts, + RunOptions, +} from "./types/index.js"; import type prompts from "prompts"; const modpackLock = new Command("modpack-lock"); @@ -257,15 +265,15 @@ modpackLock .helpOption("-h, --help", `display help for ${pkg.name} run`) .allowExcessArguments(true) .allowUnknownOption(true) - .action(async (script, options, command) => { + .action(async (script: string, options: RunOptions, command: Command) => { options._run = true; try { if (options.debug) { logm.debug("COMMAND:", command); } - const currDir = options.folder || process.cwd(); - const modpackInfo = await getModpackInfo(currDir); + const currDir: string = options.folder || process.cwd(); + const modpackInfo: Jsonfile | null = await getModpackInfo(currDir); // verify neccecary files and information exist if (!modpackInfo) { @@ -279,9 +287,9 @@ modpackLock } // build the full command - const scriptCommand = modpackInfo.scripts[script]; - const args = command.args ? command.args.slice(1) : []; - const fullCommand = `${scriptCommand} ${args.join(" ")}`; + const scriptCommand: string = modpackInfo.scripts[script]; + const args: string[] = command.args ? command.args.slice(1) : []; + const fullCommand: string = `${scriptCommand} ${args.join(" ")}`; // debug logging if (options.debug) { @@ -294,15 +302,15 @@ modpackLock } // spawn the command - const child = spawn(fullCommand, [], { + const child: ChildProcess = spawn(fullCommand, [], { shell: true, stdio: "inherit", cwd: currDir, }); // preserve exit code on completion - const exitCode = await new Promise((resolve) => { - child.on("close", (code) => { + const exitCode: number = await new Promise((resolve) => { + child.on("close", (code: number) => { resolve(code || 0); }); }); From 331a75bf9ead07d3954317f455ee0edac65f2a4d Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:36:18 -0500 Subject: [PATCH 069/110] update eslint config --- eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index c072828..35c4c6c 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -4,7 +4,7 @@ import {defineConfig} from "eslint/config"; export default defineConfig([ { - files: ["**/*.{js,mjs,cjs}"], + files: ["**/*.{ts}", "test/**/*.{ts,js}"], plugins: {js}, extends: ["js/recommended"], languageOptions: {globals: globals.node}, From 3221f2dd1b7b97f98b87badf4fb64de7b85fe9fc Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:39:35 -0500 Subject: [PATCH 070/110] rename Options file to optionsObject --- src/types/index.ts | 2 +- src/types/{Options.ts => optionsObjects.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/types/{Options.ts => optionsObjects.ts} (100%) diff --git a/src/types/index.ts b/src/types/index.ts index 00d25b2..dc47230 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ export type * from "./Lockfile.js"; export type * from "./Jsonfile.js"; export type * from "./ModpackInfo.js"; -export type * from "./Options.js"; +export type * from "./optionsObjects.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; export type * from "./contentFiles.js"; diff --git a/src/types/Options.ts b/src/types/optionsObjects.ts similarity index 100% rename from src/types/Options.ts rename to src/types/optionsObjects.ts From 3f17b531c29342d9a79a48c3e327f277ca9567c3 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:40:28 -0500 Subject: [PATCH 071/110] rename optiondObject file to options --- src/types/index.ts | 2 +- src/types/{optionsObjects.ts => options.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/types/{optionsObjects.ts => options.ts} (100%) diff --git a/src/types/index.ts b/src/types/index.ts index dc47230..26b7c28 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ export type * from "./Lockfile.js"; export type * from "./Jsonfile.js"; export type * from "./ModpackInfo.js"; -export type * from "./optionsObjects.js"; +export type * from "./options.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; export type * from "./contentFiles.js"; diff --git a/src/types/optionsObjects.ts b/src/types/options.ts similarity index 100% rename from src/types/optionsObjects.ts rename to src/types/options.ts From c14c1ba0813c5e61960b9675bbc561b5718d4707 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:41:32 -0500 Subject: [PATCH 072/110] rename modpack_info file to user_prompts --- src/cli.ts | 2 +- src/modpack-lock.ts | 2 +- src/{modpack_info.ts => user_prompts.ts} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{modpack_info.ts => user_prompts.ts} (100%) diff --git a/src/cli.ts b/src/cli.ts index 427eff0..b3322ca 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -8,7 +8,7 @@ import {generateLockfile, printLockfileSummary} from "./generate_lockfile.js"; import {generateReadmeFiles} from "./generate_readme.js"; import {generateGitignoreRules} from "./generate_gitignore.js"; import {generateModpackFiles} from "./modpack-lock.js"; -import {promptUserForInfo, promptUserAboutOptionalFiles} from "./modpack_info.js"; +import {promptUserForInfo, promptUserAboutOptionalFiles} from "./user_prompts.js"; import {getModpackInfo} from "./directory_scanning.js"; import * as config from "./config/index.js"; import pkg from "../package.json" with {type: "json"}; diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 8a1c7e6..0afff27 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -4,7 +4,7 @@ import {generateGitignoreRules} from "./generate_gitignore.js"; import generateJson from "./generate_json.js"; import generateLicense from "./generate_license.js"; import {logm} from "./logger.js"; -import {promptUserForInfo} from "./modpack_info.js"; +import {promptUserForInfo} from "./user_prompts.js"; import {getModpackInfo, getLockfile} from "./directory_scanning.js"; import type {Jsonfile, Options, InitOptions, Lockfile} from "./types/index.js"; diff --git a/src/modpack_info.ts b/src/user_prompts.ts similarity index 100% rename from src/modpack_info.ts rename to src/user_prompts.ts From 4d518ac9fee17d0c9ec61e2b03b0037bea3cdfdb Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 02:58:34 -0500 Subject: [PATCH 073/110] rename LockfileDependencyEntry to LockfileDependency --- src/generate_lockfile.ts | 4 ++-- src/generate_readme.ts | 6 +++--- src/types/Lockfile.ts | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index c9e6023..8f34764 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -11,7 +11,7 @@ import type { InitOptions, VersionResponseItem, DependencyCategory, - LockfileDependencyEntry, + LockfileDependency, } from "./types/index.js"; /** @@ -164,7 +164,7 @@ export function printLockfileSummary(lockfile: Lockfile): void { for (const [category, entries] of Object.entries(lockfile.dependencies) as [ DependencyCategory, - LockfileDependencyEntry[], + LockfileDependency[], ][]) { const withVersion: number = entries.filter((e) => e.version !== null).length; const withoutVersion: number = entries.length - withVersion; diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 1e4b70a..daaf941 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -10,7 +10,7 @@ import type { Lockfile, ProjectResponseItem, UserResponseItem, - LockfileDependencyEntry, + LockfileDependency, ContentDirectory, DependencyCategory, } from "./types/index.js"; @@ -20,7 +20,7 @@ import type { */ function generateCategoryReadme( category: DependencyCategory, - entries: LockfileDependencyEntry[], + entries: LockfileDependency[], projectsMap: Record, usersMap: Record, ): string { @@ -219,7 +219,7 @@ export async function generateReadmeFiles( // Generate README for each category for (const [category, entries] of Object.entries(lockfile.dependencies) as [ DependencyCategory, - LockfileDependencyEntry[], + LockfileDependency[], ][]) { if (entries.length === 0) { continue; diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 97362ff..e942550 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -22,16 +22,16 @@ export type Lockfile = { total: number; counts: Partial>; dependencies: { - mods?: LockfileDependencyEntry[]; - resourcepacks?: LockfileDependencyEntry[]; - datapacks?: LockfileDependencyEntry[]; - shaderpacks?: LockfileDependencyEntry[]; + mods?: LockfileDependency[]; + resourcepacks?: LockfileDependency[]; + datapacks?: LockfileDependency[]; + shaderpacks?: LockfileDependency[]; }; }; export type DependencyCategory = keyof Lockfile["dependencies"]; -export type LockfileDependencyEntry = { +export type LockfileDependency = { path: string; version: VersionResponseItem | null; }; From c5e69a1dc506716bba048b6448e8f94ffffa676e Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 03:01:04 -0500 Subject: [PATCH 074/110] rename VersionResponseItem to ContentVersion --- src/generate_lockfile.ts | 8 ++++---- src/modrinth_interactions.ts | 6 +++--- src/types/Lockfile.ts | 4 ++-- src/types/modrinthResponses.ts | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index 8f34764..43cc21c 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -9,7 +9,7 @@ import type { Lockfile, Options, InitOptions, - VersionResponseItem, + ContentVersion, DependencyCategory, LockfileDependency, } from "./types/index.js"; @@ -30,13 +30,13 @@ function createEmptyLockfile(): Lockfile { /** * Create lockfile structure from file info and version data */ -function createLockfile(fileEntries: ContentFile[], versionData: Record): Lockfile { +function createLockfile(fileEntries: ContentFile[], versionData: Record): Lockfile { const lockfile: Lockfile = createEmptyLockfile(); logm.newline(); // Organize by category for (const fileInfo of fileEntries) { - const version: VersionResponseItem | undefined = versionData[fileInfo.hash]; + const version: ContentVersion | undefined = versionData[fileInfo.hash]; lockfile.dependencies[fileInfo.category] ||= []; @@ -125,7 +125,7 @@ export async function generateLockfile(workingDir: string, options: Options | In const hashes: string[] = allFileEntries.map((info) => info.hash); // Query Modrinth API - const versionData: Record = await getVersionsFromHashes(hashes); + const versionData: Record = await getVersionsFromHashes(hashes); logm.info(styleText(["dim"], "Found version information for:")); logm.info( diff --git a/src/modrinth_interactions.ts b/src/modrinth_interactions.ts index 22674de..0567387 100644 --- a/src/modrinth_interactions.ts +++ b/src/modrinth_interactions.ts @@ -2,7 +2,7 @@ import * as config from "./config/index.js"; import {logm} from "./logger.js"; import type {Choice} from "prompts"; import type { - VersionResponseItem, + ContentVersion, ProjectResponseItem, MinecraftVersionResponseItem, ModloaderResponseItem, @@ -23,7 +23,7 @@ function chunkArray(array: any[], size: number) { /** * Query Modrinth API for version information from hashes */ -export async function getVersionsFromHashes(hashes: string[]): Promise> { +export async function getVersionsFromHashes(hashes: string[]): Promise> { if (hashes.length === 0) { return {}; } @@ -46,7 +46,7 @@ export async function getVersionsFromHashes(hashes: string[]): Promise; + return (await response.json()) as Record; } catch (error: unknown) { if (error instanceof Error) { logm.error(`Error fetching version information from hashes: ${error.message}`); diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index e942550..c2b2dff 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -1,4 +1,4 @@ -import type {VersionResponseItem} from "./index.js"; +import type {ContentVersion} from "./index.js"; /** * Contains information about the modpack dependencies and their versions. @@ -33,5 +33,5 @@ export type DependencyCategory = keyof Lockfile["dependencies"]; export type LockfileDependency = { path: string; - version: VersionResponseItem | null; + version: ContentVersion | null; }; diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 931fc66..74c9f85 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -5,7 +5,7 @@ export type DependencyResponseItem = { dependency_type: string; }; -export type VersionResponseItem = { +export type ContentVersion = { id: string; project_id: string; author_id: string; From 4849f85917922fe6d27386a03f6597696a0311dc Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 03:03:05 -0500 Subject: [PATCH 075/110] rename DependencyResponseItem to ContentVersionDependency --- src/types/modrinthResponses.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 74c9f85..00d7a58 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -1,4 +1,4 @@ -export type DependencyResponseItem = { +export type ContentVersionDependency = { version_id: string; project_id: string; file_name: string; @@ -22,7 +22,7 @@ export type ContentVersion = { version_type?: string; status?: string; requested_status?: string | null; - dependencies?: DependencyResponseItem[]; + dependencies?: ContentVersionDependency[]; }; export type ProjectResponseItem = { From eecc4658496ff872631179ec4a07f9b3c98ce0a1 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 03:04:35 -0500 Subject: [PATCH 076/110] add type exports refs #21 --- src/modpack-lock.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 0afff27..4d5cdb8 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -6,7 +6,17 @@ import generateLicense from "./generate_license.js"; import {logm} from "./logger.js"; import {promptUserForInfo} from "./user_prompts.js"; import {getModpackInfo, getLockfile} from "./directory_scanning.js"; -import type {Jsonfile, Options, InitOptions, Lockfile} from "./types/index.js"; +import type { + Jsonfile, + Options, + InitOptions, + Lockfile, + ModpackInfo, + DependencyCategory, + LockfileDependency, + ContentVersion, + ContentVersionDependency, +} from "./types/index.js"; /** * @license MIT @@ -65,3 +75,14 @@ export { getLockfile, promptUserForInfo, }; +export type { + Lockfile, // + ModpackInfo, + Jsonfile, + Options, + InitOptions, + DependencyCategory, + LockfileDependency, + ContentVersion, + ContentVersionDependency, +}; From 92e0aa3e1a92660bdf185b5f626ea0b91988cb65 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 03:22:23 -0500 Subject: [PATCH 077/110] remove jsdoc types --- src/config/types.ts | 76 ------------------------------------ src/directory_scanning.ts | 8 ++-- src/generate_gitignore.ts | 6 +-- src/generate_json.ts | 10 ++--- src/generate_license.ts | 10 ++--- src/generate_lockfile.ts | 8 ++-- src/generate_readme.ts | 6 +-- src/modpack-lock.ts | 8 ++-- src/modrinth_interactions.ts | 4 +- src/types/ModpackInfo.ts | 23 ++++++----- src/types/options.ts | 56 +++++++++++++------------- src/user_prompts.ts | 10 ++--- 12 files changed, 73 insertions(+), 152 deletions(-) delete mode 100644 src/config/types.ts diff --git a/src/config/types.ts b/src/config/types.ts deleted file mode 100644 index 082bd60..0000000 --- a/src/config/types.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @typedef {Object} ModpackInfo - * Contains information about the modpack that is not dependent on the lockfile. - * @property {string} name - The name of the modpack (Required) - * @property {string} version - The version of the modpack (Required) - * @property {string} description - The description of the modpack - * @property {string} id - The slug/ID of the modpack (Required) - * @property {string} author - The author of the modpack (Required) - * @property {string} projectUrl - The project URL of the modpack - * @property {string} sourceUrl - The source code URL of the modpack - * @property {string} license - The license of the modpack - * @property {string} modloader - The modloader of the modpack (Required) - * @property {string} targetModloaderVersion - The target modloader version of the modpack - * @property {string} targetMinecraftVersion - The target Minecraft version of the modpack (Required) - */ - -/** - * @typedef {Object} Lockfile - * Contains information about the modpack dependencies and their versions. - * @property {string} version - The version of the modpack - * @property {string} generated - The date and time the lockfile was generated - * @property {number} total - The total number of files in the modpack - * @property {Object} counts - The counts object - * @property {number} counts.mods - The mods count - * @property {number} counts.resourcepacks - The resourcepacks count - * @property {number} counts.datapacks - The datapacks count - * @property {number} counts.shaderpacks - The shaderpacks count - * @property {Object} dependencies - The dependencies object - * @property {Array} dependencies.mods - The mods object - * @property {Array} dependencies.resourcepacks - The resourcepacks object - * @property {Array} dependencies.datapacks - The datapacks object - * @property {Array} dependencies.shaderpacks - The shaderpacks object - */ - -/** - * @typedef {Object} Options - * Contains options for the generation of the modpack files. - * @property {boolean} dryRun - Whether to dry run the generation - * @property {boolean} quiet - Whether to quiet the console output - * @property {boolean} silent - Whether to silent the console output - * @property {boolean} gitignore - Whether to generate a .gitignore file - * @property {boolean} readme - Whether to generate README.md files - * @property {boolean} licenseFile - Whether to generate a license file - */ - -/** - * @typedef {Object} InitOptions - * Contains options for the initialization of the modpack files. - * @property {string} folder - The folder to generate the modpack files in - * @property {boolean} noninteractive - Whether to run the interactive mode - * @property {boolean} addLicense - Whether to add the license file to the modpack - * @property {boolean} addGitignore - Whether to generate .gitignore rules - * @property {boolean} addReadme - Whether to generate README.md files - * @property {string} name - The name of the modpack - * @property {string} version - The version of the modpack - * @property {string} id - The slug/ID of the modpack - * @property {string} description - The description of the modpack - * @property {string} author - The author of the modpack - * @property {string} projectUrl - The modpack's project URL - * @property {string} sourceUrl - The modpack's source code URL - * @property {string} license - The modpack's license - * @property {string} modloader - The modpack's modloader - * @property {string} targetModloaderVersion - The target modloader version - * @property {string} targetMinecraftVersion - The target Minecraft version - * @property {boolean} _init - Internal boolean added to indicate options come from the `init` command. - */ - -/** - * @typedef {Object} RunOptions - * Contains options for the running scripts defined in modpack.json. - * @property {string} folder - The folder to look for modpack.json in - * @property {boolean} debug - Whether to print debug information about the executed script - * @property {boolean} _run - Internal boolean added to indicate options come from the `run` command. - */ - -export {}; diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index 80c9ba0..451c2ad 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -9,8 +9,8 @@ import type {ContentFile} from "./types/index.js"; /** * Get the directories to scan for modpack files - * @param {string} directoryPath - The path to the directory to scan - * @returns {ContentDirectory[]} The directories to scan + * @param directoryPath - The path to the directory to scan + * @returns The directories to scan */ export function getScanDirectories(directoryPath: string): ContentDirectory[] { const scanDirectories: ContentDirectory[] = []; @@ -99,8 +99,8 @@ async function getJsonFile(directoryPath: string, filename: string): Promise} The modpack info JSON object if the file exists, otherwise null + * @param directoryPath - The path to the directory to scan + * @returns The modpack info JSON object if the file exists, otherwise null */ export async function getModpackInfo(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_JSON_NAME); diff --git a/src/generate_gitignore.ts b/src/generate_gitignore.ts index 09c97d0..f85341a 100644 --- a/src/generate_gitignore.ts +++ b/src/generate_gitignore.ts @@ -6,9 +6,9 @@ import type {Lockfile, Options, InitOptions} from "./types/index.js"; /** * Generate .gitignore rules for files not hosted on Modrinth and write them to .gitignore file - * @param {Lockfile} lockfile - The lockfile object - * @param {string} workingDir - The working directory - * @param {Options | InitOptions} options - The options object + * @param lockfile - The lockfile object + * @param workingDir - The working directory + * @param options - The options object */ export async function generateGitignoreRules( lockfile: Lockfile, diff --git a/src/generate_json.ts b/src/generate_json.ts index 720b7ac..f0436f3 100644 --- a/src/generate_json.ts +++ b/src/generate_json.ts @@ -26,11 +26,11 @@ async function writeJson(jsonObject: Jsonfile, outputPath: string): Promise} The JSON file's object + * @param modpackInfo - The modpack information + * @param lockfile - The lockfile + * @param workingDir - The path to write the JSON object to + * @param options - The options object + * @returns The JSON file's object */ export default async function generateJson( modpackInfo: Jsonfile, diff --git a/src/generate_license.ts b/src/generate_license.ts index 488d489..8e67687 100644 --- a/src/generate_license.ts +++ b/src/generate_license.ts @@ -12,11 +12,11 @@ async function writeLicense(licenseText: string, outputPath: string) { /** * Write a license to a file - * @param {Jsonfile} modpackInfo - The modpack information - * @param {string} workingDir - The path to write the license to - * @param {InitOptions} options - The initialization options object - * @param {string} licenseTextOverride - The license text to override the default license text with - * @returns {Promise | null} The license text or null if the license text could not be generated + * @param modpackInfo - The modpack information + * @param workingDir - The path to write the license to + * @param options - The initialization options object + * @param licenseTextOverride - The license text to override the default license text with + * @returns The license text or null if the license text could not be generated */ export default async function generateLicense( modpackInfo: Jsonfile, diff --git a/src/generate_lockfile.ts b/src/generate_lockfile.ts index 43cc21c..edc53ee 100644 --- a/src/generate_lockfile.ts +++ b/src/generate_lockfile.ts @@ -75,9 +75,9 @@ async function writeLockfile(lockfile: Lockfile, outputPath: string): Promise { logm.quietFromOptions(options); @@ -152,7 +152,7 @@ export async function generateLockfile(workingDir: string, options: Options | In /** * Print a summary of the lockfile contents - * @param {Lockfile} lockfile - The lockfile object + * @param lockfile - The lockfile object */ export function printLockfileSummary(lockfile: Lockfile): void { logm.header("Lockfile Summary"); diff --git a/src/generate_readme.ts b/src/generate_readme.ts index daaf941..502b5e9 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -166,9 +166,9 @@ function generateCategoryReadme( /** * Generate the README.md files for each category - * @param {Lockfile} lockfile - The lockfile object - * @param {string} workingDir - The working directory - * @param {Options | InitOptions} options - The options object + * @param lockfile - The lockfile object + * @param workingDir - The working directory + * @param options - The options object */ export async function generateReadmeFiles( lockfile: Lockfile, diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 4d5cdb8..18452cc 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -26,10 +26,10 @@ import type { /** * Generate the modpack files (lockfile, JSON, and optionally license, gitignore, and readme) - * @param {Jsonfile} modpackInfo - The modpack information - * @param {string} workingDir - The directory to generate the files in - * @param {Options | InitOptions } options - The options object - * @returns {Promise} The lockfile object + * @param modpackInfo - The modpack information + * @param workingDir - The directory to generate the files in + * @param options - The options object + * @returns The lockfile object */ async function generateModpackFiles( modpackInfo: Jsonfile, diff --git a/src/modrinth_interactions.ts b/src/modrinth_interactions.ts index 0567387..05ac658 100644 --- a/src/modrinth_interactions.ts +++ b/src/modrinth_interactions.ts @@ -139,7 +139,7 @@ export async function getUsers(userIds: string[]): Promise { /** * Fetch Minecraft versions from Modrinth - * @returns {Promise>} The Minecraft versions + * @returns The Minecraft versions */ export async function getMinecraftVersions(): Promise { try { @@ -178,7 +178,7 @@ export async function getMinecraftVersions(): Promise { /** * Fetch Modloaders from Modrinth - * @returns the modloaders + * @returns The modloaders */ export async function getModloaders(): Promise { try { diff --git a/src/types/ModpackInfo.ts b/src/types/ModpackInfo.ts index ecf9134..fb6958b 100644 --- a/src/types/ModpackInfo.ts +++ b/src/types/ModpackInfo.ts @@ -1,17 +1,16 @@ /** - * @typedef {Object} ModpackInfo * Contains information about the modpack that is not dependent on the lockfile. - * @property {string} name - The name of the modpack (Required) - * @property {string} version - The version of the modpack (Required) - * @property {string} description - The description of the modpack - * @property {string} id - The slug/ID of the modpack (Required) - * @property {string} author - The author of the modpack (Required) - * @property {string} projectUrl - The project URL of the modpack - * @property {string} sourceUrl - The source code URL of the modpack - * @property {string} license - The license of the modpack - * @property {string} modloader - The modloader of the modpack (Required) - * @property {string} targetModloaderVersion - The target modloader version of the modpack - * @property {string} targetMinecraftVersion - The target Minecraft version of the modpack (Required) + * @property name - The name of the modpack (Required) + * @property version - The version of the modpack (Required) + * @property description - The description of the modpack + * @property id - The slug/ID of the modpack (Required) + * @property author - The author of the modpack (Required) + * @property projectUrl - The project URL of the modpack + * @property sourceUrl - The source code URL of the modpack + * @property license - The license of the modpack + * @property modloader - The modloader of the modpack (Required) + * @property targetModloaderVersion - The target modloader version of the modpack + * @property targetMinecraftVersion - The target Minecraft version of the modpack (Required) */ export type ModpackInfo = { name: string; diff --git a/src/types/options.ts b/src/types/options.ts index 71659eb..1866900 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -1,13 +1,12 @@ /** * Contains options for the generation of the modpack files. - * @property {boolean} dryRun - Whether to dry run the generation - * @property {boolean} quiet - Whether to quiet the console output - * @property {boolean} silent - Whether to silent the console output - * @property {boolean} gitignore - Whether to generate a .gitignore file - * @property {boolean} readme - Whether to generate README.md files - * @property {boolean} licenseFile - Whether to generate a license file + * @property dryRun - Whether to dry run the generation + * @property quiet - Whether to quiet the console output + * @property silent - Whether to silent the console output + * @property gitignore - Whether to generate a .gitignore file + * @property readme - Whether to generate README.md files + * @property licenseFile - Whether to generate a license file */ - export interface Options { dryRun?: boolean; quiet?: boolean; @@ -17,27 +16,27 @@ export interface Options { licenseFile?: boolean; path?: string; } + /** * Contains options for the initialization of the modpack files. - * @property {string} folder - The folder to generate the modpack files in - * @property {boolean} noninteractive - Whether to run the interactive mode - * @property {boolean} addLicense - Whether to add the license file to the modpack - * @property {boolean} addGitignore - Whether to generate .gitignore rules - * @property {boolean} addReadme - Whether to generate README.md files - * @property {string} name - The name of the modpack - * @property {string} version - The version of the modpack - * @property {string} id - The slug/ID of the modpack - * @property {string} description - The description of the modpack - * @property {string} author - The author of the modpack - * @property {string} projectUrl - The modpack's project URL - * @property {string} sourceUrl - The modpack's source code URL - * @property {string} license - The modpack's license - * @property {string} modloader - The modpack's modloader - * @property {string} targetModloaderVersion - The target modloader version - * @property {string} targetMinecraftVersion - The target Minecraft version - * @property {boolean} _init - Internal boolean added to indicate options come from the `init` command. + * @property folder - The folder to generate the modpack files in + * @property noninteractive - Whether to run the interactive mode + * @property addLicense - Whether to add the license file to the modpack + * @property addGitignore - Whether to generate .gitignore rules + * @property addReadme - Whether to generate README.md files + * @property name - The name of the modpack + * @property version - The version of the modpack + * @property id - The slug/ID of the modpack + * @property description - The description of the modpack + * @property author - The author of the modpack + * @property projectUrl - The modpack's project URL + * @property sourceUrl - The modpack's source code URL + * @property license - The modpack's license + * @property modloader - The modpack's modloader + * @property targetModloaderVersion - The target modloader version + * @property targetMinecraftVersion - The target Minecraft version + * @property _init - Internal boolean added to indicate options come from the `init` command. */ - export interface InitOptions extends Options { folder?: string; noninteractive?: boolean; @@ -60,11 +59,10 @@ export interface InitOptions extends Options { /** * Contains options for the running scripts defined in modpack.json. - * @property {string} folder - The folder to look for modpack.json in - * @property {boolean} debug - Whether to print debug information about the executed script - * @property {boolean} _run - Internal boolean added to indicate options come from the `run` command. + * @property folder - The folder to look for modpack.json in + * @property debug - Whether to print debug information about the executed script + * @property _run - Internal boolean added to indicate options come from the `run` command. */ - export interface RunOptions extends Options { folder?: string; debug?: boolean; diff --git a/src/user_prompts.ts b/src/user_prompts.ts index f138dd7..4401c92 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -111,8 +111,8 @@ function fileGenerationConfirm(name: FileOptionPrompts | "other", message: strin /** * Get user input for modpack information - * @param {Jsonfile} defaults - The initial/default modpack information - * @returns {Promise} The modpack information from the user + * @param defaults - The initial/default modpack information + * @returns The modpack information from the user */ export async function promptUserForInfo(defaults: Jsonfile): Promise> { const licenseList = await getLicenseList(); @@ -176,9 +176,9 @@ export async function promptUserForInfo(defaults: Jsonfile): Promise} The answers from the user + * @param modpackInfo - The modpack information + * @param defaults - The default options + * @returns The answers from the user */ export async function promptUserAboutOptionalFiles( modpackInfo: Jsonfile, From c0ac4c1f7f42769113687622b54edb8f247c194a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Tue, 3 Mar 2026 03:29:31 -0500 Subject: [PATCH 078/110] update package lock --- package-lock.json | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 3b1e54f..7e60439 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "slugify": "^1.6.6" }, "bin": { - "modpack-lock": "src/cli.js" + "modpack-lock": "build/cli.js" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -23,6 +23,7 @@ "@vitest/coverage-v8": "^4.0.18", "eslint": "^10.0.0", "globals": "^17.3.0", + "tsx": "^4.21.0", "typedoc": "^0.28.17", "typedoc-github-theme": "^0.3.1", "typescript": "^5.9.3", @@ -2012,6 +2013,19 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2610,6 +2624,16 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", @@ -2811,6 +2835,26 @@ "node": ">=14.0.0" } }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", From 571814fa80e87364a99da4775c3b4335260d333d Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:06:21 -0500 Subject: [PATCH 079/110] fixed and renamed fileoptionprompt to OptionalFileOption --- src/cli.ts | 4 ++-- src/types/FileOptionPrompts.ts | 3 --- src/types/OptionalFileOptions.ts | 9 +++++++++ src/types/index.ts | 2 +- src/user_prompts.ts | 12 ++++++++---- 5 files changed, 20 insertions(+), 10 deletions(-) delete mode 100644 src/types/FileOptionPrompts.ts create mode 100644 src/types/OptionalFileOptions.ts diff --git a/src/cli.ts b/src/cli.ts index b3322ca..cb2ce9c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -19,7 +19,7 @@ import type { InitOptions, Lockfile, ModpackInfo, - FileOptionPrompts, + OptionalFileOptions, RunOptions, } from "./types/index.js"; import type prompts from "prompts"; @@ -233,7 +233,7 @@ modpackLock const modpackInfo: Jsonfile = {...mergedDefaults, ...userAnswers}; // prompt user if they want to add the license text - const optionalFiles: prompts.Answers = await promptUserAboutOptionalFiles( + const optionalFiles: prompts.Answers = await promptUserAboutOptionalFiles( modpackInfo, options, ); diff --git a/src/types/FileOptionPrompts.ts b/src/types/FileOptionPrompts.ts deleted file mode 100644 index 26de686..0000000 --- a/src/types/FileOptionPrompts.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type {InitOptions} from "./index.js"; - -export type FileOptionPrompts = keyof InitOptions & ("addLicense" | "addReadme" | "addGitignore"); diff --git a/src/types/OptionalFileOptions.ts b/src/types/OptionalFileOptions.ts new file mode 100644 index 0000000..4200855 --- /dev/null +++ b/src/types/OptionalFileOptions.ts @@ -0,0 +1,9 @@ +import type {InitOptions} from "./index.js"; + +/** + * The options available for the user to add optional files to the modpack + * @property addLicense - Whether to add the license text to the modpack + * @property addReadme - Whether to add the README.md file to the modpack + * @property addGitignore - Whether to add the .gitignore file to the modpack + */ +export type OptionalFileOptions = "addLicense" | "addReadme" | "addGitignore"; diff --git a/src/types/index.ts b/src/types/index.ts index 26b7c28..8e5212e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -5,4 +5,4 @@ export type * from "./options.js"; export type * from "./modrinthResponses.js"; export type * from "./githubResponses.js"; export type * from "./contentFiles.js"; -export type * from "./FileOptionPrompts.js"; +export type * from "./OptionalFileOptions.js"; diff --git a/src/user_prompts.ts b/src/user_prompts.ts index 4401c92..218505b 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -3,7 +3,7 @@ import slugify from "slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; -import type {FileOptionPrompts, InitOptions, Jsonfile, ModpackInfo} from "./types/index.js"; +import type {OptionalFileOptions, InitOptions, Jsonfile, ModpackInfo} from "./types/index.js"; /** * Capitalizes a string @@ -100,7 +100,11 @@ function requiredAutocomplete( /** * Returns an confirmation prompt to generate an optional file */ -function fileGenerationConfirm(name: FileOptionPrompts | "other", message: string, showPrompt: boolean): PromptObject { +function fileGenerationConfirm( + name: OptionalFileOptions | "other", + message: string, + showPrompt: boolean, +): PromptObject { return { type: showPrompt ? "confirm" : null, name: name, @@ -183,9 +187,9 @@ export async function promptUserForInfo(defaults: Jsonfile): Promise> { +): Promise> { const licenseText = await getLicenseText(modpackInfo.license); - const answers: prompts.Answers = await prompts( + const answers: prompts.Answers = await prompts( [ fileGenerationConfirm( "addLicense", From f6848c1f073fa0465efd0015f548813d5e83dea2 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:06:38 -0500 Subject: [PATCH 080/110] add content file jsdocs --- src/types/contentFiles.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/types/contentFiles.ts b/src/types/contentFiles.ts index 601ad54..0f18560 100644 --- a/src/types/contentFiles.ts +++ b/src/types/contentFiles.ts @@ -1,10 +1,22 @@ import type {DependencyCategory} from "./index.js"; +/** + * A directory that contains modpack content (e.g. mods, resourcepacks, datapacks, shaderpacks) + * @property name - The name of the directory + * @property path - The path to the directory + */ export type ContentDirectory = { name: DependencyCategory; path: string; }; +/** + * A binary content file in the modpack -- a file tracked by the modpack lockfile + * @property path - The path to the file + * @property fullPath - The full path to the file + * @property hash - The hash of the file + * @property category - The content category of the file (e.g. mods, resourcepacks, datapacks, shaderpacks) + */ export type ContentFile = { path: string; fullPath: string; From c6b03196f8d0ae132df6718650bf785b1f7b5c31 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:10:11 -0500 Subject: [PATCH 081/110] add github response jsdocs --- src/types/githubResponses.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/types/githubResponses.ts b/src/types/githubResponses.ts index 6da8533..0ecb237 100644 --- a/src/types/githubResponses.ts +++ b/src/types/githubResponses.ts @@ -1,8 +1,17 @@ +/** + * One of the license objects in a response from the GitHub API + * @property spdx_id - The SPDX ID of the license + * @property key - The key of the license + */ export type LicenseResponseItem = { spdx_id: string; key: string; }; +/** + * The response from the GitHub API for a license text + * @property body - The text of the license + */ export type LicenseTextResponse = { body: string; }; From 83e037e72b21ca8e0d526d11ef4300bf224c8be1 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:12:15 -0500 Subject: [PATCH 082/110] add jsonfile jsdoc --- src/types/Jsonfile.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index 1c4e37a..ad8cb3a 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,5 +1,11 @@ import type {DependencyCategory, ModpackInfo} from "./index.js"; +/** + * The `modpack.json` file shape + * @property dependencies - The dependencies of the modpack + * @property scripts - The scripts of the modpack + * @property [key: string] - Any other properties of the modpack + */ export type Jsonfile = ModpackInfo & { dependencies?: Record; scripts?: { From 946c1ffcf222b818782dbba04d0bd4f049867380 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:20:49 -0500 Subject: [PATCH 083/110] update jsonfile description --- src/types/Jsonfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index ad8cb3a..8996a87 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -1,7 +1,7 @@ import type {DependencyCategory, ModpackInfo} from "./index.js"; /** - * The `modpack.json` file shape + * The modpack.json file's shape; contains the modpack information and dependencies * @property dependencies - The dependencies of the modpack * @property scripts - The scripts of the modpack * @property [key: string] - Any other properties of the modpack From 4e684625bb0428e2ca6aaa05d686f9d515515ddf Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:21:10 -0500 Subject: [PATCH 084/110] update and add lockfile jsdocs --- src/types/Lockfile.ts | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index c2b2dff..95acf83 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -1,20 +1,20 @@ import type {ContentVersion} from "./index.js"; /** - * Contains information about the modpack dependencies and their versions. - * @property version - The version of the modpack + * Lockfile shape; contains detailed information about the modpack dependencies and their versions. + * @property version - The version of the lockfile * @property generated - The date and time the lockfile was generated * @property total - The total number of files in the modpack - * @property counts - The counts object - * @property counts.mods - The mods count - * @property counts.resourcepacks - The resourcepacks count - * @property counts.datapacks - The datapacks count - * @property counts.shaderpacks - The shaderpacks count - * @property dependencies - The dependencies object - * @property dependencies.mods - The mods array - * @property dependencies.resourcepacks - The resourcepacks array - * @property dependencies.datapacks - The datapacks array - * @property dependencies.shaderpacks - The shaderpacks array + * @property counts - An object containing the number of files in each category + * @property counts.mods - The number of mods in the modpack + * @property counts.resourcepacks - The number of resourcepacks in the modpack + * @property counts.datapacks - The number of datapacks in the modpack + * @property counts.shaderpacks - The number of shaderpacks in the modpack + * @property dependencies - An object containing all dependency version information + * @property dependencies.mods - An array with version information for each mod + * @property dependencies.resourcepacks - An array with version information for each resourcepack + * @property dependencies.datapacks - An array with version information for each datapack + * @property dependencies.shaderpacks - An array with version information for each shaderpack */ export type Lockfile = { version: string; @@ -29,8 +29,20 @@ export type Lockfile = { }; }; +/** + * The categories of dependencies in the lockfile + * @property mods - The mods folder + * @property resourcepacks - The resourcepacks folder + * @property datapacks - The datapacks folder + * @property shaderpacks - The shaderpacks folder + */ export type DependencyCategory = keyof Lockfile["dependencies"]; +/** + * The shape of a dependency in the lockfile + * @property path - The path to the dependency file in the modpack directory + * @property version - The version of the dependency, or null if the dependency is not found on Modrinth + */ export type LockfileDependency = { path: string; version: ContentVersion | null; From 920bd339273f0f33d9ed24bd48673dc4b7a6a6cc Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:24:31 -0500 Subject: [PATCH 085/110] update modpackinfo jsdoc --- src/types/ModpackInfo.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/types/ModpackInfo.ts b/src/types/ModpackInfo.ts index fb6958b..bf2adb5 100644 --- a/src/types/ModpackInfo.ts +++ b/src/types/ModpackInfo.ts @@ -1,16 +1,16 @@ /** * Contains information about the modpack that is not dependent on the lockfile. * @property name - The name of the modpack (Required) - * @property version - The version of the modpack (Required) - * @property description - The description of the modpack - * @property id - The slug/ID of the modpack (Required) + * @property version - The modpack version (Required) + * @property description - A description of the modpack + * @property id - The modpack's slug/ID (Required) * @property author - The author of the modpack (Required) - * @property projectUrl - The project URL of the modpack - * @property sourceUrl - The source code URL of the modpack - * @property license - The license of the modpack - * @property modloader - The modloader of the modpack (Required) - * @property targetModloaderVersion - The target modloader version of the modpack - * @property targetMinecraftVersion - The target Minecraft version of the modpack (Required) + * @property projectUrl - The project's homepage URL + * @property sourceUrl - The project's source code URL + * @property license - The modpack's license + * @property modloader - The modpack's modloader (Required) + * @property targetModloaderVersion - The target modloader version + * @property targetMinecraftVersion - The target Minecraft version (Required) */ export type ModpackInfo = { name: string; From 79bfaf757e5e876d989df9da2da2b1a2c2913dbf Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 00:32:41 -0500 Subject: [PATCH 086/110] updated options jsdocs --- src/types/options.ts | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/types/options.ts b/src/types/options.ts index 1866900..4d46fba 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -1,8 +1,8 @@ /** * Contains options for the generation of the modpack files. - * @property dryRun - Whether to dry run the generation + * @property dryRun - Whether to run in dry-run mode (no files written) * @property quiet - Whether to quiet the console output - * @property silent - Whether to silent the console output + * @property silent - Whether to silence the console output * @property gitignore - Whether to generate a .gitignore file * @property readme - Whether to generate README.md files * @property licenseFile - Whether to generate a license file @@ -19,22 +19,22 @@ export interface Options { /** * Contains options for the initialization of the modpack files. - * @property folder - The folder to generate the modpack files in - * @property noninteractive - Whether to run the interactive mode + * @property folder - The modpack root directory + * @property noninteractive - Whether to initialize in non-interactive mode * @property addLicense - Whether to add the license file to the modpack * @property addGitignore - Whether to generate .gitignore rules * @property addReadme - Whether to generate README.md files - * @property name - The name of the modpack - * @property version - The version of the modpack - * @property id - The slug/ID of the modpack - * @property description - The description of the modpack - * @property author - The author of the modpack - * @property projectUrl - The modpack's project URL - * @property sourceUrl - The modpack's source code URL - * @property license - The modpack's license - * @property modloader - The modpack's modloader - * @property targetModloaderVersion - The target modloader version - * @property targetMinecraftVersion - The target Minecraft version + * @property name - The option to set the modpack name + * @property version - The option to set the version + * @property id - The option to set the slug/ID + * @property description - The option to set the description + * @property author - The option to set the author + * @property projectUrl - The option to set the project URL + * @property sourceUrl - The option to set the source code URL + * @property license - The option to set the license + * @property modloader - The option to set the modloader + * @property targetModloaderVersion - The option to set the target modloader version + * @property targetMinecraftVersion - The option to set the target Minecraft version * @property _init - Internal boolean added to indicate options come from the `init` command. */ export interface InitOptions extends Options { @@ -59,8 +59,8 @@ export interface InitOptions extends Options { /** * Contains options for the running scripts defined in modpack.json. - * @property folder - The folder to look for modpack.json in - * @property debug - Whether to print debug information about the executed script + * @property folder - The modpack root directory + * @property debug - Whether to print debug information * @property _run - Internal boolean added to indicate options come from the `run` command. */ export interface RunOptions extends Options { From a492117e6d92b3c1502bc15c8ef1d57bf46398ce Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 07:56:01 -0500 Subject: [PATCH 087/110] update directory scanning jsdocs --- src/directory_scanning.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index 451c2ad..0c28824 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -100,7 +100,7 @@ async function getJsonFile(directoryPath: string, filename: string): Promise { return getJsonFile(directoryPath, config.MODPACK_JSON_NAME); @@ -109,7 +109,7 @@ export async function getModpackInfo(directoryPath: string): Promise} The JSON object if the file exists, otherwise null + * @returns {Promise} The Lockfile object if the file exists, otherwise null */ export async function getLockfile(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_LOCKFILE_NAME); From 705352d274b92ddddc092b04debf93e45ce1476f Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 08:05:37 -0500 Subject: [PATCH 088/110] update generate license jsdocs --- src/generate_license.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/generate_license.ts b/src/generate_license.ts index 8e67687..8e39094 100644 --- a/src/generate_license.ts +++ b/src/generate_license.ts @@ -11,18 +11,18 @@ async function writeLicense(licenseText: string, outputPath: string) { } /** - * Write a license to a file + * Generate a license file * @param modpackInfo - The modpack information * @param workingDir - The path to write the license to - * @param options - The initialization options object - * @param licenseTextOverride - The license text to override the default license text with + * @param options - The options object + * @param licenseTextOverride - Text to override the license's default content * @returns The license text or null if the license text could not be generated */ export default async function generateLicense( modpackInfo: Jsonfile, workingDir: string, options: Options | InitOptions = {}, - licenseTextOverride: string | null = null, + licenseTextOverride?: string, ): Promise { logm.quietFromOptions(options); From d1b9eff3c1f9b731997d76d0457876c62a765027 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 08:07:05 -0500 Subject: [PATCH 089/110] update generate readme jsdoc --- src/generate_readme.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generate_readme.ts b/src/generate_readme.ts index 502b5e9..1d91780 100644 --- a/src/generate_readme.ts +++ b/src/generate_readme.ts @@ -165,7 +165,7 @@ function generateCategoryReadme( } /** - * Generate the README.md files for each category + * Generate README.md files for each category * @param lockfile - The lockfile object * @param workingDir - The working directory * @param options - The options object From 49bd2759dc26240341d78343e5dfcf6ce50f208a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 08:10:10 -0500 Subject: [PATCH 090/110] add explicit return type from getLicenseList --- src/github_interactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github_interactions.ts b/src/github_interactions.ts index c7243ff..311a751 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -8,7 +8,7 @@ import type {LicenseResponseItem, LicenseTextResponse} from "./types/index.js"; * @param featured - If the fetch should be limited to featured licenses * @returns The list of licenses for use in a prompt */ -export async function getLicenseList(featured: boolean = false) { +export async function getLicenseList(featured: boolean = false): Promise { try { const url: string = featured ? config.GITHUB_FEATURED_LICENSES_ENDPOINT : config.GITHUB_LICENSES_ENDPOINT; const response = await fetch(url, { From 381f855a093c5bf4e1edc0e7e0146ca83092c617 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 08:10:58 -0500 Subject: [PATCH 091/110] update get license text jsdoc --- src/github_interactions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github_interactions.ts b/src/github_interactions.ts index 311a751..bb48145 100644 --- a/src/github_interactions.ts +++ b/src/github_interactions.ts @@ -48,7 +48,7 @@ export async function getLicenseList(featured: boolean = false): Promise { From 8102d16fca041cb3e1b56caf423730cdd4c28683 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 13:41:58 -0500 Subject: [PATCH 092/110] updated modrinth interaction jsdocs --- src/modrinth_interactions.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/modrinth_interactions.ts b/src/modrinth_interactions.ts index 05ac658..d75ec54 100644 --- a/src/modrinth_interactions.ts +++ b/src/modrinth_interactions.ts @@ -21,7 +21,9 @@ function chunkArray(array: any[], size: number) { } /** - * Query Modrinth API for version information from hashes + * Fetch version information for multiple file hashes from the Modrinth API + * @param hashes - An array of hashes to fetch version information for + * @returns An object with the version information for each hash */ export async function getVersionsFromHashes(hashes: string[]): Promise> { if (hashes.length === 0) { @@ -58,7 +60,9 @@ export async function getVersionsFromHashes(hashes: string[]): Promise { if (projectIds.length === 0) { @@ -98,7 +102,9 @@ export async function getProjects(projectIds: string[]): Promise { if (userIds.length === 0) { @@ -138,8 +144,8 @@ export async function getUsers(userIds: string[]): Promise { } /** - * Fetch Minecraft versions from Modrinth - * @returns The Minecraft versions + * Fetch Minecraft versions from the Modrinth API + * @returns An array of Minecraft versions for use with a prompt */ export async function getMinecraftVersions(): Promise { try { @@ -177,8 +183,8 @@ export async function getMinecraftVersions(): Promise { } /** - * Fetch Modloaders from Modrinth - * @returns The modloaders + * Fetch modloaders from the Modrinth API + * @returns An array of modloaders for use with a prompt */ export async function getModloaders(): Promise { try { From cb2bea4246659aec480000e89303124da292e875 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 13:53:06 -0500 Subject: [PATCH 093/110] renamed defaults param to options --- src/user_prompts.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/user_prompts.ts b/src/user_prompts.ts index 218505b..3461166 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -181,12 +181,12 @@ export async function promptUserForInfo(defaults: Jsonfile): Promise> { const licenseText = await getLicenseText(modpackInfo.license); const answers: prompts.Answers = await prompts( @@ -194,26 +194,26 @@ export async function promptUserAboutOptionalFiles( fileGenerationConfirm( "addLicense", `${config.fileFields.addLicense.prompt}?`, - licenseText && defaults.addLicense === undefined ? true : false, + licenseText && options.addLicense === undefined ? true : false, ), fileGenerationConfirm( "addReadme", `${config.fileFields.addReadme.prompt}?`, - defaults.addReadme === undefined, + options.addReadme === undefined, ), fileGenerationConfirm( "addGitignore", `${config.fileFields.addGitignore.prompt}?`, - defaults.addGitignore === undefined, + options.addGitignore === undefined, ), ], config.PROMPTS_OPTIONS, ); answers.addLicense = - answers.addLicense === undefined ? (licenseText ? defaults.addLicense : false) : answers.addLicense; - answers.addReadme = answers.addReadme === undefined ? defaults.addReadme : answers.addReadme; - answers.addGitignore = answers.addGitignore === undefined ? defaults.addGitignore : answers.addGitignore; + answers.addLicense === undefined ? (licenseText ? options.addLicense : false) : answers.addLicense; + answers.addReadme = answers.addReadme === undefined ? options.addReadme : answers.addReadme; + answers.addGitignore = answers.addGitignore === undefined ? options.addGitignore : answers.addGitignore; return answers; } From fb78108d36f2c9a323f85514ab8bab197611a20d Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:01:04 -0500 Subject: [PATCH 094/110] update user prompts jsdocs --- src/user_prompts.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/user_prompts.ts b/src/user_prompts.ts index 3461166..4fbfe65 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -58,7 +58,7 @@ function optionalText( } /** - * Get an other answer from the user + * Get the value of an "other" answer from the user */ async function getOtherAnswer(value: string, message: string, initial: PromptObject["initial"]) { if (value && value !== config.OTHER_OPTION.value) { @@ -70,7 +70,7 @@ async function getOtherAnswer(value: string, message: string, initial: PromptObj } /** - * Returns a required autocomplete prompt with a fallback to the other option + * Returns a required autocomplete prompt with a fallback to the "other" option */ function requiredAutocomplete( name: keyof ModpackInfo | "other", @@ -98,7 +98,7 @@ function requiredAutocomplete( } /** - * Returns an confirmation prompt to generate an optional file + * Returns a confirmation prompt to generate an optional file */ function fileGenerationConfirm( name: OptionalFileOptions | "other", @@ -114,9 +114,9 @@ function fileGenerationConfirm( } /** - * Get user input for modpack information - * @param defaults - The initial/default modpack information - * @returns The modpack information from the user + * Prompt the user for modpack information + * @param defaults - The default modpack information, used as the initial value for each prompt + * @returns The answers to the prompts from the user */ export async function promptUserForInfo(defaults: Jsonfile): Promise> { const licenseList = await getLicenseList(); @@ -180,7 +180,7 @@ export async function promptUserForInfo(defaults: Jsonfile): Promise Date: Fri, 6 Mar 2026 14:15:45 -0500 Subject: [PATCH 095/110] update logger jsdocs --- src/logger.ts | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index d4ba896..0fd458c 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -36,11 +36,19 @@ class Logger { silentConsole = false; lastLogWasNewline = false; + /** + * Set the quiet console flag. When set, only errors and warnings are logged to the console. + * @param silent - Whether to also set the silent console flag. When set, no console output is logged. + */ quiet(silent: boolean = false) { this.quietConsole = true; this.silentConsole = silent; } + /** + * Set the quiet console flag based on the options object. + * @param options - The options object containing the quiet and silent flags. + */ quietFromOptions(options: InitOptions | Options) { if (options.silent) { this.quietConsole = true; @@ -50,7 +58,13 @@ class Logger { } } - styleArgs(style: InspectColor[] | null, args: any[]) { + /** + * Style the arguments with the given style. + * @param style - The style to apply to the arguments. + * @param args - The arguments to style. + * @returns The styled arguments. + */ + styleArgs(style: InspectColor[] | undefined, args: any[]): any[] | "" { if (!style) { return args; } @@ -86,6 +100,11 @@ class Logger { this.lastLogWasNewline = true; } + /** + * Log a message indicating that a file was generated. + * @param desc - The description of the file that was generated. + * @param outputPath - The path to the file that was generated. + */ generated(desc: string, outputPath: string) { if (this.quietConsole) { return; @@ -100,6 +119,9 @@ class Logger { this.lastLogWasNewline = false; } + /** + * Log a newline. Only logs a newline if the last log was not a newline. + */ newline() { if (this.quietConsole) { return; @@ -114,7 +136,7 @@ class Logger { /** * Log a message. * @param message - The message to log. - * @param otherMessages - The other messages to log. + * @param otherMessages - Other messages to log. */ log(message: any, ...otherMessages: any[]) { if (this.quietConsole) { @@ -127,7 +149,7 @@ class Logger { /** * Log an info message. * @param message - The message to log. - * @param otherMessages - The other messages to log. + * @param otherMessages - Other messages to log. */ info(message: any, ...otherMessages: any[]) { if (this.quietConsole) { @@ -140,7 +162,7 @@ class Logger { /** * Log a debug message. * @param message - The message to log. - * @param otherMessages - The other messages to log. + * @param otherMessages - Other messages to log. */ debug(message: any, ...otherMessages: any[]) { if (this.silentConsole) { @@ -156,7 +178,7 @@ class Logger { /** * Log a warning message. * @param message - The message to log. - * @param otherMessages - The other messages to log. + * @param otherMessages - Other messages to log. */ warn(message: any, ...otherMessages: any[]) { if (this.silentConsole) { @@ -172,7 +194,7 @@ class Logger { /** * Log an error message. * @param message - The message to log. - * @param otherMessages - The other messages to log. + * @param otherMessages - Other messages to log. */ error(message: any, ...otherMessages: any[]) { if (this.silentConsole) { From dbb44f8453bfc12ff104973ce63b54299adc5507 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:24:28 -0500 Subject: [PATCH 096/110] rename ContentVersionDependency to VersionDependency --- src/modpack-lock.ts | 6 +++--- src/types/modrinthResponses.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modpack-lock.ts b/src/modpack-lock.ts index 18452cc..b158620 100644 --- a/src/modpack-lock.ts +++ b/src/modpack-lock.ts @@ -15,7 +15,7 @@ import type { DependencyCategory, LockfileDependency, ContentVersion, - ContentVersionDependency, + VersionDependency, } from "./types/index.js"; /** @@ -26,7 +26,7 @@ import type { /** * Generate the modpack files (lockfile, JSON, and optionally license, gitignore, and readme) - * @param modpackInfo - The modpack information + * @param modpackInfo - The Jsonfile object containing the modpack information * @param workingDir - The directory to generate the files in * @param options - The options object * @returns The lockfile object @@ -84,5 +84,5 @@ export type { DependencyCategory, LockfileDependency, ContentVersion, - ContentVersionDependency, + VersionDependency, }; diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 00d7a58..5291bad 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -1,4 +1,4 @@ -export type ContentVersionDependency = { +export type VersionDependency = { version_id: string; project_id: string; file_name: string; @@ -22,7 +22,7 @@ export type ContentVersion = { version_type?: string; status?: string; requested_status?: string | null; - dependencies?: ContentVersionDependency[]; + dependencies?: VersionDependency[]; }; export type ProjectResponseItem = { From 727c1d91969901c620daadf3ddd49b2543332033 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:24:46 -0500 Subject: [PATCH 097/110] add modloaders to workspace dictionary --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 00d665f..ddd3cd7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "logm", "modloader", + "modloaders", "modpack", "modrinth" ] From 67205aec7f85d6403bcfa17c474073e55b4fbe6b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:36:11 -0500 Subject: [PATCH 098/110] add jsdocs for modrinth responses --- src/types/modrinthResponses.ts | 64 ++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/src/types/modrinthResponses.ts b/src/types/modrinthResponses.ts index 5291bad..221b08c 100644 --- a/src/types/modrinthResponses.ts +++ b/src/types/modrinthResponses.ts @@ -1,3 +1,10 @@ +/** + * The shape of a dependency on another version of another project + * @property version_id - The ID of the dependency version + * @property project_id - The ID of the project + * @property file_name - The name of the file + * @property dependency_type - The type of dependency + */ export type VersionDependency = { version_id: string; project_id: string; @@ -5,6 +12,26 @@ export type VersionDependency = { dependency_type: string; }; +/** + * A metadata for a specific version file of a project on Modrinth. Saved in the lockfile. + * @property id - The ID of the version + * @property project_id - The ID of the project + * @property author_id - The ID of the author + * @property date_published - The date the version was published + * @property downloads - The number of downloads of the version + * @property files - The files of the version + * @property game_versions - The game versions the version is compatible with + * @property loaders - The loaders the version is compatible with + * @property featured - Whether the version is featured + * @property name - The name of the version + * @property version_number - The version number + * @property changelog - The changelog of the version + * @property changelog_url - The URL of the changelog + * @property version_type - The type of version + * @property status - The status of the version + * @property requested_status - The requested status of the version + * @property dependencies - The dependencies for this version + */ export type ContentVersion = { id: string; project_id: string; @@ -25,14 +52,17 @@ export type ContentVersion = { dependencies?: VersionDependency[]; }; +/** + * The shape of a project response from the Modrinth API + */ export type ProjectResponseItem = { - id: string; // - project_type: string; // - team: string; // - published: string; // - updated: string; // - downloads: number; // - followers: number; // + id: string; + project_type: string; + team: string; + published: string; + updated: string; + downloads: number; + followers: number; slug?: string; client_side?: string; server_side?: string; @@ -64,8 +94,14 @@ export type ProjectResponseItem = { monetization_status?: string; }; +/** + * The types of Minecraft versions that can be returned from the Modrinth API + */ export type MinecraftVersionType = "release" | "alpha" | "beta" | "snapshot"; +/** + * The shape of an item in the Minecraft versions response from the Modrinth API + */ export type MinecraftVersionResponseItem = { version: string; version_type: MinecraftVersionType; @@ -73,17 +109,23 @@ export type MinecraftVersionResponseItem = { major: boolean; }; +/** + * The shape of an item in the modloaders response from the Modrinth API + */ export type ModloaderResponseItem = { icon: string; name: string; supported_project_types: string[]; }; +/** + * The shape of an item in the users response from the Modrinth API + */ export type UserResponseItem = { - username: string; // - id: string; // - created: string; // - role: "admin" | "moderator" | "developer"; // + username: string; + id: string; + created: string; + role: "admin" | "moderator" | "developer"; name?: string; email?: string | null; bio?: string; From fc563c960eca4a9964bfae06230724b6c7ff7105 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:51:15 -0500 Subject: [PATCH 099/110] added path property to Options type --- src/types/options.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/options.ts b/src/types/options.ts index 4d46fba..ed1fc24 100644 --- a/src/types/options.ts +++ b/src/types/options.ts @@ -6,6 +6,7 @@ * @property gitignore - Whether to generate a .gitignore file * @property readme - Whether to generate README.md files * @property licenseFile - Whether to generate a license file + * @property path - The modpack root directory */ export interface Options { dryRun?: boolean; From 3e3967790f8b298225bc8035ccda6a47b5c6a0ea Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:51:52 -0500 Subject: [PATCH 100/110] removed types from getLockfile jsdoc --- src/directory_scanning.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directory_scanning.ts b/src/directory_scanning.ts index 0c28824..dd6e35a 100644 --- a/src/directory_scanning.ts +++ b/src/directory_scanning.ts @@ -108,8 +108,8 @@ export async function getModpackInfo(directoryPath: string): Promise} The Lockfile object if the file exists, otherwise null + * @param directoryPath - The path to the directory to scan + * @returns The Lockfile object if the file exists, otherwise null */ export async function getLockfile(directoryPath: string): Promise { return getJsonFile(directoryPath, config.MODPACK_LOCKFILE_NAME); From bfb4be1bf30cacfc517b809fc55661c158f44e90 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 14:52:19 -0500 Subject: [PATCH 101/110] removed extra properties from lockfile type --- src/types/Lockfile.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/types/Lockfile.ts b/src/types/Lockfile.ts index 95acf83..8ccc025 100644 --- a/src/types/Lockfile.ts +++ b/src/types/Lockfile.ts @@ -5,16 +5,8 @@ import type {ContentVersion} from "./index.js"; * @property version - The version of the lockfile * @property generated - The date and time the lockfile was generated * @property total - The total number of files in the modpack - * @property counts - An object containing the number of files in each category - * @property counts.mods - The number of mods in the modpack - * @property counts.resourcepacks - The number of resourcepacks in the modpack - * @property counts.datapacks - The number of datapacks in the modpack - * @property counts.shaderpacks - The number of shaderpacks in the modpack - * @property dependencies - An object containing all dependency version information - * @property dependencies.mods - An array with version information for each mod - * @property dependencies.resourcepacks - An array with version information for each resourcepack - * @property dependencies.datapacks - An array with version information for each datapack - * @property dependencies.shaderpacks - An array with version information for each shaderpack + * @property counts - An object containing the number of files in each dependency category + * @property dependencies - An object containing arrays with all the modpack's dependencies and their version information */ export type Lockfile = { version: string; From 43f4867ad2242b29c7be0314614435f913a865a7 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Fri, 6 Mar 2026 15:00:47 -0500 Subject: [PATCH 102/110] add docs deploy action --- .github/workflows/deploy-docs.yml | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/deploy-docs.yml diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..7a5c00b --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,56 @@ +name: Deploy Docs + +on: + push: + branches: + - "main" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "github-pages" + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Build docs + run: npm run docs + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From 4e2a9c0e71bae80f897108c79fabacc52a22bc5a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sat, 7 Mar 2026 22:34:01 -0500 Subject: [PATCH 103/110] fixed string template missing $ --- src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index cb2ce9c..965414f 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -149,7 +149,7 @@ modpackLock `Must provide options for required fields:`, styleText( ["bold"], - `${author ? "" : "author"}$ {modloader ? "" : "modloader"} ${targetMinecraftVersion ? "" : "targetMinecraftVersion"}`, + `${author ? "" : "author"}$ ${modloader ? "" : "modloader"} ${targetMinecraftVersion ? "" : "targetMinecraftVersion"}`, ), ); process.exitCode = 1; From 4049a9860f265ec48fb964cea1a80690266d535a Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 12:08:03 -0400 Subject: [PATCH 104/110] made Jsonfile type less strict -- reads from file, could be incomplete --- src/types/Jsonfile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/Jsonfile.ts b/src/types/Jsonfile.ts index 8996a87..23a3fc5 100644 --- a/src/types/Jsonfile.ts +++ b/src/types/Jsonfile.ts @@ -6,8 +6,8 @@ import type {DependencyCategory, ModpackInfo} from "./index.js"; * @property scripts - The scripts of the modpack * @property [key: string] - Any other properties of the modpack */ -export type Jsonfile = ModpackInfo & { - dependencies?: Record; +export type Jsonfile = Partial & { + dependencies?: Partial>; scripts?: { [key: string]: string; }; From d49289cc96a3d1bbf547ff4de2f5b2d32e478be2 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 12:08:38 -0400 Subject: [PATCH 105/110] guard for missing license in optional file prompts --- src/user_prompts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user_prompts.ts b/src/user_prompts.ts index 4fbfe65..e2cb857 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -188,7 +188,7 @@ export async function promptUserAboutOptionalFiles( modpackInfo: Jsonfile, options: InitOptions, ): Promise> { - const licenseText = await getLicenseText(modpackInfo.license); + const licenseText = modpackInfo.license ? await getLicenseText(modpackInfo.license) : null; const answers: prompts.Answers = await prompts( [ fileGenerationConfirm( From c7f09f4c6d071d86919736ca37235345c0598091 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 12:09:35 -0400 Subject: [PATCH 106/110] guard for missing fields in generateLicense --- src/generate_license.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/generate_license.ts b/src/generate_license.ts index 8e39094..d4764ab 100644 --- a/src/generate_license.ts +++ b/src/generate_license.ts @@ -28,6 +28,9 @@ export default async function generateLicense( try { const spdxId = modpackInfo.license; + if (!spdxId) { + throw new Error("License ID is required to generate a license file"); + } let licenseText = licenseTextOverride || (await getLicenseText(spdxId)); if (!licenseText) { @@ -36,12 +39,16 @@ export default async function generateLicense( licenseText = licenseText.replace("[year]", String(new Date().getFullYear())); licenseText = licenseText.replace("{{year}}", String(new Date().getFullYear())); - licenseText = licenseText.replace("[fullname]", modpackInfo.author); - licenseText = licenseText.replace("{{fullname}}", modpackInfo.author); - licenseText = licenseText.replace("[organization]", modpackInfo.author); - licenseText = licenseText.replace("{{organization}}", modpackInfo.author); - licenseText = licenseText.replace("[project]", modpackInfo.name); - licenseText = licenseText.replace("{{project}}", modpackInfo.name); + if (modpackInfo.author) { + licenseText = licenseText.replace("[fullname]", modpackInfo.author); + licenseText = licenseText.replace("{{fullname}}", modpackInfo.author); + licenseText = licenseText.replace("[organization]", modpackInfo.author); + licenseText = licenseText.replace("{{organization}}", modpackInfo.author); + } + if (modpackInfo.name) { + licenseText = licenseText.replace("[project]", modpackInfo.name); + licenseText = licenseText.replace("{{project}}", modpackInfo.name); + } if (options.dryRun) { logm.debug( From 2e77805fd66da07c23cd4be23983aca8ef69e2f2 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 12:10:31 -0400 Subject: [PATCH 107/110] guard against missing id and set correct default if missing --- src/cli.ts | 6 +++--- test/modpack-lock.test.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 965414f..4c771b4 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -149,7 +149,7 @@ modpackLock `Must provide options for required fields:`, styleText( ["bold"], - `${author ? "" : "author"}$ ${modloader ? "" : "modloader"} ${targetMinecraftVersion ? "" : "targetMinecraftVersion"}`, + `${author ? "" : "author"} ${modloader ? "" : "modloader"} ${targetMinecraftVersion ? "" : "targetMinecraftVersion"}`, ), ); process.exitCode = 1; @@ -159,7 +159,7 @@ modpackLock const defaults: ModpackInfo = { name: defaultName, version: config.DEFAULT_MODPACK_VERSION, - id: defaultName, + id: "", // Required, defaults after merge if not provided description: "", author: author, // Required, no default projectUrl: "", @@ -171,7 +171,7 @@ modpackLock }; const modpackInfo: Jsonfile = mergeModpackInfo(existingInfo, options, defaults); - modpackInfo.id = slugify(modpackInfo.id, config.SLUGIFY_OPTIONS); + modpackInfo.id = slugify(modpackInfo.id || modpackInfo.name || defaultName, config.SLUGIFY_OPTIONS); options.readme = options.addReadme || false; options.gitignore = options.addGitignore || false; diff --git a/test/modpack-lock.test.js b/test/modpack-lock.test.js index f0439ea..0f0d130 100644 --- a/test/modpack-lock.test.js +++ b/test/modpack-lock.test.js @@ -1047,5 +1047,26 @@ describe("CLI", () => { expect(result.stderr).not.toContain("targetMinecraftVersion"); expect(result.stderr).not.toContain("targetMinecraftVersion"); }); + + it("fills and slugifies id during noninteractive init when existing modpack.json is missing it", async () => { + const existingJsonWorkspace = await extractWorkspaceFixture(); + + const modpackInfo = { + name: "Incomplete Pack", + version: "1.0.0", + author: "Test Author", + modloader: "fabric", + targetMinecraftVersion: "1.21.1", + }; + + await fs.writeFile(path.join(existingJsonWorkspace, JSON_NAME), JSON.stringify(modpackInfo, null, 2)); + + const result = await runCli(["init", "--noninteractive", "--folder", existingJsonWorkspace]); + + expect(result.exitCode).toBe(0); + + const json = await readModpackJson(existingJsonWorkspace); + expect(json.id).toBe("incomplete-pack"); + }); }); }); From a4a982845e62151243aad25aba67ede000fa4a10 Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 14:12:04 -0400 Subject: [PATCH 108/110] replace slugify with @sindersorhus/slugify --- package-lock.json | 41 +++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/cli.ts | 2 +- src/config/options.ts | 17 +++++++---------- src/user_prompts.ts | 2 +- 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e60439..dab9153 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.6.2", "license": "MIT", "dependencies": { + "@sindresorhus/slugify": "^3.0.0", "commander": "^14.0.3", "prompts": "^2.4.2", "slugify": "^1.6.6" @@ -1209,6 +1210,46 @@ "dev": true, "license": "MIT" }, + "node_modules/@sindresorhus/slugify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-3.0.0.tgz", + "integrity": "sha512-SCrKh1zS96q+CuH5GumHcyQEVPsM4Ve8oE0E6tw7AAhGq50K8ojbTUOQnX/j9Mhcv/AXiIsbCfquovyGOo5fGw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/transliterate": "^2.0.0", + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/slugify/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-2.3.1.tgz", + "integrity": "sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", diff --git a/package.json b/package.json index 9952e3b..16e35bf 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "build/**/*" ], "dependencies": { + "@sindresorhus/slugify": "^3.0.0", "commander": "^14.0.3", "prompts": "^2.4.2", "slugify": "^1.6.6" diff --git a/src/cli.ts b/src/cli.ts index 4c771b4..e2f4c22 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,7 +1,7 @@ #!/usr/bin/env NODE_OPTIONS=--no-warnings node import {Command} from "commander"; -import slugify from "slugify"; +import slugify from "@sindresorhus/slugify"; import path from "path"; import {ChildProcess, spawn} from "child_process"; import {generateLockfile, printLockfileSummary} from "./generate_lockfile.js"; diff --git a/src/config/options.ts b/src/config/options.ts index 96336b7..337bd28 100644 --- a/src/config/options.ts +++ b/src/config/options.ts @@ -1,18 +1,15 @@ import {logm} from "../logger.js"; +import type {Options as slugifyOptions} from "@sindresorhus/slugify"; /** Options for slugify */ -export const SLUGIFY_OPTIONS: { - lower: boolean; - strict: boolean; - separator: string; - locale: string; - trim: boolean; -} = { - lower: true, - strict: true, +export const SLUGIFY_OPTIONS: slugifyOptions = { + lowercase: true, separator: "-", locale: "en", - trim: true, + transliterate: true, + preserveTrailingDash: false, + preserveLeadingUnderscore: false, + decamelize: false, }; /** Options for prompts */ diff --git a/src/user_prompts.ts b/src/user_prompts.ts index e2cb857..b18d52b 100644 --- a/src/user_prompts.ts +++ b/src/user_prompts.ts @@ -1,5 +1,5 @@ import prompts, {type Choice, type InitialReturnValue, type PromptObject} from "prompts"; -import slugify from "slugify"; +import slugify from "@sindresorhus/slugify"; import * as config from "./config/index.js"; import {getLicenseList, getLicenseText} from "./github_interactions.js"; import {getMinecraftVersions, getModloaders} from "./modrinth_interactions.js"; From 0fa5e86708c19b2cefe577b91dd965187609d22b Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 19:07:24 -0400 Subject: [PATCH 109/110] remove docs folder from committed files --- docs/.nojekyll | 1 - docs/assets/hierarchy.js | 1 - docs/assets/highlight.css | 64 - docs/assets/icons.js | 18 - docs/assets/icons.svg | 1 - docs/assets/main.js | 60 - docs/assets/navigation.js | 1 - docs/assets/search.js | 1 - docs/assets/style.css | 1633 -------------------- docs/assets/typedoc-github-style.css | 434 ------ docs/functions/generateGitignoreRules.html | 5 - docs/functions/generateJson.html | 7 - docs/functions/generateLicense.html | 7 - docs/functions/generateLockfile.html | 5 - docs/functions/generateModpackFiles.html | 6 - docs/functions/generateReadmeFiles.html | 5 - docs/functions/getLockfile.html | 4 - docs/functions/getModpackInfo.html | 4 - docs/functions/promptUserForInfo.html | 4 - docs/hierarchy.html | 1 - docs/index.html | 185 --- docs/interfaces/InitOptions.html | 36 - docs/interfaces/Lockfile.html | 20 - docs/interfaces/ModpackInfo.html | 24 - docs/interfaces/Options.html | 14 - docs/media/LICENSE | 21 - docs/modules.html | 1 - docs/sitemap.xml | 67 - 28 files changed, 2630 deletions(-) delete mode 100644 docs/.nojekyll delete mode 100644 docs/assets/hierarchy.js delete mode 100644 docs/assets/highlight.css delete mode 100644 docs/assets/icons.js delete mode 100644 docs/assets/icons.svg delete mode 100644 docs/assets/main.js delete mode 100644 docs/assets/navigation.js delete mode 100644 docs/assets/search.js delete mode 100644 docs/assets/style.css delete mode 100644 docs/assets/typedoc-github-style.css delete mode 100644 docs/functions/generateGitignoreRules.html delete mode 100644 docs/functions/generateJson.html delete mode 100644 docs/functions/generateLicense.html delete mode 100644 docs/functions/generateLockfile.html delete mode 100644 docs/functions/generateModpackFiles.html delete mode 100644 docs/functions/generateReadmeFiles.html delete mode 100644 docs/functions/getLockfile.html delete mode 100644 docs/functions/getModpackInfo.html delete mode 100644 docs/functions/promptUserForInfo.html delete mode 100644 docs/hierarchy.html delete mode 100644 docs/index.html delete mode 100644 docs/interfaces/InitOptions.html delete mode 100644 docs/interfaces/Lockfile.html delete mode 100644 docs/interfaces/ModpackInfo.html delete mode 100644 docs/interfaces/Options.html delete mode 100644 docs/media/LICENSE delete mode 100644 docs/modules.html delete mode 100644 docs/sitemap.xml diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e2ac661..0000000 --- a/docs/.nojekyll +++ /dev/null @@ -1 +0,0 @@ -TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/assets/hierarchy.js b/docs/assets/hierarchy.js deleted file mode 100644 index 88636f0..0000000 --- a/docs/assets/hierarchy.js +++ /dev/null @@ -1 +0,0 @@ -window.hierarchyData = "eJyrVirKzy8pVrKKjtVRKkpNy0lNLsnMzwMKVNfWAgCbHgqm" \ No newline at end of file diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css deleted file mode 100644 index 3f96598..0000000 --- a/docs/assets/highlight.css +++ /dev/null @@ -1,64 +0,0 @@ -:root { - --light-hl-0: #6F42C1; - --dark-hl-0: #B392F0; - --light-hl-1: #24292E; - --dark-hl-1: #E1E4E8; - --light-hl-2: #032F62; - --dark-hl-2: #9ECBFF; - --light-hl-3: #005CC5; - --dark-hl-3: #79B8FF; - --light-hl-4: #D73A49; - --dark-hl-4: #F97583; - --light-hl-5: #B31D28; - --dark-hl-5: #FDAEB7; - --light-code-background: #fff; - --dark-code-background: #24292e; -} - -@media (prefers-color-scheme: light) { :root { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --code-background: var(--light-code-background); -} } - -@media (prefers-color-scheme: dark) { :root { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --code-background: var(--dark-code-background); -} } - -:root[data-theme='light'] { - --hl-0: var(--light-hl-0); - --hl-1: var(--light-hl-1); - --hl-2: var(--light-hl-2); - --hl-3: var(--light-hl-3); - --hl-4: var(--light-hl-4); - --hl-5: var(--light-hl-5); - --code-background: var(--light-code-background); -} - -:root[data-theme='dark'] { - --hl-0: var(--dark-hl-0); - --hl-1: var(--dark-hl-1); - --hl-2: var(--dark-hl-2); - --hl-3: var(--dark-hl-3); - --hl-4: var(--dark-hl-4); - --hl-5: var(--dark-hl-5); - --code-background: var(--dark-code-background); -} - -.hl-0 { color: var(--hl-0); } -.hl-1 { color: var(--hl-1); } -.hl-2 { color: var(--hl-2); } -.hl-3 { color: var(--hl-3); } -.hl-4 { color: var(--hl-4); } -.hl-5 { color: var(--hl-5); } -pre, code { background: var(--code-background); } diff --git a/docs/assets/icons.js b/docs/assets/icons.js deleted file mode 100644 index 3ae8f55..0000000 --- a/docs/assets/icons.js +++ /dev/null @@ -1,18 +0,0 @@ -(function() { - addIcons(); - function addIcons() { - if (document.readyState === "loading") return document.addEventListener("DOMContentLoaded", addIcons); - const svg = document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg")); - svg.innerHTML = `MMNEPVFCICPMFPCPTTAAATR`; - svg.style.display = "none"; - if (location.protocol === "file:") updateUseElements(); - } - - function updateUseElements() { - document.querySelectorAll("use").forEach(el => { - if (el.getAttribute("href").includes("#icon-")) { - el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); - } - }); - } -})() \ No newline at end of file diff --git a/docs/assets/icons.svg b/docs/assets/icons.svg deleted file mode 100644 index 10db10b..0000000 --- a/docs/assets/icons.svg +++ /dev/null @@ -1 +0,0 @@ -MMNEPVFCICPMFPCPTTAAATR \ No newline at end of file diff --git a/docs/assets/main.js b/docs/assets/main.js deleted file mode 100644 index 64b80ab..0000000 --- a/docs/assets/main.js +++ /dev/null @@ -1,60 +0,0 @@ -"use strict"; -window.translations={"copy":"Copy","copied":"Copied!","normally_hidden":"This member is normally hidden due to your filter settings.","hierarchy_expand":"Expand","hierarchy_collapse":"Collapse","folder":"Folder","search_index_not_available":"The search index is not available","search_no_results_found_for_0":"No results found for {0}","kind_1":"Project","kind_2":"Module","kind_4":"Namespace","kind_8":"Enumeration","kind_16":"Enumeration Member","kind_32":"Variable","kind_64":"Function","kind_128":"Class","kind_256":"Interface","kind_512":"Constructor","kind_1024":"Property","kind_2048":"Method","kind_4096":"Call Signature","kind_8192":"Index Signature","kind_16384":"Constructor Signature","kind_32768":"Parameter","kind_65536":"Type Literal","kind_131072":"Type Parameter","kind_262144":"Accessor","kind_524288":"Get Signature","kind_1048576":"Set Signature","kind_2097152":"Type Alias","kind_4194304":"Reference","kind_8388608":"Document"}; -"use strict";(()=>{var Ke=Object.create;var he=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ye=Object.prototype.hasOwnProperty;var et=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var tt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ze(e))!Ye.call(t,i)&&i!==n&&he(t,i,{get:()=>e[i],enumerable:!(r=Ge(e,i))||r.enumerable});return t};var nt=(t,e,n)=>(n=t!=null?Ke(Xe(t)):{},tt(e||!t||!t.__esModule?he(n,"default",{value:t,enumerable:!0}):n,t));var ye=et((me,ge)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=(function(e){return function(n){e.console&&console.warn&&console.warn(n)}})(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,l],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. -`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(oc?d+=2:a==c&&(n+=r[l+1]*i[d+1],l+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}if(s.str.length==0&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),f=s.str.charAt(1),p;f in s.node.edges?p=s.node.edges[f]:(p=new t.TokenSet,s.node.edges[f]=p),s.str.length==1&&(p.final=!0),i.push({node:p,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),c=0;c1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},(function(e,n){typeof define=="function"&&define.amd?define(n):typeof me=="object"?ge.exports=n():e.lunr=n()})(this,function(){return t})})()});var M,G={getItem(){return null},setItem(){}},K;try{K=localStorage,M=K}catch{K=G,M=G}var S={getItem:t=>M.getItem(t),setItem:(t,e)=>M.setItem(t,e),disableWritingLocalStorage(){M=G},disable(){localStorage.clear(),M=G},enable(){M=K}};window.TypeDoc||={disableWritingLocalStorage(){S.disableWritingLocalStorage()},disableLocalStorage:()=>{S.disable()},enableLocalStorage:()=>{S.enable()}};window.translations||={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings.",hierarchy_expand:"Expand",hierarchy_collapse:"Collapse",search_index_not_available:"The search index is not available",search_no_results_found_for_0:"No results found for {0}",folder:"Folder",kind_1:"Project",kind_2:"Module",kind_4:"Namespace",kind_8:"Enumeration",kind_16:"Enumeration Member",kind_32:"Variable",kind_64:"Function",kind_128:"Class",kind_256:"Interface",kind_512:"Constructor",kind_1024:"Property",kind_2048:"Method",kind_4096:"Call Signature",kind_8192:"Index Signature",kind_16384:"Constructor Signature",kind_32768:"Parameter",kind_65536:"Type Literal",kind_131072:"Type Parameter",kind_262144:"Accessor",kind_524288:"Get Signature",kind_1048576:"Set Signature",kind_2097152:"Type Alias",kind_4194304:"Reference",kind_8388608:"Document"};var pe=[];function X(t,e){pe.push({selector:e,constructor:t})}var Z=class{alwaysVisibleMember=null;constructor(){this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible()),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){pe.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e&&!rt(e)){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r,document.querySelector(".col-sidebar").scrollTop=r}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),n=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach(r=>{r.style.display="block";let i=Array.from(r.querySelectorAll(".tsd-index-link")).every(s=>s.offsetParent==null);r.style.display=i?"none":"block"}),e&&(e.open=n)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(!n)return;let r=n.offsetParent==null,i=n;for(;i!==document.body;)i instanceof HTMLDetailsElement&&(i.open=!0),i=i.parentElement;if(n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let s=document.createElement("p");s.classList.add("warning"),s.textContent=window.translations.normally_hidden,n.prepend(s)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent=window.translations.copy},100)},1e3)})})}};function rt(t){let e=t.getBoundingClientRect(),n=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(e.bottom<0||e.top-n>=0)}var fe=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var Ie=nt(ye(),1);async function R(t){let e=Uint8Array.from(atob(t),s=>s.charCodeAt(0)),r=new Blob([e]).stream().pipeThrough(new DecompressionStream("deflate")),i=await new Response(r).text();return JSON.parse(i)}var Y="closing",ae="tsd-overlay";function it(){let t=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.body.style.overflow="hidden",document.body.style.paddingRight=`${t}px`}function st(){document.body.style.removeProperty("overflow"),document.body.style.removeProperty("padding-right")}function xe(t,e){t.addEventListener("animationend",()=>{t.classList.contains(Y)&&(t.classList.remove(Y),document.getElementById(ae)?.remove(),t.close(),st())}),t.addEventListener("cancel",n=>{n.preventDefault(),ve(t)}),e?.closeOnClick&&document.addEventListener("click",n=>{t.open&&!t.contains(n.target)&&ve(t)},!0)}function Ee(t){if(t.open)return;let e=document.createElement("div");e.id=ae,document.body.appendChild(e),t.showModal(),it()}function ve(t){if(!t.open)return;document.getElementById(ae)?.classList.add(Y),t.classList.add(Y)}var I=class{el;app;constructor(e){this.el=e.el,this.app=e.app}};var be=document.head.appendChild(document.createElement("style"));be.dataset.for="filters";var le={};function we(t){for(let e of t.split(/\s+/))if(le.hasOwnProperty(e)&&!le[e])return!0;return!1}var ee=class extends I{key;value;constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),be.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } -`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=S.getItem(this.key);return e?e==="true":this.el.checked}setLocalStorage(e){S.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),le[`tsd-is-${this.el.name}`]=this.value,this.app.filterChanged(),this.app.updateIndexVisibility()}};var Le=0;async function Se(t,e){if(!window.searchData)return;let n=await R(window.searchData);t.data=n,t.index=Ie.Index.load(n.index),e.innerHTML=""}function _e(){let t=document.getElementById("tsd-search-trigger"),e=document.getElementById("tsd-search"),n=document.getElementById("tsd-search-input"),r=document.getElementById("tsd-search-results"),i=document.getElementById("tsd-search-script"),s=document.getElementById("tsd-search-status");if(!(t&&e&&n&&r&&i&&s))throw new Error("Search controls missing");let o={base:document.documentElement.dataset.base};o.base.endsWith("/")||(o.base+="/"),i.addEventListener("error",()=>{let a=window.translations.search_index_not_available;Pe(s,a)}),i.addEventListener("load",()=>{Se(o,s)}),Se(o,s),ot({trigger:t,searchEl:e,results:r,field:n,status:s},o)}function ot(t,e){let{field:n,results:r,searchEl:i,status:s,trigger:o}=t;xe(i,{closeOnClick:!0});function a(){Ee(i),n.setSelectionRange(0,n.value.length)}o.addEventListener("click",a),n.addEventListener("input",fe(()=>{at(r,n,s,e)},200)),n.addEventListener("keydown",l=>{if(r.childElementCount===0||l.ctrlKey||l.metaKey||l.altKey)return;let d=n.getAttribute("aria-activedescendant"),f=d?document.getElementById(d):null;if(f){let p=!1,v=!1;switch(l.key){case"Home":case"End":case"ArrowLeft":case"ArrowRight":v=!0;break;case"ArrowDown":case"ArrowUp":p=l.shiftKey;break}(p||v)&&ke(n)}if(!l.shiftKey)switch(l.key){case"Enter":f?.querySelector("a")?.click();break;case"ArrowUp":Te(r,n,f,-1),l.preventDefault();break;case"ArrowDown":Te(r,n,f,1),l.preventDefault();break}});function c(){ke(n)}n.addEventListener("change",c),n.addEventListener("blur",c),n.addEventListener("click",c),document.body.addEventListener("keydown",l=>{if(l.altKey||l.metaKey||l.shiftKey)return;let d=l.ctrlKey&&l.key==="k",f=!l.ctrlKey&&!ut()&&l.key==="/";(d||f)&&(l.preventDefault(),a())})}function at(t,e,n,r){if(!r.index||!r.data)return;t.innerHTML="",n.innerHTML="",Le+=1;let i=e.value.trim(),s;if(i){let a=i.split(" ").map(c=>c.length?`*${c}*`:"").join(" ");s=r.index.search(a).filter(({ref:c})=>{let l=r.data.rows[Number(c)].classes;return!l||!we(l)})}else s=[];if(s.length===0&&i){let a=window.translations.search_no_results_found_for_0.replace("{0}",` "${te(i)}" `);Pe(n,a);return}for(let a=0;ac.score-a.score);let o=Math.min(10,s.length);for(let a=0;a`,f=Ce(c.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(f+=` (score: ${s[a].score.toFixed(2)})`),c.parent&&(f=` - ${Ce(c.parent,i)}.${f}`);let p=document.createElement("li");p.id=`tsd-search:${Le}-${a}`,p.role="option",p.ariaSelected="false",p.classList.value=c.classes??"";let v=document.createElement("a");v.tabIndex=-1,v.href=r.base+c.url,v.innerHTML=d+`${f}`,p.append(v),t.appendChild(p)}}function Te(t,e,n,r){let i;if(r===1?i=n?.nextElementSibling||t.firstElementChild:i=n?.previousElementSibling||t.lastElementChild,i!==n){if(!i||i.role!=="option"){console.error("Option missing");return}i.ariaSelected="true",i.scrollIntoView({behavior:"smooth",block:"nearest"}),e.setAttribute("aria-activedescendant",i.id),n?.setAttribute("aria-selected","false")}}function ke(t){let e=t.getAttribute("aria-activedescendant");(e?document.getElementById(e):null)?.setAttribute("aria-selected","false"),t.setAttribute("aria-activedescendant","")}function Ce(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(te(t.substring(s,o)),`${te(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(te(t.substring(s))),i.join("")}var lt={"&":"&","<":"<",">":">","'":"'",'"':"""};function te(t){return t.replace(/[&<>"'"]/g,e=>lt[e])}function Pe(t,e){t.innerHTML=e?`
${e}
`:""}var ct=["button","checkbox","file","hidden","image","radio","range","reset","submit"];function ut(){let t=document.activeElement;return t?t.isContentEditable||t.tagName==="TEXTAREA"||t.tagName==="SEARCH"?!0:t.tagName==="INPUT"&&!ct.includes(t.type):!1}var D="mousedown",Me="mousemove",$="mouseup",ne={x:0,y:0},Qe=!1,ce=!1,dt=!1,F=!1,Oe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(Oe?"is-mobile":"not-mobile");Oe&&"ontouchstart"in document.documentElement&&(dt=!0,D="touchstart",Me="touchmove",$="touchend");document.addEventListener(D,t=>{ce=!0,F=!1;let e=D=="touchstart"?t.targetTouches[0]:t;ne.y=e.pageY||0,ne.x=e.pageX||0});document.addEventListener(Me,t=>{if(ce&&!F){let e=D=="touchstart"?t.targetTouches[0]:t,n=ne.x-(e.pageX||0),r=ne.y-(e.pageY||0);F=Math.sqrt(n*n+r*r)>10}});document.addEventListener($,()=>{ce=!1});document.addEventListener("click",t=>{Qe&&(t.preventDefault(),t.stopImmediatePropagation(),Qe=!1)});var re=class extends I{active;className;constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener($,n=>this.onPointerUp(n)),this.el.addEventListener("click",n=>n.preventDefault()),document.addEventListener(D,n=>this.onDocumentPointerDown(n)),document.addEventListener($,n=>this.onDocumentPointerUp(n))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let n=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(n),setTimeout(()=>document.documentElement.classList.remove(n),500)}onPointerUp(e){F||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!F&&this.active&&e.target.closest(".col-sidebar")){let n=e.target.closest("a");if(n){let r=window.location.href;r.indexOf("#")!=-1&&(r=r.substring(0,r.indexOf("#"))),n.href.substring(0,r.length)==r&&setTimeout(()=>this.setActive(!1),250)}}}};var ue=new Map,de=class{open;accordions=[];key;constructor(e,n){this.key=e,this.open=n}add(e){this.accordions.push(e),e.open=this.open,e.addEventListener("toggle",()=>{this.toggle(e.open)})}toggle(e){for(let n of this.accordions)n.open=e;S.setItem(this.key,e.toString())}},ie=class extends I{constructor(e){super(e);let n=this.el.querySelector("summary"),r=n.querySelector("a");r&&r.addEventListener("click",()=>{location.assign(r.href)});let i=`tsd-accordion-${n.dataset.key??n.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`,s;if(ue.has(i))s=ue.get(i);else{let o=S.getItem(i),a=o?o==="true":this.el.open;s=new de(i,a),ue.set(i,s)}s.add(this.el)}};function He(t){let e=S.getItem("tsd-theme")||"os";t.value=e,Ae(e),t.addEventListener("change",()=>{S.setItem("tsd-theme",t.value),Ae(t.value)})}function Ae(t){document.documentElement.dataset.theme=t}var se;function Ne(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",Re),Re())}async function Re(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let e=await R(window.navigationData);se=document.documentElement.dataset.base,se.endsWith("/")||(se+="/"),t.innerHTML="";for(let n of e)Be(n,t,[]);window.app.createComponents(t),window.app.showPage(),window.app.ensureActivePageVisible()}function Be(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-accordion`:"tsd-accordion";let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.dataset.key=i.join("$"),o.innerHTML='',De(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let c=a.appendChild(document.createElement("ul"));c.className="tsd-nested-navigation";for(let l of t.children)Be(l,c,i)}else De(t,r,t.class)}function De(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));if(r.href=se+t.path,n&&(r.className=n),location.pathname===r.pathname&&!r.href.includes("#")&&(r.classList.add("current"),r.ariaCurrent="page"),t.kind){let i=window.translations[`kind_${t.kind}`].replaceAll('"',""");r.innerHTML=``}r.appendChild(Fe(t.text,document.createElement("span")))}else{let r=e.appendChild(document.createElement("span")),i=window.translations.folder.replaceAll('"',""");r.innerHTML=``,r.appendChild(Fe(t.text,document.createElement("span")))}}function Fe(t,e){let n=t.split(/(?<=[^A-Z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[_-])(?=[^_-])/);for(let r=0;r{let i=r.target;for(;i.parentElement&&i.parentElement.tagName!="LI";)i=i.parentElement;i.dataset.dropdown&&(i.dataset.dropdown=String(i.dataset.dropdown!=="true"))});let t=new Map,e=new Set;for(let r of document.querySelectorAll(".tsd-full-hierarchy [data-refl]")){let i=r.querySelector("ul");t.has(r.dataset.refl)?e.add(r.dataset.refl):i&&t.set(r.dataset.refl,i)}for(let r of e)n(r);function n(r){let i=t.get(r).cloneNode(!0);i.querySelectorAll("[id]").forEach(s=>{s.removeAttribute("id")}),i.querySelectorAll("[data-dropdown]").forEach(s=>{s.dataset.dropdown="false"});for(let s of document.querySelectorAll(`[data-refl="${r}"]`)){let o=gt(),a=s.querySelector("ul");s.insertBefore(o,a),o.dataset.dropdown=String(!!a),a||s.appendChild(i.cloneNode(!0))}}}function pt(){let t=document.getElementById("tsd-hierarchy-script");t&&(t.addEventListener("load",Ve),Ve())}async function Ve(){let t=document.querySelector(".tsd-panel.tsd-hierarchy:has(h4 a)");if(!t||!window.hierarchyData)return;let e=+t.dataset.refl,n=await R(window.hierarchyData),r=t.querySelector("ul"),i=document.createElement("ul");if(i.classList.add("tsd-hierarchy"),ft(i,n,e),r.querySelectorAll("li").length==i.querySelectorAll("li").length)return;let s=document.createElement("span");s.classList.add("tsd-hierarchy-toggle"),s.textContent=window.translations.hierarchy_expand,t.querySelector("h4 a")?.insertAdjacentElement("afterend",s),s.insertAdjacentText("beforebegin",", "),s.addEventListener("click",()=>{s.textContent===window.translations.hierarchy_expand?(r.insertAdjacentElement("afterend",i),r.remove(),s.textContent=window.translations.hierarchy_collapse):(i.insertAdjacentElement("afterend",r),i.remove(),s.textContent=window.translations.hierarchy_expand)})}function ft(t,e,n){let r=e.roots.filter(i=>mt(e,i,n));for(let i of r)t.appendChild(je(e,i,n))}function je(t,e,n,r=new Set){if(r.has(e))return;r.add(e);let i=t.reflections[e],s=document.createElement("li");if(s.classList.add("tsd-hierarchy-item"),e===n){let o=s.appendChild(document.createElement("span"));o.textContent=i.name,o.classList.add("tsd-hierarchy-target")}else{for(let a of i.uniqueNameParents||[]){let c=t.reflections[a],l=s.appendChild(document.createElement("a"));l.textContent=c.name,l.href=oe+c.url,l.className=c.class+" tsd-signature-type",s.append(document.createTextNode("."))}let o=s.appendChild(document.createElement("a"));o.textContent=t.reflections[e].name,o.href=oe+i.url,o.className=i.class+" tsd-signature-type"}if(i.children){let o=s.appendChild(document.createElement("ul"));o.classList.add("tsd-hierarchy");for(let a of i.children){let c=je(t,a,n,r);c&&o.appendChild(c)}}return r.delete(e),s}function mt(t,e,n){if(e===n)return!0;let r=new Set,i=[t.reflections[e]];for(;i.length;){let s=i.pop();if(!r.has(s)){r.add(s);for(let o of s.children||[]){if(o===n)return!0;i.push(t.reflections[o])}}}return!1}function gt(){let t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("width","20"),t.setAttribute("height","20"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.innerHTML='',t}X(re,"a[data-toggle]");X(ie,".tsd-accordion");X(ee,".tsd-filter-item input[type=checkbox]");var qe=document.getElementById("tsd-theme");qe&&He(qe);var yt=new Z;Object.defineProperty(window,"app",{value:yt});_e();Ne();$e();"virtualKeyboard"in navigator&&(navigator.virtualKeyboard.overlaysContent=!0);})(); -/*! Bundled license information: - -lunr/lunr.js: - (** - * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 - * Copyright (C) 2020 Oliver Nightingale - * @license MIT - *) - (*! - * lunr.utils - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Set - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.tokenizer - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Pipeline - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Vector - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.stemmer - * Copyright (C) 2020 Oliver Nightingale - * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt - *) - (*! - * lunr.stopWordFilter - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.trimmer - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.TokenSet - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Index - * Copyright (C) 2020 Oliver Nightingale - *) - (*! - * lunr.Builder - * Copyright (C) 2020 Oliver Nightingale - *) -*/ diff --git a/docs/assets/navigation.js b/docs/assets/navigation.js deleted file mode 100644 index 205eb25..0000000 --- a/docs/assets/navigation.js +++ /dev/null @@ -1 +0,0 @@ -window.navigationData = "eJyN0k0KwjAQBeC7ZC0WRLvoARRFEQRX4iKkUx3aTkIygiDe3R9UGhtjtn1vPugju4tgOLMoxEqXRqp6TpUWA2EkH+8fkRhsJRW4rJMPj9w291KNVIpiNMmvgw+z1KqusIGg8Q5jwNowanLB+1cWO58Tcozo5DHmABwcpDqReh5nfsO38rFP9UfxnPAsXwiBlQwzZDyQtrA5NeDCXqiZQC+cphj4yBOYJSog9+NXvUoKFh3O7yRwG5BlC1P8M12nloC+XsFftduLsMbq1vDWgZ1q++vx9Uo9cH8DEhlX7w==" \ No newline at end of file diff --git a/docs/assets/search.js b/docs/assets/search.js deleted file mode 100644 index c9733cc..0000000 --- a/docs/assets/search.js +++ /dev/null @@ -1 +0,0 @@ -window.searchData = "eJytmtuOm0gQht+F3FqT6QM+zAMkyirRSpGSm9FohQBPSGzwAs7uajTvvt0YcJWrGpdJrhJM1f838HV1F8xLVFf/NNHD40v0oyiz6EHHy0VUJvs8eog+VdkhSX98KLdVtIiO9c79VpRtXm+TNG/egtN339r9zsWku6RpcqcXRa+LQVLdaztqdv8IxN70gUBxER2SOi/bi5EFjH7mdVNUpcjrHDvbLsubtC4OrdQSx8+2LTKRWxc22yQ5tt+qWmQ0hs42O9TV9zxtv9Q7kWEffqx3v2LaVMc6zaWep+hftNwVaV42srlwjp1tt6+yXZVkuewxwujZlm1SP+ftp0Hq6w0T8pQ6juI3zM9+MEWZp3WybWcMZkidNxhYVz9W6Y9tsWOf/XBOXlEnCh0Su1rlxmEFjJ7zMq+TNmdLDraCofPM2qpN2NmIjYaweSZpdSzb5rrLGDfPJssPeZnlZVrkArOLaLElJOzPbmFhzfpTcr6y+r/PRxYvKPXGhdXHMFzDiAImfx+LvL3qMUTNsmjc7Sqve4xhs0yei7Z4LquandvIB0bOsqrzJOP3UshnDJtl0q887wLVCjn1sX1lk9pBbD+URTuBLjgtx3db7QKr3qXcmzGUHzscXWh3W5WdQZK2xU/2jhFTkjLbPMmyj+FNBTF24df2FTLT91PMc7bX0ZcZfw7OAM71ykSQPN1A70Kf6VTvIjCaWNKJ17VVXWDHNxHEaaKJEJhcaZCIm6RBkmAS7F0oI9O9i8BsunchhoLeRWA62bsQz+u9i8Byonchhr+hxkz2LsTweu8isJT3LsT/xt5FPhhB7xIajLR3EQzmr8LFiLyHyFuslrDdaLkXUNtjmXZZb3HA5I4Ay5L+C2mKOrAlbYvGZfDzcQf2+VCbC7zV5o8GPHoq7k/fKnm5a6CqfcTNwlM3GofcKn1a+/2+dOpWg6hbDXq0rjnAMKmFq/v7Q/ulyet3VR2Am8Rw4k8LNwGz/N/o4WXcMzxE+s7cbVzktsh3mX+3O2xc0mq/P/U2WZUeu/8+9WFf3TpU1T74FP32Plo83i9MfLe066enxeOQ3J3ofhg0zr90icodqYW5v4stylMkT6E87Y70Qq/u1CpGiZokapRo3JFhDA3JMyjPuiPL5FmSZ1Fe7I5iJi8meTHKW7qjJZO3JHlLlLdyRysmb0XyVihv7Y7WTN6a5K1RnkPnccPkbUjeBj94z4G65x49ZUZdQNNRw2LDcIPBUR4HpTlWFWVHYXiUCWGnKD8KA6Q8F8qwxhQihSlSHg5l2WRKksIoKU+IitlkipPCPCmPiVqyyZQphaFSnhW1YpMpWAqTpTwwas0mU7oUxkt3eG24ZE350pgv7ZHRbD3TFDB9UZm60qTYZKY4YcB0BxhLp6aEaUyY9sxoljBNCdOYMO2Z0SxhmhKmMWHaM6NZwjQlTGPCtGdGs4RpSpjGhGnPjGYJ05QwjQnTnhnNEqYpYRoTZjwzmiXMUMIMJsyE1j1D+TKYLxNc+gzFy1wsfiawihlm+cNwGRtaOClaBqNlQmugoWAZDJYJLYOGYmUwVia0EhoKlcFQmdBiaChSBiNlQuuhoUAZDJQNroiW8mQxTza4IloKlMVAWc+IYaudpURZTJTt9lNstbOUKXuxp+qYYqudZfZVmCrrSTFstbOUK4u5sp4Vw1Y7S8mymCzraTFstbOULYvZsp4Xw1Y7S+mymC7riTFstbOUL4v5ij0yhq12MQUsxoDFnhnDVruYEtb/1DUcrtNo8+zDqfFw/ULf57/4/3S/OfT6VuclcnQ9vLy+npsPdwT6D3/OG+G3wmcpV8tHKVeuhVLjOycgtAJCa6nQ8M4Y6GzOOm4JEOn07xXPIvFZIz4lmVgkNXyIPEspoOU2ehIR/IERSC2B1EooBV7SAgDAPeqvz8r0+o+IYFAAACUDYPiMAx4auEladpPAF2wwGHBhSnZFg85Id316OwRuFhC1MgwG0e/NxX23QOq262SmjAF3zcp4GNXGFz9ADuBlZTNwkNufXrJsi8tbB+CIZZNxkDzNbKoIyoSV4fact+zlaqAkZaXtr7ToXgoBMQXEjEyMLadAR8sqc4FmAASsn9my4fg1oho+7YIBAUEtg58hFWCw7kclAwx9sgajAlNSy54dh4ACCCjZ3QYfL846YMnZ9JcnQzNAE1ieZZPm9P4QXBi4rn5ASiZ08bEb3HJQHbSs2DA4KTB9lQwB+BHuLARGs+yvUFZPT+9tj01eb6uaTGPwJGPZHev/5AVcItDQssfH7GIAmVo2gYe/iwEigCMtuxrw9fGsA57Zqr/XMgBCH7fAzYKk9qha2VBDn/GAOLh+dd+Ly55I/2drQAvUQSWrg8yI4FM9Zalh/yUoP25zfygObidQOoXHp9fX/wGI+PsX"; \ No newline at end of file diff --git a/docs/assets/style.css b/docs/assets/style.css deleted file mode 100644 index 44328e9..0000000 --- a/docs/assets/style.css +++ /dev/null @@ -1,1633 +0,0 @@ -@layer typedoc { - :root { - --dim-toolbar-contents-height: 2.5rem; - --dim-toolbar-border-bottom-width: 1px; - --dim-header-height: calc( - var(--dim-toolbar-border-bottom-width) + - var(--dim-toolbar-contents-height) - ); - - /* 0rem For mobile; unit is required for calculation in `calc` */ - --dim-container-main-margin-y: 0rem; - - --dim-footer-height: 3.5rem; - - --modal-animation-duration: 0.2s; - } - - :root { - /* Light */ - --light-color-background: #f2f4f8; - --light-color-background-secondary: #eff0f1; - /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ - --light-color-background-active: #d6d8da; - --light-color-background-warning: #e6e600; - --light-color-warning-text: #222; - --light-color-accent: #c5c7c9; - --light-color-active-menu-item: var(--light-color-background-active); - --light-color-text: #222; - --light-color-contrast-text: #000; - --light-color-text-aside: #5e5e5e; - - --light-color-icon-background: var(--light-color-background); - --light-color-icon-text: var(--light-color-text); - - --light-color-comment-tag-text: var(--light-color-text); - --light-color-comment-tag: var(--light-color-background); - - --light-color-link: #1f70c2; - --light-color-focus-outline: #3584e4; - - --light-color-ts-keyword: #056bd6; - --light-color-ts-project: #b111c9; - --light-color-ts-module: var(--light-color-ts-project); - --light-color-ts-namespace: var(--light-color-ts-project); - --light-color-ts-enum: #7e6f15; - --light-color-ts-enum-member: var(--light-color-ts-enum); - --light-color-ts-variable: #4760ec; - --light-color-ts-function: #572be7; - --light-color-ts-class: #1f70c2; - --light-color-ts-interface: #108024; - --light-color-ts-constructor: var(--light-color-ts-class); - --light-color-ts-property: #9f5f30; - --light-color-ts-method: #be3989; - --light-color-ts-reference: #ff4d82; - --light-color-ts-call-signature: var(--light-color-ts-method); - --light-color-ts-index-signature: var(--light-color-ts-property); - --light-color-ts-constructor-signature: var( - --light-color-ts-constructor - ); - --light-color-ts-parameter: var(--light-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --light-color-ts-type-parameter: #a55c0e; - --light-color-ts-accessor: #c73c3c; - --light-color-ts-get-signature: var(--light-color-ts-accessor); - --light-color-ts-set-signature: var(--light-color-ts-accessor); - --light-color-ts-type-alias: #d51270; - /* reference not included as links will be colored with the kind that it points to */ - --light-color-document: #000000; - - --light-color-alert-note: #0969d9; - --light-color-alert-tip: #1a7f37; - --light-color-alert-important: #8250df; - --light-color-alert-warning: #9a6700; - --light-color-alert-caution: #cf222e; - - --light-external-icon: url("data:image/svg+xml;utf8,"); - --light-color-scheme: light; - } - - :root { - /* Dark */ - --dark-color-background: #2b2e33; - --dark-color-background-secondary: #1e2024; - /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ - --dark-color-background-active: #5d5d6a; - --dark-color-background-warning: #bebe00; - --dark-color-warning-text: #222; - --dark-color-accent: #9096a2; - --dark-color-active-menu-item: var(--dark-color-background-active); - --dark-color-text: #f5f5f5; - --dark-color-contrast-text: #ffffff; - --dark-color-text-aside: #dddddd; - - --dark-color-icon-background: var(--dark-color-background-secondary); - --dark-color-icon-text: var(--dark-color-text); - - --dark-color-comment-tag-text: var(--dark-color-text); - --dark-color-comment-tag: var(--dark-color-background); - - --dark-color-link: #00aff4; - --dark-color-focus-outline: #4c97f2; - - --dark-color-ts-keyword: #3399ff; - --dark-color-ts-project: #e358ff; - --dark-color-ts-module: var(--dark-color-ts-project); - --dark-color-ts-namespace: var(--dark-color-ts-project); - --dark-color-ts-enum: #f4d93e; - --dark-color-ts-enum-member: var(--dark-color-ts-enum); - --dark-color-ts-variable: #798dff; - --dark-color-ts-function: #a280ff; - --dark-color-ts-class: #8ac4ff; - --dark-color-ts-interface: #6cff87; - --dark-color-ts-constructor: var(--dark-color-ts-class); - --dark-color-ts-property: #ff984d; - --dark-color-ts-method: #ff4db8; - --dark-color-ts-reference: #ff4d82; - --dark-color-ts-call-signature: var(--dark-color-ts-method); - --dark-color-ts-index-signature: var(--dark-color-ts-property); - --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); - --dark-color-ts-parameter: var(--dark-color-ts-variable); - /* type literal not included as links will never be generated to it */ - --dark-color-ts-type-parameter: #e07d13; - --dark-color-ts-accessor: #ff6060; - --dark-color-ts-get-signature: var(--dark-color-ts-accessor); - --dark-color-ts-set-signature: var(--dark-color-ts-accessor); - --dark-color-ts-type-alias: #ff6492; - /* reference not included as links will be colored with the kind that it points to */ - --dark-color-document: #ffffff; - - --dark-color-alert-note: #0969d9; - --dark-color-alert-tip: #1a7f37; - --dark-color-alert-important: #8250df; - --dark-color-alert-warning: #9a6700; - --dark-color-alert-caution: #cf222e; - - --dark-external-icon: url("data:image/svg+xml;utf8,"); - --dark-color-scheme: dark; - } - - @media (prefers-color-scheme: light) { - :root { - --color-background: var(--light-color-background); - --color-background-secondary: var( - --light-color-background-secondary - ); - --color-background-active: var(--light-color-background-active); - --color-background-warning: var(--light-color-background-warning); - --color-warning-text: var(--light-color-warning-text); - --color-accent: var(--light-color-accent); - --color-active-menu-item: var(--light-color-active-menu-item); - --color-text: var(--light-color-text); - --color-contrast-text: var(--light-color-contrast-text); - --color-text-aside: var(--light-color-text-aside); - - --color-icon-background: var(--light-color-icon-background); - --color-icon-text: var(--light-color-icon-text); - - --color-comment-tag-text: var(--light-color-text); - --color-comment-tag: var(--light-color-background); - - --color-link: var(--light-color-link); - --color-focus-outline: var(--light-color-focus-outline); - - --color-ts-keyword: var(--light-color-ts-keyword); - --color-ts-project: var(--light-color-ts-project); - --color-ts-module: var(--light-color-ts-module); - --color-ts-namespace: var(--light-color-ts-namespace); - --color-ts-enum: var(--light-color-ts-enum); - --color-ts-enum-member: var(--light-color-ts-enum-member); - --color-ts-variable: var(--light-color-ts-variable); - --color-ts-function: var(--light-color-ts-function); - --color-ts-class: var(--light-color-ts-class); - --color-ts-interface: var(--light-color-ts-interface); - --color-ts-constructor: var(--light-color-ts-constructor); - --color-ts-property: var(--light-color-ts-property); - --color-ts-method: var(--light-color-ts-method); - --color-ts-reference: var(--light-color-ts-reference); - --color-ts-call-signature: var(--light-color-ts-call-signature); - --color-ts-index-signature: var(--light-color-ts-index-signature); - --color-ts-constructor-signature: var( - --light-color-ts-constructor-signature - ); - --color-ts-parameter: var(--light-color-ts-parameter); - --color-ts-type-parameter: var(--light-color-ts-type-parameter); - --color-ts-accessor: var(--light-color-ts-accessor); - --color-ts-get-signature: var(--light-color-ts-get-signature); - --color-ts-set-signature: var(--light-color-ts-set-signature); - --color-ts-type-alias: var(--light-color-ts-type-alias); - --color-document: var(--light-color-document); - - --color-alert-note: var(--light-color-alert-note); - --color-alert-tip: var(--light-color-alert-tip); - --color-alert-important: var(--light-color-alert-important); - --color-alert-warning: var(--light-color-alert-warning); - --color-alert-caution: var(--light-color-alert-caution); - - --external-icon: var(--light-external-icon); - --color-scheme: var(--light-color-scheme); - } - } - - @media (prefers-color-scheme: dark) { - :root { - --color-background: var(--dark-color-background); - --color-background-secondary: var( - --dark-color-background-secondary - ); - --color-background-active: var(--dark-color-background-active); - --color-background-warning: var(--dark-color-background-warning); - --color-warning-text: var(--dark-color-warning-text); - --color-accent: var(--dark-color-accent); - --color-active-menu-item: var(--dark-color-active-menu-item); - --color-text: var(--dark-color-text); - --color-contrast-text: var(--dark-color-contrast-text); - --color-text-aside: var(--dark-color-text-aside); - - --color-icon-background: var(--dark-color-icon-background); - --color-icon-text: var(--dark-color-icon-text); - - --color-comment-tag-text: var(--dark-color-text); - --color-comment-tag: var(--dark-color-background); - - --color-link: var(--dark-color-link); - --color-focus-outline: var(--dark-color-focus-outline); - - --color-ts-keyword: var(--dark-color-ts-keyword); - --color-ts-project: var(--dark-color-ts-project); - --color-ts-module: var(--dark-color-ts-module); - --color-ts-namespace: var(--dark-color-ts-namespace); - --color-ts-enum: var(--dark-color-ts-enum); - --color-ts-enum-member: var(--dark-color-ts-enum-member); - --color-ts-variable: var(--dark-color-ts-variable); - --color-ts-function: var(--dark-color-ts-function); - --color-ts-class: var(--dark-color-ts-class); - --color-ts-interface: var(--dark-color-ts-interface); - --color-ts-constructor: var(--dark-color-ts-constructor); - --color-ts-property: var(--dark-color-ts-property); - --color-ts-method: var(--dark-color-ts-method); - --color-ts-reference: var(--dark-color-ts-reference); - --color-ts-call-signature: var(--dark-color-ts-call-signature); - --color-ts-index-signature: var(--dark-color-ts-index-signature); - --color-ts-constructor-signature: var( - --dark-color-ts-constructor-signature - ); - --color-ts-parameter: var(--dark-color-ts-parameter); - --color-ts-type-parameter: var(--dark-color-ts-type-parameter); - --color-ts-accessor: var(--dark-color-ts-accessor); - --color-ts-get-signature: var(--dark-color-ts-get-signature); - --color-ts-set-signature: var(--dark-color-ts-set-signature); - --color-ts-type-alias: var(--dark-color-ts-type-alias); - --color-document: var(--dark-color-document); - - --color-alert-note: var(--dark-color-alert-note); - --color-alert-tip: var(--dark-color-alert-tip); - --color-alert-important: var(--dark-color-alert-important); - --color-alert-warning: var(--dark-color-alert-warning); - --color-alert-caution: var(--dark-color-alert-caution); - - --external-icon: var(--dark-external-icon); - --color-scheme: var(--dark-color-scheme); - } - } - - :root[data-theme="light"] { - --color-background: var(--light-color-background); - --color-background-secondary: var(--light-color-background-secondary); - --color-background-active: var(--light-color-background-active); - --color-background-warning: var(--light-color-background-warning); - --color-warning-text: var(--light-color-warning-text); - --color-icon-background: var(--light-color-icon-background); - --color-accent: var(--light-color-accent); - --color-active-menu-item: var(--light-color-active-menu-item); - --color-text: var(--light-color-text); - --color-contrast-text: var(--light-color-contrast-text); - --color-text-aside: var(--light-color-text-aside); - --color-icon-text: var(--light-color-icon-text); - - --color-comment-tag-text: var(--light-color-text); - --color-comment-tag: var(--light-color-background); - - --color-link: var(--light-color-link); - --color-focus-outline: var(--light-color-focus-outline); - - --color-ts-keyword: var(--light-color-ts-keyword); - --color-ts-project: var(--light-color-ts-project); - --color-ts-module: var(--light-color-ts-module); - --color-ts-namespace: var(--light-color-ts-namespace); - --color-ts-enum: var(--light-color-ts-enum); - --color-ts-enum-member: var(--light-color-ts-enum-member); - --color-ts-variable: var(--light-color-ts-variable); - --color-ts-function: var(--light-color-ts-function); - --color-ts-class: var(--light-color-ts-class); - --color-ts-interface: var(--light-color-ts-interface); - --color-ts-constructor: var(--light-color-ts-constructor); - --color-ts-property: var(--light-color-ts-property); - --color-ts-method: var(--light-color-ts-method); - --color-ts-reference: var(--light-color-ts-reference); - --color-ts-call-signature: var(--light-color-ts-call-signature); - --color-ts-index-signature: var(--light-color-ts-index-signature); - --color-ts-constructor-signature: var( - --light-color-ts-constructor-signature - ); - --color-ts-parameter: var(--light-color-ts-parameter); - --color-ts-type-parameter: var(--light-color-ts-type-parameter); - --color-ts-accessor: var(--light-color-ts-accessor); - --color-ts-get-signature: var(--light-color-ts-get-signature); - --color-ts-set-signature: var(--light-color-ts-set-signature); - --color-ts-type-alias: var(--light-color-ts-type-alias); - --color-document: var(--light-color-document); - - --color-note: var(--light-color-note); - --color-tip: var(--light-color-tip); - --color-important: var(--light-color-important); - --color-warning: var(--light-color-warning); - --color-caution: var(--light-color-caution); - - --external-icon: var(--light-external-icon); - --color-scheme: var(--light-color-scheme); - } - - :root[data-theme="dark"] { - --color-background: var(--dark-color-background); - --color-background-secondary: var(--dark-color-background-secondary); - --color-background-active: var(--dark-color-background-active); - --color-background-warning: var(--dark-color-background-warning); - --color-warning-text: var(--dark-color-warning-text); - --color-icon-background: var(--dark-color-icon-background); - --color-accent: var(--dark-color-accent); - --color-active-menu-item: var(--dark-color-active-menu-item); - --color-text: var(--dark-color-text); - --color-contrast-text: var(--dark-color-contrast-text); - --color-text-aside: var(--dark-color-text-aside); - --color-icon-text: var(--dark-color-icon-text); - - --color-comment-tag-text: var(--dark-color-text); - --color-comment-tag: var(--dark-color-background); - - --color-link: var(--dark-color-link); - --color-focus-outline: var(--dark-color-focus-outline); - - --color-ts-keyword: var(--dark-color-ts-keyword); - --color-ts-project: var(--dark-color-ts-project); - --color-ts-module: var(--dark-color-ts-module); - --color-ts-namespace: var(--dark-color-ts-namespace); - --color-ts-enum: var(--dark-color-ts-enum); - --color-ts-enum-member: var(--dark-color-ts-enum-member); - --color-ts-variable: var(--dark-color-ts-variable); - --color-ts-function: var(--dark-color-ts-function); - --color-ts-class: var(--dark-color-ts-class); - --color-ts-interface: var(--dark-color-ts-interface); - --color-ts-constructor: var(--dark-color-ts-constructor); - --color-ts-property: var(--dark-color-ts-property); - --color-ts-method: var(--dark-color-ts-method); - --color-ts-reference: var(--dark-color-ts-reference); - --color-ts-call-signature: var(--dark-color-ts-call-signature); - --color-ts-index-signature: var(--dark-color-ts-index-signature); - --color-ts-constructor-signature: var( - --dark-color-ts-constructor-signature - ); - --color-ts-parameter: var(--dark-color-ts-parameter); - --color-ts-type-parameter: var(--dark-color-ts-type-parameter); - --color-ts-accessor: var(--dark-color-ts-accessor); - --color-ts-get-signature: var(--dark-color-ts-get-signature); - --color-ts-set-signature: var(--dark-color-ts-set-signature); - --color-ts-type-alias: var(--dark-color-ts-type-alias); - --color-document: var(--dark-color-document); - - --color-note: var(--dark-color-note); - --color-tip: var(--dark-color-tip); - --color-important: var(--dark-color-important); - --color-warning: var(--dark-color-warning); - --color-caution: var(--dark-color-caution); - - --external-icon: var(--dark-external-icon); - --color-scheme: var(--dark-color-scheme); - } - - html { - color-scheme: var(--color-scheme); - @media (prefers-reduced-motion: no-preference) { - scroll-behavior: smooth; - } - } - - *:focus-visible, - .tsd-accordion-summary:focus-visible svg { - outline: 2px solid var(--color-focus-outline); - } - - .always-visible, - .always-visible .tsd-signatures { - display: inherit !important; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - line-height: 1.2; - } - - h1 { - font-size: 1.875rem; - margin: 0.67rem 0; - } - - h2 { - font-size: 1.5rem; - margin: 0.83rem 0; - } - - h3 { - font-size: 1.25rem; - margin: 1rem 0; - } - - h4 { - font-size: 1.05rem; - margin: 1.33rem 0; - } - - h5 { - font-size: 1rem; - margin: 1.5rem 0; - } - - h6 { - font-size: 0.875rem; - margin: 2.33rem 0; - } - - dl, - menu, - ol, - ul { - margin: 1em 0; - } - - dd { - margin: 0 0 0 34px; - } - - .container { - max-width: 1700px; - padding: 0 2rem; - } - - /* Footer */ - footer { - border-top: 1px solid var(--color-accent); - padding-top: 1rem; - padding-bottom: 1rem; - max-height: var(--dim-footer-height); - } - footer > p { - margin: 0 1em; - } - - .container-main { - margin: var(--dim-container-main-margin-y) auto; - /* toolbar, footer, margin */ - min-height: calc( - 100svh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - } - - @keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - @keyframes fade-out { - from { - opacity: 1; - visibility: visible; - } - to { - opacity: 0; - } - } - @keyframes pop-in-from-right { - from { - transform: translate(100%, 0); - } - to { - transform: translate(0, 0); - } - } - @keyframes pop-out-to-right { - from { - transform: translate(0, 0); - visibility: visible; - } - to { - transform: translate(100%, 0); - } - } - body { - background: var(--color-background); - font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", - Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; - font-size: 16px; - color: var(--color-text); - margin: 0; - } - - a { - color: var(--color-link); - text-decoration: none; - } - a:hover { - text-decoration: underline; - } - a.external[target="_blank"] { - background-image: var(--external-icon); - background-position: top 3px right; - background-repeat: no-repeat; - padding-right: 13px; - } - a.tsd-anchor-link { - color: var(--color-text); - } - :target { - scroll-margin-block: calc(var(--dim-header-height) + 0.5rem); - } - - code, - pre { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - padding: 0.2em; - margin: 0; - font-size: 0.875rem; - border-radius: 0.8em; - } - - pre { - position: relative; - white-space: pre-wrap; - word-wrap: break-word; - padding: 10px; - border: 1px solid var(--color-accent); - margin-bottom: 8px; - } - pre code { - padding: 0; - font-size: 100%; - } - pre > button { - position: absolute; - top: 10px; - right: 10px; - opacity: 0; - transition: opacity 0.1s; - box-sizing: border-box; - } - pre:hover > button, - pre > button.visible, - pre > button:focus-visible { - opacity: 1; - } - - blockquote { - margin: 1em 0; - padding-left: 1em; - border-left: 4px solid gray; - } - - img { - max-width: 100%; - } - - * { - scrollbar-width: thin; - scrollbar-color: var(--color-accent) var(--color-icon-background); - } - - *::-webkit-scrollbar { - width: 0.75rem; - } - - *::-webkit-scrollbar-track { - background: var(--color-icon-background); - } - - *::-webkit-scrollbar-thumb { - background-color: var(--color-accent); - border-radius: 999rem; - border: 0.25rem solid var(--color-icon-background); - } - - dialog { - border: none; - outline: none; - padding: 0; - background-color: var(--color-background); - } - dialog::backdrop { - display: none; - } - #tsd-overlay { - background-color: rgba(0, 0, 0, 0.5); - position: fixed; - z-index: 9999; - top: 0; - left: 0; - right: 0; - bottom: 0; - animation: fade-in var(--modal-animation-duration) forwards; - } - #tsd-overlay.closing { - animation-name: fade-out; - } - - .tsd-typography { - line-height: 1.333em; - } - .tsd-typography ul { - list-style: square; - padding: 0 0 0 20px; - margin: 0; - } - .tsd-typography .tsd-index-panel h3, - .tsd-index-panel .tsd-typography h3, - .tsd-typography h4, - .tsd-typography h5, - .tsd-typography h6 { - font-size: 1em; - } - .tsd-typography h5, - .tsd-typography h6 { - font-weight: normal; - } - .tsd-typography p, - .tsd-typography ul, - .tsd-typography ol { - margin: 1em 0; - } - .tsd-typography table { - border-collapse: collapse; - border: none; - } - .tsd-typography td, - .tsd-typography th { - padding: 6px 13px; - border: 1px solid var(--color-accent); - } - .tsd-typography thead, - .tsd-typography tr:nth-child(even) { - background-color: var(--color-background-secondary); - } - - .tsd-alert { - padding: 8px 16px; - margin-bottom: 16px; - border-left: 0.25em solid var(--alert-color); - } - .tsd-alert blockquote > :last-child, - .tsd-alert > :last-child { - margin-bottom: 0; - } - .tsd-alert-title { - color: var(--alert-color); - display: inline-flex; - align-items: center; - } - .tsd-alert-title span { - margin-left: 4px; - } - - .tsd-alert-note { - --alert-color: var(--color-alert-note); - } - .tsd-alert-tip { - --alert-color: var(--color-alert-tip); - } - .tsd-alert-important { - --alert-color: var(--color-alert-important); - } - .tsd-alert-warning { - --alert-color: var(--color-alert-warning); - } - .tsd-alert-caution { - --alert-color: var(--color-alert-caution); - } - - .tsd-breadcrumb { - margin: 0; - margin-top: 1rem; - padding: 0; - color: var(--color-text-aside); - } - .tsd-breadcrumb a { - color: var(--color-text-aside); - text-decoration: none; - } - .tsd-breadcrumb a:hover { - text-decoration: underline; - } - .tsd-breadcrumb li { - display: inline; - } - .tsd-breadcrumb li:after { - content: " / "; - } - - .tsd-comment-tags { - display: flex; - flex-direction: column; - } - dl.tsd-comment-tag-group { - display: flex; - align-items: center; - overflow: hidden; - margin: 0.5em 0; - } - dl.tsd-comment-tag-group dt { - display: flex; - margin-right: 0.5em; - font-size: 0.875em; - font-weight: normal; - } - dl.tsd-comment-tag-group dd { - margin: 0; - } - code.tsd-tag { - padding: 0.25em 0.4em; - border: 0.1em solid var(--color-accent); - margin-right: 0.25em; - font-size: 70%; - } - h1 code.tsd-tag:first-of-type { - margin-left: 0.25em; - } - - dl.tsd-comment-tag-group dd:before, - dl.tsd-comment-tag-group dd:after { - content: " "; - } - dl.tsd-comment-tag-group dd pre, - dl.tsd-comment-tag-group dd:after { - clear: both; - } - dl.tsd-comment-tag-group p { - margin: 0; - } - - .tsd-panel.tsd-comment .lead { - font-size: 1.1em; - line-height: 1.333em; - margin-bottom: 2em; - } - .tsd-panel.tsd-comment .lead:last-child { - margin-bottom: 0; - } - - .tsd-filter-visibility h4 { - font-size: 1rem; - padding-top: 0.75rem; - padding-bottom: 0.5rem; - margin: 0; - } - .tsd-filter-item:not(:last-child) { - margin-bottom: 0.5rem; - } - .tsd-filter-input { - display: flex; - width: -moz-fit-content; - width: fit-content; - align-items: center; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: pointer; - } - .tsd-filter-input input[type="checkbox"] { - cursor: pointer; - position: absolute; - width: 1.5em; - height: 1.5em; - opacity: 0; - } - .tsd-filter-input input[type="checkbox"]:disabled { - pointer-events: none; - } - .tsd-filter-input svg { - cursor: pointer; - width: 1.5em; - height: 1.5em; - margin-right: 0.5em; - border-radius: 0.33em; - /* Leaving this at full opacity breaks event listeners on Firefox. - Don't remove unless you know what you're doing. */ - opacity: 0.99; - } - .tsd-filter-input input[type="checkbox"]:focus-visible + svg { - outline: 2px solid var(--color-focus-outline); - } - .tsd-checkbox-background { - fill: var(--color-accent); - } - input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { - stroke: var(--color-text); - } - .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { - fill: var(--color-background); - stroke: var(--color-accent); - stroke-width: 0.25rem; - } - .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { - stroke: var(--color-accent); - } - - .settings-label { - font-weight: bold; - text-transform: uppercase; - display: inline-block; - } - - .tsd-filter-visibility .settings-label { - margin: 0.75rem 0 0.5rem 0; - } - - .tsd-theme-toggle .settings-label { - margin: 0.75rem 0.75rem 0 0; - } - - .tsd-hierarchy h4 label:hover span { - text-decoration: underline; - } - - .tsd-hierarchy { - list-style: square; - margin: 0; - } - .tsd-hierarchy-target { - font-weight: bold; - } - .tsd-hierarchy-toggle { - color: var(--color-link); - cursor: pointer; - } - - .tsd-full-hierarchy:not(:last-child) { - margin-bottom: 1em; - padding-bottom: 1em; - border-bottom: 1px solid var(--color-accent); - } - .tsd-full-hierarchy, - .tsd-full-hierarchy ul { - list-style: none; - margin: 0; - padding: 0; - } - .tsd-full-hierarchy ul { - padding-left: 1.5rem; - } - .tsd-full-hierarchy a { - padding: 0.25rem 0 !important; - font-size: 1rem; - display: inline-flex; - align-items: center; - color: var(--color-text); - } - .tsd-full-hierarchy svg[data-dropdown] { - cursor: pointer; - } - .tsd-full-hierarchy svg[data-dropdown="false"] { - transform: rotate(-90deg); - } - .tsd-full-hierarchy svg[data-dropdown="false"] ~ ul { - display: none; - } - - .tsd-panel-group.tsd-index-group { - margin-bottom: 0; - } - .tsd-index-panel .tsd-index-list { - list-style: none; - line-height: 1.333em; - margin: 0; - padding: 0.25rem 0 0 0; - overflow: hidden; - display: grid; - grid-template-columns: repeat(3, 1fr); - column-gap: 1rem; - grid-template-rows: auto; - } - @media (max-width: 1024px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(2, 1fr); - } - } - @media (max-width: 768px) { - .tsd-index-panel .tsd-index-list { - grid-template-columns: repeat(1, 1fr); - } - } - .tsd-index-panel .tsd-index-list li { - -webkit-page-break-inside: avoid; - -moz-page-break-inside: avoid; - -ms-page-break-inside: avoid; - -o-page-break-inside: avoid; - page-break-inside: avoid; - } - - .tsd-flag { - display: inline-block; - padding: 0.25em 0.4em; - border-radius: 4px; - color: var(--color-comment-tag-text); - background-color: var(--color-comment-tag); - text-indent: 0; - font-size: 75%; - line-height: 1; - font-weight: normal; - } - - .tsd-anchor { - position: relative; - top: -100px; - } - - .tsd-member { - position: relative; - } - .tsd-member .tsd-anchor + h3 { - display: flex; - align-items: center; - margin-top: 0; - margin-bottom: 0; - border-bottom: none; - } - - .tsd-navigation.settings { - margin: 0; - margin-bottom: 1rem; - } - .tsd-navigation > a, - .tsd-navigation .tsd-accordion-summary { - width: calc(100% - 0.25rem); - display: flex; - align-items: center; - } - .tsd-navigation a, - .tsd-navigation summary > span, - .tsd-page-navigation a { - display: flex; - width: calc(100% - 0.25rem); - align-items: center; - padding: 0.25rem; - color: var(--color-text); - text-decoration: none; - box-sizing: border-box; - } - .tsd-navigation a.current, - .tsd-page-navigation a.current { - background: var(--color-active-menu-item); - color: var(--color-contrast-text); - } - .tsd-navigation a:hover, - .tsd-page-navigation a:hover { - text-decoration: underline; - } - .tsd-navigation ul, - .tsd-page-navigation ul { - margin-top: 0; - margin-bottom: 0; - padding: 0; - list-style: none; - } - .tsd-navigation li, - .tsd-page-navigation li { - padding: 0; - max-width: 100%; - } - .tsd-navigation .tsd-nav-link { - display: none; - } - .tsd-nested-navigation { - margin-left: 3rem; - } - .tsd-nested-navigation > li > details { - margin-left: -1.5rem; - } - .tsd-small-nested-navigation { - margin-left: 1.5rem; - } - .tsd-small-nested-navigation > li > details { - margin-left: -1.5rem; - } - - .tsd-page-navigation-section > summary { - padding: 0.25rem; - } - .tsd-page-navigation-section > summary > svg { - margin-right: 0.25rem; - } - .tsd-page-navigation-section > div { - margin-left: 30px; - } - .tsd-page-navigation ul { - padding-left: 1.75rem; - } - - #tsd-sidebar-links a { - margin-top: 0; - margin-bottom: 0.5rem; - line-height: 1.25rem; - } - #tsd-sidebar-links a:last-of-type { - margin-bottom: 0; - } - - a.tsd-index-link { - padding: 0.25rem 0 !important; - font-size: 1rem; - line-height: 1.25rem; - display: inline-flex; - align-items: center; - color: var(--color-text); - } - .tsd-accordion-summary { - list-style-type: none; /* hide marker on non-safari */ - outline: none; /* broken on safari, so just hide it */ - display: flex; - align-items: center; - gap: 0.25rem; - box-sizing: border-box; - } - .tsd-accordion-summary::-webkit-details-marker { - display: none; /* hide marker on safari */ - } - .tsd-accordion-summary, - .tsd-accordion-summary a { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - - cursor: pointer; - } - .tsd-accordion-summary a { - width: calc(100% - 1.5rem); - } - .tsd-accordion-summary > * { - margin-top: 0; - margin-bottom: 0; - padding-top: 0; - padding-bottom: 0; - } - /* - * We need to be careful to target the arrow indicating whether the accordion - * is open, but not any other SVGs included in the details element. - */ - .tsd-accordion:not([open]) > .tsd-accordion-summary > svg:first-child { - transform: rotate(-90deg); - } - .tsd-index-content > :not(:first-child) { - margin-top: 0.75rem; - } - .tsd-index-summary { - margin-top: 1.5rem; - margin-bottom: 0.75rem; - display: flex; - align-content: center; - } - - .tsd-no-select { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - .tsd-kind-icon { - margin-right: 0.5rem; - width: 1.25rem; - height: 1.25rem; - min-width: 1.25rem; - min-height: 1.25rem; - } - .tsd-signature > .tsd-kind-icon { - margin-right: 0.8rem; - } - - .tsd-panel { - margin-bottom: 2.5rem; - } - .tsd-panel.tsd-member { - margin-bottom: 4rem; - } - .tsd-panel:empty { - display: none; - } - .tsd-panel > h1, - .tsd-panel > h2, - .tsd-panel > h3 { - margin: 1.5rem -1.5rem 0.75rem -1.5rem; - padding: 0 1.5rem 0.75rem 1.5rem; - } - .tsd-panel > h1.tsd-before-signature, - .tsd-panel > h2.tsd-before-signature, - .tsd-panel > h3.tsd-before-signature { - margin-bottom: 0; - border-bottom: none; - } - - .tsd-panel-group { - margin: 2rem 0; - } - .tsd-panel-group.tsd-index-group { - margin: 2rem 0; - } - .tsd-panel-group.tsd-index-group details { - margin: 2rem 0; - } - .tsd-panel-group > .tsd-accordion-summary { - margin-bottom: 1rem; - } - - #tsd-search[open] { - animation: fade-in var(--modal-animation-duration) ease-out forwards; - } - #tsd-search[open].closing { - animation-name: fade-out; - } - - /* Avoid setting `display` on closed dialog */ - #tsd-search[open] { - display: flex; - flex-direction: column; - padding: 1rem; - width: 32rem; - max-width: 90vw; - max-height: calc(100vh - env(keyboard-inset-height, 0px) - 25vh); - /* Anchor dialog to top */ - margin-top: 10vh; - border-radius: 6px; - will-change: max-height; - } - #tsd-search-input { - box-sizing: border-box; - width: 100%; - padding: 0 0.625rem; /* 10px */ - outline: 0; - border: 2px solid var(--color-accent); - background-color: transparent; - color: var(--color-text); - border-radius: 4px; - height: 2.5rem; - flex: 0 0 auto; - font-size: 0.875rem; - transition: border-color 0.2s, background-color 0.2s; - } - #tsd-search-input:focus-visible { - background-color: var(--color-background-active); - border-color: transparent; - color: var(--color-contrast-text); - } - #tsd-search-input::placeholder { - color: inherit; - opacity: 0.8; - } - #tsd-search-results { - margin: 0; - padding: 0; - list-style: none; - flex: 1 1 auto; - display: flex; - flex-direction: column; - overflow-y: auto; - } - #tsd-search-results:not(:empty) { - margin-top: 0.5rem; - } - #tsd-search-results > li { - background-color: var(--color-background); - line-height: 1.5; - box-sizing: border-box; - border-radius: 4px; - } - #tsd-search-results > li:nth-child(even) { - background-color: var(--color-background-secondary); - } - #tsd-search-results > li:is(:hover, [aria-selected="true"]) { - background-color: var(--color-background-active); - color: var(--color-contrast-text); - } - /* It's important that this takes full size of parent `li`, to capture a click on `li` */ - #tsd-search-results > li > a { - display: flex; - align-items: center; - padding: 0.5rem 0.25rem; - box-sizing: border-box; - width: 100%; - } - #tsd-search-results > li > a > .text { - flex: 1 1 auto; - min-width: 0; - overflow-wrap: anywhere; - } - #tsd-search-results > li > a .parent { - color: var(--color-text-aside); - } - #tsd-search-results > li > a mark { - color: inherit; - background-color: inherit; - font-weight: bold; - } - #tsd-search-status { - flex: 1; - display: grid; - place-content: center; - text-align: center; - overflow-wrap: anywhere; - } - #tsd-search-status:not(:empty) { - min-height: 6rem; - } - - .tsd-signature { - margin: 0 0 1rem 0; - padding: 1rem 0.5rem; - border: 1px solid var(--color-accent); - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - font-size: 14px; - overflow-x: auto; - } - - .tsd-signature-keyword { - color: var(--color-ts-keyword); - font-weight: normal; - } - - .tsd-signature-symbol { - color: var(--color-text-aside); - font-weight: normal; - } - - .tsd-signature-type { - font-style: italic; - font-weight: normal; - } - - .tsd-signatures { - padding: 0; - margin: 0 0 1em 0; - list-style-type: none; - } - .tsd-signatures .tsd-signature { - margin: 0; - border-color: var(--color-accent); - border-width: 1px 0; - transition: background-color 0.1s; - } - .tsd-signatures .tsd-index-signature:not(:last-child) { - margin-bottom: 1em; - } - .tsd-signatures .tsd-index-signature .tsd-signature { - border-width: 1px; - } - .tsd-description .tsd-signatures .tsd-signature { - border-width: 1px; - } - - ul.tsd-parameter-list, - ul.tsd-type-parameter-list { - list-style: square; - margin: 0; - padding-left: 20px; - } - ul.tsd-parameter-list > li.tsd-parameter-signature, - ul.tsd-type-parameter-list > li.tsd-parameter-signature { - list-style: none; - margin-left: -20px; - } - ul.tsd-parameter-list h5, - ul.tsd-type-parameter-list h5 { - font-size: 16px; - margin: 1em 0 0.5em 0; - } - .tsd-sources { - margin-top: 1rem; - font-size: 0.875em; - } - .tsd-sources a { - color: var(--color-text-aside); - text-decoration: underline; - } - .tsd-sources ul { - list-style: none; - padding: 0; - } - - .tsd-page-toolbar { - position: sticky; - z-index: 1; - top: 0; - left: 0; - width: 100%; - color: var(--color-text); - background: var(--color-background-secondary); - border-bottom: var(--dim-toolbar-border-bottom-width) - var(--color-accent) solid; - transition: transform 0.3s ease-in-out; - } - .tsd-page-toolbar a { - color: var(--color-text); - } - .tsd-toolbar-contents { - display: flex; - align-items: center; - height: var(--dim-toolbar-contents-height); - margin: 0 auto; - } - .tsd-toolbar-contents > .title { - font-weight: bold; - margin-right: auto; - } - #tsd-toolbar-links { - display: flex; - align-items: center; - gap: 1.5rem; - margin-right: 1rem; - } - - .tsd-widget { - box-sizing: border-box; - display: inline-block; - opacity: 0.8; - height: 2.5rem; - width: 2.5rem; - transition: opacity 0.1s, background-color 0.1s; - text-align: center; - cursor: pointer; - border: none; - background-color: transparent; - } - .tsd-widget:hover { - opacity: 0.9; - } - .tsd-widget:active { - opacity: 1; - background-color: var(--color-accent); - } - #tsd-toolbar-menu-trigger { - display: none; - } - - .tsd-member-summary-name { - display: inline-flex; - align-items: center; - padding: 0.25rem; - text-decoration: none; - } - - .tsd-anchor-icon { - display: inline-flex; - align-items: center; - margin-left: 0.5rem; - color: var(--color-text); - vertical-align: middle; - } - - .tsd-anchor-icon svg { - width: 1em; - height: 1em; - visibility: hidden; - } - - .tsd-member-summary-name:hover > .tsd-anchor-icon svg, - .tsd-anchor-link:hover > .tsd-anchor-icon svg, - .tsd-anchor-icon:focus-visible svg { - visibility: visible; - } - - .deprecated { - text-decoration: line-through !important; - } - - .warning { - padding: 1rem; - color: var(--color-warning-text); - background: var(--color-background-warning); - } - - .tsd-kind-project { - color: var(--color-ts-project); - } - .tsd-kind-module { - color: var(--color-ts-module); - } - .tsd-kind-namespace { - color: var(--color-ts-namespace); - } - .tsd-kind-enum { - color: var(--color-ts-enum); - } - .tsd-kind-enum-member { - color: var(--color-ts-enum-member); - } - .tsd-kind-variable { - color: var(--color-ts-variable); - } - .tsd-kind-function { - color: var(--color-ts-function); - } - .tsd-kind-class { - color: var(--color-ts-class); - } - .tsd-kind-interface { - color: var(--color-ts-interface); - } - .tsd-kind-constructor { - color: var(--color-ts-constructor); - } - .tsd-kind-property { - color: var(--color-ts-property); - } - .tsd-kind-method { - color: var(--color-ts-method); - } - .tsd-kind-reference { - color: var(--color-ts-reference); - } - .tsd-kind-call-signature { - color: var(--color-ts-call-signature); - } - .tsd-kind-index-signature { - color: var(--color-ts-index-signature); - } - .tsd-kind-constructor-signature { - color: var(--color-ts-constructor-signature); - } - .tsd-kind-parameter { - color: var(--color-ts-parameter); - } - .tsd-kind-type-parameter { - color: var(--color-ts-type-parameter); - } - .tsd-kind-accessor { - color: var(--color-ts-accessor); - } - .tsd-kind-get-signature { - color: var(--color-ts-get-signature); - } - .tsd-kind-set-signature { - color: var(--color-ts-set-signature); - } - .tsd-kind-type-alias { - color: var(--color-ts-type-alias); - } - - /* if we have a kind icon, don't color the text by kind */ - .tsd-kind-icon ~ span { - color: var(--color-text); - } - - /* mobile */ - @media (max-width: 769px) { - #tsd-toolbar-menu-trigger { - display: inline-block; - /* temporary fix to vertically align, for compatibility */ - line-height: 2.5; - } - #tsd-toolbar-links { - display: none; - } - - .container-main { - display: flex; - } - .col-content { - float: none; - max-width: 100%; - width: 100%; - } - .col-sidebar { - position: fixed !important; - overflow-y: auto; - -webkit-overflow-scrolling: touch; - z-index: 1024; - top: 0 !important; - bottom: 0 !important; - left: auto !important; - right: 0 !important; - padding: 1.5rem 1.5rem 0 0; - width: 75vw; - visibility: hidden; - background-color: var(--color-background); - transform: translate(100%, 0); - } - .col-sidebar > *:last-child { - padding-bottom: 20px; - } - .overlay { - content: ""; - display: block; - position: fixed; - z-index: 1023; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.75); - visibility: hidden; - } - - .to-has-menu .overlay { - animation: fade-in 0.4s; - } - - .to-has-menu .col-sidebar { - animation: pop-in-from-right 0.4s; - } - - .from-has-menu .overlay { - animation: fade-out 0.4s; - } - - .from-has-menu .col-sidebar { - animation: pop-out-to-right 0.4s; - } - - .has-menu body { - overflow: hidden; - } - .has-menu .overlay { - visibility: visible; - } - .has-menu .col-sidebar { - visibility: visible; - transform: translate(0, 0); - display: flex; - flex-direction: column; - gap: 1.5rem; - max-height: 100vh; - padding: 1rem 2rem; - } - .has-menu .tsd-navigation { - max-height: 100%; - } - .tsd-navigation .tsd-nav-link { - display: flex; - } - } - - /* one sidebar */ - @media (min-width: 770px) { - .container-main { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); - grid-template-areas: "sidebar content"; - --dim-container-main-margin-y: 2rem; - } - - .tsd-breadcrumb { - margin-top: 0; - } - - .col-sidebar { - grid-area: sidebar; - } - .col-content { - grid-area: content; - padding: 0 1rem; - } - } - @media (min-width: 770px) and (max-width: 1399px) { - .col-sidebar { - max-height: calc( - 100vh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - overflow: auto; - position: sticky; - top: calc( - var(--dim-header-height) + var(--dim-container-main-margin-y) - ); - } - .site-menu { - margin-top: 1rem; - } - } - - /* two sidebars */ - @media (min-width: 1200px) { - .container-main { - grid-template-columns: - minmax(0, 1fr) minmax(0, 2.5fr) minmax( - 0, - 20rem - ); - grid-template-areas: "sidebar content toc"; - } - - .col-sidebar { - display: contents; - } - - .page-menu { - grid-area: toc; - padding-left: 1rem; - } - .site-menu { - grid-area: sidebar; - } - - .site-menu { - margin-top: 0rem; - } - - .page-menu, - .site-menu { - max-height: calc( - 100vh - var(--dim-header-height) - var(--dim-footer-height) - - 2 * var(--dim-container-main-margin-y) - ); - overflow: auto; - position: sticky; - top: calc( - var(--dim-header-height) + var(--dim-container-main-margin-y) - ); - } - } -} diff --git a/docs/assets/typedoc-github-style.css b/docs/assets/typedoc-github-style.css deleted file mode 100644 index 7107051..0000000 --- a/docs/assets/typedoc-github-style.css +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Define colors - */ - -:root { - /* GitHub "Light default" */ - --light-color-background: #ffffff; - --light-color-background-secondary: #f6f8fa; - --light-color-background-navbar: #f6f8fa; - --light-color-background-overlay: #c8d1da66; - - --light-color-accent: #d1d9e0; - - --light-color-text: #1f2328; - --light-color-text-aside: #59636e; - - --light-color-link: #0969da; - - --light-color-warning-border: #f7ebba; - --light-color-background-warning: #fff8c5; - - --light-color-alert-note: #0969da; - --light-color-alert-tip: #1a7f37; - --light-color-alert-important: #8250df; - --light-color-alert-warning: #9a6700; - --light-color-alert-caution: #cf222e; - - /* GitHub "Dark default" */ - --dark-color-background: #0d1117; - --dark-color-background-secondary: #151b23; - --dark-color-background-navbar: #010409; - --dark-color-background-overlay: #21283066; - - --dark-color-accent: #383e48; - - --dark-color-text: #f0f6fc; - --dark-color-text-aside: #9198a1; - - --dark-color-link: #4493f8; - - --dark-color-warning-border: #3a2d12; - --dark-color-background-warning: #282215; - - --dark-color-alert-note: #1f6feb; - --dark-color-alert-tip: #238636; - --dark-color-alert-important: #8957e5; - --dark-color-alert-warning: #9e6a03; - --dark-color-alert-caution: #da3633; - - /* Link colors */ - --color-warning-text: var(--color-text); - --color-contrast-text: var(--color-text); - --color-icon-background: var(--color-background); - --color-focus-outline: var(--color-accent); -} - -@media (prefers-color-scheme: light) { - :root { - --color-background-navbar: var(--light-color-background-navbar); - --color-background-overlay: var(--light-color-background-overlay); - --color-warning-border: var(--light-color-warning-border); - } -} - -@media (prefers-color-scheme: dark) { - :root { - --color-background-navbar: var(--dark-color-background-navbar); - --color-background-overlay: var(--dark-color-background-overlay); - --color-warning-border: var(--dark-color-warning-border); - } -} - -:root[data-theme='light'] { - --color-background-navbar: var(--light-color-background-navbar); - --color-background-overlay: var(--light-color-background-overlay); - --color-warning-border: var(--light-color-warning-border); -} - -:root[data-theme='dark'] { - --color-background-navbar: var(--dark-color-background-navbar); - --color-background-overlay: var(--dark-color-background-overlay); - --color-warning-border: var(--dark-color-warning-border); -} - -/* - * Define fonts - */ - -:root { - --font-family-text: - -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; - --font-family-code: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; -} - -body { - font-family: var(--font-family-text); -} - -/* - * Links - */ - -.tsd-accordion-details a, -.tsd-accordion a, -.tsd-page-toolbar a.title { - color: var(--color-text); - text-decoration: none; -} - -.tsd-accordion-details a:hover, -.tsd-page-toolbar a.title:hover, -.tsd-accordion a:hover, -.tsd-anchor-icon { - color: var(--color-text-aside); -} - -.tsd-kind-class { - color: var(--color-link); - text-decoration: underline; - text-underline-offset: 3px; -} - -.tsd-index-link, -.tsd-page-navigation a:hover { - text-decoration: none; -} - -.tsd-index-link:hover { - text-decoration: underline; - text-underline-offset: 3px; -} - -a code, -.tsd-sources a, -.tsd-page-navigation a:hover { - color: var(--color-link); -} - -a.external[target='_blank'] { - background-image: none; - padding-right: 0px; -} - -/* - * Tables - */ - -table { - margin: 1em 0; -} - -.tsd-typography th, -.tsd-typography td { - padding: 8px; - text-align: left; -} - -.tsd-typography th { - background-color: var(--color-background); - color: var(--color-text); -} - -.tsd-typography tr:nth-child(2n) { - background-color: var(--color-background-code); -} - -/* - * Horizontal line - */ - -.tsd-typography hr { - color: var(--color-accent); -} - -/* - * Buttons - */ - -button { - background-color: var(--color-background-navbar); - color: var(--color-text); - border: 1px solid var(--color-accent); - border-radius: 6px; - padding: 8px 16px; - cursor: pointer; - transition: background-color 0.1s ease-in-out; -} - -button:hover { - background-color: var(--color-accent); -} - -pre > button { - background-color: transparent; - transition: background-color 0.1s ease-in-out; - border: none; - opacity: 1; - top: 8px; - padding: 4px 8px; -} - -/* - * Checkbox - */ - -.tsd-filter-input input[type='checkbox'], -.tsd-filter-input svg { - width: 1em; - height: 1em; -} - -.tsd-filter-input svg { - border-radius: 2px; -} - -.tsd-checkbox-background { - fill: var(--color-background); - stroke: var(--color-accent); - stroke-width: 6px; -} - -input[type='checkbox']:checked ~ svg .tsd-checkbox-background { - fill: var(--color-accent); -} - -.tsd-checkbox-checkmark { - color: var(--color-text); -} - -/* - * Select - */ - -select { - background-color: var(--color-background); - border: 1px solid var(--color-accent); - border-radius: 6px; - padding: 8px; - font-family: inherit; -} - -/* - * Code blocks - */ - -code, -pre { - border: none; - border-radius: 6px; - margin: 1em 0; - background-color: var(--color-background-secondary); - color: var(--color-text); - font-family: var(--font-family-code); -} - -code.tsd-tag { - background-color: var(--color-accent); - border: unset; -} - -/* - * Warnings - */ - -.warning { - border-style: solid; - border-width: 1px; - border-color: var(--color-warning-border); - border-radius: 6px; -} - -/* - * Topbar - */ - -.tsd-page-toolbar { - background-color: var(--color-background-navbar); - border-bottom-color: var(--color-accent); -} - -.tsd-toolbar-contents a.title:hover { - color: var(--color-text); -} - -/* - * Search - */ - -#tsd-search-trigger { - width: unset; - border: unset; - background-color: unset; - transition: opacity 0.15s ease-in-out; -} - -#tsd-search-trigger:hover { - opacity: 1; -} - -#tsd-search-input, -#tsd-search-input:focus-visible { - background-color: transparent; - border: 1px solid var(--color-focus-outline); -} - -#tsd-search-status:not(:empty) { - min-height: unset; - padding-top: 1.5rem; - padding-bottom: 0.5rem; -} - -#tsd-search-results > li:is(:hover, [aria-selected='true']) { - background-color: color-mix(in srgb, var(--color-text-aside), #0000 88%); -} - -#tsd-search-results > li > a:hover { - text-decoration: unset; -} - -#tsd-overlay { - background-color: var(--color-background-overlay); -} - -/* - * Baseboard - */ - -footer { - border-top-color: var(--color-accent); -} - -/* - * Side navigations - */ - -.site-menu { - padding: 1rem 0; -} - -.tsd-navigation a { - color: var(--color-text); - border-radius: 6px; - padding: 6px; -} - -.tsd-navigation a, -.tsd-navigation a:hover { - text-decoration: none; -} - -.tsd-navigation a:hover:not(.current) { - background-color: color-mix(in srgb, var(--color-text-aside), #0000 88%); -} - -.tsd-navigation a.current { - background-color: color-mix(in srgb, var(--color-text-aside), #0000 92%); -} - -/* - * Type definition groups - */ - -.tsd-index-panel, -.tsd-member-group { - background-color: var(--color-background); - padding: 16px; - border: 1px var(--color-accent) solid; - border-radius: 6px; -} - -.tsd-panel > h1, -.tsd-panel > h2, -.tsd-panel > h3 { - margin-top: 0px; -} - -.tsd-panel-group.tsd-index-group details { - margin: 0px; -} - -.tsd-member-group .tsd-member:last-child { - margin-bottom: 0px; -} - -.tsd-signature { - border: 1px solid var(--color-accent); - border-radius: 6px; -} - -.tsd-signatures .tsd-signature { - border-color: var(--color-accent); - border-radius: 0px; -} - -.tsd-description .tsd-signatures .tsd-signature { - border-radius: 6px; -} - -.tsd-full-hierarchy:not(:last-child) { - border-bottom: var(--color-accent); -} - -/* - * Footer - */ - -footer p { - font-size: 1rem; - text-align: center; - color: var(--color-text-aside); -} - -/* - * Fix collapsed margin - */ - -.tsd-accordion-summary > h3 { - margin-top: 0px; - margin-bottom: 0px; -} - -.tsd-page-navigation:not([open]) > .tsd-accordion-summary { - margin-bottom: 0px; -} - -/* - * Fix collapse arrows position - */ - -.tsd-accordion-summary svg { - transition: transform 0.1s ease-in-out; - margin-top: auto; - margin-bottom: auto; -} diff --git a/docs/functions/generateGitignoreRules.html b/docs/functions/generateGitignoreRules.html deleted file mode 100644 index 071806a..0000000 --- a/docs/functions/generateGitignoreRules.html +++ /dev/null @@ -1,5 +0,0 @@ -generateGitignoreRules | modpack-lock
modpack-lock
    Preparing search index...

    Function generateGitignoreRules

    • Generate .gitignore rules for files not hosted on Modrinth and write them to .gitignore file

      -

      Parameters

      • lockfile: Lockfile

        The lockfile object

        -
      • workingDir: string

        The working directory

        -
      • options: Options | InitOptions = {}

        The options object

        -

      Returns Promise<void>

    diff --git a/docs/functions/generateJson.html b/docs/functions/generateJson.html deleted file mode 100644 index eccf37f..0000000 --- a/docs/functions/generateJson.html +++ /dev/null @@ -1,7 +0,0 @@ -generateJson | modpack-lock
    modpack-lock
      Preparing search index...

      Function generateJson

      diff --git a/docs/functions/generateLicense.html b/docs/functions/generateLicense.html deleted file mode 100644 index 2e87ce0..0000000 --- a/docs/functions/generateLicense.html +++ /dev/null @@ -1,7 +0,0 @@ -generateLicense | modpack-lock
      modpack-lock
        Preparing search index...

        Function generateLicense

        • Write a license to a file

          -

          Parameters

          • modpackInfo: ModpackInfo

            The modpack information

            -
          • workingDir: string

            The path to write the license to

            -
          • options: InitOptions = {}

            The initialization options object

            -
          • licenseTextOverride: string = null

            The license text to override the default license text with

            -

          Returns Promise<string>

          The license text or null if the license text could not be generated

          -
        diff --git a/docs/functions/generateLockfile.html b/docs/functions/generateLockfile.html deleted file mode 100644 index e0b5e7a..0000000 --- a/docs/functions/generateLockfile.html +++ /dev/null @@ -1,5 +0,0 @@ -generateLockfile | modpack-lock
        modpack-lock
          Preparing search index...

          Function generateLockfile

          diff --git a/docs/functions/generateModpackFiles.html b/docs/functions/generateModpackFiles.html deleted file mode 100644 index 0f51445..0000000 --- a/docs/functions/generateModpackFiles.html +++ /dev/null @@ -1,6 +0,0 @@ -generateModpackFiles | modpack-lock
          modpack-lock
            Preparing search index...

            Function generateModpackFiles

            • Generate the modpack files (lockfile, JSON, and optionally license, gitignore, and readme)

              -

              Parameters

              • modpackInfo: ModpackInfo

                The modpack information

                -
              • workingDir: string

                The directory to generate the files in

                -
              • options: Options | InitOptions = {}

                The options object

                -

              Returns Promise<Lockfile>

              The lockfile object

              -
            diff --git a/docs/functions/generateReadmeFiles.html b/docs/functions/generateReadmeFiles.html deleted file mode 100644 index e244222..0000000 --- a/docs/functions/generateReadmeFiles.html +++ /dev/null @@ -1,5 +0,0 @@ -generateReadmeFiles | modpack-lock
            modpack-lock
              Preparing search index...

              Function generateReadmeFiles

              diff --git a/docs/functions/getLockfile.html b/docs/functions/getLockfile.html deleted file mode 100644 index 1363f45..0000000 --- a/docs/functions/getLockfile.html +++ /dev/null @@ -1,4 +0,0 @@ -getLockfile | modpack-lock
              modpack-lock
                Preparing search index...

                Function getLockfile

                • Get the lockfile file if it exists

                  -

                  Parameters

                  • directoryPath: string

                    The path to the directory to scan

                    -

                  Returns Lockfile

                  The JSON object if the file exists, otherwise null

                  -
                diff --git a/docs/functions/getModpackInfo.html b/docs/functions/getModpackInfo.html deleted file mode 100644 index 43662b6..0000000 --- a/docs/functions/getModpackInfo.html +++ /dev/null @@ -1,4 +0,0 @@ -getModpackInfo | modpack-lock
                modpack-lock
                  Preparing search index...

                  Function getModpackInfo

                  • Get the modpack info from the JSON file if it exists

                    -

                    Parameters

                    • directoryPath: string

                      The path to the directory to scan

                      -

                    Returns Promise<ModpackInfo>

                    The modpack info JSON object if the file exists, otherwise null

                    -
                  diff --git a/docs/functions/promptUserForInfo.html b/docs/functions/promptUserForInfo.html deleted file mode 100644 index 940e009..0000000 --- a/docs/functions/promptUserForInfo.html +++ /dev/null @@ -1,4 +0,0 @@ -promptUserForInfo | modpack-lock
                  modpack-lock
                    Preparing search index...

                    Function promptUserForInfo

                    diff --git a/docs/hierarchy.html b/docs/hierarchy.html deleted file mode 100644 index 70f06f7..0000000 --- a/docs/hierarchy.html +++ /dev/null @@ -1 +0,0 @@ -modpack-lock
                    modpack-lock
                      Preparing search index...

                      modpack-lock

                      Hierarchy Summary

                      diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index b8abb8f..0000000 --- a/docs/index.html +++ /dev/null @@ -1,185 +0,0 @@ -modpack-lock
                      modpack-lock
                        Preparing search index...

                        modpack-lock

                        NPM: npmjs.com/package/modpack-lock -Source: github.com/nickesc/modpack-lock -Tests: github.com/nickesc/modpack-lock/actions/workflows/modpack-lock-tests.yml

                        -

                        modpack-lock

                        - -

                        Creates a modpack lockfile for files hosted on Modrinth (mods, resource packs, shaders and datapacks).

                        - -

                        Many mod and pack authors request that modpack creators link to Modrinth or CurseForge downloads rather than re-hosting files. This makes it difficult to track content files in version control when pushing to a remote server.

                        -

                        This script generates a modpack.lock file containing a plaintext representation of the modpack's contents. This object contains the metadata for the content available on Modrinth, including hashes, versions, names, download URLs and more. An optional modpack.json file can also be created to store your modpack's metadata (name, version, modloader, dependencies, etc.) alongside the lockfile. This setup allows for easy diffing and clear version history.

                        -
                        -

                        While an .mrpack file could be used to track changes to the modpack, it is a large, binary file that cannot be diffed and can contain large amounts of duplicate data from the rest of the repository.

                        -
                        -

                        Using the scripts field in modpack.json, you can also define reusable, tracked shell commands for common modpack tasks (like publishing, generating assets or CI/CD workflows).

                        - -

                        To install the script globally with npm:

                        -
                        npm install -g modpack-lock
                        -
                        - -

                        Alternatively, you can run it using npx:

                        -
                        npx modpack-lock
                        -
                        - - -

                        To generate a lockfile for your modpack, run:

                        -
                        modpack-lock
                        -
                        - -

                        The script will:

                        -
                          -
                        • Scan target directory's mods, resourcepacks, datapacks, and shaderpacks directories for .jar and .zip files
                        • -
                        • Calculate SHA1 hashes for each file
                        • -
                        • Query the Modrinth API for matching versions
                        • -
                        • Generate a modpack.lock file (and update modpack.json dependencies if present)
                        • -
                        -

                        Use flags to generate README.md files for each category or update the .gitignore to ignore content hosted on Modrinth.

                        -
                        Usage: modpack-lock [options] [command]
                        -
                        -Creates a modpack lockfile for files hosted on Modrinth (mods, resource packs, shaders and datapacks)
                        -
                        -Options:
                        -  -p, --path <path>       Path to the modpack directory
                        -  -d, --dry-run           Dry-run mode - no files will be written
                        -
                        -GENERATION
                        -  -g, --gitignore         Update the .gitignore file to ignore content hosted on Modrinth
                        -  -r, --readme            Generate README.md files for each category
                        -
                        -LOGGING
                        -  -q, --quiet             Quiet mode - only show errors and warnings
                        -  -s, --silent            Silent mode - no output
                        -
                        -INFORMATION
                        -  -V                      output the version number
                        -  -h, --help              display help for modpack-lock
                        -
                        -Commands:
                        -  init [options]          This utility will walk you through creating a modpack.json file. It only covers the most common items, and tries to guess sensible defaults.
                        -  run [options] <script>  Run a script defined in the modpack.json file's 'scripts' field
                        -
                        - -
                        Tip

                        - -

                        You can generate summary files for each category by running modpack-lock -r. This will generate a README.md file in each of the content folders, detailing the scanned files and important attribution information for them.

                        -
                        - -

                        To initialize a new modpack, run:

                        -
                        modpack-lock init
                        -
                        - -

                        This command will:

                        -
                          -
                        • Prompt the user for the modpack's metadata (name, version, author, etc.)
                        • -
                        • Generate the lockfile
                        • -
                        • Generate a modpack.json file that stores your modpack's metadata (name, version, author, etc.), including a list of dependencies
                        • -
                        -

                        The interactive mode will prompt you for each field. Set their initial values using the available option flags. Use --noninteractive with the required options to skip the interactive-prompt and use the provided values.

                        -
                        Usage: modpack-lock init [options]
                        -
                        -This utility will walk you through creating a modpack.json file. It only covers the most common items, and tries to guess sensible defaults.
                        -
                        -Options:
                        -  -f, --folder <path>                                Path to the modpack directory
                        -  -n, --noninteractive                               Non-interactive mode - must provide options for required fields
                        -  --add-license                                      Add the LICENSE file to the modpack
                        -  --add-gitignore                                    Update the .gitignore file to ignore content hosted on Modrinth
                        -  --add-readme                                       Generate README.md files for each category
                        -
                        -MODPACK INFORMATION
                        -  --name <name>                                      Modpack name; defaults to the directory name
                        -  --version <version>                                Modpack version; defaults to 1.0.0
                        -  --id <id>                                          Modpack slug/ID; defaults to the directory name slugified
                        -  --description <description>                        Modpack description
                        -  --author <author>                                  Modpack author; required
                        -  --projectUrl <projectUrl>                          Modpack URL; defaults to a guessed Modrinth project URL
                        -  --sourceUrl <sourceUrl>                            Modpack source code URL; defaults to a guessed GitHub repository URL
                        -  --license <license>                                Modpack license, popular licenses fetched from GitHub; defaults to MIT in interactive mode
                        -  --modloader <modloader>                            Modpack modloader, list of loaders fetched from Modrinth; required
                        -  --targetModloaderVersion <targetModloaderVersion>  Target modloader version
                        -  --targetMinecraftVersion <targetMinecraftVersion>  Target Minecraft version, list of versions fetched from Modrinth; required
                        -
                        -INFORMATION
                        -  -h, --help                                         display help for modpack-lock init
                        -
                        - - -

                        To run a script defined in modpack.json, run:

                        -
                        modpack-lock run <script>
                        -
                        - -

                        This command takes the name of the script as its first argument:

                        -
                          -
                        • It searches for a scripts fiels in modpack.json in the current directory by default.
                        • -
                        • Use the -f option to specify a different path to the modpack directory.
                        • -
                        • For debug logging, use the -D option.
                        • -
                        -
                        -

                        To pass additional arguments and options to the script, write them after a -- separator:

                        -
                        modpack-lock run <script> -- [options] <args>
                        -
                        - -
                        -

                        The scripts field in modpack.json is a key-value pair of script names and their corresponding shell commands. The scripts field is optional and is omitted by default.

                        -
                        Usage: modpack-lock run [options] <script>
                        -
                        -Run a script defined in the modpack.json file's 'scripts' field
                        -
                        -Arguments:
                        -  script               The name of the script to run
                        -
                        -Options:
                        -  -f, --folder <path>  Path to the modpack directory
                        -  -D, --debug          Debug mode -- show more information about how the command is being parsed
                        -
                        -INFORMATION
                        -  -h, --help           display help for modpack-lock run
                        -
                        - - -

                        For programmatic usage, modpack-lock exports these functions:

                        -
                          -
                        • getModpackInfo()
                        • -
                        • getLockfile()
                        • -
                        • generateJson()
                        • -
                        • generateGitignoreRules()
                        • -
                        • generateReadmeFiles()
                        • -
                        • generateLicense()
                        • -
                        • generateLockfile()
                        • -
                        • generateModpackFiles()
                        • -
                        • promptUserForInfo()
                        • -
                        -

                        See the API documentation for full details.

                        - - -

                        The lockfile contains metadata about Modrinth-hosted files found in modpack directories:

                        -
                        {
                        "version": "1.0.1",
                        "generated": "2026-01-06T03:00:00.000Z",
                        "total": 7,
                        "counts": {
                        "mods": 1,
                        "resourcepacks": 3,
                        "datapacks": 1,
                        "shaderpacks": 2
                        },
                        "dependencies": {
                        "mods": [
                        {
                        "path": "mods/example-mod.jar",
                        "version": { ... }
                        }
                        ],
                        "resourcepacks": [ ... ],
                        "datapacks": [ ... ],
                        "shaderpacks": [ ... ]
                        }
                        } -
                        - - -

                        The JSON file contains your modpack metadata and a dependency list:

                        -
                        {
                        "name": "My Modpack",
                        "version": "1.0.0",
                        "id": "my-modpack",
                        "description": "",
                        "author": "name",
                        "projectUrl": "",
                        "sourceUrl": "",
                        "license": "",
                        "modloader": "modloader",
                        "targetModloaderVersion": "",
                        "targetMinecraftVersion": "x.y.z",
                        "scripts": {
                        "example": "echo 'example script'"
                        },
                        "dependencies": {
                        "mods": [ ... ],
                        "resourcepacks": [ ... ],
                        "datapacks": [ ... ],
                        "shaderpacks": [ ... ]
                        }
                        } -
                        - -
                        Important

                        - -

                        Use modpack-lock -g to automatically update your .gitignore file with rules to ignore modpack contents, with exceptions for any files that are not hosted by Modrinth:

                        -
                        # .gitignore
                        -
                        -# modpack-lock:start
                        -mods/*.jar
                        -resourcepacks/*.zip
                        -datapacks/*.zip
                        -shaderpacks/*.zip
                        -*/**/*.disabled
                        -
                        -## Exceptions
                        -!mods/example.jar
                        -# modpack-lock:end
                        -
                        - -

                        This section is managed by modpack-lock and will be updated automatically when you run modpack-lock -g. Changes made inside this section will be overwritten, but any changes you make outside of this section will be preserved.

                        -
                        - -

                        This project is licensed under the MIT License - see the LICENSE file for more details.

                        -

                        GitHub License

                        -
                        diff --git a/docs/interfaces/InitOptions.html b/docs/interfaces/InitOptions.html deleted file mode 100644 index dde5d0b..0000000 --- a/docs/interfaces/InitOptions.html +++ /dev/null @@ -1,36 +0,0 @@ -InitOptions | modpack-lock
                        modpack-lock
                          Preparing search index...

                          Interface InitOptions

                          Contains options for the initialization of the modpack files.

                          -
                          interface InitOptions {
                              folder: string;
                              noninteractive: boolean;
                              addLicense: boolean;
                              addGitignore: boolean;
                              addReadme: boolean;
                              name: string;
                              version: string;
                              id: string;
                              description: string;
                              author: string;
                              projectUrl: string;
                              sourceUrl: string;
                              license: string;
                              modloader: string;
                              targetModloaderVersion: string;
                              targetMinecraftVersion: string;
                              _init: boolean;
                          }
                          Index

                          Properties

                          folder: string

                          The folder to generate the modpack files in

                          -
                          noninteractive: boolean

                          Whether to run the interactive mode

                          -
                          addLicense: boolean

                          Whether to add the license file to the modpack

                          -
                          addGitignore: boolean

                          Whether to generate .gitignore rules

                          -
                          addReadme: boolean

                          Whether to generate README.md files

                          -
                          name: string

                          The name of the modpack

                          -
                          version: string

                          The version of the modpack

                          -
                          id: string

                          The slug/ID of the modpack

                          -
                          description: string

                          The description of the modpack

                          -
                          author: string

                          The author of the modpack

                          -
                          projectUrl: string

                          The modpack's project URL

                          -
                          sourceUrl: string

                          The modpack's source code URL

                          -
                          license: string

                          The modpack's license

                          -
                          modloader: string

                          The modpack's modloader

                          -
                          targetModloaderVersion: string

                          The target modloader version

                          -
                          targetMinecraftVersion: string

                          The target Minecraft version

                          -
                          _init: boolean

                          Internal boolean added to indicate options come from the init command.

                          -
                          diff --git a/docs/interfaces/Lockfile.html b/docs/interfaces/Lockfile.html deleted file mode 100644 index 2099cdf..0000000 --- a/docs/interfaces/Lockfile.html +++ /dev/null @@ -1,20 +0,0 @@ -Lockfile | modpack-lock
                          modpack-lock
                            Preparing search index...

                            Interface Lockfile

                            Contains information about the modpack dependencies and their versions.

                            -
                            interface Lockfile {
                                version: string;
                                generated: string;
                                total: number;
                                counts: {
                                    mods: number;
                                    resourcepacks: number;
                                    datapacks: number;
                                    shaderpacks: number;
                                };
                                dependencies: {
                                    mods: any[];
                                    resourcepacks: any[];
                                    datapacks: any[];
                                    shaderpacks: any[];
                                };
                            }
                            Index

                            Properties

                            version: string

                            The version of the modpack

                            -
                            generated: string

                            The date and time the lockfile was generated

                            -
                            total: number

                            The total number of files in the modpack

                            -
                            counts: {
                                mods: number;
                                resourcepacks: number;
                                datapacks: number;
                                shaderpacks: number;
                            }

                            The counts object

                            -

                            Type Declaration

                            • mods: number

                              The mods count

                              -
                            • resourcepacks: number

                              The resourcepacks count

                              -
                            • datapacks: number

                              The datapacks count

                              -
                            • shaderpacks: number

                              The shaderpacks count

                              -
                            dependencies: {
                                mods: any[];
                                resourcepacks: any[];
                                datapacks: any[];
                                shaderpacks: any[];
                            }

                            The dependencies object

                            -

                            Type Declaration

                            • mods: any[]

                              The mods object

                              -
                            • resourcepacks: any[]

                              The resourcepacks object

                              -
                            • datapacks: any[]

                              The datapacks object

                              -
                            • shaderpacks: any[]

                              The shaderpacks object

                              -
                            diff --git a/docs/interfaces/ModpackInfo.html b/docs/interfaces/ModpackInfo.html deleted file mode 100644 index 98f70ff..0000000 --- a/docs/interfaces/ModpackInfo.html +++ /dev/null @@ -1,24 +0,0 @@ -ModpackInfo | modpack-lock
                            modpack-lock
                              Preparing search index...

                              Interface ModpackInfo

                              Contains information about the modpack that is not dependent on the lockfile.

                              -
                              interface ModpackInfo {
                                  name: string;
                                  version: string;
                                  description: string;
                                  id: string;
                                  author: string;
                                  projectUrl: string;
                                  sourceUrl: string;
                                  license: string;
                                  modloader: string;
                                  targetModloaderVersion: string;
                                  targetMinecraftVersion: string;
                              }
                              Index

                              Properties

                              name: string

                              The name of the modpack (Required)

                              -
                              version: string

                              The version of the modpack (Required)

                              -
                              description: string

                              The description of the modpack

                              -
                              id: string

                              The slug/ID of the modpack (Required)

                              -
                              author: string

                              The author of the modpack (Required)

                              -
                              projectUrl: string

                              The project URL of the modpack

                              -
                              sourceUrl: string

                              The source code URL of the modpack

                              -
                              license: string

                              The license of the modpack

                              -
                              modloader: string

                              The modloader of the modpack (Required)

                              -
                              targetModloaderVersion: string

                              The target modloader version of the modpack

                              -
                              targetMinecraftVersion: string

                              The target Minecraft version of the modpack (Required)

                              -
                              diff --git a/docs/interfaces/Options.html b/docs/interfaces/Options.html deleted file mode 100644 index 6fe4120..0000000 --- a/docs/interfaces/Options.html +++ /dev/null @@ -1,14 +0,0 @@ -Options | modpack-lock
                              modpack-lock
                                Preparing search index...

                                Interface Options

                                Contains options for the generation of the modpack files.

                                -
                                interface Options {
                                    dryRun: boolean;
                                    quiet: boolean;
                                    silent: boolean;
                                    gitignore: boolean;
                                    readme: boolean;
                                    licenseFile: boolean;
                                }
                                Index

                                Properties

                                dryRun: boolean

                                Whether to dry run the generation

                                -
                                quiet: boolean

                                Whether to quiet the console output

                                -
                                silent: boolean

                                Whether to silent the console output

                                -
                                gitignore: boolean

                                Whether to generate a .gitignore file

                                -
                                readme: boolean

                                Whether to generate README.md files

                                -
                                licenseFile: boolean

                                Whether to generate a license file

                                -
                                diff --git a/docs/media/LICENSE b/docs/media/LICENSE deleted file mode 100644 index 90b5e58..0000000 --- a/docs/media/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 N. Escobar - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/docs/modules.html b/docs/modules.html deleted file mode 100644 index b4fb24c..0000000 --- a/docs/modules.html +++ /dev/null @@ -1 +0,0 @@ -modpack-lock
                                modpack-lock
                                  Preparing search index...
                                  diff --git a/docs/sitemap.xml b/docs/sitemap.xml deleted file mode 100644 index 684c124..0000000 --- a/docs/sitemap.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - https://nickesc.github.io/modpack-lock/index.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/modules.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/hierarchy.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/interfaces/ModpackInfo.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/interfaces/Lockfile.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/interfaces/Options.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/interfaces/InitOptions.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/getModpackInfo.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/getLockfile.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateGitignoreRules.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateJson.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateLicense.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateLockfile.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateReadmeFiles.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/generateModpackFiles.html - 2026-02-15T00:19:06.741Z - - - https://nickesc.github.io/modpack-lock/functions/promptUserForInfo.html - 2026-02-15T00:19:06.741Z - - From cb01a4a6282629820cc1f09380f800bd77d1f7ae Mon Sep 17 00:00:00 2001 From: "N. Escobar" Date: Sun, 8 Mar 2026 19:08:33 -0400 Subject: [PATCH 110/110] add docs to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d846dcf..a07ed22 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ modpack.json coverage/ build/ + +docs/