From ffe125a250a4acf8202060a16c6e034666e24f01 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Thu, 29 Apr 2021 20:43:36 +0800 Subject: [PATCH 01/14] Allow user to pass in package url for package reading --- estest/index.js | 1 + index.d.ts | 8 +++ index.js | 12 +++-- package.json | 2 +- readme.md | 54 ++++---------------- test/fixtures/fixture-allow-unknown-flags.js | 2 + test/fixtures/fixture-required-function.js | 2 + test/fixtures/fixture-required-multiple.js | 2 + test/fixtures/fixture-required.js | 2 + test/fixtures/fixture.js | 2 + test/test.js | 54 ++++++++++++++++++-- 11 files changed, 88 insertions(+), 53 deletions(-) diff --git a/estest/index.js b/estest/index.js index c10f205..23cfb8d 100644 --- a/estest/index.js +++ b/estest/index.js @@ -13,6 +13,7 @@ meow( 🌈 unicorns 🌈 `, { + packagePath: import.meta.url, flags: { rainbow: { type: 'boolean', diff --git a/index.d.ts b/index.d.ts index 70733bc..cc09578 100644 --- a/index.d.ts +++ b/index.d.ts @@ -151,6 +151,7 @@ export interface Options { $ foo 🌈 unicorns✨🌈 `, { + packagePath: import.meta.url, booleanDefault: undefined, flags: { rainbow: { @@ -206,6 +207,13 @@ export interface Options { @default true */ readonly allowUnknownFlags?: boolean; + + /** + Directory to start looking for the module package.json file. + + @default process.cwd() + */ + readonly packagePath?: string; } type TypedFlag = diff --git a/index.js b/index.js index 2959bc9..78094a2 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +import {dirname} from 'node:path'; +import {fileURLToPath} from 'node:url'; import buildParserOptions from 'minimist-options'; import parseArguments from 'yargs-parser'; import camelCaseKeys from 'camelcase-keys'; @@ -5,7 +7,7 @@ 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 {readPackageSync} from 'read-pkg'; import hardRejection from 'hard-rejection'; import normalizePackageData from 'normalize-package-data'; @@ -97,18 +99,20 @@ const validateFlags = (flags, options) => { } }; -const meow = (helpText, options) => { +const meow = (helpText, options = {}) => { if (typeof helpText !== 'string') { options = helpText; helpText = ''; } - const foundPackage = readPackageUpSync({ + const foundPackage = readPackageSync({ + cwd: options.packagePath ? dirname(fileURLToPath(options.packagePath)) : process.cwd(), normalize: false }); options = { - pkg: foundPackage ? foundPackage.packageJson : {}, + packagePath: process.cwd(), + pkg: foundPackage || {}, argv: process.argv.slice(2), flags: {}, inferType: false, diff --git a/package.json b/package.json index 2ed2791..ff8554e 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.2", + "read-pkg": "^6.0.0", "read-pkg-up": "^8.0.0", "redent": "^3.0.0", "trim-newlines": "^4.0.0", @@ -59,7 +60,6 @@ "ava": "^3.15.0", "execa": "^5.0.0", "indent-string": "^5.0.0", - "read-pkg": "^6.0.0", "tsd": "^0.14.0", "xo": "^0.39.1" }, diff --git a/readme.md b/readme.md index dd9f337..f3366db 100644 --- a/readme.md +++ b/readme.md @@ -26,52 +26,11 @@ $ npm install meow $ ./foo-app.js unicorns --rainbow ``` -**CommonJS** - -```js -#!/usr/bin/env node -'use strict'; -const meow = require('meow'); -const foo = require('.'); - -const cli = meow(` - Usage - $ foo - - Options - --rainbow, -r Include a rainbow - - Examples - $ foo unicorns --rainbow - 🌈 unicorns 🌈 -`, { - flags: { - rainbow: { - type: 'boolean', - alias: 'r' - } - } -}); -/* -{ - input: ['unicorns'], - flags: {rainbow: true}, - ... -} -*/ - -foo(cli.input[0], cli.flags); -``` - -**ES Modules** - ```js #!/usr/bin/env node -import {createRequire} from 'module'; +import meow from 'meow'; import foo from './lib/index.js'; -const meow = createRequire(import.meta.url)('meow'); - const cli = meow(` Usage $ foo @@ -83,6 +42,7 @@ const cli = meow(` $ foo unicorns --rainbow 🌈 unicorns 🌈 `, { + packagePath: import.meta.url, flags: { rainbow: { type: 'boolean', @@ -126,6 +86,13 @@ Shortcut for the `help` option. Type: `object` +##### packagePath + +Type: `string`\ +Default: `process.cwd()` + +Directory to start looking for the module package.json file. + ##### flags Type: `object` @@ -253,7 +220,7 @@ __Caution: Explicitly specifying `undefined` for `booleanDefault` has different Example: ```js -const meow = require('meow'); +const meow from 'meow'; const cli = meow(` Usage @@ -268,6 +235,7 @@ const cli = meow(` $ foo 🌈 unicorns✨🌈 `, { + packagePath: import.meta.url, booleanDefault: undefined, flags: { rainbow: { diff --git a/test/fixtures/fixture-allow-unknown-flags.js b/test/fixtures/fixture-allow-unknown-flags.js index eb0c100..ac02dae 100755 --- a/test/fixtures/fixture-allow-unknown-flags.js +++ b/test/fixtures/fixture-allow-unknown-flags.js @@ -1,7 +1,9 @@ #!/usr/bin/env node +import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ + packagePath: path.join(import.meta.url, '../..'), description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required-function.js b/test/fixtures/fixture-required-function.js index c509254..8727ed2 100755 --- a/test/fixtures/fixture-required-function.js +++ b/test/fixtures/fixture-required-function.js @@ -1,7 +1,9 @@ #!/usr/bin/env node +import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ + packagePath: path.join(import.meta.url, '../..'), description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required-multiple.js b/test/fixtures/fixture-required-multiple.js index 907ffc4..a7d3653 100755 --- a/test/fixtures/fixture-required-multiple.js +++ b/test/fixtures/fixture-required-multiple.js @@ -1,7 +1,9 @@ #!/usr/bin/env node +import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ + packagePath: path.join(import.meta.url, '../..'), description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required.js b/test/fixtures/fixture-required.js index ad9341a..6d10524 100755 --- a/test/fixtures/fixture-required.js +++ b/test/fixtures/fixture-required.js @@ -1,8 +1,10 @@ #!/usr/bin/env node 'use strict'; +import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ + packagePath: path.join(import.meta.url, '../..'), description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture.js b/test/fixtures/fixture.js index 5fc0f17..01e9d39 100755 --- a/test/fixtures/fixture.js +++ b/test/fixtures/fixture.js @@ -1,7 +1,9 @@ #!/usr/bin/env node +import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ + packagePath: path.join(import.meta.url, '../..'), description: 'Custom description', help: ` Usage diff --git a/test/test.js b/test/test.js index 0487543..43def80 100644 --- a/test/test.js +++ b/test/test.js @@ -8,10 +8,21 @@ import meow from '../index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const fixturePath = path.join(__dirname, 'fixtures', 'fixture.js'); +const packagePath = path.join(import.meta.url, '..'); const NODE_MAJOR_VERSION = process.versions.node.split('.')[0]; +test('invalid package url', t => { + const error = t.throws(() => { + meow({ + packagePath: '/path/to/package' + }); + }); + t.is(error.message, 'Invalid URL: /path/to/package'); +}); + test('return object', t => { const cli = meow({ + packagePath, argv: ['foo', '--foo-bar', '-u', 'cat', '--', 'unicorn', 'cake'], help: ` Usage @@ -37,7 +48,9 @@ test('support help shortcut', t => { const cli = meow(` unicorn cat - `); + `, { + packagePath + }); t.is(cli.help, indentString('\nCLI app helper\n\nunicorn\ncat\n', 2)); }); @@ -90,6 +103,7 @@ test('spawn cli and test input flag', async t => { test.serial('pkg.bin as a string should work', t => { meow({ pkg: { + packagePath, name: 'browser-sync', bin: 'bin/browser-sync.js' } @@ -99,12 +113,18 @@ test.serial('pkg.bin as a string should work', t => { }); test('single character flag casing should be preserved', t => { - t.deepEqual(meow({argv: ['-F']}).flags, {F: true}); + t.deepEqual(meow({ + packagePath, + argv: ['-F'] + }).flags, {F: true}); }); test('flag declared in kebab-case is an error', t => { const error = t.throws(() => { - meow({flags: {'kebab-case': 'boolean', test: 'boolean', 'another-one': 'boolean'}}); + meow({ + packagePath, + flags: {'kebab-case': 'boolean', test: 'boolean', 'another-one': 'boolean'} + }); }); t.is(error.message, 'Flag keys may not contain \'-\': kebab-case, another-one'); }); @@ -136,6 +156,7 @@ test('type inference', t => { test('booleanDefault: undefined, filter out unset boolean args', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo'], booleanDefault: undefined, flags: { @@ -158,6 +179,7 @@ test('booleanDefault: undefined, filter out unset boolean args', t => { test('boolean args are false by default', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo'], flags: { foo: { @@ -180,6 +202,7 @@ test('boolean args are false by default', t => { test('enforces boolean flag type', t => { const cli = meow({ + packagePath, argv: ['--cursor=false'], flags: { cursor: { @@ -192,6 +215,7 @@ test('enforces boolean flag type', t => { test('accept help and options', t => { t.deepEqual(meow({ + packagePath, argv: ['-f'], flags: { foo: { @@ -206,6 +230,7 @@ test('accept help and options', t => { test('grouped short-flags work', t => { const cli = meow({ + packagePath, argv: ['-cl'], flags: { coco: { @@ -228,6 +253,7 @@ test('grouped short-flags work', t => { test('grouped flags work', t => { const cli = meow({ + packagePath, argv: ['-cl'], flags: { coco: { @@ -256,6 +282,7 @@ test('disable autoVersion/autoHelp if `cli.input.length > 0`', t => { test('supports `number` flag type', t => { const cli = meow({ + packagePath, argv: ['--foo=1.3'], flags: { foo: { @@ -269,6 +296,7 @@ test('supports `number` flag type', t => { test('supports `number` flag type - flag but no value', t => { const cli = meow({ + packagePath, argv: ['--foo'], flags: { foo: { @@ -282,6 +310,7 @@ test('supports `number` flag type - flag but no value', t => { test('supports `number` flag type - flag but no value but default', t => { const cli = meow({ + packagePath, argv: ['--foo'], flags: { foo: { @@ -296,6 +325,7 @@ test('supports `number` flag type - flag but no value but default', t => { test('supports `number` flag type - no flag but default', t => { const cli = meow({ + packagePath, argv: [], flags: { foo: { @@ -311,6 +341,7 @@ test('supports `number` flag type - no flag but default', t => { test('supports `number` flag type - throws on incorrect default value', t => { t.throws(() => { meow({ + packagePath, argv: [], flags: { foo: { @@ -324,6 +355,7 @@ test('supports `number` flag type - throws on incorrect default value', t => { test('isMultiple - unset flag returns empty array', t => { t.deepEqual(meow({ + packagePath, argv: [], flags: { foo: { @@ -338,6 +370,7 @@ test('isMultiple - unset flag returns empty array', t => { test('isMultiple - flag set once returns array', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo=bar'], flags: { foo: { @@ -352,6 +385,7 @@ test('isMultiple - flag set once returns array', t => { test('isMultiple - flag set multiple times', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo=bar', '--foo=baz'], flags: { foo: { @@ -366,6 +400,7 @@ test('isMultiple - flag set multiple times', t => { test('isMultiple - flag with space separated values', t => { const {input, flags} = meow({ + packagePath, argv: ['--foo', 'bar', 'baz'], flags: { foo: { @@ -381,6 +416,7 @@ test('isMultiple - flag with space separated values', t => { test('isMultiple - flag with comma separated values', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo', 'bar,baz'], flags: { foo: { @@ -396,6 +432,7 @@ test('isMultiple - flag with comma separated values', t => { test('single flag set more than once => throws', t => { t.throws(() => { meow({ + packagePath, argv: ['--foo=bar', '--foo=baz'], flags: { foo: { @@ -408,6 +445,7 @@ test('single flag set more than once => throws', t => { test('isMultiple - default to type string', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo=bar'], flags: { foo: { @@ -421,6 +459,7 @@ test('isMultiple - default to type string', t => { test('isMultiple - boolean flag', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo', '--foo=false'], flags: { foo: { @@ -435,6 +474,7 @@ test('isMultiple - boolean flag', t => { test('isMultiple - boolean flag is false by default', t => { t.deepEqual(meow({ + packagePath, argv: [], flags: { foo: { @@ -449,6 +489,7 @@ test('isMultiple - boolean flag is false by default', t => { test('isMultiple - number flag', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo=1.3', '--foo=-1'], flags: { foo: { @@ -463,6 +504,7 @@ test('isMultiple - number flag', t => { test('isMultiple - flag default values', t => { t.deepEqual(meow({ + packagePath, argv: [], flags: { string: { @@ -490,6 +532,7 @@ test('isMultiple - flag default values', t => { test('isMultiple - multiple flag default values', t => { t.deepEqual(meow({ + packagePath, argv: [], flags: { string: { @@ -518,6 +561,7 @@ test('isMultiple - multiple flag default values', t => { // Happened in production 2020-05-10: https://github.com/sindresorhus/meow/pull/143#issuecomment-626287226 test('isMultiple - handles multi-word flag name', t => { t.deepEqual(meow({ + packagePath, argv: ['--foo-bar=baz'], flags: { fooBar: { @@ -533,8 +577,8 @@ test('isMultiple - handles multi-word flag name', t => { if (NODE_MAJOR_VERSION >= 14) { test('supports es modules', async t => { try { - const {stdout} = await execa('node', ['index.js', '--version'], { - cwd: path.join(__dirname, '..', 'estest') + const {stdout} = await execa('node', ['estest/index.js', '--version'], { + packagePath: path.join(__dirname, '..') }); t.regex(stdout, /1.2.3/); } catch (error) { From e1ac829b19a8ed911097cf2b21fc94acbbe26b8a Mon Sep 17 00:00:00 2001 From: LitoMore Date: Fri, 30 Apr 2021 16:20:49 +0800 Subject: [PATCH 02/14] Update option name to `importMeta` --- estest/index.js | 2 +- index.d.ts | 18 +++-- index.js | 13 ++-- index.test-d.ts | 48 ++++++------ package.json | 2 +- readme.md | 11 +-- test/fixtures/fixture-allow-unknown-flags.js | 3 +- test/fixtures/fixture-required-function.js | 3 +- test/fixtures/fixture-required-multiple.js | 3 +- test/fixtures/fixture-required.js | 3 +- test/fixtures/fixture.js | 3 +- test/test.js | 81 +++++++++++--------- tsconfig.json | 2 +- 13 files changed, 101 insertions(+), 91 deletions(-) diff --git a/estest/index.js b/estest/index.js index 23cfb8d..3c85bc0 100644 --- a/estest/index.js +++ b/estest/index.js @@ -13,7 +13,7 @@ meow( 🌈 unicorns 🌈 `, { - packagePath: import.meta.url, + importMeta: import.meta, flags: { rainbow: { type: 'boolean', diff --git a/index.d.ts b/index.d.ts index cc09578..47279ad 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,6 +20,7 @@ export interface Flag { readonly isMultiple?: boolean; } +type ImportMeta = {url: string}; type StringFlag = Flag<'string', string>; type BooleanFlag = Flag<'boolean', boolean>; type NumberFlag = Flag<'number', number>; @@ -27,6 +28,13 @@ type AnyFlag = StringFlag | BooleanFlag | NumberFlag; type AnyFlags = Record; export interface Options { + /** + Directory to start looking for the module package.json file. + + This option is required, its value should be `import.meta`. + */ + readonly importMeta: ImportMeta; + /** Define argument flags. @@ -151,7 +159,7 @@ export interface Options { $ foo 🌈 unicorns✨🌈 `, { - packagePath: import.meta.url, + importMeta: import.meta, booleanDefault: undefined, flags: { rainbow: { @@ -207,13 +215,6 @@ export interface Options { @default true */ readonly allowUnknownFlags?: boolean; - - /** - Directory to start looking for the module package.json file. - - @default process.cwd() - */ - readonly packagePath?: string; } type TypedFlag = @@ -296,6 +297,7 @@ const cli = meow(` $ foo unicorns --rainbow 🌈 unicorns 🌈 `, { + importMeta: import.meta, flags: { rainbow: { type: 'boolean', diff --git a/index.js b/index.js index 78094a2..b56722f 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ import decamelize from 'decamelize'; import decamelizeKeys from 'decamelize-keys'; import trimNewlines from 'trim-newlines'; import redent from 'redent'; -import {readPackageSync} from 'read-pkg'; +import {readPackageUpSync} from 'read-pkg-up'; import hardRejection from 'hard-rejection'; import normalizePackageData from 'normalize-package-data'; @@ -105,14 +105,17 @@ const meow = (helpText, options = {}) => { helpText = ''; } - const foundPackage = readPackageSync({ - cwd: options.packagePath ? dirname(fileURLToPath(options.packagePath)) : process.cwd(), + if (!(options.importMeta && options.importMeta.url)) { + throw new Error('`importMeta` options is required, its value should be `import.meta`'); + } + + const foundPackage = readPackageUpSync({ + cwd: dirname(fileURLToPath(options.importMeta.url)), normalize: false }); options = { - packagePath: process.cwd(), - pkg: foundPackage || {}, + pkg: foundPackage ? foundPackage.packageJson : {}, argv: process.argv.slice(2), flags: {}, inferType: false, diff --git a/index.test-d.ts b/index.test-d.ts index 5c154d2..28b6098 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -2,43 +2,46 @@ import {expectAssignable, expectType} from 'tsd'; import {PackageJson} from 'type-fest'; import meow, {Result} from './index.js'; +const importMeta = import.meta; + expectType>(meow('Help text')); -expectType>(meow('Help text', {hardRejection: false})); +expectType>(meow('Help text', {importMeta, hardRejection: false})); expectAssignable<{flags: {foo: number}}>( - meow({flags: {foo: {type: 'number', isRequired: true}}}) + meow({importMeta: import.meta, flags: {foo: {type: 'number', isRequired: true}}}) ); expectAssignable<{flags: {foo: string}}>( - meow({flags: {foo: {type: 'string', isRequired: true}}}) + meow({importMeta, flags: {foo: {type: 'string', isRequired: true}}}) ); expectAssignable<{flags: {foo: boolean}}>( - meow({flags: {foo: {type: 'boolean', isRequired: true}}}) + meow({importMeta, flags: {foo: {type: 'boolean', isRequired: true}}}) ); expectAssignable<{flags: {foo: number | undefined}}>( - meow({flags: {foo: {type: 'number'}}}) + meow({importMeta, flags: {foo: {type: 'number'}}}) ); expectAssignable<{flags: {foo: string | undefined}}>( - meow({flags: {foo: {type: 'string'}}}) + meow({importMeta, flags: {foo: {type: 'string'}}}) ); expectAssignable<{flags: {foo: boolean | undefined}}>( - meow({flags: {foo: {type: 'boolean'}}}) + meow({importMeta, flags: {foo: {type: 'boolean'}}}) ); -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})); +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, hardRejection: false})); const result = meow('Help text', { + importMeta, flags: { foo: {type: 'boolean', alias: 'f'}, 'foo-bar': {type: 'number'}, @@ -66,6 +69,7 @@ result.showHelp(1); result.showVersion(); const options = { + importMeta, flags: { rainbow: { type: 'boolean', diff --git a/package.json b/package.json index ff8554e..2ed2791 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.2", - "read-pkg": "^6.0.0", "read-pkg-up": "^8.0.0", "redent": "^3.0.0", "trim-newlines": "^4.0.0", @@ -60,6 +59,7 @@ "ava": "^3.15.0", "execa": "^5.0.0", "indent-string": "^5.0.0", + "read-pkg": "^6.0.0", "tsd": "^0.14.0", "xo": "^0.39.1" }, diff --git a/readme.md b/readme.md index f3366db..f065e6b 100644 --- a/readme.md +++ b/readme.md @@ -42,7 +42,7 @@ const cli = meow(` $ foo unicorns --rainbow 🌈 unicorns 🌈 `, { - packagePath: import.meta.url, + importMeta: import.meta, flags: { rainbow: { type: 'boolean', @@ -86,13 +86,14 @@ Shortcut for the `help` option. Type: `object` -##### packagePath +##### importMeta -Type: `string`\ -Default: `process.cwd()` +Type: `string` Directory to start looking for the module package.json file. +This option is required, its value should be `import.meta`. + ##### flags Type: `object` @@ -235,7 +236,7 @@ const cli = meow(` $ foo 🌈 unicorns✨🌈 `, { - packagePath: import.meta.url, + importMeta: import.meta, booleanDefault: undefined, flags: { rainbow: { diff --git a/test/fixtures/fixture-allow-unknown-flags.js b/test/fixtures/fixture-allow-unknown-flags.js index ac02dae..e14de67 100755 --- a/test/fixtures/fixture-allow-unknown-flags.js +++ b/test/fixtures/fixture-allow-unknown-flags.js @@ -1,9 +1,8 @@ #!/usr/bin/env node -import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ - packagePath: path.join(import.meta.url, '../..'), + importMeta: import.meta, description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required-function.js b/test/fixtures/fixture-required-function.js index 8727ed2..1d4129b 100755 --- a/test/fixtures/fixture-required-function.js +++ b/test/fixtures/fixture-required-function.js @@ -1,9 +1,8 @@ #!/usr/bin/env node -import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ - packagePath: path.join(import.meta.url, '../..'), + importMeta: import.meta, description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required-multiple.js b/test/fixtures/fixture-required-multiple.js index a7d3653..7fa3bd3 100755 --- a/test/fixtures/fixture-required-multiple.js +++ b/test/fixtures/fixture-required-multiple.js @@ -1,9 +1,8 @@ #!/usr/bin/env node -import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ - packagePath: path.join(import.meta.url, '../..'), + importMeta: import.meta, description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture-required.js b/test/fixtures/fixture-required.js index 6d10524..ad2b4a6 100755 --- a/test/fixtures/fixture-required.js +++ b/test/fixtures/fixture-required.js @@ -1,10 +1,9 @@ #!/usr/bin/env node 'use strict'; -import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ - packagePath: path.join(import.meta.url, '../..'), + importMeta: import.meta, description: 'Custom description', help: ` Usage diff --git a/test/fixtures/fixture.js b/test/fixtures/fixture.js index 01e9d39..dab6eb9 100755 --- a/test/fixtures/fixture.js +++ b/test/fixtures/fixture.js @@ -1,9 +1,8 @@ #!/usr/bin/env node -import path from 'node:path'; import meow from '../../index.js'; const cli = meow({ - packagePath: path.join(import.meta.url, '../..'), + importMeta: import.meta, description: 'Custom description', help: ` Usage diff --git a/test/test.js b/test/test.js index 43def80..f1e7d2f 100644 --- a/test/test.js +++ b/test/test.js @@ -8,21 +8,21 @@ import meow from '../index.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const fixturePath = path.join(__dirname, 'fixtures', 'fixture.js'); -const packagePath = path.join(import.meta.url, '..'); +const importMeta = import.meta; const NODE_MAJOR_VERSION = process.versions.node.split('.')[0]; test('invalid package url', t => { const error = t.throws(() => { meow({ - packagePath: '/path/to/package' + importMeta: '/path/to/package' }); }); - t.is(error.message, 'Invalid URL: /path/to/package'); + t.is(error.message, '`importMeta` options is required, its value should be `import.meta`'); }); test('return object', t => { const cli = meow({ - packagePath, + importMeta, argv: ['foo', '--foo-bar', '-u', 'cat', '--', 'unicorn', 'cake'], help: ` Usage @@ -49,7 +49,7 @@ test('support help shortcut', t => { unicorn cat `, { - packagePath + importMeta }); t.is(cli.help, indentString('\nCLI app helper\n\nunicorn\ncat\n', 2)); }); @@ -102,8 +102,9 @@ test('spawn cli and test input flag', async t => { test.serial('pkg.bin as a string should work', t => { meow({ + importMeta, pkg: { - packagePath, + importMeta, name: 'browser-sync', bin: 'bin/browser-sync.js' } @@ -114,7 +115,7 @@ test.serial('pkg.bin as a string should work', t => { test('single character flag casing should be preserved', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['-F'] }).flags, {F: true}); }); @@ -122,7 +123,7 @@ test('single character flag casing should be preserved', t => { test('flag declared in kebab-case is an error', t => { const error = t.throws(() => { meow({ - packagePath, + importMeta, flags: {'kebab-case': 'boolean', test: 'boolean', 'another-one': 'boolean'} }); }); @@ -130,18 +131,21 @@ test('flag declared in kebab-case is an error', t => { }); test('type inference', t => { - t.is(meow({argv: ['5']}).input[0], '5'); - t.is(meow({argv: ['5']}, {input: 'string'}).input[0], '5'); + t.is(meow({importMeta, argv: ['5']}).input[0], '5'); + t.is(meow({importMeta, argv: ['5']}, {input: 'string'}).input[0], '5'); t.is(meow({ + importMeta, argv: ['5'], inferType: true }).input[0], 5); t.is(meow({ + importMeta, argv: ['5'], inferType: true, flags: {foo: 'string'} }).input[0], 5); t.is(meow({ + importMeta, argv: ['5'], inferType: true, flags: { @@ -149,6 +153,7 @@ test('type inference', t => { } }).input[0], 5); t.is(meow({ + importMeta, argv: ['5'], input: 'number' }).input[0], 5); @@ -156,7 +161,7 @@ test('type inference', t => { test('booleanDefault: undefined, filter out unset boolean args', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo'], booleanDefault: undefined, flags: { @@ -179,7 +184,7 @@ test('booleanDefault: undefined, filter out unset boolean args', t => { test('boolean args are false by default', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo'], flags: { foo: { @@ -202,7 +207,7 @@ test('boolean args are false by default', t => { test('enforces boolean flag type', t => { const cli = meow({ - packagePath, + importMeta, argv: ['--cursor=false'], flags: { cursor: { @@ -215,7 +220,7 @@ test('enforces boolean flag type', t => { test('accept help and options', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['-f'], flags: { foo: { @@ -230,7 +235,7 @@ test('accept help and options', t => { test('grouped short-flags work', t => { const cli = meow({ - packagePath, + importMeta, argv: ['-cl'], flags: { coco: { @@ -253,7 +258,7 @@ test('grouped short-flags work', t => { test('grouped flags work', t => { const cli = meow({ - packagePath, + importMeta, argv: ['-cl'], flags: { coco: { @@ -275,14 +280,14 @@ test('grouped flags work', t => { }); test('disable autoVersion/autoHelp if `cli.input.length > 0`', t => { - t.is(meow({argv: ['bar', '--version']}).input[0], 'bar'); - t.is(meow({argv: ['bar', '--help']}).input[0], 'bar'); - t.is(meow({argv: ['bar', '--version', '--help']}).input[0], 'bar'); + t.is(meow({importMeta, argv: ['bar', '--version']}).input[0], 'bar'); + t.is(meow({importMeta, argv: ['bar', '--help']}).input[0], 'bar'); + t.is(meow({importMeta, argv: ['bar', '--version', '--help']}).input[0], 'bar'); }); test('supports `number` flag type', t => { const cli = meow({ - packagePath, + importMeta, argv: ['--foo=1.3'], flags: { foo: { @@ -296,7 +301,7 @@ test('supports `number` flag type', t => { test('supports `number` flag type - flag but no value', t => { const cli = meow({ - packagePath, + importMeta, argv: ['--foo'], flags: { foo: { @@ -310,7 +315,7 @@ test('supports `number` flag type - flag but no value', t => { test('supports `number` flag type - flag but no value but default', t => { const cli = meow({ - packagePath, + importMeta, argv: ['--foo'], flags: { foo: { @@ -325,7 +330,7 @@ test('supports `number` flag type - flag but no value but default', t => { test('supports `number` flag type - no flag but default', t => { const cli = meow({ - packagePath, + importMeta, argv: [], flags: { foo: { @@ -341,7 +346,7 @@ test('supports `number` flag type - no flag but default', t => { test('supports `number` flag type - throws on incorrect default value', t => { t.throws(() => { meow({ - packagePath, + importMeta, argv: [], flags: { foo: { @@ -355,7 +360,7 @@ test('supports `number` flag type - throws on incorrect default value', t => { test('isMultiple - unset flag returns empty array', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: [], flags: { foo: { @@ -370,7 +375,7 @@ test('isMultiple - unset flag returns empty array', t => { test('isMultiple - flag set once returns array', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo=bar'], flags: { foo: { @@ -385,7 +390,7 @@ test('isMultiple - flag set once returns array', t => { test('isMultiple - flag set multiple times', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo=bar', '--foo=baz'], flags: { foo: { @@ -400,7 +405,7 @@ test('isMultiple - flag set multiple times', t => { test('isMultiple - flag with space separated values', t => { const {input, flags} = meow({ - packagePath, + importMeta, argv: ['--foo', 'bar', 'baz'], flags: { foo: { @@ -416,7 +421,7 @@ test('isMultiple - flag with space separated values', t => { test('isMultiple - flag with comma separated values', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo', 'bar,baz'], flags: { foo: { @@ -432,7 +437,7 @@ test('isMultiple - flag with comma separated values', t => { test('single flag set more than once => throws', t => { t.throws(() => { meow({ - packagePath, + importMeta, argv: ['--foo=bar', '--foo=baz'], flags: { foo: { @@ -445,7 +450,7 @@ test('single flag set more than once => throws', t => { test('isMultiple - default to type string', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo=bar'], flags: { foo: { @@ -459,7 +464,7 @@ test('isMultiple - default to type string', t => { test('isMultiple - boolean flag', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo', '--foo=false'], flags: { foo: { @@ -474,7 +479,7 @@ test('isMultiple - boolean flag', t => { test('isMultiple - boolean flag is false by default', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: [], flags: { foo: { @@ -489,7 +494,7 @@ test('isMultiple - boolean flag is false by default', t => { test('isMultiple - number flag', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo=1.3', '--foo=-1'], flags: { foo: { @@ -504,7 +509,7 @@ test('isMultiple - number flag', t => { test('isMultiple - flag default values', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: [], flags: { string: { @@ -532,7 +537,7 @@ test('isMultiple - flag default values', t => { test('isMultiple - multiple flag default values', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: [], flags: { string: { @@ -561,7 +566,7 @@ test('isMultiple - multiple flag default values', t => { // Happened in production 2020-05-10: https://github.com/sindresorhus/meow/pull/143#issuecomment-626287226 test('isMultiple - handles multi-word flag name', t => { t.deepEqual(meow({ - packagePath, + importMeta, argv: ['--foo-bar=baz'], flags: { fooBar: { @@ -578,7 +583,7 @@ if (NODE_MAJOR_VERSION >= 14) { test('supports es modules', async t => { try { const {stdout} = await execa('node', ['estest/index.js', '--version'], { - packagePath: path.join(__dirname, '..') + importMeta: path.join(__dirname, '..') }); t.regex(stdout, /1.2.3/); } catch (error) { diff --git a/tsconfig.json b/tsconfig.json index 720afed..edadef1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "lib": [ "es2018" ], - "module": "commonjs", + "module": "esnext", "moduleResolution": "node", "noImplicitAny": true, "strictNullChecks": true, From 9c7fa68bcd85c7ffe7a1be689d7d23b91ebde8d1 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Sun, 2 May 2021 19:54:36 +0800 Subject: [PATCH 03/14] Use TypeError --- index.d.ts | 2 +- index.js | 2 +- readme.md | 2 +- test/test.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 47279ad..af45462 100644 --- a/index.d.ts +++ b/index.d.ts @@ -31,7 +31,7 @@ export interface Options { /** Directory to start looking for the module package.json file. - This option is required, its value should be `import.meta`. + This option is required, its value must be `import.meta`. */ readonly importMeta: ImportMeta; diff --git a/index.js b/index.js index b56722f..60e60f5 100644 --- a/index.js +++ b/index.js @@ -106,7 +106,7 @@ const meow = (helpText, options = {}) => { } if (!(options.importMeta && options.importMeta.url)) { - throw new Error('`importMeta` options is required, its value should be `import.meta`'); + throw new TypeError('`importMeta` options is required, its value must be `import.meta`'); } const foundPackage = readPackageUpSync({ diff --git a/readme.md b/readme.md index f065e6b..b5bce36 100644 --- a/readme.md +++ b/readme.md @@ -92,7 +92,7 @@ Type: `string` Directory to start looking for the module package.json file. -This option is required, its value should be `import.meta`. +This option is required, its value must be `import.meta`. ##### flags diff --git a/test/test.js b/test/test.js index f1e7d2f..769a61e 100644 --- a/test/test.js +++ b/test/test.js @@ -17,7 +17,7 @@ test('invalid package url', t => { importMeta: '/path/to/package' }); }); - t.is(error.message, '`importMeta` options is required, its value should be `import.meta`'); + t.is(error.message, '`importMeta` options is required, its value must be `import.meta`'); }); test('return object', t => { From c2fbbfb995730912f8547407835efe3ee3c9c911 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Mon, 3 May 2021 11:46:47 +0800 Subject: [PATCH 04/14] Update index.d.ts Co-authored-by: Sindre Sorhus --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index af45462..0cdbcdb 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,7 +20,7 @@ export interface Flag { readonly isMultiple?: boolean; } -type ImportMeta = {url: string}; +type ImportMeta = typeof import.meta; type StringFlag = Flag<'string', string>; type BooleanFlag = Flag<'boolean', boolean>; type NumberFlag = Flag<'number', number>; From 0b74ec31893bd3eda685f10377494ea4323c3731 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Mon, 3 May 2021 12:16:22 +0800 Subject: [PATCH 05/14] Tweaks --- index.d.ts | 6 +++--- readme.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0cdbcdb..485147e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,7 +20,7 @@ export interface Flag { readonly isMultiple?: boolean; } -type ImportMeta = typeof import.meta; +type ImportMeta = Record & {url: string}; type StringFlag = Flag<'string', string>; type BooleanFlag = Flag<'boolean', boolean>; type NumberFlag = Flag<'number', number>; @@ -29,9 +29,9 @@ type AnyFlags = Record; export interface Options { /** - Directory to start looking for the module package.json file. + Your `import.meta` used for start looking for the module package.json file. - This option is required, its value must be `import.meta`. + Set it to `import.meta` to find the module package.json file. */ readonly importMeta: ImportMeta; diff --git a/readme.md b/readme.md index b5bce36..f0ee11a 100644 --- a/readme.md +++ b/readme.md @@ -90,7 +90,7 @@ Type: `object` Type: `string` -Directory to start looking for the module package.json file. +Your `import.meta` used for start looking for the module package.json file. This option is required, its value must be `import.meta`. From fc519c069d134755e5b6ea4a293ac1cec6290ab0 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Mon, 3 May 2021 12:17:38 +0800 Subject: [PATCH 06/14] Update `importMeta` type --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index f0ee11a..d50f25c 100644 --- a/readme.md +++ b/readme.md @@ -88,7 +88,7 @@ Type: `object` ##### importMeta -Type: `string` +Type: `object` Your `import.meta` used for start looking for the module package.json file. From 9378efc5cb50d3f33df8ce1ae08df0ce7bee09fd Mon Sep 17 00:00:00 2001 From: LitoMore Date: Mon, 3 May 2021 12:35:26 +0800 Subject: [PATCH 07/14] Update type --- index.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 485147e..74b4beb 100644 --- a/index.d.ts +++ b/index.d.ts @@ -20,7 +20,6 @@ export interface Flag { readonly isMultiple?: boolean; } -type ImportMeta = Record & {url: string}; type StringFlag = Flag<'string', string>; type BooleanFlag = Flag<'boolean', boolean>; type NumberFlag = Flag<'number', number>; From 8589ff6ea3de5e78ede4edf0706e273cc8b16cb3 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Tue, 4 May 2021 20:29:58 +0800 Subject: [PATCH 08/14] Update index.js Co-authored-by: Sindre Sorhus --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 60e60f5..8d3d76f 100644 --- a/index.js +++ b/index.js @@ -106,7 +106,7 @@ const meow = (helpText, options = {}) => { } if (!(options.importMeta && options.importMeta.url)) { - throw new TypeError('`importMeta` options is required, its value must be `import.meta`'); + throw new TypeError('The `importMeta` option is required. Its value must be `import.meta`.'); } const foundPackage = readPackageUpSync({ From cc8e475e355ca77e461d1b6aae3222281cf2bbb1 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Tue, 4 May 2021 20:44:09 +0800 Subject: [PATCH 09/14] Update test --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 769a61e..f47dc28 100644 --- a/test/test.js +++ b/test/test.js @@ -17,7 +17,7 @@ test('invalid package url', t => { importMeta: '/path/to/package' }); }); - t.is(error.message, '`importMeta` options is required, its value must be `import.meta`'); + t.is(error.message, 'The `importMeta` option is required. Its value must be `import.meta`.'); }); test('return object', t => { From 968d7900183e6a28855c3d544dbefdabb28f2c9d Mon Sep 17 00:00:00 2001 From: LitoMore Date: Tue, 4 May 2021 20:55:13 +0800 Subject: [PATCH 10/14] Update doc --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 74b4beb..f303876 100644 --- a/index.d.ts +++ b/index.d.ts @@ -30,7 +30,7 @@ export interface Options { /** Your `import.meta` used for start looking for the module package.json file. - Set it to `import.meta` to find the module package.json file. + This option is required, its value must be `import.meta`. */ readonly importMeta: ImportMeta; From 6b2648596b0506d1ded587baf0349580fd3b1cb3 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Tue, 4 May 2021 20:58:38 +0800 Subject: [PATCH 11/14] Add link to Node.js doc --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index d50f25c..4823f1f 100644 --- a/readme.md +++ b/readme.md @@ -90,7 +90,7 @@ Type: `object` Type: `object` -Your `import.meta` used for start looking for the module package.json file. +Your [`import.meta`](https://nodejs.org/dist/latest/docs/api/esm.html#esm_import_meta) used for start looking for the module package.json file. This option is required, its value must be `import.meta`. From 61e04be31bf865e00362053e1af61739060a03f9 Mon Sep 17 00:00:00 2001 From: LitoMore Date: Wed, 5 May 2021 11:24:39 +0800 Subject: [PATCH 12/14] Update index.d.ts Co-authored-by: Sindre Sorhus --- index.d.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index f303876..b925d8e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -28,9 +28,7 @@ type AnyFlags = Record; export interface Options { /** - Your `import.meta` used for start looking for the module package.json file. - - This option is required, its value must be `import.meta`. + Pass in `import.meta`. This is used to find the correct package.json file. */ readonly importMeta: ImportMeta; From 138c2b6d9e494db286771480d577a9a7093a797a Mon Sep 17 00:00:00 2001 From: LitoMore Date: Wed, 5 May 2021 11:26:27 +0800 Subject: [PATCH 13/14] Update doc --- readme.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 4823f1f..0b2d434 100644 --- a/readme.md +++ b/readme.md @@ -90,9 +90,7 @@ Type: `object` Type: `object` -Your [`import.meta`](https://nodejs.org/dist/latest/docs/api/esm.html#esm_import_meta) used for start looking for the module package.json file. - -This option is required, its value must be `import.meta`. +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. ##### flags From d2c720b9e4d812e66dd107e6235b9a235b171842 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 5 May 2021 22:06:29 +0700 Subject: [PATCH 14/14] Update index.d.ts --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index b925d8e..2ba2f25 100644 --- a/index.d.ts +++ b/index.d.ts @@ -28,7 +28,7 @@ type AnyFlags = Record; export interface Options { /** - Pass in `import.meta`. This is used to find the correct package.json file. + 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;