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. PR-URL: https://github.com/nodejs/node/pull/22788 Refs: https://github.com/nodejs/node/issues/22763 Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
parent
9d71e6a607
commit
b95b0d87c3
@ -360,6 +360,9 @@ stream.write('With ES6');
|
||||
<!-- YAML
|
||||
added: v0.3.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/22788
|
||||
description: The `sorted` option is supported now.
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/22756
|
||||
description: The inspection output is now limited to about 128 MB. Data
|
||||
@ -426,6 +429,10 @@ changes:
|
||||
objects the same as arrays. Note that no text will be reduced below 16
|
||||
characters, no matter the `breakLength` size. For more information, see the
|
||||
example below. **Default:** `true`.
|
||||
* `sorted` {boolean|Function} If set to `true` or a function, all properties
|
||||
of an object and Set and Map entries will be sorted in the returned string.
|
||||
If set to `true` the [default sort][] is going to be used. If set to a
|
||||
function, it is used as a [compare function][].
|
||||
* Returns: {string} The representation of passed object
|
||||
|
||||
The `util.inspect()` method returns a string representation of `object` that is
|
||||
@ -535,6 +542,34 @@ console.log(inspect(weakSet, { showHidden: true }));
|
||||
// WeakSet { { a: 1 }, { b: 2 } }
|
||||
```
|
||||
|
||||
The `sorted` option makes sure the output is identical, no matter of the
|
||||
properties insertion order:
|
||||
|
||||
```js
|
||||
const { inspect } = require('util');
|
||||
const assert = require('assert');
|
||||
|
||||
const o1 = {
|
||||
b: [2, 3, 1],
|
||||
a: '`a` comes before `b`',
|
||||
c: new Set([2, 3, 1])
|
||||
};
|
||||
console.log(inspect(o1, { sorted: true }));
|
||||
// { a: '`a` comes before `b`', b: [ 2, 3, 1 ], c: Set { 1, 2, 3 } }
|
||||
console.log(inspect(o1, { sorted: (a, b) => a < b }));
|
||||
// { c: Set { 3, 2, 1 }, b: [ 2, 3, 1 ], a: '`a` comes before `b`' }
|
||||
|
||||
const o2 = {
|
||||
c: new Set([2, 1, 3]),
|
||||
a: '`a` comes before `b`',
|
||||
b: [2, 3, 1]
|
||||
};
|
||||
assert.strict.equal(
|
||||
inspect(o1, { sorted: true }),
|
||||
inspect(o2, { sorted: true })
|
||||
);
|
||||
```
|
||||
|
||||
Please note that `util.inspect()` is a synchronous method that is mainly
|
||||
intended as a debugging tool. Its maximum output length is limited to
|
||||
approximately 128 MB and input values that result in output bigger than that
|
||||
@ -2165,7 +2200,9 @@ Deprecated predecessor of `console.log`.
|
||||
[WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/
|
||||
[Common System Errors]: errors.html#errors_common_system_errors
|
||||
[async function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
||||
[compare function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters
|
||||
[constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
|
||||
[default sort]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
|
||||
[global symbol registry]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
|
||||
[list of deprecated APIS]: deprecations.html#deprecations_list_of_deprecated_apis
|
||||
[semantically incompatible]: https://github.com/nodejs/node/issues/4179
|
||||
|
18
lib/util.js
18
lib/util.js
@ -99,7 +99,8 @@ const inspectDefaultOptions = Object.seal({
|
||||
showProxy: false,
|
||||
maxArrayLength: 100,
|
||||
breakLength: 60,
|
||||
compact: true
|
||||
compact: true,
|
||||
sorted: false
|
||||
});
|
||||
|
||||
const kObjectType = 0;
|
||||
@ -394,6 +395,8 @@ function debuglog(set) {
|
||||
function inspect(value, opts) {
|
||||
// Default options
|
||||
const ctx = {
|
||||
budget: {},
|
||||
indentationLvl: 0,
|
||||
seen: [],
|
||||
stylize: stylizeNoColor,
|
||||
showHidden: inspectDefaultOptions.showHidden,
|
||||
@ -405,9 +408,8 @@ function inspect(value, opts) {
|
||||
// `maxEntries`.
|
||||
maxArrayLength: inspectDefaultOptions.maxArrayLength,
|
||||
breakLength: inspectDefaultOptions.breakLength,
|
||||
indentationLvl: 0,
|
||||
compact: inspectDefaultOptions.compact,
|
||||
budget: {}
|
||||
sorted: inspectDefaultOptions.sorted
|
||||
};
|
||||
if (arguments.length > 1) {
|
||||
// Legacy...
|
||||
@ -894,6 +896,16 @@ function formatRaw(ctx, value, recurseTimes) {
|
||||
}
|
||||
ctx.seen.pop();
|
||||
|
||||
if (ctx.sorted) {
|
||||
const comparator = ctx.sorted === true ? undefined : ctx.sorted;
|
||||
if (extrasType === kObjectType) {
|
||||
output = output.sort(comparator);
|
||||
} else if (keys.length > 1) {
|
||||
const sorted = output.slice(output.length - keys.length).sort(comparator);
|
||||
output.splice(output.length - keys.length, keys.length, ...sorted);
|
||||
}
|
||||
}
|
||||
|
||||
const res = reduceToSingleString(ctx, output, base, braces);
|
||||
const budget = ctx.budget[ctx.indentationLvl] || 0;
|
||||
const newLength = budget + res.length;
|
||||
|
@ -1676,3 +1676,33 @@ assert.strictEqual(inspect(new BigUint64Array([0n])), 'BigUint64Array [ 0n ]');
|
||||
);
|
||||
rejection.catch(() => {});
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
inspect([1, 3, 2], { sorted: true }),
|
||||
inspect([1, 3, 2])
|
||||
);
|
||||
assert.strictEqual(
|
||||
inspect({ c: 3, a: 1, b: 2 }, { sorted: true }),
|
||||
'{ a: 1, b: 2, c: 3 }'
|
||||
);
|
||||
assert.strictEqual(
|
||||
inspect(
|
||||
{ a200: 4, a100: 1, a102: 3, a101: 2 },
|
||||
{ sorted(a, b) { return a < b; } }
|
||||
),
|
||||
'{ a200: 4, a102: 3, a101: 2, a100: 1 }'
|
||||
);
|
||||
|
||||
// Non-indices array properties are sorted as well.
|
||||
{
|
||||
const arr = [3, 2, 1];
|
||||
arr.b = 2;
|
||||
arr.c = 3;
|
||||
arr.a = 1;
|
||||
arr[Symbol('b')] = true;
|
||||
arr[Symbol('a')] = false;
|
||||
assert.strictEqual(
|
||||
inspect(arr, { sorted: true }),
|
||||
'[ 3, 2, 1, [Symbol(a)]: false, [Symbol(b)]: true, a: 1, b: 2, c: 3 ]'
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user