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