From 76a83c2023e6a2131fb3487693e12505361106f7 Mon Sep 17 00:00:00 2001 From: hiroki osame Date: Wed, 9 Nov 2022 22:07:43 -0500 Subject: [PATCH] fix: follow Node.js flag handling (#133) --- package.json | 4 +-- pnpm-lock.yaml | 18 +++++----- src/cli.ts | 71 ++++++++++++++++++---------------------- src/remove-argv-flags.ts | 35 ++++++++++++++++++++ src/watch/index.ts | 10 ++---- tests/specs/cli.ts | 5 ++- 6 files changed, 85 insertions(+), 58 deletions(-) create mode 100644 src/remove-argv-flags.ts diff --git a/package.json b/package.json index eca62d96..210f83f3 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@types/semver": "^7.3.12", "chokidar": "^3.5.3", "clean-pkg-json": "^1.2.0", - "cleye": "^1.2.1", + "cleye": "^1.3.0", "cross-spawn": "^7.0.3", "eslint": "^8.24.0", "execa": "^6.1.0", @@ -74,7 +74,7 @@ "semver": "^7.3.8", "simple-git-hooks": "^2.8.1", "strip-ansi": "^7.0.1", - "type-flag": "^2.2.0", + "type-flag": "^3.0.0", "typescript": "^4.8.4" }, "eslintConfig": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cec390f3..b7d5ade6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,7 +11,7 @@ specifiers: '@types/semver': ^7.3.12 chokidar: ^3.5.3 clean-pkg-json: ^1.2.0 - cleye: ^1.2.1 + cleye: ^1.3.0 cross-spawn: ^7.0.3 eslint: ^8.24.0 execa: ^6.1.0 @@ -26,7 +26,7 @@ specifiers: semver: ^7.3.8 simple-git-hooks: ^2.8.1 strip-ansi: ^7.0.1 - type-flag: ^2.2.0 + type-flag: ^3.0.0 typescript: ^4.8.4 dependencies: @@ -45,7 +45,7 @@ devDependencies: '@types/semver': 7.3.12 chokidar: 3.5.3 clean-pkg-json: 1.2.0 - cleye: 1.2.1 + cleye: 1.3.0 cross-spawn: 7.0.3 eslint: 8.24.0 execa: 6.1.0 @@ -59,7 +59,7 @@ devDependencies: semver: 7.3.8 simple-git-hooks: 2.8.1 strip-ansi: 7.0.1 - type-flag: 2.2.0 + type-flag: 3.0.0 typescript: 4.8.4 packages: @@ -921,11 +921,11 @@ packages: engines: {node: '>=6'} dev: true - /cleye/1.2.1: - resolution: {integrity: sha512-DjoWA/dFn1rQypY4juFH4IvjVxXxld4o92bmkGPR+uZNqBMpvDXx1VUmL93p2R5CBwSWt83eEe/SLPqtQahZNg==} + /cleye/1.3.0: + resolution: {integrity: sha512-IZ0mRzFQeeQwQk6gT1KIjxa0U86VdFmVB+EIlW3t1Wl1jZShTuWbCu11LcfOA6kODYJ2K7AwgVEb4b7TxN/s2A==} dependencies: terminal-columns: 1.4.1 - type-flag: 2.2.0 + type-flag: 3.0.0 dev: true /cli-cursor/3.1.0: @@ -4109,8 +4109,8 @@ packages: engines: {node: '>=8'} dev: true - /type-flag/2.2.0: - resolution: {integrity: sha512-zumH8ohtlidBe1aqRY99OxaUY1SCdtyQlCxiXlnAyPMby6GtMem4Y7+geySt/k3MFs0pnNzQpI/nSki4yJp5Jg==} + /type-flag/3.0.0: + resolution: {integrity: sha512-3YaYwMseXCAhBB14RXW5cRQfJQlEknS6i4C8fCfeUdS3ihG9EdccdR9kt3vP73ZdeTGmPb4bZtkDn5XMIn1DLA==} dev: true /typescript/4.8.4: diff --git a/src/cli.ts b/src/cli.ts index fca3aeb5..af325622 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,8 +1,11 @@ import { cli } from 'cleye'; -import typeFlag from 'type-flag'; import { version } from '../package.json'; import { run } from './run'; import { watchCommand } from './watch'; +import { + removeArgvFlags, + ignoreAfterArgument, +} from './remove-argv-flags'; const tsxFlags = { noCache: { @@ -15,54 +18,44 @@ const tsxFlags = { }, }; -const flags = { - ...tsxFlags, - version: { - type: Boolean, - description: 'Show version', - }, - help: { - type: Boolean, - alias: 'h', - description: 'Show help', - }, -}; - cli({ name: 'tsx', parameters: ['[script path]'], commands: [ watchCommand, ], - flags, + flags: { + ...tsxFlags, + version: { + type: Boolean, + alias: 'v', + description: 'Show version', + }, + help: { + type: Boolean, + alias: 'h', + description: 'Show help', + }, + }, help: false, + ignoreArgv: ignoreAfterArgument(), }, (argv) => { - const noArgs = argv._.length === 0; - - if (noArgs) { - if (argv.flags.version) { - console.log(version); - return; - } - - if (argv.flags.help) { - argv.showHelp({ - description: 'Node.js runtime enhanced with esbuild for loading TypeScript & ESM', - }); - return; - } + if (argv.flags.version) { + process.stdout.write(`tsx v${version}\nnode `); + } else if (argv.flags.help) { + argv.showHelp({ + description: 'Node.js runtime enhanced with esbuild for loading TypeScript & ESM', + }); + console.log(`${'-'.repeat(45)}\n`); } - const args = typeFlag( - noArgs ? flags : tsxFlags, - process.argv.slice(2), - { ignoreUnknown: true }, - )._; - - const childProcess = run(args, { - noCache: Boolean(argv.flags.noCache), - tsconfigPath: argv.flags.tsconfig, - }); + const childProcess = run( + removeArgvFlags(tsxFlags), + { + noCache: Boolean(argv.flags.noCache), + tsconfigPath: argv.flags.tsconfig, + }, + ); const relaySignal = async (signal: NodeJS.Signals) => { const message = await Promise.race([ diff --git a/src/remove-argv-flags.ts b/src/remove-argv-flags.ts new file mode 100644 index 00000000..0278fd6e --- /dev/null +++ b/src/remove-argv-flags.ts @@ -0,0 +1,35 @@ +import { + typeFlag, + type Flags, + type TypeFlagOptions, +} from 'type-flag'; + +export const ignoreAfterArgument = (): TypeFlagOptions['ignore'] => { + let ignore = false; + + return (type) => { + if (ignore) { + return true; + } + const isArgument = type === 'argument'; + if (isArgument || type === 'unknown-flag') { + ignore = isArgument; + return true; + } + }; +}; + +export function removeArgvFlags( + tsxFlags: Flags, + argv = process.argv.slice(2), +) { + typeFlag( + tsxFlags, + argv, + { + ignore: ignoreAfterArgument(), + }, + ); + + return argv; +} diff --git a/src/watch/index.ts b/src/watch/index.ts index 3752b497..29a4bf42 100644 --- a/src/watch/index.ts +++ b/src/watch/index.ts @@ -3,9 +3,9 @@ import { fileURLToPath } from 'url'; import { constants as osConstants } from 'os'; import path from 'path'; import { command } from 'cleye'; -import typeFlag from 'type-flag'; import { watch } from 'chokidar'; import { run } from '../run'; +import { removeArgvFlags } from '../remove-argv-flags'; import { clearScreen, debounce, @@ -42,11 +42,7 @@ export const watchCommand = command({ description: 'Run the script and watch for changes', }, }, (argv) => { - const args = typeFlag( - flags, - process.argv.slice(3), - { ignoreUnknown: true }, - )._; + const rawArgvs = removeArgvFlags(flags, process.argv.slice(3)); const options = { noCache: argv.flags.noCache, @@ -75,7 +71,7 @@ export const watchCommand = command({ process.stdout.write(clearScreen); } - runProcess = run(args, options); + runProcess = run(rawArgvs, options); runProcess.on('message', (data) => { // Collect run-time dependencies to watch diff --git a/tests/specs/cli.ts b/tests/specs/cli.ts index 97a486f4..65c32d8e 100644 --- a/tests/specs/cli.ts +++ b/tests/specs/cli.ts @@ -13,7 +13,7 @@ export default testSuite(({ describe }, fixturePath: string) => { }); expect(tsxProcess.exitCode).toBe(0); - expect(tsxProcess.stdout).toBe(packageJson.version); + expect(tsxProcess.stdout).toBe(`tsx v${packageJson.version}\nnode ${process.version}`); expect(tsxProcess.stderr).toBe(''); }); @@ -27,6 +27,7 @@ export default testSuite(({ describe }, fixturePath: string) => { expect(tsxProcess.exitCode).toBe(0); expect(tsxProcess.stdout).toMatch('"--version"'); + expect(tsxProcess.stdout).not.toMatch(packageJson.version); expect(tsxProcess.stderr).toBe(''); }); }); @@ -39,6 +40,7 @@ export default testSuite(({ describe }, fixturePath: string) => { expect(tsxProcess.exitCode).toBe(0); expect(tsxProcess.stdout).toMatch('Node.js runtime enhanced with esbuild for loading TypeScript & ESM'); + expect(tsxProcess.stdout).toMatch('Usage: node [options] [ script.js ] [arguments]'); expect(tsxProcess.stderr).toBe(''); }); @@ -52,6 +54,7 @@ export default testSuite(({ describe }, fixturePath: string) => { expect(tsxProcess.exitCode).toBe(0); expect(tsxProcess.stdout).toMatch('"--help"'); + expect(tsxProcess.stdout).not.toMatch('tsx'); expect(tsxProcess.stderr).toBe(''); }); });