Skip to content

Commit 68eaa87

Browse files
BridgeARtargos
authored andcommittedSep 24, 2018
util: add order option to .inspect()
The order option can be used to sort the inspected values in case they do not rely on their order as arrays. That way the output is stable no matter of the object property inspection order. Backport-PR-URL: #23039 PR-URL: #22788 Refs: #22763 Reviewed-By: John-David Dalton <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Trivikram Kamat <[email protected]>
1 parent a2a1ebf commit 68eaa87

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed
 

‎doc/api/util.md

+37-1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ stream.write('With ES6');
360360
<!-- YAML
361361
added: v0.3.0
362362
changes:
363+
- version: REPLACEME
364+
pr-url: https://github.com/nodejs/node/pull/22788
365+
description: The `sorted` option is supported now.
363366
- version: v10.6.0
364367
pr-url: https://github.com/nodejs/node/pull/20725
365368
description: Inspecting linked lists and similar objects is now possible
@@ -420,7 +423,10 @@ changes:
420423
objects the same as arrays. Note that no text will be reduced below 16
421424
characters, no matter the `breakLength` size. For more information, see the
422425
example below. **Default:** `true`.
423-
426+
* `sorted` {boolean|Function} If set to `true` or a function, all properties
427+
of an object and Set and Map entries will be sorted in the returned string.
428+
If set to `true` the [default sort][] is going to be used. If set to a
429+
function, it is used as a [compare function][].
424430
* Returns: {string} The representation of passed object
425431

426432
The `util.inspect()` method returns a string representation of `object` that is
@@ -534,6 +540,34 @@ console.log(inspect(weakSet, { showHidden: true }));
534540
// WeakSet { { a: 1 }, { b: 2 } }
535541
```
536542

543+
The `sorted` option makes sure the output is identical, no matter of the
544+
properties insertion order:
545+
546+
```js
547+
const { inspect } = require('util');
548+
const assert = require('assert');
549+
550+
const o1 = {
551+
b: [2, 3, 1],
552+
a: '`a` comes before `b`',
553+
c: new Set([2, 3, 1])
554+
};
555+
console.log(inspect(o1, { sorted: true }));
556+
// { a: '`a` comes before `b`', b: [ 2, 3, 1 ], c: Set { 1, 2, 3 } }
557+
console.log(inspect(o1, { sorted: (a, b) => a < b }));
558+
// { c: Set { 3, 2, 1 }, b: [ 2, 3, 1 ], a: '`a` comes before `b`' }
559+
560+
const o2 = {
561+
c: new Set([2, 1, 3]),
562+
a: '`a` comes before `b`',
563+
b: [2, 3, 1]
564+
};
565+
assert.strict.equal(
566+
inspect(o1, { sorted: true }),
567+
inspect(o2, { sorted: true })
568+
);
569+
```
570+
537571
Please note that `util.inspect()` is a synchronous method that is mainly
538572
intended as a debugging tool. Some input values can have a significant
539573
performance overhead that can block the event loop. Use this function
@@ -2150,7 +2184,9 @@ Deprecated predecessor of `console.log`.
21502184
[WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/
21512185
[Common System Errors]: errors.html#errors_common_system_errors
21522186
[async function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
2187+
[compare function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters
21532188
[constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
2189+
[default sort]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
21542190
[global symbol registry]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
21552191
[list of deprecated APIS]: deprecations.html#deprecations_list_of_deprecated_apis
21562192
[semantically incompatible]: https://github.com/nodejs/node/issues/4179

‎lib/util.js

+16-3
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ const inspectDefaultOptions = Object.seal({
9999
showProxy: false,
100100
maxArrayLength: 100,
101101
breakLength: 60,
102-
compact: true
102+
compact: true,
103+
sorted: false
103104
});
104105

105106
const kObjectType = 0;
@@ -344,6 +345,8 @@ function debuglog(set) {
344345
function inspect(value, opts) {
345346
// Default options
346347
const ctx = {
348+
budget: {},
349+
indentationLvl: 0,
347350
seen: [],
348351
stylize: stylizeNoColor,
349352
showHidden: inspectDefaultOptions.showHidden,
@@ -355,8 +358,8 @@ function inspect(value, opts) {
355358
// `maxEntries`.
356359
maxArrayLength: inspectDefaultOptions.maxArrayLength,
357360
breakLength: inspectDefaultOptions.breakLength,
358-
indentationLvl: 0,
359-
compact: inspectDefaultOptions.compact
361+
compact: inspectDefaultOptions.compact,
362+
sorted: inspectDefaultOptions.sorted
360363
};
361364
// Legacy...
362365
if (arguments.length > 2) {
@@ -846,6 +849,16 @@ function formatRaw(ctx, value, recurseTimes) {
846849
}
847850
ctx.seen.pop();
848851

852+
if (ctx.sorted) {
853+
const comparator = ctx.sorted === true ? undefined : ctx.sorted;
854+
if (extrasType === kObjectType) {
855+
output = output.sort(comparator);
856+
} else if (keys.length > 1) {
857+
const sorted = output.slice(output.length - keys.length).sort(comparator);
858+
output.splice(output.length - keys.length, keys.length, ...sorted);
859+
}
860+
}
861+
849862
return reduceToSingleString(ctx, output, base, braces);
850863
}
851864

‎test/parallel/test-util-inspect.js

+30
Original file line numberDiff line numberDiff line change
@@ -1718,3 +1718,33 @@ assert.strictEqual(inspect(Object(13n)), '[BigInt: 13n]');
17181718
);
17191719
rejection.catch(() => {});
17201720
}
1721+
1722+
assert.strictEqual(
1723+
inspect([1, 3, 2], { sorted: true }),
1724+
inspect([1, 3, 2])
1725+
);
1726+
assert.strictEqual(
1727+
inspect({ c: 3, a: 1, b: 2 }, { sorted: true }),
1728+
'{ a: 1, b: 2, c: 3 }'
1729+
);
1730+
assert.strictEqual(
1731+
inspect(
1732+
{ a200: 4, a100: 1, a102: 3, a101: 2 },
1733+
{ sorted(a, b) { return a < b; } }
1734+
),
1735+
'{ a200: 4, a102: 3, a101: 2, a100: 1 }'
1736+
);
1737+
1738+
// Non-indices array properties are sorted as well.
1739+
{
1740+
const arr = [3, 2, 1];
1741+
arr.b = 2;
1742+
arr.c = 3;
1743+
arr.a = 1;
1744+
arr[Symbol('b')] = true;
1745+
arr[Symbol('a')] = false;
1746+
assert.strictEqual(
1747+
inspect(arr, { sorted: true }),
1748+
'[ 3, 2, 1, [Symbol(a)]: false, [Symbol(b)]: true, a: 1, b: 2, c: 3 ]'
1749+
);
1750+
}

0 commit comments

Comments
 (0)
Please sign in to comment.