qs 6.15.2 → 6.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## **6.15.3**
2
+ - [Fix] `parse`: enforce `throwOnLimitExceeded` for cumulative array growth via `combine`/`merge`
3
+ - [Fix] `utils`: respect encoding of surrogate pairs across chunks (#559)
4
+ - [Robustness] `parse`: throw the `arrayLimit` error before splitting oversized comma values
5
+ - [Robustness] `utils.merge` / `utils.assign`: avoid invoking `__proto__` setter when copying own properties
6
+ - [Robustness] `utils`: enforce `arrayLimit` consistently across `merge`'s array paths
7
+ - [Perf] `utils`: make `compact` O(n) via a side-channel visited-set instead of `Array.indexOf`
8
+ - [Deps] update `side-channel`
9
+ - [Dev Deps] update `eslint`, `mock-property`, `tape`
10
+ - [Tests] `parse`: characterize current lenient handling of unbalanced bracket keys (#558)
11
+
1
12
  ## **6.15.2**
2
13
  - [Fix] `stringify`: skip null/undefined entries in `arrayFormat: 'comma'` + `encodeValuesOnly` instead of crashing in `encoder`
3
14
  - [Fix] `stringify`: use configured `delimiter` after `charsetSentinel` (#555)
package/dist/qs.js CHANGED
@@ -5,18 +5,21 @@
5
5
  "use strict";var stringify=require(4),parse=require(3),formats=require(1);module.exports={formats:formats,parse:parse,stringify:stringify};
6
6
 
7
7
  },{"1":1,"3":3,"4":4}],3:[function(require,module,exports){
8
- "use strict";var utils=require(5),has=Object.prototype.hasOwnProperty,isArray=Array.isArray,defaults={allowDots:!1,allowEmptyArrays:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decodeDotInKeys:!1,decoder:utils.decode,delimiter:"&",depth:5,duplicates:"combine",ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictDepth:!1,strictMerge:!0,strictNullHandling:!1,throwOnLimitExceeded:!1},interpretNumericEntities=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(parseInt(t,10))})},parseArrayValue=function(e,t,r){if(e&&"string"==typeof e&&t.comma&&e.indexOf(",")>-1)return e.split(",");if(t.throwOnLimitExceeded&&r>=t.arrayLimit)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");return e},isoSentinel="utf8=%26%2310003%3B",charsetSentinel="utf8=%E2%9C%93",parseValues=function parseQueryStringValues(e,t){var r={__proto__:null},i=t.ignoreQueryPrefix?e.replace(/^\?/,""):e;i=i.replace(/%5B/gi,"[").replace(/%5D/gi,"]");var a=t.parameterLimit===1/0?void 0:t.parameterLimit,o=i.split(t.delimiter,t.throwOnLimitExceeded&&void 0!==a?a+1:a);if(t.throwOnLimitExceeded&&void 0!==a&&o.length>a)throw new RangeError("Parameter limit exceeded. Only "+a+" parameter"+(1===a?"":"s")+" allowed.");var l,n=-1,s=t.charset;if(t.charsetSentinel)for(l=0;l<o.length;++l)0===o[l].indexOf("utf8=")&&(o[l]===charsetSentinel?s="utf-8":o[l]===isoSentinel&&(s="iso-8859-1"),n=l,l=o.length);for(l=0;l<o.length;++l)if(l!==n){var d,c,p=o[l],u=p.indexOf("]="),y=-1===u?p.indexOf("="):u+1;if(-1===y?(d=t.decoder(p,defaults.decoder,s,"key"),c=t.strictNullHandling?null:""):null!==(d=t.decoder(p.slice(0,y),defaults.decoder,s,"key"))&&(c=utils.maybeMap(parseArrayValue(p.slice(y+1),t,isArray(r[d])?r[d].length:0),function(e){return t.decoder(e,defaults.decoder,s,"value")})),c&&t.interpretNumericEntities&&"iso-8859-1"===s&&(c=interpretNumericEntities(String(c))),p.indexOf("[]=")>-1&&(c=isArray(c)?[c]:c),t.comma&&isArray(c)&&c.length>t.arrayLimit){if(t.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");c=utils.combine([],c,t.arrayLimit,t.plainObjects)}if(null!==d){var f=has.call(r,d);f&&("combine"===t.duplicates||p.indexOf("[]=")>-1)?r[d]=utils.combine(r[d],c,t.arrayLimit,t.plainObjects):f&&"last"!==t.duplicates||(r[d]=c)}}return r},parseObject=function(e,t,r,i){var a=0;if(e.length>0&&"[]"===e[e.length-1]){var o=e.slice(0,-1).join("");a=Array.isArray(t)&&t[o]?t[o].length:0}for(var l=i?t:parseArrayValue(t,r,a),n=e.length-1;n>=0;--n){var s,d=e[n];if("[]"===d&&r.parseArrays)s=utils.isOverflow(l)?l:r.allowEmptyArrays&&(""===l||r.strictNullHandling&&null===l)?[]:utils.combine([],l,r.arrayLimit,r.plainObjects);else{s=r.plainObjects?{__proto__:null}:{};var c="["===d.charAt(0)&&"]"===d.charAt(d.length-1)?d.slice(1,-1):d,p=r.decodeDotInKeys?c.replace(/%2E/g,"."):c,u=parseInt(p,10),y=!isNaN(u)&&d!==p&&String(u)===p&&u>=0&&r.parseArrays;if(r.parseArrays||""!==p)if(y&&u<r.arrayLimit)(s=[])[u]=l;else{if(y&&r.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+r.arrayLimit+" element"+(1===r.arrayLimit?"":"s")+" allowed in an array.");y?(s[u]=l,utils.markOverflow(s,u)):"__proto__"!==p&&(s[p]=l)}else s={0:l}}l=s}return l},splitKeyIntoSegments=function splitKeyIntoSegments(e,t){var r=t.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e;if(t.depth<=0){if(!t.plainObjects&&has.call(Object.prototype,r)&&!t.allowPrototypes)return;return[r]}var i=[],a=r.indexOf("["),o=a>=0?r.slice(0,a):r;if(o){if(!t.plainObjects&&has.call(Object.prototype,o)&&!t.allowPrototypes)return;i[i.length]=o}for(var l=r.length,n=a,s=0;n>=0&&s<t.depth;){for(var d=1,c=n+1,p=-1;c<l&&p<0;){var u=r.charCodeAt(c);91===u?d+=1:93===u&&0==(d-=1)&&(p=c),c+=1}if(p<0)return i[i.length]="["+r.slice(n)+"]",i;var y=r.slice(n,p+1),f=y.slice(1,-1);if(!t.plainObjects&&has.call(Object.prototype,f)&&!t.allowPrototypes)return;i[i.length]=y,s+=1,n=r.indexOf("[",p+1)}if(n>=0){if(!0===t.strictDepth)throw new RangeError("Input depth exceeded depth option of "+t.depth+" and strictDepth is true");i[i.length]="["+r.slice(n)+"]"}return i},parseKeys=function parseQueryStringKeys(e,t,r,i){if(e){var a=splitKeyIntoSegments(e,r);if(a)return parseObject(a,t,r,i)}},normalizeParseOptions=function normalizeParseOptions(e){if(!e)return defaults;if(void 0!==e.allowEmptyArrays&&"boolean"!=typeof e.allowEmptyArrays)throw new TypeError("`allowEmptyArrays` option can only be `true` or `false`, when provided");if(void 0!==e.decodeDotInKeys&&"boolean"!=typeof e.decodeDotInKeys)throw new TypeError("`decodeDotInKeys` option can only be `true` or `false`, when provided");if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");if(void 0!==e.throwOnLimitExceeded&&"boolean"!=typeof e.throwOnLimitExceeded)throw new TypeError("`throwOnLimitExceeded` option must be a boolean");var t=void 0===e.charset?defaults.charset:e.charset,r=void 0===e.duplicates?defaults.duplicates:e.duplicates;if("combine"!==r&&"first"!==r&&"last"!==r)throw new TypeError("The duplicates option must be either combine, first, or last");return{allowDots:void 0===e.allowDots?!0===e.decodeDotInKeys||defaults.allowDots:!!e.allowDots,allowEmptyArrays:"boolean"==typeof e.allowEmptyArrays?!!e.allowEmptyArrays:defaults.allowEmptyArrays,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:defaults.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:defaults.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:defaults.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:defaults.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:defaults.comma,decodeDotInKeys:"boolean"==typeof e.decodeDotInKeys?e.decodeDotInKeys:defaults.decodeDotInKeys,decoder:"function"==typeof e.decoder?e.decoder:defaults.decoder,delimiter:"string"==typeof e.delimiter||utils.isRegExp(e.delimiter)?e.delimiter:defaults.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:defaults.depth,duplicates:r,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:defaults.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:defaults.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:defaults.plainObjects,strictDepth:"boolean"==typeof e.strictDepth?!!e.strictDepth:defaults.strictDepth,strictMerge:"boolean"==typeof e.strictMerge?!!e.strictMerge:defaults.strictMerge,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:defaults.strictNullHandling,throwOnLimitExceeded:"boolean"==typeof e.throwOnLimitExceeded&&e.throwOnLimitExceeded}};module.exports=function(e,t){var r=normalizeParseOptions(t);if(""===e||null==e)return r.plainObjects?{__proto__:null}:{};for(var i="string"==typeof e?parseValues(e,r):e,a=r.plainObjects?{__proto__:null}:{},o=Object.keys(i),l=0;l<o.length;++l){var n=o[l],s=parseKeys(n,i[n],r,"string"==typeof e);a=utils.merge(a,s,r)}return!0===r.allowSparse?a:utils.compact(a)};
8
+ "use strict";var utils=require(5),has=Object.prototype.hasOwnProperty,isArray=Array.isArray,defaults={allowDots:!1,allowEmptyArrays:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decodeDotInKeys:!1,decoder:utils.decode,delimiter:"&",depth:5,duplicates:"combine",ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictDepth:!1,strictMerge:!0,strictNullHandling:!1,throwOnLimitExceeded:!1},interpretNumericEntities=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(parseInt(t,10))})},parseArrayValue=function(e,t,r,i){if(e&&"string"==typeof e&&t.comma&&e.indexOf(",")>-1){if(i&&t.throwOnLimitExceeded)for(var a=0,o=e.indexOf(",");o>-1;){if((a+=1)>=t.arrayLimit)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");o=e.indexOf(",",o+1)}return e.split(",")}if(t.throwOnLimitExceeded&&r>=t.arrayLimit)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");return e},isoSentinel="utf8=%26%2310003%3B",charsetSentinel="utf8=%E2%9C%93",parseValues=function parseQueryStringValues(e,t){var r={__proto__:null},i=t.ignoreQueryPrefix?e.replace(/^\?/,""):e;i=i.replace(/%5B/gi,"[").replace(/%5D/gi,"]");var a=t.parameterLimit===1/0?void 0:t.parameterLimit,o=i.split(t.delimiter,t.throwOnLimitExceeded&&void 0!==a?a+1:a);if(t.throwOnLimitExceeded&&void 0!==a&&o.length>a)throw new RangeError("Parameter limit exceeded. Only "+a+" parameter"+(1===a?"":"s")+" allowed.");var l,n=-1,s=t.charset;if(t.charsetSentinel)for(l=0;l<o.length;++l)0===o[l].indexOf("utf8=")&&(o[l]===charsetSentinel?s="utf-8":o[l]===isoSentinel&&(s="iso-8859-1"),n=l,l=o.length);for(l=0;l<o.length;++l)if(l!==n){var d,c,p=o[l],u=p.indexOf("]="),y=-1===u?p.indexOf("="):u+1;if(-1===y?(d=t.decoder(p,defaults.decoder,s,"key"),c=t.strictNullHandling?null:""):null!==(d=t.decoder(p.slice(0,y),defaults.decoder,s,"key"))&&(c=utils.maybeMap(parseArrayValue(p.slice(y+1),t,isArray(r[d])?r[d].length:0,-1===p.indexOf("[]=")),function(e){return t.decoder(e,defaults.decoder,s,"value")})),c&&t.interpretNumericEntities&&"iso-8859-1"===s&&(c=interpretNumericEntities(String(c))),p.indexOf("[]=")>-1&&(c=isArray(c)?[c]:c),t.comma&&isArray(c)&&c.length>t.arrayLimit&&(c=utils.combine([],c,t.arrayLimit,t.plainObjects,t.throwOnLimitExceeded)),null!==d){var f=has.call(r,d);f&&("combine"===t.duplicates||p.indexOf("[]=")>-1)?r[d]=utils.combine(r[d],c,t.arrayLimit,t.plainObjects,t.throwOnLimitExceeded):f&&"last"!==t.duplicates||(r[d]=c)}}return r},parseObject=function(e,t,r,i){var a=0;if(e.length>0&&"[]"===e[e.length-1]){var o=e.slice(0,-1).join("");a=Array.isArray(t)&&t[o]?t[o].length:0}for(var l=i?t:parseArrayValue(t,r,a),n=e.length-1;n>=0;--n){var s,d=e[n];if("[]"===d&&r.parseArrays)s=utils.isOverflow(l)?l:r.allowEmptyArrays&&(""===l||r.strictNullHandling&&null===l)?[]:utils.combine([],l,r.arrayLimit,r.plainObjects,r.throwOnLimitExceeded);else{s=r.plainObjects?{__proto__:null}:{};var c="["===d.charAt(0)&&"]"===d.charAt(d.length-1)?d.slice(1,-1):d,p=r.decodeDotInKeys?c.replace(/%2E/g,"."):c,u=parseInt(p,10),y=!isNaN(u)&&d!==p&&String(u)===p&&u>=0&&r.parseArrays;if(r.parseArrays||""!==p)if(y&&u<r.arrayLimit)(s=[])[u]=l;else{if(y&&r.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+r.arrayLimit+" element"+(1===r.arrayLimit?"":"s")+" allowed in an array.");y?(s[u]=l,utils.markOverflow(s,u)):"__proto__"!==p&&(s[p]=l)}else s={0:l}}l=s}return l},splitKeyIntoSegments=function splitKeyIntoSegments(e,t){var r=t.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e;if(t.depth<=0){if(!t.plainObjects&&has.call(Object.prototype,r)&&!t.allowPrototypes)return;return[r]}var i=[],a=r.indexOf("["),o=a>=0?r.slice(0,a):r;if(o){if(!t.plainObjects&&has.call(Object.prototype,o)&&!t.allowPrototypes)return;i[i.length]=o}for(var l=r.length,n=a,s=0;n>=0&&s<t.depth;){for(var d=1,c=n+1,p=-1;c<l&&p<0;){var u=r.charCodeAt(c);91===u?d+=1:93===u&&0==(d-=1)&&(p=c),c+=1}if(p<0)return i[i.length]="["+r.slice(n)+"]",i;var y=r.slice(n,p+1),f=y.slice(1,-1);if(!t.plainObjects&&has.call(Object.prototype,f)&&!t.allowPrototypes)return;i[i.length]=y,s+=1,n=r.indexOf("[",p+1)}if(n>=0){if(!0===t.strictDepth)throw new RangeError("Input depth exceeded depth option of "+t.depth+" and strictDepth is true");i[i.length]="["+r.slice(n)+"]"}return i},parseKeys=function parseQueryStringKeys(e,t,r,i){if(e){var a=splitKeyIntoSegments(e,r);if(a)return parseObject(a,t,r,i)}},normalizeParseOptions=function normalizeParseOptions(e){if(!e)return defaults;if(void 0!==e.allowEmptyArrays&&"boolean"!=typeof e.allowEmptyArrays)throw new TypeError("`allowEmptyArrays` option can only be `true` or `false`, when provided");if(void 0!==e.decodeDotInKeys&&"boolean"!=typeof e.decodeDotInKeys)throw new TypeError("`decodeDotInKeys` option can only be `true` or `false`, when provided");if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");if(void 0!==e.throwOnLimitExceeded&&"boolean"!=typeof e.throwOnLimitExceeded)throw new TypeError("`throwOnLimitExceeded` option must be a boolean");var t=void 0===e.charset?defaults.charset:e.charset,r=void 0===e.duplicates?defaults.duplicates:e.duplicates;if("combine"!==r&&"first"!==r&&"last"!==r)throw new TypeError("The duplicates option must be either combine, first, or last");return{allowDots:void 0===e.allowDots?!0===e.decodeDotInKeys||defaults.allowDots:!!e.allowDots,allowEmptyArrays:"boolean"==typeof e.allowEmptyArrays?!!e.allowEmptyArrays:defaults.allowEmptyArrays,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:defaults.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:defaults.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:defaults.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:defaults.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:defaults.comma,decodeDotInKeys:"boolean"==typeof e.decodeDotInKeys?e.decodeDotInKeys:defaults.decodeDotInKeys,decoder:"function"==typeof e.decoder?e.decoder:defaults.decoder,delimiter:"string"==typeof e.delimiter||utils.isRegExp(e.delimiter)?e.delimiter:defaults.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:defaults.depth,duplicates:r,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:defaults.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:defaults.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:defaults.plainObjects,strictDepth:"boolean"==typeof e.strictDepth?!!e.strictDepth:defaults.strictDepth,strictMerge:"boolean"==typeof e.strictMerge?!!e.strictMerge:defaults.strictMerge,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:defaults.strictNullHandling,throwOnLimitExceeded:"boolean"==typeof e.throwOnLimitExceeded&&e.throwOnLimitExceeded}};module.exports=function(e,t){var r=normalizeParseOptions(t);if(""===e||null==e)return r.plainObjects?{__proto__:null}:{};for(var i="string"==typeof e?parseValues(e,r):e,a=r.plainObjects?{__proto__:null}:{},o=Object.keys(i),l=0;l<o.length;++l){var n=o[l],s=parseKeys(n,i[n],r,"string"==typeof e);a=utils.merge(a,s,r)}return!0===r.allowSparse?a:utils.compact(a)};
9
9
 
10
10
  },{"5":5}],4:[function(require,module,exports){
11
11
  "use strict";var getSideChannel=require(46),utils=require(5),formats=require(1),has=Object.prototype.hasOwnProperty,arrayPrefixGenerators={brackets:function brackets(e){return e+"[]"},comma:"comma",indices:function indices(e,r){return e+"["+r+"]"},repeat:function repeat(e){return e}},isArray=Array.isArray,push=Array.prototype.push,pushToArray=function(e,r){push.apply(e,isArray(r)?r:[r])},toISO=Date.prototype.toISOString,defaultFormat=formats.default,defaults={addQueryPrefix:!1,allowDots:!1,allowEmptyArrays:!1,arrayFormat:"indices",charset:"utf-8",charsetSentinel:!1,commaRoundTrip:!1,delimiter:"&",encode:!0,encodeDotInKeys:!1,encoder:utils.encode,encodeValuesOnly:!1,filter:void 0,format:defaultFormat,formatter:formats.formatters[defaultFormat],indices:!1,serializeDate:function serializeDate(e){return toISO.call(e)},skipNulls:!1,strictNullHandling:!1},isNonNullishPrimitive=function isNonNullishPrimitive(e){return"string"==typeof e||"number"==typeof e||"boolean"==typeof e||"symbol"==typeof e||"bigint"==typeof e},sentinel={},stringify=function stringify(e,r,t,o,a,n,i,l,s,f,u,d,y,c,p,m,h,v){for(var g=e,w=v,b=0,A=!1;void 0!==(w=w.get(sentinel))&&!A;){var D=w.get(e);if(b+=1,void 0!==D){if(D===b)throw new RangeError("Cyclic object value");A=!0}void 0===w.get(sentinel)&&(b=0)}if("function"==typeof f?g=f(r,g):g instanceof Date?g=y(g):"comma"===t&&isArray(g)&&(g=utils.maybeMap(g,function(e){return e instanceof Date?y(e):e})),null===g){if(n)return p(s&&!m?s(r,defaults.encoder,h,"key",c):r);g=""}if(isNonNullishPrimitive(g)||utils.isBuffer(g))return s?[p(m?r:s(r,defaults.encoder,h,"key",c))+"="+p(s(g,defaults.encoder,h,"value",c))]:[p(r)+"="+p(String(g))];var S,E=[];if(void 0===g)return E;if("comma"===t&&isArray(g))m&&s&&(g=utils.maybeMap(g,function(e){return null==e?e:s(e)})),S=[{value:g.length>0?g.join(",")||null:void 0}];else if(isArray(f))S=f;else{var N=Object.keys(g);S=u?N.sort(u):N}var T=l?String(r).replace(/\./g,"%2E"):String(r),O=o&&isArray(g)&&1===g.length?T+"[]":T;if(a&&isArray(g)&&0===g.length)return O+"[]";for(var k=0;k<S.length;++k){var I=S[k],P="object"==typeof I&&I&&void 0!==I.value?I.value:g[I];if(!i||null!==P){var x=d&&l?String(I).replace(/\./g,"%2E"):String(I),z=isArray(g)?"function"==typeof t?t(O,x):O:O+(d?"."+x:"["+x+"]");v.set(e,b);var K=getSideChannel();K.set(sentinel,v),pushToArray(E,stringify(P,z,t,o,a,n,i,l,"comma"===t&&m&&isArray(g)?null:s,f,u,d,y,c,p,m,h,K))}}return E},normalizeStringifyOptions=function normalizeStringifyOptions(e){if(!e)return defaults;if(void 0!==e.allowEmptyArrays&&"boolean"!=typeof e.allowEmptyArrays)throw new TypeError("`allowEmptyArrays` option can only be `true` or `false`, when provided");if(void 0!==e.encodeDotInKeys&&"boolean"!=typeof e.encodeDotInKeys)throw new TypeError("`encodeDotInKeys` option can only be `true` or `false`, when provided");if(null!==e.encoder&&void 0!==e.encoder&&"function"!=typeof e.encoder)throw new TypeError("Encoder has to be a function.");var r=e.charset||defaults.charset;if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t=formats.default;if(void 0!==e.format){if(!has.call(formats.formatters,e.format))throw new TypeError("Unknown format option provided.");t=e.format}var o,a=formats.formatters[t],n=defaults.filter;if(("function"==typeof e.filter||isArray(e.filter))&&(n=e.filter),o=e.arrayFormat in arrayPrefixGenerators?e.arrayFormat:"indices"in e?e.indices?"indices":"repeat":defaults.arrayFormat,"commaRoundTrip"in e&&"boolean"!=typeof e.commaRoundTrip)throw new TypeError("`commaRoundTrip` must be a boolean, or absent");var i=void 0===e.allowDots?!0===e.encodeDotInKeys||defaults.allowDots:!!e.allowDots;return{addQueryPrefix:"boolean"==typeof e.addQueryPrefix?e.addQueryPrefix:defaults.addQueryPrefix,allowDots:i,allowEmptyArrays:"boolean"==typeof e.allowEmptyArrays?!!e.allowEmptyArrays:defaults.allowEmptyArrays,arrayFormat:o,charset:r,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:defaults.charsetSentinel,commaRoundTrip:!!e.commaRoundTrip,delimiter:void 0===e.delimiter?defaults.delimiter:e.delimiter,encode:"boolean"==typeof e.encode?e.encode:defaults.encode,encodeDotInKeys:"boolean"==typeof e.encodeDotInKeys?e.encodeDotInKeys:defaults.encodeDotInKeys,encoder:"function"==typeof e.encoder?e.encoder:defaults.encoder,encodeValuesOnly:"boolean"==typeof e.encodeValuesOnly?e.encodeValuesOnly:defaults.encodeValuesOnly,filter:n,format:t,formatter:a,serializeDate:"function"==typeof e.serializeDate?e.serializeDate:defaults.serializeDate,skipNulls:"boolean"==typeof e.skipNulls?e.skipNulls:defaults.skipNulls,sort:"function"==typeof e.sort?e.sort:null,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:defaults.strictNullHandling}};module.exports=function(e,r){var t,o=e,a=normalizeStringifyOptions(r);"function"==typeof a.filter?o=(0,a.filter)("",o):isArray(a.filter)&&(t=a.filter);var n=[];if("object"!=typeof o||null===o)return"";var i=arrayPrefixGenerators[a.arrayFormat],l="comma"===i&&a.commaRoundTrip;t||(t=Object.keys(o)),a.sort&&t.sort(a.sort);for(var s=getSideChannel(),f=0;f<t.length;++f){var u=t[f];if(null!=u){var d=o[u];a.skipNulls&&null===d||pushToArray(n,stringify(d,u,i,l,a.allowEmptyArrays,a.strictNullHandling,a.skipNulls,a.encodeDotInKeys,a.encode?a.encoder:null,a.filter,a.sort,a.allowDots,a.serializeDate,a.format,a.formatter,a.encodeValuesOnly,a.charset,s))}}var y=n.join(a.delimiter),c=!0===a.addQueryPrefix?"?":"";return a.charsetSentinel&&("iso-8859-1"===a.charset?c+="utf8=%26%2310003%3B"+a.delimiter:c+="utf8=%E2%9C%93"+a.delimiter),y.length>0?c+y:""};
12
12
 
13
13
  },{"1":1,"46":46,"5":5}],5:[function(require,module,exports){
14
- "use strict";var formats=require(1),getSideChannel=require(46),has=Object.prototype.hasOwnProperty,isArray=Array.isArray,overflowChannel=getSideChannel(),markOverflow=function markOverflow(e,r){return overflowChannel.set(e,r),e},isOverflow=function isOverflow(e){return overflowChannel.has(e)},getMaxIndex=function getMaxIndex(e){return overflowChannel.get(e)},setMaxIndex=function setMaxIndex(e,r){overflowChannel.set(e,r)},hexTable=function(){for(var e=[],r=0;r<256;++r)e[e.length]="%"+((r<16?"0":"")+r.toString(16)).toUpperCase();return e}(),compactQueue=function compactQueue(e){for(;e.length>1;){var r=e.pop(),t=r.obj[r.prop];if(isArray(t)){for(var n=[],o=0;o<t.length;++o)void 0!==t[o]&&(n[n.length]=t[o]);r.obj[r.prop]=n}}},arrayToObject=function arrayToObject(e,r){for(var t=r&&r.plainObjects?{__proto__:null}:{},n=0;n<e.length;++n)void 0!==e[n]&&(t[n]=e[n]);return t},merge=function merge(e,r,t){if(!r)return e;if("object"!=typeof r&&"function"!=typeof r){if(isArray(e)){var n=e.length;if(t&&"number"==typeof t.arrayLimit&&n>t.arrayLimit)return markOverflow(arrayToObject(e.concat(r),t),n);e[n]=r}else{if(!e||"object"!=typeof e)return[e,r];if(isOverflow(e)){var o=getMaxIndex(e)+1;e[o]=r,setMaxIndex(e,o)}else{if(t&&t.strictMerge)return[e,r];(t&&(t.plainObjects||t.allowPrototypes)||!has.call(Object.prototype,r))&&(e[r]=!0)}}return e}if(!e||"object"!=typeof e){if(isOverflow(r)){for(var a=Object.keys(r),i=t&&t.plainObjects?{__proto__:null,0:e}:{0:e},c=0;c<a.length;c++)i[parseInt(a[c],10)+1]=r[a[c]];return markOverflow(i,getMaxIndex(r)+1)}var l=[e].concat(r);return t&&"number"==typeof t.arrayLimit&&l.length>t.arrayLimit?markOverflow(arrayToObject(l,t),l.length-1):l}var f=e;return isArray(e)&&!isArray(r)&&(f=arrayToObject(e,t)),isArray(e)&&isArray(r)?(r.forEach(function(r,n){if(has.call(e,n)){var o=e[n];o&&"object"==typeof o&&r&&"object"==typeof r?e[n]=merge(o,r,t):e[e.length]=r}else e[n]=r}),e):Object.keys(r).reduce(function(e,n){var o=r[n];if(has.call(e,n)?e[n]=merge(e[n],o,t):e[n]=o,isOverflow(r)&&!isOverflow(e)&&markOverflow(e,getMaxIndex(r)),isOverflow(e)){var a=parseInt(n,10);String(a)===n&&a>=0&&a>getMaxIndex(e)&&setMaxIndex(e,a)}return e},f)},assign=function assignSingleSource(e,r){return Object.keys(r).reduce(function(e,t){return e[t]=r[t],e},e)},decode=function(e,r,t){var n=e.replace(/\+/g," ");if("iso-8859-1"===t)return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch(e){return n}},limit=1024,encode=function encode(e,r,t,n,o){if(0===e.length)return e;var a=e;if("symbol"==typeof e?a=Symbol.prototype.toString.call(e):"string"!=typeof e&&(a=String(e)),"iso-8859-1"===t)return escape(a).replace(/%u[0-9a-f]{4}/gi,function(e){return"%26%23"+parseInt(e.slice(2),16)+"%3B"});for(var i="",c=0;c<a.length;c+=limit){for(var l=a.length>=limit?a.slice(c,c+limit):a,f=[],s=0;s<l.length;++s){var u=l.charCodeAt(s);45===u||46===u||95===u||126===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122||o===formats.RFC1738&&(40===u||41===u)?f[f.length]=l.charAt(s):u<128?f[f.length]=hexTable[u]:u<2048?f[f.length]=hexTable[192|u>>6]+hexTable[128|63&u]:u<55296||u>=57344?f[f.length]=hexTable[224|u>>12]+hexTable[128|u>>6&63]+hexTable[128|63&u]:(s+=1,u=65536+((1023&u)<<10|1023&l.charCodeAt(s)),f[f.length]=hexTable[240|u>>18]+hexTable[128|u>>12&63]+hexTable[128|u>>6&63]+hexTable[128|63&u])}i+=f.join("")}return i},compact=function compact(e){for(var r=[{obj:{o:e},prop:"o"}],t=[],n=0;n<r.length;++n)for(var o=r[n],a=o.obj[o.prop],i=Object.keys(a),c=0;c<i.length;++c){var l=i[c],f=a[l];"object"==typeof f&&null!==f&&-1===t.indexOf(f)&&(r[r.length]={obj:a,prop:l},t[t.length]=f)}return compactQueue(r),e},isRegExp=function isRegExp(e){return"[object RegExp]"===Object.prototype.toString.call(e)},isBuffer=function isBuffer(e){return!(!e||"object"!=typeof e||!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e)))},combine=function combine(e,r,t,n){if(isOverflow(e)){var o=getMaxIndex(e)+1;return e[o]=r,setMaxIndex(e,o),e}var a=[].concat(e,r);return a.length>t?markOverflow(arrayToObject(a,{plainObjects:n}),a.length-1):a},maybeMap=function maybeMap(e,r){if(isArray(e)){for(var t=[],n=0;n<e.length;n+=1)t[t.length]=r(e[n]);return t}return r(e)};module.exports={/* common-shake removed: arrayToObject:arrayToObject *//* common-shake removed: assign:assign */combine:combine,compact:compact,decode:decode,encode:encode,isBuffer:isBuffer,isOverflow:isOverflow,isRegExp:isRegExp,markOverflow:markOverflow,maybeMap:maybeMap,merge:merge};
14
+ "use strict";var formats=require(1),getSideChannel=require(46),defineProperty=require(14),has=Object.prototype.hasOwnProperty,isArray=Array.isArray,overflowChannel=getSideChannel(),markOverflow=function markOverflow(e,r){return overflowChannel.set(e,r),e},isOverflow=function isOverflow(e){return overflowChannel.has(e)},getMaxIndex=function getMaxIndex(e){return overflowChannel.get(e)},setMaxIndex=function setMaxIndex(e,r){overflowChannel.set(e,r)},hexTable=function(){for(var e=[],r=0;r<256;++r)e[e.length]="%"+((r<16?"0":"")+r.toString(16)).toUpperCase();return e}(),compactQueue=function compactQueue(e){for(;e.length>1;){var r=e.pop(),t=r.obj[r.prop];if(isArray(t)){for(var n=[],a=0;a<t.length;++a)void 0!==t[a]&&(n[n.length]=t[a]);r.obj[r.prop]=n}}},arrayToObject=function arrayToObject(e,r){for(var t=r&&r.plainObjects?{__proto__:null}:{},n=0;n<e.length;++n)void 0!==e[n]&&(t[n]=e[n]);return t},setProperty=function setProperty(e,r,t){"__proto__"===r&&defineProperty?defineProperty(e,r,{configurable:!0,enumerable:!0,value:t,writable:!0}):e[r]=t},merge=function merge(e,r,t){if(!r)return e;if("object"!=typeof r&&"function"!=typeof r){if(isArray(e)){var n=e.length;if(t&&"number"==typeof t.arrayLimit&&n>=t.arrayLimit){if(t.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");return markOverflow(arrayToObject(e.concat(r),t),n)}e[n]=r}else{if(!e||"object"!=typeof e)return[e,r];if(isOverflow(e)){var a=getMaxIndex(e)+1;e[a]=r,setMaxIndex(e,a)}else{if(t&&t.strictMerge)return[e,r];(t&&(t.plainObjects||t.allowPrototypes)||!has.call(Object.prototype,r))&&(e[r]=!0)}}return e}if(!e||"object"!=typeof e){if(isOverflow(r)){for(var o=Object.keys(r),i=t&&t.plainObjects?{__proto__:null,0:e}:{0:e},l=0;l<o.length;l++)i[parseInt(o[l],10)+1]=r[o[l]];return markOverflow(i,getMaxIndex(r)+1)}var c=[e].concat(r);if(t&&"number"==typeof t.arrayLimit&&c.length>t.arrayLimit){if(t.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");return markOverflow(arrayToObject(c,t),c.length-1)}return c}var f=e;if(isArray(e)&&!isArray(r)&&(f=arrayToObject(e,t)),isArray(e)&&isArray(r)){if(r.forEach(function(r,n){if(has.call(e,n)){var a=e[n];a&&"object"==typeof a&&r&&"object"==typeof r?e[n]=merge(a,r,t):e[e.length]=r}else e[n]=r}),t&&"number"==typeof t.arrayLimit&&e.length>t.arrayLimit){if(t.throwOnLimitExceeded)throw new RangeError("Array limit exceeded. Only "+t.arrayLimit+" element"+(1===t.arrayLimit?"":"s")+" allowed in an array.");return markOverflow(arrayToObject(e,t),e.length-1)}return e}return Object.keys(r).reduce(function(e,n){var a=r[n];if(has.call(e,n)?setProperty(e,n,merge(e[n],a,t)):setProperty(e,n,a),isOverflow(r)&&!isOverflow(e)&&markOverflow(e,getMaxIndex(r)),isOverflow(e)){var o=parseInt(n,10);String(o)===n&&o>=0&&o>getMaxIndex(e)&&setMaxIndex(e,o)}return e},f)},assign=function assignSingleSource(e,r){return Object.keys(r).reduce(function(e,t){return setProperty(e,t,r[t]),e},e)},decode=function(e,r,t){var n=e.replace(/\+/g," ");if("iso-8859-1"===t)return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch(e){return n}},limit=1024,encode=function encode(e,r,t,n,a){if(0===e.length)return e;var o=e;if("symbol"==typeof e?o=Symbol.prototype.toString.call(e):"string"!=typeof e&&(o=String(e)),"iso-8859-1"===t)return escape(o).replace(/%u[0-9a-f]{4}/gi,function(e){return"%26%23"+parseInt(e.slice(2),16)+"%3B"});for(var i="",l=0;l<o.length;l+=limit){var c=o.length>=limit?o.slice(l,l+limit):o;if(l+limit<o.length){var f=c.charCodeAt(c.length-1);f>=55296&&f<=56319&&(c=c.slice(0,-1),l-=1)}for(var s=[],u=0;u<c.length;++u){var y=c.charCodeAt(u);45===y||46===y||95===y||126===y||y>=48&&y<=57||y>=65&&y<=90||y>=97&&y<=122||a===formats.RFC1738&&(40===y||41===y)?s[s.length]=c.charAt(u):y<128?s[s.length]=hexTable[y]:y<2048?s[s.length]=hexTable[192|y>>6]+hexTable[128|63&y]:y<55296||y>=57344?s[s.length]=hexTable[224|y>>12]+hexTable[128|y>>6&63]+hexTable[128|63&y]:(u+=1,y=65536+((1023&y)<<10|1023&c.charCodeAt(u)),s[s.length]=hexTable[240|y>>18]+hexTable[128|y>>12&63]+hexTable[128|y>>6&63]+hexTable[128|63&y])}i+=s.join("")}return i},compact=function compact(e){for(var r=[{obj:{o:e},prop:"o"}],t=getSideChannel(),n=0;n<r.length;++n)for(var a=r[n],o=a.obj[a.prop],i=Object.keys(o),l=0;l<i.length;++l){var c=i[l],f=o[c];"object"!=typeof f||null===f||t.has(f)||(r[r.length]={obj:o,prop:c},t.set(f,!0))}return compactQueue(r),e},isRegExp=function isRegExp(e){return"[object RegExp]"===Object.prototype.toString.call(e)},isBuffer=function isBuffer(e){return!(!e||"object"!=typeof e||!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e)))},combine=function combine(e,r,t,n,a){if(isOverflow(e)){if(a)throw new RangeError("Array limit exceeded. Only "+t+" element"+(1===t?"":"s")+" allowed in an array.");var o=getMaxIndex(e)+1;return e[o]=r,setMaxIndex(e,o),e}var i=[].concat(e,r);if(i.length>t){if(a)throw new RangeError("Array limit exceeded. Only "+t+" element"+(1===t?"":"s")+" allowed in an array.");return markOverflow(arrayToObject(i,{plainObjects:n}),i.length-1)}return i},maybeMap=function maybeMap(e,r){if(isArray(e)){for(var t=[],n=0;n<e.length;n+=1)t[t.length]=r(e[n]);return t}return r(e)};module.exports={/* common-shake removed: arrayToObject:arrayToObject *//* common-shake removed: assign:assign */combine:combine,compact:compact,decode:decode,encode:encode,isBuffer:isBuffer,isOverflow:isOverflow,isRegExp:isRegExp,markOverflow:markOverflow,maybeMap:maybeMap,merge:merge};
15
15
 
