| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 | 'use strict';var utils = require('./utils');var has = Object.prototype.hasOwnProperty;var defaults = {    allowDots: false,    allowPrototypes: false,    arrayLimit: 20,    decoder: utils.decode,    delimiter: '&',    depth: 5,    parameterLimit: 1000,    plainObjects: false,    strictNullHandling: false};var parseValues = function parseQueryStringValues(str, options) {    var obj = {};    var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);    for (var i = 0; i < parts.length; ++i) {        var part = parts[i];        var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;        var key, val;        if (pos === -1) {            key = options.decoder(part);            val = options.strictNullHandling ? null : '';        } else {            key = options.decoder(part.slice(0, pos));            val = options.decoder(part.slice(pos + 1));        }        if (has.call(obj, key)) {            obj[key] = [].concat(obj[key]).concat(val);        } else {            obj[key] = val;        }    }    return obj;};var parseObject = function parseObjectRecursive(chain, val, options) {    if (!chain.length) {        return val;    }    var root = chain.shift();    var obj;    if (root === '[]' && options.parseArrays) {        obj = [];        obj = obj.concat(parseObject(chain, val, options));    } else {        obj = options.plainObjects ? Object.create(null) : {};        var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;        var index = parseInt(cleanRoot, 10);        if (!options.parseArrays && cleanRoot === '') {            obj = { 0: val };        } else if (            !isNaN(index)            && root !== cleanRoot            && String(index) === cleanRoot            && index >= 0            && (options.parseArrays && index <= options.arrayLimit)        ) {            obj = [];            obj[index] = parseObject(chain, val, options);        } else if (cleanRoot !== '__proto__') {            obj[cleanRoot] = parseObject(chain, val, options);        }    }    return obj;};var parseKeys = function parseQueryStringKeys(givenKey, val, options) {    if (!givenKey) {        return;    }    // Transform dot notation to bracket notation    var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey;    // The regex chunks    var brackets = /(\[[^[\]]*])/;    var child = /(\[[^[\]]*])/g;    // Get the parent    var segment = brackets.exec(key);    var parent = segment ? key.slice(0, segment.index) : key;    // Stash the parent if it exists    var keys = [];    if (parent) {        // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties        if (!options.plainObjects && has.call(Object.prototype, parent)) {            if (!options.allowPrototypes) {                return;            }        }        keys.push(parent);    }    // Loop through children appending to the array until we hit depth    var i = 0;    while ((segment = child.exec(key)) !== null && i < options.depth) {        i += 1;        if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {            if (!options.allowPrototypes) {                return;            }        }        keys.push(segment[1]);    }    // If there's a remainder, just add whatever is left    if (segment) {        keys.push('[' + key.slice(segment.index) + ']');    }    return parseObject(keys, val, options);};module.exports = function (str, opts) {    var options = opts || {};    if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {        throw new TypeError('Decoder has to be a function.');    }    options.delimiter = typeof options.delimiter === 'string' || utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;    options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;    options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;    options.parseArrays = options.parseArrays !== false;    options.decoder = typeof options.decoder === 'function' ? options.decoder : defaults.decoder;    options.allowDots = typeof options.allowDots === 'boolean' ? options.allowDots : defaults.allowDots;    options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : defaults.plainObjects;    options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : defaults.allowPrototypes;    options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : defaults.parameterLimit;    options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;    if (str === '' || str === null || typeof str === 'undefined') {        return options.plainObjects ? Object.create(null) : {};    }    var tempObj = typeof str === 'string' ? parseValues(str, options) : str;    var obj = options.plainObjects ? Object.create(null) : {};    // Iterate over the keys and setup the new object    var keys = Object.keys(tempObj);    for (var i = 0; i < keys.length; ++i) {        var key = keys[i];        var newObj = parseKeys(key, tempObj[key], options);        obj = utils.merge(obj, newObj, options);    }    return utils.compact(obj);};
 |