From a7c6ced936f3b4c1c9eeb3bcb0811ed8ccfd387f Mon Sep 17 00:00:00 2001 From: Keiichiro Amemiya Date: Fri, 27 Dec 2024 11:10:13 +0100 Subject: [PATCH 1/2] refactor: use template literals for log output --- src/commands/defaultconfig.ts | 19 +++++++------------ src/commands/schema-types.ts | 3 +-- src/commands/uninstall.ts | 2 +- src/index.ts | 9 ++------- src/lib/install-bundle-deps.ts | 7 ++++--- test/mocks/program.ts | 5 ++--- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/commands/defaultconfig.ts b/src/commands/defaultconfig.ts index 34a8f75..6fca4e5 100644 --- a/src/commands/defaultconfig.ts +++ b/src/commands/defaultconfig.ts @@ -25,7 +25,7 @@ function action(bundleName?: string) { bundleName = bundleName ?? path.basename(cwd); } else { console.error( - chalk.red("Error:") + " No bundle found in the current directory!", + `${chalk.red("Error:")} No bundle found in the current directory!`, ); return; } @@ -41,17 +41,13 @@ function action(bundleName?: string) { const cfgPath = path.join(nodecgPath, "cfg/"); if (!fs.existsSync(bundlePath)) { - console.error( - chalk.red("Error:") + " Bundle %s does not exist", - bundleName, - ); + console.error(`${chalk.red("Error:")} Bundle ${bundleName} does not exist`); return; } if (!fs.existsSync(schemaPath)) { console.error( - chalk.red("Error:") + " Bundle %s does not have a configschema.json", - bundleName, + `${chalk.red("Error:")} Bundle ${bundleName} does not have a configschema.json`, ); return; } @@ -63,11 +59,10 @@ function action(bundleName?: string) { const schema: JSONSchemaType = JSON.parse( fs.readFileSync(schemaPath, "utf8"), ); - const configPath = path.join(nodecgPath, "cfg/", bundleName + ".json"); + const configPath = path.join(nodecgPath, "cfg/", `${bundleName}.json`); if (fs.existsSync(configPath)) { console.error( - chalk.red("Error:") + " Bundle %s already has a config file", - bundleName, + `${chalk.red("Error:")} Bundle ${bundleName} already has a config file`, ); } else { try { @@ -79,8 +74,8 @@ function action(bundleName?: string) { console.log( `${chalk.green("Success:")} Created ${chalk.bold(bundleName)}'s default config from schema\n`, ); - } catch (e) { - console.error(chalk.red("Error: ") + String(e)); + } catch (error) { + console.error(chalk.red("Error:"), error); } } } diff --git a/src/commands/schema-types.ts b/src/commands/schema-types.ts index a7f5a1a..17452f9 100644 --- a/src/commands/schema-types.ts +++ b/src/commands/schema-types.ts @@ -28,8 +28,7 @@ function action(inDir: string, cmd: { outDir: string; configSchema: boolean }) { const schemasDir = path.resolve(processCwd, inDir || "schemas"); if (!fs.existsSync(schemasDir)) { console.error( - chalk.red("Error:") + ' Input directory ("%s") does not exist', - inDir, + `${chalk.red("Error:")} Input directory "${inDir}" does not exist`, ); return; } diff --git a/src/commands/uninstall.ts b/src/commands/uninstall.ts index c073bb5..dd2110c 100644 --- a/src/commands/uninstall.ts +++ b/src/commands/uninstall.ts @@ -48,7 +48,7 @@ function deleteBundle(name: string, path: string) { return; } - process.stdout.write("Uninstalling " + chalk.magenta(name) + "... "); + process.stdout.write(`Uninstalling ${chalk.magenta(name)}... `); try { fs.rmSync(path, { recursive: true, force: true }); } catch (e: any) { diff --git a/src/index.ts b/src/index.ts index a390277..d6dfa60 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,15 +21,10 @@ getLatestCLIRelease() .then((release) => { if (semver.gt(release.version, packageVersion)) { console.log( - chalk.yellow("?") + - " A new update is available for nodecg-cli: " + - chalk.green.bold(release.version) + - chalk.dim(" (current: " + packageVersion + ")"), + `${chalk.yellow("?")} A new update is available for nodecg-cli: ${chalk.green.bold(release.version)} ${chalk.dim(`(current: ${packageVersion})`)}`, ); console.log( - " Run " + - chalk.cyan.bold("npm install -g nodecg-cli") + - " to install the latest version", + ` Run ${chalk.cyan.bold("npm install -g nodecg-cli")} to install the latest version`, ); } }) diff --git a/src/lib/install-bundle-deps.ts b/src/lib/install-bundle-deps.ts index 12818d8..4c7502c 100644 --- a/src/lib/install-bundle-deps.ts +++ b/src/lib/install-bundle-deps.ts @@ -1,6 +1,7 @@ import { execSync } from "node:child_process"; import fs from "node:fs"; import os from "node:os"; +import path from "node:path"; import { format } from "node:util"; import chalk from "chalk"; @@ -26,10 +27,10 @@ export function installBundleDeps(bundlePath: string, installDev = false) { let cmdline; const cachedCwd = process.cwd(); - if (fs.existsSync(bundlePath + "/package.json")) { + if (fs.existsSync(path.join(bundlePath, "package.json"))) { process.chdir(bundlePath); let cmdline: string; - if (fs.existsSync(bundlePath + "/yarn.lock")) { + if (fs.existsSync(path.join(bundlePath, "yarn.lock"))) { cmdline = installDev ? "yarn" : "yarn --production"; process.stdout.write( format( @@ -62,7 +63,7 @@ export function installBundleDeps(bundlePath: string, installDev = false) { process.chdir(cachedCwd); } - if (fs.existsSync(bundlePath + "/bower.json")) { + if (fs.existsSync(path.join(bundlePath, "bower.json"))) { cmdline = format("bower install %s", installDev ? "" : "--production"); process.stdout.write( format("Installing bower dependencies (dev: %s)... ", installDev), diff --git a/test/mocks/program.ts b/test/mocks/program.ts index 5ef4975..5c2424b 100644 --- a/test/mocks/program.ts +++ b/test/mocks/program.ts @@ -1,6 +1,5 @@ -import { mock } from "node:test"; - import { Command } from "commander"; +import { vi } from "vitest"; export class MockCommand extends Command { log() { @@ -19,7 +18,7 @@ export class MockCommand extends Command { export const createMockProgram = () => { const program = new MockCommand(); - mock.method(program, "log").mock.mockImplementation(() => void 0); + vi.spyOn(program, "log").mockImplementation(() => void 0); return program; }; From 2bc3423575bebc509420e4a1ccf78fa34f34d98f Mon Sep 17 00:00:00 2001 From: Keiichiro Amemiya Date: Fri, 27 Dec 2024 11:39:56 +0100 Subject: [PATCH 2/2] fix tests --- src/bin/nodecg.ts | 30 ++++----------------------- src/commands/schema-types.ts | 4 +--- src/commands/setup.ts | 11 +++------- src/commands/uninstall.ts | 3 +-- src/lib/install-bundle-deps.ts | 17 +++++---------- test/commands/defaultconfig.spec.ts | 32 +++++++++++++++++++++-------- test/commands/schema-types.spec.ts | 8 ++++++-- test/commands/setup.spec.ts | 8 +++++--- test/commands/uninstall.spec.ts | 8 +++++--- test/mocks/program.ts | 2 +- 10 files changed, 55 insertions(+), 68 deletions(-) diff --git a/src/bin/nodecg.ts b/src/bin/nodecg.ts index 7b0518a..8b9da67 100755 --- a/src/bin/nodecg.ts +++ b/src/bin/nodecg.ts @@ -1,36 +1,14 @@ #!/usr/bin/env node -import { execSync } from "node:child_process"; +import { execFileSync } from "node:child_process"; import chalk from "chalk"; -const REQUIRED_VERSION = "v0.11.22"; - -if (typeof execSync !== "function") { - console.error( - "nodecg-cli relies on %s, which was added to Node.js in %s (your version: %s).", - chalk.cyan("execSync"), - chalk.magenta(REQUIRED_VERSION), - chalk.magenta(process.version), - ); - console.error("Please upgrade your Node.js installation."); - process.exit(1); -} - try { - execSync("git --version", { stdio: ["pipe", "pipe", "pipe"] }); -} catch (_) { - console.error( - "nodecg-cli requires that %s be available in your PATH.", - chalk.cyan("git"), - ); - console.error( - "If you do not have %s installed, you can get it from http://git-scm.com/", - chalk.cyan("git"), - ); + execFileSync("git", ["--version"]); +} catch { console.error( - "By default, the installer will add %s to your PATH.", - chalk.cyan("git"), + `nodecg-cli requires that ${chalk.cyan("git")} be available in your PATH.`, ); process.exit(1); } diff --git a/src/commands/schema-types.ts b/src/commands/schema-types.ts index 17452f9..6ac7e2d 100644 --- a/src/commands/schema-types.ts +++ b/src/commands/schema-types.ts @@ -27,9 +27,7 @@ function action(inDir: string, cmd: { outDir: string; configSchema: boolean }) { const processCwd = process.cwd(); const schemasDir = path.resolve(processCwd, inDir || "schemas"); if (!fs.existsSync(schemasDir)) { - console.error( - `${chalk.red("Error:")} Input directory "${inDir}" does not exist`, - ); + console.error(`${chalk.red("Error:")} Input directory does not exist`); return; } diff --git a/src/commands/setup.ts b/src/commands/setup.ts index af55318..83c5b6e 100644 --- a/src/commands/setup.ts +++ b/src/commands/setup.ts @@ -150,7 +150,7 @@ async function decideActionVersion( if (isUpdate) { const verb = downgrade ? "downgraded" : "upgraded"; - console.log("NodeCG %s to", verb, chalk.magenta(target)); + console.log(`NodeCG ${verb} to ${chalk.magenta(target)}`); } else { console.log(`NodeCG (${target}) installed to ${process.cwd()}`); } @@ -282,13 +282,8 @@ function logDownOrUpgradeMessage( target: string, downgrade: boolean, ): void { - const Verb = downgrade ? "Downgrading" : "Upgrading"; + const verb = downgrade ? "Downgrading" : "Upgrading"; process.stdout.write( - Verb + - " from " + - chalk.magenta(current) + - " to " + - chalk.magenta(target) + - "... ", + `${verb} from ${chalk.magenta(current)} to ${chalk.magenta(target)}... `, ); } diff --git a/src/commands/uninstall.ts b/src/commands/uninstall.ts index dd2110c..ed6116d 100644 --- a/src/commands/uninstall.ts +++ b/src/commands/uninstall.ts @@ -22,8 +22,7 @@ function action(bundleName: string, options: { force: boolean }) { if (!fs.existsSync(bundlePath)) { console.error( - "Cannot uninstall %s: bundle is not installed.", - chalk.magenta(bundleName), + `Cannot uninstall ${chalk.magenta(bundleName)}: bundle is not installed.`, ); return; } diff --git a/src/lib/install-bundle-deps.ts b/src/lib/install-bundle-deps.ts index 4c7502c..03650d0 100644 --- a/src/lib/install-bundle-deps.ts +++ b/src/lib/install-bundle-deps.ts @@ -2,7 +2,6 @@ import { execSync } from "node:child_process"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { format } from "node:util"; import chalk from "chalk"; @@ -16,10 +15,7 @@ import { isBundleFolder } from "./util.js"; export function installBundleDeps(bundlePath: string, installDev = false) { if (!isBundleFolder(bundlePath)) { console.error( - chalk.red("Error:") + - " There doesn't seem to be a valid NodeCG bundle in this folder:" + - "\n\t" + - chalk.magenta(bundlePath), + `${chalk.red("Error:")} There doesn't seem to be a valid NodeCG bundle in this folder:\n\t${chalk.magenta(bundlePath)}`, ); process.exit(1); } @@ -33,15 +29,12 @@ export function installBundleDeps(bundlePath: string, installDev = false) { if (fs.existsSync(path.join(bundlePath, "yarn.lock"))) { cmdline = installDev ? "yarn" : "yarn --production"; process.stdout.write( - format( - "Installing npm dependencies with yarn (dev: %s)... ", - installDev, - ), + `Installling npm dependencies with yarn (dev: ${installDev})... `, ); } else { cmdline = installDev ? "npm install" : "npm install --production"; process.stdout.write( - format("Installing npm dependencies (dev: %s)... ", installDev), + `Installing npm dependencies (dev: ${installDev})... `, ); } @@ -64,9 +57,9 @@ export function installBundleDeps(bundlePath: string, installDev = false) { } if (fs.existsSync(path.join(bundlePath, "bower.json"))) { - cmdline = format("bower install %s", installDev ? "" : "--production"); + cmdline = installDev ? "bower install" : "bower install --production"; process.stdout.write( - format("Installing bower dependencies (dev: %s)... ", installDev), + `Installing bower dependencies (dev: ${installDev})... `, ); try { execSync(cmdline, { diff --git a/test/commands/defaultconfig.spec.ts b/test/commands/defaultconfig.spec.ts index 3a129c3..b85b165 100644 --- a/test/commands/defaultconfig.spec.ts +++ b/test/commands/defaultconfig.spec.ts @@ -45,8 +45,12 @@ describe("when run with a bundle argument", () => { { recursive: true }, ); await program.runWith("defaultconfig missing-schema-bundle"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"Error: Bundle %s does not have a configschema.json"`, + expect(spy.mock.calls[0]).toMatchInlineSnapshot( + ` + [ + "Error: Bundle missing-schema-bundle does not have a configschema.json", + ] + `, ); spy.mockRestore(); }); @@ -54,8 +58,12 @@ describe("when run with a bundle argument", () => { it("should print an error when the target bundle does not exist", async () => { const spy = vi.spyOn(console, "error"); await program.runWith("defaultconfig not-installed"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"Error: Bundle %s does not exist"`, + expect(spy.mock.calls[0]).toMatchInlineSnapshot( + ` + [ + "Error: Bundle not-installed does not exist", + ] + `, ); spy.mockRestore(); }); @@ -68,8 +76,12 @@ describe("when run with a bundle argument", () => { JSON.stringify({ fake: "data" }), ); await program.runWith("defaultconfig config-schema"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"Error: Bundle %s already has a config file"`, + expect(spy.mock.calls[0]).toMatchInlineSnapshot( + ` + [ + "Error: Bundle config-schema already has a config file", + ] + `, ); spy.mockRestore(); }); @@ -90,8 +102,12 @@ describe("when run with no arguments", () => { const spy = vi.spyOn(console, "error"); await program.runWith("defaultconfig"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"Error: No bundle found in the current directory!"`, + expect(spy.mock.calls[0]).toMatchInlineSnapshot( + ` + [ + "Error: No bundle found in the current directory!", + ] + `, ); spy.mockRestore(); }); diff --git a/test/commands/schema-types.spec.ts b/test/commands/schema-types.spec.ts index 891334e..fcfe0e8 100644 --- a/test/commands/schema-types.spec.ts +++ b/test/commands/schema-types.spec.ts @@ -73,8 +73,12 @@ it("should print an error when the target bundle does not have a schemas dir", a process.chdir("bundles/uninstall-test"); const spy = vi.spyOn(console, "error"); await program.runWith("schema-types"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"Error: Input directory ("%s") does not exist"`, + expect(spy.mock.calls[0]).toMatchInlineSnapshot( + ` + [ + "Error: Input directory does not exist", + ] + `, ); spy.mockRestore(); }); diff --git a/test/commands/setup.spec.ts b/test/commands/setup.spec.ts index ee61dc2..32188b7 100644 --- a/test/commands/setup.spec.ts +++ b/test/commands/setup.spec.ts @@ -82,9 +82,11 @@ test("should correctly handle and refuse when you try to downgrade from v2 to v1 test("should print an error when the target version doesn't exist", async () => { const spy = vi.spyOn(console, "error"); await program.runWith("setup 0.0.99 -u --skip-dependencies"); - expect(spy.mock.calls[0]![0]).toMatchInlineSnapshot( - `"No releases match the supplied semver range (0.0.99)"`, - ); + expect(spy.mock.calls[0]).toMatchInlineSnapshot(` + [ + "No releases match the supplied semver range (0.0.99)", + ] + `); spy.mockRestore(); }); diff --git a/test/commands/uninstall.spec.ts b/test/commands/uninstall.spec.ts index 5cd6ac9..b466aa5 100644 --- a/test/commands/uninstall.spec.ts +++ b/test/commands/uninstall.spec.ts @@ -37,8 +37,10 @@ it("should delete the bundle's folder after prompting for confirmation", async ( it("should print an error when the target bundle is not installed", async () => { const spy = vi.spyOn(console, "error"); await program.runWith("uninstall not-installed"); - expect(spy.mock.calls[0]![0]).toBe( - "Cannot uninstall %s: bundle is not installed.", - ); + expect(spy.mock.calls[0]).toMatchInlineSnapshot(` + [ + "Cannot uninstall not-installed: bundle is not installed.", + ] + `); spy.mockRestore(); }); diff --git a/test/mocks/program.ts b/test/mocks/program.ts index 5c2424b..14b3206 100644 --- a/test/mocks/program.ts +++ b/test/mocks/program.ts @@ -7,7 +7,7 @@ export class MockCommand extends Command { } request(opts: any) { - throw new Error("Unexpected request: " + JSON.stringify(opts, null, 2)); + throw new Error(`Unexpected request: ${JSON.stringify(opts, null, 2)}`); } runWith(argString: string) {