From 2fb71b2b1d25316f94786a385616ebe34a6cbd73 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Sun, 27 Jan 2019 18:32:55 -0800 Subject: [PATCH] fix: better handling of quoted strings (#153) BREAKING CHANGE: quotes and beginning and endings of strings are not removed during parsing. --- example.js | 2 +- index.js | 9 +++++++++ lib/tokenize-arg-string.js | 2 -- test/tokenize-arg-string.js | 24 ++++++++++++------------ test/yargs-parser.js | 27 +++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/example.js b/example.js index 1c1ea630..cbfe167d 100755 --- a/example.js +++ b/example.js @@ -1,3 +1,3 @@ var parser = require('./') -var parse = parser(['-cats', 'meow']) +var parse = parser('--foo "-bar"') console.log(parse) diff --git a/index.js b/index.js index 69fa72dc..b628e7dd 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ function parse (args, opts) { // allow a string argument to be passed in rather // than an argv array. args = tokenizeArgString(args) + // aliases might have transitive relationships, normalize this. var aliases = combineAliases(opts.alias || {}) var configuration = assign({ @@ -450,6 +451,14 @@ function parse (args, opts) { } function processValue (key, val) { + // 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) + } + // handle parsing boolean arguments --foo=true --bar false. if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) { if (typeof val === 'string') val = val === 'true' diff --git a/lib/tokenize-arg-string.js b/lib/tokenize-arg-string.js index 73e14cd6..569f61ad 100644 --- a/lib/tokenize-arg-string.js +++ b/lib/tokenize-arg-string.js @@ -27,10 +27,8 @@ module.exports = function (argString) { if (c === opening) { if (!args[i]) args[i] = '' opening = null - continue } else if ((c === "'" || c === '"') && !opening) { opening = c - continue } if (!args[i]) args[i] = '' diff --git a/test/tokenize-arg-string.js b/test/tokenize-arg-string.js index 8bb6a95f..e33c2466 100644 --- a/test/tokenize-arg-string.js +++ b/test/tokenize-arg-string.js @@ -15,42 +15,42 @@ describe('TokenizeArgString', function () { it('handles quoted string with no spaces', function () { var args = tokenizeArgString("--foo 'hello'") args[0].should.equal('--foo') - args[1].should.equal('hello') + args[1].should.equal("'hello'") }) it('handles single quoted string with spaces', function () { var args = tokenizeArgString("--foo 'hello world' --bar='foo bar'") args[0].should.equal('--foo') - args[1].should.equal('hello world') - args[2].should.equal('--bar=foo bar') + args[1].should.equal("'hello world'") + args[2].should.equal("--bar='foo bar'") }) it('handles double quoted string with spaces', function () { var args = tokenizeArgString('--foo "hello world" --bar="foo bar"') args[0].should.equal('--foo') - args[1].should.equal('hello world') - args[2].should.equal('--bar=foo bar') + args[1].should.equal('"hello world"') + args[2].should.equal('--bar="foo bar"') }) it('handles single quoted empty string', function () { var args = tokenizeArgString('--foo \'\' --bar=\'\'') args[0].should.equal('--foo') - args[1].should.equal('') - args[2].should.equal('--bar=') + args[1].should.equal("''") + args[2].should.equal("--bar=''") }) it('handles double quoted empty string', function () { var args = tokenizeArgString('--foo "" --bar=""') args[0].should.equal('--foo') - args[1].should.equal('') - args[2].should.equal('--bar=') + args[1].should.equal('""') + args[2].should.equal('--bar=""') }) it('handles quoted string with embeded quotes', function () { var args = tokenizeArgString('--foo "hello \'world\'" --bar=\'foo "bar"\'') args[0].should.equal('--foo') - args[1].should.equal('hello \'world\'') - args[2].should.equal('--bar=foo "bar"') + args[1].should.equal('"hello \'world\'"') + args[2].should.equal('--bar=\'foo "bar"\'') }) // https://github.com/yargs/yargs-parser/pull/100 @@ -59,6 +59,6 @@ describe('TokenizeArgString', function () { var args = tokenizeArgString(' foo bar "foo bar" ') args[0].should.equal('foo') expect(args[1]).equal('bar') - expect(args[2]).equal('foo bar') + expect(args[2]).equal('"foo bar"') }) }) diff --git a/test/yargs-parser.js b/test/yargs-parser.js index f6420932..ea9f70e9 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -2796,4 +2796,31 @@ describe('yargs-parser', function () { argv.foo[3].bla.should.equal('banana') }) }) + + // see: https://github.com/yargs/yargs-parser/issues/145 + describe('strings with quotes and dashes', () => { + it('handles double quoted strings', function () { + const args = parser('--foo "hello world" --bar="goodnight\'moon"') + 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.bar.should.equal('goodnight\'moon') + }) + + it('handles single quoted strings', function () { + const args = parser("--foo 'hello world' --bar='goodnight\"moon'") + 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.bar.should.equal('goodnight"moon') + }) + + it('handles strings with dashes', function () { + const args = parser('--foo "-hello world" --bar="--goodnight moon"') + args.foo.should.equal('-hello world') + args.bar.should.equal('--goodnight moon') + }) + }) })