From a599ed59b68e6c3381fd5139b0851f0189117d8f Mon Sep 17 00:00:00 2001 From: bcoe Date: Fri, 2 Apr 2021 15:43:58 -0700 Subject: [PATCH 1/3] feat: add parseSync/parseAsync --- lib/yargs-factory.ts | 25 +++++++++++++++++++++++++ test/yargs.cjs | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/lib/yargs-factory.ts b/lib/yargs-factory.ts index 54c1c3ba8..5ef10e8f3 100644 --- a/lib/yargs-factory.ts +++ b/lib/yargs-factory.ts @@ -1082,6 +1082,31 @@ export class YargsInstance { } return parsed; } + parseAsync( + args?: string | string[], + shortCircuit?: object | ParseCallback | boolean, + _parseFn?: ParseCallback + ): Promise { + const maybePromise = this.parse(args, shortCircuit, _parseFn); + if (!isPromise(maybePromise)) { + return Promise.resolve(maybePromise); + } else { + return maybePromise; + } + } + parseSync( + args?: string | string[], + shortCircuit?: object | ParseCallback | boolean, + _parseFn?: ParseCallback + ): Arguments { + const maybePromise = this.parse(args, shortCircuit, _parseFn); + if (isPromise(maybePromise)) { + throw new YError( + '.parseSync() must not be used with asynchronous builders, handlers, or middleware' + ); + } + return maybePromise; + } parserConfiguration(config: Configuration) { argsert('', [config], arguments.length); this.#parserConfig = config; diff --git a/test/yargs.cjs b/test/yargs.cjs index 1840fda46..875c57ef9 100644 --- a/test/yargs.cjs +++ b/test/yargs.cjs @@ -23,6 +23,9 @@ function clearRequireCache() { delete require.cache[require.resolve('../index.cjs')]; delete require.cache[require.resolve('../build/index.cjs')]; } +function isPromise(maybePromise) { + return typeof maybePromise.then === 'function'; +} describe('yargs dsl tests', () => { const oldProcess = {versions: {}}; @@ -3115,4 +3118,18 @@ describe('yargs dsl tests', () => { assert.strictEqual(y2.getStrictOptions(), false); }); }); + describe('parseAsync', () => { + it('returns promise when parse is synchronous', () => { + const argv = yargs('foo').parseAsync(); + assert.strictEqual(isPromise(argv), true); + }); + it('returns promise when parse is asynchronous', async () => { + const argv = yargs('--foo bar').middleware(async () => { + await wait(); + }).parse(); + assert.strictEqual(isPromise(argv), true); + assert.strictEqual((await argv).foo, 'bar'); + }); + }); + // TODO: add tests for parseSync. }); From 8d042d583e3ae07e6fd0a31f3deff57d127c56db Mon Sep 17 00:00:00 2001 From: bcoe Date: Sat, 3 Apr 2021 15:33:44 -0700 Subject: [PATCH 2/3] feat: add parseSync/parseAsync Introduces parseSync/parseAsync, allowing an application to explicitly state whether or not it expects the parse goal of yargs to be asynchronous --- docs/api.md | 16 ++++++++++++++-- test/yargs.cjs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/docs/api.md b/docs/api.md index 9bcf3e2cb..3d11de387 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1338,9 +1338,21 @@ the resulting error and output will not be passed to the `parse()` callback (the ***Note:*** `parse()` should be called only once when [`command()`](#command) is called with a handler returning a promise. If your use case requires `parse()` to be called several times, any asynchronous -operation performed in a command handler should not result in the handler returning a promise +operation performed in a command handler should not result in the handler returning a promise. -.parsed +.parseAsync([args], [context], [parseCallback]) +------------ + +Identical to `.parse()`, except always returns a promise for a parsed argv +object, regardless of whether an async builder, handler, or middleware is used. + +.parseSync([args], [context], [parseCallback]) +------------ + +Identical to `.parse()`, except an exception is thrown if an asynchronous +builder, handler, or middleware is used. + +.parsed [DEPRECATED] ------------ If the arguments have not been parsed, this property is `false`. diff --git a/test/yargs.cjs b/test/yargs.cjs index 875c57ef9..7b81729f0 100644 --- a/test/yargs.cjs +++ b/test/yargs.cjs @@ -3124,12 +3124,44 @@ describe('yargs dsl tests', () => { assert.strictEqual(isPromise(argv), true); }); it('returns promise when parse is asynchronous', async () => { - const argv = yargs('--foo bar').middleware(async () => { - await wait(); - }).parse(); + const argv = yargs('--foo bar') + .middleware(async () => { + await wait(); + }) + .parseAsync(); assert.strictEqual(isPromise(argv), true); assert.strictEqual((await argv).foo, 'bar'); }); }); - // TODO: add tests for parseSync. + describe('parseSync', () => { + it('succeeds if no async functions used during parsing', () => { + const argv = yargs('foo 33') + .command( + 'foo [bar]', + 'foo command', + () => {}, + () => {} + ) + .middleware(argv => { + argv.bar *= 2; + }) + .parseSync(); + assert.strictEqual(argv.bar, 66); + }); + it('throws if any async method is used', () => { + assert.throws(() => { + yargs('foo 33') + .command( + 'foo [bar]', + 'foo command', + () => {}, + () => {} + ) + .middleware(async argv => { + argv.bar *= 2; + }) + .parseSync(); + }, /.*parseSync\(\) must not be used.*/); + }); + }); }); From 7f89aabb8cca6628be1c5795cf99a7d02846df67 Mon Sep 17 00:00:00 2001 From: bcoe Date: Sat, 3 Apr 2021 19:53:54 -0700 Subject: [PATCH 3/3] docs: slight tweak to documentation --- docs/api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api.md b/docs/api.md index 3d11de387..0bd5d9e16 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1343,13 +1343,13 @@ operation performed in a command handler should not result in the handler return .parseAsync([args], [context], [parseCallback]) ------------ -Identical to `.parse()`, except always returns a promise for a parsed argv +Identical to `.parse()` except always returns a promise for a parsed argv object, regardless of whether an async builder, handler, or middleware is used. .parseSync([args], [context], [parseCallback]) ------------ -Identical to `.parse()`, except an exception is thrown if an asynchronous +Identical to `.parse()` except an exception is thrown if an asynchronous builder, handler, or middleware is used. .parsed [DEPRECATED]