Comparing version 6.2.3 to 6.2.4
@@ -0,1 +1,18 @@ | ||
## **6.2.4** | ||
- [Fix] `parse`: ignore `__proto__` keys (#428) | ||
- [Fix] `utils.merge`: avoid a crash with a null target and an array source | ||
- [Fix] `utils.merge`: avoid a crash with a null target and a truthy non-array source | ||
- [Fix] `utils`: `merge`: fix crash when `source` is a truthy primitive & no options are provided | ||
- [Fix] when `parseArrays` is false, properly handle keys ending in `[]` | ||
- [Robustness] `stringify`: avoid relying on a global `undefined` (#427) | ||
- [Refactor] use cached `Array.isArray` | ||
- [Docs] Clarify the need for "arrayLimit" option | ||
- [meta] fix README.md (#399) | ||
- [meta] Clean up license text so it’s properly detected as BSD-3-Clause | ||
- [meta] add FUNDING.yml | ||
- [actions] backport actions from main | ||
- [Tests] use `safer-buffer` instead of `Buffer` constructor | ||
- [Tests] remove nonexistent tape option | ||
- [Dev Deps] backport from main | ||
## **6.2.3** | ||
@@ -2,0 +19,0 @@ - [Fix] follow `allowPrototypes` option during merge (#201, #200) |
157
dist/qs.js
@@ -1,2 +0,2 @@ | ||
(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){ | ||
(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(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
'use strict'; | ||
@@ -65,3 +65,3 @@ | ||
var obj; | ||
if (root === '[]') { | ||
if (root === '[]' && options.parseArrays) { | ||
obj = []; | ||
@@ -73,12 +73,14 @@ obj = obj.concat(parseObject(chain, val, options)); | ||
var index = parseInt(cleanRoot, 10); | ||
if ( | ||
!isNaN(index) && | ||
root !== cleanRoot && | ||
String(index) === cleanRoot && | ||
index >= 0 && | ||
(options.parseArrays && index <= options.arrayLimit) | ||
if (!options.parseArrays && cleanRoot === '') { | ||
obj = { 0: val }; | ||
} else if ( | ||
!isNaN(index) | ||
&& root !== cleanRoot | ||
&& String(index) === cleanRoot | ||
&& index >= 0 | ||
&& (options.parseArrays && index <= options.arrayLimit) | ||
) { | ||
obj = []; | ||
obj[index] = parseObject(chain, val, options); | ||
} else { | ||
} else if (cleanRoot !== '__proto__') { | ||
obj[cleanRoot] = parseObject(chain, val, options); | ||
@@ -113,4 +115,3 @@ } | ||
if (parent) { | ||
// If we aren't using plain objects, optionally prefix keys | ||
// that would overwrite object prototype properties | ||
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties | ||
if (!options.plainObjects && has.call(Object.prototype, parent)) { | ||
@@ -209,3 +210,14 @@ if (!options.allowPrototypes) { | ||
var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots) { | ||
var isArray = Array.isArray; | ||
var stringify = function stringify( | ||
object, | ||
prefix, | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
) { | ||
var obj = object; | ||
@@ -238,3 +250,3 @@ if (typeof filter === 'function') { | ||
var objKeys; | ||
if (Array.isArray(filter)) { | ||
if (isArray(filter)) { | ||
objKeys = filter; | ||
@@ -253,6 +265,26 @@ } else { | ||
if (Array.isArray(obj)) { | ||
values = values.concat(stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
if (isArray(obj)) { | ||
values = values.concat(stringify( | ||
obj[key], | ||
generateArrayPrefix(prefix, key), | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} else { | ||
values = values.concat(stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
values = values.concat(stringify( | ||
obj[key], | ||
prefix + (allowDots ? '.' + key : '[' + key + ']'), | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} | ||
@@ -271,3 +303,3 @@ } | ||
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode; | ||
var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null; | ||
var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null; | ||
var sort = typeof options.sort === 'function' ? options.sort : null; | ||
@@ -278,3 +310,3 @@ var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots; | ||
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') { | ||
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') { | ||
throw new TypeError('Encoder has to be a function.'); | ||
@@ -286,4 +318,5 @@ } | ||
obj = filter('', obj); | ||
} else if (Array.isArray(options.filter)) { | ||
objKeys = filter = options.filter; | ||
} else if (isArray(options.filter)) { | ||
objKeys = options.filter; | ||
filter = options.filter; | ||
} | ||
@@ -323,3 +356,13 @@ | ||
keys = keys.concat(stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
keys = keys.concat(stringify( | ||
obj[key], | ||
key, | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} | ||
@@ -345,3 +388,3 @@ | ||
exports.arrayToObject = function (source, options) { | ||
var obj = options.plainObjects ? Object.create(null) : {}; | ||
var obj = options && options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0; i < source.length; ++i) { | ||
@@ -356,3 +399,17 @@ if (typeof source[i] !== 'undefined') { | ||
exports.merge = function (target, source, options) { | ||
var isArray = Array.isArray; | ||
var arrayToObject = function arrayToObject(source, options) { | ||
var obj = options && options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0; i < source.length; ++i) { | ||
if (typeof source[i] !== 'undefined') { | ||
obj[i] = source[i]; | ||
} | ||
} | ||
return obj; | ||
}; | ||
exports.merge = function merge(target, source, options) { | ||
/* eslint no-param-reassign: 0 */ | ||
if (!source) { | ||
@@ -363,6 +420,6 @@ return target; | ||
if (typeof source !== 'object') { | ||
if (Array.isArray(target)) { | ||
if (isArray(target)) { | ||
target.push(source); | ||
} else if (typeof target === 'object') { | ||
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) { | ||
} else if (target && typeof target === 'object') { | ||
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) { | ||
target[source] = true; | ||
@@ -377,3 +434,3 @@ } | ||
if (typeof target !== 'object') { | ||
if (!target || typeof target !== 'object') { | ||
return [target].concat(source); | ||
@@ -383,6 +440,22 @@ } | ||
var mergeTarget = target; | ||
if (Array.isArray(target) && !Array.isArray(source)) { | ||
mergeTarget = exports.arrayToObject(target, options); | ||
if (isArray(target) && !isArray(source)) { | ||
mergeTarget = arrayToObject(target, options); | ||
} | ||
if (isArray(target) && isArray(source)) { | ||
source.forEach(function (item, i) { | ||
if (has.call(target, i)) { | ||
var targetItem = target[i]; | ||
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { | ||
target[i] = merge(targetItem, item, options); | ||
} else { | ||
target.push(item); | ||
} | ||
} else { | ||
target[i] = item; | ||
} | ||
}); | ||
return target; | ||
} | ||
return Object.keys(source).reduce(function (acc, key) { | ||
@@ -392,3 +465,3 @@ var value = source[key]; | ||
if (has.call(acc, key)) { | ||
acc[key] = exports.merge(acc[key], value, options); | ||
acc[key] = merge(acc[key], value, options); | ||
} else { | ||
@@ -423,9 +496,9 @@ acc[key] = value; | ||
if ( | ||
c === 0x2D || // - | ||
c === 0x2E || // . | ||
c === 0x5F || // _ | ||
c === 0x7E || // ~ | ||
(c >= 0x30 && c <= 0x39) || // 0-9 | ||
(c >= 0x41 && c <= 0x5A) || // a-z | ||
(c >= 0x61 && c <= 0x7A) // A-Z | ||
c === 0x2D // - | ||
|| c === 0x2E // . | ||
|| c === 0x5F // _ | ||
|| c === 0x7E // ~ | ||
|| (c >= 0x30 && c <= 0x39) // 0-9 | ||
|| (c >= 0x41 && c <= 0x5A) // a-z | ||
|| (c >= 0x61 && c <= 0x7A) // A-Z | ||
) { | ||
@@ -453,3 +526,7 @@ out += string.charAt(i); | ||
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)]; | ||
/* eslint operator-linebreak: [2, "before"] */ | ||
out += hexTable[0xF0 | (c >> 18)] | ||
+ hexTable[0x80 | ((c >> 12) & 0x3F)] | ||
+ hexTable[0x80 | ((c >> 6) & 0x3F)] | ||
+ hexTable[0x80 | (c & 0x3F)]; | ||
} | ||
@@ -473,3 +550,3 @@ | ||
if (Array.isArray(obj)) { | ||
if (isArray(obj)) { | ||
var compacted = []; | ||
@@ -510,2 +587,2 @@ | ||
},{}]},{},[1])(1) | ||
}); | ||
}); |
@@ -53,3 +53,3 @@ 'use strict'; | ||
var obj; | ||
if (root === '[]') { | ||
if (root === '[]' && options.parseArrays) { | ||
obj = []; | ||
@@ -61,12 +61,14 @@ obj = obj.concat(parseObject(chain, val, options)); | ||
var index = parseInt(cleanRoot, 10); | ||
if ( | ||
!isNaN(index) && | ||
root !== cleanRoot && | ||
String(index) === cleanRoot && | ||
index >= 0 && | ||
(options.parseArrays && index <= options.arrayLimit) | ||
if (!options.parseArrays && cleanRoot === '') { | ||
obj = { 0: val }; | ||
} else if ( | ||
!isNaN(index) | ||
&& root !== cleanRoot | ||
&& String(index) === cleanRoot | ||
&& index >= 0 | ||
&& (options.parseArrays && index <= options.arrayLimit) | ||
) { | ||
obj = []; | ||
obj[index] = parseObject(chain, val, options); | ||
} else { | ||
} else if (cleanRoot !== '__proto__') { | ||
obj[cleanRoot] = parseObject(chain, val, options); | ||
@@ -101,4 +103,3 @@ } | ||
if (parent) { | ||
// If we aren't using plain objects, optionally prefix keys | ||
// that would overwrite object prototype properties | ||
// If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties | ||
if (!options.plainObjects && has.call(Object.prototype, parent)) { | ||
@@ -105,0 +106,0 @@ if (!options.allowPrototypes) { |
@@ -25,3 +25,14 @@ 'use strict'; | ||
var stringify = function stringify(object, prefix, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots) { | ||
var isArray = Array.isArray; | ||
var stringify = function stringify( | ||
object, | ||
prefix, | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
) { | ||
var obj = object; | ||
@@ -54,3 +65,3 @@ if (typeof filter === 'function') { | ||
var objKeys; | ||
if (Array.isArray(filter)) { | ||
if (isArray(filter)) { | ||
objKeys = filter; | ||
@@ -69,6 +80,26 @@ } else { | ||
if (Array.isArray(obj)) { | ||
values = values.concat(stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
if (isArray(obj)) { | ||
values = values.concat(stringify( | ||
obj[key], | ||
generateArrayPrefix(prefix, key), | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} else { | ||
values = values.concat(stringify(obj[key], prefix + (allowDots ? '.' + key : '[' + key + ']'), generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
values = values.concat(stringify( | ||
obj[key], | ||
prefix + (allowDots ? '.' + key : '[' + key + ']'), | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} | ||
@@ -87,3 +118,3 @@ } | ||
var encode = typeof options.encode === 'boolean' ? options.encode : defaults.encode; | ||
var encoder = encode ? (typeof options.encoder === 'function' ? options.encoder : defaults.encoder) : null; | ||
var encoder = encode ? typeof options.encoder === 'function' ? options.encoder : defaults.encoder : null; | ||
var sort = typeof options.sort === 'function' ? options.sort : null; | ||
@@ -94,3 +125,3 @@ var allowDots = typeof options.allowDots === 'undefined' ? false : options.allowDots; | ||
if (options.encoder !== null && options.encoder !== undefined && typeof options.encoder !== 'function') { | ||
if (options.encoder !== null && typeof options.encoder !== 'undefined' && typeof options.encoder !== 'function') { | ||
throw new TypeError('Encoder has to be a function.'); | ||
@@ -102,4 +133,5 @@ } | ||
obj = filter('', obj); | ||
} else if (Array.isArray(options.filter)) { | ||
objKeys = filter = options.filter; | ||
} else if (isArray(options.filter)) { | ||
objKeys = options.filter; | ||
filter = options.filter; | ||
} | ||
@@ -139,3 +171,13 @@ | ||
keys = keys.concat(stringify(obj[key], key, generateArrayPrefix, strictNullHandling, skipNulls, encoder, filter, sort, allowDots)); | ||
keys = keys.concat(stringify( | ||
obj[key], | ||
key, | ||
generateArrayPrefix, | ||
strictNullHandling, | ||
skipNulls, | ||
encoder, | ||
filter, | ||
sort, | ||
allowDots | ||
)); | ||
} | ||
@@ -142,0 +184,0 @@ |
@@ -15,3 +15,3 @@ 'use strict'; | ||
exports.arrayToObject = function (source, options) { | ||
var obj = options.plainObjects ? Object.create(null) : {}; | ||
var obj = options && options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0; i < source.length; ++i) { | ||
@@ -26,3 +26,17 @@ if (typeof source[i] !== 'undefined') { | ||
exports.merge = function (target, source, options) { | ||
var isArray = Array.isArray; | ||
var arrayToObject = function arrayToObject(source, options) { | ||
var obj = options && options.plainObjects ? Object.create(null) : {}; | ||
for (var i = 0; i < source.length; ++i) { | ||
if (typeof source[i] !== 'undefined') { | ||
obj[i] = source[i]; | ||
} | ||
} | ||
return obj; | ||
}; | ||
exports.merge = function merge(target, source, options) { | ||
/* eslint no-param-reassign: 0 */ | ||
if (!source) { | ||
@@ -33,6 +47,6 @@ return target; | ||
if (typeof source !== 'object') { | ||
if (Array.isArray(target)) { | ||
if (isArray(target)) { | ||
target.push(source); | ||
} else if (typeof target === 'object') { | ||
if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) { | ||
} else if (target && typeof target === 'object') { | ||
if ((options && (options.plainObjects || options.allowPrototypes)) || !has.call(Object.prototype, source)) { | ||
target[source] = true; | ||
@@ -47,3 +61,3 @@ } | ||
if (typeof target !== 'object') { | ||
if (!target || typeof target !== 'object') { | ||
return [target].concat(source); | ||
@@ -53,6 +67,22 @@ } | ||
var mergeTarget = target; | ||
if (Array.isArray(target) && !Array.isArray(source)) { | ||
mergeTarget = exports.arrayToObject(target, options); | ||
if (isArray(target) && !isArray(source)) { | ||
mergeTarget = arrayToObject(target, options); | ||
} | ||
if (isArray(target) && isArray(source)) { | ||
source.forEach(function (item, i) { | ||
if (has.call(target, i)) { | ||
var targetItem = target[i]; | ||
if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { | ||
target[i] = merge(targetItem, item, options); | ||
} else { | ||
target.push(item); | ||
} | ||
} else { | ||
target[i] = item; | ||
} | ||
}); | ||
return target; | ||
} | ||
return Object.keys(source).reduce(function (acc, key) { | ||
@@ -62,3 +92,3 @@ var value = source[key]; | ||
if (has.call(acc, key)) { | ||
acc[key] = exports.merge(acc[key], value, options); | ||
acc[key] = merge(acc[key], value, options); | ||
} else { | ||
@@ -93,9 +123,9 @@ acc[key] = value; | ||
if ( | ||
c === 0x2D || // - | ||
c === 0x2E || // . | ||
c === 0x5F || // _ | ||
c === 0x7E || // ~ | ||
(c >= 0x30 && c <= 0x39) || // 0-9 | ||
(c >= 0x41 && c <= 0x5A) || // a-z | ||
(c >= 0x61 && c <= 0x7A) // A-Z | ||
c === 0x2D // - | ||
|| c === 0x2E // . | ||
|| c === 0x5F // _ | ||
|| c === 0x7E // ~ | ||
|| (c >= 0x30 && c <= 0x39) // 0-9 | ||
|| (c >= 0x41 && c <= 0x5A) // a-z | ||
|| (c >= 0x61 && c <= 0x7A) // A-Z | ||
) { | ||
@@ -123,3 +153,7 @@ out += string.charAt(i); | ||
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)]; | ||
/* eslint operator-linebreak: [2, "before"] */ | ||
out += hexTable[0xF0 | (c >> 18)] | ||
+ hexTable[0x80 | ((c >> 12) & 0x3F)] | ||
+ hexTable[0x80 | ((c >> 6) & 0x3F)] | ||
+ hexTable[0x80 | (c & 0x3F)]; | ||
} | ||
@@ -143,3 +177,3 @@ | ||
if (Array.isArray(obj)) { | ||
if (isArray(obj)) { | ||
var compacted = []; | ||
@@ -146,0 +180,0 @@ |
{ | ||
"name": "qs", | ||
"description": "A querystring parser that supports nesting and arrays, with a depth limit", | ||
"homepage": "https://github.com/ljharb/qs", | ||
"version": "6.2.3", | ||
"repository": { | ||
"type": "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": [ | ||
"querystring", | ||
"qs" | ||
], | ||
"engines": { | ||
"node": ">=0.6" | ||
}, | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"browserify": "^13.0.1", | ||
"tape": "^4.6.0", | ||
"covert": "^1.1.0", | ||
"mkdirp": "^0.5.1", | ||
"eslint": "^3.1.0", | ||
"@ljharb/eslint-config": "^6.0.0", | ||
"parallelshell": "^2.0.0", | ||
"iconv-lite": "^0.4.13", | ||
"qs-iconv": "^1.0.3", | ||
"evalmd": "^0.0.17" | ||
}, | ||
"scripts": { | ||
"pretest": "npm run --silent readme && npm run --silent lint", | ||
"test": "npm run --silent 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" | ||
"name": "qs", | ||
"description": "A querystring parser that supports nesting and arrays, with a depth limit", | ||
"homepage": "https://github.com/ljharb/qs", | ||
"version": "6.2.4", | ||
"repository": { | ||
"type": "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": [ | ||
"querystring", | ||
"qs" | ||
], | ||
"engines": { | ||
"node": ">=0.6" | ||
}, | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^20.1.0", | ||
"aud": "^1.1.5", | ||
"browserify": "^16.5.2", | ||
"eclint": "^2.8.1", | ||
"eslint": "^8.6.0", | ||
"evalmd": "^0.0.17", | ||
"iconv-lite": "^0.4.24", | ||
"in-publish": "^2.0.1", | ||
"mkdirp": "^0.5.1", | ||
"nyc": "^10.3.2", | ||
"qs-iconv": "^1.0.4", | ||
"safe-publish-latest": "^2.0.0", | ||
"safer-buffer": "^2.1.2", | ||
"tape": "^5.4.0" | ||
}, | ||
"scripts": { | ||
"prepublishOnly": "safe-publish-latest && npm run dist", | ||
"prepublish": "not-in-publish || npm run prepublishOnly", | ||
"pretest": "npm run --silent readme && npm run --silent lint", | ||
"test": "npm run --silent tests-only", | ||
"tests-only": "nyc tape 'test/**/*.js'", | ||
"posttest": "aud --production", | ||
"readme": "evalmd README.md", | ||
"postlint": "eclint check $(git ls-files | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')", | ||
"lint": "eslint --ext=js,mjs .", | ||
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js" | ||
}, | ||
"license": "BSD-3-Clause" | ||
} |
@@ -172,3 +172,3 @@ # qs | ||
**qs** will also limit specifying indices in an array to a maximum index of `20`. Any array members with an index of greater than `20` will | ||
instead be converted to an object with the index as the key: | ||
instead be converted to an object with the index as the key. This is needed to handle cases when someone sent, for example, `a[999999999]` and it will take significant time to iterate over this huge array. | ||
@@ -249,2 +249,26 @@ ```javascript | ||
You can encode keys and values using different logic by using the type argument provided to the encoder: | ||
```javascript | ||
var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) { | ||
if (type === 'key') { | ||
return // Encoded key | ||
} else if (type === 'value') { | ||
return // Encoded value | ||
} | ||
}}) | ||
``` | ||
The type argument is also provided to the decoder: | ||
```javascript | ||
var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) { | ||
if (type === 'key') { | ||
return // Decoded key | ||
} else if (type === 'value') { | ||
return // Decoded value | ||
} | ||
}}) | ||
``` | ||
Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage. | ||
@@ -361,3 +385,3 @@ | ||
By default the encoding and decoding of characters is done in `utf-8`. If you | ||
By default the encoding and decoding of characters is done in `utf-8`. If you | ||
wish to encode querystrings to a different character set (i.e. | ||
@@ -364,0 +388,0 @@ [Shift JIS](https://en.wikipedia.org/wiki/Shift_JIS)) you can use the |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
require('./parse'); | ||
@@ -2,0 +4,0 @@ |
@@ -6,6 +6,7 @@ 'use strict'; | ||
var iconv = require('iconv-lite'); | ||
var SaferBuffer = require('safer-buffer').Buffer; | ||
test('parse()', function (t) { | ||
t.test('parses a simple string', function (st) { | ||
st.deepEqual(qs.parse('0=foo'), { '0': 'foo' }); | ||
st.deepEqual(qs.parse('0=foo'), { 0: 'foo' }); | ||
st.deepEqual(qs.parse('foo=c++'), { foo: 'c ' }); | ||
@@ -88,3 +89,3 @@ st.deepEqual(qs.parse('a[>=]=23'), { a: { '>=': '23' } }); | ||
st.deepEqual(qs.parse('a[20]=a'), { a: ['a'] }); | ||
st.deepEqual(qs.parse('a[21]=a'), { a: { '21': 'a' } }); | ||
st.deepEqual(qs.parse('a[21]=a'), { a: { 21: 'a' } }); | ||
st.end(); | ||
@@ -120,7 +121,7 @@ }); | ||
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]=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' }] }); | ||
@@ -141,6 +142,6 @@ | ||
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.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' }] }); | ||
@@ -151,3 +152,3 @@ st.end(); | ||
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.deepEqual(qs.parse('a[2]=b&a[99999999]=c'), { a: { 2: 'b', 99999999: 'c' } }); | ||
st.end(); | ||
@@ -164,3 +165,3 @@ }); | ||
t.test('doesn\'t produce empty keys', function (st) { | ||
st.deepEqual(qs.parse('_r=1&'), { '_r': '1' }); | ||
st.deepEqual(qs.parse('_r=1&'), { _r: '1' }); | ||
st.end(); | ||
@@ -230,3 +231,3 @@ }); | ||
t.test('parses buffers correctly', function (st) { | ||
var b = new Buffer('test'); | ||
var b = SaferBuffer.from('test'); | ||
st.deepEqual(qs.parse({ a: b }), { a: b }); | ||
@@ -237,4 +238,4 @@ st.end(); | ||
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('[]=&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' }); | ||
@@ -255,3 +256,3 @@ st.end(); | ||
t.test('should not throw when a native prototype has an enumerable property', { parallel: false }, function (st) { | ||
t.test('should not throw when a native prototype has an enumerable property', function (st) { | ||
Object.prototype.crash = ''; | ||
@@ -294,5 +295,5 @@ Array.prototype.crash = ''; | ||
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[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.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayLimit: 0 }), { a: { 0: 'b', 1: 'c' } }); | ||
st.end(); | ||
@@ -302,3 +303,10 @@ }); | ||
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' } }); | ||
var indices = qs.parse('a[0]=b&a[1]=c', { parseArrays: false }); | ||
st.deepEqual(indices, { a: { 0: 'b', 1: 'c' } }); | ||
st.equal(Array.isArray(indices.a), false, 'parseArrays:false, indices case is not an array'); | ||
var emptyBrackets = qs.parse('a[]=b', { parseArrays: false }); | ||
st.deepEqual(emptyBrackets, { a: { 0: 'b' } }); | ||
st.equal(Array.isArray(emptyBrackets.a), false, 'parseArrays:false, empty brackets case is not an array'); | ||
st.end(); | ||
@@ -347,3 +355,3 @@ }); | ||
var input = { | ||
'user[name]': { 'pop[bob]': { 'test': 3 } }, | ||
'user[name]': { 'pop[bob]': { test: 3 } }, | ||
'user[email]': null | ||
@@ -354,3 +362,3 @@ }; | ||
user: { | ||
name: { 'pop[bob]': { 'test': 3 } }, | ||
name: { 'pop[bob]': { test: 3 } }, | ||
email: null | ||
@@ -477,3 +485,3 @@ } | ||
qs.parse('a[b]=c&a=toString', { plainObjects: true }), | ||
{ a: { b: 'c', toString: true } }, | ||
{ __proto__: null, a: { __proto__: null, b: 'c', toString: true } }, | ||
'can overwrite prototype with plainObjects true' | ||
@@ -485,2 +493,62 @@ ); | ||
t.test('dunder proto is ignored', function (st) { | ||
var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42'; | ||
var result = qs.parse(payload, { allowPrototypes: true }); | ||
st.deepEqual( | ||
result, | ||
{ | ||
categories: { | ||
length: '42' | ||
} | ||
}, | ||
'silent [[Prototype]] payload' | ||
); | ||
var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true }); | ||
st.deepEqual( | ||
plainResult, | ||
{ | ||
__proto__: null, | ||
categories: { | ||
__proto__: null, | ||
length: '42' | ||
} | ||
}, | ||
'silent [[Prototype]] payload: plain objects' | ||
); | ||
var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true }); | ||
st.notOk(Array.isArray(query.categories), 'is not an array'); | ||
st.notOk(query.categories instanceof Array, 'is not instanceof an array'); | ||
st.deepEqual(query.categories, { some: { json: 'toInject' } }); | ||
st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array'); | ||
st.deepEqual( | ||
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }), | ||
{ | ||
foo: { | ||
bar: 'stuffs' | ||
} | ||
}, | ||
'hidden values' | ||
); | ||
st.deepEqual( | ||
qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }), | ||
{ | ||
__proto__: null, | ||
foo: { | ||
__proto__: null, | ||
bar: 'stuffs' | ||
} | ||
}, | ||
'hidden values: plain objects' | ||
); | ||
st.end(); | ||
}); | ||
t.test('can return null objects', { skip: !Object.create }, function (st) { | ||
@@ -504,11 +572,11 @@ var expected = Object.create(null); | ||
decoder: function (str) { | ||
var reg = /\%([0-9A-F]{2})/ig; | ||
var reg = /%([0-9A-F]{2})/ig; | ||
var result = []; | ||
var parts; | ||
var last = 0; | ||
while (parts = reg.exec(str)) { | ||
// var last = 0; | ||
while ((parts = reg.exec(str))) { | ||
result.push(parseInt(parts[1], 16)); | ||
last = parts.index + parts[0].length; | ||
// last = parts.index + parts[0].length; | ||
} | ||
return iconv.decode(new Buffer(result), 'shift_jis').toString(); | ||
return iconv.decode(SaferBuffer.from(result), 'shift_jis').toString(); | ||
} | ||
@@ -520,6 +588,4 @@ }), { 県: '大阪府' }); | ||
t.test('throws error with wrong decoder', function (st) { | ||
st.throws(function () { | ||
qs.parse({}, { | ||
decoder: 'string' | ||
}); | ||
st['throws'](function () { | ||
qs.parse({}, { decoder: 'string' }); | ||
}, new TypeError('Decoder has to be a function.')); | ||
@@ -526,0 +592,0 @@ st.end(); |
@@ -6,2 +6,3 @@ 'use strict'; | ||
var iconv = require('iconv-lite'); | ||
var SaferBuffer = require('safer-buffer').Buffer; | ||
@@ -43,3 +44,2 @@ test('stringify()', function (t) { | ||
t.test('omits nested nulls when asked', function (st) { | ||
@@ -199,4 +199,4 @@ st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c'); | ||
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.equal(qs.stringify({ a: SaferBuffer.from('test') }), 'a=test'); | ||
st.equal(qs.stringify({ a: { b: SaferBuffer.from('test') } }), 'a%5Bb%5D=test'); | ||
st.end(); | ||
@@ -230,3 +230,3 @@ }); | ||
var filterFunc = function (prefix, value) { | ||
calls++; | ||
calls += 1; | ||
if (calls === 1) { | ||
@@ -265,4 +265,4 @@ st.equal(prefix, '', 'prefix is empty'); | ||
var sort = function (a, b) { return a.localeCompare(b); }; | ||
st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: sort, encode: false }), 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb'); | ||
st.equal(qs.stringify({ a: 'a', z: { zj: {zjb: 'zjb', zja: 'zja'}, zi: {zib: 'zib', zia: 'zia'} }, b: 'b' }, { sort: null, encode: false }), 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b'); | ||
st.equal(qs.stringify({ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, { sort: sort, encode: false }), 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb'); | ||
st.equal(qs.stringify({ a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, { sort: null, encode: false }), 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b'); | ||
st.end(); | ||
@@ -272,3 +272,3 @@ }); | ||
t.test('can stringify with custom encoding', function (st) { | ||
st.equal(qs.stringify({ 県: '大阪府', '': ''}, { | ||
st.equal(qs.stringify({ 県: '大阪府', '': '' }, { | ||
encoder: function (str) { | ||
@@ -280,3 +280,3 @@ if (str.length === 0) { | ||
var result = []; | ||
for (var i=0; i < buf.length; ++i) { | ||
for (var i = 0; i < buf.length; ++i) { | ||
result.push(buf.readUInt8(i).toString(16)); | ||
@@ -291,3 +291,3 @@ } | ||
t.test('throws error with wrong encoder', function (st) { | ||
st.throws(function () { | ||
st['throws'](function () { | ||
qs.stringify({}, { | ||
@@ -300,6 +300,4 @@ encoder: 'string' | ||
t.test('can use custom encoder for a buffer object', { | ||
skip: typeof Buffer === 'undefined' | ||
}, function (st) { | ||
st.equal(qs.stringify({ a: new Buffer([1]) }, { | ||
t.test('can use custom encoder for a buffer object', { skip: typeof Buffer === 'undefined' }, function (st) { | ||
st.equal(qs.stringify({ a: SaferBuffer.from([1]) }, { | ||
encoder: function (buffer) { | ||
@@ -306,0 +304,0 @@ if (typeof buffer === 'string') { |
@@ -7,4 +7,24 @@ 'use strict'; | ||
test('merge()', function (t) { | ||
t.deepEqual(utils.merge(null, true), [null, true], 'merges true into null'); | ||
t.deepEqual(utils.merge(null, [42]), [null, 42], 'merges null into an array'); | ||
t.deepEqual(utils.merge({ a: 'b' }, { a: 'c' }), { a: ['b', 'c'] }, 'merges two objects with the same key'); | ||
var oneMerged = utils.merge({ foo: 'bar' }, { foo: { first: '123' } }); | ||
t.deepEqual(oneMerged, { foo: ['bar', { first: '123' }] }, 'merges a standalone and an object into an array'); | ||
var twoMerged = utils.merge({ foo: ['bar', { first: '123' }] }, { foo: { second: '456' } }); | ||
t.deepEqual(twoMerged, { foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }, 'merges a standalone and two objects into an array'); | ||
var sandwiched = utils.merge({ foo: ['bar', { first: '123', second: '456' }] }, { foo: 'baz' }); | ||
t.deepEqual(sandwiched, { foo: ['bar', { first: '123', second: '456' }, 'baz'] }, 'merges an object sandwiched by two standalones into an array'); | ||
var nestedArrays = utils.merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] }); | ||
t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] }); | ||
var noOptionsNonObjectSource = utils.merge({ foo: 'baz' }, 'bar'); | ||
t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true }); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
97073
20
1730
401
14