Skip to content

Commit 408ff95

Browse files
committed
v6.10.2
1 parent 3cea04d commit 408ff95

File tree

3 files changed

+135
-27
lines changed

3 files changed

+135
-27
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## **6.10.2**
2+
- [Fix] `stringify`: actually fix cyclic references (#426)
3+
- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424)
4+
- [readme] remove travis badge; add github actions/codecov badges; update URLs
5+
- [Docs] add note and links for coercing primitive values (#408)
6+
- [actions] update codecov uploader
7+
- [actions] update workflows
8+
- [Tests] clean up stringify tests slightly
9+
- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `object-inspect`, `safe-publish-latest`, `tape`
10+
111
## **6.10.1**
212
- [Fix] `stringify`: avoid exception on repeated object values (#402)
313

dist/qs.js

+124-26
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ var arrayPrefixGenerators = {
323323
};
324324

325325
var isArray = Array.isArray;
326+
var split = String.prototype.split;
326327
var push = Array.prototype.push;
327328
var pushToArray = function (arr, valueOrArray) {
328329
push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
@@ -359,6 +360,8 @@ var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
359360
|| typeof v === 'bigint';
360361
};
361362

363+
var sentinel = {};
364+
362365
var stringify = function stringify(
363366
object,
364367
prefix,
@@ -378,8 +381,23 @@ var stringify = function stringify(
378381
) {
379382
var obj = object;
380383

381-
if (sideChannel.has(object)) {
382-
throw new RangeError('Cyclic object value');
384+
var tmpSc = sideChannel;
385+
var step = 0;
386+
var findFlag = false;
387+
while ((tmpSc = tmpSc.get(sentinel)) !== undefined && !findFlag) {
388+
// Where object last appeared in the ref tree
389+
var pos = tmpSc.get(object);
390+
step += 1;
391+
if (typeof pos !== 'undefined') {
392+
if (pos === step) {
393+
throw new RangeError('Cyclic object value');
394+
} else {
395+
findFlag = true; // Break while
396+
}
397+
}
398+
if (typeof tmpSc.get(sentinel) === 'undefined') {
399+
step = 0;
400+
}
383401
}
384402

385403
if (typeof filter === 'function') {
@@ -406,6 +424,14 @@ var stringify = function stringify(
406424
if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) {
407425
if (encoder) {
408426
var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format);
427+
if (generateArrayPrefix === 'comma' && encodeValuesOnly) {
428+
var valuesArray = split.call(String(obj), ',');
429+
var valuesJoined = '';
430+
for (var i = 0; i < valuesArray.length; ++i) {
431+
valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format));
432+
}
433+
return [formatter(keyValue) + '=' + valuesJoined];
434+
}
409435
return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))];
410436
}
411437
return [formatter(prefix) + '=' + formatter(String(obj))];
@@ -428,8 +454,8 @@ var stringify = function stringify(
428454
objKeys = sort ? keys.sort(sort) : keys;
429455
}
430456

431-
for (var i = 0; i < objKeys.length; ++i) {
432-
var key = objKeys[i];
457+
for (var j = 0; j < objKeys.length; ++j) {
458+
var key = objKeys[j];
433459
var value = typeof key === 'object' && key.value !== undefined ? key.value : obj[key];
434460

435461
if (skipNulls && value === null) {
@@ -440,7 +466,9 @@ var stringify = function stringify(
440466
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
441467
: prefix + (allowDots ? '.' + key : '[' + key + ']');
442468

443-
sideChannel.set(object, true);
469+
sideChannel.set(object, step);
470+
var valueSideChannel = getSideChannel();
471+
valueSideChannel.set(sentinel, sideChannel);
444472
pushToArray(values, stringify(
445473
value,
446474
keyPrefix,
@@ -456,7 +484,7 @@ var stringify = function stringify(
456484
formatter,
457485
encodeValuesOnly,
458486
charset,
459-
sideChannel
487+
valueSideChannel
460488
));
461489
}
462490

@@ -772,6 +800,7 @@ var encode = function encode(str, defaultEncoder, charset, kind, format) {
772800

773801
i += 1;
774802
c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));
803+
/* eslint operator-linebreak: [2, "before"] */
775804
out += hexTable[0xF0 | (c >> 18)]
776805
+ hexTable[0x80 | ((c >> 12) & 0x3F)]
777806
+ hexTable[0x80 | ((c >> 6) & 0x3F)]
@@ -1385,17 +1414,29 @@ var hasWeakMap = typeof WeakMap === 'function' && WeakMap.prototype;
13851414
var weakMapHas = hasWeakMap ? WeakMap.prototype.has : null;
13861415
var hasWeakSet = typeof WeakSet === 'function' && WeakSet.prototype;
13871416
var weakSetHas = hasWeakSet ? WeakSet.prototype.has : null;
1417+
var hasWeakRef = typeof WeakRef === 'function' && WeakRef.prototype;
1418+
var weakRefDeref = hasWeakRef ? WeakRef.prototype.deref : null;
13881419
var booleanValueOf = Boolean.prototype.valueOf;
13891420
var objectToString = Object.prototype.toString;
13901421
var functionToString = Function.prototype.toString;
13911422
var match = String.prototype.match;
13921423
var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null;
13931424
var gOPS = Object.getOwnPropertySymbols;
1394-
var symToString = typeof Symbol === 'function' ? Symbol.prototype.toString : null;
1425+
var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null;
1426+
var hasShammedSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'object';
13951427
var isEnumerable = Object.prototype.propertyIsEnumerable;
13961428

1429+
var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || (
1430+
[].__proto__ === Array.prototype // eslint-disable-line no-proto
1431+
? function (O) {
1432+
return O.__proto__; // eslint-disable-line no-proto
1433+
}
1434+
: null
1435+
);
1436+
13971437
var inspectCustom = require('./util.inspect').custom;
13981438
var inspectSymbol = inspectCustom && isSymbol(inspectCustom) ? inspectCustom : null;
1439+
var toStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag !== 'undefined' ? Symbol.toStringTag : null;
13991440

14001441
module.exports = function inspect_(obj, options, depth, seen) {
14011442
var opts = options || {};
@@ -1412,8 +1453,8 @@ module.exports = function inspect_(obj, options, depth, seen) {
14121453
throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');
14131454
}
14141455
var customInspect = has(opts, 'customInspect') ? opts.customInspect : true;
1415-
if (typeof customInspect !== 'boolean') {
1416-
throw new TypeError('option "customInspect", if provided, must be `true` or `false`');
1456+
if (typeof customInspect !== 'boolean' && customInspect !== 'symbol') {
1457+
throw new TypeError('option "customInspect", if provided, must be `true`, `false`, or `\'symbol\'`');
14171458
}
14181459

14191460
if (
@@ -1485,8 +1526,8 @@ module.exports = function inspect_(obj, options, depth, seen) {
14851526
return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']' + (keys.length > 0 ? ' { ' + keys.join(', ') + ' }' : '');
14861527
}
14871528
if (isSymbol(obj)) {
1488-
var symString = symToString.call(obj);
1489-
return typeof obj === 'object' ? markBoxed(symString) : symString;
1529+
var symString = hasShammedSymbols ? String(obj).replace(/^(Symbol\(.*\))_[^)]*$/, '$1') : symToString.call(obj);
1530+
return typeof obj === 'object' && !hasShammedSymbols ? markBoxed(symString) : symString;
14901531
}
14911532
if (isElement(obj)) {
14921533
var s = '<' + String(obj.nodeName).toLowerCase();
@@ -1515,7 +1556,7 @@ module.exports = function inspect_(obj, options, depth, seen) {
15151556
if (typeof obj === 'object' && customInspect) {
15161557
if (inspectSymbol && typeof obj[inspectSymbol] === 'function') {
15171558
return obj[inspectSymbol]();
1518-
} else if (typeof obj.inspect === 'function') {
1559+
} else if (customInspect !== 'symbol' && typeof obj.inspect === 'function') {
15191560
return obj.inspect();
15201561
}
15211562
}
@@ -1539,6 +1580,9 @@ module.exports = function inspect_(obj, options, depth, seen) {
15391580
if (isWeakSet(obj)) {
15401581
return weakCollectionOf('WeakSet');
15411582
}
1583+
if (isWeakRef(obj)) {
1584+
return weakCollectionOf('WeakRef');
1585+
}
15421586
if (isNumber(obj)) {
15431587
return markBoxed(inspect(Number(obj)));
15441588
}
@@ -1553,11 +1597,16 @@ module.exports = function inspect_(obj, options, depth, seen) {
15531597
}
15541598
if (!isDate(obj) && !isRegExp(obj)) {
15551599
var ys = arrObjKeys(obj, inspect);
1556-
if (ys.length === 0) { return '{}'; }
1600+
var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
1601+
var protoTag = obj instanceof Object ? '' : 'null prototype';
1602+
var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? toStr(obj).slice(8, -1) : protoTag ? 'Object' : '';
1603+
var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : '';
1604+
var tag = constructorTag + (stringTag || protoTag ? '[' + [].concat(stringTag || [], protoTag || []).join(': ') + '] ' : '');
1605+
if (ys.length === 0) { return tag + '{}'; }
15571606
if (indent) {
1558-
return '{' + indentedJoin(ys, indent) + '}';
1607+
return tag + '{' + indentedJoin(ys, indent) + '}';
15591608
}
1560-
return '{ ' + ys.join(', ') + ' }';
1609+
return tag + '{ ' + ys.join(', ') + ' }';
15611610
}
15621611
return String(obj);
15631612
};
@@ -1571,15 +1620,42 @@ function quote(s) {
15711620
return String(s).replace(/"/g, '&quot;');
15721621
}
15731622

1574-
function isArray(obj) { return toStr(obj) === '[object Array]'; }
1575-
function isDate(obj) { return toStr(obj) === '[object Date]'; }
1576-
function isRegExp(obj) { return toStr(obj) === '[object RegExp]'; }
1577-
function isError(obj) { return toStr(obj) === '[object Error]'; }
1578-
function isSymbol(obj) { return toStr(obj) === '[object Symbol]'; }
1579-
function isString(obj) { return toStr(obj) === '[object String]'; }
1580-
function isNumber(obj) { return toStr(obj) === '[object Number]'; }
1581-
function isBigInt(obj) { return toStr(obj) === '[object BigInt]'; }
1582-
function isBoolean(obj) { return toStr(obj) === '[object Boolean]'; }
1623+
function isArray(obj) { return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1624+
function isDate(obj) { return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1625+
function isRegExp(obj) { return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1626+
function isError(obj) { return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1627+
function isString(obj) { return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1628+
function isNumber(obj) { return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1629+
function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); }
1630+
1631+
// Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives
1632+
function isSymbol(obj) {
1633+
if (hasShammedSymbols) {
1634+
return obj && typeof obj === 'object' && obj instanceof Symbol;
1635+
}
1636+
if (typeof obj === 'symbol') {
1637+
return true;
1638+
}
1639+
if (!obj || typeof obj !== 'object' || !symToString) {
1640+
return false;
1641+
}
1642+
try {
1643+
symToString.call(obj);
1644+
return true;
1645+
} catch (e) {}
1646+
return false;
1647+
}
1648+
1649+
function isBigInt(obj) {
1650+
if (!obj || typeof obj !== 'object' || !bigIntValueOf) {
1651+
return false;
1652+
}
1653+
try {
1654+
bigIntValueOf.call(obj);
1655+
return true;
1656+
} catch (e) {}
1657+
return false;
1658+
}
15831659

15841660
var hasOwn = Object.prototype.hasOwnProperty || function (key) { return key in this; };
15851661
function has(obj, key) {
@@ -1637,6 +1713,17 @@ function isWeakMap(x) {
16371713
return false;
16381714
}
16391715

1716+
function isWeakRef(x) {
1717+
if (!weakRefDeref || !x || typeof x !== 'object') {
1718+
return false;
1719+
}
1720+
try {
1721+
weakRefDeref.call(x);
1722+
return true;
1723+
} catch (e) {}
1724+
return false;
1725+
}
1726+
16401727
function isSet(x) {
16411728
if (!setSize || !x || typeof x !== 'object') {
16421729
return false;
@@ -1753,17 +1840,28 @@ function arrObjKeys(obj, inspect) {
17531840
xs[i] = has(obj, i) ? inspect(obj[i], obj) : '';
17541841
}
17551842
}
1843+
var syms = typeof gOPS === 'function' ? gOPS(obj) : [];
1844+
var symMap;
1845+
if (hasShammedSymbols) {
1846+
symMap = {};
1847+
for (var k = 0; k < syms.length; k++) {
1848+
symMap['$' + syms[k]] = syms[k];
1849+
}
1850+
}
1851+
17561852
for (var key in obj) { // eslint-disable-line no-restricted-syntax
17571853
if (!has(obj, key)) { continue; } // eslint-disable-line no-restricted-syntax, no-continue
17581854
if (isArr && String(Number(key)) === key && key < obj.length) { continue; } // eslint-disable-line no-restricted-syntax, no-continue
1759-
if ((/[^\w$]/).test(key)) {
1855+
if (hasShammedSymbols && symMap['$' + key] instanceof Symbol) {
1856+
// this is to prevent shammed Symbols, which are stored as strings, from being included in the string key section
1857+
continue; // eslint-disable-line no-restricted-syntax, no-continue
1858+
} else if ((/[^\w$]/).test(key)) {
17601859
xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj));
17611860
} else {
17621861
xs.push(key + ': ' + inspect(obj[key], obj));
17631862
}
17641863
}
17651864
if (typeof gOPS === 'function') {
1766-
var syms = gOPS(obj);
17671865
for (var j = 0; j < syms.length; j++) {
17681866
if (isEnumerable.call(obj, syms[j])) {
17691867
xs.push('[' + inspect(syms[j]) + ']: ' + inspect(obj[syms[j]], obj));

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "qs",
33
"description": "A querystring parser that supports nesting and arrays, with a depth limit",
44
"homepage": "https://github.com/ljharb/qs",
5-
"version": "6.10.1",
5+
"version": "6.10.2",
66
"repository": {
77
"type": "git",
88
"url": "https://github.com/ljharb/qs.git"

0 commit comments

Comments
 (0)