From 4f7346e2ebcbf72181f147e38a7d94bcd443c08b Mon Sep 17 00:00:00 2001 From: Mike Donnalley Date: Tue, 2 Jan 2024 09:24:39 -0800 Subject: [PATCH] feat: add 'only' option to allowStdin (#900) * feat: add 'only' option to allowStdin * test: add more allowStdin tests --- src/interfaces/parser.ts | 5 +++-- src/parser/parse.ts | 4 ++++ test/parser/parse.test.ts | 44 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/interfaces/parser.ts b/src/interfaces/parser.ts index d46616d7c..a1b00abb8 100644 --- a/src/interfaces/parser.ts +++ b/src/interfaces/parser.ts @@ -222,10 +222,11 @@ export type OptionFlagProps = FlagProps & { */ delimiter?: ',' /** - * Allow input value to be read from stdin. + * Allow input value to be read from stdin if the provided value is `-`. + * If set to `only`, the flag will only accept input from stdin. * Should only be used on one flag at a time. */ - allowStdin?: boolean + allowStdin?: boolean | 'only' } export type FlagParserContext = Command & {token: FlagToken} diff --git a/src/parser/parse.ts b/src/parser/parse.ts index 14183efc2..4a60e3ddc 100644 --- a/src/parser/parse.ts +++ b/src/parser/parse.ts @@ -156,6 +156,10 @@ export class Parser< throw new CLIError(`Flag --${name} expects a value`) } + if (flag.allowStdin === 'only' && input !== '-') { + throw new CLIError(`Flag --${name} can only be read from stdin. The value must be "-".`) + } + if (flag.allowStdin && input === '-') { const stdin = await readStdin() if (stdin) { diff --git a/test/parser/parse.test.ts b/test/parser/parse.test.ts index fb4d83afb..645044ae2 100644 --- a/test/parser/parse.test.ts +++ b/test/parser/parse.test.ts @@ -1872,7 +1872,7 @@ describe('allowStdin', () => { sandbox.restore() }) - it('should read stdin as input for flag', async () => { + it('should read stdin as input for flag when value is "-"', async () => { sandbox.stub(parser, 'readStdin').returns(stdinPromise) const out = await parse(['--myflag', '-'], { flags: { @@ -1883,4 +1883,46 @@ describe('allowStdin', () => { expect(out.flags.myflag).to.equals(stdinValue) expect(out.raw[0].input).to.equal('x') }) + + it('should not read stdin when value is not "-"', async () => { + sandbox.stub(parser, 'readStdin').returns(stdinPromise) + const out = await parse(['--myflag', 'foo'], { + flags: { + myflag: Flags.string({allowStdin: true}), + }, + }) + + expect(out.flags.myflag).to.equals('foo') + expect(out.raw[0].input).to.equal('foo') + }) + + it('should read stdin as input for flag when allowStdin is "only" and when value is "-"', async () => { + sandbox.stub(parser, 'readStdin').returns(stdinPromise) + const out = await parse(['--myflag', '-'], { + flags: { + myflag: Flags.string({allowStdin: 'only'}), + }, + }) + + expect(out.flags.myflag).to.equals(stdinValue) + expect(out.raw[0].input).to.equal('x') + }) + + it('should throw if allowStdin is "only" but value is not "-"', async () => { + sandbox.stub(parser, 'readStdin').returns(stdinPromise) + try { + await parse(['--myflag', 'INVALID'], { + flags: { + myflag: Flags.string({allowStdin: 'only'}), + }, + }) + expect.fail('Should have thrown an error') + } catch (error) { + if (error instanceof CLIError) { + expect(error.message).to.equal('Flag --myflag can only be read from stdin. The value must be "-".') + } else { + expect.fail('Should have thrown a CLIError') + } + } + }) })