Skip to content

Commit 25c33af

Browse files
BridgeARaduh95
authored andcommitted
util: mark special properties when inspecting them
This makes sure special properties (such as a byteLength, buffer, and more) are marked that they are not regular properties. They are mostly getters, that just seemed even more of a breaking change. Thus, they just use square brackets for now. On top of that, it makes inspecting detached DataViews robust. Inspecting those failed so far. PR-URL: #60131 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent b53d35a commit 25c33af

File tree

3 files changed

+103
-79
lines changed

3 files changed

+103
-79
lines changed

lib/internal/util/inspect.js

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ const {
111111
StringPrototypeSplit,
112112
StringPrototypeStartsWith,
113113
StringPrototypeToLowerCase,
114-
StringPrototypeTrim,
115114
StringPrototypeValueOf,
116115
SymbolIterator,
117116
SymbolPrototypeToString,
@@ -965,6 +964,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
965964
const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
966965

967966
let extrasType = kObjectType;
967+
let extraKeys;
968968

969969
// Iterators and the rest are split to reduce checks.
970970
// We have to check all values in case the constructor is set to null.
@@ -1020,6 +1020,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
10201020
// bound function is required to reconstruct missing information.
10211021
formatter = FunctionPrototypeBind(formatTypedArray, null, bound, size);
10221022
extrasType = kArrayExtrasType;
1023+
1024+
if (ctx.showHidden) {
1025+
extraKeys = ['BYTES_PER_ELEMENT', 'length', 'byteLength', 'byteOffset', 'buffer'];
1026+
typedArray = true;
1027+
}
10231028
} else if (isMapIterator(value)) {
10241029
keys = getKeys(value, ctx.showHidden);
10251030
braces = getIteratorBraces('Map', tag);
@@ -1088,14 +1093,14 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
10881093
formatter = formatArrayBuffer;
10891094
} else if (keys.length === 0 && protoProps === undefined) {
10901095
return prefix +
1091-
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength, false)} }`;
1096+
`{ [byteLength]: ${formatNumber(ctx.stylize, value.byteLength, false)} }`;
10921097
}
10931098
braces[0] = `${prefix}{`;
1094-
ArrayPrototypeUnshift(keys, 'byteLength');
1099+
extraKeys = ['byteLength'];
10951100
} else if (isDataView(value)) {
10961101
braces[0] = `${getPrefix(constructor, tag, 'DataView')}{`;
10971102
// .buffer goes last, it's not a primitive like the others.
1098-
ArrayPrototypeUnshift(keys, 'byteLength', 'byteOffset', 'buffer');
1103+
extraKeys = ['byteLength', 'byteOffset', 'buffer'];
10991104
} else if (isPromise(value)) {
11001105
braces[0] = `${getPrefix(constructor, tag, 'Promise')}{`;
11011106
formatter = formatPromise;
@@ -1145,6 +1150,18 @@ function formatRaw(ctx, value, recurseTimes, typedArray) {
11451150
const indentationLvl = ctx.indentationLvl;
11461151
try {
11471152
output = formatter(ctx, value, recurseTimes);
1153+
if (extraKeys !== undefined) {
1154+
for (i = 0; i < extraKeys.length; i++) {
1155+
let formatted;
1156+
try {
1157+
formatted = formatExtraProperties(ctx, value, recurseTimes, extraKeys[i], typedArray);
1158+
} catch {
1159+
const tempValue = { [extraKeys[i]]: value.buffer[extraKeys[i]] };
1160+
formatted = formatExtraProperties(ctx, tempValue, recurseTimes, extraKeys[i], typedArray);
1161+
}
1162+
ArrayPrototypePush(output, formatted);
1163+
}
1164+
}
11481165
for (i = 0; i < keys.length; i++) {
11491166
ArrayPrototypePush(
11501167
output,
@@ -2004,11 +2021,15 @@ function formatArrayBuffer(ctx, value) {
20042021
}
20052022
if (hexSlice === undefined)
20062023
hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice);
2007-
let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace(
2008-
/(.{2})/g,
2009-
hexSlice(buffer, 0, MathMin(ctx.maxArrayLength, buffer.length)),
2010-
'$1 ',
2011-
));
2024+
const rawString = hexSlice(buffer, 0, MathMin(ctx.maxArrayLength, buffer.length));
2025+
let str = '';
2026+
let i = 0;
2027+
for (; i < rawString.length - 2; i += 2) {
2028+
str += `${rawString[i]}${rawString[i + 1]} `;
2029+
}
2030+
if (rawString.length > 0) {
2031+
str += `${rawString[i]}${rawString[i + 1]}`;
2032+
}
20122033
const remaining = buffer.length - ctx.maxArrayLength;
20132034
if (remaining > 0)
20142035
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
@@ -2035,7 +2056,7 @@ function formatArray(ctx, value, recurseTimes) {
20352056
return output;
20362057
}
20372058

2038-
function formatTypedArray(value, length, ctx, ignored, recurseTimes) {
2059+
function formatTypedArray(value, length, ctx) {
20392060
const maxLength = MathMin(MathMax(0, ctx.maxArrayLength), length);
20402061
const remaining = value.length - maxLength;
20412062
const output = new Array(maxLength);
@@ -2048,22 +2069,6 @@ function formatTypedArray(value, length, ctx, ignored, recurseTimes) {
20482069
if (remaining > 0) {
20492070
output[maxLength] = remainingText(remaining);
20502071
}
2051-
if (ctx.showHidden) {
2052-
// .buffer goes last, it's not a primitive like the others.
2053-
// All besides `BYTES_PER_ELEMENT` are actually getters.
2054-
ctx.indentationLvl += 2;
2055-
for (const key of [
2056-
'BYTES_PER_ELEMENT',
2057-
'length',
2058-
'byteLength',
2059-
'byteOffset',
2060-
'buffer',
2061-
]) {
2062-
const str = formatValue(ctx, value[key], recurseTimes, true);
2063-
ArrayPrototypePush(output, `[${key}]: ${str}`);
2064-
}
2065-
ctx.indentationLvl -= 2;
2066-
}
20672072
return output;
20682073
}
20692074

@@ -2211,12 +2216,20 @@ function formatPromise(ctx, value, recurseTimes) {
22112216
return output;
22122217
}
22132218

2219+
function formatExtraProperties(ctx, value, recurseTimes, key, typedArray) {
2220+
ctx.indentationLvl += 2;
2221+
const str = formatValue(ctx, value[key], recurseTimes, typedArray);
2222+
ctx.indentationLvl -= 2;
2223+
2224+
// These entries are mainly getters. Should they be formatted like getters?
2225+
return ctx.stylize(`[${key}]: ${str}`, 'string');
2226+
}
2227+
22142228
function formatProperty(ctx, value, recurseTimes, key, type, desc,
22152229
original = value) {
22162230
let name, str;
22172231
let extra = ' ';
2218-
desc ||= ObjectGetOwnPropertyDescriptor(value, key) ||
2219-
{ value: value[key], enumerable: true };
2232+
desc ??= ObjectGetOwnPropertyDescriptor(value, key);
22202233
if (desc.value !== undefined) {
22212234
const diff = (ctx.compact !== true || type !== kObjectType) ? 2 : 3;
22222235
ctx.indentationLvl += diff;

test/parallel/test-util-format.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ assert.strictEqual(
588588

589589
assert.strictEqual(
590590
util.format(new SharedArrayBuffer(4)),
591-
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
591+
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, [byteLength]: 4 }'
592592
);
593593

594594
assert.strictEqual(

test/parallel/test-util-inspect.js

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -172,56 +172,67 @@ assert.doesNotMatch(
172172
const dv = new DataView(ab, 1, 2);
173173
assert.strictEqual(
174174
util.inspect(ab, showHidden),
175-
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
175+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, [byteLength]: 4 }'
176176
);
177177
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
178178
'DataView {\n' +
179-
' byteLength: 2,\n' +
180-
' byteOffset: 1,\n' +
181-
' buffer: ArrayBuffer {' +
182-
' [Uint8Contents]: <01 02 03 04>, byteLength: 4 }\n}');
179+
' [byteLength]: 2,\n' +
180+
' [byteOffset]: 1,\n' +
181+
' [buffer]: ArrayBuffer {' +
182+
' [Uint8Contents]: <01 02 03 04>, [byteLength]: 4 }\n}');
183183
assert.strictEqual(
184184
util.inspect(ab, showHidden),
185-
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
185+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, [byteLength]: 4 }'
186186
);
187187
assert.strictEqual(util.inspect(dv, showHidden),
188188
'DataView {\n' +
189-
' byteLength: 2,\n' +
190-
' byteOffset: 1,\n' +
191-
' buffer: ArrayBuffer { [Uint8Contents]: ' +
192-
'<01 02 03 04>, byteLength: 4 }\n}');
189+
' [byteLength]: 2,\n' +
190+
' [byteOffset]: 1,\n' +
191+
' [buffer]: ArrayBuffer { [Uint8Contents]: ' +
192+
'<01 02 03 04>, [byteLength]: 4 }\n}');
193193
ab.x = 42;
194194
dv.y = 1337;
195195
assert.strictEqual(util.inspect(ab, showHidden),
196196
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
197-
'byteLength: 4, x: 42 }');
198-
assert.strictEqual(util.inspect(dv, showHidden),
197+
'[byteLength]: 4, x: 42 }');
198+
assert.strictEqual(util.inspect(dv, { showHidden, breakLength: 82 }),
199199
'DataView {\n' +
200-
' byteLength: 2,\n' +
201-
' byteOffset: 1,\n' +
202-
' buffer: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' +
203-
' byteLength: 4, x: 42 },\n' +
200+
' [byteLength]: 2,\n' +
201+
' [byteOffset]: 1,\n' +
202+
' [buffer]: ArrayBuffer { [Uint8Contents]: <01 02 03 04>,' +
203+
' [byteLength]: 4, x: 42 },\n' +
204204
' y: 1337\n}');
205205
}
206206

207207
{
208208
const ab = new ArrayBuffer(42);
209+
const dv = new DataView(ab);
210+
209211
assert.strictEqual(ab.byteLength, 42);
210212
new MessageChannel().port1.postMessage(ab, [ ab ]);
211213
assert.strictEqual(ab.byteLength, 0);
212214
assert.strictEqual(util.inspect(ab),
213-
'ArrayBuffer { (detached), byteLength: 0 }');
215+
'ArrayBuffer { (detached), [byteLength]: 0 }');
216+
217+
assert.strictEqual(
218+
util.inspect(dv),
219+
'DataView {\n' +
220+
' [byteLength]: 0,\n' +
221+
' [byteOffset]: undefined,\n' +
222+
' [buffer]: ArrayBuffer { (detached), [byteLength]: 0 }\n' +
223+
' }',
224+
);
214225
}
215226

216227
// Truncate output for ArrayBuffers using plural or singular bytes
217228
{
218229
const ab = new ArrayBuffer(3);
219-
assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 2 }),
230+
assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 2, breakLength: 82 }),
220231
'ArrayBuffer { [Uint8Contents]' +
221-
': <00 00 ... 1 more byte>, byteLength: 3 }');
222-
assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 1 }),
232+
': <00 00 ... 1 more byte>, [byteLength]: 3 }');
233+
assert.strictEqual(util.inspect(ab, { showHidden: true, maxArrayLength: 1, breakLength: 82 }),
223234
'ArrayBuffer { [Uint8Contents]' +
224-
': <00 ... 2 more bytes>, byteLength: 3 }');
235+
': <00 ... 2 more bytes>, [byteLength]: 3 }');
225236
}
226237

227238
// Now do the same checks but from a different context.
@@ -231,35 +242,35 @@ assert.doesNotMatch(
231242
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
232243
assert.strictEqual(
233244
util.inspect(ab, showHidden),
234-
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
245+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, [byteLength]: 4 }'
235246
);
236247
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
237248
'DataView {\n' +
238-
' byteLength: 2,\n' +
239-
' byteOffset: 1,\n' +
240-
' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
241-
' byteLength: 4 }\n}');
249+
' [byteLength]: 2,\n' +
250+
' [byteOffset]: 1,\n' +
251+
' [buffer]: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
252+
' [byteLength]: 4 }\n}');
242253
assert.strictEqual(
243254
util.inspect(ab, showHidden),
244-
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
255+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, [byteLength]: 4 }'
245256
);
246257
assert.strictEqual(util.inspect(dv, showHidden),
247258
'DataView {\n' +
248-
' byteLength: 2,\n' +
249-
' byteOffset: 1,\n' +
250-
' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
251-
' byteLength: 4 }\n}');
259+
' [byteLength]: 2,\n' +
260+
' [byteOffset]: 1,\n' +
261+
' [buffer]: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
262+
' [byteLength]: 4 }\n}');
252263
ab.x = 42;
253264
dv.y = 1337;
254265
assert.strictEqual(util.inspect(ab, showHidden),
255266
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
256-
'byteLength: 4, x: 42 }');
257-
assert.strictEqual(util.inspect(dv, showHidden),
267+
'[byteLength]: 4, x: 42 }');
268+
assert.strictEqual(util.inspect(dv, { showHidden, breakLength: 82 }),
258269
'DataView {\n' +
259-
' byteLength: 2,\n' +
260-
' byteOffset: 1,\n' +
261-
' buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
262-
' byteLength: 4, x: 42 },\n' +
270+
' [byteLength]: 2,\n' +
271+
' [byteOffset]: 1,\n' +
272+
' [buffer]: ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
273+
' [byteLength]: 4, x: 42 },\n' +
263274
' y: 1337\n}');
264275
}
265276

@@ -286,7 +297,7 @@ assert.doesNotMatch(
286297
` [length]: ${length},\n` +
287298
` [byteLength]: ${byteLength},\n` +
288299
' [byteOffset]: 0,\n' +
289-
` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
300+
` [buffer]: ArrayBuffer { [byteLength]: ${byteLength} }\n]`);
290301
assert.strictEqual(
291302
util.inspect(array, false),
292303
`${constructor.name}(${length}) [ 65, 97 ]`
@@ -320,7 +331,7 @@ assert.doesNotMatch(
320331
` [length]: ${length},\n` +
321332
` [byteLength]: ${byteLength},\n` +
322333
' [byteOffset]: 0,\n' +
323-
` [buffer]: ArrayBuffer { byteLength: ${byteLength} }\n]`);
334+
` [buffer]: ArrayBuffer { [byteLength]: ${byteLength} }\n]`);
324335
assert.strictEqual(
325336
util.inspect(array, false),
326337
`${constructor.name}(${length}) [ 65, 97 ]`
@@ -1831,7 +1842,7 @@ util.inspect(process);
18311842
' [byteLength]: 0,',
18321843
' [byteOffset]: 0,',
18331844
' [buffer]: ArrayBuffer {',
1834-
' byteLength: 0,',
1845+
' [byteLength]: 0,',
18351846
' foo: true',
18361847
' }',
18371848
' ],',
@@ -1849,7 +1860,7 @@ util.inspect(process);
18491860
' [byteLength]: 0,',
18501861
' [byteOffset]: 0,',
18511862
' [buffer]: ArrayBuffer {',
1852-
' byteLength: 0,',
1863+
' [byteLength]: 0,',
18531864
' foo: true',
18541865
' }',
18551866
' ],',
@@ -1879,7 +1890,7 @@ util.inspect(process);
18791890
' [length]: 0,',
18801891
' [byteLength]: 0,',
18811892
' [byteOffset]: 0,',
1882-
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1893+
' [buffer]: ArrayBuffer { [byteLength]: 0, foo: true }',
18831894
' ],',
18841895
' [Set Iterator] {',
18851896
' [ 1, 2, [length]: 2 ],',
@@ -1890,7 +1901,7 @@ util.inspect(process);
18901901
' [length]: 0,',
18911902
' [byteLength]: 0,',
18921903
' [byteOffset]: 0,',
1893-
' [buffer]: ArrayBuffer { byteLength: 0, foo: true }',
1904+
' [buffer]: ArrayBuffer { [byteLength]: 0, foo: true }',
18941905
' ],',
18951906
' [Circular *1],',
18961907
" [Symbol(Symbol.toStringTag)]: 'Map Iterator'",
@@ -1918,7 +1929,7 @@ util.inspect(process);
19181929
' [byteLength]: 0,',
19191930
' [byteOffset]: 0,',
19201931
' [buffer]: ArrayBuffer {',
1921-
' byteLength: 0,',
1932+
' [byteLength]: 0,',
19221933
' foo: true } ],',
19231934
' [Set Iterator] {',
19241935
' [ 1,',
@@ -1932,7 +1943,7 @@ util.inspect(process);
19321943
' [byteLength]: 0,',
19331944
' [byteOffset]: 0,',
19341945
' [buffer]: ArrayBuffer {',
1935-
' byteLength: 0,',
1946+
' [byteLength]: 0,',
19361947
' foo: true } ],',
19371948
' [Circular *1],',
19381949
' [Symbol(Symbol.toStringTag)]:',
@@ -2238,12 +2249,12 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
22382249
[new BigUint64Array(2), '[BigUint64Array(2): null prototype] [ 0n, 0n ]'],
22392250
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
22402251
' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
2241-
' byteLength: undefined\n}'],
2252+
' [byteLength]: undefined\n}'],
22422253
[new DataView(new ArrayBuffer(16)),
2243-
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
2244-
'byteOffset: undefined,\n buffer: undefined\n}'],
2254+
'[DataView: null prototype] {\n [byteLength]: undefined,\n ' +
2255+
'[byteOffset]: undefined,\n [buffer]: undefined\n}'],
22452256
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
2246-
'{\n [Uint8Contents]: <00 00>,\n byteLength: undefined\n}'],
2257+
'{\n [Uint8Contents]: <00 00>,\n [byteLength]: undefined\n}'],
22472258
[/foobar/, '[RegExp: null prototype] /foobar/'],
22482259
[new Date('Sun, 14 Feb 2010 11:48:40 GMT'),
22492260
'[Date: null prototype] 2010-02-14T11:48:40.000Z'],
@@ -3596,7 +3607,7 @@ assert.strictEqual(
35963607
assert.strictEqual(
35973608
util.inspect(o),
35983609
'{\n' +
3599-
' arrayBuffer: ArrayBuffer { [Uint8Contents]: <>, byteLength: 0 },\n' +
3610+
' arrayBuffer: ArrayBuffer { [Uint8Contents]: <>, [byteLength]: 0 },\n' +
36003611
' buffer: <Buffer 48 65 6c 6c 6f>,\n' +
36013612
' typedArray: TypedArray(5) [Uint8Array] [ 72, 101, 108, 108, 111 ],\n' +
36023613
' array: [],\n' +

0 commit comments

Comments
 (0)