From ac90d46039850b17735d47717092e226a7035909 Mon Sep 17 00:00:00 2001 From: brn Date: Thu, 3 Aug 2017 21:40:46 +0900 Subject: [PATCH] Fix options key name conflict with commander object's' key (#404, #648, etc...). --- index.js | 20 +++++++++++--------- test/test.options.func.js | 8 ++++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index aacce61d5..d7d5f74c2 100644 --- a/index.js +++ b/index.js @@ -85,6 +85,7 @@ function Command(name) { this._allowUnknownOption = false; this._args = []; this._name = name || ''; + this._optionKeyValueHolder = Object.create(null); } /** @@ -357,6 +358,7 @@ Command.prototype.action = function(fn) { Command.prototype.option = function(flags, description, fn, defaultValue) { var self = this + , optionKeyValueHolder = this._optionKeyValueHolder , option = new Option(flags, description) , oname = option.name() , name = camelcase(oname); @@ -381,7 +383,7 @@ Command.prototype.option = function(flags, description, fn, defaultValue) { // when --no-* we make sure default is true if (false == option.bool) defaultValue = true; // preassign only if we have a default - if (undefined !== defaultValue) self[name] = defaultValue; + if (undefined !== defaultValue) self[name] = optionKeyValueHolder[name] = defaultValue; } // register the option @@ -391,23 +393,23 @@ Command.prototype.option = function(flags, description, fn, defaultValue) { // and conditionally invoke the callback this.on('option:' + oname, function(val) { // coercion - if (null !== val && fn) val = fn(val, undefined === self[name] + if (null !== val && fn) val = fn(val, undefined === optionKeyValueHolder[name] ? defaultValue - : self[name]); + : optionKeyValueHolder[name]); // unassigned or bool - if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + if ('boolean' == typeof optionKeyValueHolder[name] || 'undefined' == typeof optionKeyValueHolder[name]) { // if no value, bool true, and we have a default, then use it! if (null == val) { - self[name] = option.bool + self[name] = optionKeyValueHolder[name] = option.bool ? defaultValue || true : false; } else { - self[name] = val; + self[name] = optionKeyValueHolder[name] = val; } } else if (null !== val) { // reassign - self[name] = val; + self[name] = optionKeyValueHolder[name] = val; } }); @@ -751,12 +753,12 @@ Command.prototype.parseOptions = function(argv) { * @api public */ Command.prototype.opts = function() { - var result = {} + var result = Object.create(null) , len = this.options.length; for (var i = 0 ; i < len; i++) { var key = camelcase(this.options[i].name()); - result[key] = key === 'version' ? this._version : this[key]; + result[key] = key === 'version' ? this._version : this._optionKeyValueHolder[key]; } return result; }; diff --git a/test/test.options.func.js b/test/test.options.func.js index 1acb39124..2f1272d52 100644 --- a/test/test.options.func.js +++ b/test/test.options.func.js @@ -4,18 +4,22 @@ var program = require('../') program .version('0.0.1') .description('sdfdsfsfsdfdsf') + .option('-n, --name', 'confliced option') + .option('-n, --toString', 'confliced option') + .option('-n, --once', 'confliced option') .option('-f, --foo', 'add some foo') .option('-b, --bar', 'add some bar') .option('-M, --no-magic', 'disable magic') .option('-c, --camel-case', 'convert to camelCase') .option('-q, --quux ', 'add some quux'); -program.parse(['node', 'test', '--foo', '--bar', '--no-magic', '--camel-case', '--quux', 'value']); +program.parse(['node', 'test', '--name', '--toString', '--once', '--foo', '--bar', '--no-magic', '--camel-case', '--quux', 'value']); program.opts.should.be.a.Function; var opts = program.opts(); -opts.should.be.an.Object; opts.version.should.equal('0.0.1'); +opts.name.should.be.true; +opts.toString.should.be.true; opts.foo.should.be.true; opts.bar.should.be.true; opts.magic.should.be.false;