1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 08:39:09 -05:00

chore(ext/console): add 'quotes' internal option to Deno.inspect (#18183)

This commit is contained in:
Yoshiya Hinosawa 2023-03-17 12:22:09 +09:00 committed by GitHub
parent 8f9becee76
commit e30d24be72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 24 deletions

View file

@ -2155,3 +2155,16 @@ Deno.test(function inspectorMethods() {
console.profile("test"); console.profile("test");
console.profileEnd("test"); console.profileEnd("test");
}); });
Deno.test(function inspectQuotesOverride() {
assertEquals(
// @ts-ignore - 'quotes' is an internal option
Deno.inspect("foo", { quotes: ["'", '"', "`"] }),
"'foo'",
);
assertEquals(
// @ts-ignore - 'quotes' is an internal option
Deno.inspect("'foo'", { quotes: ["'", '"', "`"] }),
`"'foo'"`,
);
});

View file

@ -288,6 +288,11 @@ function cliTable(head, columns) {
} }
/* End of forked part */ /* End of forked part */
// We can match Node's quoting behavior exactly by swapping the double quote and
// single quote in this array. That would give preference to single quotes.
// However, we prefer double quotes as the default.
const QUOTES = ['"', "'", "`"];
const DEFAULT_INSPECT_OPTIONS = { const DEFAULT_INSPECT_OPTIONS = {
depth: 4, depth: 4,
indentLevel: 0, indentLevel: 0,
@ -300,6 +305,11 @@ const DEFAULT_INSPECT_OPTIONS = {
getters: false, getters: false,
showHidden: false, showHidden: false,
strAbbreviateSize: 100, strAbbreviateSize: 100,
/** You can override the quotes preference in inspectString.
* Used by util.inspect() */
// TODO(kt3k): Consider using symbol as a key to hide this from the public
// API.
quotes: QUOTES,
}; };
const DEFAULT_INDENT = " "; // Default indent string const DEFAULT_INDENT = " "; // Default indent string
@ -678,7 +688,7 @@ function _inspectValue(
switch (typeof value) { switch (typeof value) {
case "string": case "string":
return green(quoteString(value)); return green(quoteString(value, inspectOptions));
case "number": // Numbers are yellow case "number": // Numbers are yellow
// Special handling of -0 // Special handling of -0
return yellow(ObjectIs(value, -0) ? "-0" : `${value}`); return yellow(ObjectIs(value, -0) ? "-0" : `${value}`);
@ -687,7 +697,7 @@ function _inspectValue(
case "undefined": // undefined is gray case "undefined": // undefined is gray
return gray(String(value)); return gray(String(value));
case "symbol": // Symbols are green case "symbol": // Symbols are green
return green(maybeQuoteSymbol(value)); return green(maybeQuoteSymbol(value, inspectOptions));
case "bigint": // Bigints are yellow case "bigint": // Bigints are yellow
return yellow(`${value}n`); return yellow(`${value}n`);
case "function": // Function string is cyan case "function": // Function string is cyan
@ -731,11 +741,6 @@ function inspectValue(
return x; return x;
} }
// We can match Node's quoting behavior exactly by swapping the double quote and
// single quote in this array. That would give preference to single quotes.
// However, we prefer double quotes as the default.
const QUOTES = ['"', "'", "`"];
/** Surround the string in quotes. /** Surround the string in quotes.
* *
* The quote symbol is chosen by taking the first of the `QUOTES` array which * The quote symbol is chosen by taking the first of the `QUOTES` array which
@ -744,10 +749,11 @@ const QUOTES = ['"', "'", "`"];
* Insert a backslash before any occurrence of the chosen quote symbol and * Insert a backslash before any occurrence of the chosen quote symbol and
* before any backslash. * before any backslash.
*/ */
function quoteString(string) { function quoteString(string, inspectOptions = DEFAULT_INSPECT_OPTIONS) {
const quotes = inspectOptions.quotes;
const quote = const quote =
ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ?? ArrayPrototypeFind(quotes, (c) => !StringPrototypeIncludes(string, c)) ??
QUOTES[0]; quotes[0];
const escapePattern = new SafeRegExp(`(?=[${quote}\\\\])`, "g"); const escapePattern = new SafeRegExp(`(?=[${quote}\\\\])`, "g");
string = StringPrototypeReplace(string, escapePattern, "\\"); string = StringPrototypeReplace(string, escapePattern, "\\");
string = replaceEscapeSequences(string); string = replaceEscapeSequences(string);
@ -789,20 +795,20 @@ function replaceEscapeSequences(string) {
const QUOTE_STRING_PATTERN = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_0-9]*$/); const QUOTE_STRING_PATTERN = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_0-9]*$/);
// Surround a string with quotes when it is required (e.g the string not a valid identifier). // Surround a string with quotes when it is required (e.g the string not a valid identifier).
function maybeQuoteString(string) { function maybeQuoteString(string, inspectOptions) {
if ( if (
RegExpPrototypeTest(QUOTE_STRING_PATTERN, string) RegExpPrototypeTest(QUOTE_STRING_PATTERN, string)
) { ) {
return replaceEscapeSequences(string); return replaceEscapeSequences(string);
} }
return quoteString(string); return quoteString(string, inspectOptions);
} }
const QUOTE_SYMBOL_REG = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_.0-9]*$/); const QUOTE_SYMBOL_REG = new SafeRegExp(/^[a-zA-Z_][a-zA-Z_.0-9]*$/);
// Surround a symbol's description in quotes when it is required (e.g the description has non printable characters). // Surround a symbol's description in quotes when it is required (e.g the description has non printable characters).
function maybeQuoteSymbol(symbol) { function maybeQuoteSymbol(symbol, inspectOptions) {
if (symbol.description === undefined) { if (symbol.description === undefined) {
return SymbolPrototypeToString(symbol); return SymbolPrototypeToString(symbol);
} }
@ -816,7 +822,7 @@ function maybeQuoteSymbol(symbol) {
return SymbolPrototypeToString(symbol); return SymbolPrototypeToString(symbol);
} }
return `Symbol(${quoteString(symbol.description)})`; return `Symbol(${quoteString(symbol.description, inspectOptions)})`;
} }
const CTX_STACK = []; const CTX_STACK = [];
@ -842,7 +848,7 @@ function inspectValueWithQuotes(
const trunc = value.length > abbreviateSize const trunc = value.length > abbreviateSize
? StringPrototypeSlice(value, 0, abbreviateSize) + "..." ? StringPrototypeSlice(value, 0, abbreviateSize) + "..."
: value; : value;
return green(quoteString(trunc)); // Quoted strings are green return green(quoteString(trunc, inspectOptions)); // Quoted strings are green
} }
default: default:
return inspectValue(value, inspectOptions); return inspectValue(value, inspectOptions);
@ -1101,7 +1107,11 @@ function inspectBigIntObject(value, inspectOptions) {
function inspectSymbolObject(value, inspectOptions) { function inspectSymbolObject(value, inspectOptions) {
const cyan = maybeColor(colors.cyan, inspectOptions); const cyan = maybeColor(colors.cyan, inspectOptions);
return cyan(`[Symbol: ${maybeQuoteSymbol(SymbolPrototypeValueOf(value))}]`); // wrappers are in cyan return cyan(
`[Symbol: ${
maybeQuoteSymbol(SymbolPrototypeValueOf(value), inspectOptions)
}]`,
); // wrappers are in cyan
} }
const PromiseState = { const PromiseState = {
@ -1206,21 +1216,24 @@ function inspectRawObject(
: red(`[Thrown ${error.name}: ${error.message}]`); : red(`[Thrown ${error.name}: ${error.message}]`);
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`${maybeQuoteString(key)}: ${inspectedValue}`, `${maybeQuoteString(key, inspectOptions)}: ${inspectedValue}`,
); );
} else { } else {
const descriptor = ObjectGetOwnPropertyDescriptor(value, key); const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
if (descriptor.get !== undefined && descriptor.set !== undefined) { if (descriptor.get !== undefined && descriptor.set !== undefined) {
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`${maybeQuoteString(key)}: [Getter/Setter]`, `${maybeQuoteString(key, inspectOptions)}: [Getter/Setter]`,
); );
} else if (descriptor.get !== undefined) { } else if (descriptor.get !== undefined) {
ArrayPrototypePush(entries, `${maybeQuoteString(key)}: [Getter]`); ArrayPrototypePush(
entries,
`${maybeQuoteString(key, inspectOptions)}: [Getter]`,
);
} else { } else {
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`${maybeQuoteString(key)}: ${ `${maybeQuoteString(key, inspectOptions)}: ${
inspectValueWithQuotes(value[key], inspectOptions) inspectValueWithQuotes(value[key], inspectOptions)
}`, }`,
); );
@ -1250,21 +1263,24 @@ function inspectRawObject(
: red(`Thrown ${error.name}: ${error.message}`); : red(`Thrown ${error.name}: ${error.message}`);
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`[${maybeQuoteSymbol(key)}]: ${inspectedValue}`, `[${maybeQuoteSymbol(key, inspectOptions)}]: ${inspectedValue}`,
); );
} else { } else {
const descriptor = ObjectGetOwnPropertyDescriptor(value, key); const descriptor = ObjectGetOwnPropertyDescriptor(value, key);
if (descriptor.get !== undefined && descriptor.set !== undefined) { if (descriptor.get !== undefined && descriptor.set !== undefined) {
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`[${maybeQuoteSymbol(key)}]: [Getter/Setter]`, `[${maybeQuoteSymbol(key, inspectOptions)}]: [Getter/Setter]`,
); );
} else if (descriptor.get !== undefined) { } else if (descriptor.get !== undefined) {
ArrayPrototypePush(entries, `[${maybeQuoteSymbol(key)}]: [Getter]`); ArrayPrototypePush(
entries,
`[${maybeQuoteSymbol(key, inspectOptions)}]: [Getter]`,
);
} else { } else {
ArrayPrototypePush( ArrayPrototypePush(
entries, entries,
`[${maybeQuoteSymbol(key)}]: ${ `[${maybeQuoteSymbol(key, inspectOptions)}]: ${
inspectValueWithQuotes(value[key], inspectOptions) inspectValueWithQuotes(value[key], inspectOptions)
}`, }`,
); );