Skip to content

Commit

Permalink
fix: ignore escaped delimiters (#1148)
Browse files Browse the repository at this point in the history
* fix: ignore escaped delimiters

* test: qa for delimiter escaping

* test: basic space delimiter

---------

Co-authored-by: mshanemc <[email protected]>
  • Loading branch information
mdonnalley and mshanemc authored Jul 26, 2024
1 parent 501c4e9 commit a41962a
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/parser/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,17 +412,27 @@ export class Parser<

// multiple with custom delimiter
if (fws.inputFlag.flag.type === 'option' && fws.inputFlag.flag.delimiter && fws.inputFlag.flag.multiple) {
// regex that will identify unescaped delimiters
const makeDelimiter = (delimiter: string) => new RegExp(`(?<!\\\\)${delimiter}`)
return {
...fws,
valueFunction: async (i) =>
(
await Promise.all(
(i.tokens ?? [])
.flatMap((token) => token.input.split((i.inputFlag.flag as OptionFlag<any>).delimiter ?? ','))
.flatMap((token) =>
token.input.split(makeDelimiter((i.inputFlag.flag as OptionFlag<any>).delimiter ?? ',')),
)
// trim, and remove surrounding doubleQuotes (which would hav been needed if the elements contain spaces)
.map((v) =>
v
.trim()
// remove escaped characters from delimiter
// example: --opt="a\,b,c" -> ["a,b", "c"]
.replaceAll(
new RegExp(`\\\\${(i.inputFlag.flag as OptionFlag<any>).delimiter}`, 'g'),
(i.inputFlag.flag as OptionFlag<any>).delimiter ?? ',',
)
.replace(/^"(.*)"$/, '$1')
.replace(/^'(.*)'$/, '$1'),
)
Expand Down
63 changes: 62 additions & 1 deletion test/parser/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,33 @@ See more help with --help`)
})
expect(out.flags).to.deep.include({foo: ['a', 'b']})
})
it('parses single flag starting with with \\ escape char', async () => {
const out = await parse(['--foo', '\\file:foo'], {
flags: {
foo: Flags.custom({multiple: true})(),
},
})
expect(out.flags).to.deep.include({foo: ['\\file:foo']})
})
it('parses multiple space-delimited flags', async () => {
const out = await parse(['--foo', 'a', 'b', 'c'], {
flags: {foo: Flags.string({multiple: true})},
})
expect(out.flags).to.deep.include({foo: ['a', 'b', 'c']})
})
it('parses multiple space-delimited flags ending with with \\ escape char', async () => {
const out = await parse(['--foo', 'c:\\', 'd:\\'], {
flags: {foo: Flags.string({multiple: true})},
})
expect(out.flags).to.deep.include({foo: ['c:\\', 'd:\\']})
})
it('parses multiple space-delimited flags ending with with \\ escape char', async () => {
const out = await parse(['--foo', 'c:\\', 'd:\\'], {
flags: {foo: Flags.string({multiple: true})},
})
expect(out.flags).to.deep.include({foo: ['c:\\', 'd:\\']})
})

it('allowed options on multiple', async () => {
const out = await parse(['--foo', 'a', '--foo=b'], {
flags: {
Expand Down Expand Up @@ -646,6 +673,41 @@ See more help with --help`)
expect(error.message).to.include('Expected --foo=b c to be one of: a a, b b')
}
})
it('retains escape char without delimiter', async () => {
const out = await parse(['--foo', 'a\\'], {
flags: {
foo: Flags.string({multiple: true, delimiter: ','}),
},
})
expect(out.flags).to.deep.include({foo: ['a\\']})
})
it('does not split on escaped delimiter', async () => {
const out = await parse(['--foo', 'a\\,b,c'], {
flags: {
foo: Flags.string({multiple: true, delimiter: ','}),
},
})
expect(out.flags).to.deep.include({foo: ['a,b', 'c']})
})
it('escapes with multiple invocation', async () => {
const out = await parse(['--foo', 'a\\,b', '--foo', 'b'], {
flags: {
foo: Flags.string({multiple: true, delimiter: ','}),
},
})
expect(out.flags).to.deep.include({foo: ['a,b', 'b']})
})

it('comma-escaped stringified json', async () => {
const val = '{"a":"b"\\,"c":"d"}'
const expected = '{"a":"b","c":"d"}'
const out = await parse(['--foo', val], {
flags: {
foo: Flags.string({multiple: true, delimiter: ','}),
},
})
expect(out.flags).to.deep.include({foo: [expected]})
})
})
})

Expand Down Expand Up @@ -709,7 +771,6 @@ See more help with --help`)
strict: false,
'--': false,
})
console.log(out)
expect(out.argv).to.deep.equal(['foo', 'bar', '--', '--myflag'])
expect(out.args).to.deep.equal({argOne: 'foo'})
})
Expand Down

0 comments on commit a41962a

Please sign in to comment.