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

Add TypeScript definition #116

Merged
merged 3 commits into from Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
195 changes: 195 additions & 0 deletions index.d.ts
@@ -0,0 +1,195 @@
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
BendingBender marked this conversation as resolved.
Show resolved Hide resolved
*
* 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.
*/
BendingBender marked this conversation as resolved.
Show resolved Hide resolved
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)
*/
BendingBender marked this conversation as resolved.
Show resolved Hide resolved
readonly argv?: ReadonlyArray<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`.
*
* **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;
BendingBender marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What your opinion on {[name: string]: unknown}; vs Record<string, unknown>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think {[name: string]: unknown}; is more common, so I'd prefer this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it allows naming the key.


/**
* Flags converted camelCase including aliases.
*/
unnormalizedFlags: {[name: string]: unknown};

/**
* The `package.json` object.
*/
pkg: {[key: string]: unknown};
BendingBender marked this conversation as resolved.
Show resolved Hide resolved

/**
* The help text used with `--help`.
*/
help: string;

/**
* Show the help text and exit with code.
*
* @param code The exit code to use. Default: `2`.
*/
showHelp(code?: number): void;
BendingBender marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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;
5 changes: 4 additions & 1 deletion index.js
Expand Up @@ -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 = '';
Expand Down Expand Up @@ -126,3 +126,6 @@ module.exports = (helpText, options) => {
showVersion
};
};

module.exports = meow;
module.exports.default = meow;
46 changes: 46 additions & 0 deletions index.test-d.ts
@@ -0,0 +1,46 @@
import {expectType} from 'tsd-check';
import meow, {Result} from '.';

expectType<Result>(meow('Help text'));
expectType<Result>(meow('Help text', {hardRejection: false}));
expectType<Result>(
meow({
flags: {
unicorn: {
type: 'boolean',
alias: 'u'
},
fooBar: {
type: 'string',
default: 'foo'
}
}
})
);
expectType<Result>(meow({description: 'foo'}));
expectType<Result>(meow({description: false}));
expectType<Result>(meow({help: 'foo'}));
expectType<Result>(meow({help: false}));
expectType<Result>(meow({version: 'foo'}));
expectType<Result>(meow({version: false}));
expectType<Result>(meow({autoHelp: false}));
expectType<Result>(meow({autoVersion: false}));
expectType<Result>(meow({pkg: {foo: 'bar'}}));
expectType<Result>(meow({argv: ['foo', 'bar']}));
expectType<Result>(meow({inferType: true}));
expectType<Result>(meow({booleanDefault: true}));
expectType<Result>(meow({booleanDefault: null}));
expectType<Result>(meow({booleanDefault: undefined}));
expectType<Result>(meow({hardRejection: false}));

const result = meow('Help text');

expectType<string[]>(result.input);
expectType<{[name: string]: unknown}>(result.flags);
expectType<{[name: string]: unknown}>(result.unnormalizedFlags);
expectType<{[name: string]: unknown}>(result.pkg);
expectType<string>(result.help);

result.showHelp();
result.showHelp(1);
result.showVersion();
13 changes: 8 additions & 5 deletions package.json
Expand Up @@ -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",
Expand All @@ -38,21 +39,23 @@
"console"
],
"dependencies": {
"@types/minimist": "^1.2.0",
"camelcase-keys": "^5.0.0",
"decamelize-keys": "^1.0.0",
"hard-rejection": "^1.0.0",
"minimist-options": "^3.0.1",
"minimist-options": "^4.0.1",
"normalize-package-data": "^2.3.4",
"read-pkg-up": "^4.0.0",
"redent": "^2.0.0",
"trim-newlines": "^2.0.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"
"tsd-check": "^0.3.0",
"xo": "^0.24.0"
},
"xo": {
"rules": {
Expand Down