From 901b9fc666656c75cbe1654fbc7ed9c0b048b93b Mon Sep 17 00:00:00 2001 From: Tommy Date: Mon, 20 Mar 2023 01:20:55 -0500 Subject: [PATCH] Add `aliases` option (#226) --- index.d.ts | 5 +++- index.js | 15 ++++++++++++ index.test-d.ts | 4 +++- readme.md | 4 +++- test/test.js | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 2f7574b..b9ba23c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -21,6 +21,7 @@ export type Flag = { readonly default?: Default; readonly isRequired?: boolean | IsRequiredPredicate; readonly isMultiple?: IsMultiple; + readonly aliases?: string[]; }; type StringFlag = Flag<'string', string> | Flag<'string', string[], true>; @@ -47,6 +48,7 @@ export type Options = { If it's only known at runtime whether the flag is required or not you can pass a Function instead of a boolean, which based on the given flags and other non-flag arguments should decide if the flag is required. - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values are *not* supported. + - `aliases`: Other names for the flag. Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`). @@ -64,7 +66,8 @@ export type Options = { } return false; - } + }, + aliases: ['unicorns'] } } ``` diff --git a/index.js b/index.js index 6d23ce4..2b805e3 100644 --- a/index.js +++ b/index.js @@ -97,6 +97,15 @@ const buildParserFlags = ({flags, booleanDefault}) => { delete flag.isMultiple; } + if (Array.isArray(flag.aliases)) { + if (flag.alias) { + flag.aliases.push(flag.alias); + } + + flag.alias = flag.aliases; + delete flag.aliases; + } + parserFlags[flagKey] = flag; } @@ -235,6 +244,12 @@ const meow = (helpText, options = {}) => { validateFlags(flags, options); for (const flagValue of Object.values(options.flags)) { + if (Array.isArray(flagValue.aliases)) { + for (const alias of flagValue.aliases) { + delete flags[alias]; + } + } + delete flags[flagValue.shortFlag]; } diff --git a/index.test-d.ts b/index.test-d.ts index 69d7968..8e26884 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -53,7 +53,7 @@ const result = meow('Help text', { importMeta, flags: { foo: {type: 'boolean', shortFlag: 'f'}, - 'foo-bar': {type: 'number'}, + 'foo-bar': {type: 'number', aliases: ['foobar', 'fooBar']}, bar: {type: 'string', default: ''}, abc: {type: 'string', isMultiple: true}, }, @@ -70,6 +70,8 @@ expectType(result.flags.abc); expectType(result.unnormalizedFlags.foo); expectType(result.unnormalizedFlags.f); expectType(result.unnormalizedFlags['foo-bar']); +expectType(result.unnormalizedFlags.foobar); +expectType(result.unnormalizedFlags.fooBar); expectType(result.unnormalizedFlags.bar); expectType(result.unnormalizedFlags.abc); diff --git a/readme.md b/readme.md index 748929b..a3a5c15 100644 --- a/readme.md +++ b/readme.md @@ -112,6 +112,7 @@ The key is the flag name in camel-case and the value is an object with any of: - The function should return a `boolean`, true if the flag is required, otherwise false. - `isMultiple`: Indicates a flag can be set multiple times. Values are turned into an array. (Default: false) - Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values are [currently *not* supported](https://github.com/sindresorhus/meow/issues/164). +- `aliases`: Other names for the flag. Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`). @@ -130,7 +131,8 @@ flags: { } return false; - } + }, + aliases: ['unicorns'] } } ``` diff --git a/test/test.js b/test/test.js index c21308e..38ab8ba 100644 --- a/test/test.js +++ b/test/test.js @@ -602,6 +602,69 @@ test('suggests renaming alias to shortFlag', t => { }, {message: 'The option `alias` has been renamed to `shortFlag`. The following flags need to be updated: `foo`, `bar`'}); }); +test('aliases - accepts one', t => { + t.deepEqual(meow({ + importMeta, + argv: ['--foo=baz'], + flags: { + fooBar: { + type: 'string', + aliases: ['foo'], + }, + }, + }).flags, { + fooBar: 'baz', + }); +}); + +test('aliases - accepts multiple', t => { + t.deepEqual(meow({ + importMeta, + argv: ['--foo=baz1', '--bar=baz2'], + flags: { + fooBar: { + type: 'string', + aliases: ['foo', 'bar'], + isMultiple: true, + }, + }, + }).flags, { + fooBar: ['baz1', 'baz2'], + }); +}); + +test('aliases - can be a short flag', t => { + t.deepEqual(meow({ + importMeta, + argv: ['--f=baz'], + flags: { + fooBar: { + type: 'string', + aliases: ['f'], + }, + }, + }).flags, { + fooBar: 'baz', + }); +}); + +test('aliases - works with short flag', t => { + t.deepEqual(meow({ + importMeta, + argv: ['--foo=baz1', '--bar=baz2', '-f=baz3'], + flags: { + fooBar: { + type: 'string', + shortFlag: 'f', + aliases: ['foo', 'bar'], + isMultiple: true, + }, + }, + }).flags, { + fooBar: ['baz1', 'baz2', 'baz3'], + }); +}); + if (NODE_MAJOR_VERSION >= 14) { test('supports es modules', async t => { try {