From f1036dfdf975abda6a87cb210b86fbd8a3429a48 Mon Sep 17 00:00:00 2001 From: Dimitri Benin Date: Tue, 19 Mar 2019 05:04:52 +0000 Subject: [PATCH] Add TypeScript definition (#116) --- index.d.ts | 198 ++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 5 +- index.test-d.ts | 47 ++++++++++++ package.json | 20 +++-- readme.md | 2 +- 5 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 index.d.ts create mode 100644 index.test-d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..43c6a93 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,198 @@ +import {PackageJson} from 'type-fest'; +import {Options as MinimistOptions} from 'minimist-options'; + +export interface Options { + /** + Define argument flags. + + The key is the flag name and the value is an object with any of: + + - `type`: Type of value. (Possible values: `string` `boolean`) + - `alias`: Usually used to define a short flag alias. + - `default`: Default value when the flag is not specified. + + @example + ``` + flags: { + unicorn: { + type: 'string', + alias: 'u', + default: 'rainbow' + } + } + ``` + */ + readonly flags?: MinimistOptions; + + /** + 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. + + Set it to `false` to disable it altogether. + */ + readonly version?: string | false; + + /** + 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. + */ + 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. + */ + readonly autoVersion?: boolean; + + /** + package.json as an `Object`. Default: Closest package.json upwards. + + _You most likely don't need this option._ + */ + readonly pkg?: {[key: string]: unknown}; + + /** + Custom arguments object. + + @default process.argv.slice(2) + */ + readonly argv?: ReadonlyArray; + + /** + 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`. + + __Caution: Explicitly specifying undefined for `booleanDefault` has different meaning from omitting key itself.__ + + @example + ``` + const cli = meow(` + Usage + $ foo + + Options + --rainbow, -r Include a rainbow + --unicorn, -u Include a unicorn + --no-sparkles Exclude sparkles + + Examples + $ foo + 🌈 unicorns✨🌈 + `, { + booleanDefault: undefined, + flags: { + rainbow: { + type: 'boolean', + default: true, + alias: 'r' + }, + unicorn: { + type: 'boolean', + default: false, + alias: 'u' + }, + cake: { + type: 'boolean', + alias: '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 | null | undefined; + + /** + 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. + + @default true + */ + readonly hardRejection?: boolean; +} + +export interface Result { + /** + Non-flag arguments. + */ + input: string[]; + + /** + Flags converted to camelCase excluding aliases. + */ + flags: {[name: string]: unknown}; + + /** + Flags converted camelCase including aliases. + */ + unnormalizedFlags: {[name: string]: unknown}; + + /** + 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): void; + + /** + Show the version text and exit. + */ + showVersion(): void; +} + +/** +@param helpMessage - Shortcut for the `help` option. +*/ +export default function meow(helpMessage: string, options?: Options): Result; +export default function meow(options?: Options): Result; diff --git a/index.js b/index.js index 8db102e..1130ee5 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ const normalizePackageData = require('normalize-package-data'); delete require.cache[__filename]; const parentDir = path.dirname(module.parent.filename); -module.exports = (helpText, options) => { +const meow = (helpText, options) => { if (typeof helpText !== 'string') { options = helpText; helpText = ''; @@ -126,3 +126,6 @@ module.exports = (helpText, options) => { showVersion }; }; + +module.exports = meow; +module.exports.default = meow; diff --git a/index.test-d.ts b/index.test-d.ts new file mode 100644 index 0000000..b939a60 --- /dev/null +++ b/index.test-d.ts @@ -0,0 +1,47 @@ +import {expectType} from 'tsd-check'; +import {PackageJson} from 'type-fest'; +import meow, {Result} from '.'; + +expectType(meow('Help text')); +expectType(meow('Help text', {hardRejection: false})); +expectType( + meow({ + flags: { + unicorn: { + type: 'boolean', + alias: 'u' + }, + fooBar: { + type: 'string', + default: 'foo' + } + } + }) +); +expectType(meow({description: 'foo'})); +expectType(meow({description: false})); +expectType(meow({help: 'foo'})); +expectType(meow({help: false})); +expectType(meow({version: 'foo'})); +expectType(meow({version: false})); +expectType(meow({autoHelp: false})); +expectType(meow({autoVersion: false})); +expectType(meow({pkg: {foo: 'bar'}})); +expectType(meow({argv: ['foo', 'bar']})); +expectType(meow({inferType: true})); +expectType(meow({booleanDefault: true})); +expectType(meow({booleanDefault: null})); +expectType(meow({booleanDefault: undefined})); +expectType(meow({hardRejection: false})); + +const result = meow('Help text'); + +expectType(result.input); +expectType<{[name: string]: unknown}>(result.flags); +expectType<{[name: string]: unknown}>(result.unnormalizedFlags); +expectType(result.pkg); +expectType(result.help); + +result.showHelp(); +result.showHelp(1); +result.showVersion(); diff --git a/package.json b/package.json index 9e32c7b..5ebfcdc 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,11 @@ "node": ">=8" }, "scripts": { - "test": "xo && ava" + "test": "xo && ava && tsd-check" }, "files": [ - "index.js" + "index.js", + "index.d.ts" ], "keywords": [ "cli", @@ -38,21 +39,24 @@ "console" ], "dependencies": { + "@types/minimist": "^1.2.0", "camelcase-keys": "^5.0.0", - "decamelize-keys": "^1.0.0", + "decamelize-keys": "^1.1.0", "hard-rejection": "^1.0.0", - "minimist-options": "^3.0.1", - "normalize-package-data": "^2.3.4", + "minimist-options": "^4.0.1", + "normalize-package-data": "^2.5.0", "read-pkg-up": "^4.0.0", "redent": "^2.0.0", "trim-newlines": "^2.0.0", + "type-fest": "^0.2.0", "yargs-parser": "^11.0.0" }, "devDependencies": { - "ava": "^0.25.0", + "ava": "^1.3.1", "execa": "^1.0.0", - "indent-string": "^3.0.0", - "xo": "^0.23.0" + "indent-string": "^3.2.0", + "tsd-check": "^0.3.0", + "xo": "^0.24.0" }, "xo": { "rules": { diff --git a/readme.md b/readme.md index a0725a5..246bf78 100644 --- a/readme.md +++ b/readme.md @@ -77,7 +77,7 @@ Returns an `Object` with: - `unnormalizedFlags` *(Object)* - Flags converted camelCase including aliases - `pkg` *(Object)* - The `package.json` object - `help` *(string)* - The help text used with `--help` -- `showHelp([code=2])` *(Function)* - Show the help text and exit with `code` +- `showHelp([exitCode=2])` *(Function)* - Show the help text and exit with `exitCode` - `showVersion()` *(Function)* - Show the version text and exit #### helpText