From 1cd4eb0f1b568bdc6977fcdeb33ffb0b9dbd23dc Mon Sep 17 00:00:00 2001 From: rxliuli Date: Fri, 28 Jul 2023 21:17:38 +0800 Subject: [PATCH] feat(vite-node): make CLI arguments parsing behavior consistent with node/tsx/ts-node (#3574) --- packages/vite-node/src/cli.ts | 29 ++++++++++++++++++--- test/vite-node/src/cli-parse-args.js | 2 ++ test/vite-node/test/cli.test.ts | 38 ++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 test/vite-node/src/cli-parse-args.js create mode 100644 test/vite-node/test/cli.test.ts diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index ef8e607e47f0..77e5900db1e6 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -12,21 +12,31 @@ import { installSourcemapsSupport } from './source-map' const cli = cac('vite-node') cli - .version(version) .option('-r, --root ', 'Use specified root directory') .option('-c, --config ', 'Use specified config file') .option('-m, --mode ', 'Set env mode') .option('-w, --watch', 'Restart on file changes, similar to "nodemon"') .option('--script', 'Use vite-node as a script runner') .option('--options ', 'Use specified Vite server options') - .help() + .option('-v, --version', 'Output the version number') + .option('-h, --help', 'Display help for command') cli .command('[...files]') .allowUnknownOptions() .action(run) -cli.parse() +cli.parse(process.argv, { run: false }) + +if (cli.args.length === 0) { + cli.runMatchedCommand() +} +else { + const i = cli.rawArgs.indexOf(cli.args[0]) + 1 + const scriptArgs = cli.rawArgs.slice(i).filter(it => it !== '--') + const executeArgs = [...cli.rawArgs.slice(0, i), '--', ...scriptArgs] + cli.parse(executeArgs) +} export interface CliOptions { root?: string @@ -35,6 +45,8 @@ export interface CliOptions { mode?: string watch?: boolean options?: ViteNodeServerOptionsCLI + version?: boolean + help?: boolean '--'?: string[] } @@ -48,9 +60,18 @@ async function run(files: string[], options: CliOptions = {}) { process.argv = [...process.argv.slice(0, 2), ...(options['--'] || [])] } + if (options.version) { + cli.version(version) + cli.outputVersion() + process.exit(0) + } + if (options.help) { + cli.version(version).outputHelp() + process.exit(0) + } if (!files.length) { console.error(c.red('No files specified.')) - cli.outputHelp() + cli.version(version).outputHelp() process.exit(1) } diff --git a/test/vite-node/src/cli-parse-args.js b/test/vite-node/src/cli-parse-args.js new file mode 100644 index 000000000000..afaf1236eae6 --- /dev/null +++ b/test/vite-node/src/cli-parse-args.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-console +console.log(process.argv) diff --git a/test/vite-node/test/cli.test.ts b/test/vite-node/test/cli.test.ts new file mode 100644 index 000000000000..600a316cf971 --- /dev/null +++ b/test/vite-node/test/cli.test.ts @@ -0,0 +1,38 @@ +import { execa } from 'execa' +import { resolve } from 'pathe' +import { expect, it } from 'vitest' + +const cliPath = resolve(__dirname, '../../../packages/vite-node/src/cli.ts') +const entryPath = resolve(__dirname, '../src/cli-parse-args.js') + +const parseResult = (s: string) => JSON.parse(s.replaceAll('\'', '"')) + +it('basic', async () => { + const result = await execa('npx', ['esno', cliPath, entryPath], { reject: true }) + expect(result.stdout).include('node') + expect(parseResult(result.stdout)).length(2) +}, 60_000) + +it('--help', async () => { + const r1 = await execa('npx', ['esno', cliPath, '--help', entryPath], { reject: true }) + expect(r1.stdout).include('help') + const r2 = await execa('npx', ['esno', cliPath, '-h', entryPath], { reject: true }) + expect(r2.stdout).include('help') +}, 60_000) + +it('--version', async () => { + const r1 = await execa('npx', ['esno', cliPath, '--version', entryPath], { reject: true }) + expect(r1.stdout).include('vite-node/') + const r2 = await execa('npx', ['esno', cliPath, '-v', entryPath], { reject: true }) + expect(r2.stdout).include('vite-node/') +}, 60_000) + +it('script args', async () => { + const r1 = await execa('npx', ['esno', cliPath, entryPath, '--version', '--help'], { reject: true }) + expect(parseResult(r1.stdout)).include('--version').include('--help') +}, 60_000) + +it('script args in -- after', async () => { + const r1 = await execa('npx', ['esno', cliPath, entryPath, '--', '--version', '--help'], { reject: true }) + expect(parseResult(r1.stdout)).include('--version').include('--help') +}, 60_000)