Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jQuery.deparam: coerce standalone keys to null values #60

Closed
wants to merge 10 commits into from
98 changes: 56 additions & 42 deletions jquery.ba-bbq.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,19 +451,22 @@
//
// Usage:
//
// > jQuery.deparam( params [, coerce ] );
// > jQuery.deparam( params [, coerce, standaloneKeys ] );
//
// Arguments:
//
// params - (String) A params string to be parsed.
// coerce - (Boolean) If true, coerces any numbers or true, false, null, and
// undefined to their actual value. Defaults to false if omitted.
// standaloneKeys - (Boolean) If true, keys without values are allowed in
// the input string, and will be returned as null. Defaults to false if
// omitted.
//
// Returns:
//
// (Object) An object representing the deserialized params string.

$.deparam = jq_deparam = function( params, coerce ) {
$.deparam = jq_deparam = function( params, coerce, standaloneKeys ) {
var obj = {},
coerce_types = { 'true': !0, 'false': !1, 'null': null };

Expand Down Expand Up @@ -507,48 +510,59 @@
: coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
: val; // string
}

if ( keys_last ) {
// Complex key, build deep object structure based on a few rules:
// * The 'cur' pointer starts at the object top-level.
// * [] = array push (n is set to array length), [n] = array if n is
// numeric, otherwise object.
// * If at the last keys part, set the value.
// * For each keys part, if the current level is undefined create an
// object or array based on the type of the next keys part.
// * Move the 'cur' pointer to the next level.
// * Rinse & repeat.
for ( ; i <= keys_last; i++ ) {
key = keys[i] === '' ? cur.length : keys[i];
cur = cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
: val;
}

} else {
// Simple key, even simpler rules, since only scalars and shallow
// arrays are allowed.

if ( $.isArray( obj[key] ) ) {
// val is already an array, so push on the next value.
obj[key].push( val );

} else if ( obj[key] !== undefined ) {
// val isn't an array, but since a second value has been specified,
// convert val into an array.
obj[key] = [ obj[key], val ];

} else {
// val is a scalar.
obj[key] = val;
}
}

} else if ( key ) {
}

else if ( param.length === 1 && key ) {
// No value was defined, so set something meaningful.
obj[key] = coerce
? undefined
val = coerce
? standaloneKeys
? null
: undefined
: '';

if (!standaloneKeys) {
// Backwards-compatibility:
// * Prior to the introduction of the standaloneKeys parameter, keys
// without corresponding values would result in an undefined entry
keys_last = false;
obj[key] = undefined;
}
}

if ( keys_last ) {
// Complex key, build deep object structure based on a few rules:
// * The 'cur' pointer starts at the object top-level.
// * [] = array push (n is set to array length), [n] = array if n is
// numeric, otherwise object.
// * If at the last keys part, set the value.
// * For each keys part, if the current level is undefined create an
// object or array based on the type of the next keys part.
// * Move the 'cur' pointer to the next level.
// * Rinse & repeat.
for ( ; i <= keys_last; i++ ) {
key = keys[i] === '' ? cur.length : keys[i];
cur = cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
: val;
}

} else if ( key ) {
// Simple key, even simpler rules, since only scalars and shallow
// arrays are allowed.

if ( $.isArray( obj[key] ) ) {
// val is already an array, so push on the next value.
obj[key].push( val );

} else if ( obj[key] !== undefined ) {
// val isn't an array, but since a second value has been specified,
// convert val into an array.
obj[key] = [ obj[key], val ];

} else {
// val is a scalar.
obj[key] = val;
}
}
});

Expand Down
8 changes: 4 additions & 4 deletions jquery.ba-bbq.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions unit/unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,24 @@ test( 'jQuery.deparam - pre-1.4-style params', function() {
same( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' );
});

test( 'jQuery.deparam - standalone keys', function() {
var params_str = 'a=1&a&b=2&c=3&c=undefined&c=&d&e[a]=4&e[b]&e[c]=';

// Backwards-compatibility test cases
var bc_params_obj = { a:'', b:'2', c:['3','undefined',''], d:'', e:{a:'4',c:''}, 'e[b]':'' },
bc_params_obj_coerce = { a:undefined, b:2, c:[3,undefined,''], d:undefined, e:{a:4,c:''}, 'e[b]':undefined };

// Intended-behaviour test cases
var params_obj = { a:['1',''], b:'2', c:['3','undefined',''], d:'', e:{a:'4',b:'',c:''} },
params_obj_coerce = { a:[1,null], b:2, c:[3,undefined,''], d:null, e:{a:4,b:null,c:''} };

expect( 4 );
same( $.deparam( params_str, false ), bc_params_obj, '$.deparam( String, false )' );
same( $.deparam( params_str, true ), bc_params_obj_coerce, '$.deparam( String, true )' );
same( $.deparam( params_str, false, true ), params_obj, '$.deparam( String, false, true )' );
same( $.deparam( params_str, true, true ), params_obj_coerce, '$.deparam( String, true, true )' );
});

test( 'jQuery.deparam.querystring', function() {
expect( 12 );

Expand Down