Comparing version 6.10.1 to 6.10.2
@@ -0,1 +1,11 @@ | ||
## **6.10.2** | ||
- [Fix] `stringify`: actually fix cyclic references (#426) | ||
- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424) | ||
- [readme] remove travis badge; add github actions/codecov badges; update URLs | ||
- [Docs] add note and links for coercing primitive values (#408) | ||
- [actions] update codecov uploader | ||
- [actions] update workflows | ||
- [Tests] clean up stringify tests slightly | ||
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `object-inspect`, `safe-publish-latest`, `tape` | ||
## **6.10.1** | ||
@@ -2,0 +12,0 @@ - [Fix] `stringify`: avoid exception on repeated object values (#402) |
@@ -22,2 +22,3 @@ 'use strict'; | ||
var isArray = Array.isArray; | ||
var split = String.prototype.split; | ||
var push = Array.prototype.push; | ||
@@ -59,2 +60,4 @@ var pushToArray = function (arr, valueOrArray) { | ||
var sentinel = {}; | ||
var stringify = function stringify( | ||
@@ -79,4 +82,19 @@ object, | ||
if (sideChannel.has(object)) { | ||
throw new RangeError('Cyclic object value'); | ||
var tmpSc = sideChannel; | ||
var step = 0; | ||
var findFlag = false; | ||
while ((tmpSc = tmpSc.get(sentinel)) !== undefined && !findFlag) { | ||
// Where object last appeared in the ref tree | ||
var pos = tmpSc.get(object); | ||
step += 1; | ||
if (typeof pos !== 'undefined') { | ||
if (pos === step) { | ||
throw new RangeError('Cyclic object value'); | ||
} else { | ||
findFlag = true; // Break while | ||
} | ||
} | ||
if (typeof tmpSc.get(sentinel) === 'undefined') { | ||
step = 0; | ||
} | ||
} | ||
@@ -108,2 +126,10 @@ | ||
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format); | ||
if (generateArrayPrefix === 'comma' && encodeValuesOnly) { | ||
var valuesArray = split.call(String(obj), ','); | ||
var valuesJoined = ''; | ||
for (var i = 0; i < valuesArray.length; ++i) { | ||
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format)); | ||
} | ||
return [formatter(keyValue) + '=' + valuesJoined]; | ||
} | ||
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))]; | ||
@@ -131,4 +157,4 @@ } | ||
for (var i = 0; i < objKeys.length; ++i) { | ||
var key = objKeys[i]; | ||
for (var j = 0; j < objKeys.length; ++j) { | ||
var key = objKeys[j]; | ||
var value = typeof key === 'object' && key.value !== undefined ? key.value : obj[key]; | ||
@@ -144,4 +170,5 @@ | ||
sideChannel.set(object, true); | ||
sideChannel.set(object, step); | ||
var valueSideChannel = getSideChannel(); | ||
valueSideChannel.set(sentinel, sideChannel); | ||
pushToArray(values, stringify( | ||
@@ -148,0 +175,0 @@ value, |
@@ -180,2 +180,3 @@ 'use strict'; | ||
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); | ||
/* eslint operator-linebreak: [2, "before"] */ | ||
out += hexTable[0xF0 | (c >> 18)] | ||
@@ -182,0 +183,0 @@ + hexTable[0x80 | ((c >> 12) & 0x3F)] |
@@ -5,3 +5,3 @@ { | ||
"homepage": "https://github.com/ljharb/qs", | ||
"version": "6.10.1", | ||
"version": "6.10.2", | ||
"repository": { | ||
@@ -37,7 +37,7 @@ "type": "git", | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^17.5.1", | ||
"aud": "^1.1.4", | ||
"@ljharb/eslint-config": "^20.0.0", | ||
"aud": "^1.1.5", | ||
"browserify": "^16.5.2", | ||
"eclint": "^2.8.1", | ||
"eslint": "^7.22.0", | ||
"eslint": "^8.4.0", | ||
"evalmd": "^0.0.19", | ||
@@ -50,10 +50,11 @@ "for-each": "^0.3.3", | ||
"nyc": "^10.3.2", | ||
"object-inspect": "^1.9.0", | ||
"object-inspect": "^1.11.0", | ||
"qs-iconv": "^1.0.4", | ||
"safe-publish-latest": "^1.1.4", | ||
"safe-publish-latest": "^2.0.0", | ||
"safer-buffer": "^2.1.2", | ||
"tape": "^5.2.2" | ||
"tape": "^5.3.2" | ||
}, | ||
"scripts": { | ||
"prepublish": "safe-publish-latest && (not-in-publish || npm run dist)", | ||
"prepublishOnly": "safe-publish-latest && npm run dist", | ||
"prepublish": "not-in-publish || npm run prepublishOnly", | ||
"pretest": "npm run --silent readme && npm run --silent lint", | ||
@@ -65,3 +66,3 @@ "test": "npm run tests-only", | ||
"postlint": "eclint check * lib/* test/* !dist/*", | ||
"lint": "eslint lib/*.js test/*.js", | ||
"lint": "eslint .", | ||
"dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js" | ||
@@ -68,0 +69,0 @@ }, |
# qs <sup>[![Version Badge][2]][1]</sup> | ||
[![Build Status][3]][4] | ||
[![dependency status][5]][6] | ||
[![dev dependency status][7]][8] | ||
[![github actions][actions-image]][actions-url] | ||
[![coverage][codecov-image]][codecov-url] | ||
[![dependency status][deps-svg]][deps-url] | ||
[![dev dependency status][dev-deps-svg]][dev-deps-url] | ||
[![License][license-image]][license-url] | ||
[![Downloads][downloads-image]][downloads-url] | ||
[![npm badge][11]][1] | ||
[![npm badge][npm-badge-png]][package-url] | ||
@@ -290,2 +291,13 @@ A querystring parsing and stringifying library with some added security. | ||
### Parsing primitive/scalar values (numbers, booleans, null, etc) | ||
By default, all values are parsed as strings. This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91). | ||
```javascript | ||
var primitiveValues = qs.parse('a=15&b=true&c=null'); | ||
assert.deepEqual(primitiveValues, { a: '15', b: 'true', c: 'null' }); | ||
``` | ||
If you wish to auto-convert values which look like numbers, booleans, and other values into their primitive counterparts, you can use the [query-types Express JS middleware](https://github.com/xpepermint/query-types) which will auto-convert all request query parameters. | ||
### Stringifying | ||
@@ -598,16 +610,16 @@ | ||
[1]: https://npmjs.org/package/qs | ||
[2]: http://versionbadg.es/ljharb/qs.svg | ||
[3]: https://api.travis-ci.org/ljharb/qs.svg | ||
[4]: https://travis-ci.org/ljharb/qs | ||
[5]: https://david-dm.org/ljharb/qs.svg | ||
[6]: https://david-dm.org/ljharb/qs | ||
[7]: https://david-dm.org/ljharb/qs/dev-status.svg | ||
[8]: https://david-dm.org/ljharb/qs?type=dev | ||
[9]: https://ci.testling.com/ljharb/qs.png | ||
[10]: https://ci.testling.com/ljharb/qs | ||
[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true | ||
[license-image]: http://img.shields.io/npm/l/qs.svg | ||
[package-url]: https://npmjs.org/package/qs | ||
[npm-version-svg]: https://versionbadg.es/ljharb/qs.svg | ||
[deps-svg]: https://david-dm.org/ljharb/qs.svg | ||
[deps-url]: https://david-dm.org/ljharb/qs | ||
[dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg | ||
[dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies | ||
[npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true | ||
[license-image]: https://img.shields.io/npm/l/qs.svg | ||
[license-url]: LICENSE | ||
[downloads-image]: http://img.shields.io/npm/dm/qs.svg | ||
[downloads-url]: http://npm-stat.com/charts.html?package=qs | ||
[downloads-image]: https://img.shields.io/npm/dm/qs.svg | ||
[downloads-url]: https://npm-stat.com/charts.html?package=qs | ||
[codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg | ||
[codecov-url]: https://app.codecov.io/gh/ljharb/qs/ | ||
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs | ||
[actions-url]: https://github.com/ljharb/qs/actions |
@@ -135,6 +135,6 @@ 'use strict'; | ||
t.test('stringifies a nested array value', function (st) { | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D=c%2Cd'); // a[b]=c,d | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[b][0]=c&a[b][1]=d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[b][]=c&a[b][]=d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a[b]=c,d'); | ||
st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true }), 'a[b][0]=c&a[b][1]=d'); | ||
st.end(); | ||
@@ -147,3 +147,3 @@ }); | ||
{ a: { b: ['c', 'd'] } }, | ||
{ allowDots: true, encode: false, arrayFormat: 'indices' } | ||
{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' } | ||
), | ||
@@ -156,3 +156,3 @@ 'a.b[0]=c&a.b[1]=d', | ||
{ a: { b: ['c', 'd'] } }, | ||
{ allowDots: true, encode: false, arrayFormat: 'brackets' } | ||
{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' } | ||
), | ||
@@ -165,3 +165,3 @@ 'a.b[]=c&a.b[]=d', | ||
{ a: { b: ['c', 'd'] } }, | ||
{ allowDots: true, encode: false, arrayFormat: 'comma' } | ||
{ allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' } | ||
), | ||
@@ -174,3 +174,3 @@ 'a.b=c,d', | ||
{ a: { b: ['c', 'd'] } }, | ||
{ allowDots: true, encode: false } | ||
{ allowDots: true, encodeValuesOnly: true } | ||
), | ||
@@ -223,3 +223,3 @@ 'a.b[0]=c&a.b[1]=d', | ||
st.equal( | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }), | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), | ||
'a[0][b]=1&a[1]=2&a[2]=3', | ||
@@ -229,3 +229,3 @@ 'indices => indices' | ||
st.equal( | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }), | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), | ||
'a[][b]=1&a[]=2&a[]=3', | ||
@@ -235,3 +235,9 @@ 'brackets => brackets' | ||
st.equal( | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }), | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), | ||
'???', | ||
'brackets => brackets', | ||
{ skip: 'TODO: figure out what this should do' } | ||
); | ||
st.equal( | ||
qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }), | ||
'a[0][b]=1&a[1]=2&a[2]=3', | ||
@@ -459,3 +465,3 @@ 'default => indices' | ||
function () { qs.stringify({ 'foo[bar]': 'baz', 'foo[baz]': a }); }, | ||
RangeError, | ||
/RangeError: Cyclic object value/, | ||
'cyclic values throw' | ||
@@ -470,6 +476,12 @@ ); | ||
function () { qs.stringify(circular); }, | ||
RangeError, | ||
/RangeError: Cyclic object value/, | ||
'cyclic values throw' | ||
); | ||
var arr = ['a']; | ||
st.doesNotThrow( | ||
function () { qs.stringify({ x: arr, y: arr }); }, | ||
'non-cyclic values do not throw' | ||
); | ||
st.end(); | ||
@@ -842,3 +854,8 @@ }); | ||
st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices'); | ||
st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), '???', 'array, comma (pending issue #378)', { skip: true }); | ||
st.equal( | ||
qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }), | ||
'???', | ||
'array, comma', | ||
{ skip: 'TODO: figure out what this should do' } | ||
); | ||
@@ -845,0 +862,0 @@ st.end(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
212118
3992
624