diff --git a/packages/rstack/src/cli/commands.ts b/packages/rstack/src/cli/commands.ts index 28b4406..fb3155f 100644 --- a/packages/rstack/src/cli/commands.ts +++ b/packages/rstack/src/cli/commands.ts @@ -1,7 +1,7 @@ import { join } from 'node:path'; import { getConfigState } from '../config.ts'; import { insertConfigArg, parseArgs, parseCliArgs } from './args.ts'; -import { renderHelp } from './help.ts'; +import { hasHelpFlag, renderHelp } from './help.ts'; const renderRootHelp = (): string => renderHelp({ @@ -54,7 +54,77 @@ const renderCheckHelp = (): string => ], }); +const renderDevHelp = (): string => + renderHelp({ + usage: 'rs dev [options]', + description: 'Run the app dev server', + sections: [ + { + title: 'Options', + items: [ + ['-o, --open [url]', 'Open the page in browser on startup'], + ['--port ', 'Set the port number for the server'], + ['--strict-port', 'Exit if the specified port is already in use'], + ['--host [host]', 'Set the host that the server listens to'], + ['-c, --config ', 'Specify Rstack config file path'], + ['-h, --help', 'Display this help message'], + ], + }, + ], + }); + +const renderBuildHelp = (): string => + renderHelp({ + usage: 'rs build [options]', + description: 'Build the app for production', + sections: [ + { + title: 'Options', + items: [ + ['-w, --watch', 'Enable watch mode to automatically rebuild on file changes'], + ['--dist-path ', 'Set the root directory of output files'], + ['--source-map', 'Enable source map'], + ['-c, --config ', 'Specify Rstack config file path'], + ['-h, --help', 'Display this help message'], + ], + }, + ], + }); + +const renderPreviewHelp = (): string => + renderHelp({ + usage: 'rs preview [options]', + description: 'Preview the app production build', + sections: [ + { + title: 'Options', + items: [ + ['-o, --open [url]', 'Open the page in browser on startup'], + ['--port ', 'Set the port number for the server'], + ['--strict-port', 'Exit if the specified port is already in use'], + ['--host [host]', 'Set the host that the server listens to'], + ['-c, --config ', 'Specify Rstack config file path'], + ['-h, --help', 'Display this help message'], + ], + }, + ], + }); + async function runRsbuildCLI(args: string[]): Promise { + if (hasHelpFlag(args)) { + switch (args[0]) { + case 'dev': + console.log(renderDevHelp()); + return; + case 'build': + console.log(renderBuildHelp()); + return; + case 'preview': + console.log(renderPreviewHelp()); + return; + } + } + const argv = [ process.execPath, 'rsbuild', diff --git a/packages/rstack/src/cli/help.ts b/packages/rstack/src/cli/help.ts index 42ee9db..1936ecf 100644 --- a/packages/rstack/src/cli/help.ts +++ b/packages/rstack/src/cli/help.ts @@ -22,6 +22,13 @@ export type HelpDefinition = { sections?: readonly HelpSection[]; }; +export const hasHelpFlag = (args: readonly string[]): boolean => { + const end = args.indexOf('--'); + const flags = end === -1 ? args : args.slice(0, end); + + return flags.some((flag) => flag === '-h' || flag === '--help'); +}; + const renderItems = (items: readonly HelpItem[]): string => { const labelWidth = items.reduce((width, [label]) => Math.max(width, label.length), 0); diff --git a/packages/rstack/tests/cli/__snapshots__/help.test.ts.snap b/packages/rstack/tests/cli/__snapshots__/help.test.ts.snap index 16becaf..53d4820 100644 --- a/packages/rstack/tests/cli/__snapshots__/help.test.ts.snap +++ b/packages/rstack/tests/cli/__snapshots__/help.test.ts.snap @@ -1,5 +1,58 @@ // Rstest Snapshot v1 +exports[`displays build help 1`] = ` +"Rstack v + +Usage: + $ rs build [options] + +Build the app for production + +Options: + -w, --watch Enable watch mode to automatically rebuild on file changes + --dist-path Set the root directory of output files + --source-map Enable source map + -c, --config Specify Rstack config file path + -h, --help Display this help message +" +`; + +exports[`displays dev help 1`] = ` +"Rstack v + +Usage: + $ rs dev [options] + +Run the app dev server + +Options: + -o, --open [url] Open the page in browser on startup + --port Set the port number for the server + --strict-port Exit if the specified port is already in use + --host [host] Set the host that the server listens to + -c, --config Specify Rstack config file path + -h, --help Display this help message +" +`; + +exports[`displays preview help 1`] = ` +"Rstack v + +Usage: + $ rs preview [options] + +Preview the app production build + +Options: + -o, --open [url] Open the page in browser on startup + --port Set the port number for the server + --strict-port Exit if the specified port is already in use + --host [host] Set the host that the server listens to + -c, --config Specify Rstack config file path + -h, --help Display this help message +" +`; + exports[`displays top-level help 1`] = ` "Rstack v diff --git a/packages/rstack/tests/cli/help.test.ts b/packages/rstack/tests/cli/help.test.ts index 92bc7c3..2d399cd 100644 --- a/packages/rstack/tests/cli/help.test.ts +++ b/packages/rstack/tests/cli/help.test.ts @@ -1,5 +1,22 @@ import { normalizeHelpOutput, test } from '#test-helpers'; +import { hasHelpFlag } from '../../src/cli/help.ts'; + +test('detects help flags before the option terminator', ({ expect }) => { + expect(hasHelpFlag(['dev', '-h'])).toBe(true); + expect(hasHelpFlag(['dev', '--help'])).toBe(true); + expect(hasHelpFlag(['dev', '--', '--help'])).toBe(false); + expect(hasHelpFlag(['dev'])).toBe(false); +}); test('displays top-level help', ({ execCli, expect }) => { expect(normalizeHelpOutput(execCli('--help'))).toMatchSnapshot(); }); + +for (const command of ['dev', 'build', 'preview']) { + test(`displays ${command} help`, ({ execCli, expect }) => { + const output = execCli(`${command} --help`); + + expect(execCli(`${command} -h`)).toBe(output); + expect(normalizeHelpOutput(output)).toMatchSnapshot(); + }); +}