From ae11f496a8318ea8885aa25015d429b33713c314 Mon Sep 17 00:00:00 2001 From: Landon Yarrington <33426811+jly36963@users.noreply.github.com> Date: Mon, 15 Nov 2021 16:41:07 -0700 Subject: [PATCH] fix: parser should preserve inner quotes (#407) --- lib/yargs-parser.ts | 32 +++++++++++++++++++++----------- test/yargs-parser.cjs | 18 ++++++++++++++++-- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/yargs-parser.ts b/lib/yargs-parser.ts index ca7daac4..571a0cbc 100644 --- a/lib/yargs-parser.ts +++ b/lib/yargs-parser.ts @@ -59,6 +59,9 @@ export class YargsParser { // allow a string argument to be passed in rather // than an argv array. const args = tokenizeArgString(argsInput) + // tokenizeArgString adds extra quotes to args if argsInput is a string + // only strip those extra quotes in processValue if argsInput is a string + const inputIsString = typeof argsInput === 'string' // aliases might have transitive relationships, normalize this. const aliases = combineAliases(Object.assign(Object.create(null), opts.alias)) @@ -243,7 +246,7 @@ export class YargsParser { // nargs format = '--f=monkey washing cat' i = eatNargs(i, m[1], args, m[2]) } else { - setArg(m[1], m[2]) + setArg(m[1], m[2], true) } } } else if (arg.match(negatedBoolean) && configuration['boolean-negation']) { @@ -516,7 +519,7 @@ export class YargsParser { } else { // value in --option=value is eaten as is if (!isUndefined(argAfterEqualSign)) { - argsToSet.push(processValue(key, argAfterEqualSign)) + argsToSet.push(processValue(key, argAfterEqualSign, true)) } for (let ii = i + 1; ii < args.length; ii++) { if ((!configuration['greedy-arrays'] && argsToSet.length > 0) || @@ -524,7 +527,7 @@ export class YargsParser { next = args[ii] if (/^-/.test(next) && !negative.test(next) && !isUnknownOptionAsArg(next)) break i = ii - argsToSet.push(processValue(key, next)) + argsToSet.push(processValue(key, next, inputIsString)) } } @@ -540,7 +543,7 @@ export class YargsParser { return i } - function setArg (key: string, val: any): void { + function setArg (key: string, val: any, shouldStripQuotes: boolean = inputIsString): void { if (/-/.test(key) && configuration['camel-case-expansion']) { const alias = key.split('.').map(function (prop) { return camelCase(prop) @@ -548,7 +551,7 @@ export class YargsParser { addNewAlias(key, alias) } - const value = processValue(key, val) + const value = processValue(key, val, shouldStripQuotes) const splitKey = key.split('.') setKey(argv, splitKey, value) @@ -605,13 +608,10 @@ export class YargsParser { } } - function processValue (key: string, val: any) { + function processValue (key: string, val: any, shouldStripQuotes: boolean) { // strings may be quoted, clean this up as we assign values. - if (typeof val === 'string' && - (val[0] === "'" || val[0] === '"') && - val[val.length - 1] === val[0] - ) { - val = val.substring(1, val.length - 1) + if (shouldStripQuotes) { + val = stripQuotes(val) } // handle parsing boolean arguments --foo=true --bar false. @@ -1116,3 +1116,13 @@ function sanitizeKey (key: string): string { if (key === '__proto__') return '___proto___' return key } + +function stripQuotes (val: string): string { + return ( + typeof val === 'string' && + (val[0] === "'" || val[0] === '"') && + val[val.length - 1] === val[0] + ) + ? val.substring(1, val.length - 1) + : val +} diff --git a/test/yargs-parser.cjs b/test/yargs-parser.cjs index 95bee24a..aa6bf6bf 100644 --- a/test/yargs-parser.cjs +++ b/test/yargs-parser.cjs @@ -3569,7 +3569,7 @@ describe('yargs-parser', function () { args.foo.should.equal('hello world') args.bar.should.equal('goodnight\'moon') const args2 = parser(['--foo', '"hello world"', '--bar="goodnight\'moon"']) - args2.foo.should.equal('hello world') + args2.foo.should.equal('"hello world"') args2.bar.should.equal('goodnight\'moon') }) @@ -3578,7 +3578,7 @@ describe('yargs-parser', function () { args.foo.should.equal('hello world') args.bar.should.equal('goodnight"moon') const args2 = parser(['--foo', "'hello world'", "--bar='goodnight\"moon'"]) - args2.foo.should.equal('hello world') + args2.foo.should.equal("'hello world'") args2.bar.should.equal('goodnight"moon') }) @@ -3587,6 +3587,20 @@ describe('yargs-parser', function () { args.foo.should.equal('-hello world') args.bar.should.equal('--goodnight moon') }) + + it('respects inner quotes (string)', function () { + const args = parser('cmd --foo ""Hello"" --bar ""World"" --baz="":)""') + args.foo.should.equal('"Hello"') + args.bar.should.equal('"World"') + args.baz.should.equal('":)"') + }) + + it('respects inner quotes (array)', function () { + const args = parser(['cmd', '--foo', '"Hello"', '--bar', '"World"', '--baz="":)""']) + args.foo.should.equal('"Hello"') + args.bar.should.equal('"World"') + args.baz.should.equal('":)"') + }) }) // see: https://github.com/yargs/yargs-parser/issues/144