16
- },{"1":1,"46":46}],46:[function(require,module,exports){
17
- "use strict";var $TypeError=require(20),inspect=require(42),getSideChannelList=require(43),getSideChannelMap=require(44),getSideChannelWeakMap=require(45),makeChannel=getSideChannelWeakMap||getSideChannelMap||getSideChannelList;module.exports=function getSideChannel(){var e,n={assert:function(e){if(!n.has(e))throw new $TypeError("Side channel does not contain "+inspect(e))},delete:function(n){return!!e&&e.delete(n)},get:function(n){return e&&e.get(n)},has:function(n){return!!e&&e.has(n)},set:function(n,t){e||(e=makeChannel()),e.set(n,t)}};return n};
16
+ },{"1":1,"14":14,"46":46}],46:[function(require,module,exports){
17
+ "use strict";var $TypeError=require(20),inspect=require(42),getSideChannelList=require(43),getSideChannelMap=require(44),getSideChannelWeakMap=require(45),makeChannel=getSideChannelWeakMap||getSideChannelMap||getSideChannelList;module.exports=function getSideChannel(){var e,n={assert:function(e){if(!n.has(e)){var t=e&&Object(e)===e?"the given object key":inspect(e);throw new $TypeError("Side channel does not contain "+t)}},delete:function(n){return!!e&&e.delete(n)},get:function(n){return e&&e.get(n)},has:function(n){return!!e&&e.has(n)},set:function(n,t){e||(e=makeChannel()),e.set(n,t)}};return n};
18
18
 
19
- },{"20":20,"42":42,"43":43,"44":44,"45":45}],6:[function(require,module,exports){
19
+ },{"20":20,"42":42,"43":43,"44":44,"45":45}],14:[function(require,module,exports){
20
+ "use strict";var $defineProperty=Object.defineProperty||!1;if($defineProperty)try{$defineProperty({},"a",{value:1})}catch(e){$defineProperty=!1}module.exports=$defineProperty;
21
+
22
+ },{}],6:[function(require,module,exports){
20
23
 
21
24
  },{}],7:[function(require,module,exports){
22
25
  "use strict";var bind=require(24),$apply=require(8),$call=require(9),$reflectApply=require(11);module.exports=$reflectApply||bind.call($call,$apply);
@@ -51,10 +54,7 @@
51
54
  },{"10":10,"30":30}],30:[function(require,module,exports){
52
55
  "use strict";var $gOPD=require(29);if($gOPD)try{$gOPD([],"length")}catch(g){$gOPD=null}module.exports=$gOPD;
53
56
 
54
- },{"29":29}],14:[function(require,module,exports){
55
- "use strict";var $defineProperty=Object.defineProperty||!1;if($defineProperty)try{$defineProperty({},"a",{value:1})}catch(e){$defineProperty=!1}module.exports=$defineProperty;
56
-
57
- },{}],15:[function(require,module,exports){
57
+ },{"29":29}],15:[function(require,module,exports){
58
58
  "use strict";module.exports=EvalError;
59
59
 
60
60
  },{}],16:[function(require,module,exports){
@@ -78,8 +78,11 @@
78
78
  },{}],23:[function(require,module,exports){
79
79
  "use strict";var ERROR_MESSAGE="Function.prototype.bind called on incompatible ",toStr=Object.prototype.toString,max=Math.max,funcType="[object Function]",concatty=function concatty(t,n){for(var r=[],o=0;o<t.length;o+=1)r[o]=t[o];for(var e=0;e<n.length;e+=1)r[e+t.length]=n[e];return r},slicy=function slicy(t,n){for(var r=[],o=n||0,e=0;o<t.length;o+=1,e+=1)r[e]=t[o];return r},joiny=function(t,n){for(var r="",o=0;o<t.length;o+=1)r+=t[o],o+1<t.length&&(r+=n);return r};module.exports=function bind(t){var n=this;if("function"!=typeof n||toStr.apply(n)!==funcType)throw new TypeError(ERROR_MESSAGE+n);for(var r,o=slicy(arguments,1),e=max(0,n.length-o.length),i=[],c=0;c<e;c++)i[c]="$"+c;if(r=Function("binder","return function ("+joiny(i,",")+"){ return binder.apply(this,arguments); }")(function(){if(this instanceof r){var e=n.apply(this,concatty(o,arguments));return Object(e)===e?e:this}return n.apply(t,concatty(o,arguments))}),n.prototype){var p=function Empty(){};p.prototype=n.prototype,r.prototype=new p,p.prototype=null}return r};
80
80
 
81
- },{}],35:[function(require,module,exports){
82
- "use strict";module.exports=Math.floor;
81
+ },{}],37:[function(require,module,exports){
82
+ "use strict";module.exports=Math.max;
83
+
84
+ },{}],40:[function(require,module,exports){
85
+ "use strict";module.exports=Math.round;
83
86
 
84
87
  },{}],34:[function(require,module,exports){
85
88
  "use strict";module.exports=Math.abs;
@@ -87,15 +90,12 @@
87
90
  },{}],38:[function(require,module,exports){
88
91
  "use strict";module.exports=Math.min;
89
92
 
90
- },{}],40:[function(require,module,exports){
91
- "use strict";module.exports=Math.round;
92
-
93
- },{}],37:[function(require,module,exports){
94
- "use strict";module.exports=Math.max;
95
-
96
93
  },{}],39:[function(require,module,exports){
97
94
  "use strict";module.exports=Math.pow;
98
95
 
96
+ },{}],35:[function(require,module,exports){
97
+ "use strict";module.exports=Math.floor;
98
+
99
99
  },{}],27:[function(require,module,exports){
100
100
  "use strict";module.exports="undefined"!=typeof Reflect&&Reflect.getPrototypeOf||null;
101
101
 
package/lib/parse.js CHANGED
@@ -36,8 +36,19 @@ var interpretNumericEntities = function (str) {
36
36
  });
37
37
  };
