diff --git a/README.md b/README.md index 1f8247c..6fa80cc 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # Mod Manager + A package manager-like CLI utility for installing, upgrading and migrating mods on Fabric Minecraft Servers ## Envrionment Variables + The list of required variables are as follows: + ``` CURSEFORGE_API_KEY="**api key goes here**" ``` \ No newline at end of file diff --git a/src/commands/install_command.ts b/src/commands/install_command.ts index 3f31a8a..fb18737 100644 --- a/src/commands/install_command.ts +++ b/src/commands/install_command.ts @@ -9,7 +9,7 @@ export default class InstallCommand implements Subcommand { .description("Installs the provided mods") .argument("", "The mods to install") .option("-e, --essential", "Marks these mods as essential", false) - .action(function() { + .action(function () { ModManager.execute(async () => { for (const mod of this.args) { await Mods.install(mod, this.opts().essential); diff --git a/src/commands/list_command.ts b/src/commands/list_command.ts index d9d2918..5e7adfc 100644 --- a/src/commands/list_command.ts +++ b/src/commands/list_command.ts @@ -13,7 +13,7 @@ export class ListCommand implements Subcommand { .description("Lists installed mods") .action(() => { ModManager.execute(() => { - const tableFunc = asTable.configure ({ + const tableFunc = asTable.configure({ title: x => chalk.cyanBright(Util.stringPrettyify(x)), delimiter: chalk.blueBright(' | '), dash: chalk.blueBright('-') diff --git a/src/commands/uninstall_command.ts b/src/commands/uninstall_command.ts index ed1566d..1f5b0df 100644 --- a/src/commands/uninstall_command.ts +++ b/src/commands/uninstall_command.ts @@ -16,5 +16,5 @@ export default class UninstallCommand implements Subcommand { }) }) } - + } \ No newline at end of file diff --git a/src/commands/update_command.ts b/src/commands/update_command.ts index d6e52ba..ec3afe0 100644 --- a/src/commands/update_command.ts +++ b/src/commands/update_command.ts @@ -8,7 +8,7 @@ export default class UpdateCommand implements Subcommand { program.command("update") .description("Checks for and updates mods that have a newer available version") .action(() => { - ModManager.execute(async() => { + ModManager.execute(async () => { await Mods.update(); }) }) diff --git a/src/mod-manager.ts b/src/mod-manager.ts index b8411a6..80f3fd7 100644 --- a/src/mod-manager.ts +++ b/src/mod-manager.ts @@ -20,9 +20,15 @@ import {CurseforgeSource} from "./mods/sources/curseforge_source.js"; export default class ModManager { public static logger: Logger | null = null; - + static FilePaths = class { + public static readonly MOD_MANAGER_FOLDER_PATH = path.join(".mod-manager"); + public static readonly LOGS_FOLDER = path.join(this.MOD_MANAGER_FOLDER_PATH, "logs"); + public static readonly LOG_FILE: string = path.join(this.LOGS_FOLDER, `${new Date().valueOf()}.log.json`); + public static readonly MOD_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "mods.json"); + public static readonly VERSION_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "version") + public static readonly MODS_FOLDER_PATH = path.join("mods") + } private static program: Command = new Command(); - private static subcommands: Array = [ new InitCommand(), new InstallCommand(), @@ -34,15 +40,6 @@ export default class ModManager { new MigrateCommand() ]; - static FilePaths = class { - public static readonly MOD_MANAGER_FOLDER_PATH = path.join(".mod-manager"); - public static readonly LOGS_FOLDER = path.join(this.MOD_MANAGER_FOLDER_PATH, "logs"); - public static readonly LOG_FILE: string = path.join(this.LOGS_FOLDER, `${new Date().valueOf()}.log.json`); - public static readonly MOD_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "mods.json"); - public static readonly VERSION_FILE_PATH = path.join(this.MOD_MANAGER_FOLDER_PATH, "version") - public static readonly MODS_FOLDER_PATH = path.join("mods") - } - static init() { if (Initialiser.isInitialised()) { this.logger = ModManager.createLogger(); @@ -74,10 +71,11 @@ export default class ModManager { static createLogger(): Logger { let logger = pino({ - base: { - pid: undefined, - hostname: undefined} - }, + base: { + pid: undefined, + hostname: undefined + } + }, pino.destination({ dest: ModManager.FilePaths.LOG_FILE, sync: true diff --git a/src/mods/mods.ts b/src/mods/mods.ts index 25b436f..2daea72 100644 --- a/src/mods/mods.ts +++ b/src/mods/mods.ts @@ -107,12 +107,12 @@ export default class Mods { this.silentUninstall(modToUninstall); for (let dependency of modToUninstall.dependencies) { - if (!this.isDependedOn(dependency)) { - const dependencyMod = this.findMod(dependency); - if (dependencyMod != undefined) { - this.silentUninstall(dependencyMod) - } + if (!this.isDependedOn(dependency)) { + const dependencyMod = this.findMod(dependency); + if (dependencyMod != undefined) { + this.silentUninstall(dependencyMod) } + } } spinner.succeed(`${modToUninstall.name} successfully uninstalled!`) @@ -161,30 +161,6 @@ export default class Mods { } } - /** - * Finds the mod based on the provided id or name - * @param mod the id or mod name - * @return the found Mod, or undefined if no mod was found - */ - private static findMod(mod: string): TrackedMod | undefined { - // Replace underscores and dashes with spaces - mod = mod.replaceAll("_", " "); - mod = mod.replaceAll("-", " ") - - let mods: Array = this.getTrackedMods(); - for (let modEle of mods) { - const id = modEle.id.toLowerCase(); - const name = modEle.name.toLowerCase(); - - const query = mod.toLowerCase(); - if (id == query || Util.areStringsSimilar(mod, name)) { - return modEle; - } - } - - return undefined; - } - static async update() { const trackedMods = this.getTrackedMods(); @@ -202,7 +178,7 @@ export default class Mods { // Get the latest version const source = this.getSourceFromName(mod.source); - let latestVersion: Version | undefined = undefined; + let latestVersion: Version | undefined = undefined; try { latestVersion = await source.getLatestVersion(mod.id, mcVersion); @@ -286,10 +262,6 @@ export default class Mods { return possible; } - private static getEssentialMods() { - return this.getTrackedMods().filter(mod => mod.essential); - } - /** * Migrates to the provided version of minecraft * @param version the Minecraft version to migrate to @@ -343,6 +315,34 @@ export default class Mods { PrintUtils.success(`Successfully migrated to ${version}`) } + /** + * Finds the mod based on the provided id or name + * @param mod the id or mod name + * @return the found Mod, or undefined if no mod was found + */ + private static findMod(mod: string): TrackedMod | undefined { + // Replace underscores and dashes with spaces + mod = mod.replaceAll("_", " "); + mod = mod.replaceAll("-", " ") + + let mods: Array = this.getTrackedMods(); + for (let modEle of mods) { + const id = modEle.id.toLowerCase(); + const name = modEle.name.toLowerCase(); + + const query = mod.toLowerCase(); + if (id == query || Util.areStringsSimilar(mod, name)) { + return modEle; + } + } + + return undefined; + } + + private static getEssentialMods() { + return this.getTrackedMods().filter(mod => mod.essential); + } + private static isDependedOn(dependency: string) { const trackedMods = this.getTrackedMods(); diff --git a/src/util/util.ts b/src/util/util.ts index b1cd784..6cb8cd6 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -1,4 +1,4 @@ -import { stringSimilarity } from "string-similarity-js"; +import {stringSimilarity} from "string-similarity-js"; export default class Util { private static readonly SIMILARITY_THRESHOLD: number = 0.8; @@ -11,7 +11,9 @@ export default class Util { return str // insert a space before all caps .replace(/([A-Z])/g, ' $1') // uppercase the first character - .replace(/^./, function(str){ return str.toUpperCase(); }) + .replace(/^./, function (str) { + return str.toUpperCase(); + }) } static areStringsSimilar(master: string, compare: string): boolean { diff --git a/tsconfig.json b/tsconfig.json index 35e9a1e..b53e305 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,34 +4,53 @@ "lib": [ "ESNext", "dom" - ], // specifies which default set of type definitions to use ("DOM", "ES6", etc) - "outDir": "dist", // .js (as well as .d.ts, .js.map, etc.) files will be emitted into this directory., - "removeComments": true, // Strips all comments from TypeScript files when converting into JavaScript- you rarely read compiled code so this saves space - "target": "ES6", // Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3) + ], + // specifies which default set of type definitions to use ("DOM", "ES6", etc) + "outDir": "dist", + // .js (as well as .d.ts, .js.map, etc.) files will be emitted into this directory., + "removeComments": true, + // Strips all comments from TypeScript files when converting into JavaScript- you rarely read compiled code so this saves space + "target": "ES6", + // Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3) // Module resolution - "baseUrl": "./", // Lets you set a base directory to resolve non-absolute module names. - "esModuleInterop": true, // fixes some issues TS originally had with the ES6 spec where TypeScript treats CommonJS/AMD/UMD modules similar to ES6 module - "moduleResolution": "node", // Pretty much always node for modern JS. Other option is "classic" - "paths": {}, // A series of entries which re-map imports to lookup locations relative to the baseUrl + "baseUrl": "./", + // Lets you set a base directory to resolve non-absolute module names. + "esModuleInterop": true, + // fixes some issues TS originally had with the ES6 spec where TypeScript treats CommonJS/AMD/UMD modules similar to ES6 module + "moduleResolution": "node", + // Pretty much always node for modern JS. Other option is "classic" + "paths": {}, + // A series of entries which re-map imports to lookup locations relative to the baseUrl // Source Map - "sourceMap": true, // enables the use of source maps for debuggers and error reporting etc - "sourceRoot": "/", // Specify the location where a debugger should locate TypeScript files instead of relative source locations. + "sourceMap": true, + // enables the use of source maps for debuggers and error reporting etc + "sourceRoot": "/", + // Specify the location where a debugger should locate TypeScript files instead of relative source locations. // Strict Checks - "alwaysStrict": true, // Ensures that your files are parsed in the ECMAScript strict mode, and emit “use strict” for each source file. - "allowUnreachableCode": false, // pick up dead code paths - "noImplicitAny": true, // In some cases where no type annotations are present, TypeScript will fall back to a type of any for a variable when it cannot infer the type. - "strictNullChecks": true, // When strictNullChecks is true, null and undefined have their own distinct types and you’ll get a type error if you try to use them where a concrete value is expected. + "alwaysStrict": true, + // Ensures that your files are parsed in the ECMAScript strict mode, and emit “use strict” for each source file. + "allowUnreachableCode": false, + // pick up dead code paths + "noImplicitAny": true, + // In some cases where no type annotations are present, TypeScript will fall back to a type of any for a variable when it cannot infer the type. + "strictNullChecks": true, + // When strictNullChecks is true, null and undefined have their own distinct types and you’ll get a type error if you try to use them where a concrete value is expected. // Linter Checks "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, // accessing index must always check for undefined - "noUnusedLocals": true, // Report errors on unused local variables. - "noUnusedParameters": true // Report errors on unused parameters in functions + "noUncheckedIndexedAccess": true, + // accessing index must always check for undefined + "noUnusedLocals": true, + // Report errors on unused local variables. + "noUnusedParameters": true + // Report errors on unused parameters in functions }, - "include": ["./**/*.ts"], + "include": [ + "./**/*.ts" + ], "exclude": [ "node_modules/**/*" ]