diff --git a/source/index.d.ts b/source/index.d.ts deleted file mode 100644 index 245dc74..0000000 --- a/source/index.d.ts +++ /dev/null @@ -1,380 +0,0 @@ -import type {CamelCasedProperties, PackageJson} from 'type-fest'; - -export type FlagType = 'string' | 'boolean' | 'number'; - -type ParsedFlag = string | boolean | number; -export type ParsedFlags = Readonly>; - -/** -Callback function to determine if a flag is required during runtime. - -@param flags - Contains the flags converted to camel-case excluding aliases. -@param input - Contains the non-flag arguments. - -@returns True if the flag is required, otherwise false. -*/ -export type IsRequiredPredicate = (flags: ParsedFlags, input: readonly string[]) => boolean; - -export type Flag = { - /** - Type of value. (Possible values: `string` `boolean` `number`) - */ - readonly type?: PrimitiveType; - - /** - Limit valid values to a predefined set of choices. - - @example - ``` - unicorn: { - isMultiple: true, - choices: ['rainbow', 'cat', 'unicorn'] - } - ``` - */ - readonly choices?: Type extends unknown[] ? Type : Type[]; - - /** - Default value when the flag is not specified. - - @example - ``` - unicorn: { - type: 'boolean', - default: true - } - ``` - */ - readonly default?: Type; - - /** - A short flag alias. - - @example - ``` - unicorn: { - shortFlag: 'u' - } - ``` - */ - readonly shortFlag?: string; - - /** - Other names for the flag. - - @example - ``` - unicorn: { - aliases: ['unicorns', 'uni'] - } - ``` - */ - readonly aliases?: string[]; - - /** - Indicates a flag can be set multiple times. Values are turned into an array. - - Multiple values are provided by specifying the flag multiple times, for example, `$ foo -u rainbow -u cat`. Space- or comma-separated values [currently *not* supported](https://github.com/sindresorhus/meow/issues/164). - - @default false - */ - readonly isMultiple?: IsMultiple; - - /** - Determine if the flag is required. - - 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. - - - The first argument is the **flags** object, which contains the flags converted to camel-case excluding aliases. - - The second argument is the **input** string array, which contains the non-flag arguments. - - The function should return a `boolean`, true if the flag is required, otherwise false. - - @default false - - @example - ``` - isRequired: (flags, input) => { - if (flags.otherFlag) { - return true; - } - - return false; - } - ``` - */ - readonly isRequired?: boolean | IsRequiredPredicate; -}; - -type StringFlag = Flag<'string', string> | Flag<'string', string[], true>; -type BooleanFlag = Flag<'boolean', boolean> | Flag<'boolean', boolean[], true>; -type NumberFlag = Flag<'number', number> | Flag<'number', number[], true>; -export type AnyFlag = StringFlag | BooleanFlag | NumberFlag; -export type AnyFlags = Record; - -export type Options = { - /** - Pass in [`import.meta`](https://nodejs.org/dist/latest/docs/api/esm.html#esm_import_meta). This is used to find the correct package.json file. - */ - readonly importMeta: ImportMeta; - - /** - Define argument flags. - - The key is the flag name in camel-case and the value is an object with any of: - - - `type`: Type of value. (Possible values: `string` `boolean` `number`) - - `choices`: Limit valid values to a predefined set of choices. - - `default`: Default value when the flag is not specified. - - `shortFlag`: A short flag alias. - - `aliases`: Other names for the flag. - - `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 [currently *not* supported](https://github.com/sindresorhus/meow/issues/164). - - `isRequired`: Determine if the flag is required. (Default: false) - - 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. Two arguments are passed to the function: - - The first argument is the **flags** object, which contains the flags converted to camel-case excluding aliases. - - The second argument is the **input** string array, which contains the non-flag arguments. - - The function should return a `boolean`, true if the flag is required, otherwise false. - - Note that flags are always defined using a camel-case key (`myKey`), but will match arguments in kebab-case (`--my-key`). - - @example - ``` - flags: { - unicorn: { - type: 'string', - choices: ['rainbow', 'cat', 'unicorn'], - default: ['rainbow', 'cat'], - shortFlag: 'u', - aliases: ['unicorns'] - isMultiple: true, - isRequired: (flags, input) => { - if (flags.otherFlag) { - return true; - } - - return false; - } - } - } - ``` - */ - readonly flags?: Flags; // & Pick - - /** - Description to show above the help text. Default: The package.json `"description"` property. - - Set it to `false` to disable it altogether. - */ - readonly description?: string | false; - - /** - The help text you want shown. - - The input is reindented and starting/ending newlines are trimmed which means you can use a [template literal](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings) without having to care about using the correct amount of indent. - - The description will be shown above your help text automatically. - - Set it to `false` to disable it altogether. - */ - readonly help?: string | false; - - /** - Set a custom version output. Default: The package.json `"version"` property. - */ - readonly version?: string; - - /** - Automatically show the help text when the `--help` flag is present. Useful to set this value to `false` when a CLI manages child CLIs with their own help text. - - This option is only considered when there is only one argument in `process.argv`. - */ - readonly autoHelp?: boolean; - - /** - Automatically show the version text when the `--version` flag is present. Useful to set this value to `false` when a CLI manages child CLIs with their own version text. - - This option is only considered when there is only one argument in `process.argv`. - */ - readonly autoVersion?: boolean; - - /** - `package.json` as an `Object`. Default: Closest `package.json` upwards. - - Note: Setting this stops `meow` from finding a package.json. - - _You most likely don't need this option._ - */ - readonly pkg?: PackageJson; - - /** - Custom arguments object. - - @default process.argv.slice(2) - */ - readonly argv?: readonly string[]; - - /** - Infer the argument type. - - By default, the argument `5` in `$ foo 5` becomes a string. Enabling this would infer it as a number. - - @default false - */ - readonly inferType?: boolean; - - /** - Value of `boolean` flags not defined in `argv`. - - If set to `undefined`, the flags not defined in `argv` will be excluded from the result. The `default` value set in `boolean` flags take precedence over `booleanDefault`. - - _Note: If used in conjunction with `isMultiple`, the default flag value is set to `[]`._ - - __Caution: Explicitly specifying `undefined` for `booleanDefault` has different meaning from omitting key itself.__ - - @default false - - @example - ``` - import meow from 'meow'; - - const cli = meow(` - Usage - $ foo - - Options - --rainbow, -r Include a rainbow - --unicorn, -u Include a unicorn - --no-sparkles Exclude sparkles - - Examples - $ foo - 🌈 unicorns✨🌈 - `, { - importMeta: import.meta, - booleanDefault: undefined, - flags: { - rainbow: { - type: 'boolean', - default: true, - shortFlag: 'r' - }, - unicorn: { - type: 'boolean', - default: false, - shortFlag: 'u' - }, - cake: { - type: 'boolean', - shortFlag: 'c' - }, - sparkles: { - type: 'boolean', - default: true - } - } - }); - - //{ - // flags: { - // rainbow: true, - // unicorn: false, - // sparkles: true - // }, - // unnormalizedFlags: { - // rainbow: true, - // r: true, - // unicorn: false, - // u: false, - // sparkles: true - // }, - // … - //} - ``` - */ - readonly booleanDefault?: boolean; - - // TODO: Remove this in meow 14. - /** - Whether to use [hard-rejection](https://github.com/sindresorhus/hard-rejection) or not. Disabling this can be useful if you need to handle `process.on('unhandledRejection')` yourself. - - @deprecated This is the default behavior since Node.js 16, so this option is moot. - @default true - */ - readonly hardRejection?: boolean; - - /** - Whether to allow unknown flags or not. - - @default true - */ - readonly allowUnknownFlags?: boolean; -}; - -type OptionsWithoutBooleanDefault = Omit, 'booleanDefault'>; -type BooleanDefault = Pick, 'booleanDefault'>; - -export type ParsedOptions = Required & BooleanDefault & { - input: string; - allowParentFlags: boolean; -}; - -type TypedFlag = - Flag extends {type: 'number'} - ? number - : Flag extends {type: 'string'} - ? string - : Flag extends {type: 'boolean'} - ? boolean - : unknown; - -type PossiblyOptionalFlag = - Flag extends {isRequired: true} - ? FlagType - : Flag extends {default: any} - ? FlagType - : FlagType | undefined; - -export type TypedFlags = { - [F in keyof Flags]: Flags[F] extends {isMultiple: true} - ? PossiblyOptionalFlag>> - : PossiblyOptionalFlag> -}; - -export type Result = { - /** - Non-flag arguments. - */ - input: string[]; - - /** - Flags converted to camelCase excluding aliases. - */ - flags: CamelCasedProperties> & Record; - - /** - Flags converted camelCase including aliases. - */ - unnormalizedFlags: TypedFlags & Record; - - /** - The `package.json` object. - */ - pkg: PackageJson; - - /** - The help text used with `--help`. - */ - help: string; - - /** - Show the help text and exit with code. - - @param exitCode - The exit code to use. Default: `2`. - */ - showHelp: (exitCode?: number) => never; - - /** - Show the version text and exit. - */ - showVersion: () => void; -}; diff --git a/test-d/build.test-d.ts b/test-d/build.test-d.ts deleted file mode 100644 index 29ec7de..0000000 --- a/test-d/build.test-d.ts +++ /dev/null @@ -1,132 +0,0 @@ -import {expectAssignable, expectError, expectType} from 'tsd'; -import type {PackageJson} from 'type-fest'; -import meow, {type Result} from '../build/index.js'; - -type AnyFlag = NonNullable[0]>['flags']>[string]; - -const importMeta = import.meta; - -expectType>(meow('Help text')); -expectType>(meow('Help text', {importMeta})); -expectAssignable<{flags: {foo: number}}>( - meow({importMeta: import.meta, flags: {foo: {type: 'number', isRequired: true}}}), -); -expectAssignable<{flags: {foo: string}}>( - meow({importMeta, flags: {foo: {type: 'string', isRequired: true}}}), -); -expectAssignable<{flags: {foo: boolean}}>( - meow({importMeta, flags: {foo: {type: 'boolean', isRequired: true}}}), -); -expectAssignable<{flags: {foo: number | undefined}}>( - meow({importMeta, flags: {foo: {type: 'number'}}}), -); -expectAssignable<{flags: {foo: string | undefined}}>( - meow({importMeta, flags: {foo: {type: 'string'}}}), -); -expectAssignable<{flags: {foo: boolean | undefined}}>( - meow({importMeta, flags: {foo: {type: 'boolean'}}}), -); -expectAssignable<{flags: {foo: number[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'number', isMultiple: true}}}), -); -expectAssignable<{flags: {foo: string[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'string', isMultiple: true}}}), -); -expectAssignable<{flags: {foo: boolean[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'boolean', isMultiple: true}}}), -); -expectType>(meow({importMeta, description: 'foo'})); -expectType>(meow({importMeta, description: false})); -expectType>(meow({importMeta, help: 'foo'})); -expectType>(meow({importMeta, help: false})); -expectType>(meow({importMeta, version: 'foo'})); -expectType>(meow({importMeta, version: false})); -expectType>(meow({importMeta, autoHelp: false})); -expectType>(meow({importMeta, autoVersion: false})); -expectType>(meow({importMeta, pkg: {foo: 'bar'}})); -expectType>(meow({importMeta, argv: ['foo', 'bar']})); -expectType>(meow({importMeta, inferType: true})); -expectType>(meow({importMeta, booleanDefault: true})); -expectType>(meow({importMeta, booleanDefault: null})); -expectType>(meow({importMeta, booleanDefault: undefined})); -expectType>(meow({importMeta})); - -const result = meow('Help text', { - importMeta, - flags: { - foo: {type: 'boolean', shortFlag: 'f'}, - 'foo-bar': {type: 'number', aliases: ['foobar', 'fooBar']}, - bar: {type: 'string', default: ''}, - abc: {type: 'string', isMultiple: true}, - baz: {type: 'string', choices: ['rainbow', 'cat', 'unicorn']}, - }, -}); - -expectType(result.input); -expectType(result.pkg); -expectType(result.help); - -expectType(result.flags.foo); -expectType(result.flags.fooBar); -expectType(result.flags.bar); -expectType(result.flags.abc); -expectType(result.flags.baz); -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); -expectType(result.unnormalizedFlags.baz); - -result.showHelp(); -result.showHelp(1); -result.showVersion(); - -const options = { - importMeta, - flags: { - rainbow: { - type: 'boolean', - shortFlag: 'r', - }, - }, -} as const; - -meow('', options); - -expectAssignable({type: 'string', default: 'cat'}); -expectAssignable({type: 'number', default: 42}); -expectAssignable({type: 'boolean', default: true}); - -expectAssignable({type: 'string', default: undefined}); -expectAssignable({type: 'number', default: undefined}); -expectAssignable({type: 'boolean', default: undefined}); - -expectAssignable({type: 'string', isMultiple: true, default: ['cat']}); -expectAssignable({type: 'number', isMultiple: true, default: [42]}); -expectAssignable({type: 'boolean', isMultiple: true, default: [false]}); - -expectError({type: 'string', isMultiple: true, default: 'cat'}); -expectError({type: 'number', isMultiple: true, default: 42}); -expectError({type: 'boolean', isMultiple: true, default: false}); - -expectAssignable({type: 'string', choices: ['cat', 'unicorn']}); -expectAssignable({type: 'number', choices: [1, 2]}); -expectAssignable({type: 'boolean', choices: [true, false]}); -expectAssignable({type: 'string', isMultiple: true, choices: ['cat']}); -expectAssignable({type: 'string', isMultiple: false, choices: ['cat']}); - -expectError({type: 'string', choices: 'cat'}); -expectError({type: 'number', choices: 1}); -expectError({type: 'boolean', choices: true}); - -expectError({type: 'string', choices: [1]}); -expectError({type: 'number', choices: ['cat']}); -expectError({type: 'boolean', choices: ['cat']}); - -expectAssignable({choices: ['cat']}); -expectAssignable({choices: [1]}); -expectAssignable({choices: [true]}); -expectError({choices: ['cat', 1, true]}); diff --git a/test-d/index.test-d.ts b/test-d/index.test-d.ts deleted file mode 100644 index 538d833..0000000 --- a/test-d/index.test-d.ts +++ /dev/null @@ -1,135 +0,0 @@ -import {expectAssignable, expectError, expectType} from 'tsd'; -import type {PackageJson} from 'type-fest'; -<<<<<<<< HEAD:test-d/index.ts -import type {Result, AnyFlag} from '../source/types.js'; -import meow from '../source/index.js'; -======== -import meow, {type Result} from '../source/index.js'; - -type AnyFlag = NonNullable[0]>['flags']>[string]; ->>>>>>>> main:test-d/index.test-d.ts - -const importMeta = import.meta; - -expectType>(meow('Help text')); -expectType>(meow('Help text', {importMeta, hardRejection: false})); -expectAssignable<{flags: {foo: number}}>( - meow({importMeta: import.meta, flags: {foo: {type: 'number', isRequired: true}}}), -); -expectAssignable<{flags: {foo: string}}>( - meow({importMeta, flags: {foo: {type: 'string', isRequired: true}}}), -); -expectAssignable<{flags: {foo: boolean}}>( - meow({importMeta, flags: {foo: {type: 'boolean', isRequired: true}}}), -); -expectAssignable<{flags: {foo: number | undefined}}>( - meow({importMeta, flags: {foo: {type: 'number'}}}), -); -expectAssignable<{flags: {foo: string | undefined}}>( - meow({importMeta, flags: {foo: {type: 'string'}}}), -); -expectAssignable<{flags: {foo: boolean | undefined}}>( - meow({importMeta, flags: {foo: {type: 'boolean'}}}), -); -expectAssignable<{flags: {foo: number[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'number', isMultiple: true}}}), -); -expectAssignable<{flags: {foo: string[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'string', isMultiple: true}}}), -); -expectAssignable<{flags: {foo: boolean[] | undefined}}>( - meow({importMeta, flags: {foo: {type: 'boolean', isMultiple: true}}}), -); -expectType>(meow({importMeta, description: 'foo'})); -expectType>(meow({importMeta, description: false})); -expectType>(meow({importMeta, help: 'foo'})); -expectType>(meow({importMeta, help: false})); -expectType>(meow({importMeta, version: 'foo'})); -expectType>(meow({importMeta, autoHelp: false})); -expectType>(meow({importMeta, autoVersion: false})); -expectType>(meow({importMeta, pkg: {foo: 'bar'}})); -expectType>(meow({importMeta, argv: ['foo', 'bar']})); -expectType>(meow({importMeta, inferType: true})); -expectType>(meow({importMeta, booleanDefault: true})); -expectType>(meow({importMeta, booleanDefault: undefined})); -expectType>(meow({importMeta, hardRejection: false})); - -const result = meow('Help text', { - importMeta, - flags: { - foo: {type: 'boolean', shortFlag: 'f'}, - 'foo-bar': {type: 'number', aliases: ['foobar', 'fooBar']}, - bar: {type: 'string', default: ''}, - abc: {type: 'string', isMultiple: true}, - baz: {type: 'string', choices: ['rainbow', 'cat', 'unicorn']}, - }, -}); - -expectType(result.input); -expectType(result.pkg); -expectType(result.help); - -expectType(result.flags.foo); -expectType(result.flags.fooBar); -expectType(result.flags.bar); -expectType(result.flags.abc); -expectType(result.flags.baz); -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); -expectType(result.unnormalizedFlags.baz); - -result.showHelp(); -result.showHelp(1); -result.showVersion(); - -const options = { - importMeta, - flags: { - rainbow: { - type: 'boolean', - shortFlag: 'r', - }, - }, -} as const; - -meow('', options); - -expectAssignable({type: 'string', default: 'cat'}); -expectAssignable({type: 'number', default: 42}); -expectAssignable({type: 'boolean', default: true}); - -expectAssignable({type: 'string', default: undefined}); -expectAssignable({type: 'number', default: undefined}); -expectAssignable({type: 'boolean', default: undefined}); - -expectAssignable({type: 'string', isMultiple: true, default: ['cat']}); -expectAssignable({type: 'number', isMultiple: true, default: [42]}); -expectAssignable({type: 'boolean', isMultiple: true, default: [false]}); - -expectError({type: 'string', isMultiple: true, default: 'cat'}); -expectError({type: 'number', isMultiple: true, default: 42}); -expectError({type: 'boolean', isMultiple: true, default: false}); - -expectAssignable({type: 'string', choices: ['cat', 'unicorn']}); -expectAssignable({type: 'number', choices: [1, 2]}); -expectAssignable({type: 'boolean', choices: [true, false]}); -expectAssignable({type: 'string', isMultiple: true, choices: ['cat']}); -expectAssignable({type: 'string', isMultiple: false, choices: ['cat']}); - -expectError({type: 'string', choices: 'cat'}); -expectError({type: 'number', choices: 1}); -expectError({type: 'boolean', choices: true}); - -expectError({type: 'string', choices: [1]}); -expectError({type: 'number', choices: ['cat']}); -expectError({type: 'boolean', choices: ['cat']}); - -expectAssignable({choices: ['cat']}); -expectAssignable({choices: [1]}); -expectAssignable({choices: [true]}); -expectError({choices: ['cat', 1, true]}); diff --git a/test-d/index.ts b/test-d/index.ts index 538d833..271d447 100644 --- a/test-d/index.ts +++ b/test-d/index.ts @@ -1,13 +1,7 @@ import {expectAssignable, expectError, expectType} from 'tsd'; import type {PackageJson} from 'type-fest'; -<<<<<<<< HEAD:test-d/index.ts import type {Result, AnyFlag} from '../source/types.js'; import meow from '../source/index.js'; -======== -import meow, {type Result} from '../source/index.js'; - -type AnyFlag = NonNullable[0]>['flags']>[string]; ->>>>>>>> main:test-d/index.test-d.ts const importMeta = import.meta;