qs 6.1.2 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc +4 -2
- package/.jscs.json +176 -0
- package/CHANGELOG.md +5 -9
- package/dist/qs.js +86 -82
- package/lib/index.js +0 -0
- package/lib/parse.js +42 -42
- package/lib/stringify.js +36 -30
- package/lib/utils.js +8 -10
- package/package.json +9 -8
- package/test/parse.js +37 -70
- package/test/stringify.js +50 -4
- package/test/utils.js +0 -0
- package/.npmignore +0 -18
- package/.travis.yml +0 -173
- package/README.md +0 -335
- package/bower.json +0 -21
- package/component.json +0 -15
package/lib/parse.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var Utils = require('./utils');
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var defaults = {
|
|
6
6
|
delimiter: '&',
|
|
7
7
|
depth: 5,
|
|
8
8
|
arrayLimit: 20,
|
|
@@ -10,12 +10,11 @@ var internals = {
|
|
|
10
10
|
strictNullHandling: false,
|
|
11
11
|
plainObjects: false,
|
|
12
12
|
allowPrototypes: false,
|
|
13
|
-
allowDots: false
|
|
13
|
+
allowDots: false,
|
|
14
|
+
decoder: Utils.decode
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
var
|
|
17
|
-
|
|
18
|
-
internals.parseValues = function (str, options) {
|
|
17
|
+
var parseValues = function parseValues(str, options) {
|
|
19
18
|
var obj = {};
|
|
20
19
|
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit);
|
|
21
20
|
|
|
@@ -24,16 +23,16 @@ internals.parseValues = function (str, options) {
|
|
|
24
23
|
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1;
|
|
25
24
|
|
|
26
25
|
if (pos === -1) {
|
|
27
|
-
obj[
|
|
26
|
+
obj[options.decoder(part)] = '';
|
|
28
27
|
|
|
29
28
|
if (options.strictNullHandling) {
|
|
30
|
-
obj[
|
|
29
|
+
obj[options.decoder(part)] = null;
|
|
31
30
|
}
|
|
32
31
|
} else {
|
|
33
|
-
var key =
|
|
34
|
-
var val =
|
|
32
|
+
var key = options.decoder(part.slice(0, pos));
|
|
33
|
+
var val = options.decoder(part.slice(pos + 1));
|
|
35
34
|
|
|
36
|
-
if (
|
|
35
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
37
36
|
obj[key] = [].concat(obj[key]).concat(val);
|
|
38
37
|
} else {
|
|
39
38
|
obj[key] = val;
|
|
@@ -44,7 +43,7 @@ internals.parseValues = function (str, options) {
|
|
|
44
43
|
return obj;
|
|
45
44
|
};
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
var parseObject = function parseObject(chain, val, options) {
|
|
48
47
|
if (!chain.length) {
|
|
49
48
|
return val;
|
|
50
49
|
}
|
|
@@ -54,10 +53,10 @@ internals.parseObject = function (chain, val, options) {
|
|
|
54
53
|
var obj;
|
|
55
54
|
if (root === '[]') {
|
|
56
55
|
obj = [];
|
|
57
|
-
obj = obj.concat(
|
|
56
|
+
obj = obj.concat(parseObject(chain, val, options));
|
|
58
57
|
} else {
|
|
59
58
|
obj = options.plainObjects ? Object.create(null) : {};
|
|
60
|
-
var cleanRoot = root
|
|
59
|
+
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root;
|
|
61
60
|
var index = parseInt(cleanRoot, 10);
|
|
62
61
|
if (
|
|
63
62
|
!isNaN(index) &&
|
|
@@ -67,16 +66,16 @@ internals.parseObject = function (chain, val, options) {
|
|
|
67
66
|
(options.parseArrays && index <= options.arrayLimit)
|
|
68
67
|
) {
|
|
69
68
|
obj = [];
|
|
70
|
-
obj[index] =
|
|
69
|
+
obj[index] = parseObject(chain, val, options);
|
|
71
70
|
} else {
|
|
72
|
-
obj[cleanRoot] =
|
|
71
|
+
obj[cleanRoot] = parseObject(chain, val, options);
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
return obj;
|
|
77
76
|
};
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
var parseKeys = function parseKeys(givenKey, val, options) {
|
|
80
79
|
if (!givenKey) {
|
|
81
80
|
return;
|
|
82
81
|
}
|
|
@@ -86,27 +85,26 @@ internals.parseKeys = function (givenKey, val, options) {
|
|
|
86
85
|
|
|
87
86
|
// The regex chunks
|
|
88
87
|
|
|
89
|
-
var
|
|
90
|
-
var child = /(\[[
|
|
88
|
+
var parent = /^([^\[\]]*)/;
|
|
89
|
+
var child = /(\[[^\[\]]*\])/g;
|
|
91
90
|
|
|
92
91
|
// Get the parent
|
|
93
92
|
|
|
94
|
-
var segment =
|
|
95
|
-
var parent = segment ? key.slice(0, segment.index) : key;
|
|
93
|
+
var segment = parent.exec(key);
|
|
96
94
|
|
|
97
95
|
// Stash the parent if it exists
|
|
98
96
|
|
|
99
97
|
var keys = [];
|
|
100
|
-
if (
|
|
98
|
+
if (segment[1]) {
|
|
101
99
|
// If we aren't using plain objects, optionally prefix keys
|
|
102
100
|
// that would overwrite object prototype properties
|
|
103
|
-
if (!options.plainObjects &&
|
|
101
|
+
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) {
|
|
104
102
|
if (!options.allowPrototypes) {
|
|
105
103
|
return;
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
keys.push(
|
|
107
|
+
keys.push(segment[1]);
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
// Loop through children appending to the array until we hit depth
|
|
@@ -114,9 +112,9 @@ internals.parseKeys = function (givenKey, val, options) {
|
|
|
114
112
|
var i = 0;
|
|
115
113
|
while ((segment = child.exec(key)) !== null && i < options.depth) {
|
|
116
114
|
i += 1;
|
|
117
|
-
if (!options.plainObjects &&
|
|
115
|
+
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) {
|
|
118
116
|
if (!options.allowPrototypes) {
|
|
119
|
-
|
|
117
|
+
continue;
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
120
|
keys.push(segment[1]);
|
|
@@ -128,30 +126,32 @@ internals.parseKeys = function (givenKey, val, options) {
|
|
|
128
126
|
keys.push('[' + key.slice(segment.index) + ']');
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
return
|
|
129
|
+
return parseObject(keys, val, options);
|
|
132
130
|
};
|
|
133
131
|
|
|
134
132
|
module.exports = function (str, opts) {
|
|
135
133
|
var options = opts || {};
|
|
136
|
-
|
|
137
|
-
options.
|
|
138
|
-
|
|
134
|
+
|
|
135
|
+
if (options.decoder !== null && options.decoder !== undefined && typeof options.decoder !== 'function') {
|
|
136
|
+
throw new TypeError('Decoder has to be a function.');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : defaults.delimiter;
|
|
140
|
+
options.depth = typeof options.depth === 'number' ? options.depth : defaults.depth;
|
|
141
|
+
options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : defaults.arrayLimit;
|
|
139
142
|
options.parseArrays = options.parseArrays !== false;
|
|
140
|
-
options.
|
|
141
|
-
options.
|
|
142
|
-
options.
|
|
143
|
-
options.
|
|
144
|
-
options.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
str === null ||
|
|
149
|
-
typeof str === 'undefined'
|
|
150
|
-
) {
|
|
143
|
+
options.decoder = typeof options.decoder === 'function' ? options.decoder : defaults.decoder;
|
|
144
|
+
options.allowDots = typeof options.allowDots === 'boolean' ? options.allowDots : defaults.allowDots;
|
|
145
|
+
options.plainObjects = typeof options.plainObjects === 'boolean' ? options.plainObjects : defaults.plainObjects;
|
|
146
|
+
options.allowPrototypes = typeof options.allowPrototypes === 'boolean' ? options.allowPrototypes : defaults.allowPrototypes;
|
|
147
|
+
options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : defaults.parameterLimit;
|
|
148
|
+
options.strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
149
|
+
|
|
150
|
+
if (str === '' || str === null || typeof str === 'undefined') {
|
|
151
151
|
return options.plainObjects ? Object.create(null) : {};
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
var tempObj = typeof str === 'string' ?
|
|
154
|
+
var tempObj = typeof str === 'string' ? parseValues(str, options) : str;
|
|
155
155
|
var obj = options.plainObjects ? Object.create(null) : {};
|
|
156
156
|
|
|
157
157
|
// Iterate over the keys and setup the new object
|
|
@@ -159,7 +159,7 @@ module.exports = function (str, opts) {
|
|
|
159
159
|
var keys = Object.keys(tempObj);
|
|
160
160
|
for (var i = 0; i < keys.length; ++i) {
|
|
161
161
|
var key = keys[i];
|
|
162
|
-
var newObj =
|
|
162
|
+
var newObj = parseKeys(key, tempObj[key], options);
|
|
163
163
|
obj = Utils.merge(obj, newObj, options);
|
|
164
164
|
}
|
|
165
165
|
|
package/lib/stringify.js
CHANGED
|
@@ -2,45 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
var Utils = require('./utils');
|
|
4
4
|
|
|
5
|
-
var
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
indices: function (prefix, key) {
|
|
12
|
-
return prefix + '[' + key + ']';
|
|
13
|
-
},
|
|
14
|
-
repeat: function (prefix) {
|
|
15
|
-
return prefix;
|
|
16
|
-
}
|
|
5
|
+
var arrayPrefixGenerators = {
|
|
6
|
+
brackets: function brackets(prefix) {
|
|
7
|
+
return prefix + '[]';
|
|
8
|
+
},
|
|
9
|
+
indices: function indices(prefix, key) {
|
|
10
|
+
return prefix + '[' + key + ']';
|
|
17
11
|
},
|
|
12
|
+
repeat: function repeat(prefix) {
|
|
13
|
+
return prefix;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
var defaults = {
|
|
18
|
+
delimiter: '&',
|
|
18
19
|
strictNullHandling: false,
|
|
19
20
|
skipNulls: false,
|
|
20
|
-
encode: true
|
|
21
|
+
encode: true,
|
|
22
|
+
encoder: Utils.encode
|
|
21
23
|
};
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots) {
|
|
24
26
|
var obj = object;
|
|
25
27
|
if (typeof filter === 'function') {
|
|
26
28
|
obj = filter(prefix, obj);
|
|
27
|
-
} else if (Utils.isBuffer(obj)) {
|
|
28
|
-
obj = String(obj);
|
|
29
29
|
} else if (obj instanceof Date) {
|
|
30
30
|
obj = obj.toISOString();
|
|
31
31
|
} else if (obj === null) {
|
|
32
32
|
if (strictNullHandling) {
|
|
33
|
-
return
|
|
33
|
+
return encoder ? encoder(prefix) : prefix;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
obj = '';
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {
|
|
40
|
-
if (
|
|
41
|
-
return [
|
|
39
|
+
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || Utils.isBuffer(obj)) {
|
|
40
|
+
if (encoder) {
|
|
41
|
+
return [encoder(prefix) + '=' + encoder(obj)];
|
|
42
42
|
}
|
|
43
|
-
return [prefix + '=' + obj];
|
|
43
|
+
return [prefix + '=' + String(obj)];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
var values = [];
|
|
@@ -65,9 +65,9 @@ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullH
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
if (Array.isArray(obj)) {
|
|
68
|
-
values = values.concat(
|
|
68
|
+
values = values.concat(stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
|
|
69
69
|
} else {
|
|
70
|
-
values = values.concat(
|
|
70
|
+
values = values.concat(stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -77,14 +77,20 @@ internals.stringify = function (object, prefix, generateArrayPrefix, strictNullH
|
|
|
77
77
|
module.exports = function (object, opts) {
|
|
78
78
|
var obj = object;
|
|
79
79
|
var options = opts || {};
|
|
80
|
-
var delimiter = typeof options.delimiter === 'undefined' ?
|
|
81
|
-
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling :
|
|
82
|
-
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls :
|
|
83
|
-
var encode = typeof options.encode === 'boolean' ? options.encode :
|
|
80
|
+
var delimiter = typeof options.delimiter === 'undefined' ? defaults.delimiter : options.delimiter;
|
|
81
|
+
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : defaults.strictNullHandling;
|
|
82
|
+
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : defaults.skipNulls;
|
|
83
|
+
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode;
|
|
84
|
+
var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null;
|
|
84
85
|
var sort = typeof options.sort === 'function' ? options.sort : null;
|
|
85
86
|
var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots;
|
|
86
87
|
var objKeys;
|
|
87
88
|
var filter;
|
|
89
|
+
|
|
90
|
+
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') {
|
|
91
|
+
throw new TypeError('Encoder has to be a function.');
|
|
92
|
+
}
|
|
93
|
+
|
|
88
94
|
if (typeof options.filter === 'function') {
|
|
89
95
|
filter = options.filter;
|
|
90
96
|
obj = filter('', obj);
|
|
@@ -99,7 +105,7 @@ module.exports = function (object, opts) {
|
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
var arrayFormat;
|
|
102
|
-
if (options.arrayFormat in
|
|
108
|
+
if (options.arrayFormat in arrayPrefixGenerators) {
|
|
103
109
|
arrayFormat = options.arrayFormat;
|
|
104
110
|
} else if ('indices' in options) {
|
|
105
111
|
arrayFormat = options.indices ? 'indices' : 'repeat';
|
|
@@ -107,7 +113,7 @@ module.exports = function (object, opts) {
|
|
|
107
113
|
arrayFormat = 'indices';
|
|
108
114
|
}
|
|
109
115
|
|
|
110
|
-
var generateArrayPrefix =
|
|
116
|
+
var generateArrayPrefix = arrayPrefixGenerators[arrayFormat];
|
|
111
117
|
|
|
112
118
|
if (!objKeys) {
|
|
113
119
|
objKeys = Object.keys(obj);
|
|
@@ -124,7 +130,7 @@ module.exports = function (object, opts) {
|
|
|
124
130
|
continue;
|
|
125
131
|
}
|
|
126
132
|
|
|
127
|
-
keys = keys.concat(
|
|
133
|
+
keys = keys.concat(stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots));
|
|
128
134
|
}
|
|
129
135
|
|
|
130
136
|
return keys.join(delimiter);
|
package/lib/utils.js
CHANGED
|
@@ -9,8 +9,6 @@ var hexTable = (function () {
|
|
|
9
9
|
return array;
|
|
10
10
|
}());
|
|
11
11
|
|
|
12
|
-
var has = Object.prototype.hasOwnProperty;
|
|
13
|
-
|
|
14
12
|
exports.arrayToObject = function (source, options) {
|
|
15
13
|
var obj = options.plainObjects ? Object.create(null) : {};
|
|
16
14
|
for (var i = 0; i < source.length; ++i) {
|
|
@@ -31,9 +29,7 @@ exports.merge = function (target, source, options) {
|
|
|
31
29
|
if (Array.isArray(target)) {
|
|
32
30
|
target.push(source);
|
|
33
31
|
} else if (typeof target === 'object') {
|
|
34
|
-
|
|
35
|
-
target[source] = true;
|
|
36
|
-
}
|
|
32
|
+
target[source] = true;
|
|
37
33
|
} else {
|
|
38
34
|
return [target, source];
|
|
39
35
|
}
|
|
@@ -50,15 +46,15 @@ exports.merge = function (target, source, options) {
|
|
|
50
46
|
mergeTarget = exports.arrayToObject(target, options);
|
|
51
47
|
}
|
|
52
48
|
|
|
53
|
-
|
|
49
|
+
return Object.keys(source).reduce(function (acc, key) {
|
|
54
50
|
var value = source[key];
|
|
55
51
|
|
|
56
|
-
if (
|
|
52
|
+
if (Object.prototype.hasOwnProperty.call(acc, key)) {
|
|
57
53
|
acc[key] = exports.merge(acc[key], value, options);
|
|
58
54
|
} else {
|
|
59
55
|
acc[key] = value;
|
|
60
56
|
}
|
|
61
|
-
|
|
57
|
+
return acc;
|
|
62
58
|
}, mergeTarget);
|
|
63
59
|
};
|
|
64
60
|
|
|
@@ -113,7 +109,7 @@ exports.encode = function (str) {
|
|
|
113
109
|
|
|
114
110
|
i += 1;
|
|
115
111
|
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
|
|
116
|
-
out +=
|
|
112
|
+
out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)];
|
|
117
113
|
}
|
|
118
114
|
|
|
119
115
|
return out;
|
|
@@ -136,7 +132,9 @@ exports.compact = function (obj, references) {
|
|
|
136
132
|
var compacted = [];
|
|
137
133
|
|
|
138
134
|
for (var i = 0; i < obj.length; ++i) {
|
|
139
|
-
if (typeof obj[i]
|
|
135
|
+
if (obj[i] && typeof obj[i] === 'object') {
|
|
136
|
+
compacted.push(exports.compact(obj[i], refs));
|
|
137
|
+
} else if (typeof obj[i] !== 'undefined') {
|
|
140
138
|
compacted.push(obj[i]);
|
|
141
139
|
}
|
|
142
140
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "qs",
|
|
3
3
|
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
|
|
4
4
|
"homepage": "https://github.com/ljharb/qs",
|
|
5
|
-
"version": "6.
|
|
5
|
+
"version": "6.2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/ljharb/qs.git"
|
|
@@ -24,18 +24,19 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"browserify": "^
|
|
28
|
-
"tape": "^4.
|
|
27
|
+
"browserify": "^13.0.1",
|
|
28
|
+
"tape": "^4.5.1",
|
|
29
29
|
"covert": "^1.1.0",
|
|
30
30
|
"mkdirp": "^0.5.1",
|
|
31
|
-
"eslint": "^
|
|
32
|
-
"@ljharb/eslint-config": "^
|
|
31
|
+
"eslint": "^2.9.0",
|
|
32
|
+
"@ljharb/eslint-config": "^4.0.0",
|
|
33
33
|
"parallelshell": "^2.0.0",
|
|
34
|
-
"
|
|
34
|
+
"iconv-lite": "^0.4.13",
|
|
35
|
+
"evalmd": "^0.0.17"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
|
-
"pretest": "npm run
|
|
38
|
-
"test": "npm run coverage",
|
|
38
|
+
"pretest": "parallelshell 'npm run --silent readme' 'npm run --silent lint'",
|
|
39
|
+
"test": "npm run --silent coverage",
|
|
39
40
|
"tests-only": "node test",
|
|
40
41
|
"readme": "evalmd README.md",
|
|
41
42
|
"lint": "eslint lib/*.js text/*.js",
|
package/test/parse.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
|
+
var iconv = require('iconv-lite');
|
|
5
6
|
|
|
6
7
|
test('parse()', function (t) {
|
|
7
8
|
t.test('parses a simple string', function (st) {
|
|
@@ -120,11 +121,8 @@ test('parse()', function (t) {
|
|
|
120
121
|
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { '0': 'bar', bad: 'baz' } });
|
|
121
122
|
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', '0': 'bar', '1': 'foo' } });
|
|
122
123
|
st.deepEqual(qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb'), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] });
|
|
123
|
-
|
|
124
|
-
st.deepEqual(qs.parse('a[]=b&a[
|
|
125
|
-
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c', { allowPrototypes: true }), { a: { 0: 'b', t: 'u', hasOwnProperty: 'c' } });
|
|
126
|
-
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: false }), { a: { 0: 'b', x: 'y' } });
|
|
127
|
-
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y', { allowPrototypes: true }), { a: { 0: 'b', hasOwnProperty: 'c', x: 'y' } });
|
|
124
|
+
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c'), { a: { '0': 'b', t: 'u', c: true } });
|
|
125
|
+
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y'), { a: { '0': 'b', '1': 'c', x: 'y' } });
|
|
128
126
|
st.end();
|
|
129
127
|
});
|
|
130
128
|
|
|
@@ -142,6 +140,8 @@ test('parse()', function (t) {
|
|
|
142
140
|
st.end();
|
|
143
141
|
});
|
|
144
142
|
|
|
143
|
+
t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects');
|
|
144
|
+
|
|
145
145
|
t.test('correctly prunes undefined values when converting an array to an object', function (st) {
|
|
146
146
|
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { '2': 'b', '99999999': 'c' } });
|
|
147
147
|
st.end();
|
|
@@ -182,6 +182,9 @@ test('parse()', function (t) {
|
|
|
182
182
|
|
|
183
183
|
t.test('compacts sparse arrays', function (st) {
|
|
184
184
|
st.deepEqual(qs.parse('a[10]=1&a[2]=2'), { a: ['2', '1'] });
|
|
185
|
+
st.deepEqual(qs.parse('a[1][b][2][c]=1'), { a: [{ b: [{ c: '1' }] }] });
|
|
186
|
+
st.deepEqual(qs.parse('a[1][2][3][c]=1'), { a: [[[{ c: '1' }]]] });
|
|
187
|
+
st.deepEqual(qs.parse('a[1][2][3][c][1]=1'), { a: [[[{ c: ['1'] }]]] });
|
|
185
188
|
st.end();
|
|
186
189
|
});
|
|
187
190
|
|
|
@@ -371,75 +374,13 @@ test('parse()', function (t) {
|
|
|
371
374
|
st.end();
|
|
372
375
|
});
|
|
373
376
|
|
|
374
|
-
t.test('does not allow overwriting prototype properties', function (st) {
|
|
375
|
-
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: false }), {});
|
|
376
|
-
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: false }), {});
|
|
377
|
-
|
|
378
|
-
st.deepEqual(
|
|
379
|
-
qs.parse('toString', { allowPrototypes: false }),
|
|
380
|
-
{},
|
|
381
|
-
'bare "toString" results in {}'
|
|
382
|
-
);
|
|
383
|
-
|
|
384
|
-
st.end();
|
|
385
|
-
});
|
|
386
|
-
|
|
387
377
|
t.test('can allow overwriting prototype properties', function (st) {
|
|
388
|
-
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } });
|
|
389
|
-
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' });
|
|
390
|
-
|
|
391
|
-
st.deepEqual(
|
|
392
|
-
qs.parse('toString', { allowPrototypes: true }),
|
|
393
|
-
{ toString: '' },
|
|
394
|
-
'bare "toString" results in { toString: "" }'
|
|
395
|
-
);
|
|
396
|
-
|
|
397
|
-
st.end();
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
t.test('params starting with a closing bracket', function (st) {
|
|
401
|
-
st.deepEqual(qs.parse(']=toString'), { ']': 'toString' });
|
|
402
|
-
st.deepEqual(qs.parse(']]=toString'), { ']]': 'toString' });
|
|
403
|
-
st.deepEqual(qs.parse(']hello]=toString'), { ']hello]': 'toString' });
|
|
404
|
-
st.end();
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
t.test('params starting with a starting bracket', function (st) {
|
|
408
|
-
st.deepEqual(qs.parse('[=toString'), { '[': 'toString' });
|
|
409
|
-
st.deepEqual(qs.parse('[[=toString'), { '[[': 'toString' });
|
|
410
|
-
st.deepEqual(qs.parse('[hello[=toString'), { '[hello[': 'toString' });
|
|
378
|
+
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }, { prototype: false });
|
|
379
|
+
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }, { prototype: false });
|
|
411
380
|
st.end();
|
|
412
381
|
});
|
|
413
382
|
|
|
414
|
-
t.test('
|
|
415
|
-
st.deepEqual(
|
|
416
|
-
qs.parse('a[b]=c&a=d'),
|
|
417
|
-
{ a: { b: 'c', d: true } },
|
|
418
|
-
'can add keys to objects'
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
st.deepEqual(
|
|
422
|
-
qs.parse('a[b]=c&a=toString'),
|
|
423
|
-
{ a: { b: 'c' } },
|
|
424
|
-
'can not overwrite prototype'
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
st.deepEqual(
|
|
428
|
-
qs.parse('a[b]=c&a=toString', { allowPrototypes: true }),
|
|
429
|
-
{ a: { b: 'c', toString: true } },
|
|
430
|
-
'can overwrite prototype with allowPrototypes true'
|
|
431
|
-
);
|
|
432
|
-
|
|
433
|
-
st.deepEqual(
|
|
434
|
-
qs.parse('a[b]=c&a=toString', { plainObjects: true }),
|
|
435
|
-
{ a: { b: 'c', toString: true } },
|
|
436
|
-
'can overwrite prototype with plainObjects true'
|
|
437
|
-
);
|
|
438
|
-
|
|
439
|
-
st.end();
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
t.test('can return null objects', { skip: !Object.create }, function (st) {
|
|
383
|
+
t.test('can return plain objects', function (st) {
|
|
443
384
|
var expected = Object.create(null);
|
|
444
385
|
expected.a = Object.create(null);
|
|
445
386
|
expected.a.b = 'c';
|
|
@@ -453,4 +394,30 @@ test('parse()', function (t) {
|
|
|
453
394
|
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray);
|
|
454
395
|
st.end();
|
|
455
396
|
});
|
|
397
|
+
|
|
398
|
+
t.test('can parse with custom encoding', function (st) {
|
|
399
|
+
st.deepEqual(qs.parse('%8c%a7=%91%e5%8d%e3%95%7b', {
|
|
400
|
+
decoder: function (str) {
|
|
401
|
+
var reg = /\%([0-9A-F]{2})/ig;
|
|
402
|
+
var result = [];
|
|
403
|
+
var parts;
|
|
404
|
+
var last = 0;
|
|
405
|
+
while (parts = reg.exec(str)) {
|
|
406
|
+
result.push(parseInt(parts[1], 16));
|
|
407
|
+
last = parts.index + parts[0].length;
|
|
408
|
+
}
|
|
409
|
+
return iconv.decode(new Buffer(result), 'shift_jis').toString();
|
|
410
|
+
}
|
|
411
|
+
}), { 県: '大阪府' });
|
|
412
|
+
st.end();
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
t.test('throws error with wrong decoder', function (st) {
|
|
416
|
+
st.throws(function () {
|
|
417
|
+
qs.parse({}, {
|
|
418
|
+
decoder: 'string'
|
|
419
|
+
});
|
|
420
|
+
}, new TypeError('Decoder has to be a function.'));
|
|
421
|
+
st.end();
|
|
422
|
+
});
|
|
456
423
|
});
|
package/test/stringify.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var test = require('tape');
|
|
4
4
|
var qs = require('../');
|
|
5
|
+
var iconv = require('iconv-lite');
|
|
5
6
|
|
|
6
7
|
test('stringify()', function (t) {
|
|
7
8
|
t.test('stringifies a querystring object', function (st) {
|
|
@@ -21,7 +22,7 @@ test('stringify()', function (t) {
|
|
|
21
22
|
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
|
|
22
23
|
st.end();
|
|
23
24
|
});
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
t.test('stringifies a nested object with dots notation', function (st) {
|
|
26
27
|
st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
|
|
27
28
|
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
|
|
@@ -53,7 +54,7 @@ test('stringify()', function (t) {
|
|
|
53
54
|
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d');
|
|
54
55
|
st.end();
|
|
55
56
|
});
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
t.test('stringifies a nested array value with dots notation', function (st) {
|
|
58
59
|
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encode: false }), 'a.b[0]=c&a.b[1]=d');
|
|
59
60
|
st.end();
|
|
@@ -64,7 +65,12 @@ test('stringify()', function (t) {
|
|
|
64
65
|
st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }), 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1');
|
|
65
66
|
st.end();
|
|
66
67
|
});
|
|
67
|
-
|
|
68
|
+
|
|
69
|
+
t.test('stringifies an array with mixed objects and primitives', function (st) {
|
|
70
|
+
st.equal(qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }), 'a[0][b]=1&a[1]=2&a[2]=3');
|
|
71
|
+
st.end();
|
|
72
|
+
});
|
|
73
|
+
|
|
68
74
|
t.test('stringifies an object inside an array with dots notation', function (st) {
|
|
69
75
|
st.equal(qs.stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false }), 'a[0].b=c');
|
|
70
76
|
st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false }), 'a[0].b.c[0]=1');
|
|
@@ -249,11 +255,51 @@ test('stringify()', function (t) {
|
|
|
249
255
|
st.equal(qs.stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }), 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a');
|
|
250
256
|
st.end();
|
|
251
257
|
});
|
|
252
|
-
|
|
258
|
+
|
|
253
259
|
t.test('can sort the keys at depth 3 or more too', function (st) {
|
|
254
260
|
var sort = function (a, b) { return a.localeCompare(b); };
|
|
255
261
|
st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: sort, encode: false }), 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb');
|
|
256
262
|
st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: null, encode: false }), 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b');
|
|
257
263
|
st.end();
|
|
258
264
|
});
|
|
265
|
+
|
|
266
|
+
t.test('can stringify with custom encoding', function (st) {
|
|
267
|
+
st.equal(qs.stringify({ 県: '大阪府', '': ''}, {
|
|
268
|
+
encoder: function (str) {
|
|
269
|
+
if (str.length === 0) {
|
|
270
|
+
return '';
|
|
271
|
+
}
|
|
272
|
+
var buf = iconv.encode(str, 'shiftjis');
|
|
273
|
+
var result = [];
|
|
274
|
+
for (var i=0; i < buf.length; ++i) {
|
|
275
|
+
result.push(buf.readUInt8(i).toString(16));
|
|
276
|
+
}
|
|
277
|
+
return '%' + result.join('%');
|
|
278
|
+
}
|
|
279
|
+
}), '%8c%a7=%91%e5%8d%e3%95%7b&=');
|
|
280
|
+
st.end();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
t.test('throws error with wrong encoder', function (st) {
|
|
284
|
+
st.throws(function () {
|
|
285
|
+
qs.stringify({}, {
|
|
286
|
+
encoder: 'string'
|
|
287
|
+
});
|
|
288
|
+
}, new TypeError('Encoder has to be a function.'));
|
|
289
|
+
st.end();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
t.test('can use custom encoder for a buffer object', {
|
|
293
|
+
skip: typeof Buffer === 'undefined'
|
|
294
|
+
}, function (st) {
|
|
295
|
+
st.equal(qs.stringify({ a: new Buffer([1]) }, {
|
|
296
|
+
encoder: function (buffer) {
|
|
297
|
+
if (typeof buffer === 'string') {
|
|
298
|
+
return buffer;
|
|
299
|
+
}
|
|
300
|
+
return String.fromCharCode(buffer.readUInt8(0) + 97);
|
|
301
|
+
}
|
|
302
|
+
}), 'a=b');
|
|
303
|
+
st.end();
|
|
304
|
+
});
|
|
259
305
|
});
|
package/test/utils.js
CHANGED
|
File without changes
|