diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2023-02-07 20:22:46 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-07 20:22:46 +0100 |
commit | b4aa1530970f7b9cc4e6f2f27e077852c4e178d3 (patch) | |
tree | 3d008912affe8550692183bd2697a386db5e3c79 /ext/console/02_console.js | |
parent | 65500f36e870b4ada3996b06aa287e30177d21a3 (diff) |
refactor: Use ES modules for internal runtime code (#17648)
This PR refactors all internal js files (except core) to be written as
ES modules.
`__bootstrap`has been mostly replaced with static imports in form in
`internal:[path to file from repo root]`.
To specify if files are ESM, an `esm` method has been added to
`Extension`, similar to the `js` method.
A new ModuleLoader called `InternalModuleLoader` has been added to
enable the loading of internal specifiers, which is used in all
situations except when a snapshot is only loaded, and not a new one is
created from it.
---------
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/console/02_console.js')
-rw-r--r-- | ext/console/02_console.js | 4288 |
1 files changed, 2141 insertions, 2147 deletions
diff --git a/ext/console/02_console.js b/ext/console/02_console.js index a9ec52488..22524e6b9 100644 --- a/ext/console/02_console.js +++ b/ext/console/02_console.js @@ -2,2385 +2,2379 @@ /// <reference path="../../core/internal.d.ts" /> -"use strict"; - -((window) => { - const core = window.Deno.core; - const colors = window.__bootstrap.colors; - const { - AggregateErrorPrototype, - ArrayPrototypeUnshift, - isNaN, - DatePrototype, - DateNow, - DatePrototypeGetTime, - DatePrototypeToISOString, - Boolean, - BooleanPrototype, - BooleanPrototypeToString, - ObjectKeys, - ObjectCreate, - ObjectAssign, - ObjectIs, - ObjectValues, - ObjectFromEntries, - ObjectGetPrototypeOf, - ObjectGetOwnPropertyDescriptor, - ObjectGetOwnPropertySymbols, - ObjectPrototypeHasOwnProperty, - ObjectPrototypeIsPrototypeOf, - ObjectPrototypePropertyIsEnumerable, - PromisePrototype, - String, - StringPrototype, - StringPrototypeRepeat, - StringPrototypeReplace, - StringPrototypeReplaceAll, - StringPrototypeSplit, - StringPrototypeSlice, - StringPrototypeCodePointAt, - StringPrototypeCharCodeAt, - StringPrototypeNormalize, - StringPrototypeMatch, - StringPrototypePadStart, - StringPrototypeLocaleCompare, - StringPrototypeToString, - StringPrototypeTrim, - StringPrototypeIncludes, - StringPrototypeStartsWith, - TypeError, - NumberParseInt, - RegExp, - RegExpPrototype, - RegExpPrototypeTest, - RegExpPrototypeToString, - SafeArrayIterator, - SafeStringIterator, - SafeSet, - SetPrototype, - SetPrototypeEntries, - SetPrototypeGetSize, - Symbol, - SymbolPrototype, - SymbolPrototypeToString, - SymbolPrototypeValueOf, - SymbolToStringTag, - SymbolHasInstance, - SymbolFor, - Array, - ArrayIsArray, - ArrayPrototypeJoin, - ArrayPrototypeMap, - ArrayPrototypeReduce, - ArrayPrototypeEntries, - ArrayPrototypePush, - ArrayPrototypePop, - ArrayPrototypeSort, - ArrayPrototypeSlice, - ArrayPrototypeShift, - ArrayPrototypeIncludes, - ArrayPrototypeFill, - ArrayPrototypeFilter, - ArrayPrototypeFind, - FunctionPrototypeBind, - FunctionPrototypeToString, - Map, - MapPrototype, - MapPrototypeHas, - MapPrototypeGet, - MapPrototypeSet, - MapPrototypeDelete, - MapPrototypeEntries, - MapPrototypeForEach, - MapPrototypeGetSize, - Error, - ErrorPrototype, - ErrorCaptureStackTrace, - MathAbs, - MathMax, - MathMin, - MathSqrt, - MathRound, - MathFloor, - Number, - NumberPrototype, - NumberPrototypeToString, - NumberPrototypeValueOf, - BigIntPrototype, - BigIntPrototypeToString, - Proxy, - ReflectGet, - ReflectGetOwnPropertyDescriptor, - ReflectGetPrototypeOf, - ReflectHas, - TypedArrayPrototypeGetLength, - TypedArrayPrototypeGetSymbolToStringTag, - WeakMapPrototype, - WeakSetPrototype, - } = window.__bootstrap.primordials; - - function isInvalidDate(x) { - return isNaN(DatePrototypeGetTime(x)); - } - - function hasOwnProperty(obj, v) { - if (obj == null) { - return false; - } - return ObjectPrototypeHasOwnProperty(obj, v); - } - - function propertyIsEnumerable(obj, prop) { - if ( - obj == null || - typeof obj.propertyIsEnumerable !== "function" - ) { - return false; - } - - return ObjectPrototypePropertyIsEnumerable(obj, prop); +const core = globalThis.Deno.core; +const internals = globalThis.__bootstrap.internals; +const primordials = globalThis.__bootstrap.primordials; +const { + AggregateErrorPrototype, + ArrayPrototypeUnshift, + isNaN, + DatePrototype, + DateNow, + DatePrototypeGetTime, + DatePrototypeToISOString, + Boolean, + BooleanPrototype, + BooleanPrototypeToString, + ObjectKeys, + ObjectCreate, + ObjectAssign, + ObjectIs, + ObjectValues, + ObjectFromEntries, + ObjectGetPrototypeOf, + ObjectGetOwnPropertyDescriptor, + ObjectGetOwnPropertySymbols, + ObjectPrototypeHasOwnProperty, + ObjectPrototypeIsPrototypeOf, + ObjectPrototypePropertyIsEnumerable, + PromisePrototype, + String, + StringPrototype, + StringPrototypeRepeat, + StringPrototypeReplace, + StringPrototypeReplaceAll, + StringPrototypeSplit, + StringPrototypeSlice, + StringPrototypeCodePointAt, + StringPrototypeCharCodeAt, + StringPrototypeNormalize, + StringPrototypeMatch, + StringPrototypePadStart, + StringPrototypeLocaleCompare, + StringPrototypeToString, + StringPrototypeTrim, + StringPrototypeIncludes, + StringPrototypeStartsWith, + TypeError, + NumberParseInt, + RegExp, + RegExpPrototype, + RegExpPrototypeTest, + RegExpPrototypeToString, + SafeArrayIterator, + SafeStringIterator, + SafeSet, + SetPrototype, + SetPrototypeEntries, + SetPrototypeGetSize, + Symbol, + SymbolPrototype, + SymbolPrototypeToString, + SymbolPrototypeValueOf, + SymbolToStringTag, + SymbolHasInstance, + SymbolFor, + Array, + ArrayIsArray, + ArrayPrototypeJoin, + ArrayPrototypeMap, + ArrayPrototypeReduce, + ArrayPrototypeEntries, + ArrayPrototypePush, + ArrayPrototypePop, + ArrayPrototypeSort, + ArrayPrototypeSlice, + ArrayPrototypeShift, + ArrayPrototypeIncludes, + ArrayPrototypeFill, + ArrayPrototypeFilter, + ArrayPrototypeFind, + FunctionPrototypeBind, + FunctionPrototypeToString, + Map, + MapPrototype, + MapPrototypeHas, + MapPrototypeGet, + MapPrototypeSet, + MapPrototypeDelete, + MapPrototypeEntries, + MapPrototypeForEach, + MapPrototypeGetSize, + Error, + ErrorPrototype, + ErrorCaptureStackTrace, + MathAbs, + MathMax, + MathMin, + MathSqrt, + MathRound, + MathFloor, + Number, + NumberPrototype, + NumberPrototypeToString, + NumberPrototypeValueOf, + BigIntPrototype, + BigIntPrototypeToString, + Proxy, + ReflectGet, + ReflectGetOwnPropertyDescriptor, + ReflectGetPrototypeOf, + ReflectHas, + TypedArrayPrototypeGetLength, + TypedArrayPrototypeGetSymbolToStringTag, + WeakMapPrototype, + WeakSetPrototype, +} = primordials; +import * as colors from "internal:ext/console/01_colors.js"; + +function isInvalidDate(x) { + return isNaN(DatePrototypeGetTime(x)); +} + +function hasOwnProperty(obj, v) { + if (obj == null) { + return false; } + return ObjectPrototypeHasOwnProperty(obj, v); +} - // Copyright Joyent, Inc. and other Node contributors. MIT license. - // Forked from Node's lib/internal/cli_table.js - - function isTypedArray(x) { - return TypedArrayPrototypeGetSymbolToStringTag(x) !== undefined; +function propertyIsEnumerable(obj, prop) { + if ( + obj == null || + typeof obj.propertyIsEnumerable !== "function" + ) { + return false; } - const tableChars = { - middleMiddle: "─", - rowMiddle: "┼", - topRight: "┐", - topLeft: "┌", - leftMiddle: "├", - topMiddle: "┬", - bottomRight: "┘", - bottomLeft: "└", - bottomMiddle: "┴", - rightMiddle: "┤", - left: "│ ", - right: " │", - middle: " │ ", - }; - - function isFullWidthCodePoint(code) { - // Code points are partially derived from: - // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt - return ( - code >= 0x1100 && - (code <= 0x115f || // Hangul Jamo - code === 0x2329 || // LEFT-POINTING ANGLE BRACKET - code === 0x232a || // RIGHT-POINTING ANGLE BRACKET - // CJK Radicals Supplement .. Enclosed CJK Letters and Months - (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) || - // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A - (code >= 0x3250 && code <= 0x4dbf) || - // CJK Unified Ideographs .. Yi Radicals - (code >= 0x4e00 && code <= 0xa4c6) || - // Hangul Jamo Extended-A - (code >= 0xa960 && code <= 0xa97c) || - // Hangul Syllables - (code >= 0xac00 && code <= 0xd7a3) || - // CJK Compatibility Ideographs - (code >= 0xf900 && code <= 0xfaff) || - // Vertical Forms - (code >= 0xfe10 && code <= 0xfe19) || - // CJK Compatibility Forms .. Small Form Variants - (code >= 0xfe30 && code <= 0xfe6b) || - // Halfwidth and Fullwidth Forms - (code >= 0xff01 && code <= 0xff60) || - (code >= 0xffe0 && code <= 0xffe6) || - // Kana Supplement - (code >= 0x1b000 && code <= 0x1b001) || - // Enclosed Ideographic Supplement - (code >= 0x1f200 && code <= 0x1f251) || - // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff - // Emoticons 0x1f600 - 0x1f64f - (code >= 0x1f300 && code <= 0x1f64f) || - // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane - (code >= 0x20000 && code <= 0x3fffd)) - ); + return ObjectPrototypePropertyIsEnumerable(obj, prop); +} + +// Copyright Joyent, Inc. and other Node contributors. MIT license. +// Forked from Node's lib/internal/cli_table.js + +function isTypedArray(x) { + return TypedArrayPrototypeGetSymbolToStringTag(x) !== undefined; +} + +const tableChars = { + middleMiddle: "─", + rowMiddle: "┼", + topRight: "┐", + topLeft: "┌", + leftMiddle: "├", + topMiddle: "┬", + bottomRight: "┘", + bottomLeft: "└", + bottomMiddle: "┴", + rightMiddle: "┤", + left: "│ ", + right: " │", + middle: " │ ", +}; + +function isFullWidthCodePoint(code) { + // Code points are partially derived from: + // http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt + return ( + code >= 0x1100 && + (code <= 0x115f || // Hangul Jamo + code === 0x2329 || // LEFT-POINTING ANGLE BRACKET + code === 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK Radicals Supplement .. Enclosed CJK Letters and Months + (code >= 0x2e80 && code <= 0x3247 && code !== 0x303f) || + // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A + (code >= 0x3250 && code <= 0x4dbf) || + // CJK Unified Ideographs .. Yi Radicals + (code >= 0x4e00 && code <= 0xa4c6) || + // Hangul Jamo Extended-A + (code >= 0xa960 && code <= 0xa97c) || + // Hangul Syllables + (code >= 0xac00 && code <= 0xd7a3) || + // CJK Compatibility Ideographs + (code >= 0xf900 && code <= 0xfaff) || + // Vertical Forms + (code >= 0xfe10 && code <= 0xfe19) || + // CJK Compatibility Forms .. Small Form Variants + (code >= 0xfe30 && code <= 0xfe6b) || + // Halfwidth and Fullwidth Forms + (code >= 0xff01 && code <= 0xff60) || + (code >= 0xffe0 && code <= 0xffe6) || + // Kana Supplement + (code >= 0x1b000 && code <= 0x1b001) || + // Enclosed Ideographic Supplement + (code >= 0x1f200 && code <= 0x1f251) || + // Miscellaneous Symbols and Pictographs 0x1f300 - 0x1f5ff + // Emoticons 0x1f600 - 0x1f64f + (code >= 0x1f300 && code <= 0x1f64f) || + // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane + (code >= 0x20000 && code <= 0x3fffd)) + ); +} + +function getStringWidth(str) { + str = StringPrototypeNormalize(colors.stripColor(str), "NFC"); + let width = 0; + + for (const ch of new SafeStringIterator(str)) { + width += isFullWidthCodePoint(StringPrototypeCodePointAt(ch, 0)) ? 2 : 1; } - function getStringWidth(str) { - str = StringPrototypeNormalize(colors.stripColor(str), "NFC"); - let width = 0; - - for (const ch of new SafeStringIterator(str)) { - width += isFullWidthCodePoint(StringPrototypeCodePointAt(ch, 0)) ? 2 : 1; + return width; +} + +function renderRow(row, columnWidths, columnRightAlign) { + let out = tableChars.left; + for (let i = 0; i < row.length; i++) { + const cell = row[i]; + const len = getStringWidth(cell); + const padding = StringPrototypeRepeat(" ", columnWidths[i] - len); + if (columnRightAlign?.[i]) { + out += `${padding}${cell}`; + } else { + out += `${cell}${padding}`; + } + if (i !== row.length - 1) { + out += tableChars.middle; } - - return width; } - - function renderRow(row, columnWidths, columnRightAlign) { - let out = tableChars.left; - for (let i = 0; i < row.length; i++) { - const cell = row[i]; - const len = getStringWidth(cell); - const padding = StringPrototypeRepeat(" ", columnWidths[i] - len); - if (columnRightAlign?.[i]) { - out += `${padding}${cell}`; - } else { - out += `${cell}${padding}`; - } - if (i !== row.length - 1) { - out += tableChars.middle; + out += tableChars.right; + return out; +} + +function canRightAlign(value) { + const isNumber = !isNaN(value); + return isNumber; +} + +function cliTable(head, columns) { + const rows = []; + const columnWidths = ArrayPrototypeMap(head, (h) => getStringWidth(h)); + const longestColumn = ArrayPrototypeReduce( + columns, + (n, a) => MathMax(n, a.length), + 0, + ); + const columnRightAlign = new Array(columnWidths.length).fill(true); + + for (let i = 0; i < head.length; i++) { + const column = columns[i]; + for (let j = 0; j < longestColumn; j++) { + if (rows[j] === undefined) { + rows[j] = []; } + const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : ""); + const width = columnWidths[i] || 0; + const counted = getStringWidth(value); + columnWidths[i] = MathMax(width, counted); + columnRightAlign[i] &= canRightAlign(value); } - out += tableChars.right; - return out; } - function canRightAlign(value) { - const isNumber = !isNaN(value); - return isNumber; + const divider = ArrayPrototypeMap( + columnWidths, + (i) => StringPrototypeRepeat(tableChars.middleMiddle, i + 2), + ); + + let result = + `${tableChars.topLeft}${ + ArrayPrototypeJoin(divider, tableChars.topMiddle) + }` + + `${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` + + `${tableChars.leftMiddle}${ + ArrayPrototypeJoin(divider, tableChars.rowMiddle) + }` + + `${tableChars.rightMiddle}\n`; + + for (let i = 0; i < rows.length; ++i) { + const row = rows[i]; + result += `${renderRow(row, columnWidths, columnRightAlign)}\n`; } - function cliTable(head, columns) { - const rows = []; - const columnWidths = ArrayPrototypeMap(head, (h) => getStringWidth(h)); - const longestColumn = ArrayPrototypeReduce( - columns, - (n, a) => MathMax(n, a.length), - 0, - ); - const columnRightAlign = new Array(columnWidths.length).fill(true); - - for (let i = 0; i < head.length; i++) { - const column = columns[i]; - for (let j = 0; j < longestColumn; j++) { - if (rows[j] === undefined) { - rows[j] = []; - } - const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : ""); - const width = columnWidths[i] || 0; - const counted = getStringWidth(value); - columnWidths[i] = MathMax(width, counted); - columnRightAlign[i] &= canRightAlign(value); - } - } + result += + `${tableChars.bottomLeft}${ + ArrayPrototypeJoin(divider, tableChars.bottomMiddle) + }` + + tableChars.bottomRight; + + return result; +} +/* End of forked part */ + +const DEFAULT_INSPECT_OPTIONS = { + depth: 4, + indentLevel: 0, + sorted: false, + trailingComma: false, + compact: true, + iterableLimit: 100, + showProxy: false, + colors: false, + getters: false, + showHidden: false, + strAbbreviateSize: 100, +}; + +const DEFAULT_INDENT = " "; // Default indent string + +const LINE_BREAKING_LENGTH = 80; +const MIN_GROUP_LENGTH = 6; +const STR_ABBREVIATE_SIZE = 100; + +const PROMISE_STRING_BASE_LENGTH = 12; + +class CSI { + static kClear = "\x1b[1;1H"; + static kClearScreenDown = "\x1b[0J"; +} + +function getClassInstanceName(instance) { + if (typeof instance != "object") { + return ""; + } + const constructor = instance?.constructor; + if (typeof constructor == "function") { + return constructor.name ?? ""; + } + return ""; +} + +function maybeColor(fn, inspectOptions) { + return inspectOptions.colors ? fn : (s) => s; +} + +function inspectFunction(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + if ( + ReflectHas(value, customInspect) && + typeof value[customInspect] === "function" + ) { + return String(value[customInspect](inspect, inspectOptions)); + } + // Might be Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction + let cstrName = ObjectGetPrototypeOf(value)?.constructor?.name; + if (!cstrName) { + // If prototype is removed or broken, + // use generic 'Function' instead. + cstrName = "Function"; + } + const stringValue = FunctionPrototypeToString(value); + // Might be Class + if (StringPrototypeStartsWith(stringValue, "class")) { + cstrName = "Class"; + } - const divider = ArrayPrototypeMap( - columnWidths, - (i) => StringPrototypeRepeat(tableChars.middleMiddle, i + 2), + // Our function may have properties, so we want to format those + // as if our function was an object + // If we didn't find any properties, we will just append an + // empty suffix. + let suffix = ``; + let refStr = ""; + if ( + ObjectKeys(value).length > 0 || + ObjectGetOwnPropertySymbols(value).length > 0 + ) { + const { 0: propString, 1: refIndex } = inspectRawObject( + value, + inspectOptions, ); - - let result = - `${tableChars.topLeft}${ - ArrayPrototypeJoin(divider, tableChars.topMiddle) - }` + - `${tableChars.topRight}\n${renderRow(head, columnWidths)}\n` + - `${tableChars.leftMiddle}${ - ArrayPrototypeJoin(divider, tableChars.rowMiddle) - }` + - `${tableChars.rightMiddle}\n`; - - for (let i = 0; i < rows.length; ++i) { - const row = rows[i]; - result += `${renderRow(row, columnWidths, columnRightAlign)}\n`; + refStr = refIndex; + // Filter out the empty string for the case we only have + // non-enumerable symbols. + if ( + propString.length > 0 && + propString !== "{}" + ) { + suffix = ` ${propString}`; } - - result += - `${tableChars.bottomLeft}${ - ArrayPrototypeJoin(divider, tableChars.bottomMiddle) - }` + - tableChars.bottomRight; - - return result; - } - /* End of forked part */ - - const DEFAULT_INSPECT_OPTIONS = { - depth: 4, - indentLevel: 0, - sorted: false, - trailingComma: false, - compact: true, - iterableLimit: 100, - showProxy: false, - colors: false, - getters: false, - showHidden: false, - strAbbreviateSize: 100, - }; - - const DEFAULT_INDENT = " "; // Default indent string - - const LINE_BREAKING_LENGTH = 80; - const MIN_GROUP_LENGTH = 6; - const STR_ABBREVIATE_SIZE = 100; - - const PROMISE_STRING_BASE_LENGTH = 12; - - class CSI { - static kClear = "\x1b[1;1H"; - static kClearScreenDown = "\x1b[0J"; } - function getClassInstanceName(instance) { - if (typeof instance != "object") { - return ""; - } - const constructor = instance?.constructor; - if (typeof constructor == "function") { - return constructor.name ?? ""; - } - return ""; + if (value.name && value.name !== "anonymous") { + // from MDN spec + return cyan(`${refStr}[${cstrName}: ${value.name}]`) + suffix; } - - function maybeColor(fn, inspectOptions) { - return inspectOptions.colors ? fn : (s) => s; + return cyan(`${refStr}[${cstrName}]`) + suffix; +} + +function inspectIterable( + value, + options, + inspectOptions, +) { + const cyan = maybeColor(colors.cyan, inspectOptions); + if (inspectOptions.indentLevel >= inspectOptions.depth) { + return cyan(`[${options.typeName}]`); } - function inspectFunction(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - if ( - ReflectHas(value, customInspect) && - typeof value[customInspect] === "function" - ) { - return String(value[customInspect](inspect, inspectOptions)); - } - // Might be Function/AsyncFunction/GeneratorFunction/AsyncGeneratorFunction - let cstrName = ObjectGetPrototypeOf(value)?.constructor?.name; - if (!cstrName) { - // If prototype is removed or broken, - // use generic 'Function' instead. - cstrName = "Function"; - } - const stringValue = FunctionPrototypeToString(value); - // Might be Class - if (StringPrototypeStartsWith(stringValue, "class")) { - cstrName = "Class"; - } + const entries = []; + let iter; + let valueIsTypedArray = false; + let entriesLength; + + switch (options.typeName) { + case "Map": + iter = MapPrototypeEntries(value); + entriesLength = MapPrototypeGetSize(value); + break; + case "Set": + iter = SetPrototypeEntries(value); + entriesLength = SetPrototypeGetSize(value); + break; + case "Array": + entriesLength = value.length; + break; + default: + if (isTypedArray(value)) { + entriesLength = TypedArrayPrototypeGetLength(value); + iter = ArrayPrototypeEntries(value); + valueIsTypedArray = true; + } else { + throw new TypeError("unreachable"); + } + } - // Our function may have properties, so we want to format those - // as if our function was an object - // If we didn't find any properties, we will just append an - // empty suffix. - let suffix = ``; - let refStr = ""; - if ( - ObjectKeys(value).length > 0 || - ObjectGetOwnPropertySymbols(value).length > 0 + let entriesLengthWithoutEmptyItems = entriesLength; + if (options.typeName === "Array") { + for ( + let i = 0, j = 0; + i < entriesLength && j < inspectOptions.iterableLimit; + i++, j++ ) { - const { 0: propString, 1: refIndex } = inspectRawObject( - value, + inspectOptions.indentLevel++; + const { entry, skipTo } = options.entryHandler( + [i, value[i]], inspectOptions, ); - refStr = refIndex; - // Filter out the empty string for the case we only have - // non-enumerable symbols. - if ( - propString.length > 0 && - propString !== "{}" - ) { - suffix = ` ${propString}`; - } - } - - if (value.name && value.name !== "anonymous") { - // from MDN spec - return cyan(`${refStr}[${cstrName}: ${value.name}]`) + suffix; - } - return cyan(`${refStr}[${cstrName}]`) + suffix; - } + ArrayPrototypePush(entries, entry); + inspectOptions.indentLevel--; - function inspectIterable( - value, - options, - inspectOptions, - ) { - const cyan = maybeColor(colors.cyan, inspectOptions); - if (inspectOptions.indentLevel >= inspectOptions.depth) { - return cyan(`[${options.typeName}]`); + if (skipTo) { + // subtract skipped (empty) items + entriesLengthWithoutEmptyItems -= skipTo - i; + i = skipTo; + } } - - const entries = []; - let iter; - let valueIsTypedArray = false; - let entriesLength; - - switch (options.typeName) { - case "Map": - iter = MapPrototypeEntries(value); - entriesLength = MapPrototypeGetSize(value); - break; - case "Set": - iter = SetPrototypeEntries(value); - entriesLength = SetPrototypeGetSize(value); - break; - case "Array": - entriesLength = value.length; - break; - default: - if (isTypedArray(value)) { - entriesLength = TypedArrayPrototypeGetLength(value); - iter = ArrayPrototypeEntries(value); - valueIsTypedArray = true; - } else { - throw new TypeError("unreachable"); + } else { + let i = 0; + while (true) { + let el; + try { + const res = iter.next(); + if (res.done) { + break; } - } - - let entriesLengthWithoutEmptyItems = entriesLength; - if (options.typeName === "Array") { - for ( - let i = 0, j = 0; - i < entriesLength && j < inspectOptions.iterableLimit; - i++, j++ - ) { + el = res.value; + } catch (err) { + if (valueIsTypedArray) { + // TypedArray.prototype.entries doesn't throw, unless the ArrayBuffer + // is detached. We don't want to show the exception in that case, so + // we catch it here and pretend the ArrayBuffer has no entries (like + // Chrome DevTools does). + break; + } + throw err; + } + if (i < inspectOptions.iterableLimit) { inspectOptions.indentLevel++; - const { entry, skipTo } = options.entryHandler( - [i, value[i]], - inspectOptions, + ArrayPrototypePush( + entries, + options.entryHandler( + el, + inspectOptions, + ), ); - ArrayPrototypePush(entries, entry); inspectOptions.indentLevel--; - - if (skipTo) { - // subtract skipped (empty) items - entriesLengthWithoutEmptyItems -= skipTo - i; - i = skipTo; - } - } - } else { - let i = 0; - while (true) { - let el; - try { - const res = iter.next(); - if (res.done) { - break; - } - el = res.value; - } catch (err) { - if (valueIsTypedArray) { - // TypedArray.prototype.entries doesn't throw, unless the ArrayBuffer - // is detached. We don't want to show the exception in that case, so - // we catch it here and pretend the ArrayBuffer has no entries (like - // Chrome DevTools does). - break; - } - throw err; - } - if (i < inspectOptions.iterableLimit) { - inspectOptions.indentLevel++; - ArrayPrototypePush( - entries, - options.entryHandler( - el, - inspectOptions, - ), - ); - inspectOptions.indentLevel--; - } else { - break; - } - i++; + } else { + break; } + i++; } + } - if (options.sort) { - ArrayPrototypeSort(entries); - } - - if (entriesLengthWithoutEmptyItems > inspectOptions.iterableLimit) { - const nmore = entriesLengthWithoutEmptyItems - - inspectOptions.iterableLimit; - ArrayPrototypePush(entries, `... ${nmore} more items`); - } + if (options.sort) { + ArrayPrototypeSort(entries); + } - const iPrefix = `${options.displayName ? options.displayName + " " : ""}`; + if (entriesLengthWithoutEmptyItems > inspectOptions.iterableLimit) { + const nmore = entriesLengthWithoutEmptyItems - + inspectOptions.iterableLimit; + ArrayPrototypePush(entries, `... ${nmore} more items`); + } - const level = inspectOptions.indentLevel; - const initIndentation = `\n${ - StringPrototypeRepeat(DEFAULT_INDENT, level + 1) - }`; - const entryIndentation = `,\n${ - StringPrototypeRepeat(DEFAULT_INDENT, level + 1) - }`; - const closingDelimIndentation = StringPrototypeRepeat( - DEFAULT_INDENT, - level, - ); - const closingIndentation = `${ - inspectOptions.trailingComma ? "," : "" - }\n${closingDelimIndentation}`; - - let iContent; - if (entries.length === 0 && !inspectOptions.compact) { - iContent = `\n${closingDelimIndentation}`; - } else if (options.group && entries.length > MIN_GROUP_LENGTH) { - const groups = groupEntries(entries, level, value); + const iPrefix = `${options.displayName ? options.displayName + " " : ""}`; + + const level = inspectOptions.indentLevel; + const initIndentation = `\n${ + StringPrototypeRepeat(DEFAULT_INDENT, level + 1) + }`; + const entryIndentation = `,\n${ + StringPrototypeRepeat(DEFAULT_INDENT, level + 1) + }`; + const closingDelimIndentation = StringPrototypeRepeat( + DEFAULT_INDENT, + level, + ); + const closingIndentation = `${ + inspectOptions.trailingComma ? "," : "" + }\n${closingDelimIndentation}`; + + let iContent; + if (entries.length === 0 && !inspectOptions.compact) { + iContent = `\n${closingDelimIndentation}`; + } else if (options.group && entries.length > MIN_GROUP_LENGTH) { + const groups = groupEntries(entries, level, value); + iContent = `${initIndentation}${ + ArrayPrototypeJoin(groups, entryIndentation) + }${closingIndentation}`; + } else { + iContent = entries.length === 0 + ? "" + : ` ${ArrayPrototypeJoin(entries, ", ")} `; + if ( + colors.stripColor(iContent).length > LINE_BREAKING_LENGTH || + !inspectOptions.compact + ) { iContent = `${initIndentation}${ - ArrayPrototypeJoin(groups, entryIndentation) + ArrayPrototypeJoin(entries, entryIndentation) }${closingIndentation}`; - } else { - iContent = entries.length === 0 - ? "" - : ` ${ArrayPrototypeJoin(entries, ", ")} `; - if ( - colors.stripColor(iContent).length > LINE_BREAKING_LENGTH || - !inspectOptions.compact - ) { - iContent = `${initIndentation}${ - ArrayPrototypeJoin(entries, entryIndentation) - }${closingIndentation}`; - } } - - return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`; } - // Ported from Node.js - // Copyright Node.js contributors. All rights reserved. - function groupEntries( - entries, - level, - value, - iterableLimit = 100, + return `${iPrefix}${options.delims[0]}${iContent}${options.delims[1]}`; +} + +// Ported from Node.js +// Copyright Node.js contributors. All rights reserved. +function groupEntries( + entries, + level, + value, + iterableLimit = 100, +) { + let totalLength = 0; + let maxLength = 0; + let entriesLength = entries.length; + if (iterableLimit < entriesLength) { + // This makes sure the "... n more items" part is not taken into account. + entriesLength--; + } + const separatorSpace = 2; // Add 1 for the space and 1 for the separator. + const dataLen = new Array(entriesLength); + // Calculate the total length of all output entries and the individual max + // entries length of all output entries. + // IN PROGRESS: Colors are being taken into account. + for (let i = 0; i < entriesLength; i++) { + // Taking colors into account: removing the ANSI color + // codes from the string before measuring its length + const len = colors.stripColor(entries[i]).length; + dataLen[i] = len; + totalLength += len + separatorSpace; + if (maxLength < len) maxLength = len; + } + // Add two to `maxLength` as we add a single whitespace character plus a comma + // in-between two entries. + const actualMax = maxLength + separatorSpace; + // Check if at least three entries fit next to each other and prevent grouping + // of arrays that contains entries of very different length (i.e., if a single + // entry is longer than 1/5 of all other entries combined). Otherwise the + // space in-between small entries would be enormous. + if ( + actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH && + (totalLength / actualMax > 5 || maxLength <= 6) ) { - let totalLength = 0; - let maxLength = 0; - let entriesLength = entries.length; - if (iterableLimit < entriesLength) { - // This makes sure the "... n more items" part is not taken into account. - entriesLength--; - } - const separatorSpace = 2; // Add 1 for the space and 1 for the separator. - const dataLen = new Array(entriesLength); - // Calculate the total length of all output entries and the individual max - // entries length of all output entries. - // IN PROGRESS: Colors are being taken into account. - for (let i = 0; i < entriesLength; i++) { - // Taking colors into account: removing the ANSI color - // codes from the string before measuring its length - const len = colors.stripColor(entries[i]).length; - dataLen[i] = len; - totalLength += len + separatorSpace; - if (maxLength < len) maxLength = len; - } - // Add two to `maxLength` as we add a single whitespace character plus a comma - // in-between two entries. - const actualMax = maxLength + separatorSpace; - // Check if at least three entries fit next to each other and prevent grouping - // of arrays that contains entries of very different length (i.e., if a single - // entry is longer than 1/5 of all other entries combined). Otherwise the - // space in-between small entries would be enormous. - if ( - actualMax * 3 + (level + 1) < LINE_BREAKING_LENGTH && - (totalLength / actualMax > 5 || maxLength <= 6) - ) { - const approxCharHeights = 2.5; - const averageBias = MathSqrt(actualMax - totalLength / entries.length); - const biasedMax = MathMax(actualMax - 3 - averageBias, 1); - // Dynamically check how many columns seem possible. - const columns = MathMin( - // Ideally a square should be drawn. We expect a character to be about 2.5 - // times as high as wide. This is the area formula to calculate a square - // which contains n rectangles of size `actualMax * approxCharHeights`. - // Divide that by `actualMax` to receive the correct number of columns. - // The added bias increases the columns for short entries. - MathRound( - MathSqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax, - ), - // Do not exceed the breakLength. - MathFloor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax), - // Limit the columns to a maximum of fifteen. - 15, - ); - // Return with the original output if no grouping should happen. - if (columns <= 1) { - return entries; - } - const tmp = []; - const maxLineLength = []; - for (let i = 0; i < columns; i++) { - let lineMaxLength = 0; - for (let j = i; j < entries.length; j += columns) { - if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j]; - } - lineMaxLength += separatorSpace; - maxLineLength[i] = lineMaxLength; + const approxCharHeights = 2.5; + const averageBias = MathSqrt(actualMax - totalLength / entries.length); + const biasedMax = MathMax(actualMax - 3 - averageBias, 1); + // Dynamically check how many columns seem possible. + const columns = MathMin( + // Ideally a square should be drawn. We expect a character to be about 2.5 + // times as high as wide. This is the area formula to calculate a square + // which contains n rectangles of size `actualMax * approxCharHeights`. + // Divide that by `actualMax` to receive the correct number of columns. + // The added bias increases the columns for short entries. + MathRound( + MathSqrt(approxCharHeights * biasedMax * entriesLength) / biasedMax, + ), + // Do not exceed the breakLength. + MathFloor((LINE_BREAKING_LENGTH - (level + 1)) / actualMax), + // Limit the columns to a maximum of fifteen. + 15, + ); + // Return with the original output if no grouping should happen. + if (columns <= 1) { + return entries; + } + const tmp = []; + const maxLineLength = []; + for (let i = 0; i < columns; i++) { + let lineMaxLength = 0; + for (let j = i; j < entries.length; j += columns) { + if (dataLen[j] > lineMaxLength) lineMaxLength = dataLen[j]; } - let order = "padStart"; - if (value !== undefined) { - for (let i = 0; i < entries.length; i++) { - if ( - typeof value[i] !== "number" && - typeof value[i] !== "bigint" - ) { - order = "padEnd"; - break; - } + lineMaxLength += separatorSpace; + maxLineLength[i] = lineMaxLength; + } + let order = "padStart"; + if (value !== undefined) { + for (let i = 0; i < entries.length; i++) { + if ( + typeof value[i] !== "number" && + typeof value[i] !== "bigint" + ) { + order = "padEnd"; + break; } } - // Each iteration creates a single line of grouped entries. - for (let i = 0; i < entriesLength; i += columns) { - // The last lines may contain less entries than columns. - const max = MathMin(i + columns, entriesLength); - let str = ""; - let j = i; - for (; j < max - 1; j++) { - const lengthOfColorCodes = entries[j].length - dataLen[j]; - const padding = maxLineLength[j - i] + lengthOfColorCodes; - str += `${entries[j]}, `[order](padding, " "); - } - if (order === "padStart") { - const lengthOfColorCodes = entries[j].length - dataLen[j]; - const padding = maxLineLength[j - i] + - lengthOfColorCodes - - separatorSpace; - str += StringPrototypePadStart(entries[j], padding, " "); - } else { - str += entries[j]; - } - ArrayPrototypePush(tmp, str); + } + // Each iteration creates a single line of grouped entries. + for (let i = 0; i < entriesLength; i += columns) { + // The last lines may contain less entries than columns. + const max = MathMin(i + columns, entriesLength); + let str = ""; + let j = i; + for (; j < max - 1; j++) { + const lengthOfColorCodes = entries[j].length - dataLen[j]; + const padding = maxLineLength[j - i] + lengthOfColorCodes; + str += `${entries[j]}, `[order](padding, " "); } - if (iterableLimit < entries.length) { - ArrayPrototypePush(tmp, entries[entriesLength]); + if (order === "padStart") { + const lengthOfColorCodes = entries[j].length - dataLen[j]; + const padding = maxLineLength[j - i] + + lengthOfColorCodes - + separatorSpace; + str += StringPrototypePadStart(entries[j], padding, " "); + } else { + str += entries[j]; } - entries = tmp; + ArrayPrototypePush(tmp, str); + } + if (iterableLimit < entries.length) { + ArrayPrototypePush(tmp, entries[entriesLength]); } - return entries; + entries = tmp; } - - let circular; - function handleCircular(value, cyan) { - let index = 1; - if (circular === undefined) { - circular = new Map(); + return entries; +} + +let circular; +function handleCircular(value, cyan) { + let index = 1; + if (circular === undefined) { + circular = new Map(); + MapPrototypeSet(circular, value, index); + } else { + index = MapPrototypeGet(circular, value); + if (index === undefined) { + index = circular.size + 1; MapPrototypeSet(circular, value, index); - } else { - index = MapPrototypeGet(circular, value); - if (index === undefined) { - index = circular.size + 1; - MapPrototypeSet(circular, value, index); - } } - // Circular string is cyan - return cyan(`[Circular *${index}]`); + } + // Circular string is cyan + return cyan(`[Circular *${index}]`); +} + +function _inspectValue( + value, + inspectOptions, +) { + const proxyDetails = core.getProxyDetails(value); + if (proxyDetails != null && inspectOptions.showProxy) { + return inspectProxy(proxyDetails, inspectOptions); } - function _inspectValue( - value, - inspectOptions, - ) { - const proxyDetails = core.getProxyDetails(value); - if (proxyDetails != null && inspectOptions.showProxy) { - return inspectProxy(proxyDetails, inspectOptions); - } - - const green = maybeColor(colors.green, inspectOptions); - const yellow = maybeColor(colors.yellow, inspectOptions); - const gray = maybeColor(colors.gray, inspectOptions); - const cyan = maybeColor(colors.cyan, inspectOptions); - const bold = maybeColor(colors.bold, inspectOptions); - const red = maybeColor(colors.red, inspectOptions); - - switch (typeof value) { - case "string": - return green(quoteString(value)); - case "number": // Numbers are yellow - // Special handling of -0 - return yellow(ObjectIs(value, -0) ? "-0" : `${value}`); - case "boolean": // booleans are yellow - return yellow(String(value)); - case "undefined": // undefined is gray - return gray(String(value)); - case "symbol": // Symbols are green - return green(maybeQuoteSymbol(value)); - case "bigint": // Bigints are yellow - return yellow(`${value}n`); - case "function": // Function string is cyan - if (ctxHas(value)) { - // Circular string is cyan - return handleCircular(value, cyan); - } + const green = maybeColor(colors.green, inspectOptions); + const yellow = maybeColor(colors.yellow, inspectOptions); + const gray = maybeColor(colors.gray, inspectOptions); + const cyan = maybeColor(colors.cyan, inspectOptions); + const bold = maybeColor(colors.bold, inspectOptions); + const red = maybeColor(colors.red, inspectOptions); + + switch (typeof value) { + case "string": + return green(quoteString(value)); + case "number": // Numbers are yellow + // Special handling of -0 + return yellow(ObjectIs(value, -0) ? "-0" : `${value}`); + case "boolean": // booleans are yellow + return yellow(String(value)); + case "undefined": // undefined is gray + return gray(String(value)); + case "symbol": // Symbols are green + return green(maybeQuoteSymbol(value)); + case "bigint": // Bigints are yellow + return yellow(`${value}n`); + case "function": // Function string is cyan + if (ctxHas(value)) { + // Circular string is cyan + return handleCircular(value, cyan); + } - return inspectFunction(value, inspectOptions); - case "object": // null is bold - if (value === null) { - return bold("null"); - } + return inspectFunction(value, inspectOptions); + case "object": // null is bold + if (value === null) { + return bold("null"); + } - if (ctxHas(value)) { - return handleCircular(value, cyan); - } + if (ctxHas(value)) { + return handleCircular(value, cyan); + } - return inspectObject( - value, - inspectOptions, - proxyDetails, - ); - default: - // Not implemented is red - return red("[Not Implemented]"); - } + return inspectObject( + value, + inspectOptions, + proxyDetails, + ); + default: + // Not implemented is red + return red("[Not Implemented]"); } - - function inspectValue( - value, - inspectOptions, - ) { - ArrayPrototypePush(CTX_STACK, value); - let x; - try { - x = _inspectValue(value, inspectOptions); - } finally { - ArrayPrototypePop(CTX_STACK); - } - 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. - * - * The quote symbol is chosen by taking the first of the `QUOTES` array which - * does not occur in the string. If they all occur, settle with `QUOTES[0]`. - * - * Insert a backslash before any occurrence of the chosen quote symbol and - * before any backslash. - */ - function quoteString(string) { - const quote = - ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ?? - QUOTES[0]; - const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g"); - string = StringPrototypeReplace(string, escapePattern, "\\"); - string = replaceEscapeSequences(string); - return `${quote}${string}${quote}`; - } - - // Replace escape sequences that can modify output. - function replaceEscapeSequences(string) { - const escapeMap = { - "\b": "\\b", - "\f": "\\f", - "\n": "\\n", - "\r": "\\r", - "\t": "\\t", - "\v": "\\v", - }; - - return StringPrototypeReplace( - StringPrototypeReplace( - string, - /([\b\f\n\r\t\v])/g, - (c) => escapeMap[c], - ), - // deno-lint-ignore no-control-regex - /[\x00-\x1f\x7f-\x9f]/g, - (c) => - "\\x" + - StringPrototypePadStart( - NumberPrototypeToString(StringPrototypeCharCodeAt(c, 0), 16), - 2, - "0", - ), - ); +} + +function inspectValue( + value, + inspectOptions, +) { + ArrayPrototypePush(CTX_STACK, value); + let x; + try { + x = _inspectValue(value, inspectOptions); + } finally { + ArrayPrototypePop(CTX_STACK); } + 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. + * + * The quote symbol is chosen by taking the first of the `QUOTES` array which + * does not occur in the string. If they all occur, settle with `QUOTES[0]`. + * + * Insert a backslash before any occurrence of the chosen quote symbol and + * before any backslash. + */ +function quoteString(string) { + const quote = + ArrayPrototypeFind(QUOTES, (c) => !StringPrototypeIncludes(string, c)) ?? + QUOTES[0]; + const escapePattern = new RegExp(`(?=[${quote}\\\\])`, "g"); + string = StringPrototypeReplace(string, escapePattern, "\\"); + string = replaceEscapeSequences(string); + return `${quote}${string}${quote}`; +} + +// Replace escape sequences that can modify output. +function replaceEscapeSequences(string) { + const escapeMap = { + "\b": "\\b", + "\f": "\\f", + "\n": "\\n", + "\r": "\\r", + "\t": "\\t", + "\v": "\\v", + }; - // Surround a string with quotes when it is required (e.g the string not a valid identifier). - function maybeQuoteString(string) { - if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_0-9]*$/, string)) { - return replaceEscapeSequences(string); - } + return StringPrototypeReplace( + StringPrototypeReplace( + string, + /([\b\f\n\r\t\v])/g, + (c) => escapeMap[c], + ), + // deno-lint-ignore no-control-regex + /[\x00-\x1f\x7f-\x9f]/g, + (c) => + "\\x" + + StringPrototypePadStart( + NumberPrototypeToString(StringPrototypeCharCodeAt(c, 0), 16), + 2, + "0", + ), + ); +} - return quoteString(string); +// Surround a string with quotes when it is required (e.g the string not a valid identifier). +function maybeQuoteString(string) { + if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_0-9]*$/, string)) { + return replaceEscapeSequences(string); } - // Surround a symbol's description in quotes when it is required (e.g the description has non printable characters). - function maybeQuoteSymbol(symbol) { - if (symbol.description === undefined) { - return SymbolPrototypeToString(symbol); - } - - if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_.0-9]*$/, symbol.description)) { - return SymbolPrototypeToString(symbol); - } + return quoteString(string); +} - return `Symbol(${quoteString(symbol.description)})`; +// Surround a symbol's description in quotes when it is required (e.g the description has non printable characters). +function maybeQuoteSymbol(symbol) { + if (symbol.description === undefined) { + return SymbolPrototypeToString(symbol); } - const CTX_STACK = []; - function ctxHas(x) { - // Only check parent contexts - return ArrayPrototypeIncludes( - ArrayPrototypeSlice(CTX_STACK, 0, CTX_STACK.length - 1), - x, - ); + if (RegExpPrototypeTest(/^[a-zA-Z_][a-zA-Z_.0-9]*$/, symbol.description)) { + return SymbolPrototypeToString(symbol); } - // Print strings when they are inside of arrays or objects with quotes - function inspectValueWithQuotes( - value, - inspectOptions, - ) { - const abbreviateSize = - typeof inspectOptions.strAbbreviateSize === "undefined" - ? STR_ABBREVIATE_SIZE - : inspectOptions.strAbbreviateSize; - const green = maybeColor(colors.green, inspectOptions); - switch (typeof value) { - case "string": { - const trunc = value.length > abbreviateSize - ? StringPrototypeSlice(value, 0, abbreviateSize) + "..." - : value; - return green(quoteString(trunc)); // Quoted strings are green - } - default: - return inspectValue(value, inspectOptions); - } + return `Symbol(${quoteString(symbol.description)})`; +} + +const CTX_STACK = []; +function ctxHas(x) { + // Only check parent contexts + return ArrayPrototypeIncludes( + ArrayPrototypeSlice(CTX_STACK, 0, CTX_STACK.length - 1), + x, + ); +} + +// Print strings when they are inside of arrays or objects with quotes +function inspectValueWithQuotes( + value, + inspectOptions, +) { + const abbreviateSize = typeof inspectOptions.strAbbreviateSize === "undefined" + ? STR_ABBREVIATE_SIZE + : inspectOptions.strAbbreviateSize; + const green = maybeColor(colors.green, inspectOptions); + switch (typeof value) { + case "string": { + const trunc = value.length > abbreviateSize + ? StringPrototypeSlice(value, 0, abbreviateSize) + "..." + : value; + return green(quoteString(trunc)); // Quoted strings are green + } + default: + return inspectValue(value, inspectOptions); } - - function inspectArray( - value, - inspectOptions, - ) { - const gray = maybeColor(colors.gray, inspectOptions); - let lastValidIndex = 0; - let keys; - const options = { - typeName: "Array", - displayName: "", - delims: ["[", "]"], - entryHandler: (entry, inspectOptions) => { - const { 0: index, 1: val } = entry; - let i = index; - lastValidIndex = index; - if (!ObjectPrototypeHasOwnProperty(value, i)) { - let skipTo; - keys = keys || ObjectKeys(value); - i = value.length; - if (keys.length === 0) { - // fast path, all items are empty - skipTo = i; - } else { - // Not all indexes are empty or there's a non-index property - // Find first non-empty array index - while (keys.length) { - const key = ArrayPrototypeShift(keys); - // check if it's a valid array index - if (key > lastValidIndex && key < 2 ** 32 - 1) { - i = Number(key); - break; - } +} + +function inspectArray( + value, + inspectOptions, +) { + const gray = maybeColor(colors.gray, inspectOptions); + let lastValidIndex = 0; + let keys; + const options = { + typeName: "Array", + displayName: "", + delims: ["[", "]"], + entryHandler: (entry, inspectOptions) => { + const { 0: index, 1: val } = entry; + let i = index; + lastValidIndex = index; + if (!ObjectPrototypeHasOwnProperty(value, i)) { + let skipTo; + keys = keys || ObjectKeys(value); + i = value.length; + if (keys.length === 0) { + // fast path, all items are empty + skipTo = i; + } else { + // Not all indexes are empty or there's a non-index property + // Find first non-empty array index + while (keys.length) { + const key = ArrayPrototypeShift(keys); + // check if it's a valid array index + if (key > lastValidIndex && key < 2 ** 32 - 1) { + i = Number(key); + break; } - - skipTo = i - 1; } - const emptyItems = i - index; - const ending = emptyItems > 1 ? "s" : ""; - return { - entry: gray(`<${emptyItems} empty item${ending}>`), - skipTo, - }; - } else { - return { entry: inspectValueWithQuotes(val, inspectOptions) }; - } - }, - group: inspectOptions.compact, - sort: false, - }; - return inspectIterable(value, options, inspectOptions); - } - function inspectTypedArray( - typedArrayName, - value, - inspectOptions, - ) { - const valueLength = value.length; - const options = { - typeName: typedArrayName, - displayName: `${typedArrayName}(${valueLength})`, - delims: ["[", "]"], - entryHandler: (entry, inspectOptions) => { - const val = entry[1]; - inspectOptions.indentLevel++; - const inspectedValue = inspectValueWithQuotes(val, inspectOptions); - inspectOptions.indentLevel--; - return inspectedValue; - }, - group: inspectOptions.compact, - sort: false, - }; - return inspectIterable(value, options, inspectOptions); - } - - function inspectSet( - value, - inspectOptions, - ) { - const options = { - typeName: "Set", - displayName: "Set", - delims: ["{", "}"], - entryHandler: (entry, inspectOptions) => { - const val = entry[1]; - inspectOptions.indentLevel++; - const inspectedValue = inspectValueWithQuotes(val, inspectOptions); - inspectOptions.indentLevel--; - return inspectedValue; - }, - group: false, - sort: inspectOptions.sorted, - }; - return inspectIterable(value, options, inspectOptions); - } - - function inspectMap( + skipTo = i - 1; + } + const emptyItems = i - index; + const ending = emptyItems > 1 ? "s" : ""; + return { + entry: gray(`<${emptyItems} empty item${ending}>`), + skipTo, + }; + } else { + return { entry: inspectValueWithQuotes(val, inspectOptions) }; + } + }, + group: inspectOptions.compact, + sort: false, + }; + return inspectIterable(value, options, inspectOptions); +} + +function inspectTypedArray( + typedArrayName, + value, + inspectOptions, +) { + const valueLength = value.length; + const options = { + typeName: typedArrayName, + displayName: `${typedArrayName}(${valueLength})`, + delims: ["[", "]"], + entryHandler: (entry, inspectOptions) => { + const val = entry[1]; + inspectOptions.indentLevel++; + const inspectedValue = inspectValueWithQuotes(val, inspectOptions); + inspectOptions.indentLevel--; + return inspectedValue; + }, + group: inspectOptions.compact, + sort: false, + }; + return inspectIterable(value, options, inspectOptions); +} + +function inspectSet( + value, + inspectOptions, +) { + const options = { + typeName: "Set", + displayName: "Set", + delims: ["{", "}"], + entryHandler: (entry, inspectOptions) => { + const val = entry[1]; + inspectOptions.indentLevel++; + const inspectedValue = inspectValueWithQuotes(val, inspectOptions); + inspectOptions.indentLevel--; + return inspectedValue; + }, + group: false, + sort: inspectOptions.sorted, + }; + return inspectIterable(value, options, inspectOptions); +} + +function inspectMap( + value, + inspectOptions, +) { + const options = { + typeName: "Map", + displayName: "Map", + delims: ["{", "}"], + entryHandler: (entry, inspectOptions) => { + const { 0: key, 1: val } = entry; + inspectOptions.indentLevel++; + const inspectedValue = `${ + inspectValueWithQuotes(key, inspectOptions) + } => ${inspectValueWithQuotes(val, inspectOptions)}`; + inspectOptions.indentLevel--; + return inspectedValue; + }, + group: false, + sort: inspectOptions.sorted, + }; + return inspectIterable( value, + options, inspectOptions, - ) { - const options = { - typeName: "Map", - displayName: "Map", - delims: ["{", "}"], - entryHandler: (entry, inspectOptions) => { - const { 0: key, 1: val } = entry; - inspectOptions.indentLevel++; - const inspectedValue = `${ - inspectValueWithQuotes(key, inspectOptions) - } => ${inspectValueWithQuotes(val, inspectOptions)}`; - inspectOptions.indentLevel--; - return inspectedValue; - }, - group: false, - sort: inspectOptions.sorted, - }; - return inspectIterable( - value, - options, - inspectOptions, - ); - } - - function inspectWeakSet(inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color - } - - function inspectWeakMap(inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color - } - - function inspectDate(value, inspectOptions) { - // without quotes, ISO format, in magenta like before - const magenta = maybeColor(colors.magenta, inspectOptions); - return magenta( - isInvalidDate(value) ? "Invalid Date" : DatePrototypeToISOString(value), - ); + ); +} + +function inspectWeakSet(inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return `WeakSet { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color +} + +function inspectWeakMap(inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return `WeakMap { ${cyan("[items unknown]")} }`; // as seen in Node, with cyan color +} + +function inspectDate(value, inspectOptions) { + // without quotes, ISO format, in magenta like before + const magenta = maybeColor(colors.magenta, inspectOptions); + return magenta( + isInvalidDate(value) ? "Invalid Date" : DatePrototypeToISOString(value), + ); +} + +function inspectRegExp(value, inspectOptions) { + const red = maybeColor(colors.red, inspectOptions); + return red(RegExpPrototypeToString(value)); // RegExps are red +} + +function inspectError(value, cyan) { + const causes = [value]; + + let err = value; + while (err.cause) { + if (ArrayPrototypeIncludes(causes, err.cause)) { + ArrayPrototypePush(causes, handleCircular(err.cause, cyan)); + break; + } else { + ArrayPrototypePush(causes, err.cause); + err = err.cause; + } } - function inspectRegExp(value, inspectOptions) { - const red = maybeColor(colors.red, inspectOptions); - return red(RegExpPrototypeToString(value)); // RegExps are red + const refMap = new Map(); + for (let i = 0; i < causes.length; ++i) { + const cause = causes[i]; + if (circular !== undefined) { + const index = MapPrototypeGet(circular, cause); + if (index !== undefined) { + MapPrototypeSet(refMap, cause, cyan(`<ref *${index}> `)); + } + } } + ArrayPrototypeShift(causes); - function inspectError(value, cyan) { - const causes = [value]; + let finalMessage = MapPrototypeGet(refMap, value) ?? ""; - let err = value; - while (err.cause) { - if (ArrayPrototypeIncludes(causes, err.cause)) { - ArrayPrototypePush(causes, handleCircular(err.cause, cyan)); + if (ObjectPrototypeIsPrototypeOf(AggregateErrorPrototype, value)) { + const stackLines = StringPrototypeSplit(value.stack, "\n"); + while (true) { + const line = ArrayPrototypeShift(stackLines); + if (RegExpPrototypeTest(/\s+at/, line)) { + ArrayPrototypeUnshift(stackLines, line); + break; + } else if (typeof line === "undefined") { break; - } else { - ArrayPrototypePush(causes, err.cause); - err = err.cause; - } - } - - const refMap = new Map(); - for (let i = 0; i < causes.length; ++i) { - const cause = causes[i]; - if (circular !== undefined) { - const index = MapPrototypeGet(circular, cause); - if (index !== undefined) { - MapPrototypeSet(refMap, cause, cyan(`<ref *${index}> `)); - } } - } - ArrayPrototypeShift(causes); - - let finalMessage = MapPrototypeGet(refMap, value) ?? ""; - - if (ObjectPrototypeIsPrototypeOf(AggregateErrorPrototype, value)) { - const stackLines = StringPrototypeSplit(value.stack, "\n"); - while (true) { - const line = ArrayPrototypeShift(stackLines); - if (RegExpPrototypeTest(/\s+at/, line)) { - ArrayPrototypeUnshift(stackLines, line); - break; - } else if (typeof line === "undefined") { - break; - } - finalMessage += line; - finalMessage += "\n"; - } - const aggregateMessage = ArrayPrototypeJoin( - ArrayPrototypeMap( - value.errors, - (error) => - StringPrototypeReplace( - inspectArgs([error]), - /^(?!\s*$)/gm, - StringPrototypeRepeat(" ", 4), - ), - ), - "\n", - ); - finalMessage += aggregateMessage; + finalMessage += line; finalMessage += "\n"; - finalMessage += ArrayPrototypeJoin(stackLines, "\n"); - } else { - finalMessage += value.stack; } - - finalMessage += ArrayPrototypeJoin( + const aggregateMessage = ArrayPrototypeJoin( ArrayPrototypeMap( - causes, - (cause) => - "\nCaused by " + (MapPrototypeGet(refMap, cause) ?? "") + - (cause?.stack ?? cause), + value.errors, + (error) => + StringPrototypeReplace( + inspectArgs([error]), + /^(?!\s*$)/gm, + StringPrototypeRepeat(" ", 4), + ), ), - "", + "\n", ); - - return finalMessage; + finalMessage += aggregateMessage; + finalMessage += "\n"; + finalMessage += ArrayPrototypeJoin(stackLines, "\n"); + } else { + finalMessage += value.stack; } - function inspectStringObject(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return cyan(`[String: "${StringPrototypeToString(value)}"]`); // wrappers are in cyan + finalMessage += ArrayPrototypeJoin( + ArrayPrototypeMap( + causes, + (cause) => + "\nCaused by " + (MapPrototypeGet(refMap, cause) ?? "") + + (cause?.stack ?? cause), + ), + "", + ); + + return finalMessage; +} + +function inspectStringObject(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return cyan(`[String: "${StringPrototypeToString(value)}"]`); // wrappers are in cyan +} + +function inspectBooleanObject(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return cyan(`[Boolean: ${BooleanPrototypeToString(value)}]`); // wrappers are in cyan +} + +function inspectNumberObject(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + // Special handling of -0 + return cyan( + `[Number: ${ + ObjectIs(NumberPrototypeValueOf(value), -0) + ? "-0" + : NumberPrototypeToString(value) + }]`, + ); // wrappers are in cyan +} + +function inspectBigIntObject(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return cyan(`[BigInt: ${BigIntPrototypeToString(value)}n]`); // wrappers are in cyan +} + +function inspectSymbolObject(value, inspectOptions) { + const cyan = maybeColor(colors.cyan, inspectOptions); + return cyan(`[Symbol: ${maybeQuoteSymbol(SymbolPrototypeValueOf(value))}]`); // wrappers are in cyan +} + +const PromiseState = { + Pending: 0, + Fulfilled: 1, + Rejected: 2, +}; + +function inspectPromise( + value, + inspectOptions, +) { + const cyan = maybeColor(colors.cyan, inspectOptions); + const red = maybeColor(colors.red, inspectOptions); + + const { 0: state, 1: result } = core.getPromiseDetails(value); + + if (state === PromiseState.Pending) { + return `Promise { ${cyan("<pending>")} }`; } - function inspectBooleanObject(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return cyan(`[Boolean: ${BooleanPrototypeToString(value)}]`); // wrappers are in cyan - } + const prefix = state === PromiseState.Fulfilled + ? "" + : `${red("<rejected>")} `; - function inspectNumberObject(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - // Special handling of -0 - return cyan( - `[Number: ${ - ObjectIs(NumberPrototypeValueOf(value), -0) - ? "-0" - : NumberPrototypeToString(value) - }]`, - ); // wrappers are in cyan - } + inspectOptions.indentLevel++; + const str = `${prefix}${inspectValueWithQuotes(result, inspectOptions)}`; + inspectOptions.indentLevel--; - function inspectBigIntObject(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return cyan(`[BigInt: ${BigIntPrototypeToString(value)}n]`); // wrappers are in cyan + if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) { + return `Promise {\n${ + StringPrototypeRepeat(DEFAULT_INDENT, inspectOptions.indentLevel + 1) + }${str}\n}`; } - function inspectSymbolObject(value, inspectOptions) { - const cyan = maybeColor(colors.cyan, inspectOptions); - return cyan(`[Symbol: ${maybeQuoteSymbol(SymbolPrototypeValueOf(value))}]`); // wrappers are in cyan - } + return `Promise { ${str} }`; +} - const PromiseState = { - Pending: 0, - Fulfilled: 1, - Rejected: 2, - }; - - function inspectPromise( - value, - inspectOptions, - ) { - const cyan = maybeColor(colors.cyan, inspectOptions); - const red = maybeColor(colors.red, inspectOptions); +function inspectProxy( + targetAndHandler, + inspectOptions, +) { + return `Proxy ${inspectArray(targetAndHandler, inspectOptions)}`; +} - const { 0: state, 1: result } = core.getPromiseDetails(value); - - if (state === PromiseState.Pending) { - return `Promise { ${cyan("<pending>")} }`; - } - - const prefix = state === PromiseState.Fulfilled - ? "" - : `${red("<rejected>")} `; +function inspectRawObject( + value, + inspectOptions, +) { + const cyan = maybeColor(colors.cyan, inspectOptions); - inspectOptions.indentLevel++; - const str = `${prefix}${inspectValueWithQuotes(result, inspectOptions)}`; - inspectOptions.indentLevel--; + if (inspectOptions.indentLevel >= inspectOptions.depth) { + return [cyan("[Object]"), ""]; // wrappers are in cyan + } - if (str.length + PROMISE_STRING_BASE_LENGTH > LINE_BREAKING_LENGTH) { - return `Promise {\n${ - StringPrototypeRepeat(DEFAULT_INDENT, inspectOptions.indentLevel + 1) - }${str}\n}`; - } + let baseString; - return `Promise { ${str} }`; + let shouldShowDisplayName = false; + let displayName = value[ + SymbolToStringTag + ]; + if (!displayName) { + displayName = getClassInstanceName(value); } - - function inspectProxy( - targetAndHandler, - inspectOptions, + if ( + displayName && displayName !== "Object" && displayName !== "anonymous" ) { - return `Proxy ${inspectArray(targetAndHandler, inspectOptions)}`; + shouldShowDisplayName = true; } - function inspectRawObject( - value, - inspectOptions, - ) { - const cyan = maybeColor(colors.cyan, inspectOptions); - - if (inspectOptions.indentLevel >= inspectOptions.depth) { - return [cyan("[Object]"), ""]; // wrappers are in cyan - } + const entries = []; + const stringKeys = ObjectKeys(value); + const symbolKeys = ObjectGetOwnPropertySymbols(value); + if (inspectOptions.sorted) { + ArrayPrototypeSort(stringKeys); + ArrayPrototypeSort( + symbolKeys, + (s1, s2) => + StringPrototypeLocaleCompare( + s1.description ?? "", + s2.description ?? "", + ), + ); + } - let baseString; + const red = maybeColor(colors.red, inspectOptions); - let shouldShowDisplayName = false; - let displayName = value[ - SymbolToStringTag - ]; - if (!displayName) { - displayName = getClassInstanceName(value); - } - if ( - displayName && displayName !== "Object" && displayName !== "anonymous" - ) { - shouldShowDisplayName = true; - } + inspectOptions.indentLevel++; - const entries = []; - const stringKeys = ObjectKeys(value); - const symbolKeys = ObjectGetOwnPropertySymbols(value); - if (inspectOptions.sorted) { - ArrayPrototypeSort(stringKeys); - ArrayPrototypeSort( - symbolKeys, - (s1, s2) => - StringPrototypeLocaleCompare( - s1.description ?? "", - s2.description ?? "", - ), + for (let i = 0; i < stringKeys.length; ++i) { + const key = stringKeys[i]; + if (inspectOptions.getters) { + let propertyValue; + let error = null; + try { + propertyValue = value[key]; + } catch (error_) { + error = error_; + } + const inspectedValue = error == null + ? inspectValueWithQuotes(propertyValue, inspectOptions) + : red(`[Thrown ${error.name}: ${error.message}]`); + ArrayPrototypePush( + entries, + `${maybeQuoteString(key)}: ${inspectedValue}`, ); - } - - const red = maybeColor(colors.red, inspectOptions); - - inspectOptions.indentLevel++; - - for (let i = 0; i < stringKeys.length; ++i) { - const key = stringKeys[i]; - if (inspectOptions.getters) { - let propertyValue; - let error = null; - try { - propertyValue = value[key]; - } catch (error_) { - error = error_; - } - const inspectedValue = error == null - ? inspectValueWithQuotes(propertyValue, inspectOptions) - : red(`[Thrown ${error.name}: ${error.message}]`); + } else { + const descriptor = ObjectGetOwnPropertyDescriptor(value, key); + if (descriptor.get !== undefined && descriptor.set !== undefined) { ArrayPrototypePush( entries, - `${maybeQuoteString(key)}: ${inspectedValue}`, + `${maybeQuoteString(key)}: [Getter/Setter]`, ); + } else if (descriptor.get !== undefined) { + ArrayPrototypePush(entries, `${maybeQuoteString(key)}: [Getter]`); } else { - const descriptor = ObjectGetOwnPropertyDescriptor(value, key); - if (descriptor.get !== undefined && descriptor.set !== undefined) { - ArrayPrototypePush( - entries, - `${maybeQuoteString(key)}: [Getter/Setter]`, - ); - } else if (descriptor.get !== undefined) { - ArrayPrototypePush(entries, `${maybeQuoteString(key)}: [Getter]`); - } else { - ArrayPrototypePush( - entries, - `${maybeQuoteString(key)}: ${ - inspectValueWithQuotes(value[key], inspectOptions) - }`, - ); - } + ArrayPrototypePush( + entries, + `${maybeQuoteString(key)}: ${ + inspectValueWithQuotes(value[key], inspectOptions) + }`, + ); } } + } - for (let i = 0; i < symbolKeys.length; ++i) { - const key = symbolKeys[i]; - if ( - !inspectOptions.showHidden && - !propertyIsEnumerable(value, key) - ) { - continue; - } + for (let i = 0; i < symbolKeys.length; ++i) { + const key = symbolKeys[i]; + if ( + !inspectOptions.showHidden && + !propertyIsEnumerable(value, key) + ) { + continue; + } - if (inspectOptions.getters) { - let propertyValue; - let error; - try { - propertyValue = value[key]; - } catch (error_) { - error = error_; - } - const inspectedValue = error == null - ? inspectValueWithQuotes(propertyValue, inspectOptions) - : red(`Thrown ${error.name}: ${error.message}`); + if (inspectOptions.getters) { + let propertyValue; + let error; + try { + propertyValue = value[key]; + } catch (error_) { + error = error_; + } + const inspectedValue = error == null + ? inspectValueWithQuotes(propertyValue, inspectOptions) + : red(`Thrown ${error.name}: ${error.message}`); + ArrayPrototypePush( + entries, + `[${maybeQuoteSymbol(key)}]: ${inspectedValue}`, + ); + } else { + const descriptor = ObjectGetOwnPropertyDescriptor(value, key); + if (descriptor.get !== undefined && descriptor.set !== undefined) { ArrayPrototypePush( entries, - `[${maybeQuoteSymbol(key)}]: ${inspectedValue}`, + `[${maybeQuoteSymbol(key)}]: [Getter/Setter]`, ); + } else if (descriptor.get !== undefined) { + ArrayPrototypePush(entries, `[${maybeQuoteSymbol(key)}]: [Getter]`); } else { - const descriptor = ObjectGetOwnPropertyDescriptor(value, key); - if (descriptor.get !== undefined && descriptor.set !== undefined) { - ArrayPrototypePush( - entries, - `[${maybeQuoteSymbol(key)}]: [Getter/Setter]`, - ); - } else if (descriptor.get !== undefined) { - ArrayPrototypePush(entries, `[${maybeQuoteSymbol(key)}]: [Getter]`); - } else { - ArrayPrototypePush( - entries, - `[${maybeQuoteSymbol(key)}]: ${ - inspectValueWithQuotes(value[key], inspectOptions) - }`, - ); - } + ArrayPrototypePush( + entries, + `[${maybeQuoteSymbol(key)}]: ${ + inspectValueWithQuotes(value[key], inspectOptions) + }`, + ); } } + } - inspectOptions.indentLevel--; + inspectOptions.indentLevel--; - // Making sure color codes are ignored when calculating the total length - const totalLength = entries.length + inspectOptions.indentLevel + - colors.stripColor(ArrayPrototypeJoin(entries, "")).length; + // Making sure color codes are ignored when calculating the total length + const totalLength = entries.length + inspectOptions.indentLevel + + colors.stripColor(ArrayPrototypeJoin(entries, "")).length; - if (entries.length === 0) { - baseString = "{}"; - } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) { - const entryIndent = StringPrototypeRepeat( - DEFAULT_INDENT, - inspectOptions.indentLevel + 1, - ); - const closingIndent = StringPrototypeRepeat( - DEFAULT_INDENT, - inspectOptions.indentLevel, - ); - baseString = `{\n${entryIndent}${ - ArrayPrototypeJoin(entries, `,\n${entryIndent}`) - }${inspectOptions.trailingComma ? "," : ""}\n${closingIndent}}`; - } else { - baseString = `{ ${ArrayPrototypeJoin(entries, ", ")} }`; - } + if (entries.length === 0) { + baseString = "{}"; + } else if (totalLength > LINE_BREAKING_LENGTH || !inspectOptions.compact) { + const entryIndent = StringPrototypeRepeat( + DEFAULT_INDENT, + inspectOptions.indentLevel + 1, + ); + const closingIndent = StringPrototypeRepeat( + DEFAULT_INDENT, + inspectOptions.indentLevel, + ); + baseString = `{\n${entryIndent}${ + ArrayPrototypeJoin(entries, `,\n${entryIndent}`) + }${inspectOptions.trailingComma ? "," : ""}\n${closingIndent}}`; + } else { + baseString = `{ ${ArrayPrototypeJoin(entries, ", ")} }`; + } - if (shouldShowDisplayName) { - baseString = `${displayName} ${baseString}`; - } + if (shouldShowDisplayName) { + baseString = `${displayName} ${baseString}`; + } - let refIndex = ""; - if (circular !== undefined) { - const index = MapPrototypeGet(circular, value); - if (index !== undefined) { - refIndex = cyan(`<ref *${index}> `); - } + let refIndex = ""; + if (circular !== undefined) { + const index = MapPrototypeGet(circular, value); + if (index !== undefined) { + refIndex = cyan(`<ref *${index}> `); } - - return [baseString, refIndex]; } - function inspectObject(value, inspectOptions, proxyDetails) { - if ( - ReflectHas(value, customInspect) && - typeof value[customInspect] === "function" - ) { - return String(value[customInspect](inspect, inspectOptions)); - } - // This non-unique symbol is used to support op_crates, ie. - // in extensions/web we don't want to depend on public - // Symbol.for("Deno.customInspect") symbol defined in the public API. - // Internal only, shouldn't be used by users. - const privateCustomInspect = SymbolFor("Deno.privateCustomInspect"); - if ( - ReflectHas(value, privateCustomInspect) && - typeof value[privateCustomInspect] === "function" - ) { - // TODO(nayeemrmn): `inspect` is passed as an argument because custom - // inspect implementations in `extensions` need it, but may not have access - // to the `Deno` namespace in web workers. Remove when the `Deno` - // namespace is always enabled. - return String( - value[privateCustomInspect](inspect, inspectOptions), - ); - } - if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, value)) { - return inspectError(value, maybeColor(colors.cyan, inspectOptions)); - } else if (ArrayIsArray(value)) { - return inspectArray(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(NumberPrototype, value)) { - return inspectNumberObject(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(BigIntPrototype, value)) { - return inspectBigIntObject(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(BooleanPrototype, value)) { - return inspectBooleanObject(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(StringPrototype, value)) { - return inspectStringObject(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(SymbolPrototype, value)) { - return inspectSymbolObject(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(PromisePrototype, value)) { - return inspectPromise(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(RegExpPrototype, value)) { - return inspectRegExp(value, inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(DatePrototype, value)) { - return inspectDate( - proxyDetails ? proxyDetails[0] : value, - inspectOptions, - ); - } else if (ObjectPrototypeIsPrototypeOf(SetPrototype, value)) { - return inspectSet( - proxyDetails ? proxyDetails[0] : value, - inspectOptions, - ); - } else if (ObjectPrototypeIsPrototypeOf(MapPrototype, value)) { - return inspectMap( - proxyDetails ? proxyDetails[0] : value, - inspectOptions, - ); - } else if (ObjectPrototypeIsPrototypeOf(WeakSetPrototype, value)) { - return inspectWeakSet(inspectOptions); - } else if (ObjectPrototypeIsPrototypeOf(WeakMapPrototype, value)) { - return inspectWeakMap(inspectOptions); - } else if (isTypedArray(value)) { - return inspectTypedArray( - ObjectGetPrototypeOf(value).constructor.name, - value, - inspectOptions, - ); + return [baseString, refIndex]; +} + +function inspectObject(value, inspectOptions, proxyDetails) { + if ( + ReflectHas(value, customInspect) && + typeof value[customInspect] === "function" + ) { + return String(value[customInspect](inspect, inspectOptions)); + } + // This non-unique symbol is used to support op_crates, ie. + // in extensions/web we don't want to depend on public + // Symbol.for("Deno.customInspect") symbol defined in the public API. + // Internal only, shouldn't be used by users. + const privateCustomInspect = SymbolFor("Deno.privateCustomInspect"); + if ( + ReflectHas(value, privateCustomInspect) && + typeof value[privateCustomInspect] === "function" + ) { + // TODO(nayeemrmn): `inspect` is passed as an argument because custom + // inspect implementations in `extensions` need it, but may not have access + // to the `Deno` namespace in web workers. Remove when the `Deno` + // namespace is always enabled. + return String( + value[privateCustomInspect](inspect, inspectOptions), + ); + } + if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, value)) { + return inspectError(value, maybeColor(colors.cyan, inspectOptions)); + } else if (ArrayIsArray(value)) { + return inspectArray(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(NumberPrototype, value)) { + return inspectNumberObject(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(BigIntPrototype, value)) { + return inspectBigIntObject(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(BooleanPrototype, value)) { + return inspectBooleanObject(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(StringPrototype, value)) { + return inspectStringObject(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(SymbolPrototype, value)) { + return inspectSymbolObject(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(PromisePrototype, value)) { + return inspectPromise(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(RegExpPrototype, value)) { + return inspectRegExp(value, inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(DatePrototype, value)) { + return inspectDate( + proxyDetails ? proxyDetails[0] : value, + inspectOptions, + ); + } else if (ObjectPrototypeIsPrototypeOf(SetPrototype, value)) { + return inspectSet( + proxyDetails ? proxyDetails[0] : value, + inspectOptions, + ); + } else if (ObjectPrototypeIsPrototypeOf(MapPrototype, value)) { + return inspectMap( + proxyDetails ? proxyDetails[0] : value, + inspectOptions, + ); + } else if (ObjectPrototypeIsPrototypeOf(WeakSetPrototype, value)) { + return inspectWeakSet(inspectOptions); + } else if (ObjectPrototypeIsPrototypeOf(WeakMapPrototype, value)) { + return inspectWeakMap(inspectOptions); + } else if (isTypedArray(value)) { + return inspectTypedArray( + ObjectGetPrototypeOf(value).constructor.name, + value, + inspectOptions, + ); + } else { + // Otherwise, default object formatting + let { 0: insp, 1: refIndex } = inspectRawObject(value, inspectOptions); + insp = refIndex + insp; + return insp; + } +} + +const colorKeywords = new Map([ + ["black", "#000000"], + ["silver", "#c0c0c0"], + ["gray", "#808080"], + ["white", "#ffffff"], + ["maroon", "#800000"], + ["red", "#ff0000"], + ["purple", "#800080"], + ["fuchsia", "#ff00ff"], + ["green", "#008000"], + ["lime", "#00ff00"], + ["olive", "#808000"], + ["yellow", "#ffff00"], + ["navy", "#000080"], + ["blue", "#0000ff"], + ["teal", "#008080"], + ["aqua", "#00ffff"], + ["orange", "#ffa500"], + ["aliceblue", "#f0f8ff"], + ["antiquewhite", "#faebd7"], + ["aquamarine", "#7fffd4"], + ["azure", "#f0ffff"], + ["beige", "#f5f5dc"], + ["bisque", "#ffe4c4"], + ["blanchedalmond", "#ffebcd"], + ["blueviolet", "#8a2be2"], + ["brown", "#a52a2a"], + ["burlywood", "#deb887"], + ["cadetblue", "#5f9ea0"], + ["chartreuse", "#7fff00"], + ["chocolate", "#d2691e"], + ["coral", "#ff7f50"], + ["cornflowerblue", "#6495ed"], + ["cornsilk", "#fff8dc"], + ["crimson", "#dc143c"], + ["cyan", "#00ffff"], + ["darkblue", "#00008b"], + ["darkcyan", "#008b8b"], + ["darkgoldenrod", "#b8860b"], + ["darkgray", "#a9a9a9"], + ["darkgreen", "#006400"], + ["darkgrey", "#a9a9a9"], + ["darkkhaki", "#bdb76b"], + ["darkmagenta", "#8b008b"], + ["darkolivegreen", "#556b2f"], + ["darkorange", "#ff8c00"], + ["darkorchid", "#9932cc"], + ["darkred", "#8b0000"], + ["darksalmon", "#e9967a"], + ["darkseagreen", "#8fbc8f"], + ["darkslateblue", "#483d8b"], + ["darkslategray", "#2f4f4f"], + ["darkslategrey", "#2f4f4f"], + ["darkturquoise", "#00ced1"], + ["darkviolet", "#9400d3"], + ["deeppink", "#ff1493"], + ["deepskyblue", "#00bfff"], + ["dimgray", "#696969"], + ["dimgrey", "#696969"], + ["dodgerblue", "#1e90ff"], + ["firebrick", "#b22222"], + ["floralwhite", "#fffaf0"], + ["forestgreen", "#228b22"], + ["gainsboro", "#dcdcdc"], + ["ghostwhite", "#f8f8ff"], + ["gold", "#ffd700"], + ["goldenrod", "#daa520"], + ["greenyellow", "#adff2f"], + ["grey", "#808080"], + ["honeydew", "#f0fff0"], + ["hotpink", "#ff69b4"], + ["indianred", "#cd5c5c"], + ["indigo", "#4b0082"], + ["ivory", "#fffff0"], + ["khaki", "#f0e68c"], + ["lavender", "#e6e6fa"], + ["lavenderblush", "#fff0f5"], + ["lawngreen", "#7cfc00"], + ["lemonchiffon", "#fffacd"], + ["lightblue", "#add8e6"], + ["lightcoral", "#f08080"], + ["lightcyan", "#e0ffff"], + ["lightgoldenrodyellow", "#fafad2"], + ["lightgray", "#d3d3d3"], + ["lightgreen", "#90ee90"], + ["lightgrey", "#d3d3d3"], + ["lightpink", "#ffb6c1"], + ["lightsalmon", "#ffa07a"], + ["lightseagreen", "#20b2aa"], + ["lightskyblue", "#87cefa"], + ["lightslategray", "#778899"], + ["lightslategrey", "#778899"], + ["lightsteelblue", "#b0c4de"], + ["lightyellow", "#ffffe0"], + ["limegreen", "#32cd32"], + ["linen", "#faf0e6"], + ["magenta", "#ff00ff"], + ["mediumaquamarine", "#66cdaa"], + ["mediumblue", "#0000cd"], + ["mediumorchid", "#ba55d3"], + ["mediumpurple", "#9370db"], + ["mediumseagreen", "#3cb371"], + ["mediumslateblue", "#7b68ee"], + ["mediumspringgreen", "#00fa9a"], + ["mediumturquoise", "#48d1cc"], + ["mediumvioletred", "#c71585"], + ["midnightblue", "#191970"], + ["mintcream", "#f5fffa"], + ["mistyrose", "#ffe4e1"], + ["moccasin", "#ffe4b5"], + ["navajowhite", "#ffdead"], + ["oldlace", "#fdf5e6"], + ["olivedrab", "#6b8e23"], + ["orangered", "#ff4500"], + ["orchid", "#da70d6"], + ["palegoldenrod", "#eee8aa"], + ["palegreen", "#98fb98"], + ["paleturquoise", "#afeeee"], + ["palevioletred", "#db7093"], + ["papayawhip", "#ffefd5"], + ["peachpuff", "#ffdab9"], + ["peru", "#cd853f"], + ["pink", "#ffc0cb"], + ["plum", "#dda0dd"], + ["powderblue", "#b0e0e6"], + ["rosybrown", "#bc8f8f"], + ["royalblue", "#4169e1"], + ["saddlebrown", "#8b4513"], + ["salmon", "#fa8072"], + ["sandybrown", "#f4a460"], + ["seagreen", "#2e8b57"], + ["seashell", "#fff5ee"], + ["sienna", "#a0522d"], + ["skyblue", "#87ceeb"], + ["slateblue", "#6a5acd"], + ["slategray", "#708090"], + ["slategrey", "#708090"], + ["snow", "#fffafa"], + ["springgreen", "#00ff7f"], + ["steelblue", "#4682b4"], + ["tan", "#d2b48c"], + ["thistle", "#d8bfd8"], + ["tomato", "#ff6347"], + ["turquoise", "#40e0d0"], + ["violet", "#ee82ee"], + ["wheat", "#f5deb3"], + ["whitesmoke", "#f5f5f5"], + ["yellowgreen", "#9acd32"], + ["rebeccapurple", "#663399"], +]); + +function parseCssColor(colorString) { + if (MapPrototypeHas(colorKeywords, colorString)) { + colorString = MapPrototypeGet(colorKeywords, colorString); + } + // deno-fmt-ignore + const hashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/); + if (hashMatch != null) { + return [ + Number(`0x${hashMatch[1]}`), + Number(`0x${hashMatch[2]}`), + Number(`0x${hashMatch[3]}`), + ]; + } + // deno-fmt-ignore + const smallHashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/); + if (smallHashMatch != null) { + return [ + Number(`0x${smallHashMatch[1]}0`), + Number(`0x${smallHashMatch[2]}0`), + Number(`0x${smallHashMatch[3]}0`), + ]; + } + // deno-fmt-ignore + const rgbMatch = StringPrototypeMatch(colorString, /^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/); + if (rgbMatch != null) { + return [ + MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))), + MathRound(MathMax(0, MathMin(255, Number(rgbMatch[2])))), + MathRound(MathMax(0, MathMin(255, Number(rgbMatch[3])))), + ]; + } + // deno-fmt-ignore + const hslMatch = StringPrototypeMatch(colorString, /^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/); + if (hslMatch != null) { + // https://www.rapidtables.com/convert/color/hsl-to-rgb.html + let h = Number(hslMatch[1]) % 360; + if (h < 0) { + h += 360; + } + const s = MathMax(0, MathMin(100, Number(hslMatch[2]))) / 100; + const l = MathMax(0, MathMin(100, Number(hslMatch[3]))) / 100; + const c = (1 - MathAbs(2 * l - 1)) * s; + const x = c * (1 - MathAbs((h / 60) % 2 - 1)); + const m = l - c / 2; + let r_; + let g_; + let b_; + if (h < 60) { + ({ 0: r_, 1: g_, 2: b_ } = [c, x, 0]); + } else if (h < 120) { + ({ 0: r_, 1: g_, 2: b_ } = [x, c, 0]); + } else if (h < 180) { + ({ 0: r_, 1: g_, 2: b_ } = [0, c, x]); + } else if (h < 240) { + ({ 0: r_, 1: g_, 2: b_ } = [0, x, c]); + } else if (h < 300) { + ({ 0: r_, 1: g_, 2: b_ } = [x, 0, c]); } else { - // Otherwise, default object formatting - let { 0: insp, 1: refIndex } = inspectRawObject(value, inspectOptions); - insp = refIndex + insp; - return insp; + ({ 0: r_, 1: g_, 2: b_ } = [c, 0, x]); } + return [ + MathRound((r_ + m) * 255), + MathRound((g_ + m) * 255), + MathRound((b_ + m) * 255), + ]; } - - const colorKeywords = new Map([ - ["black", "#000000"], - ["silver", "#c0c0c0"], - ["gray", "#808080"], - ["white", "#ffffff"], - ["maroon", "#800000"], - ["red", "#ff0000"], - ["purple", "#800080"], - ["fuchsia", "#ff00ff"], - ["green", "#008000"], - ["lime", "#00ff00"], - ["olive", "#808000"], - ["yellow", "#ffff00"], - ["navy", "#000080"], - ["blue", "#0000ff"], - ["teal", "#008080"], - ["aqua", "#00ffff"], - ["orange", "#ffa500"], - ["aliceblue", "#f0f8ff"], - ["antiquewhite", "#faebd7"], - ["aquamarine", "#7fffd4"], - ["azure", "#f0ffff"], - ["beige", "#f5f5dc"], - ["bisque", "#ffe4c4"], - ["blanchedalmond", "#ffebcd"], - ["blueviolet", "#8a2be2"], - ["brown", "#a52a2a"], - ["burlywood", "#deb887"], - ["cadetblue", "#5f9ea0"], - ["chartreuse", "#7fff00"], - ["chocolate", "#d2691e"], - ["coral", "#ff7f50"], - ["cornflowerblue", "#6495ed"], - ["cornsilk", "#fff8dc"], - ["crimson", "#dc143c"], - ["cyan", "#00ffff"], - ["darkblue", "#00008b"], - ["darkcyan", "#008b8b"], - ["darkgoldenrod", "#b8860b"], - ["darkgray", "#a9a9a9"], - ["darkgreen", "#006400"], - ["darkgrey", "#a9a9a9"], - ["darkkhaki", "#bdb76b"], - ["darkmagenta", "#8b008b"], - ["darkolivegreen", "#556b2f"], - ["darkorange", "#ff8c00"], - ["darkorchid", "#9932cc"], - ["darkred", "#8b0000"], - ["darksalmon", "#e9967a"], - ["darkseagreen", "#8fbc8f"], - ["darkslateblue", "#483d8b"], - ["darkslategray", "#2f4f4f"], - ["darkslategrey", "#2f4f4f"], - ["darkturquoise", "#00ced1"], - ["darkviolet", "#9400d3"], - ["deeppink", "#ff1493"], - ["deepskyblue", "#00bfff"], - ["dimgray", "#696969"], - ["dimgrey", "#696969"], - ["dodgerblue", "#1e90ff"], - ["firebrick", "#b22222"], - ["floralwhite", "#fffaf0"], - ["forestgreen", "#228b22"], - ["gainsboro", "#dcdcdc"], - ["ghostwhite", "#f8f8ff"], - ["gold", "#ffd700"], - ["goldenrod", "#daa520"], - ["greenyellow", "#adff2f"], - ["grey", "#808080"], - ["honeydew", "#f0fff0"], - ["hotpink", "#ff69b4"], - ["indianred", "#cd5c5c"], - ["indigo", "#4b0082"], - ["ivory", "#fffff0"], - ["khaki", "#f0e68c"], - ["lavender", "#e6e6fa"], - ["lavenderblush", "#fff0f5"], - ["lawngreen", "#7cfc00"], - ["lemonchiffon", "#fffacd"], - ["lightblue", "#add8e6"], - ["lightcoral", "#f08080"], - ["lightcyan", "#e0ffff"], - ["lightgoldenrodyellow", "#fafad2"], - ["lightgray", "#d3d3d3"], - ["lightgreen", "#90ee90"], - ["lightgrey", "#d3d3d3"], - ["lightpink", "#ffb6c1"], - ["lightsalmon", "#ffa07a"], - ["lightseagreen", "#20b2aa"], - ["lightskyblue", "#87cefa"], - ["lightslategray", "#778899"], - ["lightslategrey", "#778899"], - ["lightsteelblue", "#b0c4de"], - ["lightyellow", "#ffffe0"], - ["limegreen", "#32cd32"], - ["linen", "#faf0e6"], - ["magenta", "#ff00ff"], - ["mediumaquamarine", "#66cdaa"], - ["mediumblue", "#0000cd"], - ["mediumorchid", "#ba55d3"], - ["mediumpurple", "#9370db"], - ["mediumseagreen", "#3cb371"], - ["mediumslateblue", "#7b68ee"], - ["mediumspringgreen", "#00fa9a"], - ["mediumturquoise", "#48d1cc"], - ["mediumvioletred", "#c71585"], - ["midnightblue", "#191970"], - ["mintcream", "#f5fffa"], - ["mistyrose", "#ffe4e1"], - ["moccasin", "#ffe4b5"], - ["navajowhite", "#ffdead"], - ["oldlace", "#fdf5e6"], - ["olivedrab", "#6b8e23"], - ["orangered", "#ff4500"], - ["orchid", "#da70d6"], - ["palegoldenrod", "#eee8aa"], - ["palegreen", "#98fb98"], - ["paleturquoise", "#afeeee"], - ["palevioletred", "#db7093"], - ["papayawhip", "#ffefd5"], - ["peachpuff", "#ffdab9"], - ["peru", "#cd853f"], - ["pink", "#ffc0cb"], - ["plum", "#dda0dd"], - ["powderblue", "#b0e0e6"], - ["rosybrown", "#bc8f8f"], - ["royalblue", "#4169e1"], - ["saddlebrown", "#8b4513"], - ["salmon", "#fa8072"], - ["sandybrown", "#f4a460"], - ["seagreen", "#2e8b57"], - ["seashell", "#fff5ee"], - ["sienna", "#a0522d"], - ["skyblue", "#87ceeb"], - ["slateblue", "#6a5acd"], - ["slategray", "#708090"], - ["slategrey", "#708090"], - ["snow", "#fffafa"], - ["springgreen", "#00ff7f"], - ["steelblue", "#4682b4"], - ["tan", "#d2b48c"], - ["thistle", "#d8bfd8"], - ["tomato", "#ff6347"], - ["turquoise", "#40e0d0"], - ["violet", "#ee82ee"], - ["wheat", "#f5deb3"], - ["whitesmoke", "#f5f5f5"], - ["yellowgreen", "#9acd32"], - ["rebeccapurple", "#663399"], - ]); - - function parseCssColor(colorString) { - if (MapPrototypeHas(colorKeywords, colorString)) { - colorString = MapPrototypeGet(colorKeywords, colorString); - } - // deno-fmt-ignore - const hashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})?$/); - if (hashMatch != null) { - return [ - Number(`0x${hashMatch[1]}`), - Number(`0x${hashMatch[2]}`), - Number(`0x${hashMatch[3]}`), - ]; - } - // deno-fmt-ignore - const smallHashMatch = StringPrototypeMatch(colorString, /^#([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])([\dA-Fa-f])?$/); - if (smallHashMatch != null) { - return [ - Number(`0x${smallHashMatch[1]}0`), - Number(`0x${smallHashMatch[2]}0`), - Number(`0x${smallHashMatch[3]}0`), - ]; - } - // deno-fmt-ignore - const rgbMatch = StringPrototypeMatch(colorString, /^rgba?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/); - if (rgbMatch != null) { - return [ - MathRound(MathMax(0, MathMin(255, Number(rgbMatch[1])))), - MathRound(MathMax(0, MathMin(255, Number(rgbMatch[2])))), - MathRound(MathMax(0, MathMin(255, Number(rgbMatch[3])))), - ]; - } - // deno-fmt-ignore - const hslMatch = StringPrototypeMatch(colorString, /^hsla?\(\s*([+\-]?\d*\.?\d+)\s*,\s*([+\-]?\d*\.?\d+)%\s*,\s*([+\-]?\d*\.?\d+)%\s*(,\s*([+\-]?\d*\.?\d+)\s*)?\)$/); - if (hslMatch != null) { - // https://www.rapidtables.com/convert/color/hsl-to-rgb.html - let h = Number(hslMatch[1]) % 360; - if (h < 0) { - h += 360; - } - const s = MathMax(0, MathMin(100, Number(hslMatch[2]))) / 100; - const l = MathMax(0, MathMin(100, Number(hslMatch[3]))) / 100; - const c = (1 - MathAbs(2 * l - 1)) * s; - const x = c * (1 - MathAbs((h / 60) % 2 - 1)); - const m = l - c / 2; - let r_; - let g_; - let b_; - if (h < 60) { - ({ 0: r_, 1: g_, 2: b_ } = [c, x, 0]); - } else if (h < 120) { - ({ 0: r_, 1: g_, 2: b_ } = [x, c, 0]); - } else if (h < 180) { - ({ 0: r_, 1: g_, 2: b_ } = [0, c, x]); - } else if (h < 240) { - ({ 0: r_, 1: g_, 2: b_ } = [0, x, c]); - } else if (h < 300) { - ({ 0: r_, 1: g_, 2: b_ } = [x, 0, c]); - } else { - ({ 0: r_, 1: g_, 2: b_ } = [c, 0, x]); + return null; +} + +function getDefaultCss() { + return { + backgroundColor: null, + color: null, + fontWeight: null, + fontStyle: null, + textDecorationColor: null, + textDecorationLine: [], + }; +} + +function parseCss(cssString) { + const css = getDefaultCss(); + + const rawEntries = []; + let inValue = false; + let currentKey = null; + let parenthesesDepth = 0; + let currentPart = ""; + for (let i = 0; i < cssString.length; i++) { + const c = cssString[i]; + if (c == "(") { + parenthesesDepth++; + } else if (parenthesesDepth > 0) { + if (c == ")") { + parenthesesDepth--; } - return [ - MathRound((r_ + m) * 255), - MathRound((g_ + m) * 255), - MathRound((b_ + m) * 255), - ]; - } - return null; - } - - function getDefaultCss() { - return { - backgroundColor: null, - color: null, - fontWeight: null, - fontStyle: null, - textDecorationColor: null, - textDecorationLine: [], - }; - } - - function parseCss(cssString) { - const css = getDefaultCss(); - - const rawEntries = []; - let inValue = false; - let currentKey = null; - let parenthesesDepth = 0; - let currentPart = ""; - for (let i = 0; i < cssString.length; i++) { - const c = cssString[i]; - if (c == "(") { - parenthesesDepth++; - } else if (parenthesesDepth > 0) { - if (c == ")") { - parenthesesDepth--; - } - } else if (inValue) { - if (c == ";") { - const value = StringPrototypeTrim(currentPart); - if (value != "") { - ArrayPrototypePush(rawEntries, [currentKey, value]); - } - currentKey = null; - currentPart = ""; - inValue = false; - continue; + } else if (inValue) { + if (c == ";") { + const value = StringPrototypeTrim(currentPart); + if (value != "") { + ArrayPrototypePush(rawEntries, [currentKey, value]); } - } else if (c == ":") { - currentKey = StringPrototypeTrim(currentPart); + currentKey = null; currentPart = ""; - inValue = true; + inValue = false; continue; } - currentPart += c; - } - if (inValue && parenthesesDepth == 0) { - const value = StringPrototypeTrim(currentPart); - if (value != "") { - ArrayPrototypePush(rawEntries, [currentKey, value]); - } - currentKey = null; + } else if (c == ":") { + currentKey = StringPrototypeTrim(currentPart); currentPart = ""; + inValue = true; + continue; + } + currentPart += c; + } + if (inValue && parenthesesDepth == 0) { + const value = StringPrototypeTrim(currentPart); + if (value != "") { + ArrayPrototypePush(rawEntries, [currentKey, value]); } + currentKey = null; + currentPart = ""; + } - for (let i = 0; i < rawEntries.length; ++i) { - const { 0: key, 1: value } = rawEntries[i]; - if (key == "background-color") { - if (value != null) { - css.backgroundColor = value; - } - } else if (key == "color") { - if (value != null) { - css.color = value; - } - } else if (key == "font-weight") { - if (value == "bold") { - css.fontWeight = value; - } - } else if (key == "font-style") { + for (let i = 0; i < rawEntries.length; ++i) { + const { 0: key, 1: value } = rawEntries[i]; + if (key == "background-color") { + if (value != null) { + css.backgroundColor = value; + } + } else if (key == "color") { + if (value != null) { + css.color = value; + } + } else if (key == "font-weight") { + if (value == "bold") { + css.fontWeight = value; + } + } else if (key == "font-style") { + if ( + ArrayPrototypeIncludes(["italic", "oblique", "oblique 14deg"], value) + ) { + css.fontStyle = "italic"; + } + } else if (key == "text-decoration-line") { + css.textDecorationLine = []; + const lineTypes = StringPrototypeSplit(value, /\s+/g); + for (let i = 0; i < lineTypes.length; ++i) { + const lineType = lineTypes[i]; if ( - ArrayPrototypeIncludes(["italic", "oblique", "oblique 14deg"], value) + ArrayPrototypeIncludes( + ["line-through", "overline", "underline"], + lineType, + ) ) { - css.fontStyle = "italic"; + ArrayPrototypePush(css.textDecorationLine, lineType); } - } else if (key == "text-decoration-line") { - css.textDecorationLine = []; - const lineTypes = StringPrototypeSplit(value, /\s+/g); - for (let i = 0; i < lineTypes.length; ++i) { - const lineType = lineTypes[i]; - if ( - ArrayPrototypeIncludes( - ["line-through", "overline", "underline"], - lineType, - ) - ) { - ArrayPrototypePush(css.textDecorationLine, lineType); - } - } - } else if (key == "text-decoration-color") { - const color = parseCssColor(value); - if (color != null) { - css.textDecorationColor = color; - } - } else if (key == "text-decoration") { - css.textDecorationColor = null; - css.textDecorationLine = []; - const args = StringPrototypeSplit(value, /\s+/g); - for (let i = 0; i < args.length; ++i) { - const arg = args[i]; - const maybeColor = parseCssColor(arg); - if (maybeColor != null) { - css.textDecorationColor = maybeColor; - } else if ( - ArrayPrototypeIncludes( - ["line-through", "overline", "underline"], - arg, - ) - ) { - ArrayPrototypePush(css.textDecorationLine, arg); - } + } + } else if (key == "text-decoration-color") { + const color = parseCssColor(value); + if (color != null) { + css.textDecorationColor = color; + } + } else if (key == "text-decoration") { + css.textDecorationColor = null; + css.textDecorationLine = []; + const args = StringPrototypeSplit(value, /\s+/g); + for (let i = 0; i < args.length; ++i) { + const arg = args[i]; + const maybeColor = parseCssColor(arg); + if (maybeColor != null) { + css.textDecorationColor = maybeColor; + } else if ( + ArrayPrototypeIncludes( + ["line-through", "overline", "underline"], + arg, + ) + ) { + ArrayPrototypePush(css.textDecorationLine, arg); } } } + } - return css; - } - - function colorEquals(color1, color2) { - return color1?.[0] == color2?.[0] && color1?.[1] == color2?.[1] && - color1?.[2] == color2?.[2]; - } - - function cssToAnsi(css, prevCss = null) { - prevCss = prevCss ?? getDefaultCss(); - let ansi = ""; - if (!colorEquals(css.backgroundColor, prevCss.backgroundColor)) { - if (css.backgroundColor == null) { - ansi += "\x1b[49m"; - } else if (css.backgroundColor == "black") { - ansi += `\x1b[40m`; - } else if (css.backgroundColor == "red") { - ansi += `\x1b[41m`; - } else if (css.backgroundColor == "green") { - ansi += `\x1b[42m`; - } else if (css.backgroundColor == "yellow") { - ansi += `\x1b[43m`; - } else if (css.backgroundColor == "blue") { - ansi += `\x1b[44m`; - } else if (css.backgroundColor == "magenta") { - ansi += `\x1b[45m`; - } else if (css.backgroundColor == "cyan") { - ansi += `\x1b[46m`; - } else if (css.backgroundColor == "white") { - ansi += `\x1b[47m`; + return css; +} + +function colorEquals(color1, color2) { + return color1?.[0] == color2?.[0] && color1?.[1] == color2?.[1] && + color1?.[2] == color2?.[2]; +} + +function cssToAnsi(css, prevCss = null) { + prevCss = prevCss ?? getDefaultCss(); + let ansi = ""; + if (!colorEquals(css.backgroundColor, prevCss.backgroundColor)) { + if (css.backgroundColor == null) { + ansi += "\x1b[49m"; + } else if (css.backgroundColor == "black") { + ansi += `\x1b[40m`; + } else if (css.backgroundColor == "red") { + ansi += `\x1b[41m`; + } else if (css.backgroundColor == "green") { + ansi += `\x1b[42m`; + } else if (css.backgroundColor == "yellow") { + ansi += `\x1b[43m`; + } else if (css.backgroundColor == "blue") { + ansi += `\x1b[44m`; + } else if (css.backgroundColor == "magenta") { + ansi += `\x1b[45m`; + } else if (css.backgroundColor == "cyan") { + ansi += `\x1b[46m`; + } else if (css.backgroundColor == "white") { + ansi += `\x1b[47m`; + } else { + if (ArrayIsArray(css.backgroundColor)) { + const { 0: r, 1: g, 2: b } = css.backgroundColor; + ansi += `\x1b[48;2;${r};${g};${b}m`; } else { - if (ArrayIsArray(css.backgroundColor)) { - const { 0: r, 1: g, 2: b } = css.backgroundColor; + const parsed = parseCssColor(css.backgroundColor); + if (parsed !== null) { + const { 0: r, 1: g, 2: b } = parsed; ansi += `\x1b[48;2;${r};${g};${b}m`; } else { - const parsed = parseCssColor(css.backgroundColor); - if (parsed !== null) { - const { 0: r, 1: g, 2: b } = parsed; - ansi += `\x1b[48;2;${r};${g};${b}m`; - } else { - ansi += "\x1b[49m"; - } + ansi += "\x1b[49m"; } } } - if (!colorEquals(css.color, prevCss.color)) { - if (css.color == null) { - ansi += "\x1b[39m"; - } else if (css.color == "black") { - ansi += `\x1b[30m`; - } else if (css.color == "red") { - ansi += `\x1b[31m`; - } else if (css.color == "green") { - ansi += `\x1b[32m`; - } else if (css.color == "yellow") { - ansi += `\x1b[33m`; - } else if (css.color == "blue") { - ansi += `\x1b[34m`; - } else if (css.color == "magenta") { - ansi += `\x1b[35m`; - } else if (css.color == "cyan") { - ansi += `\x1b[36m`; - } else if (css.color == "white") { - ansi += `\x1b[37m`; + } + if (!colorEquals(css.color, prevCss.color)) { + if (css.color == null) { + ansi += "\x1b[39m"; + } else if (css.color == "black") { + ansi += `\x1b[30m`; + } else if (css.color == "red") { + ansi += `\x1b[31m`; + } else if (css.color == "green") { + ansi += `\x1b[32m`; + } else if (css.color == "yellow") { + ansi += `\x1b[33m`; + } else if (css.color == "blue") { + ansi += `\x1b[34m`; + } else if (css.color == "magenta") { + ansi += `\x1b[35m`; + } else if (css.color == "cyan") { + ansi += `\x1b[36m`; + } else if (css.color == "white") { + ansi += `\x1b[37m`; + } else { + if (ArrayIsArray(css.color)) { + const { 0: r, 1: g, 2: b } = css.color; + ansi += `\x1b[38;2;${r};${g};${b}m`; } else { - if (ArrayIsArray(css.color)) { - const { 0: r, 1: g, 2: b } = css.color; + const parsed = parseCssColor(css.color); + if (parsed !== null) { + const { 0: r, 1: g, 2: b } = parsed; ansi += `\x1b[38;2;${r};${g};${b}m`; } else { - const parsed = parseCssColor(css.color); - if (parsed !== null) { - const { 0: r, 1: g, 2: b } = parsed; - ansi += `\x1b[38;2;${r};${g};${b}m`; - } else { - ansi += "\x1b[39m"; - } + ansi += "\x1b[39m"; } } } - if (css.fontWeight != prevCss.fontWeight) { - if (css.fontWeight == "bold") { - ansi += `\x1b[1m`; - } else { - ansi += "\x1b[22m"; - } + } + if (css.fontWeight != prevCss.fontWeight) { + if (css.fontWeight == "bold") { + ansi += `\x1b[1m`; + } else { + ansi += "\x1b[22m"; } - if (css.fontStyle != prevCss.fontStyle) { - if (css.fontStyle == "italic") { - ansi += `\x1b[3m`; - } else { - ansi += "\x1b[23m"; - } + } + if (css.fontStyle != prevCss.fontStyle) { + if (css.fontStyle == "italic") { + ansi += `\x1b[3m`; + } else { + ansi += "\x1b[23m"; } - if (!colorEquals(css.textDecorationColor, prevCss.textDecorationColor)) { - if (css.textDecorationColor != null) { - const { 0: r, 1: g, 2: b } = css.textDecorationColor; - ansi += `\x1b[58;2;${r};${g};${b}m`; - } else { - ansi += "\x1b[59m"; - } + } + if (!colorEquals(css.textDecorationColor, prevCss.textDecorationColor)) { + if (css.textDecorationColor != null) { + const { 0: r, 1: g, 2: b } = css.textDecorationColor; + ansi += `\x1b[58;2;${r};${g};${b}m`; + } else { + ansi += "\x1b[59m"; } - if ( - ArrayPrototypeIncludes(css.textDecorationLine, "line-through") != - ArrayPrototypeIncludes(prevCss.textDecorationLine, "line-through") - ) { - if (ArrayPrototypeIncludes(css.textDecorationLine, "line-through")) { - ansi += "\x1b[9m"; - } else { - ansi += "\x1b[29m"; - } + } + if ( + ArrayPrototypeIncludes(css.textDecorationLine, "line-through") != + ArrayPrototypeIncludes(prevCss.textDecorationLine, "line-through") + ) { + if (ArrayPrototypeIncludes(css.textDecorationLine, "line-through")) { + ansi += "\x1b[9m"; + } else { + ansi += "\x1b[29m"; } - if ( - ArrayPrototypeIncludes(css.textDecorationLine, "overline") != - ArrayPrototypeIncludes(prevCss.textDecorationLine, "overline") - ) { - if (ArrayPrototypeIncludes(css.textDecorationLine, "overline")) { - ansi += "\x1b[53m"; - } else { - ansi += "\x1b[55m"; - } + } + if ( + ArrayPrototypeIncludes(css.textDecorationLine, "overline") != + ArrayPrototypeIncludes(prevCss.textDecorationLine, "overline") + ) { + if (ArrayPrototypeIncludes(css.textDecorationLine, "overline")) { + ansi += "\x1b[53m"; + } else { + ansi += "\x1b[55m"; } - if ( - ArrayPrototypeIncludes(css.textDecorationLine, "underline") != - ArrayPrototypeIncludes(prevCss.textDecorationLine, "underline") - ) { - if (ArrayPrototypeIncludes(css.textDecorationLine, "underline")) { - ansi += "\x1b[4m"; - } else { - ansi += "\x1b[24m"; - } + } + if ( + ArrayPrototypeIncludes(css.textDecorationLine, "underline") != + ArrayPrototypeIncludes(prevCss.textDecorationLine, "underline") + ) { + if (ArrayPrototypeIncludes(css.textDecorationLine, "underline")) { + ansi += "\x1b[4m"; + } else { + ansi += "\x1b[24m"; } - return ansi; - } - - function inspectArgs(args, inspectOptions = {}) { - circular = undefined; - - const noColor = colors.getNoColor(); - const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions }; - const first = args[0]; - let a = 0; - let string = ""; - - if (typeof first == "string" && args.length > 1) { - a++; - // Index of the first not-yet-appended character. Use this so we only - // have to append to `string` when a substitution occurs / at the end. - let appendedChars = 0; - let usedStyle = false; - let prevCss = null; - for (let i = 0; i < first.length - 1; i++) { - if (first[i] == "%") { - const char = first[++i]; - if (a < args.length) { - let formattedArg = null; - if (char == "s") { - // Format as a string. - formattedArg = String(args[a++]); - } else if (ArrayPrototypeIncludes(["d", "i"], char)) { - // Format as an integer. - const value = args[a++]; - if (typeof value == "bigint") { - formattedArg = `${value}n`; - } else if (typeof value == "number") { - formattedArg = `${NumberParseInt(String(value))}`; - } else { - formattedArg = "NaN"; - } - } else if (char == "f") { - // Format as a floating point value. - const value = args[a++]; - if (typeof value == "number") { - formattedArg = `${value}`; - } else { - formattedArg = "NaN"; - } - } else if (ArrayPrototypeIncludes(["O", "o"], char)) { - // Format as an object. - formattedArg = inspectValue(args[a++], rInspectOptions); - } else if (char == "c") { - const value = args[a++]; - if (!noColor) { - const css = parseCss(value); - formattedArg = cssToAnsi(css, prevCss); - if (formattedArg != "") { - usedStyle = true; - prevCss = css; - } - } else { - formattedArg = ""; - } + } + return ansi; +} + +function inspectArgs(args, inspectOptions = {}) { + circular = undefined; + + const noColor = colors.getNoColor(); + const rInspectOptions = { ...DEFAULT_INSPECT_OPTIONS, ...inspectOptions }; + const first = args[0]; + let a = 0; + let string = ""; + + if (typeof first == "string" && args.length > 1) { + a++; + // Index of the first not-yet-appended character. Use this so we only + // have to append to `string` when a substitution occurs / at the end. + let appendedChars = 0; + let usedStyle = false; + let prevCss = null; + for (let i = 0; i < first.length - 1; i++) { + if (first[i] == "%") { + const char = first[++i]; + if (a < args.length) { + let formattedArg = null; + if (char == "s") { + // Format as a string. + formattedArg = String(args[a++]); + } else if (ArrayPrototypeIncludes(["d", "i"], char)) { + // Format as an integer. + const value = args[a++]; + if (typeof value == "bigint") { + formattedArg = `${value}n`; + } else if (typeof value == "number") { + formattedArg = `${NumberParseInt(String(value))}`; + } else { + formattedArg = "NaN"; } - - if (formattedArg != null) { - string += StringPrototypeSlice(first, appendedChars, i - 1) + - formattedArg; - appendedChars = i + 1; + } else if (char == "f") { + // Format as a floating point value. + const value = args[a++]; + if (typeof value == "number") { + formattedArg = `${value}`; + } else { + formattedArg = "NaN"; + } + } else if (ArrayPrototypeIncludes(["O", "o"], char)) { + // Format as an object. + formattedArg = inspectValue(args[a++], rInspectOptions); + } else if (char == "c") { + const value = args[a++]; + if (!noColor) { + const css = parseCss(value); + formattedArg = cssToAnsi(css, prevCss); + if (formattedArg != "") { + usedStyle = true; + prevCss = css; + } + } else { + formattedArg = ""; } } - if (char == "%") { - string += StringPrototypeSlice(first, appendedChars, i - 1) + "%"; + + if (formattedArg != null) { + string += StringPrototypeSlice(first, appendedChars, i - 1) + + formattedArg; appendedChars = i + 1; } } - } - string += StringPrototypeSlice(first, appendedChars); - if (usedStyle) { - string += "\x1b[0m"; + if (char == "%") { + string += StringPrototypeSlice(first, appendedChars, i - 1) + "%"; + appendedChars = i + 1; + } } } - - for (; a < args.length; a++) { - if (a > 0) { - string += " "; - } - if (typeof args[a] == "string") { - string += args[a]; - } else { - // Use default maximum depth for null or undefined arguments. - string += inspectValue(args[a], rInspectOptions); - } + string += StringPrototypeSlice(first, appendedChars); + if (usedStyle) { + string += "\x1b[0m"; } + } - if (rInspectOptions.indentLevel > 0) { - const groupIndent = StringPrototypeRepeat( - DEFAULT_INDENT, - rInspectOptions.indentLevel, - ); - string = groupIndent + - StringPrototypeReplaceAll(string, "\n", `\n${groupIndent}`); + for (; a < args.length; a++) { + if (a > 0) { + string += " "; + } + if (typeof args[a] == "string") { + string += args[a]; + } else { + // Use default maximum depth for null or undefined arguments. + string += inspectValue(args[a], rInspectOptions); } + } - return string; + if (rInspectOptions.indentLevel > 0) { + const groupIndent = StringPrototypeRepeat( + DEFAULT_INDENT, + rInspectOptions.indentLevel, + ); + string = groupIndent + + StringPrototypeReplaceAll(string, "\n", `\n${groupIndent}`); } - const countMap = new Map(); - const timerMap = new Map(); - const isConsoleInstance = Symbol("isConsoleInstance"); + return string; +} - function getConsoleInspectOptions() { - return { - ...DEFAULT_INSPECT_OPTIONS, - colors: !colors.getNoColor(), - }; - } +const countMap = new Map(); +const timerMap = new Map(); +const isConsoleInstance = Symbol("isConsoleInstance"); - class Console { - #printFunc = null; - [isConsoleInstance] = false; - - constructor(printFunc) { - this.#printFunc = printFunc; - this.indentLevel = 0; - this[isConsoleInstance] = true; - - // ref https://console.spec.whatwg.org/#console-namespace - // For historical web-compatibility reasons, the namespace object for - // console must have as its [[Prototype]] an empty object, created as if - // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%. - const console = ObjectCreate({}, { - [SymbolToStringTag]: { - enumerable: false, - writable: false, - configurable: true, - value: "console", - }, - }); - ObjectAssign(console, this); - return console; - } +function getConsoleInspectOptions() { + return { + ...DEFAULT_INSPECT_OPTIONS, + colors: !colors.getNoColor(), + }; +} + +class Console { + #printFunc = null; + [isConsoleInstance] = false; + + constructor(printFunc) { + this.#printFunc = printFunc; + this.indentLevel = 0; + this[isConsoleInstance] = true; + + // ref https://console.spec.whatwg.org/#console-namespace + // For historical web-compatibility reasons, the namespace object for + // console must have as its [[Prototype]] an empty object, created as if + // by ObjectCreate(%ObjectPrototype%), instead of %ObjectPrototype%. + const console = ObjectCreate({}, { + [SymbolToStringTag]: { + enumerable: false, + writable: false, + configurable: true, + value: "console", + }, + }); + ObjectAssign(console, this); + return console; + } - log = (...args) => { - this.#printFunc( - inspectArgs(args, { - ...getConsoleInspectOptions(), - indentLevel: this.indentLevel, - }) + "\n", - 1, - ); - }; + log = (...args) => { + this.#printFunc( + inspectArgs(args, { + ...getConsoleInspectOptions(), + indentLevel: this.indentLevel, + }) + "\n", + 1, + ); + }; - debug = (...args) => { - this.#printFunc( - inspectArgs(args, { - ...getConsoleInspectOptions(), - indentLevel: this.indentLevel, - }) + "\n", - 0, - ); - }; + debug = (...args) => { + this.#printFunc( + inspectArgs(args, { + ...getConsoleInspectOptions(), + indentLevel: this.indentLevel, + }) + "\n", + 0, + ); + }; - info = (...args) => { - this.#printFunc( - inspectArgs(args, { - ...getConsoleInspectOptions(), - indentLevel: this.indentLevel, - }) + "\n", - 1, - ); - }; + info = (...args) => { + this.#printFunc( + inspectArgs(args, { + ...getConsoleInspectOptions(), + indentLevel: this.indentLevel, + }) + "\n", + 1, + ); + }; - dir = (obj = undefined, options = {}) => { - this.#printFunc( - inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) + - "\n", - 1, - ); - }; + dir = (obj = undefined, options = {}) => { + this.#printFunc( + inspectArgs([obj], { ...getConsoleInspectOptions(), ...options }) + + "\n", + 1, + ); + }; - dirxml = this.dir; + dirxml = this.dir; - warn = (...args) => { - this.#printFunc( - inspectArgs(args, { - ...getConsoleInspectOptions(), - indentLevel: this.indentLevel, - }) + "\n", - 2, - ); - }; + warn = (...args) => { + this.#printFunc( + inspectArgs(args, { + ...getConsoleInspectOptions(), + indentLevel: this.indentLevel, + }) + "\n", + 2, + ); + }; - error = (...args) => { - this.#printFunc( - inspectArgs(args, { - ...getConsoleInspectOptions(), - indentLevel: this.indentLevel, - }) + "\n", - 3, - ); - }; + error = (...args) => { + this.#printFunc( + inspectArgs(args, { + ...getConsoleInspectOptions(), + indentLevel: this.indentLevel, + }) + "\n", + 3, + ); + }; - assert = (condition = false, ...args) => { - if (condition) { - return; - } + assert = (condition = false, ...args) => { + if (condition) { + return; + } - if (args.length === 0) { - this.error("Assertion failed"); - return; - } + if (args.length === 0) { + this.error("Assertion failed"); + return; + } - const [first, ...rest] = new SafeArrayIterator(args); + const [first, ...rest] = new SafeArrayIterator(args); - if (typeof first === "string") { - this.error( - `Assertion failed: ${first}`, - ...new SafeArrayIterator(rest), - ); - return; - } + if (typeof first === "string") { + this.error( + `Assertion failed: ${first}`, + ...new SafeArrayIterator(rest), + ); + return; + } - this.error(`Assertion failed:`, ...new SafeArrayIterator(args)); - }; + this.error(`Assertion failed:`, ...new SafeArrayIterator(args)); + }; - count = (label = "default") => { - label = String(label); + count = (label = "default") => { + label = String(label); - if (MapPrototypeHas(countMap, label)) { - const current = MapPrototypeGet(countMap, label) || 0; - MapPrototypeSet(countMap, label, current + 1); - } else { - MapPrototypeSet(countMap, label, 1); - } + if (MapPrototypeHas(countMap, label)) { + const current = MapPrototypeGet(countMap, label) || 0; + MapPrototypeSet(countMap, label, current + 1); + } else { + MapPrototypeSet(countMap, label, 1); + } - this.info(`${label}: ${MapPrototypeGet(countMap, label)}`); - }; + this.info(`${label}: ${MapPrototypeGet(countMap, label)}`); + }; - countReset = (label = "default") => { - label = String(label); + countReset = (label = "default") => { + label = String(label); - if (MapPrototypeHas(countMap, label)) { - MapPrototypeSet(countMap, label, 0); - } else { - this.warn(`Count for '${label}' does not exist`); - } - }; + if (MapPrototypeHas(countMap, label)) { + MapPrototypeSet(countMap, label, 0); + } else { + this.warn(`Count for '${label}' does not exist`); + } + }; - table = (data = undefined, properties = undefined) => { - if (properties !== undefined && !ArrayIsArray(properties)) { - throw new Error( - "The 'properties' argument must be of type Array. " + - "Received type string", - ); - } + table = (data = undefined, properties = undefined) => { + if (properties !== undefined && !ArrayIsArray(properties)) { + throw new Error( + "The 'properties' argument must be of type Array. " + + "Received type string", + ); + } - if (data === null || typeof data !== "object") { - return this.log(data); - } + if (data === null || typeof data !== "object") { + return this.log(data); + } - const stringifyValue = (value) => - inspectValueWithQuotes(value, { - ...DEFAULT_INSPECT_OPTIONS, - depth: 1, - }); - const toTable = (header, body) => this.log(cliTable(header, body)); - - let resultData; - const isSet = ObjectPrototypeIsPrototypeOf(SetPrototype, data); - const isMap = ObjectPrototypeIsPrototypeOf(MapPrototype, data); - const valuesKey = "Values"; - const indexKey = isSet || isMap ? "(iter idx)" : "(idx)"; - - if (isSet) { - resultData = [...new SafeSet(data)]; - } else if (isMap) { - let idx = 0; - resultData = {}; - - MapPrototypeForEach(data, (v, k) => { - resultData[idx] = { Key: k, Values: v }; - idx++; - }); - } else { - resultData = data; - } + const stringifyValue = (value) => + inspectValueWithQuotes(value, { + ...DEFAULT_INSPECT_OPTIONS, + depth: 1, + }); + const toTable = (header, body) => this.log(cliTable(header, body)); + + let resultData; + const isSet = ObjectPrototypeIsPrototypeOf(SetPrototype, data); + const isMap = ObjectPrototypeIsPrototypeOf(MapPrototype, data); + const valuesKey = "Values"; + const indexKey = isSet || isMap ? "(iter idx)" : "(idx)"; + + if (isSet) { + resultData = [...new SafeSet(data)]; + } else if (isMap) { + let idx = 0; + resultData = {}; + + MapPrototypeForEach(data, (v, k) => { + resultData[idx] = { Key: k, Values: v }; + idx++; + }); + } else { + resultData = data; + } - const keys = ObjectKeys(resultData); - const numRows = keys.length; + const keys = ObjectKeys(resultData); + const numRows = keys.length; - const objectValues = properties - ? ObjectFromEntries( - ArrayPrototypeMap( - properties, - (name) => [name, ArrayPrototypeFill(new Array(numRows), "")], - ), - ) - : {}; - const indexKeys = []; - const values = []; - - let hasPrimitives = false; - keys.forEach((k, idx) => { - const value = resultData[k]; - const primitive = value === null || - (typeof value !== "function" && typeof value !== "object"); - if (properties === undefined && primitive) { - hasPrimitives = true; - ArrayPrototypePush(values, stringifyValue(value)); - } else { - const valueObj = value || {}; - const keys = properties || ObjectKeys(valueObj); - for (let i = 0; i < keys.length; ++i) { - const k = keys[i]; - if (!primitive && ReflectHas(valueObj, k)) { - if (!(ReflectHas(objectValues, k))) { - objectValues[k] = ArrayPrototypeFill(new Array(numRows), ""); - } - objectValues[k][idx] = stringifyValue(valueObj[k]); + const objectValues = properties + ? ObjectFromEntries( + ArrayPrototypeMap( + properties, + (name) => [name, ArrayPrototypeFill(new Array(numRows), "")], + ), + ) + : {}; + const indexKeys = []; + const values = []; + + let hasPrimitives = false; + keys.forEach((k, idx) => { + const value = resultData[k]; + const primitive = value === null || + (typeof value !== "function" && typeof value !== "object"); + if (properties === undefined && primitive) { + hasPrimitives = true; + ArrayPrototypePush(values, stringifyValue(value)); + } else { + const valueObj = value || {}; + const keys = properties || ObjectKeys(valueObj); + for (let i = 0; i < keys.length; ++i) { + const k = keys[i]; + if (!primitive && ReflectHas(valueObj, k)) { + if (!(ReflectHas(objectValues, k))) { + objectValues[k] = ArrayPrototypeFill(new Array(numRows), ""); } + objectValues[k][idx] = stringifyValue(valueObj[k]); } - ArrayPrototypePush(values, ""); } - - ArrayPrototypePush(indexKeys, k); - }); - - const headerKeys = ObjectKeys(objectValues); - const bodyValues = ObjectValues(objectValues); - const headerProps = properties || - [ - ...new SafeArrayIterator(headerKeys), - !isMap && hasPrimitives && valuesKey, - ]; - const header = ArrayPrototypeFilter([ - indexKey, - ...new SafeArrayIterator(headerProps), - ], Boolean); - const body = [indexKeys, ...new SafeArrayIterator(bodyValues), values]; - - toTable(header, body); - }; - - time = (label = "default") => { - label = String(label); - - if (MapPrototypeHas(timerMap, label)) { - this.warn(`Timer '${label}' already exists`); - return; + ArrayPrototypePush(values, ""); } - MapPrototypeSet(timerMap, label, DateNow()); - }; + ArrayPrototypePush(indexKeys, k); + }); - timeLog = (label = "default", ...args) => { - label = String(label); + const headerKeys = ObjectKeys(objectValues); + const bodyValues = ObjectValues(objectValues); + const headerProps = properties || + [ + ...new SafeArrayIterator(headerKeys), + !isMap && hasPrimitives && valuesKey, + ]; + const header = ArrayPrototypeFilter([ + indexKey, + ...new SafeArrayIterator(headerProps), + ], Boolean); + const body = [indexKeys, ...new SafeArrayIterator(bodyValues), values]; - if (!MapPrototypeHas(timerMap, label)) { - this.warn(`Timer '${label}' does not exists`); - return; - } + toTable(header, body); + }; - const startTime = MapPrototypeGet(timerMap, label); - const duration = DateNow() - startTime; + time = (label = "default") => { + label = String(label); - this.info(`${label}: ${duration}ms`, ...new SafeArrayIterator(args)); - }; + if (MapPrototypeHas(timerMap, label)) { + this.warn(`Timer '${label}' already exists`); + return; + } - timeEnd = (label = "default") => { - label = String(label); + MapPrototypeSet(timerMap, label, DateNow()); + }; - if (!MapPrototypeHas(timerMap, label)) { - this.warn(`Timer '${label}' does not exist`); - return; - } + timeLog = (label = "default", ...args) => { + label = String(label); - const startTime = MapPrototypeGet(timerMap, label); - MapPrototypeDelete(timerMap, label); - const duration = DateNow() - startTime; + if (!MapPrototypeHas(timerMap, label)) { + this.warn(`Timer '${label}' does not exists`); + return; + } - this.info(`${label}: ${duration}ms`); - }; + const startTime = MapPrototypeGet(timerMap, label); + const duration = DateNow() - startTime; - group = (...label) => { - if (label.length > 0) { - this.log(...new SafeArrayIterator(label)); - } - this.indentLevel += 2; - }; + this.info(`${label}: ${duration}ms`, ...new SafeArrayIterator(args)); + }; - groupCollapsed = this.group; + timeEnd = (label = "default") => { + label = String(label); - groupEnd = () => { - if (this.indentLevel > 0) { - this.indentLevel -= 2; - } - }; - - clear = () => { - this.indentLevel = 0; - this.#printFunc(CSI.kClear, 1); - this.#printFunc(CSI.kClearScreenDown, 1); - }; + if (!MapPrototypeHas(timerMap, label)) { + this.warn(`Timer '${label}' does not exist`); + return; + } - trace = (...args) => { - const message = inspectArgs( - args, - { ...getConsoleInspectOptions(), indentLevel: 0 }, - ); - const err = { - name: "Trace", - message, - }; - ErrorCaptureStackTrace(err, this.trace); - this.error(err.stack); - }; + const startTime = MapPrototypeGet(timerMap, label); + MapPrototypeDelete(timerMap, label); + const duration = DateNow() - startTime; - // These methods are noops, but when the inspector is connected, they - // call into V8. - profile = (_label) => {}; - profileEnd = (_label) => {}; - timeStamp = (_label) => {}; + this.info(`${label}: ${duration}ms`); + }; - static [SymbolHasInstance](instance) { - return instance[isConsoleInstance]; + group = (...label) => { + if (label.length > 0) { + this.log(...new SafeArrayIterator(label)); } - } + this.indentLevel += 2; + }; - const customInspect = SymbolFor("Deno.customInspect"); + groupCollapsed = this.group; - function inspect( - value, - inspectOptions = {}, - ) { - circular = undefined; - return inspectValue(value, { - ...DEFAULT_INSPECT_OPTIONS, - ...inspectOptions, - }); - } + groupEnd = () => { + if (this.indentLevel > 0) { + this.indentLevel -= 2; + } + }; - /** Creates a proxy that represents a subset of the properties - * of the original object optionally without evaluating the properties - * in order to get the values. */ - function createFilteredInspectProxy({ object, keys, evaluate }) { - return new Proxy({}, { - get(_target, key) { - if (key === SymbolToStringTag) { - return object.constructor?.name; - } else if (ArrayPrototypeIncludes(keys, key)) { - return ReflectGet(object, key); - } else { - return undefined; - } - }, - getOwnPropertyDescriptor(_target, key) { - if (!ArrayPrototypeIncludes(keys, key)) { - return undefined; - } else if (evaluate) { - return getEvaluatedDescriptor(object, key); - } else { - return getDescendantPropertyDescriptor(object, key) ?? - getEvaluatedDescriptor(object, key); - } - }, - has(_target, key) { - return ArrayPrototypeIncludes(keys, key); - }, - ownKeys() { - return keys; - }, - }); + clear = () => { + this.indentLevel = 0; + this.#printFunc(CSI.kClear, 1); + this.#printFunc(CSI.kClearScreenDown, 1); + }; - function getDescendantPropertyDescriptor(object, key) { - let propertyDescriptor = ReflectGetOwnPropertyDescriptor(object, key); - if (!propertyDescriptor) { - const prototype = ReflectGetPrototypeOf(object); - if (prototype) { - propertyDescriptor = getDescendantPropertyDescriptor(prototype, key); - } - } - return propertyDescriptor; - } + trace = (...args) => { + const message = inspectArgs( + args, + { ...getConsoleInspectOptions(), indentLevel: 0 }, + ); + const err = { + name: "Trace", + message, + }; + ErrorCaptureStackTrace(err, this.trace); + this.error(err.stack); + }; - function getEvaluatedDescriptor(object, key) { - return { - configurable: true, - enumerable: true, - value: object[key], - }; - } - } + // These methods are noops, but when the inspector is connected, they + // call into V8. + profile = (_label) => {}; + profileEnd = (_label) => {}; + timeStamp = (_label) => {}; - // A helper function that will bind our own console implementation - // with default implementation of Console from V8. This will cause - // console messages to be piped to inspector console. - // - // We are using `Deno.core.callConsole` binding to preserve proper stack - // frames in inspector console. This has to be done because V8 considers - // the last JS stack frame as gospel for the inspector. In our case we - // specifically want the latest user stack frame to be the one that matters - // though. - // - // Inspired by: - // https://github.com/nodejs/node/blob/1317252dfe8824fd9cfee125d2aaa94004db2f3b/lib/internal/util/inspector.js#L39-L61 - function wrapConsole(consoleFromDeno, consoleFromV8) { - const callConsole = core.callConsole; - - const keys = ObjectKeys(consoleFromV8); - for (let i = 0; i < keys.length; ++i) { - const key = keys[i]; - if (ObjectPrototypeHasOwnProperty(consoleFromDeno, key)) { - consoleFromDeno[key] = FunctionPrototypeBind( - callConsole, - consoleFromDeno, - consoleFromV8[key], - consoleFromDeno[key], - ); + static [SymbolHasInstance](instance) { + return instance[isConsoleInstance]; + } +} + +const customInspect = SymbolFor("Deno.customInspect"); + +function inspect( + value, + inspectOptions = {}, +) { + circular = undefined; + return inspectValue(value, { + ...DEFAULT_INSPECT_OPTIONS, + ...inspectOptions, + }); +} + +/** Creates a proxy that represents a subset of the properties + * of the original object optionally without evaluating the properties + * in order to get the values. */ +function createFilteredInspectProxy({ object, keys, evaluate }) { + return new Proxy({}, { + get(_target, key) { + if (key === SymbolToStringTag) { + return object.constructor?.name; + } else if (ArrayPrototypeIncludes(keys, key)) { + return ReflectGet(object, key); + } else { + return undefined; + } + }, + getOwnPropertyDescriptor(_target, key) { + if (!ArrayPrototypeIncludes(keys, key)) { + return undefined; + } else if (evaluate) { + return getEvaluatedDescriptor(object, key); } else { - // Add additional console APIs from the inspector - consoleFromDeno[key] = consoleFromV8[key]; + return getDescendantPropertyDescriptor(object, key) ?? + getEvaluatedDescriptor(object, key); + } + }, + has(_target, key) { + return ArrayPrototypeIncludes(keys, key); + }, + ownKeys() { + return keys; + }, + }); + + function getDescendantPropertyDescriptor(object, key) { + let propertyDescriptor = ReflectGetOwnPropertyDescriptor(object, key); + if (!propertyDescriptor) { + const prototype = ReflectGetPrototypeOf(object); + if (prototype) { + propertyDescriptor = getDescendantPropertyDescriptor(prototype, key); } } + return propertyDescriptor; } - // Expose these fields to internalObject for tests. - window.__bootstrap.internals = { - ...window.__bootstrap.internals ?? {}, - Console, - cssToAnsi, - inspectArgs, - parseCss, - parseCssColor, - }; - - window.__bootstrap.console = { - CSI, - inspectArgs, - Console, - customInspect, - inspect, - wrapConsole, - createFilteredInspectProxy, - quoteString, - }; -})(this); + function getEvaluatedDescriptor(object, key) { + return { + configurable: true, + enumerable: true, + value: object[key], + }; + } +} + +// A helper function that will bind our own console implementation +// with default implementation of Console from V8. This will cause +// console messages to be piped to inspector console. +// +// We are using `Deno.core.callConsole` binding to preserve proper stack +// frames in inspector console. This has to be done because V8 considers +// the last JS stack frame as gospel for the inspector. In our case we +// specifically want the latest user stack frame to be the one that matters +// though. +// +// Inspired by: +// https://github.com/nodejs/node/blob/1317252dfe8824fd9cfee125d2aaa94004db2f3b/lib/internal/util/inspector.js#L39-L61 +function wrapConsole(consoleFromDeno, consoleFromV8) { + const callConsole = core.callConsole; + + const keys = ObjectKeys(consoleFromV8); + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + if (ObjectPrototypeHasOwnProperty(consoleFromDeno, key)) { + consoleFromDeno[key] = FunctionPrototypeBind( + callConsole, + consoleFromDeno, + consoleFromV8[key], + consoleFromDeno[key], + ); + } else { + // Add additional console APIs from the inspector + consoleFromDeno[key] = consoleFromV8[key]; + } + } +} + +// Expose these fields to internalObject for tests. +internals.Console = Console; +internals.cssToAnsi = cssToAnsi; +internals.inspectArgs = inspectArgs; +internals.parseCss = parseCss; +internals.parseCssColor = parseCssColor; + +export { + Console, + createFilteredInspectProxy, + CSI, + customInspect, + inspect, + inspectArgs, + quoteString, + wrapConsole, +}; |