Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: harden util.inspect #21869

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fixup: use reflect apply
  • Loading branch information
BridgeAR committed Jul 27, 2018
commit fa542c63e90b7d4738ae04b60d460355778ec5cf
63 changes: 37 additions & 26 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,31 @@ const inspectDefaultOptions = Object.seal({
compact: true
});

const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
const regExpToString = RegExp.prototype.toString;
const dateToISOString = Date.prototype.toISOString;
const errorToString = Error.prototype.toString;
const ReflectApply = Reflect.apply;

// This function is borrowed from the function with the same name on V8 Extras'
// `utils` object. V8 implements Reflect.apply very efficiently in conjunction
// with the spread syntax, such that no additional special case is needed for
// function calls w/o arguments.
// Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156
function uncurryThis(func) {
return (thisArg, ...args) => ReflectApply(func, thisArg, args);
}

const propertyIsEnumerable = uncurryThis(Object.prototype.propertyIsEnumerable);
const regExpToString = uncurryThis(RegExp.prototype.toString);
const dateToISOString = uncurryThis(Date.prototype.toISOString);
const errorToString = uncurryThis(Error.prototype.toString);

const bigIntValueOf = BigInt.prototype.valueOf;
const booleanValueOf = Boolean.prototype.valueOf;
const numberValueOf = Number.prototype.valueOf;
const symbolValueOf = Symbol.prototype.valueOf;
const stringValueOf = String.prototype.valueOf;
const bigIntValueOf = uncurryThis(BigInt.prototype.valueOf);
const booleanValueOf = uncurryThis(Boolean.prototype.valueOf);
const numberValueOf = uncurryThis(Number.prototype.valueOf);
const symbolValueOf = uncurryThis(Symbol.prototype.valueOf);
const stringValueOf = uncurryThis(String.prototype.valueOf);

const setValues = Set.prototype.values;
const mapEntries = Map.prototype.entries;
const dateGetTime = Date.prototype.getTime;
const setValues = uncurryThis(Set.prototype.values);
const mapEntries = uncurryThis(Map.prototype.entries);
const dateGetTime = uncurryThis(Date.prototype.getTime);

let CIRCULAR_ERROR_MESSAGE;
let internalDeepEqual;
Expand Down Expand Up @@ -595,7 +606,7 @@ function formatValue(ctx, value, recurseTimes) {
}

if (symbols.length !== 0)
symbols = symbols.filter((key) => propertyIsEnumerable.call(value, key));
symbols = symbols.filter((key) => propertyIsEnumerable(value, key));
}

const keyLength = keys.length + symbols.length;
Expand Down Expand Up @@ -670,16 +681,16 @@ function formatValue(ctx, value, recurseTimes) {
} else if (isRegExp(value)) {
// Make RegExps say that they are RegExps
if (keyLength === 0 || recurseTimes < 0)
return ctx.stylize(regExpToString.call(value), 'regexp');
base = `${regExpToString.call(value)}`;
return ctx.stylize(regExpToString(value), 'regexp');
base = `${regExpToString(value)}`;
} else if (isDate(value)) {
// Make dates with properties first say the date
if (keyLength === 0) {
if (Number.isNaN(dateGetTime.call(value)))
if (Number.isNaN(dateGetTime(value)))
return ctx.stylize(String(value), 'date');
return ctx.stylize(dateToISOString.call(value), 'date');
return ctx.stylize(dateToISOString(value), 'date');
}
base = dateToISOString.call(value);
base = dateToISOString(value);
} else if (isError(value)) {
// Make error with message first say the error
base = formatError(value);
Expand Down Expand Up @@ -738,23 +749,23 @@ function formatValue(ctx, value, recurseTimes) {
braces[0] = `[${tag}] {`;
formatter = formatNamespaceObject;
} else if (isNumberObject(value)) {
base = `[Number: ${getBoxedValue(numberValueOf.call(value))}]`;
base = `[Number: ${getBoxedValue(numberValueOf(value))}]`;
if (keyLength === 0)
return ctx.stylize(base, 'number');
} else if (isBooleanObject(value)) {
base = `[Boolean: ${getBoxedValue(booleanValueOf.call(value))}]`;
base = `[Boolean: ${getBoxedValue(booleanValueOf(value))}]`;
if (keyLength === 0)
return ctx.stylize(base, 'boolean');
} else if (isBigIntObject(value)) {
base = `[BigInt: ${getBoxedValue(bigIntValueOf.call(value))}]`;
base = `[BigInt: ${getBoxedValue(bigIntValueOf(value))}]`;
if (keyLength === 0)
return ctx.stylize(base, 'bigint');
} else if (isSymbolObject(value)) {
base = `[Symbol: ${getBoxedValue(symbolValueOf.call(value))}]`;
base = `[Symbol: ${getBoxedValue(symbolValueOf(value))}]`;
if (keyLength === 0)
return ctx.stylize(base, 'symbol');
} else if (isStringObject(value)) {
const raw = stringValueOf.call(value);
const raw = stringValueOf(value);
base = `[String: ${getBoxedValue(raw, ctx)}]`;
if (keyLength === raw.length)
return ctx.stylize(base, 'string');
Expand All @@ -766,10 +777,10 @@ function formatValue(ctx, value, recurseTimes) {
// The input prototype got manipulated. Special handle these.
// We have to rebuild the information so we are able to display everything.
} else if (isSet(value)) {
const newVal = addExtraKeys(value, new Set(setValues.call(value)), keys);
const newVal = addExtraKeys(value, new Set(setValues(value)), keys);
return formatValue(ctx, newVal, recurseTimes);
} else if (isMap(value)) {
const newVal = addExtraKeys(value, new Map(mapEntries.call(value)), keys);
const newVal = addExtraKeys(value, new Map(mapEntries(value)), keys);
return formatValue(ctx, newVal, recurseTimes);
} else if (Array.isArray(value)) {
// The prefix is not always possible to fully reconstruct.
Expand Down Expand Up @@ -900,7 +911,7 @@ function formatPrimitive(fn, value, ctx) {
}

function formatError(value) {
return value.stack || errorToString.call(value);
return value.stack || errorToString(value);
}

function formatObject(ctx, value, recurseTimes, keys) {
Expand Down