Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow readonly array as parameter to .aliases(), .parse(), .parseAsync() #1669

Merged
merged 2 commits into from Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions tests/command.alias.test.js
Expand Up @@ -96,3 +96,29 @@ test('when set alias on executable then can get alias', () => {
.alias(alias);
expect(program.commands[0].alias()).toEqual(alias);
});

describe('aliases parameter is treated as readonly, per TypeScript declaration', () => {
test('when aliases called then parameter does not change', () => {
// Unlikely this could break, but check the API we are declaring in TypeScript.
const original = ['b', 'bld'];
const param = original.slice();
new commander.Command('build').aliases(param);
expect(param).toEqual(original);
});

test('when aliases called and aliases later changed then parameter does not change', () => {
const original = ['b', 'bld'];
const param = original.slice();
const cmd = new commander.Command('build').aliases(param);
cmd.alias('BBB');
expect(param).toEqual(original);
});

test('when aliases called and parameter later changed then aliases does not change', () => {
const original = ['b', 'bld'];
const param = original.slice();
const cmd = new commander.Command('build').aliases(param);
param.length = 0;
expect(cmd.aliases()).toEqual(original);
});
});
68 changes: 68 additions & 0 deletions tests/command.parse.test.js
Expand Up @@ -96,3 +96,71 @@ test('when parse strings instead of array then throw', () => {
program.parse('node', 'test');
}).toThrow();
});

describe('parse parameter is treated as readonly, per TypeScript declaration', () => {
test('when parse called then parameter does not change', () => {
const program = new commander.Command();
program.option('--debug');
const original = ['node', '--debug', 'arg'];
const param = original.slice();
program.parse(param);
expect(param).toEqual(original);
});

test('when parse called and parsed args later changed then parameter does not change', () => {
const program = new commander.Command();
program.option('--debug');
const original = ['node', '--debug', 'arg'];
const param = original.slice();
program.parse(param);
program.args.length = 0;
program.rawArgs.length = 0;
expect(param).toEqual(original);
});

test('when parse called and param later changed then parsed args do not change', () => {
const program = new commander.Command();
program.option('--debug');
const param = ['node', '--debug', 'arg'];
program.parse(param);
const oldArgs = program.args.slice();
const oldRawArgs = program.rawArgs.slice();
param.length = 0;
expect(program.args).toEqual(oldArgs);
expect(program.rawArgs).toEqual(oldRawArgs);
});
});

describe('parseAsync parameter is treated as readonly, per TypeScript declaration', () => {
test('when parse called then parameter does not change', async() => {
const program = new commander.Command();
program.option('--debug');
const original = ['node', '--debug', 'arg'];
const param = original.slice();
await program.parseAsync(param);
expect(param).toEqual(original);
});

test('when parseAsync called and parsed args later changed then parameter does not change', async() => {
const program = new commander.Command();
program.option('--debug');
const original = ['node', '--debug', 'arg'];
const param = original.slice();
await program.parseAsync(param);
program.args.length = 0;
program.rawArgs.length = 0;
expect(param).toEqual(original);
});

test('when parseAsync called and param later changed then parsed args do not change', async() => {
const program = new commander.Command();
program.option('--debug');
const param = ['node', '--debug', 'arg'];
await program.parseAsync(param);
const oldArgs = program.args.slice();
const oldRawArgs = program.rawArgs.slice();
param.length = 0;
expect(program.args).toEqual(oldArgs);
expect(program.rawArgs).toEqual(oldRawArgs);
});
});
6 changes: 3 additions & 3 deletions typings/index.d.ts
Expand Up @@ -626,7 +626,7 @@ export class Command {
*
* @returns `this` command for chaining
*/
parse(argv?: string[], options?: ParseOptions): this;
parse(argv?: readonly string[], options?: ParseOptions): this;

/**
* Parse `argv`, setting options and invoking commands when defined.
Expand All @@ -645,7 +645,7 @@ export class Command {
*
* @returns Promise
*/
parseAsync(argv?: string[], options?: ParseOptions): Promise<this>;
parseAsync(argv?: readonly string[], options?: ParseOptions): Promise<this>;

/**
* Parse options from `argv` removing known options,
Expand Down Expand Up @@ -698,7 +698,7 @@ export class Command {
*
* @returns `this` command for chaining
*/
aliases(aliases: string[]): this;
aliases(aliases: readonly string[]): this;
/**
* Get aliases for the command.
*/
Expand Down
3 changes: 3 additions & 0 deletions typings/index.test-d.ts
Expand Up @@ -187,13 +187,15 @@ expectType<commander.Command>(program.parse(process.argv));
expectType<commander.Command>(program.parse(['node', 'script.js'], { from: 'node' }));
expectType<commander.Command>(program.parse(['node', 'script.js'], { from: 'electron' }));
expectType<commander.Command>(program.parse(['--option'], { from: 'user' }));
expectType<commander.Command>(program.parse(['node', 'script.js'] as const));

// parseAsync, same tests as parse
expectType<Promise<commander.Command>>(program.parseAsync());
expectType<Promise<commander.Command>>(program.parseAsync(process.argv));
expectType<Promise<commander.Command>>(program.parseAsync(['node', 'script.js'], { from: 'node' }));
expectType<Promise<commander.Command>>(program.parseAsync(['node', 'script.js'], { from: 'electron' }));
expectType<Promise<commander.Command>>(program.parseAsync(['--option'], { from: 'user' }));
expectType<Promise<commander.Command>>(program.parseAsync(['node', 'script.js'] as const));

// parseOptions (and ParseOptionsResult)
expectType<{operands: string[]; unknown: string[]}>(program.parseOptions(['node', 'script.js', 'hello']));
Expand Down Expand Up @@ -224,6 +226,7 @@ expectType<string>(program.alias());

// aliases
expectType<commander.Command>(program.aliases(['first-alias', 'second-alias']));
expectType<commander.Command>(program.aliases(['first-alias', 'second-alias'] as const));
expectType<string[]>(program.aliases());

// usage
Expand Down