Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81146 views
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
};
15
16
17
internals.parseValues = function (str, options) {
18
19
var obj = {};
20
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
21
22
for (var i = 0, il = parts.length; i < il; ++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
}
33
else {
34
var key = Utils.decode(part.slice(0, pos));
35
var val = Utils.decode(part.slice(pos + 1));
36
37
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
38
obj[key] = val;
39
}
40
else {
41
obj[key] = [].concat(obj[key]).concat(val);
42
}
43
}
44
}
45
46
return obj;
47
};
48
49
50
internals.parseObject = function (chain, val, options) {
51
52
if (!chain.length) {
53
return val;
54
}
55
56
var root = chain.shift();
57
58
var obj;
59
if (root === '[]') {
60
obj = [];
61
obj = obj.concat(internals.parseObject(chain, val, options));
62
}
63
else {
64
obj = Object.create(null);
65
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
66
var index = parseInt(cleanRoot, 10);
67
var indexString = '' + index;
68
if (!isNaN(index) &&
69
root !== cleanRoot &&
70
indexString === cleanRoot &&
71
index >= 0 &&
72
(options.parseArrays &&
73
index <= options.arrayLimit)) {
74
75
obj = [];
76
obj[index] = internals.parseObject(chain, val, options);
77
}
78
else {
79
obj[cleanRoot] = internals.parseObject(chain, val, options);
80
}
81
}
82
83
return obj;
84
};
85
86
87
internals.parseKeys = function (key, val, options) {
88
89
if (!key) {
90
return;
91
}
92
93
// Transform dot notation to bracket notation
94
95
if (options.allowDots) {
96
key = key.replace(/\.([^\.\[]+)/g, '[$1]');
97
}
98
99
// The regex chunks
100
101
var parent = /^([^\[\]]*)/;
102
var child = /(\[[^\[\]]*\])/g;
103
104
// Get the parent
105
106
var segment = parent.exec(key);
107
108
// Stash the parent if it exists
109
110
var keys = [];
111
if (segment[1]) {
112
keys.push(segment[1]);
113
}
114
115
// Loop through children appending to the array until we hit depth
116
117
var i = 0;
118
while ((segment = child.exec(key)) !== null && i < options.depth) {
119
120
++i;
121
keys.push(segment[1]);
122
}
123
124
// If there's a remainder, just add whatever is left
125
126
if (segment) {
127
keys.push('[' + key.slice(segment.index) + ']');
128
}
129
130
return internals.parseObject(keys, val, options);
131
};
132
133
134
module.exports = function (str, options) {
135
136
if (str === '' ||
137
str === null ||
138
typeof str === 'undefined') {
139
140
return Object.create(null);
141
}
142
143
options = options || {};
144
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter;
145
options.depth = typeof options.depth === 'number' ? options.depth : internals.depth;
146
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit;
147
options.parseArrays = options.parseArrays !== false;
148
options.allowDots = options.allowDots !== false;
149
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit;
150
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling;
151
152
153
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str;
154
var obj = Object.create(null);
155
156
// Iterate over the keys and setup the new object
157
158
var keys = Object.keys(tempObj);
159
for (var i = 0, il = keys.length; i < il; ++i) {
160
var key = keys[i];
161
var newObj = internals.parseKeys(key, tempObj[key], options);
162
obj = Utils.merge(obj, newObj);
163
}
164
165
return Utils.compact(obj);
166
};
167
168