Repository: yargs/yargs-parser
Pull request #16 (2016-04-01 21:47:41)

Fix issue with dot-expansion disabled and an alias of the first element of a dot-notation key
Calling this:
```javascript
var parsed = yargs(process.argv.slice(2), {
  alias: {'foo': 'f'},
  configuration: {'dot-notation': false}
})
```
With `--foo.bar "value"` results in the value being set to the key `'f.bar'`.

This fix removes the expansion of an alias of the first element of a dot-notation key, when dot-notation is disabled.

I simplified a bit the two loops that set aliases in `SetArg()`, because this new condition was making them a bit hard to follow. I moved one of the cases (calling `setKey()` for the full key if it doesn't have dot notation) from the second loop to the first loop. Here's how it looks now:
- The first loop calls `setKey()` for aliases of the full key, if the key key has dots or not.
- The second loop expands aliases of the first element in a dot-notation key, but only if dot-notation is enabled.


coveralls: 
[![Coverage Status](https://coveralls.io/builds/5635569/badge)](https://coveralls.io/builds/5635569)

Coverage remained the same at 100.0% when pulling **0c74f58219480b1f54030125e9a090798db3f1db on elas7:dot-notation** into **48b1e6a338f80417b3fd0fc3e39ae181332fdcb5 on yargs:master**.


Patch:
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index a399f75..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,5 +0,0 @@
-.nyc_output
-node_modules
-.DS_Store
-yargs-logo.png
-./test/fixtures/package.json
diff --git a/index.js b/index.js
index 834f8da..4a50d6a 100644
--- a/index.js
+++ b/index.js
@@ -240,12 +240,12 @@ function parse (args, opts) {
         } else {
           next = args[i + 1]
 
-          if (next && !/^(-|--)[^-]/.test(next) &&
+          if (next !== undefined && !/^(-|--)[^-]/.test(next) &&
             !checkAllAliases(key, flags.bools) &&
             !checkAllAliases(key, flags.counts)) {
             setArg(key, next)
             i++
-          } else if (next && /true|false/.test(next)) {
+          } else if (/true|false/.test(next)) {
             setArg(key, next)
             i++
           } else {
@@ -335,46 +335,48 @@ function parse (args, opts) {
       value = increment
     }
 
+    // Set normalized value when key is in 'normalize' and in 'arrays'
+    if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {
+      value = path.normalize(val)
+    }
+
     var splitKey = key.split('.')
     setKey(argv, splitKey, value)
 
-    // alias references an inner-value within
-    // a dot-notation object. see #279.
-    if (~key.indexOf('.') && flags.aliases[key]) {
+    // handle populating aliases of the full key
+    if (flags.aliases[key]) {
       flags.aliases[key].forEach(function (x) {
         x = x.split('.')
         setKey(argv, x, value)
       })
     }
 
-    ;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
-      x = x.split('.')
+    // handle populating aliases of the first element of the dot-notation key
+    if (splitKey.length > 1 && configuration['dot-notation']) {
+      ;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
+        x = x.split('.')
 
-      // handle populating dot notation for both
-      // the key and its aliases.
-      if (splitKey.length > 1) {
+        // expand alias with nested objects in key
         var a = [].concat(splitKey)
         a.shift() // nuke the old key.
         x = x.concat(a)
-      }
 
-      setKey(argv, x, value)
-    })
+        setKey(argv, x, value)
+      })
+    }
 
-    var keys = [key].concat(flags.aliases[key] || [])
-    for (var i = 0, l = keys.length; i < l; i++) {
-      if (flags.normalize[keys[i]]) {
-        keys.forEach(function (key) {
-          argv.__defineSetter__(key, function (v) {
-            val = path.normalize(v)
-          })
-
-          argv.__defineGetter__(key, function () {
-            return typeof val === 'string' ? path.normalize(val) : val
-          })
+    // Set normalize getter and setter when key is in 'normalize' but isn't an array
+    if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {
+      var keys = [key].concat(flags.aliases[key] || [])
+      keys.forEach(function (key) {
+        argv.__defineSetter__(key, function (v) {
+          val = path.normalize(v)
         })
-        break
-      }
+
+        argv.__defineGetter__(key, function () {
+          return typeof val === 'string' ? path.normalize(val) : val
+        })
+      })
     }
   }
 
@@ -494,7 +496,7 @@ function parse (args, opts) {
       o[key] = increment(o[key])
     } else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) {
       o[key] = Array.isArray(value) ? value : [value]
-    } else if (o[key] === undefined || typeof o[key] === 'boolean') {
+    } else if (o[key] === undefined || checkAllAliases(key, flags.bools)) {
       o[key] = value
     } else if (Array.isArray(o[key])) {
       o[key].push(value)
diff --git a/package.json b/package.json
index c2429e4..228265f 100644
--- a/package.json
+++ b/package.json
@@ -34,5 +34,9 @@
   "dependencies": {
     "camelcase": "^2.1.1",
     "lodash.assign": "^4.0.6"
-  }
+  },
+  "files": [
+    "lib",
+    "index.js"
+  ]
 }


Test patch:
diff --git a/test/yargs-parser.js b/test/yargs-parser.js
index ca1476c..a602742 100644
--- a/test/yargs-parser.js
+++ b/test/yargs-parser.js
@@ -40,6 +40,12 @@ describe('yargs-parser', function () {
     parse.should.have.property('_').with.length(0)
   })
 
+  it('should set the value of a single long option to the next supplied value, even if the value is empty', function () {
+    var parse = parser(['--pow', ''])
+    parse.should.have.property('pow', '')
+    parse.should.have.property('_').with.length(0)
+  })
+
   it('should set the value of a single long option if an = was used', function () {
     var parse = parser(['--pow=xixxle'])
     parse.should.have.property('pow', 'xixxle')
@@ -121,6 +127,12 @@ describe('yargs-parser', function () {
     argv._[0].should.be.a('number')
   })
 
+  it('should set the value of a single short option to the next supplied value, even if the value is empty', function () {
+    var parse = parser(['-p', ''])
+    parse.should.have.property('p', '')
+    parse.should.have.property('_').with.length(0)
+  })
+
   it('should not set the next value as the value of a short option if that option is explicitly defined as a boolean', function () {
     var parse = parser([ '-t', 'moo' ], {
       boolean: 't'
@@ -236,6 +248,19 @@ describe('yargs-parser', function () {
       a.s = ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep)
       a.s.should.equal(['', 'path', 'to', ''].join(path.sep))
     })
+
+    it('should normalize when key is also an array', function () {
+      var a = parser([ '-s', ['', 'tmp', '..', ''].join(path.sep), ['', 'path', 'to', 'new', 'dir', '..', '..', ''].join(path.sep) ], {
+        alias: {
+          s: ['save']
+        },
+        normalize: 's',
+        array: 's'
+      })
+      var expected = [path.sep, ['', 'path', 'to', ''].join(path.sep)]
+      a.should.have.property('s').and.deep.equal(expected)
+      a.should.have.property('save').and.deep.equal(expected)
+    })
   })
 
   describe('alias', function () {
@@ -866,7 +891,7 @@ describe('yargs-parser', function () {
     })
 
     describe('for boolean options', function () {
-      [true, false, undefined].forEach(function (def) {
+      [true, false, undefined, null].forEach(function (def) {
         describe('with explicit ' + def + ' default', function () {
           var opts = {
             default: {
@@ -1615,6 +1640,19 @@ describe('yargs-parser', function () {
 
         expect(parsed['alias.bar']).to.equal('abc')
       })
+
+      it('does not expand alias of first element of dot notation arguments', function () {
+        var parsed = parser(['--foo.bar', 'banana'], {
+          alias: {
+            'foo': ['f']
+          },
+          configuration: {
+            'dot-notation': false
+          }
+        })
+        expect(parsed['foo.bar']).to.equal('banana')
+        expect(parsed).not.to.include.keys('f.bar')
+      })
     })
 
     describe('parse numbers', function () {