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

Require Node.js 12 and move to ESM #181

Merged
merged 11 commits into from Apr 27, 2021
Merged
Show file tree
Hide file tree
Changes from 8 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
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Expand Up @@ -10,12 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
- 10
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
4 changes: 1 addition & 3 deletions estest/index.js
@@ -1,6 +1,4 @@
import {createRequire} from 'module';

const meow = createRequire(import.meta.url)('../index.js');
import meow from '../index.js';

meow(`
Usage
Expand Down
133 changes: 65 additions & 68 deletions index.d.ts
@@ -1,25 +1,24 @@
import {PackageJson} from 'type-fest';

declare namespace meow {
type FlagType = 'string' | 'boolean' | 'number';
export type FlagType = 'string' | 'boolean' | 'number';

/**
/**
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.
*/
LitoMore marked this conversation as resolved.
Show resolved Hide resolved
type IsRequiredPredicate = (flags: Readonly<AnyFlags>, input: readonly string[]) => boolean;

interface Flag<Type extends FlagType, Default> {
readonly type?: Type;
readonly alias?: string;
readonly default?: Default;
readonly isRequired?: boolean | IsRequiredPredicate;
readonly isMultiple?: boolean;
}
export type IsRequiredPredicate = (flags: Readonly<AnyFlags>, input: readonly string[]) => boolean;

export interface Flag<Type extends FlagType, Default> {
readonly type?: Type;
readonly alias?: string;
readonly default?: Default;
readonly isRequired?: boolean | IsRequiredPredicate;
readonly isMultiple?: boolean;
}

type StringFlag = Flag<'string', string>;
type BooleanFlag = Flag<'boolean', boolean>;
Expand All @@ -28,8 +27,8 @@ declare namespace meow {
type AnyFlag = StringFlag | BooleanFlag | NumberFlag;
type AnyFlags = Record<string, AnyFlag>;

interface Options<Flags extends AnyFlags> {
/**
export interface Options<Flags extends AnyFlags> {
/**
Define argument flags.

The key is the flag name in camel-case and the value is an object with any of:
Expand Down Expand Up @@ -63,16 +62,16 @@ declare namespace meow {
}
```
*/
LitoMore marked this conversation as resolved.
Show resolved Hide resolved
readonly flags?: Flags;
readonly flags?: Flags;

/**
/**
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;
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.
Expand All @@ -81,53 +80,53 @@ declare namespace meow {

Set it to `false` to disable it altogether.
*/
readonly help?: string | false;
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;
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.

This option is only considered when there is only one argument in `process.argv`.
*/
readonly autoHelp?: boolean;
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;
readonly autoVersion?: boolean;

/**
/**
`package.json` as an `Object`. Default: Closest `package.json` upwards.

_You most likely don't need this option._
*/
readonly pkg?: Record<string, unknown>;
readonly pkg?: Record<string, unknown>;

/**
/**
Custom arguments object.

@default process.argv.slice(2)
*/
readonly argv?: readonly string[];
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;
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`.
Expand All @@ -138,7 +137,7 @@ declare namespace meow {

@example
```
import meow = require('meow');
import meow from 'meow';

const cli = meow(`
Usage
Expand Down Expand Up @@ -193,24 +192,24 @@ declare namespace meow {
//}
```
*/
readonly booleanDefault?: boolean | null | undefined;
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;
readonly hardRejection?: boolean;

/**
/**
Whether to allow unknown flags or not.

@default true
*/
readonly allowUnknownFlags?: boolean;
}
readonly allowUnknownFlags?: boolean;
}

