diff --git a/lib/parse.js b/lib/parse.js index c46202eb..f95d9f9d 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -13,6 +13,8 @@ var internals = { allowDots: false }; +var has = Object.prototype.hasOwnProperty; + internals.parseValues = function (str, options) { var obj = {}; var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit); @@ -31,7 +33,7 @@ internals.parseValues = function (str, options) { var key = Utils.decode(part.slice(0, pos)); var val = Utils.decode(part.slice(pos + 1)); - if (Object.prototype.hasOwnProperty.call(obj, key)) { + if (has.call(obj, key)) { obj[key] = [].concat(obj[key]).concat(val); } else { obj[key] = val; @@ -84,26 +86,27 @@ internals.parseKeys = function (givenKey, val, options) { // The regex chunks - var parent = /^([^[]*)/; + var brackets = /(\[[^[\]]*])/; var child = /(\[[^[\]]*])/g; // Get the parent - var segment = parent.exec(key); + var segment = brackets.exec(key); + var parent = segment ? key.slice(0, segment.index) : key; // Stash the parent if it exists var keys = []; - if (segment[1]) { + if (parent) { // If we aren't using plain objects, optionally prefix keys // that would overwrite object prototype properties - if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) { + if (!options.plainObjects && has.call(Object.prototype, parent)) { if (!options.allowPrototypes) { return; } } - keys.push(segment[1]); + keys.push(parent); } // Loop through children appending to the array until we hit depth @@ -111,7 +114,7 @@ internals.parseKeys = function (givenKey, val, options) { var i = 0; while ((segment = child.exec(key)) !== null && i < options.depth) { i += 1; - if (!options.plainObjects && Object.prototype.hasOwnProperty.call(Object.prototype, segment[1].slice(1, -1))) { + if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) { if (!options.allowPrototypes) { return; } diff --git a/lib/utils.js b/lib/utils.js index d829b082..a80989fe 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -9,6 +9,8 @@ var hexTable = (function () { return array; }()); +var has = Object.prototype.hasOwnProperty; + exports.arrayToObject = function (source, options) { var obj = options.plainObjects ? Object.create(null) : {}; for (var i = 0; i < source.length; ++i) { @@ -51,7 +53,7 @@ exports.merge = function (target, source, options) { return Object.keys(source).reduce(function (acc, key) { var value = source[key]; - if (Object.prototype.hasOwnProperty.call(acc, key)) { + if (has.call(acc, key)) { acc[key] = exports.merge(acc[key], value, options); } else { acc[key] = value; diff --git a/test/parse.js b/test/parse.js index 65f6f287..35711823 100644 --- a/test/parse.js +++ b/test/parse.js @@ -399,16 +399,15 @@ test('parse()', function (t) { t.test('params starting with a closing bracket', function (st) { st.deepEqual(qs.parse(']=toString'), { ']': 'toString' }); + st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' }); + st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' }); st.end(); }); t.test('params starting with a starting bracket', function (st) { - st.deepEqual(qs.parse('[=toString'), {}); - st.end(); - }); - - t.test('params starting with a starting bracket', function (st) { - st.deepEqual(qs.parse('[=toString'), {}); + st.deepEqual(qs.parse('[=toString'), { '[': 'toString' }); + st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' }); + st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' }); st.end(); });