summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/util.md37
-rw-r--r--lib/util.js18
-rw-r--r--test/parallel/test-util-inspect.js30
3 files changed, 82 insertions, 3 deletions
diff --git a/doc/api/util.md b/doc/api/util.md
index 267bab85ae..b0e942274c 100644
--- a/doc/api/util.md
+++ b/doc/api/util.md
@@ -361,6 +361,9 @@ stream.write('With ES6');
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
above that size will not be fully inspected.
@@ -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
diff --git a/lib/util.js b/lib/util.js
index 89c86cb7fd..d1a483cf17 100644
--- a/lib/util.js
+++ b/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;
diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js
index 467849cf7a..cd7d08caf0 100644
--- a/test/parallel/test-util-inspect.js
+++ b/test/parallel/test-util-inspect.js
@@ -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 ]'
+ );
+}