type TypedFlag<Flag extends AnyFlag> =
export type TypedFlag<Flag extends AnyFlag> =
Flag extends {type: 'number'}
? number
: Flag extends {type: 'string'}
Expand All @@ -219,67 +218,65 @@ declare namespace meow {
? boolean
: unknown;

type PossiblyOptionalFlag<Flag extends AnyFlag, FlagType> =
export type PossiblyOptionalFlag<Flag extends AnyFlag, FlagType> =
Flag extends {isRequired: true}
? FlagType
: Flag extends {default: any}
? FlagType
: FlagType | undefined;

type TypedFlags<Flags extends AnyFlags> = {
[F in keyof Flags]: Flags[F] extends {isMultiple: true}
? PossiblyOptionalFlag<Flags[F], Array<TypedFlag<Flags[F]>>>
: PossiblyOptionalFlag<Flags[F], TypedFlag<Flags[F]>>
};
export type TypedFlags<Flags extends AnyFlags> = {
[F in keyof Flags]: Flags[F] extends {isMultiple: true}
? PossiblyOptionalFlag<Flags[F], Array<TypedFlag<Flags[F]>>>
: PossiblyOptionalFlag<Flags[F], TypedFlag<Flags[F]>>
};

interface Result<Flags extends AnyFlags> {
/**
export interface Result<Flags extends AnyFlags> {
/**
Non-flag arguments.
*/
input: string[];
input: string[];

/**
/**
Flags converted to camelCase excluding aliases.
*/
flags: TypedFlags<Flags> & Record<string, unknown>;
flags: TypedFlags<Flags> & Record<string, unknown>;

/**
/**
Flags converted camelCase including aliases.
*/
unnormalizedFlags: TypedFlags<Flags> & Record<string, unknown>;
unnormalizedFlags: TypedFlags<Flags> & Record<string, unknown>;

/**
/**
The `package.json` object.
*/
pkg: PackageJson;
pkg: PackageJson;

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

/**
/**
Show the help text and exit with code.

@param exitCode - The exit code to use. Default: `2`.
*/
showHelp: (exitCode?: number) => void;
showHelp: (exitCode?: number) => void;

/**
/**
Show the version text and exit.
*/
showVersion: () => void;
}
showVersion: () => void;
}
/**
@param helpMessage - Shortcut for the `help` option.

@example
```
#!/usr/bin/env node
'use strict';
import meow = require('meow');
import foo = require('.');
import meow = from 'meow';
LitoMore marked this conversation as resolved.
Show resolved Hide resolved
import foo from './index.js';

const cli = meow(`
Usage
Expand Down Expand Up @@ -309,7 +306,7 @@ const cli = meow(`
foo(cli.input[0], cli.flags);
```
*/
declare function meow<Flags extends meow.AnyFlags>(helpMessage: string, options?: meow.Options<Flags>): meow.Result<Flags>;
declare function meow<Flags extends meow.AnyFlags>(options?: meow.Options<Flags>): meow.Result<Flags>;

export = meow;
declare function meow<Flags extends AnyFlags>(helpMessage: string | Options<Flags>, options?: Options<Flags>): Result<Flags>;
LitoMore marked this conversation as resolved.
Show resolved Hide resolved

export default meow;
31 changes: 12 additions & 19 deletions index.js
@@ -1,19 +1,13 @@
'use strict';
const path = require('path');
const buildParserOptions = require('minimist-options');
const parseArguments = require('yargs-parser');
const camelCaseKeys = require('camelcase-keys');
const decamelize = require('decamelize');
const decamelizeKeys = require('decamelize-keys');
const trimNewlines = require('trim-newlines');
const redent = require('redent');
const readPkgUp = require('read-pkg-up');
const hardRejection = require('hard-rejection');
const normalizePackageData = require('normalize-package-data');

// Prevent caching of this module so module.parent is always accurate
delete require.cache[__filename];
const parentDir = path.dirname(module.parent && module.parent.filename ? module.parent.filename : '.');
import buildParserOptions from 'minimist-options';
import parseArguments from 'yargs-parser';
import camelCaseKeys from 'camelcase-keys';
import decamelize from 'decamelize';
import decamelizeKeys from 'decamelize-keys';
import trimNewlines from 'trim-newlines';
import redent from 'redent';
import {readPackageUpSync} from 'read-pkg-up';
import hardRejection from 'hard-rejection';
import normalizePackageData from 'normalize-package-data';

const isFlagMissing = (flagName, definedFlags, receivedFlags, input) => {
const flag = definedFlags[flagName];
Expand Down Expand Up @@ -109,8 +103,7 @@ const meow = (helpText, options) => {
helpText = '';
}

const foundPkg = readPkgUp.sync({
cwd: parentDir,
const foundPkg = readPackageUpSync({
normalize: false
});

Expand Down Expand Up @@ -231,4 +224,4 @@ const meow = (helpText, options) => {
};
};

module.exports = meow;
export default meow;
3 changes: 1 addition & 2 deletions index.test-d.ts
@@ -1,7 +1,6 @@
import {expectAssignable, expectType} from 'tsd';
import {PackageJson} from 'type-fest';
import meow = require('.');
import {Result} from '.';
import meow, {Result} from './index.js';

expectType<Result<never>>(meow('Help text'));
expectType<Result<never>>(meow('Help text', {hardRejection: false}));
Expand Down
11 changes: 7 additions & 4 deletions package.json
Expand Up @@ -10,8 +10,10 @@
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=10"
"node": ">=12"
},
"scripts": {
"test": "xo && ava && tsd"
Expand Down Expand Up @@ -47,18 +49,19 @@
"hard-rejection": "^2.1.0",
"minimist-options": "4.1.0",
"normalize-package-data": "^3.0.0",
"read-pkg-up": "^7.0.1",
"read-pkg-up": "^8.0.0",
"redent": "^3.0.0",
"trim-newlines": "^3.0.0",
"type-fest": "^0.18.0",
"yargs-parser": "^20.2.3"
},
"devDependencies": {
"ava": "^2.4.0",
"ava": "^3.15.0",
"execa": "^4.1.0",
"indent-string": "^4.0.0",
"read-pkg": "^6.0.0",
"tsd": "^0.13.1",
"xo": "^0.34.1"
"xo": "^0.39.1"
},
"xo": {
"rules": {
Expand Down