38
38
 
39
- var parseArrayValue = function (val, options, currentArrayLength) {
39
+ var parseArrayValue = function (val, options, currentArrayLength, isFlatArrayValue) {
40
40
  if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
41
+ if (isFlatArrayValue && options.throwOnLimitExceeded) {
42
+ var commaCount = 0;
43
+ var commaIndex = val.indexOf(',');
44
+ while (commaIndex > -1) {
45
+ commaCount += 1;
46
+ if (commaCount >= options.arrayLimit) {
47
+ throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
48
+ }
49
+ commaIndex = val.indexOf(',', commaIndex + 1);
50
+ }
51
+ }
41
52
  return val.split(',');
42
53
  }
43
54
 
@@ -114,7 +125,8 @@ var parseValues = function parseQueryStringValues(str, options) {
114
125
  parseArrayValue(
115
126
  part.slice(pos + 1),
116
127
  options,
117
- isArray(obj[key]) ? obj[key].length : 0
128
+ isArray(obj[key]) ? obj[key].length : 0,
129
+ part.indexOf('[]=') === -1
118
130
  ),
119
131
  function (encodedVal) {
120
132
  return options.decoder(encodedVal, defaults.decoder, charset, 'value');
@@ -132,10 +144,7 @@ var parseValues = function parseQueryStringValues(str, options) {
132
144
  }
133
145
 
134
146
  if (options.comma && isArray(val) && val.length > options.arrayLimit) {
135
- if (options.throwOnLimitExceeded) {
136
- throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
137
- }
138
- val = utils.combine([], val, options.arrayLimit, options.plainObjects);
147
+ val = utils.combine([], val, options.arrayLimit, options.plainObjects, options.throwOnLimitExceeded);
139
148
  }
140
149
 
141
150
  if (key !== null) {
@@ -145,7 +154,8 @@ var parseValues = function parseQueryStringValues(str, options) {
145
154
  obj[key],
146
155
  val,
147
156
  options.arrayLimit,
148
- options.plainObjects
157
+ options.plainObjects,
158
+ options.throwOnLimitExceeded
149
159
  );
150
160
  } else if (!existing || options.duplicates === 'last') {
151
161
  obj[key] = val;
@@ -180,7 +190,8 @@ var parseObject = function (chain, val, options, valuesParsed) {
180
190
  [],
181
191
  leaf,
182
192
  options.arrayLimit,
183
- options.plainObjects
193
+ options.plainObjects,
194
+ options.throwOnLimitExceeded
184
195
  );
185
196
  }
186
197
  } else {
package/lib/utils.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var formats = require('./formats');
4
4
  var getSideChannel = require('side-channel');
5
+ var defineProperty = require('es-define-property');
5
6
 
6
7
  var has = Object.prototype.hasOwnProperty;
7
8
  var isArray = Array.isArray;
@@ -66,6 +67,19 @@ var arrayToObject = function arrayToObject(source, options) {
66
67
  return obj;
67
68
  };
68
69
 
70
+ var setProperty = function setProperty(obj, key, value) {
71
+ if (key === '__proto__' && defineProperty) {
72
+ defineProperty(obj, key, {
73
+ configurable: true,
74
+ enumerable: true,
75
+ value: value,
76
+ writable: true
77
+ });
78
+ } else {
79
+ obj[key] = value;
80
+ }
81
+ };
82
+
69
83
  var merge = function merge(target, source, options) {
70
84
  /* eslint no-param-reassign: 0 */
71
85
  if (!source) {
@@ -75,7 +89,10 @@ var merge = function merge(target, source, options) {
75
89
  if (typeof source !== 'object' && typeof source !== 'function') {
76
90
  if (isArray(target)) {
77
91
  var nextIndex = target.length;
78
- if (options && typeof options.arrayLimit === 'number' && nextIndex > options.arrayLimit) {
92
+ if (options && typeof options.arrayLimit === 'number' && nextIndex >= options.arrayLimit) {
93
+ if (options.throwOnLimitExceeded) {
94
+ throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
95
+ }
79
96
  return markOverflow(arrayToObject(target.concat(source), options), nextIndex);
80
97
  }
81
98
  target[nextIndex] = source;
@@ -115,6 +132,9 @@ var merge = function merge(target, source, options) {
115
132
  }
116
133
  var combined = [target].concat(source);
117
134
  if (options && typeof options.arrayLimit === 'number' && combined.length > options.arrayLimit) {
135
+ if (options.throwOnLimitExceeded) {
136
+ throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
137
+ }
118
138
  return markOverflow(arrayToObject(combined, options), combined.length - 1);
119
139
  }
120
140
  return combined;
@@ -138,6 +158,12 @@ var merge = function merge(target, source, options) {
138
158
  target[i] = item;
139
159
  }
140
160
  });
161
+ if (options && typeof options.arrayLimit === 'number' && target.length > options.arrayLimit) {
162
+ if (options.throwOnLimitExceeded) {
163
+ throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
164
+ }
165
+ return markOverflow(arrayToObject(target, options), target.length - 1);
166
+ }
141
167
  return target;
142
168
  }
143
169
 
@@ -145,9 +171,9 @@ var merge = function merge(target, source, options) {
145
171
  var value = source[key];
146
172
 
147
173
  if (has.call(acc, key)) {
148
- acc[key] = merge(acc[key], value, options);
174
+ setProperty(acc, key, merge(acc[key], value, options));
149
175
  } else {
150
- acc[key] = value;
176
+ setProperty(acc, key, value);
151
177
  }
152
178
 
153
179
  if (isOverflow(source) && !isOverflow(acc)) {
@@ -166,7 +192,7 @@ var merge = function merge(target, source, options) {
166
192
 
167
193
  var assign = function assignSingleSource(target, source) {
168
194
  return Object.keys(source).reduce(function (acc, key) {
169
- acc[key] = source[key];
195
+ setProperty(acc, key, source[key]);
170
196
  return acc;
171
197
  }, target);
172
198
  };
@@ -212,6 +238,13 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
212
238
  var out = '';
213
239
  for (var j = 0; j < string.length; j += limit) {
214
240
  var segment = string.length >= limit ? string.slice(j, j + limit) : string;
241
+ if (j + limit < string.length) {
242
+ var last = segment.charCodeAt(segment.length - 1);
243
+ if (last >= 0xD800 && last <= 0xDBFF) {
244
+ segment = segment.slice(0, -1);
245
+ j -= 1;
246
+ }
247
+ }
215
248
  var arr = [];
216
249
 
217
250
  for (var i = 0; i < segment.length; ++i) {
@@ -265,7 +298,7 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
265
298
 
266
299
  var compact = function compact(value) {
267
300
  var queue = [{ obj: { o: value }, prop: 'o' }];
268
- var refs = [];
301
+ var refs = getSideChannel();
269
302
 
270
303
  for (var i = 0; i < queue.length; ++i) {
271
304
  var item = queue[i];
@@ -275,9 +308,9 @@ var compact = function compact(value) {
275
308
  for (var j = 0; j < keys.length; ++j) {
276
309
  var key = keys[j];
277
310
  var val = obj[key];
278
- if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {
311
+ if (typeof val === 'object' && val !== null && !refs.has(val)) {
279
312
  queue[queue.length] = { obj: obj, prop: key };
280
- refs[refs.length] = val;
313
+ refs.set(val, true);
281
314
  }
282
315
  }
283
316
  }
@@ -299,9 +332,12 @@ var isBuffer = function isBuffer(obj) {
299
332
  return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));
300
333
  };
301
334
 
302
- var combine = function combine(a, b, arrayLimit, plainObjects) {
335
+ var combine = function combine(a, b, arrayLimit, plainObjects, throwOnLimitExceeded) {
303
336
  // If 'a' is already an overflow object, add to it
304
337
  if (isOverflow(a)) {
338
+ if (throwOnLimitExceeded) {
339
+ throw new RangeError('Array limit exceeded. Only ' + arrayLimit + ' element' + (arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
340
+ }
305
341
  var newIndex = getMaxIndex(a) + 1;
306
342
  a[newIndex] = b;
307
343
  setMaxIndex(a, newIndex);
@@ -310,6 +346,9 @@ var combine = function combine(a, b, arrayLimit, plainObjects) {
310
346
 
311
347
  var result = [].concat(a, b);
312
348
  if (result.length > arrayLimit) {
349
+ if (throwOnLimitExceeded) {
350
+ throw new RangeError('Array limit exceeded. Only ' + arrayLimit + ' element' + (arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
351
+ }
313
352
  return markOverflow(arrayToObject(result, { plainObjects: plainObjects }), result.length - 1);
314
353
  }
315
354
  return result;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "qs",
3
3
  "description": "A querystring parser that supports nesting and arrays, with a depth limit",
4
4
  "homepage": "https://github.com/ljharb/qs",
5
- "version": "6.15.2",
5
+ "version": "6.15.3",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/ljharb/qs.git"
@@ -31,7 +31,8 @@
31
31
  "node": ">=0.6"
32
32
  },
33
33
  "dependencies": {
34
- "side-channel": "^1.1.0"
34
+ "es-define-property": "^1.0.1",
35
+ "side-channel": "^1.1.1"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@browserify/envify": "^6.0.0",
@@ -42,7 +43,7 @@
42
43
  "common-shakeify": "~1.0.0",
43
44
  "eclint": "^2.8.1",
44
45
  "es-value-fixtures": "^1.7.1",
45
- "eslint": "^9.39.2",
46
+ "eslint": "^10.5.0",
46
47
  "evalmd": "^0.0.19",
47
48
  "for-each": "^0.3.5",
48
49
  "glob": "=10.3.7",
@@ -56,7 +57,7 @@
56
57
  "jackspeak": "=2.1.1",
57
58
  "jiti": "^0.0.0",
58
59
  "mkdirp": "^0.5.5",
59
- "mock-property": "^1.1.0",
60
+ "mock-property": "^1.1.2",
60
61
  "module-deps": "^6.2.3",
61
62
  "npmignore": "^0.3.5",
62
63
  "nyc": "^10.3.2",
@@ -64,7 +65,7 @@
64
65
  "qs-iconv": "^1.0.4",
65
66
  "safe-publish-latest": "^2.0.0",
66
67
  "safer-buffer": "^2.1.2",
67
- "tape": "^5.9.0",
68
+ "tape": "^5.10.2",
68
69
  "unassertify": "^3.0.1"
69
70
  },
70
71
  "scripts": {
package/test/parse.js CHANGED
@@ -14,6 +14,12 @@ var hasProto = require('has-proto')();
14
14
  var qs = require('../');
15
15
  var utils = require('../lib/utils');
16
16
 
17
+ var characterizeParse = function characterizeParse(st, input, opts, expected, label) {
18
+ var result;
19
+ st.doesNotThrow(function () { result = qs.parse(input, opts); }, label + ': does not throw');
20
+ st.deepEqual(result, expected, label + ': parses to the current lenient output');
21
+ };
22
+
17
23
  test('parse()', function (t) {
18
24
  t.test('parses a simple string', function (st) {
19
25
  st.deepEqual(qs.parse('0=foo'), { 0: 'foo' });
@@ -312,6 +318,48 @@ test('parse()', function (t) {
312
318
  st.end();
313
319
  });
314
320
 
321
+ t.test('currently parses unbalanced bracket keys after a parent leniently to literal segments (issue #558)', function (st) {
322
+ characterizeParse(st, 'a[bc=v', undefined, { a: { '[bc': 'v' } }, 'unclosed group after a parent');
323
+ characterizeParse(st, 'a[=v', undefined, { a: { '[': 'v' } }, 'bare unclosed bracket after a parent');
324
+ characterizeParse(st, 'a[b][c=v', undefined, { a: { b: { '[c': 'v' } } }, 'unclosed group after a valid one');
325
+ characterizeParse(st, 'a[b]c[d=v', undefined, { a: { b: { '[d': 'v' } } }, 'unclosed group after text following a valid one');
326
+ characterizeParse(st, 'filters[customtags:Env: Prod=v', undefined, { filters: { '[customtags:Env: Prod': 'v' } }, 'the issue #558 reproduction');
327
+ characterizeParse(st, '][a=v', undefined, { ']': { '[a': 'v' } }, 'stray close bracket before an unclosed group');
328
+ characterizeParse(st, 'a][b=v', undefined, { 'a]': { '[b': 'v' } }, 'stray close bracket inside the parent');
329
+ st.end();
330
+ });
331
+
332
+ t.test('currently parses unbalanced bracket keys containing inner brackets leniently (issue #558)', function (st) {
333
+ characterizeParse(st, 'a[b[c=v', undefined, { a: { '[b[c': 'v' } }, 'unclosed group containing an inner bracket');
334
+ characterizeParse(st, 'a[b[c]=v', undefined, { a: { '[b[c]': 'v' } }, 'unbalanced group with an inner bracket and one close');
335
+ characterizeParse(st, 'a[b][c[d=v', undefined, { a: { b: { '[c[d': 'v' } } }, 'unclosed inner-bracket group after a valid one');
336
+ st.end();
337
+ });
338
+
339
+ t.test('currently parses bracket-prefixed unbalanced keys leniently (issue #558)', function (st) {
340
+ characterizeParse(st, '[abc=v', undefined, { '[abc': 'v' }, 'key starting with an unclosed bracket');
341
+ characterizeParse(st, '[[]b=v', undefined, { '[[]b': 'v' }, 'key starting with an unbalanced bracket group');
342
+ st.end();
343
+ });
344
+
345
+ t.test('lenient unbalanced-bracket handling currently depends on the depth option (issue #558)', function (st) {
346
+ characterizeParse(st, 'a[b]c[d]e[f=v', { depth: 5 }, { a: { b: { d: { '[f': 'v' } } } }, 'consumes groups up to the depth budget then keeps the unclosed remainder literal');
347
+ characterizeParse(st, 'a[b]c[d]e[f=v', { depth: 1 }, { a: { b: { '[d]e[f': 'v' } } }, 'a lower depth keeps more of the unclosed remainder literal');
348
+ characterizeParse(st, 'a[bc=v', { depth: 0 }, { 'a[bc': 'v' }, 'depth 0 keeps the entire key literal');
349
+ st.end();
350
+ });
351
+
352
+ t.test('currently parses an allowDots key with a trailing unclosed bracket leniently (issue #558)', function (st) {
353
+ characterizeParse(st, 'a.b[c=v', { allowDots: true }, { a: { b: { '[c': 'v' } } }, 'allowDots expands the dot then keeps the unclosed bracket literal');
354
+ st.end();
355
+ });
356
+
357
+ t.test('valid and stray-close bracket keys are unaffected by unbalanced-bracket handling', function (st) {
358
+ characterizeParse(st, 'a]b=v', undefined, { 'a]b': 'v' }, 'stray close bracket with no open bracket stays a flat key');
359
+ characterizeParse(st, 'a[b]extra=v', undefined, { a: { b: 'v' } }, 'text after a balanced group is ignored');
360
+ st.end();
361
+ });
362
+
315
363
  t.test('allows to specify array indices', function (st) {
316
364
  st.deepEqual(qs.parse('a[1]=c&a[0]=b&a[2]=d'), { a: ['b', 'c', 'd'] });
317
365
  st.deepEqual(qs.parse('a[1]=c&a[0]=b'), { a: ['b', 'c'] });
@@ -726,6 +774,21 @@ test('parse()', function (t) {
726
774
  st.end();
727
775
  });
728
776
 
777
+ t.test('does not crash on multi-step circular references', function (st) {
778
+ var a = {};
779
+ a.b = { c: { d: a } };
780
+
781
+ var parsed;
782
+
783
+ st.doesNotThrow(function () {
784
+ parsed = qs.parse({ foo: a });
785
+ });
786
+
787
+ st.equal('foo' in parsed, true, 'parsed has "foo" property');
788
+ st.equal(parsed.foo.b.c.d, parsed.foo, 'the multi-step cycle is preserved');
789
+ st.end();
790
+ });
791
+
729
792
  t.test('does not crash when parsing deep objects', function (st) {
730
793
  var parsed;
731
794
  var str = 'foo';
@@ -959,6 +1022,22 @@ test('parse()', function (t) {
959
1022
  st.end();
960
1023
  });
961
1024
 
1025
+ t.test('object-valued input with own `__proto__` does not mutate sub-object [[Prototype]]', function (st) {
1026
+ // JSON.parse creates own data `__proto__` properties (via CreateDataProperty),
1027
+ // which would trigger the Object.prototype.__proto__ accessor if merged via `acc[key] = value`.
1028
+ var out = qs.parse({
1029
+ 'user[name]': 'alice',
1030
+ user: JSON.parse('{"__proto__":{"isAdmin":true}}')
1031
+ }, { allowPrototypes: false });
1032
+
1033
+ st.equal(out.user.name, 'alice', 'name from bracket key is preserved');
1034
+ st.equal(out.user.isAdmin, undefined, 'attacker-controlled inherited property is not exposed');
1035
+ st.equal(Object.getPrototypeOf(out.user), Object.prototype, 'sub-object [[Prototype]] is unchanged');
1036
+ st.equal(Object.prototype.isAdmin, undefined, 'Object.prototype is not polluted');
1037
+
1038
+ st.end();
1039
+ });
1040
+
962
1041
  t.test('can return null objects', { skip: !hasProto }, function (st) {
963
1042
  var expected = {
964
1043
  __proto__: null,
@@ -1309,6 +1388,157 @@ test('parse()', function (t) {
1309
1388
  sst.end();
1310
1389
  });
1311
1390
 
1391
+ st.test('throws when cumulative comma + duplicate-key combine exceeds arrayLimit', function (sst) {
1392
+ sst['throws'](
1393
+ function () {
1394
+ qs.parse('a=1,2,3&a=4,5,6', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1395
+ },
1396
+ new RangeError('Array limit exceeded. Only 5 elements allowed in an array.'),
1397
+ 'throws when comma groups within the limit cumulatively exceed it across duplicate keys'
1398
+ );
1399
+
1400
+ sst['throws'](
1401
+ function () {
1402
+ qs.parse('a=v,v,v,v,v&a=v,v,v,v,v&a=v,v,v,v,v', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1403
+ },
1404
+ new RangeError('Array limit exceeded. Only 5 elements allowed in an array.'),
1405
+ 'throws on a subsequent part once the cumulative array is already over the limit'
1406
+ );
1407
+ sst.end();
1408
+ });
1409
+
1410
+ st.test('throws when plain duplicate keys combine past arrayLimit at the boundary', function (sst) {
1411
+ sst['throws'](
1412
+ function () { qs.parse('a=x&a=y', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1413
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1414
+ 'duplicate scalar keys'
1415
+ );
1416
+
1417
+ sst['throws'](
1418
+ function () { qs.parse('a[]=x&a[]=y', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1419
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1420
+ 'duplicate bracket keys'
1421
+ );
1422
+ sst.end();
1423
+ });
1424
+
1425
+ st.test('throws when mixed index and key notation merge past arrayLimit', function (sst) {
1426
+ sst['throws'](
1427
+ function () { qs.parse('a=x&a[0]=y', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1428
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1429
+ 'scalar then index that overflows on merge'
1430
+ );
1431
+
1432
+ sst['throws'](
1433
+ function () { qs.parse('a[0]=1&a[1]=2&a=3', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1434
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1435
+ 'indexed array then scalar that overflows on merge'
1436
+ );
1437
+ sst.end();
1438
+ });
1439
+
1440
+ st.test('enforces arrayLimit on merge at the boundary, consistently with combine', function (sst) {
1441
+ sst['throws'](
1442
+ function () { qs.parse('a[0]=x&a=y', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1443
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1444
+ 'a trailing scalar merged into an at-limit array throws'
1445
+ );
1446
+ sst.deepEqual(
1447
+ qs.parse('a[0]=x&a=y', { arrayLimit: 1 }),
1448
+ { a: { 0: 'x', 1: 'y' } },
1449
+ 'and converts to an overflow object without throwOnLimitExceeded'
1450
+ );
1451
+
1452
+ sst['throws'](
1453
+ function () { qs.parse('a[0]=x&a[]=y', { arrayLimit: 1, throwOnLimitExceeded: true }); },
1454
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1455
+ 'mixed index and bracket notation merged past the limit throws'
1456
+ );
1457
+ sst.deepEqual(
1458
+ qs.parse('a[0]=x&a[]=y', { arrayLimit: 1 }),
1459
+ { a: { 0: 'x', 1: 'y' } },
1460
+ 'mixed index and bracket notation converts like duplicate-bracket combine'
1461
+ );
1462
+
1463
+ sst.end();
1464
+ });
1465
+
1466
+ st.test('does not throw when cumulative comma combine stays within arrayLimit', function (sst) {
1467
+ var result = qs.parse('a=1,2,3&a=4', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1468
+ sst.deepEqual(result, { a: ['1', '2', '3', '4'] }, 'combined array within limit is preserved');
1469
+ sst.end();
1470
+ });
1471
+
1472
+ st.test('silently combines to an overflow object when throwOnLimitExceeded is not set', function (sst) {
1473
+ var result = qs.parse('a=1,2,3&a=4,5,6', { comma: true, arrayLimit: 5 });
1474
+ sst.deepEqual(result, { a: { 0: '1', 1: '2', 2: '3', 3: '4', 4: '5', 5: '6' } }, 'converts to object without throwing');
1475
+ sst.end();
1476
+ });
1477
+
1478
+ st.test('does not throw for comma groups nested under bracket notation, counting each group as one element', function (sst) {
1479
+ var result = qs.parse('a[]=1,2,3&a[]=4,5,6', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1480
+ sst.deepEqual(result, { a: [['1', '2', '3'], ['4', '5', '6']] }, 'nested comma groups count as one element each');
1481
+ sst.end();
1482
+ });
1483
+
1484
+ st.test('throws before splitting when a single comma value exceeds arrayLimit', function (sst) {
1485
+ sst['throws'](
1486
+ function () {
1487
+ qs.parse('a=1,2,3,4,5,6', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1488
+ },
1489
+ new RangeError('Array limit exceeded. Only 5 elements allowed in an array.'),
1490
+ 'a flat comma value over the limit throws'
1491
+ );
1492
+
1493
+ sst['throws'](
1494
+ function () {
1495
+ qs.parse('a=1,2', { comma: true, arrayLimit: 1, throwOnLimitExceeded: true });
1496
+ },
1497
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
1498
+ 'singular message at arrayLimit 1'
1499
+ );
1500
+
1501
+ sst['throws'](
1502
+ function () {
1503
+ qs.parse('a[b]=1,2,3,4,5,6', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1504
+ },
1505
+ new RangeError('Array limit exceeded. Only 5 elements allowed in an array.'),
1506
+ 'a non-bracket nested key comma value over the limit throws'
1507
+ );
1508
+ sst.end();
1509
+ });
1510
+
1511
+ st.test('does not throw for a single comma value within arrayLimit', function (sst) {
1512
+ sst.deepEqual(
1513
+ qs.parse('a=1,2,3', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true }),
1514
+ { a: ['1', '2', '3'] },
1515
+ 'within the limit'
1516
+ );
1517
+ sst.deepEqual(
1518
+ qs.parse('a=1,2,3,4,5', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true }),
1519
+ { a: ['1', '2', '3', '4', '5'] },
1520
+ 'exactly at the limit'
1521
+ );
1522
+ sst.end();
1523
+ });
1524
+
1525
+ st.test('does not throw for a bracketed comma group within arrayLimit', function (sst) {
1526
+ var result = qs.parse('a[]=1,2,3,4,5,6', { comma: true, arrayLimit: 5, throwOnLimitExceeded: true });
1527
+ sst.deepEqual(result, { a: [['1', '2', '3', '4', '5', '6']] }, 'a bracketed comma group is a single element');
1528
+ sst.end();
1529
+ });
1530
+
1531
+ st.test('throws for a bracketed comma group when arrayLimit is 0', function (sst) {
1532
+ sst['throws'](
1533
+ function () {
1534
+ qs.parse('a[]=1,2,3', { comma: true, arrayLimit: 0, throwOnLimitExceeded: true });
1535
+ },
1536
+ new RangeError('Array limit exceeded. Only 0 elements allowed in an array.'),
1537
+ 'a single bracketed element still exceeds arrayLimit 0'
1538
+ );
1539
+ sst.end();
1540
+ });
1541
+
1312
1542
  st.end();
1313
1543
  });
1314
1544
 
package/test/utils.js CHANGED
@@ -65,6 +65,7 @@ test('merge()', function (t) {
65
65
  observed[0] = observed[0]; // eslint-disable-line no-self-assign
66
66
  st.equal(setCount, 1);
67
67
  st.equal(getCount, 2);
68
+
68
69
  st.end();
69
70
  }
70
71
  );
@@ -78,6 +79,7 @@ test('merge()', function (t) {
78
79
  s2t.ok(utils.isOverflow(overflow), 'overflow object is marked');
79
80
  var merged = utils.merge(overflow, 'd');
80
81
  s2t.deepEqual(merged, { 0: 'a', 1: 'b', 2: 'c', 3: 'd' }, 'adds primitive at next numeric index');
82
+
81
83
  s2t.end();
82
84
  });
83
85
 
@@ -93,6 +95,7 @@ test('merge()', function (t) {
93
95
  var obj = { foo: 'bar' };
94
96
  var merged = utils.merge(obj, 'baz');
95
97
  s2t.deepEqual(merged, { foo: 'bar', baz: true }, 'adds primitive as key with value true');
98
+
96
99
  s2t.end();
97
100
  });
98
101
 
@@ -110,6 +113,7 @@ test('merge()', function (t) {
110
113
  var merged = utils.merge('c', overflow);
111
114
  s2t.ok(utils.isOverflow(merged), 'result is also marked as overflow');
112
115
  s2t.deepEqual(merged, { 0: 'c', 1: 'a', 2: 'b' }, 'creates object with primitive at 0, source values shifted');
116
+
113
117
  s2t.end();
114
118
  });
115
119
 
@@ -119,6 +123,7 @@ test('merge()', function (t) {
119
123
  var merged = utils.merge('c', overflow, { plainObjects: true });
120
124
  s2t.ok(utils.isOverflow(merged), 'result is also marked as overflow');
121
125
  s2t.deepEqual(merged, { __proto__: null, 0: 'c', 1: 'a', 2: 'b' }, 'creates null-proto object with primitive at 0');
126
+
122
127
  s2t.end();
123
128
  });
124
129
 
@@ -128,6 +133,7 @@ test('merge()', function (t) {
128
133
  s2t.ok(utils.isOverflow(overflow), 'overflow object is marked');
129
134
  var merged = utils.merge('a', overflow);
130
135
  s2t.deepEqual(merged, { 0: 'a', 1: 'b', 2: 'c', 3: 'd' }, 'shifts all source indices by 1');
136
+
131
137
  s2t.end();
132
138
  });
133
139
 
@@ -135,6 +141,7 @@ test('merge()', function (t) {
135
141
  var obj = { foo: 'bar' };
136
142
  var merged = utils.merge('a', obj);
137
143
  s2t.deepEqual(merged, ['a', { foo: 'bar' }], 'creates array with primitive and object');
144
+
138
145
  s2t.end();
139
146
  });
140
147
 
@@ -143,6 +150,7 @@ test('merge()', function (t) {
143
150
  var merged = utils.merge(arr, 'd', { arrayLimit: 1 });
144
151
  s2t.ok(utils.isOverflow(merged), 'result is marked as overflow');
145
152
  s2t.deepEqual(merged, { 0: 'a', 1: 'b', 2: 'c', 3: 'd' }, 'converts to overflow object with primitive appended');
153
+
146
154
  s2t.end();
147
155
  });
148
156
 
@@ -150,6 +158,78 @@ test('merge()', function (t) {
150
158
  var merged = utils.merge('a', ['b', 'c'], { arrayLimit: 1 });
151
159
  s2t.ok(utils.isOverflow(merged), 'result is marked as overflow');
152
160
  s2t.deepEqual(merged, { 0: 'a', 1: 'b', 2: 'c' }, 'converts to overflow object');
161
+
162
+ s2t.end();
163
+ });
164
+
165
+ st.test('merges primitive into array at the arrayLimit boundary, consistently with combine', function (s2t) {
166
+ var merged = utils.merge(['a'], 'b', { arrayLimit: 1 });
167
+ s2t.ok(utils.isOverflow(merged), 'result is marked as overflow at the boundary');
168
+ s2t.deepEqual(merged, { 0: 'a', 1: 'b' }, 'converts to overflow object instead of a length-2 array');
169
+
170
+ s2t.end();
171
+ });
172
+
173
+ st.test('merges two arrays that exceed arrayLimit into an overflow object', function (s2t) {
174
+ var merged = utils.merge(['a'], ['b'], { arrayLimit: 1 });
175
+ s2t.ok(utils.isOverflow(merged), 'result is marked as overflow');
176
+ s2t.deepEqual(merged, { 0: 'a', 1: 'b' }, 'array-into-array merge enforces arrayLimit like combine');
177
+
178
+ s2t.end();
179
+ });
180
+
181
+ st.test('throws at the arrayLimit boundary when merging a primitive into an array with throwOnLimitExceeded', function (s2t) {
182
+ s2t['throws'](
183
+ function () { utils.merge(['a'], 'b', { arrayLimit: 1, throwOnLimitExceeded: true }); },
184
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
185
+ 'throws when the resulting length would exceed arrayLimit'
186
+ );
187
+
188
+ s2t.end();
189
+ });
190
+
191
+ st.test('throws when merging two arrays past arrayLimit with throwOnLimitExceeded', function (s2t) {
192
+ s2t['throws'](
193
+ function () { utils.merge(['a'], ['b'], { arrayLimit: 1, throwOnLimitExceeded: true }); },
194
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
195
+ 'array-into-array merge throws rather than silently exceeding arrayLimit'
196
+ );
197
+ s2t['throws'](
198
+ function () { utils.merge(['a', 'b', 'c'], ['d', 'e', 'f'], { arrayLimit: 2, throwOnLimitExceeded: true }); },
199
+ new RangeError('Array limit exceeded. Only 2 elements allowed in an array.'),
200
+ 'uses the plural message when arrayLimit is not 1'
201
+ );
202
+
203
+ s2t.end();
204
+ });
205
+
206
+ st.test('throws instead of merging primitive into over-limit array when throwOnLimitExceeded is set', function (s2t) {
207
+ s2t['throws'](
208
+ function () { utils.merge(['a', 'b', 'c'], 'd', { arrayLimit: 1, throwOnLimitExceeded: true }); },
209
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
210
+ 'throws rather than converting to an overflow object'
211
+ );
212
+ s2t['throws'](
213
+ function () { utils.merge(['a', 'b', 'c'], 'd', { arrayLimit: 2, throwOnLimitExceeded: true }); },
214
+ new RangeError('Array limit exceeded. Only 2 elements allowed in an array.'),
215
+ 'uses the plural message when arrayLimit is not 1'
216
+ );
217
+
218
+ s2t.end();
219
+ });
220
+
221
+ st.test('throws instead of merging array into primitive when throwOnLimitExceeded is set', function (s2t) {
222
+ s2t['throws'](
223
+ function () { utils.merge('a', ['b', 'c'], { arrayLimit: 1, throwOnLimitExceeded: true }); },
224
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
225
+ 'throws rather than converting to an overflow object'
226
+ );
227
+ s2t['throws'](
228
+ function () { utils.merge('a', ['b', 'c', 'd'], { arrayLimit: 2, throwOnLimitExceeded: true }); },
229
+ new RangeError('Array limit exceeded. Only 2 elements allowed in an array.'),
230
+ 'uses the plural message when arrayLimit is not 1'
231
+ );
232
+
153
233
  s2t.end();
154
234
  });
155
235
 
@@ -274,6 +354,47 @@ test('combine()', function (t) {
274
354
  st.end();
275
355
  });
276
356
 
357
+ t.test('with throwOnLimitExceeded', function (st) {
358
+ st.test('throws when concatenation exceeds the limit', function (s2t) {
359
+ s2t['throws'](
360
+ function () { utils.combine(['a', 'b', 'c'], 'd', 3, false, true); },
361
+ new RangeError('Array limit exceeded. Only 3 elements allowed in an array.'),
362
+ 'throws instead of converting to an overflow object'
363
+ );
364
+ s2t['throws'](
365
+ function () { utils.combine([], 'a', 0, false, true); },
366
+ new RangeError('Array limit exceeded. Only 0 elements allowed in an array.'),
367
+ 'throws with the correct count at arrayLimit 0'
368
+ );
369
+ s2t.end();
370
+ });
371
+
372
+ st.test('throws when adding to an existing overflow object', function (s2t) {
373
+ var overflow = utils.combine(['a', 'b'], 'c', 0, false);
374
+ s2t.ok(utils.isOverflow(overflow), 'initial object is marked as overflow');
375
+
376
+ s2t['throws'](
377
+ function () { utils.combine(overflow, 'd', 0, false, true); },
378
+ new RangeError('Array limit exceeded. Only 0 elements allowed in an array.'),
379
+ 'throws rather than appending to the overflow object'
380
+ );
381
+ s2t['throws'](
382
+ function () { utils.combine(overflow, 'd', 1, false, true); },
383
+ new RangeError('Array limit exceeded. Only 1 element allowed in an array.'),
384
+ 'uses the singular message at arrayLimit 1'
385
+ );
386
+ s2t.end();
387
+ });
388
+
389
+ st.test('does not throw when within the limit', function (s2t) {
390
+ var combined = utils.combine(['a'], 'b', 5, false, true);
391
+ s2t.deepEqual(combined, ['a', 'b'], 'returns the array unchanged when under the limit');
392
+ s2t.end();
393
+ });
394
+
395
+ st.end();
396
+ });
397
+
277
398
  t.test('with existing overflow object', function (st) {
278
399
  st.test('adds to existing overflow object at next index', function (s2t) {
279
400
  // Create overflow object first via combine: 3 elements (indices 0-2) with limit 0
@@ -372,6 +493,79 @@ test('encode', function (t) {
372
493
  'encodes a long string'
373
494
  );
374
495
 
496
+ var boundary = '';
497
+ var expected = '';
498
+ for (var j = 0; j < 1023; j++) {
499
+ boundary += 'a';
500
+ expected += 'a';
501
+ }
502
+ boundary += '😀';
503
+ expected += '%F0%9F%98%80';
504
+
505
+ t.equal(
506
+ utils.encode(boundary),
507
+ expected,
508
+ 'encodes a surrogate pair split across long-string chunks'
509
+ );
510
+
511
+ var laterBoundary = '';
512
+ var laterExpected = '';
513
+ for (var k = 0; k < 2047; k++) {
514
+ laterBoundary += 'a';
515
+ laterExpected += 'a';
516
+ }
517
+ laterBoundary += '😀';
518
+ laterExpected += '%F0%9F%98%80';
519
+
520
+ t.equal(
521
+ utils.encode(laterBoundary),
522
+ laterExpected,
523
+ 'encodes a surrogate pair split across a later chunk boundary'
524
+ );
525
+
526
+ var twoPairs = '';
527
+ for (k = 0; k < 1023; k++) {
528
+ twoPairs += 'a';
529
+ }
530
+ twoPairs += '😀';
531
+ for (k = 0; k < 1022; k++) {
532
+ twoPairs += 'b';
533
+ }
534
+ twoPairs += '😀';
535
+
536
+ t.equal(
537
+ (utils.encode(twoPairs).match(/%F0%9F%98%80/g) || []).length,
538
+ 2,
539
+ 'encodes two surrogate pairs each split across a chunk boundary'
540
+ );
541
+
542
+ var roundTrip = '';
543
+ for (k = 0; k < 1023; k++) {
544
+ roundTrip += 'a';
545
+ }
546
+ roundTrip += '😀';
547
+
548
+ t.equal(
549
+ decodeURIComponent(utils.encode(roundTrip)),
550
+ roundTrip,
551
+ 'a boundary-split surrogate pair round-trips through decodeURIComponent'
552
+ );
553
+
554
+ var loneBoundary = '';
555
+ var loneExpected = '';
556
+ for (k = 0; k < 1023; k++) {
557
+ loneBoundary += 'a';
558
+ loneExpected += 'a';
559
+ }
560
+ loneBoundary += '\uD83DX';
561
+ loneExpected += '%F0%9F%91%98';
562
+
563
+ t.equal(
564
+ utils.encode(loneBoundary),
565
+ loneExpected,
566
+ 'a lone high surrogate at a chunk boundary encodes the same as mid-chunk'
567
+ );
568
+
375
569
  t.equal(
376
570
  utils.encode('\x28\x29'),
377
571
  '%28%29',