Skip to content

Commit

Permalink
Merge pull request #331 from bcoe/parse-string
Browse files Browse the repository at this point in the history
allow yargs.parse() and yargs(foo).argv to accept a raw argument string
  • Loading branch information
bcoe committed Jan 9, 2016
2 parents d387a3d + b43c8d1 commit 6b9890d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Upcoming

- [#331](https://github.com/bcoe/yargs/pull/331) Handle parsing a raw argument string (@kellyselden)
- [#325](https://github.com/bcoe/yargs/pull/325) Tweaks to make tests pass again on Windows (@isaacs)
- [#321](https://github.com/bcoe/yargs/pull/321) Custom config parsing function (@bcoe)

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,8 @@ Valid `opt` keys include:

Parse `args` instead of `process.argv`. Returns the `argv` object.

`args` may either be a pre-processed argv array, or a raw argument string.

.require(key, [msg | boolean])
------------------------------
.required(key, [msg | boolean])
Expand Down
10 changes: 10 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var assert = require('assert')
var Completion = require('./lib/completion')
var Parser = require('./lib/parser')
var path = require('path')
var tokenizeArgString = require('./lib/tokenize-arg-string')
var Usage = require('./lib/usage')
var Validation = require('./lib/validation')
var Y18n = require('y18n')
Expand Down Expand Up @@ -501,6 +502,8 @@ function Argv (processArgs, cwd) {
})

function parseArgs (args) {
args = normalizeArgs(args)

var parsed = Parser(args, options, y18n)
var argv = parsed.argv
var aliases = parsed.aliases
Expand Down Expand Up @@ -621,6 +624,13 @@ function Argv (processArgs, cwd) {
})
}

function normalizeArgs (args) {
if (typeof args === 'string') {
return tokenizeArgString(args)
}
return args
}

singletonify(self)
return self
}
Expand Down
32 changes: 32 additions & 0 deletions lib/tokenize-arg-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// take an un-split argv string and tokenize it.
module.exports = function (argString) {
var i = 0
var c = null
var opening = null
var args = []

for (var ii = 0; ii < argString.length; ii++) {
c = argString.charAt(ii)

// split on spaces unless we're in quotes.
if (c === ' ' && !opening) {
i++
continue
}

// don't split the string if we're in matching
// opening or closing single and double quotes.
if (c === opening) {
opening = null
continue
} else if ((c === "'" || c === '"') && !opening) {
opening = c
continue
}

if (!args[i]) args[i] = ''
args[i] += c
}

return args
}
40 changes: 40 additions & 0 deletions test/tokenize-arg-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* global describe, it */

var tokenizeArgString = require('../lib/tokenize-arg-string')

require('chai').should()

describe('TokenizeArgString', function () {
it('handles unquoted string', function () {
var args = tokenizeArgString('--foo 99')
args[0].should.equal('--foo')
args[1].should.equal('99')
})

it('handles quoted string with no spaces', function () {
var args = tokenizeArgString("--foo 'hello'")
args[0].should.equal('--foo')
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')
})

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')
})

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"')
})
})
34 changes: 34 additions & 0 deletions test/yargs.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,38 @@ describe('yargs dsl tests', function () {
expect(options.envPrefix).to.be.undefined
})
})

describe('parse', function () {
it('parses a simple string', function () {
var a1 = yargs.parse('-x=2 --foo=bar')
var a2 = yargs('-x=2 --foo=bar').argv
a1.x.should.equal(2)
a2.x.should.equal(2)

a1.foo.should.equal('bar')
a2.foo.should.equal('bar')
})

it('parses a quoted string', function () {
var a1 = yargs.parse('-x=\'marks "the" spot\' --foo "break \'dance\'"')
var a2 = yargs('-x=\'marks "the" spot\' --foo "break \'dance\'"').argv

a1.x.should.equal('marks "the" spot')
a2.x.should.equal('marks "the" spot')

a1.foo.should.equal("break 'dance'")
a2.foo.should.equal("break 'dance'")
})

it('parses an array', function () {
var a1 = yargs.parse(['-x', '99', '--why=hello world'])
var a2 = yargs(['-x', '99', '--why=hello world']).argv

a1.x.should.equal(99)
a2.x.should.equal(99)

a1.why.should.equal('hello world')
a2.why.should.equal('hello world')
})
})
})

0 comments on commit 6b9890d

Please sign in to comment.