Updated from some -dev modules to alpha, beta or full releases
[yaffs-website] / node_modules / uncss / node_modules / qs / lib / parse.js
1 'use strict';
2
3 var Utils = require('./utils');
4
5 var internals = {
6     delimiter: '&',
7     depth: 5,
8     arrayLimit: 20,
9     parameterLimit: 1000,
10     strictNullHandling: false,
11     plainObjects: false,
12     allowPrototypes: false,
13     allowDots: false
14 };
15
16 var has = Object.prototype.hasOwnProperty;
17
18 internals.parseValues = function (str, options) {
19     var obj = {};
20     var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
21
22     for (var i = 0; i < parts.length; ++i) {
23         var part = parts[i];
24         var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
25
26         if (pos === -1) {
27             obj[Utils.decode(part)] = '';
28
29             if (options.strictNullHandling) {
30                 obj[Utils.decode(part)] = null;
31             }
32         } else {
33             var key = Utils.decode(part.slice(0, pos));
34             var val = Utils.decode(part.slice(pos + 1));
35
36             if (has.call(obj, key)) {
37                 obj[key] = [].concat(obj[key]).concat(val);
38             } else {
39                 obj[key] = val;
40             }
41         }
42     }
43
44     return obj;
45 };
46
47 internals.parseObject = function (chain, val, options) {
48     if (!chain.length) {
49         return val;
50     }
51
52     var root = chain.shift();
53
54     var obj;
55     if (root === '[]') {
56         obj = [];
57         obj = obj.concat(internals.parseObject(chain, val, options));
58     } else {
59         obj = options.plainObjects ? Object.create(null) : {};
60         var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root;
61         var index = parseInt(cleanRoot, 10);
62         if (
63             !isNaN(index) &&
64             root !== cleanRoot &&
65             String(index) === cleanRoot &&
66             index >= 0 &&
67             (options.parseArrays && index <= options.arrayLimit)
68         ) {
69             obj = [];
70             obj[index] = internals.parseObject(chain, val, options);
71         } else {
72             obj[cleanRoot] = internals.parseObject(chain, val, options);
73         }
74     }
75
76     return obj;
77 };
78
79 internals.parseKeys = function (givenKey, val, options) {
80     if (!givenKey) {
81         return;
82     }
83
84     // Transform dot notation to bracket notation
85     var key = options.allowDots ? givenKey.replace(/\.([^\.\[]+)/g, '[$1]') : givenKey;
86
87     // The regex chunks
88
89     var brackets = /(\[[^[\]]*])/;
90     var child = /(\[[^[\]]*])/g;
91
92     // Get the parent
93
94     var segment = brackets.exec(key);
95     var parent = segment ? key.slice(0, segment.index) : key;
96
97     // Stash the parent if it exists
98
99     var keys = [];
100     if (parent) {
101         // If we aren't using plain objects, optionally prefix keys
102         // that would overwrite object prototype properties
103         if (!options.plainObjects && has.call(Object.prototype, parent)) {
104             if (!options.allowPrototypes) {
105                 return;
106             }
107         }
108
109         keys.push(parent);
110     }
111
112     // Loop through children appending to the array until we hit depth
113
114     var i = 0;
115     while ((segment = child.exec(key)) !== null && i < options.depth) {
116         i += 1;
117         if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) {
118             if (!options.allowPrototypes) {
119                 return;
120             }
121         }
122         keys.push(segment[1]);
123     }
124
125     // If there's a remainder, just add whatever is left
126
127     if (segment) {
128         keys.push('[' + key.slice(segment.index) + ']');
129     }
130
131     return internals.parseObject(keys, val, options);
132 };
133
134 module.exports = function (str, opts) {
135     var options = opts || {};
136     options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
137     options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
138     options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
139     options.parseArrays = options.parseArrays !== false;
140     options.allowDots = typeof options.allowDots === 'boolean' ? options.allowDots : internals.allowDots;
141     options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : internals.plainObjects;
142     options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : internals.allowPrototypes;
143     options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
144     options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
145
146     if (
147         str === '' ||
148         str === null ||
149         typeof str === 'undefined'
150     ) {
151         return options.plainObjects ? Object.create(null) : {};
152     }
153
154     var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
155     var obj = options.plainObjects ? Object.create(null) : {};
156
157     // Iterate over the keys and setup the new object
158
159     var keys = Object.keys(tempObj);
160     for (var i = 0; i < keys.length; ++i) {
161         var key = keys[i];
162         var newObj = internals.parseKeys(key, tempObj[key], options);
163         obj = Utils.merge(obj, newObj, options);
164     }
165
166     return Utils.compact(obj);
167 };