Skip to content

Commit a63ce5c

Browse files
Thomas Leery
authored andcommitted
Allow callers to disable PHP/Rails style parameter mungeing in querystring.stringify
1 parent 039d13b commit a63ce5c

3 files changed

Lines changed: 49 additions & 5 deletions

File tree

doc/api.markdown

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2459,7 +2459,7 @@ Take a base URL, and a href URL, and resolve them as a browser would for an anch
24592459

24602460
This module provides utilities for dealing with query strings. It provides the following methods:
24612461

2462-
### querystring.stringify(obj, sep='&', eq='=')
2462+
### querystring.stringify(obj, sep='&', eq='=', munge=true)
24632463

24642464
Serialize an object to a query string. Optionally override the default separator and assignment characters.
24652465
Example:
@@ -2468,6 +2468,32 @@ Example:
24682468
// returns
24692469
'foo=bar'
24702470

2471+
querystring.stringify({foo: 'bar', baz: 'bob'}, ';', ':')
2472+
// returns
2473+
'foo:bar;baz:bob'
2474+
2475+
By default, this function will perform PHP/Rails-style parameter mungeing for arrays and objects used as
2476+
values within `obj`.
2477+
Example:
2478+
2479+
querystring.stringify({foo: 'bar', foo: 'baz', foo: 'boz'})
2480+
// returns
2481+
'foo[]=bar&foo[]=baz&foo[]=boz'
2482+
2483+
querystring.stringify({foo: {bar: 'baz'}})
2484+
// returns
2485+
'foo[bar]=baz'
2486+
2487+
If you wish to disable the array mungeing (e.g. when generating parameters for a Java servlet), you
2488+
can set the `munge` argument to `false`.
2489+
Example:
2490+
2491+
querystring.stringify({foo: 'bar', foo: 'baz', foo: 'boz'}, '&', '=', false)
2492+
// returns
2493+
'foo=bar&foo=baz&foo=boz'
2494+
2495+
Note that when `munge` is `false`, parameter names with object values will still be munged.
2496+
24712497
### querystring.parse(str, sep='&', eq='=')
24722498

24732499
Deserialize a query string to an object. Optionally override the default separator and assignment characters.
@@ -2478,6 +2504,8 @@ Deserialize a query string to an object. Optionally override the default separa
24782504
, 'b': 'c'
24792505
}
24802506

2507+
This function can parse both munged and unmunged query strings (see `stringify` for details).
2508+
24812509
### querystring.escape
24822510

24832511
The escape function used by `querystring.stringify`, provided so that it could be overridden if necessary.

lib/querystring.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ var stack = [];
2121
* @param obj {Variant} any arbitrary value to convert to query string
2222
* @param sep {String} (optional) Character that should join param k=v pairs together. Default: "&"
2323
* @param eq {String} (optional) Character that should join keys to their values. Default: "="
24+
* @param munge {Boolean} (optional) Indicate whether array/object params should be munged, PHP/Rails-style. Default: true
2425
* @param name {String} (optional) Name of the current key, for handling children recursively.
2526
* @static
2627
*/
27-
QueryString.stringify = function (obj, sep, eq, name) {
28+
QueryString.stringify = function (obj, sep, eq, munge, name) {
29+
munge = typeof(munge) == "undefined" ? true : munge;
2830
sep = sep || "&";
2931
eq = eq || "=";
3032
if (isA(obj, null) || isA(obj, undefined) || typeof(obj) === 'function') {
@@ -37,9 +39,9 @@ QueryString.stringify = function (obj, sep, eq, name) {
3739
}
3840
if (isA(obj, [])) {
3941
var s = [];
40-
name = name+'[]';
42+
name = name+(munge ? '[]' : '');
4143
for (var i = 0, l = obj.length; i < l; i ++) {
42-
s.push( QueryString.stringify(obj[i], sep, eq, name) );
44+
s.push( QueryString.stringify(obj[i], sep, eq, munge, name) );
4345
}
4446
return s.join(sep);
4547
}
@@ -59,7 +61,7 @@ QueryString.stringify = function (obj, sep, eq, name) {
5961
for (var i = 0, l = keys.length; i < l; i++) {
6062
var key = keys[i];
6163
var n = begin + key + end;
62-
s.push(QueryString.stringify(obj[key], sep, eq, n));
64+
s.push(QueryString.stringify(obj[key], sep, eq, munge, n));
6365
}
6466

6567
stack.pop();

test/simple/test-querystring.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ var qsWeirdObjects = [
5858
];
5959
}
6060

61+
var qsNoMungeTestCases = [
62+
["", {}],
63+
["foo=bar&foo=baz", {"foo": ["bar", "baz"]}],
64+
["blah=burp", {"blah": "burp"}],
65+
["gragh=1&gragh=3&goo=2", {"gragh": ["1", "3"], "goo": "2"}],
66+
["frappucino=muffin&goat%5B%5D=scone&pond=moose",
67+
{"frappucino": "muffin", "goat[]": "scone", "pond": "moose"}],
68+
["obj%5Btrololol%5D=yes&obj%5Blololo%5D=no", {"obj": {"trololol": "yes", "lololo": "no"}}],
69+
];
70+
6171
// test that the canonical qs is parsed properly.
6272
qsTestCases.forEach(function (testCase) {
6373
assert.deepEqual(testCase[2], qs.parse(testCase[0]));
@@ -73,6 +83,10 @@ qsWeirdObjects.forEach(function (testCase) {
7383
assert.deepEqual(testCase[2], qs.parse(testCase[1]));
7484
});
7585

86+
qsNoMungeTestCases.forEach(function (testCase) {
87+
assert.deepEqual(testCase[0], qs.stringify(testCase[1], "&", "=", false));
88+
});
89+
7690
// test the nested qs-in-qs case
7791
var f = qs.parse("a=b&q=x%3Dy%26y%3Dz");
7892
f.q = qs.parse(f.q);

0 commit comments

Comments
 (0)