diff --git a/doc/api/util.md b/doc/api/util.md index 02453e75c34075..e7340cdec01f58 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -236,6 +236,7 @@ corresponding argument. Supported specifiers are: * `%f`: `parseFloat(value)` is used for all values expect `Symbol`. * `%j`: JSON. Replaced with the string `'[Circular]'` if the argument contains circular references. +* `%J`: Indented version of %j. * `%o`: `Object`. A string representation of an object with generic JavaScript object formatting. Similar to `util.inspect()` with options `{ showHidden: true, showProxy: true }`. This will show the full object diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index fe21854e16aa7f..4c7b4c254ae02a 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -1770,14 +1770,14 @@ function hasBuiltInToString(value) { const firstErrorLine = (error) => error.message.split('\n')[0]; let CIRCULAR_ERROR_MESSAGE; -function tryStringify(arg) { +function tryStringify(arg, indentation = 0) { try { - return JSONStringify(arg); + return JSONStringify(arg, null, indentation); } catch (err) { // Populate the circular error message lazily if (!CIRCULAR_ERROR_MESSAGE) { try { - const a = {}; a.a = a; JSONStringify(a); + const a = {}; a.a = a; JSONStringify(a, null, indentation); } catch (err) { CIRCULAR_ERROR_MESSAGE = firstErrorLine(err); } @@ -1842,6 +1842,9 @@ function formatWithOptionsInternal(inspectOptions, ...args) { case 106: // 'j' tempStr = tryStringify(args[++a]); break; + case 74: // 'J' + tempStr = tryStringify(args[++a], 2); + break; case 100: // 'd' const tempNum = args[++a]; if (typeof tempNum === 'bigint') { diff --git a/test/parallel/test-util-format.js b/test/parallel/test-util-format.js index 6de9d8d7c74c80..b37084970d403c 100644 --- a/test/parallel/test-util-format.js +++ b/test/parallel/test-util-format.js @@ -44,6 +44,7 @@ assert.strictEqual(util.format(symbol), 'Symbol(foo)'); assert.strictEqual(util.format('foo', symbol), 'foo Symbol(foo)'); assert.strictEqual(util.format('%s', symbol), 'Symbol(foo)'); assert.strictEqual(util.format('%j', symbol), 'undefined'); +assert.strictEqual(util.format('%J', symbol), 'undefined'); // Number format specifier assert.strictEqual(util.format('%d'), '%d'); @@ -237,6 +238,16 @@ assert.strictEqual(util.format('%j', '42'), '"42"'); assert.strictEqual(util.format('%j %j', 42, 43), '42 43'); assert.strictEqual(util.format('%j %j', 42), '42 %j'); +// Indented JSON format specifier +assert.strictEqual(util.format('%J'), '%J'); +assert.strictEqual(util.format('%J', 42), '42'); +assert.strictEqual(util.format('%J', '42'), '"42"'); +assert.strictEqual(util.format('%J %J', 42, 43), '42 43'); +assert.strictEqual(util.format('%J %J', 42), '42 %J'); +assert.strictEqual( + util.format('%J', { foo: { bar: 42 } }) + , '{\n "foo": {\n "bar": 42\n }\n}'); + // Object format specifier const obj = { foo: 'bar', diff --git a/test/pummel/test-child-process-spawn-loop.js b/test/pummel/test-child-process-spawn-loop.js index f6d8207df85b9b..4dc218161125bf 100644 --- a/test/pummel/test-child-process-spawn-loop.js +++ b/test/pummel/test-child-process-spawn-loop.js @@ -30,7 +30,7 @@ const N = 40; let finished = false; function doSpawn(i) { - const child = spawn('python', ['-c', `print ${SIZE} * "C"`]); + const child = spawn('python', ['-c', `print(${SIZE} * "C")`]); let count = 0; child.stdout.setEncoding('ascii');