qs
Advanced tools
Comparing version 6.0.1 to 6.0.2
269
dist/qs.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Qs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
// Load modules | ||
'use strict'; | ||
@@ -7,8 +7,2 @@ var Stringify = require('./stringify'); | ||
// Declare internals | ||
var internals = {}; | ||
module.exports = { | ||
@@ -20,9 +14,6 @@ stringify: Stringify, | ||
},{"./parse":2,"./stringify":3}],2:[function(require,module,exports){ | ||
// Load modules | ||
'use strict'; | ||
var Utils = require('./utils'); | ||
// Declare internals | ||
var internals = { | ||
@@ -39,9 +30,7 @@ delimiter: '&', | ||
internals.parseValues = function (str, options) { | ||
var obj = {}; | ||
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit); | ||
for (var i = 0, il = parts.length; i < il; ++i) { | ||
for (var i = 0; i < parts.length; ++i) { | ||
var part = parts[i]; | ||
@@ -56,13 +45,11 @@ var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1; | ||
} | ||
} | ||
else { | ||
} else { | ||
var key = Utils.decode(part.slice(0, pos)); | ||
var val = Utils.decode(part.slice(pos + 1)); | ||
if (!Object.prototype.hasOwnProperty.call(obj, key)) { | ||
if (Object.prototype.hasOwnProperty.call(obj, key)) { | ||
obj[key] = [].concat(obj[key]).concat(val); | ||
} else { | ||
obj[key] = val; | ||
} | ||
else { | ||
obj[key] = [].concat(obj[key]).concat(val); | ||
} | ||
} | ||
@@ -74,5 +61,3 @@ } | ||
internals.parseObject = function (chain, val, options) { | ||
if (!chain.length) { | ||
@@ -88,19 +73,16 @@ return val; | ||
obj = obj.concat(internals.parseObject(chain, val, options)); | ||
} | ||
else { | ||
} else { | ||
obj = options.plainObjects ? Object.create(null) : {}; | ||
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root; | ||
var index = parseInt(cleanRoot, 10); | ||
var indexString = '' + index; | ||
if (!isNaN(index) && | ||
if ( | ||
!isNaN(index) && | ||
root !== cleanRoot && | ||
indexString === cleanRoot && | ||
String(index) === cleanRoot && | ||
index >= 0 && | ||
(options.parseArrays && | ||
index <= options.arrayLimit)) { | ||
(options.parseArrays && index <= options.arrayLimit) | ||
) { | ||
obj = []; | ||
obj[index] = internals.parseObject(chain, val, options); | ||
} | ||
else { | ||
} else { | ||
obj[cleanRoot] = internals.parseObject(chain, val, options); | ||
@@ -113,6 +95,4 @@ } | ||
internals.parseKeys = function (key, val, options) { | ||
if (!key) { | ||
internals.parseKeys = function (givenKey, val, options) { | ||
if (!givenKey) { | ||
return; | ||
@@ -122,7 +102,4 @@ } | ||
// Transform dot notation to bracket notation | ||
var key = options.allowDots ? givenKey.replace(/\.([^\.\[]+)/g, '[$1]') : givenKey; | ||
if (options.allowDots) { | ||
key = key.replace(/\.([^\.\[]+)/g, '[$1]'); | ||
} | ||
// The regex chunks | ||
@@ -143,5 +120,3 @@ | ||
// that would overwrite object prototype properties | ||
if (!options.plainObjects && | ||
Object.prototype.hasOwnProperty(segment[1])) { | ||
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) { | ||
if (!options.allowPrototypes) { | ||
@@ -159,7 +134,4 @@ return; | ||
while ((segment = child.exec(key)) !== null && i < options.depth) { | ||
++i; | ||
if (!options.plainObjects && | ||
Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { | ||
i += 1; | ||
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { | ||
if (!options.allowPrototypes) { | ||
@@ -181,6 +153,4 @@ continue; | ||
module.exports = function (str, options) { | ||
options = options || {}; | ||
module.exports = function (str, opts) { | ||
var options = opts || {}; | ||
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter; | ||
@@ -196,6 +166,7 @@ options.depth = typeof options.depth === 'number' ? options.depth : internals.depth; | ||
if (str === '' || | ||
if ( | ||
str === '' || | ||
str === null || | ||
typeof str === 'undefined') { | ||
typeof str === 'undefined' | ||
) { | ||
return options.plainObjects ? Object.create(null) : {}; | ||
@@ -210,3 +181,3 @@ } | ||
var keys = Object.keys(tempObj); | ||
for (var i = 0, il = keys.length; i < il; ++i) { | ||
for (var i = 0; i < keys.length; ++i) { | ||
var key = keys[i]; | ||
@@ -221,22 +192,16 @@ var newObj = internals.parseKeys(key, tempObj[key], options); | ||
},{"./utils":4}],3:[function(require,module,exports){ | ||
// Load modules | ||
'use strict'; | ||
var Utils = require('./utils'); | ||
// Declare internals | ||
var internals = { | ||
delimiter: '&', | ||
arrayPrefixGenerators: { | ||
brackets: function (prefix, key) { | ||
brackets: function (prefix) { | ||
return prefix + '[]'; | ||
}, | ||
indices: function (prefix, key) { | ||
return prefix + '[' + key + ']'; | ||
}, | ||
repeat: function (prefix, key) { | ||
repeat: function (prefix) { | ||
return prefix; | ||
@@ -250,15 +215,11 @@ } | ||
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) { | ||
internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) { | ||
var obj = object; | ||
if (typeof filter === 'function') { | ||
obj = filter(prefix, obj); | ||
} | ||
else if (Utils.isBuffer(obj)) { | ||
obj = obj.toString(); | ||
} | ||
else if (obj instanceof Date) { | ||
} else if (Utils.isBuffer(obj)) { | ||
obj = String(obj); | ||
} else if (obj instanceof Date) { | ||
obj = obj.toISOString(); | ||
} | ||
else if (obj === null) { | ||
} else if (obj === null) { | ||
if (strictNullHandling) { | ||
@@ -271,6 +232,3 @@ return encode ? Utils.encode(prefix) : prefix; | ||
if (typeof obj === 'string' || | ||
typeof obj === 'number' || | ||
typeof obj === 'boolean') { | ||
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') { | ||
if (encode) { | ||
@@ -296,8 +254,6 @@ return [Utils.encode(prefix) + '=' + Utils.encode(obj)]; | ||
for (var i = 0, il = objKeys.length; i < il; ++i) { | ||
for (var i = 0; i < objKeys.length; ++i) { | ||
var key = objKeys[i]; | ||
if (skipNulls && | ||
obj[key] === null) { | ||
if (skipNulls && obj[key] === null) { | ||
continue; | ||
@@ -308,4 +264,3 @@ } | ||
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter)); | ||
} | ||
else { | ||
} else { | ||
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter)); | ||
@@ -318,6 +273,5 @@ } | ||
module.exports = function (obj, options) { | ||
options = options || {}; | ||
module.exports = function (object, opts) { | ||
var obj = object; | ||
var options = opts || {}; | ||
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter; | ||
@@ -333,4 +287,3 @@ var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling; | ||
obj = filter('', obj); | ||
} | ||
else if (Array.isArray(options.filter)) { | ||
} else if (Array.isArray(options.filter)) { | ||
objKeys = filter = options.filter; | ||
@@ -341,5 +294,3 @@ } | ||
if (typeof obj !== 'object' || | ||
obj === null) { | ||
if (typeof obj !== 'object' || obj === null) { | ||
return ''; | ||
@@ -351,7 +302,5 @@ } | ||
arrayFormat = options.arrayFormat; | ||
} | ||
else if ('indices' in options) { | ||
} else if ('indices' in options) { | ||
arrayFormat = options.indices ? 'indices' : 'repeat'; | ||
} | ||
else { | ||
} else { | ||
arrayFormat = 'indices'; | ||
@@ -370,8 +319,6 @@ } | ||
for (var i = 0, il = objKeys.length; i < il; ++i) { | ||
for (var i = 0; i < objKeys.length; ++i) { | ||
var key = objKeys[i]; | ||
if (skipNulls && | ||
obj[key] === null) { | ||
if (skipNulls && obj[key] === null) { | ||
continue; | ||
@@ -387,20 +334,17 @@ } | ||
},{"./utils":4}],4:[function(require,module,exports){ | ||
// Load modules | ||
'use strict'; | ||
var hexTable = (function () { | ||
var array = new Array(256); | ||
for (var i = 0; i < 256; ++i) { | ||
array[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); | ||
} | ||
// Declare internals | ||
return array; | ||
}()); | ||
var internals = {}; | ||
internals.hexTable = new Array(256); | ||
for (var h = 0; h < 256; ++h) { | ||
internals.hexTable[h] = '%' + ((h < 16 ? '0' : '') + h.toString(16)).toUpperCase(); | ||
} | ||
exports.arrayToObject = function (source, options) { | ||
var obj = options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0, il = source.length; i < il; ++i) { | ||
for (var i = 0; i < source.length; ++i) { | ||
if (typeof source[i] !== 'undefined') { | ||
obj[i] = source[i]; | ||
@@ -413,5 +357,3 @@ } | ||
exports.merge = function (target, source, options) { | ||
if (!source) { | ||
@@ -424,9 +366,7 @@ return target; | ||
target.push(source); | ||
} | ||
else if (typeof target === 'object') { | ||
} else if (typeof target === 'object') { | ||
target[source] = true; | ||
} else { | ||
return [target, source]; | ||
} | ||
else { | ||
target = [target, source]; | ||
} | ||
@@ -437,31 +377,23 @@ return target; | ||
if (typeof target !== 'object') { | ||
target = [target].concat(source); | ||
return target; | ||
return [target].concat(source); | ||
} | ||
if (Array.isArray(target) && | ||
!Array.isArray(source)) { | ||
target = exports.arrayToObject(target, options); | ||
var mergeTarget = target; | ||
if (Array.isArray(target) && !Array.isArray(source)) { | ||
mergeTarget = exports.arrayToObject(target, options); | ||
} | ||
var keys = Object.keys(source); | ||
for (var k = 0, kl = keys.length; k < kl; ++k) { | ||
var key = keys[k]; | ||
return Object.keys(source).reduce(function (acc, key) { | ||
var value = source[key]; | ||
if (!Object.prototype.hasOwnProperty.call(target, key)) { | ||
target[key] = value; | ||
if (Object.prototype.hasOwnProperty.call(acc, key)) { | ||
acc[key] = exports.merge(acc[key], value, options); | ||
} else { | ||
acc[key] = value; | ||
} | ||
else { | ||
target[key] = exports.merge(target[key], value, options); | ||
} | ||
} | ||
return target; | ||
return acc; | ||
}, mergeTarget); | ||
}; | ||
exports.decode = function (str) { | ||
try { | ||
@@ -475,3 +407,2 @@ return decodeURIComponent(str.replace(/\+/g, ' ')); | ||
exports.encode = function (str) { | ||
// This code was originally written by Brian White (mscdex) for the io.js core querystring library. | ||
@@ -483,11 +414,10 @@ // It has been adapted here for stricter adherence to RFC 3986 | ||
if (typeof str !== 'string') { | ||
str = '' + str; | ||
} | ||
var string = typeof str === 'string' ? str : String(str); | ||
var out = ''; | ||
for (var i = 0, il = str.length; i < il; ++i) { | ||
var c = str.charCodeAt(i); | ||
for (var i = 0; i < string.length; ++i) { | ||
var c = string.charCodeAt(i); | ||
if (c === 0x2D || // - | ||
if ( | ||
c === 0x2D || // - | ||
c === 0x2E || // . | ||
@@ -498,5 +428,5 @@ c === 0x5F || // _ | ||
(c >= 0x41 && c <= 0x5A) || // a-z | ||
(c >= 0x61 && c <= 0x7A)) { // A-Z | ||
out += str[i]; | ||
(c >= 0x61 && c <= 0x7A) // A-Z | ||
) { | ||
out += string.charAt(i); | ||
continue; | ||
@@ -506,3 +436,3 @@ } | ||
if (c < 0x80) { | ||
out += internals.hexTable[c]; | ||
out = out + hexTable[c]; | ||
continue; | ||
@@ -512,3 +442,3 @@ } | ||
if (c < 0x800) { | ||
out += internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); | ||
continue; | ||
@@ -518,9 +448,9 @@ } | ||
if (c < 0xD800 || c >= 0xE000) { | ||
out += internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); | ||
continue; | ||
} | ||
++i; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF)); | ||
out += internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]; | ||
i += 1; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); | ||
out += (hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); | ||
} | ||
@@ -531,11 +461,8 @@ | ||
exports.compact = function (obj, refs) { | ||
if (typeof obj !== 'object' || | ||
obj === null) { | ||
exports.compact = function (obj, references) { | ||
if (typeof obj !== 'object' || obj === null) { | ||
return obj; | ||
} | ||
refs = refs || []; | ||
var refs = references || []; | ||
var lookup = refs.indexOf(obj); | ||
@@ -551,3 +478,3 @@ if (lookup !== -1) { | ||
for (var i = 0, il = obj.length; i < il; ++i) { | ||
for (var i = 0; i < obj.length; ++i) { | ||
if (typeof obj[i] !== 'undefined') { | ||
@@ -562,4 +489,4 @@ compacted.push(obj[i]); | ||
var keys = Object.keys(obj); | ||
for (i = 0, il = keys.length; i < il; ++i) { | ||
var key = keys[i]; | ||
for (var j = 0; j < keys.length; ++j) { | ||
var key = keys[j]; | ||
obj[key] = exports.compact(obj[key], refs); | ||
@@ -571,20 +498,12 @@ } | ||
exports.isRegExp = function (obj) { | ||
return Object.prototype.toString.call(obj) === '[object RegExp]'; | ||
}; | ||
exports.isBuffer = function (obj) { | ||
if (obj === null || | ||
typeof obj === 'undefined') { | ||
if (obj === null || typeof obj === 'undefined') { | ||
return false; | ||
} | ||
return !!(obj.constructor && | ||
obj.constructor.isBuffer && | ||
obj.constructor.isBuffer(obj)); | ||
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); | ||
}; | ||
@@ -591,0 +510,0 @@ |
'use strict'; | ||
// Load modules | ||
var Stringify = require('./stringify'); | ||
var Parse = require('./parse'); | ||
const Stringify = require('./stringify'); | ||
const Parse = require('./parse'); | ||
// Declare internals | ||
const internals = {}; | ||
exports.stringify = Stringify; | ||
exports.parse = Parse; | ||
module.exports = { | ||
stringify: Stringify, | ||
parse: Parse | ||
}; |
119
lib/parse.js
'use strict'; | ||
// Load modules | ||
var Utils = require('./utils'); | ||
const Utils = require('./utils'); | ||
// Declare internals | ||
const internals = { | ||
var internals = { | ||
delimiter: '&', | ||
@@ -21,12 +16,10 @@ depth: 5, | ||
internals.parseValues = function (str, options) { | ||
var obj = {}; | ||
var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit); | ||
const obj = {}; | ||
const parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit); | ||
for (var i = 0; i < parts.length; ++i) { | ||
var part = parts[i]; | ||
var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1; | ||
for (let i = 0; i < parts.length; ++i) { | ||
const part = parts[i]; | ||
const pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1; | ||
if (pos === -1) { | ||
@@ -38,13 +31,11 @@ obj[Utils.decode(part)] = ''; | ||
} | ||
} | ||
else { | ||
const key = Utils.decode(part.slice(0, pos)); | ||
const val = Utils.decode(part.slice(pos + 1)); | ||
} else { | ||
var key = Utils.decode(part.slice(0, pos)); | ||
var val = Utils.decode(part.slice(pos + 1)); | ||
if (!Object.prototype.hasOwnProperty.call(obj, key)) { | ||
if (Object.prototype.hasOwnProperty.call(obj, key)) { | ||
obj[key] = [].concat(obj[key]).concat(val); | ||
} else { | ||
obj[key] = val; | ||
} | ||
else { | ||
obj[key] = [].concat(obj[key]).concat(val); | ||
} | ||
} | ||
@@ -56,5 +47,3 @@ } | ||
internals.parseObject = function (chain, val, options) { | ||
if (!chain.length) { | ||
@@ -64,25 +53,22 @@ return val; | ||
const root = chain.shift(); | ||
var root = chain.shift(); | ||
let obj; | ||
var obj; | ||
if (root === '[]') { | ||
obj = []; | ||
obj = obj.concat(internals.parseObject(chain, val, options)); | ||
} | ||
else { | ||
} else { | ||
obj = options.plainObjects ? Object.create(null) : {}; | ||
const cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root; | ||
const index = parseInt(cleanRoot, 10); | ||
const indexString = '' + index; | ||
if (!isNaN(index) && | ||
var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root; | ||
var index = parseInt(cleanRoot, 10); | ||
if ( | ||
!isNaN(index) && | ||
root !== cleanRoot && | ||
indexString === cleanRoot && | ||
String(index) === cleanRoot && | ||
index >= 0 && | ||
(options.parseArrays && | ||
index <= options.arrayLimit)) { | ||
(options.parseArrays && index <= options.arrayLimit) | ||
) { | ||
obj = []; | ||
obj[index] = internals.parseObject(chain, val, options); | ||
} | ||
else { | ||
} else { | ||
obj[cleanRoot] = internals.parseObject(chain, val, options); | ||
@@ -95,6 +81,4 @@ } | ||
internals.parseKeys = function (key, val, options) { | ||
if (!key) { | ||
internals.parseKeys = function (givenKey, val, options) { | ||
if (!givenKey) { | ||
return; | ||
@@ -104,25 +88,20 @@ } | ||
// Transform dot notation to bracket notation | ||
var key = options.allowDots ? givenKey.replace(/\.([^\.\[]+)/g, '[$1]') : givenKey; | ||
if (options.allowDots) { | ||
key = key.replace(/\.([^\.\[]+)/g, '[$1]'); | ||
} | ||
// The regex chunks | ||
const parent = /^([^\[\]]*)/; | ||
const child = /(\[[^\[\]]*\])/g; | ||
var parent = /^([^\[\]]*)/; | ||
var child = /(\[[^\[\]]*\])/g; | ||
// Get the parent | ||
let segment = parent.exec(key); | ||
var segment = parent.exec(key); | ||
// Stash the parent if it exists | ||
const keys = []; | ||
var keys = []; | ||
if (segment[1]) { | ||
// If we aren't using plain objects, optionally prefix keys | ||
// that would overwrite object prototype properties | ||
if (!options.plainObjects && | ||
Object.prototype.hasOwnProperty(segment[1])) { | ||
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1])) { | ||
if (!options.allowPrototypes) { | ||
@@ -138,9 +117,6 @@ return; | ||
let i = 0; | ||
var i = 0; | ||
while ((segment = child.exec(key)) !== null && i < options.depth) { | ||
++i; | ||
if (!options.plainObjects && | ||
Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { | ||
i += 1; | ||
if (!options.plainObjects && Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { | ||
if (!options.allowPrototypes) { | ||
@@ -162,6 +138,4 @@ continue; | ||
module.exports = function (str, options) { | ||
options = options || {}; | ||
module.exports = function (str, opts) { | ||
var options = opts || {}; | ||
options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter; | ||
@@ -177,18 +151,19 @@ options.depth = typeof options.depth === 'number' ? options.depth : internals.depth; | ||
if (str === '' || | ||
if ( | ||
str === '' || | ||
str === null || | ||
typeof str === 'undefined') { | ||
typeof str === 'undefined' | ||
) { | ||
return options.plainObjects ? Object.create(null) : {}; | ||
} | ||
const tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str; | ||
let obj = options.plainObjects ? Object.create(null) : {}; | ||
var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str; | ||
var obj = options.plainObjects ? Object.create(null) : {}; | ||
// Iterate over the keys and setup the new object | ||
const keys = Object.keys(tempObj); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const key = keys[i]; | ||
const newObj = internals.parseKeys(key, tempObj[key], options); | ||
var keys = Object.keys(tempObj); | ||
for (var i = 0; i < keys.length; ++i) { | ||
var key = keys[i]; | ||
var newObj = internals.parseKeys(key, tempObj[key], options); | ||
obj = Utils.merge(obj, newObj, options); | ||
@@ -195,0 +170,0 @@ } |
'use strict'; | ||
// Load modules | ||
var Utils = require('./utils'); | ||
const Utils = require('./utils'); | ||
// Declare internals | ||
const internals = { | ||
var internals = { | ||
delimiter: '&', | ||
arrayPrefixGenerators: { | ||
brackets: function (prefix, key) { | ||
brackets: function (prefix) { | ||
return prefix + '[]'; | ||
}, | ||
indices: function (prefix, key) { | ||
return prefix + '[' + key + ']'; | ||
}, | ||
repeat: function (prefix, key) { | ||
repeat: function (prefix) { | ||
return prefix; | ||
@@ -31,15 +23,11 @@ } | ||
internals.stringify = function (obj, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) { | ||
internals.stringify = function (object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encode, filter, sort) { | ||
var obj = object; | ||
if (typeof filter === 'function') { | ||
obj = filter(prefix, obj); | ||
} | ||
else if (Utils.isBuffer(obj)) { | ||
obj = obj.toString(); | ||
} | ||
else if (obj instanceof Date) { | ||
} else if (Utils.isBuffer(obj)) { | ||
obj = String(obj); | ||
} else if (obj instanceof Date) { | ||
obj = obj.toISOString(); | ||
} | ||
else if (obj === null) { | ||
} else if (obj === null) { | ||
if (strictNullHandling) { | ||
@@ -52,6 +40,3 @@ return encode ? Utils.encode(prefix) : prefix; | ||
if (typeof obj === 'string' || | ||
typeof obj === 'number' || | ||
typeof obj === 'boolean') { | ||
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') { | ||
if (encode) { | ||
@@ -63,3 +48,3 @@ return [Utils.encode(prefix) + '=' + Utils.encode(obj)]; | ||
let values = []; | ||
var values = []; | ||
@@ -70,17 +55,14 @@ if (typeof obj === 'undefined') { | ||
let objKeys; | ||
var objKeys; | ||
if (Array.isArray(filter)) { | ||
objKeys = filter; | ||
} | ||
else { | ||
const keys = Object.keys(obj); | ||
} else { | ||
var keys = Object.keys(obj); | ||
objKeys = sort ? keys.sort(sort) : keys; | ||
} | ||
for (let i = 0; i < objKeys.length; ++i) { | ||
const key = objKeys[i]; | ||
for (var i = 0; i < objKeys.length; ++i) { | ||
var key = objKeys[i]; | ||
if (skipNulls && | ||
obj[key] === null) { | ||
if (skipNulls && obj[key] === null) { | ||
continue; | ||
@@ -91,4 +73,3 @@ } | ||
values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encode, filter)); | ||
} | ||
else { | ||
} else { | ||
values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix, strictNullHandling, skipNulls, encode, filter)); | ||
@@ -101,41 +82,35 @@ } | ||
module.exports = function (obj, options) { | ||
options = options || {}; | ||
const delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter; | ||
const strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling; | ||
const skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls; | ||
const encode = typeof options.encode === 'boolean' ? options.encode : internals.encode; | ||
const sort = typeof options.sort === 'function' ? options.sort : null; | ||
let objKeys; | ||
let filter; | ||
module.exports = function (object, opts) { | ||
var obj = object; | ||
var options = opts || {}; | ||
var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter; | ||
var strictNullHandling = typeof options.strictNullHandling === 'boolean' ? options.strictNullHandling : internals.strictNullHandling; | ||
var skipNulls = typeof options.skipNulls === 'boolean' ? options.skipNulls : internals.skipNulls; | ||
var encode = typeof options.encode === 'boolean' ? options.encode : internals.encode; | ||
var sort = typeof options.sort === 'function' ? options.sort : null; | ||
var objKeys; | ||
var filter; | ||
if (typeof options.filter === 'function') { | ||
filter = options.filter; | ||
obj = filter('', obj); | ||
} | ||
else if (Array.isArray(options.filter)) { | ||
} else if (Array.isArray(options.filter)) { | ||
objKeys = filter = options.filter; | ||
} | ||
let keys = []; | ||
var keys = []; | ||
if (typeof obj !== 'object' || | ||
obj === null) { | ||
if (typeof obj !== 'object' || obj === null) { | ||
return ''; | ||
} | ||
let arrayFormat; | ||
var arrayFormat; | ||
if (options.arrayFormat in internals.arrayPrefixGenerators) { | ||
arrayFormat = options.arrayFormat; | ||
} | ||
else if ('indices' in options) { | ||
} else if ('indices' in options) { | ||
arrayFormat = options.indices ? 'indices' : 'repeat'; | ||
} | ||
else { | ||
} else { | ||
arrayFormat = 'indices'; | ||
} | ||
const generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat]; | ||
var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat]; | ||
@@ -150,8 +125,6 @@ if (!objKeys) { | ||
for (let i = 0; i < objKeys.length; ++i) { | ||
const key = objKeys[i]; | ||
for (var i = 0; i < objKeys.length; ++i) { | ||
var key = objKeys[i]; | ||
if (skipNulls && | ||
obj[key] === null) { | ||
if (skipNulls && obj[key] === null) { | ||
continue; | ||
@@ -158,0 +131,0 @@ } |
133
lib/utils.js
'use strict'; | ||
// Load modules | ||
// Declare internals | ||
const internals = {}; | ||
internals.hexTable = function () { | ||
const array = new Array(256); | ||
for (let i = 0; i < 256; ++i) { | ||
var hexTable = (function () { | ||
var array = new Array(256); | ||
for (var i = 0; i < 256; ++i) { | ||
array[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase(); | ||
@@ -19,9 +10,7 @@ } | ||
return array; | ||
}(); | ||
}()); | ||
exports.arrayToObject = function (source, options) { | ||
const obj = options.plainObjects ? Object.create(null) : {}; | ||
for (let i = 0; i < source.length; ++i) { | ||
var obj = options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0; i < source.length; ++i) { | ||
if (typeof source[i] !== 'undefined') { | ||
@@ -35,5 +24,3 @@ obj[i] = source[i]; | ||
exports.merge = function (target, source, options) { | ||
if (!source) { | ||
@@ -46,9 +33,7 @@ return target; | ||
target.push(source); | ||
} | ||
else if (typeof target === 'object') { | ||
} else if (typeof target === 'object') { | ||
target[source] = true; | ||
} else { | ||
return [target, source]; | ||
} | ||
else { | ||
target = [target, source]; | ||
} | ||
@@ -59,35 +44,26 @@ return target; | ||
if (typeof target !== 'object') { | ||
target = [target].concat(source); | ||
return target; | ||
return [target].concat(source); | ||
} | ||
if (Array.isArray(target) && | ||
!Array.isArray(source)) { | ||
target = exports.arrayToObject(target, options); | ||
var mergeTarget = target; | ||
if (Array.isArray(target) && !Array.isArray(source)) { | ||
mergeTarget = exports.arrayToObject(target, options); | ||
} | ||
const keys = Object.keys(source); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const key = keys[i]; | ||
const value = source[key]; | ||
return Object.keys(source).reduce(function (acc, key) { | ||
var value = source[key]; | ||
if (!Object.prototype.hasOwnProperty.call(target, key)) { | ||
target[key] = value; | ||
if (Object.prototype.hasOwnProperty.call(acc, key)) { | ||
acc[key] = exports.merge(acc[key], value, options); | ||
} else { | ||
acc[key] = value; | ||
} | ||
else { | ||
target[key] = exports.merge(target[key], value, options); | ||
} | ||
} | ||
return target; | ||
return acc; | ||
}, mergeTarget); | ||
}; | ||
exports.decode = function (str) { | ||
try { | ||
return decodeURIComponent(str.replace(/\+/g, ' ')); | ||
} | ||
catch (e) { | ||
} catch (e) { | ||
return str; | ||
@@ -98,3 +74,2 @@ } | ||
exports.encode = function (str) { | ||
// This code was originally written by Brian White (mscdex) for the io.js core querystring library. | ||
@@ -106,11 +81,10 @@ // It has been adapted here for stricter adherence to RFC 3986 | ||
if (typeof str !== 'string') { | ||
str = '' + str; | ||
} | ||
var string = typeof str === 'string' ? str : String(str); | ||
let out = ''; | ||
for (let i = 0; i < str.length; ++i) { | ||
let c = str.charCodeAt(i); | ||
var out = ''; | ||
for (var i = 0; i < string.length; ++i) { | ||
var c = string.charCodeAt(i); | ||
if (c === 0x2D || // - | ||
if ( | ||
c === 0x2D || // - | ||
c === 0x2E || // . | ||
@@ -121,5 +95,5 @@ c === 0x5F || // _ | ||
(c >= 0x41 && c <= 0x5A) || // a-z | ||
(c >= 0x61 && c <= 0x7A)) { // A-Z | ||
out = out + str[i]; | ||
(c >= 0x61 && c <= 0x7A) // A-Z | ||
) { | ||
out += string.charAt(i); | ||
continue; | ||
@@ -129,3 +103,3 @@ } | ||
if (c < 0x80) { | ||
out = out + internals.hexTable[c]; | ||
out = out + hexTable[c]; | ||
continue; | ||
@@ -135,3 +109,3 @@ } | ||
if (c < 0x800) { | ||
out = out + (internals.hexTable[0xC0 | (c >> 6)] + internals.hexTable[0x80 | (c & 0x3F)]); | ||
out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); | ||
continue; | ||
@@ -141,9 +115,9 @@ } | ||
if (c < 0xD800 || c >= 0xE000) { | ||
out = out + (internals.hexTable[0xE0 | (c >> 12)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]); | ||
out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); | ||
continue; | ||
} | ||
++i; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (str.charCodeAt(i) & 0x3FF)); | ||
out = out + (internals.hexTable[0xF0 | (c >> 18)] + internals.hexTable[0x80 | ((c >> 12) & 0x3F)] + internals.hexTable[0x80 | ((c >> 6) & 0x3F)] + internals.hexTable[0x80 | (c & 0x3F)]); | ||
i += 1; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); | ||
out += (hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); | ||
} | ||
@@ -154,12 +128,9 @@ | ||
exports.compact = function (obj, refs) { | ||
if (typeof obj !== 'object' || | ||
obj === null) { | ||
exports.compact = function (obj, references) { | ||
if (typeof obj !== 'object' || obj === null) { | ||
return obj; | ||
} | ||
refs = refs || []; | ||
const lookup = refs.indexOf(obj); | ||
var refs = references || []; | ||
var lookup = refs.indexOf(obj); | ||
if (lookup !== -1) { | ||
@@ -172,5 +143,5 @@ return refs[lookup]; | ||
if (Array.isArray(obj)) { | ||
const compacted = []; | ||
var compacted = []; | ||
for (let i = 0; i < obj.length; ++i) { | ||
for (var i = 0; i < obj.length; ++i) { | ||
if (typeof obj[i] !== 'undefined') { | ||
@@ -184,5 +155,5 @@ compacted.push(obj[i]); | ||
const keys = Object.keys(obj); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const key = keys[i]; | ||
var keys = Object.keys(obj); | ||
for (var j = 0; j < keys.length; ++j) { | ||
var key = keys[j]; | ||
obj[key] = exports.compact(obj[key], refs); | ||
@@ -194,20 +165,12 @@ } | ||
exports.isRegExp = function (obj) { | ||
return Object.prototype.toString.call(obj) === '[object RegExp]'; | ||
}; | ||
exports.isBuffer = function (obj) { | ||
if (obj === null || | ||
typeof obj === 'undefined') { | ||
if (obj === null || typeof obj === 'undefined') { | ||
return false; | ||
} | ||
return !!(obj.constructor && | ||
obj.constructor.isBuffer && | ||
obj.constructor.isBuffer(obj)); | ||
return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); | ||
}; |
{ | ||
"name": "qs", | ||
"description": "A querystring parser that supports nesting and arrays, with a depth limit", | ||
"homepage": "https://github.com/hapijs/qs", | ||
"version": "6.0.1", | ||
"homepage": "https://github.com/ljharb/qs", | ||
"version": "6.0.2", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/hapijs/qs.git" | ||
"url": "https://github.com/ljharb/qs.git" | ||
}, | ||
"main": "lib/index.js", | ||
"contributors": [ | ||
{ | ||
"name": "Jordan Harband", | ||
"email": "ljharb@gmail.com", | ||
"url": "http://ljharb.codes" | ||
} | ||
], | ||
"keywords": [ | ||
@@ -16,17 +23,25 @@ "querystring", | ||
"engines": { | ||
"node": ">=4.0.0" | ||
"node": ">=0.6" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"browserify": "^10.2.1", | ||
"code": "2.x.x", | ||
"lab": "7.x.x" | ||
"browserify": "^12.0.1", | ||
"tape": "^4.3.0", | ||
"covert": "^1.1.0", | ||
"mkdirp": "^0.5.1", | ||
"eslint": "^1.10.3", | ||
"@ljharb/eslint-config": "^1.6.1", | ||
"parallelshell": "^2.0.0", | ||
"evalmd": "^0.0.16" | ||
}, | ||
"scripts": { | ||
"test": "lab -a code -t 100 -L", | ||
"test-tap": "lab -a code -r tap -o tests.tap", | ||
"test-cov-html": "lab -a code -r html -o coverage.html", | ||
"dist": "browserify --standalone Qs lib/index.js > dist/qs.js" | ||
"test": "parallelshell 'npm run readme' 'npm run lint' 'npm run coverage'", | ||
"tests-only": "node test", | ||
"readme": "evalmd README.md", | ||
"lint": "eslint lib/*.js text/*.js", | ||
"coverage": "covert test", | ||
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js", | ||
"prepublish": "npm run dist" | ||
}, | ||
"license": "BSD-3-Clause" | ||
} |
166
README.md
@@ -5,5 +5,5 @@ # qs | ||
[![Build Status](https://secure.travis-ci.org/hapijs/qs.svg)](http://travis-ci.org/hapijs/qs) | ||
[![Build Status](https://api.travis-ci.org/ljharb/qs.svg)](http://travis-ci.org/ljharb/qs) | ||
Lead Maintainer: [Nathan LaFreniere](https://github.com/nlf) | ||
Lead Maintainer: [Jordan Harband](https://github.com/ljharb) | ||
@@ -15,6 +15,10 @@ The **qs** module was originally created and maintained by [TJ Holowaychuk](https://github.com/visionmedia/node-querystring). | ||
```javascript | ||
var Qs = require('qs'); | ||
var qs = require('qs'); | ||
var assert = require('assert'); | ||
var obj = Qs.parse('a=c'); // { a: 'c' } | ||
var str = Qs.stringify(obj); // 'a=c' | ||
var obj = qs.parse('a=c'); | ||
assert.deepEqual(obj, { a: 'c' }); | ||
var str = qs.stringify(obj); | ||
assert.equal(str, 'a=c'); | ||
``` | ||
@@ -24,4 +28,5 @@ | ||
[](#preventEval) | ||
```javascript | ||
Qs.parse(string, [options]); | ||
qs.parse(string, [options]); | ||
``` | ||
@@ -33,7 +38,7 @@ | ||
```javascript | ||
{ | ||
assert.deepEqual(qs.parse('foo[bar]=baz'), { | ||
foo: { | ||
bar: 'baz' | ||
} | ||
} | ||
}); | ||
``` | ||
@@ -44,4 +49,4 @@ | ||
```javascript | ||
Qs.parse('a.hasOwnProperty=b', { plainObjects: true }); | ||
// { a: { hasOwnProperty: 'b' } } | ||
var plainObject = qs.parse('a[hasOwnProperty]=b', { plainObjects: true }); | ||
assert.deepEqual(plainObject, { a: { hasOwnProperty: 'b' } }); | ||
``` | ||
@@ -52,4 +57,4 @@ | ||
```javascript | ||
Qs.parse('a.hasOwnProperty=b', { allowPrototypes: true }); | ||
// { a: { hasOwnProperty: 'b' } } | ||
var protoObject = qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }); | ||
assert.deepEqual(protoObject, { a: { hasOwnProperty: 'b' } }); | ||
``` | ||
@@ -60,4 +65,5 @@ | ||
```javascript | ||
Qs.parse('a%5Bb%5D=c'); | ||
// { a: { b: 'c' } } | ||
assert.deepEqual(qs.parse('a%5Bb%5D=c'), { | ||
a: { b: 'c' } | ||
}); | ||
``` | ||
@@ -68,3 +74,3 @@ | ||
```javascript | ||
{ | ||
assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), { | ||
foo: { | ||
@@ -75,3 +81,3 @@ bar: { | ||
} | ||
} | ||
}); | ||
``` | ||
@@ -83,3 +89,3 @@ | ||
```javascript | ||
{ | ||
var expected = { | ||
a: { | ||
@@ -98,10 +104,12 @@ b: { | ||
} | ||
} | ||
}; | ||
var string = 'a[b][c][d][e][f][g][h][i]=j'; | ||
assert.deepEqual(qs.parse(string), expected); | ||
``` | ||
This depth can be overridden by passing a `depth` option to `Qs.parse(string, [options])`: | ||
This depth can be overridden by passing a `depth` option to `qs.parse(string, [options])`: | ||
```javascript | ||
Qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 }); | ||
// { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } } | ||
var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 }); | ||
assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } }); | ||
``` | ||
@@ -114,4 +122,4 @@ | ||
```javascript | ||
Qs.parse('a=b&c=d', { parameterLimit: 1 }); | ||
// { a: 'b' } | ||
var limited = qs.parse('a=b&c=d', { parameterLimit: 1 }); | ||
assert.deepEqual(limited, { a: 'b' }); | ||
``` | ||
@@ -122,4 +130,4 @@ | ||
```javascript | ||
Qs.parse('a=b;c=d', { delimiter: ';' }); | ||
// { a: 'b', c: 'd' } | ||
var delimited = qs.parse('a=b;c=d', { delimiter: ';' }); | ||
assert.deepEqual(delimited, { a: 'b', c: 'd' }); | ||
``` | ||
@@ -130,4 +138,4 @@ | ||
```javascript | ||
Qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ }); | ||
// { a: 'b', c: 'd', e: 'f' } | ||
var regexed = qs.parse('a=b;c=d,e=f', { delimiter: /[;,]/ }); | ||
assert.deepEqual(regexed, { a: 'b', c: 'd', e: 'f' }); | ||
``` | ||
@@ -138,4 +146,4 @@ | ||
```javascript | ||
Qs.parse('a.b=c', { allowDots: true }); | ||
// { a: { b: 'c' } } | ||
var withDots = qs.parse('a.b=c', { allowDots: true }); | ||
assert.deepEqual(withDots, { a: { b: 'c' } }); | ||
``` | ||
@@ -148,4 +156,4 @@ | ||
```javascript | ||
Qs.parse('a[]=b&a[]=c'); | ||
// { a: ['b', 'c'] } | ||
var withArray = qs.parse('a[]=b&a[]=c'); | ||
assert.deepEqual(withArray, { a: ['b', 'c'] }); | ||
``` | ||
@@ -156,4 +164,4 @@ | ||
```javascript | ||
Qs.parse('a[1]=c&a[0]=b'); | ||
// { a: ['b', 'c'] } | ||
var withIndexes = qs.parse('a[1]=c&a[0]=b'); | ||
assert.deepEqual(withIndexes, { a: ['b', 'c'] }); | ||
``` | ||
@@ -166,4 +174,4 @@ | ||
```javascript | ||
Qs.parse('a[1]=b&a[15]=c'); | ||
// { a: ['b', 'c'] } | ||
var noSparse = qs.parse('a[1]=b&a[15]=c'); | ||
assert.deepEqual(noSparse, { a: ['b', 'c'] }); | ||
``` | ||
@@ -174,6 +182,7 @@ | ||
```javascript | ||
Qs.parse('a[]=&a[]=b'); | ||
// { a: ['', 'b'] } | ||
Qs.parse('a[0]=b&a[1]=&a[2]=c'); | ||
// { a: ['b', '', 'c'] } | ||
var withEmptyString = qs.parse('a[]=&a[]=b'); | ||
assert.deepEqual(withEmptyString, { a: ['', 'b'] }); | ||
var withIndexedEmptyString = qs.parse('a[0]=b&a[1]=&a[2]=c'); | ||
assert.deepEqual(withIndexedEmptyString, { a: ['b', '', 'c'] }); | ||
``` | ||
@@ -185,4 +194,4 @@ | ||
```javascript | ||
Qs.parse('a[100]=b'); | ||
// { a: { '100': 'b' } } | ||
var withMaxIndex = qs.parse('a[100]=b'); | ||
assert.deepEqual(withMaxIndex, { a: { '100': 'b' } }); | ||
``` | ||
@@ -193,4 +202,4 @@ | ||
```javascript | ||
Qs.parse('a[1]=b', { arrayLimit: 0 }); | ||
// { a: { '1': 'b' } } | ||
var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 }); | ||
assert.deepEqual(withArrayLimit, { a: { '1': 'b' } }); | ||
``` | ||
@@ -201,4 +210,4 @@ | ||
```javascript | ||
Qs.parse('a[]=b', { parseArrays: false }); | ||
// { a: { '0': 'b' } } | ||
var noParsingArrays = qs.parse('a[]=b', { parseArrays: false }); | ||
assert.deepEqual(noParsingArrays, { a: { '0': 'b' } }); | ||
``` | ||
@@ -209,4 +218,4 @@ | ||
```javascript | ||
Qs.parse('a[0]=b&a[b]=c'); | ||
// { a: { '0': 'b', b: 'c' } } | ||
var mixedNotation = qs.parse('a[0]=b&a[b]=c'); | ||
assert.deepEqual(mixedNotation, { a: { '0': 'b', b: 'c' } }); | ||
``` | ||
@@ -217,4 +226,4 @@ | ||
```javascript | ||
Qs.parse('a[][b]=c'); | ||
// { a: [{ b: 'c' }] } | ||
var arraysOfObjects = qs.parse('a[][b]=c'); | ||
assert.deepEqual(arraysOfObjects, { a: [{ b: 'c' }] }); | ||
``` | ||
@@ -224,4 +233,5 @@ | ||
[](#preventEval) | ||
```javascript | ||
Qs.stringify(object, [options]); | ||
qs.stringify(object, [options]); | ||
``` | ||
@@ -232,6 +242,4 @@ | ||
```javascript | ||
Qs.stringify({ a: 'b' }); | ||
// 'a=b' | ||
Qs.stringify({ a: { b: 'c' } }); | ||
// 'a%5Bb%5D=c' | ||
assert.equal(qs.stringify({ a: 'b' }), 'a=b'); | ||
assert.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); | ||
``` | ||
@@ -242,4 +250,4 @@ | ||
```javascript | ||
Qs.stringify({ a: { b: 'c' } }, { encode: false }); | ||
// 'a[b]=c' | ||
var unencoded = qs.stringify({ a: { b: 'c' } }, { encode: false }); | ||
assert.equal(unencoded, 'a[b]=c'); | ||
``` | ||
@@ -252,3 +260,3 @@ | ||
```javascript | ||
Qs.stringify({ a: ['b', 'c', 'd'] }); | ||
qs.stringify({ a: ['b', 'c', 'd'] }); | ||
// 'a[0]=b&a[1]=c&a[2]=d' | ||
@@ -260,3 +268,3 @@ ``` | ||
```javascript | ||
Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }); | ||
qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }); | ||
// 'a=b&a=c&a=d' | ||
@@ -268,7 +276,7 @@ ``` | ||
```javascript | ||
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }) | ||
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }) | ||
// 'a[0]=b&a[1]=c' | ||
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) | ||
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }) | ||
// 'a[]=b&a[]=c' | ||
Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) | ||
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }) | ||
// 'a=b&a=c' | ||
@@ -280,4 +288,3 @@ ``` | ||
```javascript | ||
Qs.stringify({ a: '' }); | ||
// 'a=' | ||
assert.equal(qs.stringify({ a: '' }), 'a='); | ||
``` | ||
@@ -288,4 +295,3 @@ | ||
```javascript | ||
Qs.stringify({ a: null, b: undefined }); | ||
// 'a=' | ||
assert.equal(qs.stringify({ a: null, b: undefined }), 'a='); | ||
``` | ||
@@ -296,4 +302,3 @@ | ||
```javascript | ||
Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }); | ||
// 'a=b;c=d' | ||
assert.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d'); | ||
``` | ||
@@ -319,7 +324,7 @@ | ||
} | ||
Qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc }) | ||
qs.stringify({ a: 'b', c: 'd', e: { f: new Date(123), g: [2] } }, { filter: filterFunc }); | ||
// 'a=b&c=d&e[f]=123&e[g][0]=4' | ||
Qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] }) | ||
qs.stringify({ a: 'b', c: 'd', e: 'f' }, { filter: ['a', 'e'] }); | ||
// 'a=b&e=f' | ||
Qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] }) | ||
qs.stringify({ a: ['b', 'c', 'd'], e: 'f' }, { filter: ['a', 0, 2] }); | ||
// 'a[0]=b&a[2]=d' | ||
@@ -333,4 +338,4 @@ ``` | ||
```javascript | ||
Qs.stringify({ a: null, b: '' }); | ||
// 'a=&b=' | ||
var withNull = qs.stringify({ a: null, b: '' }); | ||
assert.equal(withNull, 'a=&b='); | ||
``` | ||
@@ -341,4 +346,4 @@ | ||
```javascript | ||
Qs.parse('a&b=') | ||
// { a: '', b: '' } | ||
var equalsInsensitive = qs.parse('a&b='); | ||
assert.deepEqual(equalsInsensitive, { a: '', b: '' }); | ||
``` | ||
@@ -350,4 +355,4 @@ | ||
```javascript | ||
Qs.stringify({ a: null, b: '' }, { strictNullHandling: true }); | ||
// 'a&b=' | ||
var strictNull = qs.stringify({ a: null, b: '' }, { strictNullHandling: true }); | ||
assert.equal(strictNull, 'a&b='); | ||
``` | ||
@@ -358,5 +363,4 @@ | ||
```javascript | ||
Qs.parse('a&b=', { strictNullHandling: true }); | ||
// { a: null, b: '' } | ||
var parsedStrictNull = qs.parse('a&b=', { strictNullHandling: true }); | ||
assert.deepEqual(parsedStrictNull, { a: null, b: '' }); | ||
``` | ||
@@ -367,4 +371,4 @@ | ||
```javascript | ||
qs.stringify({ a: 'b', c: null}, { skipNulls: true }) | ||
// 'a=b' | ||
var nullsSkipped = qs.stringify({ a: 'b', c: null}, { skipNulls: true }); | ||
assert.equal(nullsSkipped, 'a=b'); | ||
``` |
'use strict'; | ||
/* eslint no-extend-native:0 */ | ||
// Load modules | ||
var test = require('tape'); | ||
var qs = require('../'); | ||
const Code = require('code'); | ||
const Lab = require('lab'); | ||
const Qs = require('../'); | ||
// Declare internals | ||
const internals = {}; | ||
// Test shortcuts | ||
const lab = exports.lab = Lab.script(); | ||
const expect = Code.expect; | ||
const describe = lab.experiment; | ||
const it = lab.test; | ||
describe('parse()', () => { | ||
it('parses a simple string', (done) => { | ||
expect(Qs.parse('0=foo')).to.deep.equal({ '0': 'foo' }); | ||
expect(Qs.parse('foo=c++')).to.deep.equal({ foo: 'c ' }); | ||
expect(Qs.parse('a[>=]=23')).to.deep.equal({ a: { '>=': '23' } }); | ||
expect(Qs.parse('a[<=>]==23')).to.deep.equal({ a: { '<=>': '=23' } }); | ||
expect(Qs.parse('a[==]=23')).to.deep.equal({ a: { '==': '23' } }); | ||
expect(Qs.parse('foo', { strictNullHandling: true })).to.deep.equal({ foo: null }); | ||
expect(Qs.parse('foo')).to.deep.equal({ foo: '' }); | ||
expect(Qs.parse('foo=')).to.deep.equal({ foo: '' }); | ||
expect(Qs.parse('foo=bar')).to.deep.equal({ foo: 'bar' }); | ||
expect(Qs.parse(' foo = bar = baz ')).to.deep.equal({ ' foo ': ' bar = baz ' }); | ||
expect(Qs.parse('foo=bar=baz')).to.deep.equal({ foo: 'bar=baz' }); | ||
expect(Qs.parse('foo=bar&bar=baz')).to.deep.equal({ foo: 'bar', bar: 'baz' }); | ||
expect(Qs.parse('foo2=bar2&baz2=')).to.deep.equal({ foo2: 'bar2', baz2: '' }); | ||
expect(Qs.parse('foo=bar&baz', { strictNullHandling: true })).to.deep.equal({ foo: 'bar', baz: null }); | ||
expect(Qs.parse('foo=bar&baz')).to.deep.equal({ foo: 'bar', baz: '' }); | ||
expect(Qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World')).to.deep.equal({ | ||
test('parse()', function (t) { | ||
t.test('parses a simple string', function (st) { | ||
st.deepEqual(qs.parse('0=foo'), { '0': 'foo' }); | ||
st.deepEqual(qs.parse('foo=c++'), { foo: 'c ' }); | ||
st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } }); | ||
st.deepEqual(qs.parse('a[<=>]==23'), { a: { '<=>': '=23' } }); | ||
st.deepEqual(qs.parse('a[==]=23'), { a: { '==': '23' } }); | ||
st.deepEqual(qs.parse('foo', { strictNullHandling: true }), { foo: null }); | ||
st.deepEqual(qs.parse('foo'), { foo: '' }); | ||
st.deepEqual(qs.parse('foo='), { foo: '' }); | ||
st.deepEqual(qs.parse('foo=bar'), { foo: 'bar' }); | ||
st.deepEqual(qs.parse(' foo = bar = baz '), { ' foo ': ' bar = baz ' }); | ||
st.deepEqual(qs.parse('foo=bar=baz'), { foo: 'bar=baz' }); | ||
st.deepEqual(qs.parse('foo=bar&bar=baz'), { foo: 'bar', bar: 'baz' }); | ||
st.deepEqual(qs.parse('foo2=bar2&baz2='), { foo2: 'bar2', baz2: '' }); | ||
st.deepEqual(qs.parse('foo=bar&baz', { strictNullHandling: true }), { foo: 'bar', baz: null }); | ||
st.deepEqual(qs.parse('foo=bar&baz'), { foo: 'bar', baz: '' }); | ||
st.deepEqual(qs.parse('cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World'), { | ||
cht: 'p3', | ||
@@ -49,227 +29,181 @@ chd: 't:60,40', | ||
}); | ||
done(); | ||
st.end(); | ||
}); | ||
it('allows enabling dot notation', (done) => { | ||
expect(Qs.parse('a.b=c')).to.deep.equal({ 'a.b': 'c' }); | ||
expect(Qs.parse('a.b=c', { allowDots: true })).to.deep.equal({ a: { b: 'c' } }); | ||
done(); | ||
t.test('allows enabling dot notation', function (st) { | ||
st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' }); | ||
st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } }); | ||
st.end(); | ||
}); | ||
it('parses a single nested string', (done) => { | ||
t.deepEqual(qs.parse('a[b]=c'), { a: { b: 'c' } }, 'parses a single nested string'); | ||
t.deepEqual(qs.parse('a[b][c]=d'), { a: { b: { c: 'd' } } }, 'parses a double nested string'); | ||
t.deepEqual( | ||
qs.parse('a[b][c][d][e][f][g][h]=i'), | ||
{ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }, | ||
'defaults to a depth of 5' | ||
); | ||
expect(Qs.parse('a[b]=c')).to.deep.equal({ a: { b: 'c' } }); | ||
done(); | ||
t.test('only parses one level when depth = 1', function (st) { | ||
st.deepEqual(qs.parse('a[b][c]=d', { depth: 1 }), { a: { b: { '[c]': 'd' } } }); | ||
st.deepEqual(qs.parse('a[b][c][d]=e', { depth: 1 }), { a: { b: { '[c][d]': 'e' } } }); | ||
st.end(); | ||
}); | ||
it('parses a double nested string', (done) => { | ||
t.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] }, 'parses a simple array'); | ||
expect(Qs.parse('a[b][c]=d')).to.deep.equal({ a: { b: { c: 'd' } } }); | ||
done(); | ||
t.test('parses an explicit array', function (st) { | ||
st.deepEqual(qs.parse('a[]=b'), { a: ['b'] }); | ||
st.deepEqual(qs.parse('a[]=b&a[]=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a[]=b&a[]=c&a[]=d'), { a: ['b', 'c', 'd'] }); | ||
st.end(); | ||
}); | ||
it('defaults to a depth of 5', (done) => { | ||
expect(Qs.parse('a[b][c][d][e][f][g][h]=i')).to.deep.equal({ a: { b: { c: { d: { e: { f: { '[g][h]': 'i' } } } } } } }); | ||
done(); | ||
t.test('parses a mix of simple and explicit arrays', function (st) { | ||
st.deepEqual(qs.parse('a=b&a[]=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a[]=b&a=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a[0]=b&a=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a=b&a[0]=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a[1]=b&a=c'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a=b&a[1]=c'), { a: ['b', 'c'] }); | ||
st.end(); | ||
}); | ||
it('only parses one level when depth = 1', (done) => { | ||
expect(Qs.parse('a[b][c]=d', { depth: 1 })).to.deep.equal({ a: { b: { '[c]': 'd' } } }); | ||
expect(Qs.parse('a[b][c][d]=e', { depth: 1 })).to.deep.equal({ a: { b: { '[c][d]': 'e' } } }); | ||
done(); | ||
t.test('parses a nested array', function (st) { | ||
st.deepEqual(qs.parse('a[b][]=c&a[b][]=d'), { a: { b: ['c', 'd'] } }); | ||
st.deepEqual(qs.parse('a[>=]=25'), { a: { '>=': '25' } }); | ||
st.end(); | ||
}); | ||
it('parses a simple array', (done) => { | ||
expect(Qs.parse('a=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
done(); | ||
t.test('allows to specify array indices', function (st) { | ||
st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] }); | ||
st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] }); | ||
st.deepEqual(qs.parse('a[1]=c'), { a: ['c'] }); | ||
st.end(); | ||
}); | ||
it('parses an explicit array', (done) => { | ||
expect(Qs.parse('a[]=b')).to.deep.equal({ a: ['b'] }); | ||
expect(Qs.parse('a[]=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[]=b&a[]=c&a[]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }); | ||
done(); | ||
t.test('limits specific array indices to 20', function (st) { | ||
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] }); | ||
st.deepEqual(qs.parse('a[21]=a'), { a: { '21': 'a' } }); | ||
st.end(); | ||
}); | ||
it('parses a mix of simple and explicit arrays', (done) => { | ||
t.deepEqual(qs.parse('a[12b]=c'), { a: { '12b': 'c' } }, 'supports keys that begin with a number'); | ||
expect(Qs.parse('a=b&a[]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[0]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a[0]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[1]=b&a=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a=b&a[1]=c')).to.deep.equal({ a: ['b', 'c'] }); | ||
done(); | ||
t.test('supports encoded = signs', function (st) { | ||
st.deepEqual(qs.parse('he%3Dllo=th%3Dere'), { 'he=llo': 'th=ere' }); | ||
st.end(); | ||
}); | ||
it('parses a nested array', (done) => { | ||
expect(Qs.parse('a[b][]=c&a[b][]=d')).to.deep.equal({ a: { b: ['c', 'd'] } }); | ||
expect(Qs.parse('a[>=]=25')).to.deep.equal({ a: { '>=': '25' } }); | ||
done(); | ||
t.test('is ok with url encoded strings', function (st) { | ||
st.deepEqual(qs.parse('a[b%20c]=d'), { a: { 'b c': 'd' } }); | ||
st.deepEqual(qs.parse('a[b]=c%20d'), { a: { b: 'c d' } }); | ||
st.end(); | ||
}); | ||
it('allows to specify array indices', (done) => { | ||
expect(Qs.parse('a[1]=c&a[0]=b&a[2]=d')).to.deep.equal({ a: ['b', 'c', 'd'] }); | ||
expect(Qs.parse('a[1]=c&a[0]=b')).to.deep.equal({ a: ['b', 'c'] }); | ||
expect(Qs.parse('a[1]=c')).to.deep.equal({ a: ['c'] }); | ||
done(); | ||
t.test('allows brackets in the value', function (st) { | ||
st.deepEqual(qs.parse('pets=["tobi"]'), { pets: '["tobi"]' }); | ||
st.deepEqual(qs.parse('operators=[">=", "<="]'), { operators: '[">=", "<="]' }); | ||
st.end(); | ||
}); | ||
it('limits specific array indices to 20', (done) => { | ||
expect(Qs.parse('a[20]=a')).to.deep.equal({ a: ['a'] }); | ||
expect(Qs.parse('a[21]=a')).to.deep.equal({ a: { '21': 'a' } }); | ||
done(); | ||
t.test('allows empty values', function (st) { | ||
st.deepEqual(qs.parse(''), {}); | ||
st.deepEqual(qs.parse(null), {}); | ||
st.deepEqual(qs.parse(undefined), {}); | ||
st.end(); | ||
}); | ||
it('supports keys that begin with a number', (done) => { | ||
expect(Qs.parse('a[12b]=c')).to.deep.equal({ a: { '12b': 'c' } }); | ||
done(); | ||
t.test('transforms arrays to objects', function (st) { | ||
st.deepEqual(qs.parse('foo[0]=bar&foo[bad]=baz'), { foo: { '0': 'bar', bad: 'baz' } }); | ||
st.deepEqual(qs.parse('foo[bad]=baz&foo[0]=bar'), { foo: { bad: 'baz', '0': 'bar' } }); | ||
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar'), { foo: { bad: 'baz', '0': 'bar' } }); | ||
st.deepEqual(qs.parse('foo[]=bar&foo[bad]=baz'), { foo: { '0': 'bar', bad: 'baz' } }); | ||
st.deepEqual(qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo'), { foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }); | ||
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' }] }); | ||
st.deepEqual(qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c'), { a: { '0': 'b', t: 'u', c: true } }); | ||
st.deepEqual(qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y'), { a: { '0': 'b', '1': 'c', x: 'y' } }); | ||
st.end(); | ||
}); | ||
it('supports encoded = signs', (done) => { | ||
expect(Qs.parse('he%3Dllo=th%3Dere')).to.deep.equal({ 'he=llo': 'th=ere' }); | ||
done(); | ||
t.test('transforms arrays to objects (dot notation)', function (st) { | ||
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: 'baz' } }); | ||
st.deepEqual(qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true }), { foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } }); | ||
st.deepEqual(qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true }), { foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } }); | ||
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15'], bar: '2' }] }); | ||
st.deepEqual(qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true }), { foo: [{ baz: ['15', '16'], bar: '2' }] }); | ||
st.deepEqual(qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar' } }); | ||
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar' } }); | ||
st.deepEqual(qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true }), { foo: { '0': 'bar', bad: 'baz' } }); | ||
st.deepEqual(qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true }), { foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }); | ||
st.deepEqual(qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true }), { foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] }); | ||
st.end(); | ||
}); | ||
it('is ok with url encoded strings', (done) => { | ||
t.deepEqual(qs.parse('a[b]=c&a=d'), { a: { b: 'c', d: true } }, 'can add keys to objects'); | ||
expect(Qs.parse('a[b%20c]=d')).to.deep.equal({ a: { 'b c': 'd' } }); | ||
expect(Qs.parse('a[b]=c%20d')).to.deep.equal({ a: { b: 'c d' } }); | ||
done(); | ||
t.test('correctly prunes undefined values when converting an array to an object', function (st) { | ||
st.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { '2': 'b', '99999999': 'c' } }); | ||
st.end(); | ||
}); | ||
it('allows brackets in the value', (done) => { | ||
expect(Qs.parse('pets=["tobi"]')).to.deep.equal({ pets: '["tobi"]' }); | ||
expect(Qs.parse('operators=[">=", "<="]')).to.deep.equal({ operators: '[">=", "<="]' }); | ||
done(); | ||
t.test('supports malformed uri characters', function (st) { | ||
st.deepEqual(qs.parse('{%:%}', { strictNullHandling: true }), { '{%:%}': null }); | ||
st.deepEqual(qs.parse('{%:%}='), { '{%:%}': '' }); | ||
st.deepEqual(qs.parse('foo=%:%}'), { foo: '%:%}' }); | ||
st.end(); | ||
}); | ||
it('allows empty values', (done) => { | ||
expect(Qs.parse('')).to.deep.equal({}); | ||
expect(Qs.parse(null)).to.deep.equal({}); | ||
expect(Qs.parse(undefined)).to.deep.equal({}); | ||
done(); | ||
t.test('doesn\'t produce empty keys', function (st) { | ||
st.deepEqual(qs.parse('_r=1&'), { '_r': '1' }); | ||
st.end(); | ||
}); | ||
it('transforms arrays to objects', (done) => { | ||
expect(Qs.parse('foo[0]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[0]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo[]=bar&foo[bad]=baz')).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }); | ||
expect(Qs.parse('foo[bad]=baz&foo[]=bar&foo[]=foo')).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }); | ||
expect(Qs.parse('foo[0][a]=a&foo[0][b]=b&foo[1][a]=aa&foo[1][b]=bb')).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] }); | ||
expect(Qs.parse('a[]=b&a[t]=u&a[hasOwnProperty]=c')).to.deep.equal({ a: { '0': 'b', t: 'u', c: true } }); | ||
expect(Qs.parse('a[]=b&a[hasOwnProperty]=c&a[x]=y')).to.deep.equal({ a: { '0': 'b', '1': 'c', x: 'y' } }); | ||
done(); | ||
t.test('cannot access Object prototype', function (st) { | ||
qs.parse('constructor[prototype][bad]=bad'); | ||
qs.parse('bad[constructor][prototype][bad]=bad'); | ||
st.equal(typeof Object.prototype.bad, 'undefined'); | ||
st.end(); | ||
}); | ||
it('transforms arrays to objects (dot notation)', (done) => { | ||
expect(Qs.parse('foo[0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: 'baz' } }); | ||
expect(Qs.parse('foo[0].baz=bar&fool.bad.boo=baz', { allowDots: true })).to.deep.equal({ foo: [{ baz: 'bar' }], fool: { bad: { boo: 'baz' } } }); | ||
expect(Qs.parse('foo[0][0].baz=bar&fool.bad=baz', { allowDots: true })).to.deep.equal({ foo: [[{ baz: 'bar' }]], fool: { bad: 'baz' } }); | ||
expect(Qs.parse('foo[0].baz[0]=15&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15'], bar: '2' }] }); | ||
expect(Qs.parse('foo[0].baz[0]=15&foo[0].baz[1]=16&foo[0].bar=2', { allowDots: true })).to.deep.equal({ foo: [{ baz: ['15', '16'], bar: '2' }] }); | ||
expect(Qs.parse('foo.bad=baz&foo[0]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo.bad=baz&foo[]=bar', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar' } }); | ||
expect(Qs.parse('foo[]=bar&foo.bad=baz', { allowDots: true })).to.deep.equal({ foo: { '0': 'bar', bad: 'baz' } }); | ||
expect(Qs.parse('foo.bad=baz&foo[]=bar&foo[]=foo', { allowDots: true })).to.deep.equal({ foo: { bad: 'baz', '0': 'bar', '1': 'foo' } }); | ||
expect(Qs.parse('foo[0].a=a&foo[0].b=b&foo[1].a=aa&foo[1].b=bb', { allowDots: true })).to.deep.equal({ foo: [{ a: 'a', b: 'b' }, { a: 'aa', b: 'bb' }] }); | ||
done(); | ||
t.test('parses arrays of objects', function (st) { | ||
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] }); | ||
st.deepEqual(qs.parse('a[0][b]=c'), { a: [{ b: 'c' }] }); | ||
st.end(); | ||
}); | ||
it('can add keys to objects', (done) => { | ||
expect(Qs.parse('a[b]=c&a=d')).to.deep.equal({ a: { b: 'c', d: true } }); | ||
done(); | ||
t.test('allows for empty strings in arrays', function (st) { | ||
st.deepEqual(qs.parse('a[]=b&a[]=&a[]=c'), { a: ['b', '', 'c'] }); | ||
st.deepEqual(qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true }), { a: ['b', null, 'c', ''] }); | ||
st.deepEqual(qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true }), { a: ['b', '', 'c', null] }); | ||
st.deepEqual(qs.parse('a[]=&a[]=b&a[]=c'), { a: ['', 'b', 'c'] }); | ||
st.end(); | ||
}); | ||
it('correctly prunes undefined values when converting an array to an object', (done) => { | ||
expect(Qs.parse('a[2]=b&a[99999999]=c')).to.deep.equal({ a: { '2': 'b', '99999999': 'c' } }); | ||
done(); | ||
t.test('compacts sparse arrays', function (st) { | ||
st.deepEqual(qs.parse('a[10]=1&a[2]=2'), { a: ['2', '1'] }); | ||
st.end(); | ||
}); | ||
it('supports malformed uri characters', (done) => { | ||
expect(Qs.parse('{%:%}', { strictNullHandling: true })).to.deep.equal({ '{%:%}': null }); | ||
expect(Qs.parse('{%:%}=')).to.deep.equal({ '{%:%}': '' }); | ||
expect(Qs.parse('foo=%:%}')).to.deep.equal({ foo: '%:%}' }); | ||
done(); | ||
t.test('parses semi-parsed strings', function (st) { | ||
st.deepEqual(qs.parse({ 'a[b]': 'c' }), { a: { b: 'c' } }); | ||
st.deepEqual(qs.parse({ 'a[b]': 'c', 'a[d]': 'e' }), { a: { b: 'c', d: 'e' } }); | ||
st.end(); | ||
}); | ||
it('doesn\'t produce empty keys', (done) => { | ||
expect(Qs.parse('_r=1&')).to.deep.equal({ '_r': '1' }); | ||
done(); | ||
t.test('parses buffers correctly', function (st) { | ||
var b = new Buffer('test'); | ||
st.deepEqual(qs.parse({ a: b }), { a: b }); | ||
st.end(); | ||
}); | ||
it('cannot access Object prototype', (done) => { | ||
Qs.parse('constructor[prototype][bad]=bad'); | ||
Qs.parse('bad[constructor][prototype][bad]=bad'); | ||
expect(typeof Object.prototype.bad).to.equal('undefined'); | ||
done(); | ||
t.test('continues parsing when no parent is found', function (st) { | ||
st.deepEqual(qs.parse('[]=&a=b'), { '0': '', a: 'b' }); | ||
st.deepEqual(qs.parse('[]&a=b', { strictNullHandling: true }), { '0': null, a: 'b' }); | ||
st.deepEqual(qs.parse('[foo]=bar'), { foo: 'bar' }); | ||
st.end(); | ||
}); | ||
it('parses arrays of objects', (done) => { | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
expect(Qs.parse('a[0][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
done(); | ||
}); | ||
it('allows for empty strings in arrays', (done) => { | ||
expect(Qs.parse('a[]=b&a[]=&a[]=c')).to.deep.equal({ a: ['b', '', 'c'] }); | ||
expect(Qs.parse('a[0]=b&a[1]&a[2]=c&a[19]=', { strictNullHandling: true })).to.deep.equal({ a: ['b', null, 'c', ''] }); | ||
expect(Qs.parse('a[0]=b&a[1]=&a[2]=c&a[19]', { strictNullHandling: true })).to.deep.equal({ a: ['b', '', 'c', null] }); | ||
expect(Qs.parse('a[]=&a[]=b&a[]=c')).to.deep.equal({ a: ['', 'b', 'c'] }); | ||
done(); | ||
}); | ||
it('compacts sparse arrays', (done) => { | ||
expect(Qs.parse('a[10]=1&a[2]=2')).to.deep.equal({ a: ['2', '1'] }); | ||
done(); | ||
}); | ||
it('parses semi-parsed strings', (done) => { | ||
expect(Qs.parse({ 'a[b]': 'c' })).to.deep.equal({ a: { b: 'c' } }); | ||
expect(Qs.parse({ 'a[b]': 'c', 'a[d]': 'e' })).to.deep.equal({ a: { b: 'c', d: 'e' } }); | ||
done(); | ||
}); | ||
it('parses buffers correctly', (done) => { | ||
const b = new Buffer('test'); | ||
expect(Qs.parse({ a: b })).to.deep.equal({ a: b }); | ||
done(); | ||
}); | ||
it('continues parsing when no parent is found', (done) => { | ||
expect(Qs.parse('[]=&a=b')).to.deep.equal({ '0': '', a: 'b' }); | ||
expect(Qs.parse('[]&a=b', { strictNullHandling: true })).to.deep.equal({ '0': null, a: 'b' }); | ||
expect(Qs.parse('[foo]=bar')).to.deep.equal({ foo: 'bar' }); | ||
done(); | ||
}); | ||
it('does not error when parsing a very long array', (done) => { | ||
let str = 'a[]=a'; | ||
t.test('does not error when parsing a very long array', function (st) { | ||
var str = 'a[]=a'; | ||
while (Buffer.byteLength(str) < 128 * 1024) { | ||
@@ -279,70 +213,58 @@ str = str + '&' + str; | ||
expect(() => { | ||
st.doesNotThrow(function () { qs.parse(str); }); | ||
Qs.parse(str); | ||
}).to.not.throw(); | ||
done(); | ||
st.end(); | ||
}); | ||
it('should not throw when a native prototype has an enumerable property', { parallel: false }, (done) => { | ||
t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) { | ||
Object.prototype.crash = ''; | ||
Array.prototype.crash = ''; | ||
expect(Qs.parse.bind(null, 'a=b')).to.not.throw(); | ||
expect(Qs.parse('a=b')).to.deep.equal({ a: 'b' }); | ||
expect(Qs.parse.bind(null, 'a[][b]=c')).to.not.throw(); | ||
expect(Qs.parse('a[][b]=c')).to.deep.equal({ a: [{ b: 'c' }] }); | ||
st.doesNotThrow(qs.parse.bind(null, 'a=b')); | ||
st.deepEqual(qs.parse('a=b'), { a: 'b' }); | ||
st.doesNotThrow(qs.parse.bind(null, 'a[][b]=c')); | ||
st.deepEqual(qs.parse('a[][b]=c'), { a: [{ b: 'c' }] }); | ||
delete Object.prototype.crash; | ||
delete Array.prototype.crash; | ||
done(); | ||
st.end(); | ||
}); | ||
it('parses a string with an alternative string delimiter', (done) => { | ||
expect(Qs.parse('a=b;c=d', { delimiter: ';' })).to.deep.equal({ a: 'b', c: 'd' }); | ||
done(); | ||
t.test('parses a string with an alternative string delimiter', function (st) { | ||
st.deepEqual(qs.parse('a=b;c=d', { delimiter: ';' }), { a: 'b', c: 'd' }); | ||
st.end(); | ||
}); | ||
it('parses a string with an alternative RegExp delimiter', (done) => { | ||
expect(Qs.parse('a=b; c=d', { delimiter: /[;,] */ })).to.deep.equal({ a: 'b', c: 'd' }); | ||
done(); | ||
t.test('parses a string with an alternative RegExp delimiter', function (st) { | ||
st.deepEqual(qs.parse('a=b; c=d', { delimiter: /[;,] */ }), { a: 'b', c: 'd' }); | ||
st.end(); | ||
}); | ||
it('does not use non-splittable objects as delimiters', (done) => { | ||
expect(Qs.parse('a=b&c=d', { delimiter: true })).to.deep.equal({ a: 'b', c: 'd' }); | ||
done(); | ||
t.test('does not use non-splittable objects as delimiters', function (st) { | ||
st.deepEqual(qs.parse('a=b&c=d', { delimiter: true }), { a: 'b', c: 'd' }); | ||
st.end(); | ||
}); | ||
it('allows overriding parameter limit', (done) => { | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: 1 })).to.deep.equal({ a: 'b' }); | ||
done(); | ||
t.test('allows overriding parameter limit', function (st) { | ||
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: 1 }), { a: 'b' }); | ||
st.end(); | ||
}); | ||
it('allows setting the parameter limit to Infinity', (done) => { | ||
expect(Qs.parse('a=b&c=d', { parameterLimit: Infinity })).to.deep.equal({ a: 'b', c: 'd' }); | ||
done(); | ||
t.test('allows setting the parameter limit to Infinity', function (st) { | ||
st.deepEqual(qs.parse('a=b&c=d', { parameterLimit: Infinity }), { a: 'b', c: 'd' }); | ||
st.end(); | ||
}); | ||
it('allows overriding array limit', (done) => { | ||
expect(Qs.parse('a[0]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '0': 'b' } }); | ||
expect(Qs.parse('a[-1]=b', { arrayLimit: -1 })).to.deep.equal({ a: { '-1': 'b' } }); | ||
expect(Qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }); | ||
done(); | ||
t.test('allows overriding array limit', function (st) { | ||
st.deepEqual(qs.parse('a[0]=b', { arrayLimit: -1 }), { a: { '0': 'b' } }); | ||
st.deepEqual(qs.parse('a[-1]=b', { arrayLimit: -1 }), { a: { '-1': 'b' } }); | ||
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { '0': 'b', '1': 'c' } }); | ||
st.end(); | ||
}); | ||
it('allows disabling array parsing', (done) => { | ||
expect(Qs.parse('a[0]=b&a[1]=c', { parseArrays: false })).to.deep.equal({ a: { '0': 'b', '1': 'c' } }); | ||
done(); | ||
t.test('allows disabling array parsing', function (st) { | ||
st.deepEqual(qs.parse('a[0]=b&a[1]=c', { parseArrays: false }), { a: { '0': 'b', '1': 'c' } }); | ||
st.end(); | ||
}); | ||
it('parses an object', (done) => { | ||
const input = { | ||
t.test('parses an object', function (st) { | ||
var input = { | ||
'user[name]': { 'pop[bob]': 3 }, | ||
@@ -352,18 +274,17 @@ 'user[email]': null | ||
const expected = { | ||
'user': { | ||
'name': { 'pop[bob]': 3 }, | ||
'email': null | ||
var expected = { | ||
user: { | ||
name: { 'pop[bob]': 3 }, | ||
email: null | ||
} | ||
}; | ||
const result = Qs.parse(input); | ||
var result = qs.parse(input); | ||
expect(result).to.deep.equal(expected); | ||
done(); | ||
st.deepEqual(result, expected); | ||
st.end(); | ||
}); | ||
it('parses an object in dot notation', (done) => { | ||
const input = { | ||
t.test('parses an object in dot notation', function (st) { | ||
var input = { | ||
'user.name': { 'pop[bob]': 3 }, | ||
@@ -373,18 +294,17 @@ 'user.email.': null | ||
const expected = { | ||
'user': { | ||
'name': { 'pop[bob]': 3 }, | ||
'email': null | ||
var expected = { | ||
user: { | ||
name: { 'pop[bob]': 3 }, | ||
email: null | ||
} | ||
}; | ||
const result = Qs.parse(input, { allowDots: true }); | ||
var result = qs.parse(input, { allowDots: true }); | ||
expect(result).to.deep.equal(expected); | ||
done(); | ||
st.deepEqual(result, expected); | ||
st.end(); | ||
}); | ||
it('parses an object and not child values', (done) => { | ||
const input = { | ||
t.test('parses an object and not child values', function (st) { | ||
var input = { | ||
'user[name]': { 'pop[bob]': { 'test': 3 } }, | ||
@@ -394,92 +314,85 @@ 'user[email]': null | ||
const expected = { | ||
'user': { | ||
'name': { 'pop[bob]': { 'test': 3 } }, | ||
'email': null | ||
var expected = { | ||
user: { | ||
name: { 'pop[bob]': { 'test': 3 } }, | ||
email: null | ||
} | ||
}; | ||
const result = Qs.parse(input); | ||
var result = qs.parse(input); | ||
expect(result).to.deep.equal(expected); | ||
done(); | ||
st.deepEqual(result, expected); | ||
st.end(); | ||
}); | ||
it('does not blow up when Buffer global is missing', (done) => { | ||
const tempBuffer = global.Buffer; | ||
t.test('does not blow up when Buffer global is missing', function (st) { | ||
var tempBuffer = global.Buffer; | ||
delete global.Buffer; | ||
const result = Qs.parse('a=b&c=d'); | ||
var result = qs.parse('a=b&c=d'); | ||
global.Buffer = tempBuffer; | ||
expect(result).to.deep.equal({ a: 'b', c: 'd' }); | ||
done(); | ||
st.deepEqual(result, { a: 'b', c: 'd' }); | ||
st.end(); | ||
}); | ||
it('does not crash when parsing circular references', (done) => { | ||
const a = {}; | ||
t.test('does not crash when parsing circular references', function (st) { | ||
var a = {}; | ||
a.b = a; | ||
let parsed; | ||
var parsed; | ||
expect(() => { | ||
st.doesNotThrow(function () { | ||
parsed = qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a }); | ||
}); | ||
parsed = Qs.parse({ 'foo[bar]': 'baz', 'foo[baz]': a }); | ||
}).to.not.throw(); | ||
expect(parsed).to.contain('foo'); | ||
expect(parsed.foo).to.contain('bar', 'baz'); | ||
expect(parsed.foo.bar).to.equal('baz'); | ||
expect(parsed.foo.baz).to.deep.equal(a); | ||
done(); | ||
st.equal('foo' in parsed, true, 'parsed has "foo" property'); | ||
st.equal('bar' in parsed.foo, true); | ||
st.equal('baz' in parsed.foo, true); | ||
st.equal(parsed.foo.bar, 'baz'); | ||
st.deepEqual(parsed.foo.baz, a); | ||
st.end(); | ||
}); | ||
it('parses plain objects correctly', (done) => { | ||
const a = Object.create(null); | ||
t.test('parses plain objects correctly', function (st) { | ||
var a = Object.create(null); | ||
a.b = 'c'; | ||
expect(Qs.parse(a)).to.deep.equal({ b: 'c' }); | ||
const result = Qs.parse({ a: a }); | ||
expect(result).to.contain('a'); | ||
expect(result.a).to.deep.equal(a); | ||
done(); | ||
st.deepEqual(qs.parse(a), { b: 'c' }); | ||
var result = qs.parse({ a: a }); | ||
st.equal('a' in result, true, 'result has "a" property'); | ||
st.deepEqual(result.a, a); | ||
st.end(); | ||
}); | ||
it('parses dates correctly', (done) => { | ||
const now = new Date(); | ||
expect(Qs.parse({ a: now })).to.deep.equal({ a: now }); | ||
done(); | ||
t.test('parses dates correctly', function (st) { | ||
var now = new Date(); | ||
st.deepEqual(qs.parse({ a: now }), { a: now }); | ||
st.end(); | ||
}); | ||
it('parses regular expressions correctly', (done) => { | ||
const re = /^test$/; | ||
expect(Qs.parse({ a: re })).to.deep.equal({ a: re }); | ||
done(); | ||
t.test('parses regular expressions correctly', function (st) { | ||
var re = /^test$/; | ||
st.deepEqual(qs.parse({ a: re }), { a: re }); | ||
st.end(); | ||
}); | ||
it('can allow overwriting prototype properties', (done) => { | ||
expect(Qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true })).to.deep.equal({ a: { hasOwnProperty: 'b' } }, { prototype: false }); | ||
expect(Qs.parse('hasOwnProperty=b', { allowPrototypes: true })).to.deep.equal({ hasOwnProperty: 'b' }, { prototype: false }); | ||
done(); | ||
t.test('can allow overwriting prototype properties', function (st) { | ||
st.deepEqual(qs.parse('a[hasOwnProperty]=b', { allowPrototypes: true }), { a: { hasOwnProperty: 'b' } }, { prototype: false }); | ||
st.deepEqual(qs.parse('hasOwnProperty=b', { allowPrototypes: true }), { hasOwnProperty: 'b' }, { prototype: false }); | ||
st.end(); | ||
}); | ||
it('can return plain objects', (done) => { | ||
const expected = Object.create(null); | ||
t.test('can return plain objects', function (st) { | ||
var expected = Object.create(null); | ||
expected.a = Object.create(null); | ||
expected.a.b = 'c'; | ||
expected.a.hasOwnProperty = 'd'; | ||
expect(Qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true })).to.deep.equal(expected); | ||
expect(Qs.parse(null, { plainObjects: true })).to.deep.equal(Object.create(null)); | ||
const expectedArray = Object.create(null); | ||
st.deepEqual(qs.parse('a[b]=c&a[hasOwnProperty]=d', { plainObjects: true }), expected); | ||
st.deepEqual(qs.parse(null, { plainObjects: true }), Object.create(null)); | ||
var expectedArray = Object.create(null); | ||
expectedArray.a = Object.create(null); | ||
expectedArray.a['0'] = 'b'; | ||
expectedArray.a.c = 'd'; | ||
expect(Qs.parse('a[]=b&a[c]=d', { plainObjects: true })).to.deep.equal(expectedArray); | ||
done(); | ||
st.deepEqual(qs.parse('a[]=b&a[c]=d', { plainObjects: true }), expectedArray); | ||
st.end(); | ||
}); | ||
}); |
'use strict'; | ||
/* eslint no-extend-native:0 */ | ||
// Load modules | ||
var test = require('tape'); | ||
var qs = require('../'); | ||
const Code = require('code'); | ||
const Lab = require('lab'); | ||
const Qs = require('../'); | ||
// Declare internals | ||
const internals = {}; | ||
// Test shortcuts | ||
const lab = exports.lab = Lab.script(); | ||
const expect = Code.expect; | ||
const describe = lab.experiment; | ||
const it = lab.test; | ||
describe('stringify()', () => { | ||
it('stringifies a querystring object', (done) => { | ||
expect(Qs.stringify({ a: 'b' })).to.equal('a=b'); | ||
expect(Qs.stringify({ a: 1 })).to.equal('a=1'); | ||
expect(Qs.stringify({ a: 1, b: 2 })).to.equal('a=1&b=2'); | ||
expect(Qs.stringify({ a: 'A_Z' })).to.equal('a=A_Z'); | ||
expect(Qs.stringify({ a: '€' })).to.equal('a=%E2%82%AC'); | ||
expect(Qs.stringify({ a: '' })).to.equal('a=%EE%80%80'); | ||
expect(Qs.stringify({ a: 'א' })).to.equal('a=%D7%90'); | ||
expect(Qs.stringify({ a: '𐐷' })).to.equal('a=%F0%90%90%B7'); | ||
done(); | ||
test('stringify()', function (t) { | ||
t.test('stringifies a querystring object', function (st) { | ||
st.equal(qs.stringify({ a: 'b' }), 'a=b'); | ||
st.equal(qs.stringify({ a: 1 }), 'a=1'); | ||
st.equal(qs.stringify({ a: 1, b: 2 }), 'a=1&b=2'); | ||
st.equal(qs.stringify({ a: 'A_Z' }), 'a=A_Z'); | ||
st.equal(qs.stringify({ a: '€' }), 'a=%E2%82%AC'); | ||
st.equal(qs.stringify({ a: '' }), 'a=%EE%80%80'); | ||
st.equal(qs.stringify({ a: 'א' }), 'a=%D7%90'); | ||
st.equal(qs.stringify({ a: '𐐷' }), 'a=%F0%90%90%B7'); | ||
st.end(); | ||
}); | ||
it('stringifies a nested object', (done) => { | ||
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c'); | ||
expect(Qs.stringify({ a: { b: { c: { d: 'e' } } } })).to.equal('a%5Bb%5D%5Bc%5D%5Bd%5D=e'); | ||
done(); | ||
t.test('stringifies a nested object', function (st) { | ||
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); | ||
st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e'); | ||
st.end(); | ||
}); | ||
it('stringifies an array value', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c', 'd'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d'); | ||
done(); | ||
t.test('stringifies an array value', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }), 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d'); | ||
st.end(); | ||
}); | ||
it('omits nulls when asked', (done) => { | ||
expect(Qs.stringify({ a: 'b', c: null }, { skipNulls: true })).to.equal('a=b'); | ||
done(); | ||
t.test('omits nulls when asked', function (st) { | ||
st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b'); | ||
st.end(); | ||
}); | ||
it('omits nested nulls when asked', (done) => { | ||
expect(Qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true })).to.equal('a%5Bb%5D=c'); | ||
done(); | ||
t.test('omits nested nulls when asked', function (st) { | ||
st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c'); | ||
st.end(); | ||
}); | ||
it('omits array indices when asked', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false })).to.equal('a=b&a=c&a=d'); | ||
done(); | ||
t.test('omits array indices when asked', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d'); | ||
st.end(); | ||
}); | ||
it('stringifies a nested array value', (done) => { | ||
expect(Qs.stringify({ a: { b: ['c', 'd'] } })).to.equal('a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); | ||
done(); | ||
t.test('stringifies a nested array value', function (st) { | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); | ||
st.end(); | ||
}); | ||
it('stringifies an object inside an array', (done) => { | ||
expect(Qs.stringify({ a: [{ b: 'c' }] })).to.equal('a%5B0%5D%5Bb%5D=c'); | ||
expect(Qs.stringify({ a: [{ b: { c: [1] } }] })).to.equal('a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1'); | ||
done(); | ||
t.test('stringifies an object inside an array', function (st) { | ||
st.equal(qs.stringify({ a: [{ b: 'c' }] }), 'a%5B0%5D%5Bb%5D=c'); | ||
st.equal(qs.stringify({ a: [{ b: { c: [1] } }] }), 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1'); | ||
st.end(); | ||
}); | ||
it('does not omit object keys when indices = false', (done) => { | ||
expect(Qs.stringify({ a: [{ b: 'c' }] }, { indices: false })).to.equal('a%5Bb%5D=c'); | ||
done(); | ||
t.test('does not omit object keys when indices = false', function (st) { | ||
st.equal(qs.stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c'); | ||
st.end(); | ||
}); | ||
it('uses indices notation for arrays when indices=true', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c'] }, { indices: true })).to.equal('a%5B0%5D=b&a%5B1%5D=c'); | ||
done(); | ||
t.test('uses indices notation for arrays when indices=true', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c'); | ||
st.end(); | ||
}); | ||
it('uses indices notation for arrays when no arrayFormat is specified', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c'] })).to.equal('a%5B0%5D=b&a%5B1%5D=c'); | ||
done(); | ||
t.test('uses indices notation for arrays when no arrayFormat is specified', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c'); | ||
st.end(); | ||
}); | ||
it('uses indices notation for arrays when no arrayFormat=indices', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).to.equal('a%5B0%5D=b&a%5B1%5D=c'); | ||
done(); | ||
t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c'); | ||
st.end(); | ||
}); | ||
it('uses repeat notation for arrays when no arrayFormat=repeat', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).to.equal('a=b&a=c'); | ||
done(); | ||
t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c'); | ||
st.end(); | ||
}); | ||
it('uses brackets notation for arrays when no arrayFormat=brackets', (done) => { | ||
expect(Qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).to.equal('a%5B%5D=b&a%5B%5D=c'); | ||
done(); | ||
t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) { | ||
st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c'); | ||
st.end(); | ||
}); | ||
it('stringifies a complicated object', (done) => { | ||
expect(Qs.stringify({ a: { b: 'c', d: 'e' } })).to.equal('a%5Bb%5D=c&a%5Bd%5D=e'); | ||
done(); | ||
t.test('stringifies a complicated object', function (st) { | ||
st.equal(qs.stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e'); | ||
st.end(); | ||
}); | ||
it('stringifies an empty value', (done) => { | ||
t.test('stringifies an empty value', function (st) { | ||
st.equal(qs.stringify({ a: '' }), 'a='); | ||
st.equal(qs.stringify({ a: null }, { strictNullHandling: true }), 'a'); | ||
expect(Qs.stringify({ a: '' })).to.equal('a='); | ||
expect(Qs.stringify({ a: null }, { strictNullHandling: true })).to.equal('a'); | ||
st.equal(qs.stringify({ a: '', b: '' }), 'a=&b='); | ||
st.equal(qs.stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b='); | ||
expect(Qs.stringify({ a: '', b: '' })).to.equal('a=&b='); | ||
expect(Qs.stringify({ a: null, b: '' }, { strictNullHandling: true })).to.equal('a&b='); | ||
st.equal(qs.stringify({ a: { b: '' } }), 'a%5Bb%5D='); | ||
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D'); | ||
st.equal(qs.stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D='); | ||
expect(Qs.stringify({ a: { b: '' } })).to.equal('a%5Bb%5D='); | ||
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: true })).to.equal('a%5Bb%5D'); | ||
expect(Qs.stringify({ a: { b: null } }, { strictNullHandling: false })).to.equal('a%5Bb%5D='); | ||
done(); | ||
st.end(); | ||
}); | ||
it('stringifies an empty object', (done) => { | ||
const obj = Object.create(null); | ||
t.test('stringifies an empty object', function (st) { | ||
var obj = Object.create(null); | ||
obj.a = 'b'; | ||
expect(Qs.stringify(obj)).to.equal('a=b'); | ||
done(); | ||
st.equal(qs.stringify(obj), 'a=b'); | ||
st.end(); | ||
}); | ||
it('returns an empty string for invalid input', (done) => { | ||
expect(Qs.stringify(undefined)).to.equal(''); | ||
expect(Qs.stringify(false)).to.equal(''); | ||
expect(Qs.stringify(null)).to.equal(''); | ||
expect(Qs.stringify('')).to.equal(''); | ||
done(); | ||
t.test('returns an empty string for invalid input', function (st) { | ||
st.equal(qs.stringify(undefined), ''); | ||
st.equal(qs.stringify(false), ''); | ||
st.equal(qs.stringify(null), ''); | ||
st.equal(qs.stringify(''), ''); | ||
st.end(); | ||
}); | ||
it('stringifies an object with an empty object as a child', (done) => { | ||
const obj = { | ||
t.test('stringifies an object with an empty object as a child', function (st) { | ||
var obj = { | ||
a: Object.create(null) | ||
@@ -165,102 +127,87 @@ }; | ||
obj.a.b = 'c'; | ||
expect(Qs.stringify(obj)).to.equal('a%5Bb%5D=c'); | ||
done(); | ||
st.equal(qs.stringify(obj), 'a%5Bb%5D=c'); | ||
st.end(); | ||
}); | ||
it('drops keys with a value of undefined', (done) => { | ||
t.test('drops keys with a value of undefined', function (st) { | ||
st.equal(qs.stringify({ a: undefined }), ''); | ||
expect(Qs.stringify({ a: undefined })).to.equal(''); | ||
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).to.equal('a%5Bc%5D'); | ||
expect(Qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).to.equal('a%5Bc%5D='); | ||
expect(Qs.stringify({ a: { b: undefined, c: '' } })).to.equal('a%5Bc%5D='); | ||
done(); | ||
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }), 'a%5Bc%5D'); | ||
st.equal(qs.stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }), 'a%5Bc%5D='); | ||
st.equal(qs.stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D='); | ||
st.end(); | ||
}); | ||
it('url encodes values', (done) => { | ||
expect(Qs.stringify({ a: 'b c' })).to.equal('a=b%20c'); | ||
done(); | ||
t.test('url encodes values', function (st) { | ||
st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c'); | ||
st.end(); | ||
}); | ||
it('stringifies a date', (done) => { | ||
const now = new Date(); | ||
const str = 'a=' + encodeURIComponent(now.toISOString()); | ||
expect(Qs.stringify({ a: now })).to.equal(str); | ||
done(); | ||
t.test('stringifies a date', function (st) { | ||
var now = new Date(); | ||
var str = 'a=' + encodeURIComponent(now.toISOString()); | ||
st.equal(qs.stringify({ a: now }), str); | ||
st.end(); | ||
}); | ||
it('stringifies the weird object from qs', (done) => { | ||
expect(Qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).to.equal('my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F'); | ||
done(); | ||
t.test('stringifies the weird object from qs', function (st) { | ||
st.equal(qs.stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }), 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F'); | ||
st.end(); | ||
}); | ||
it('skips properties that are part of the object prototype', (done) => { | ||
t.test('skips properties that are part of the object prototype', function (st) { | ||
Object.prototype.crash = 'test'; | ||
expect(Qs.stringify({ a: 'b' })).to.equal('a=b'); | ||
expect(Qs.stringify({ a: { b: 'c' } })).to.equal('a%5Bb%5D=c'); | ||
st.equal(qs.stringify({ a: 'b' }), 'a=b'); | ||
st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); | ||
delete Object.prototype.crash; | ||
done(); | ||
st.end(); | ||
}); | ||
it('stringifies boolean values', (done) => { | ||
expect(Qs.stringify({ a: true })).to.equal('a=true'); | ||
expect(Qs.stringify({ a: { b: true } })).to.equal('a%5Bb%5D=true'); | ||
expect(Qs.stringify({ b: false })).to.equal('b=false'); | ||
expect(Qs.stringify({ b: { c: false } })).to.equal('b%5Bc%5D=false'); | ||
done(); | ||
t.test('stringifies boolean values', function (st) { | ||
st.equal(qs.stringify({ a: true }), 'a=true'); | ||
st.equal(qs.stringify({ a: { b: true } }), 'a%5Bb%5D=true'); | ||
st.equal(qs.stringify({ b: false }), 'b=false'); | ||
st.equal(qs.stringify({ b: { c: false } }), 'b%5Bc%5D=false'); | ||
st.end(); | ||
}); | ||
it('stringifies buffer values', (done) => { | ||
expect(Qs.stringify({ a: new Buffer('test') })).to.equal('a=test'); | ||
expect(Qs.stringify({ a: { b: new Buffer('test') } })).to.equal('a%5Bb%5D=test'); | ||
done(); | ||
t.test('stringifies buffer values', function (st) { | ||
st.equal(qs.stringify({ a: new Buffer('test') }), 'a=test'); | ||
st.equal(qs.stringify({ a: { b: new Buffer('test') } }), 'a%5Bb%5D=test'); | ||
st.end(); | ||
}); | ||
it('stringifies an object using an alternative delimiter', (done) => { | ||
expect(Qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).to.equal('a=b;c=d'); | ||
done(); | ||
t.test('stringifies an object using an alternative delimiter', function (st) { | ||
st.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d'); | ||
st.end(); | ||
}); | ||
it('doesn\'t blow up when Buffer global is missing', (done) => { | ||
const tempBuffer = global.Buffer; | ||
t.test('doesn\'t blow up when Buffer global is missing', function (st) { | ||
var tempBuffer = global.Buffer; | ||
delete global.Buffer; | ||
const result = Qs.stringify({ a: 'b', c: 'd' }); | ||
var result = qs.stringify({ a: 'b', c: 'd' }); | ||
global.Buffer = tempBuffer; | ||
expect(result).to.equal('a=b&c=d'); | ||
done(); | ||
st.equal(result, 'a=b&c=d'); | ||
st.end(); | ||
}); | ||
it('selects properties when filter=array', (done) => { | ||
expect(Qs.stringify({ a: 'b' }, { filter: ['a'] })).to.equal('a=b'); | ||
expect(Qs.stringify({ a: 1 }, { filter: [] })).to.equal(''); | ||
expect(Qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).to.equal('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3'); | ||
done(); | ||
t.test('selects properties when filter=array', function (st) { | ||
st.equal(qs.stringify({ a: 'b' }, { filter: ['a'] }), 'a=b'); | ||
st.equal(qs.stringify({ a: 1 }, { filter: [] }), ''); | ||
st.equal(qs.stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] }), 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3'); | ||
st.end(); | ||
}); | ||
it('supports custom representations when filter=function', (done) => { | ||
let calls = 0; | ||
const obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } }; | ||
const filterFunc = function (prefix, value) { | ||
t.test('supports custom representations when filter=function', function (st) { | ||
var calls = 0; | ||
var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } }; | ||
var filterFunc = function (prefix, value) { | ||
calls++; | ||
if (calls === 1) { | ||
expect(prefix).to.be.empty(); | ||
expect(value).to.equal(obj); | ||
} | ||
else if (prefix === 'c') { | ||
st.equal(prefix, '', 'prefix is empty'); | ||
st.equal(value, obj); | ||
} else if (prefix === 'c') { | ||
return; | ||
} | ||
else if (value instanceof Date) { | ||
expect(prefix).to.equal('e[f]'); | ||
} else if (value instanceof Date) { | ||
st.equal(prefix, 'e[f]'); | ||
return value.getTime(); | ||
@@ -271,23 +218,20 @@ } | ||
expect(Qs.stringify(obj, { filter: filterFunc })).to.equal('a=b&e%5Bf%5D=1257894000000'); | ||
expect(calls).to.equal(5); | ||
done(); | ||
st.equal(qs.stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000'); | ||
st.equal(calls, 5); | ||
st.end(); | ||
}); | ||
it('can disable uri encoding', (done) => { | ||
expect(Qs.stringify({ a: 'b' }, { encode: false })).to.equal('a=b'); | ||
expect(Qs.stringify({ a: { b: 'c' } }, { encode: false })).to.equal('a[b]=c'); | ||
expect(Qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false })).to.equal('a=b&c'); | ||
done(); | ||
t.test('can disable uri encoding', function (st) { | ||
st.equal(qs.stringify({ a: 'b' }, { encode: false }), 'a=b'); | ||
st.equal(qs.stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c'); | ||
st.equal(qs.stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }), 'a=b&c'); | ||
st.end(); | ||
}); | ||
it('can sort the keys', (done) => { | ||
const sort = (a, b) => a.localeCompare(b); | ||
expect(Qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort })).to.equal('a=c&b=f&z=y'); | ||
expect(Qs.stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort })).to.equal('a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a'); | ||
done(); | ||
t.test('can sort the keys', function (st) { | ||
var sort = function (a, b) { return a.localeCompare(b); }; | ||
st.equal(qs.stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y'); | ||
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'); | ||
st.end(); | ||
}); | ||
}); |
'use strict'; | ||
// Load modules | ||
var test = require('tape'); | ||
var utils = require('../lib/utils'); | ||
const Code = require('code'); | ||
const Lab = require('lab'); | ||
const Utils = require('../lib/utils'); | ||
// Declare internals | ||
const internals = {}; | ||
// Test shortcuts | ||
const lab = exports.lab = Lab.script(); | ||
const expect = Code.expect; | ||
const describe = lab.experiment; | ||
const it = lab.test; | ||
describe('merge()', () => { | ||
it('can merge two objects with the same key', (done) => { | ||
expect(Utils.merge({ a: 'b' }, { a: 'c' })).to.deep.equal({ a: ['b', 'c'] }); | ||
done(); | ||
}); | ||
test('merge()', function (t) { | ||
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key'); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
75967
20
1
336
8
1332
2