From ed3f5414b10594b5cd5d97cc9ebf54f5399dbf68 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 16 Nov 2020 16:39:28 +0100 Subject: [PATCH 1/2] util: refactor to use more primordials --- lib/internal/util.js | 55 ++++++++------ lib/internal/util/comparisons.js | 34 +++++---- lib/internal/util/debuglog.js | 8 ++- lib/internal/util/inspect.js | 118 +++++++++++++++++++------------ lib/internal/util/inspector.js | 17 +++-- lib/util.js | 25 +++++-- 6 files changed, 160 insertions(+), 97 deletions(-) diff --git a/lib/internal/util.js b/lib/internal/util.js index f26ea970e8dce0..cd0edfe44ee13f 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -3,8 +3,11 @@ const { ArrayFrom, ArrayIsArray, + ArrayPrototypePop, + ArrayPrototypePush, + ArrayPrototypeSlice, + ArrayPrototypeSort, Error, - Map, ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, @@ -13,8 +16,14 @@ const { ObjectGetPrototypeOf, ObjectSetPrototypeOf, Promise, + ReflectApply, ReflectConstruct, - Set, + RegExpPrototypeTest, + SafeMap, + SafeSet, + StringPrototypeReplace, + StringPrototypeToLowerCase, + StringPrototypeToUpperCase, Symbol, SymbolFor, } = primordials; @@ -40,12 +49,12 @@ const { isNativeError } = internalBinding('types'); const noCrypto = !process.versions.openssl; -const experimentalWarnings = new Set(); +const experimentalWarnings = new SafeSet(); const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex function removeColors(str) { - return str.replace(colorRegExp, ''); + return StringPrototypeReplace(str, colorRegExp, ''); } function isError(e) { @@ -57,7 +66,7 @@ function isError(e) { // Keep a list of deprecation codes that have been warned on so we only warn on // each one once. -const codesWarned = new Set(); +const codesWarned = new SafeSet(); // Mark that a method should not be used. // Returns a modified function which warns once by default. @@ -86,7 +95,7 @@ function deprecate(fn, msg, code) { if (new.target) { return ReflectConstruct(fn, args, new.target); } - return fn.apply(this, args); + return ReflectApply(fn, this, args); } // The wrapper will keep the same prototype as fn to maintain prototype chain @@ -132,12 +141,13 @@ function slowCases(enc) { case 4: if (enc === 'UTF8') return 'utf8'; if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le'; - enc = `${enc}`.toLowerCase(); + enc = StringPrototypeToLowerCase(`${enc}`); if (enc === 'utf8') return 'utf8'; if (enc === 'ucs2') return 'utf16le'; break; case 3: - if (enc === 'hex' || enc === 'HEX' || `${enc}`.toLowerCase() === 'hex') + if (enc === 'hex' || enc === 'HEX' || + StringPrototypeToLowerCase(`${enc}`) === 'hex') return 'hex'; break; case 5: @@ -146,7 +156,7 @@ function slowCases(enc) { if (enc === 'UTF-8') return 'utf8'; if (enc === 'ASCII') return 'ascii'; if (enc === 'UCS-2') return 'utf16le'; - enc = `${enc}`.toLowerCase(); + enc = StringPrototypeToLowerCase(`${enc}`); if (enc === 'utf-8') return 'utf8'; if (enc === 'ascii') return 'ascii'; if (enc === 'ucs-2') return 'utf16le'; @@ -156,18 +166,18 @@ function slowCases(enc) { if (enc === 'latin1' || enc === 'binary') return 'latin1'; if (enc === 'BASE64') return 'base64'; if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1'; - enc = `${enc}`.toLowerCase(); + enc = StringPrototypeToLowerCase(`${enc}`); if (enc === 'base64') return 'base64'; if (enc === 'latin1' || enc === 'binary') return 'latin1'; break; case 7: if (enc === 'utf16le' || enc === 'UTF16LE' || - `${enc}`.toLowerCase() === 'utf16le') + StringPrototypeToLowerCase(`${enc}`) === 'utf16le') return 'utf16le'; break; case 8: if (enc === 'utf-16le' || enc === 'UTF-16LE' || - `${enc}`.toLowerCase() === 'utf-16le') + StringPrototypeToLowerCase(`${enc}`) === 'utf-16le') return 'utf16le'; break; default: @@ -184,17 +194,17 @@ function emitExperimentalWarning(feature) { } function filterDuplicateStrings(items, low) { - const map = new Map(); + const map = new SafeMap(); for (let i = 0; i < items.length; i++) { const item = items[i]; - const key = item.toLowerCase(); + const key = StringPrototypeToLowerCase(item); if (low) { map.set(key, key); } else { map.set(key, item); } } - return ArrayFrom(map.values()).sort(); + return ArrayPrototypeSort(ArrayFrom(map.values())); } function cachedResult(fn) { @@ -202,7 +212,7 @@ function cachedResult(fn) { return () => { if (result === undefined) result = fn(); - return result.slice(); + return ArrayPrototypeSlice(result); }; } @@ -244,7 +254,7 @@ function convertToValidSignal(signal) { return signal; if (typeof signal === 'string') { - const signalName = signals[signal.toUpperCase()]; + const signalName = signals[StringPrototypeToUpperCase(signal)]; if (signalName) return signalName; } @@ -294,7 +304,7 @@ function promisify(original) { function fn(...args) { return new Promise((resolve, reject) => { - original.call(this, ...args, (err, ...values) => { + ArrayPrototypePush(args, (err, ...values) => { if (err) { return reject(err); } @@ -307,6 +317,7 @@ function promisify(original) { resolve(values[0]); } }); + ReflectApply(original, this, args); }); } @@ -343,7 +354,7 @@ function join(output, separator) { function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; - list.pop(); + ArrayPrototypePop(list); } const kNodeModulesRE = /^(.*)[\\/]node_modules[\\/]/; @@ -376,9 +387,9 @@ function isInsideNodeModules() { const filename = frame.getFileName(); // If a filename does not start with / or contain \, // it's likely from Node.js core. - if (!/^\/|\\/.test(filename)) + if (!RegExpPrototypeTest(/^\/|\\/, filename)) continue; - return kNodeModulesRE.test(filename); + return RegExpPrototypeTest(kNodeModulesRE, filename); } } return false; @@ -389,7 +400,7 @@ function once(callback) { return function(...args) { if (called) return; called = true; - callback.apply(this, args); + ReflectApply(callback, this, args); }; } diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 2c10f0c8929752..0bc46257e829fc 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -2,11 +2,12 @@ const { ArrayIsArray, + ArrayPrototypeFilter, + ArrayPrototypePush, BigIntPrototypeValueOf, BooleanPrototypeValueOf, DatePrototypeGetTime, Error, - Map, NumberIsNaN, NumberPrototypeValueOf, ObjectGetOwnPropertySymbols, @@ -16,10 +17,11 @@ const { ObjectPrototypeHasOwnProperty, ObjectPrototypePropertyIsEnumerable, ObjectPrototypeToString, - Set, + SafeMap, + SafeSet, StringPrototypeValueOf, SymbolPrototypeValueOf, - SymbolToStringTag, + TypedArrayPrototypeGetSymbolToStringTag, Uint8Array, } = primordials; @@ -126,7 +128,7 @@ function isEqualBoxedPrimitive(val1, val2) { function isIdenticalTypedArrayType(a, b) { // Fast path to reduce type checks in the common case. - const check = types[`is${a[SymbolToStringTag]}`]; + const check = types[`is${TypedArrayPrototypeGetSymbolToStringTag(a)}`]; if (check !== undefined && check(a)) { return check(b); } @@ -150,8 +152,9 @@ function isIdenticalTypedArrayType(a, b) { } /* c8 ignore next 4 */ assert.fail( - `Unknown TypedArray type checking ${a[SymbolToStringTag]} ${a}\n` + - `and ${b[SymbolToStringTag]} ${b}` + 'Unknown TypedArray type checking ' + + `${TypedArrayPrototypeGetSymbolToStringTag(a)} ${a}\n` + + `and ${TypedArrayPrototypeGetSymbolToStringTag(b)} ${b}` ); } @@ -291,7 +294,10 @@ function innerDeepEqual(val1, val2, strict, memos) { } function getEnumerables(val, keys) { - return keys.filter((k) => ObjectPrototypePropertyIsEnumerable(val, k)); + return ArrayPrototypeFilter( + keys, + (k) => ObjectPrototypePropertyIsEnumerable(val, k) + ); } function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { @@ -330,7 +336,7 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { if (!ObjectPrototypePropertyIsEnumerable(val2, key)) { return false; } - aKeys.push(key); + ArrayPrototypePush(aKeys, key); count++; } else if (ObjectPrototypePropertyIsEnumerable(val2, key)) { return false; @@ -360,8 +366,8 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { // Use memos to handle cycles. if (memos === undefined) { memos = { - val1: new Map(), - val2: new Map(), + val1: new SafeMap(), + val2: new SafeMap(), position: 0 }; } else { @@ -458,7 +464,7 @@ function setEquiv(a, b, strict, memo) { // to check this improves the worst case scenario instead. if (typeof val === 'object' && val !== null) { if (set === null) { - set = new Set(); + set = new SafeSet(); } // If the specified value doesn't exist in the second set its an not null // object (or non strict only: a not matching primitive) we'll need to go @@ -475,7 +481,7 @@ function setEquiv(a, b, strict, memo) { } if (set === null) { - set = new Set(); + set = new SafeSet(); } set.add(val); } @@ -521,7 +527,7 @@ function mapEquiv(a, b, strict, memo) { for (const [key, item1] of a) { if (typeof key === 'object' && key !== null) { if (set === null) { - set = new Set(); + set = new SafeSet(); } set.add(key); } else { @@ -537,7 +543,7 @@ function mapEquiv(a, b, strict, memo) { if (!mapMightHaveLoosePrim(a, b, key, item1, memo)) return false; if (set === null) { - set = new Set(); + set = new SafeSet(); } set.add(key); } diff --git a/lib/internal/util/debuglog.js b/lib/internal/util/debuglog.js index 46d3ed5613246e..3dc7a5157d5e65 100644 --- a/lib/internal/util/debuglog.js +++ b/lib/internal/util/debuglog.js @@ -1,13 +1,15 @@ 'use strict'; const { + FunctionPrototype, FunctionPrototypeBind, ObjectCreate, ObjectDefineProperty, RegExp, RegExpPrototypeTest, SafeArrayIterator, - StringPrototypeToUpperCase + StringPrototypeToLowerCase, + StringPrototypeToUpperCase, } = primordials; const { inspect, format, formatWithOptions } = require('internal/util/inspect'); @@ -37,13 +39,13 @@ function initializeDebugEnv(debugEnv) { function emitWarningIfNeeded(set) { if ('HTTP' === set || 'HTTP2' === set) { process.emitWarning('Setting the NODE_DEBUG environment variable ' + - 'to \'' + set.toLowerCase() + '\' can expose sensitive ' + + 'to \'' + StringPrototypeToLowerCase(set) + '\' can expose sensitive ' + 'data (such as passwords, tokens and authentication headers) ' + 'in the resulting log.'); } } -function noop() {} +const noop = FunctionPrototype; function debuglogImpl(enabled, set) { if (debugImpls[set] === undefined) { diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 04b7b68c5d41c6..59f2b54013dcfa 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -3,6 +3,10 @@ const { Array, ArrayIsArray, + ArrayPrototypeFilter, + ArrayPrototypePush, + ArrayPrototypeSort, + ArrayPrototypeUnshift, BigIntPrototypeValueOf, BooleanPrototypeValueOf, DatePrototypeGetTime, @@ -12,7 +16,6 @@ const { FunctionPrototypeCall, FunctionPrototypeToString, JSONStringify, - Map, MapPrototypeGetSize, MapPrototypeEntries, MathFloor, @@ -39,14 +42,25 @@ const { ObjectPrototypePropertyIsEnumerable, ObjectSeal, ObjectSetPrototypeOf, - ReflectApply, RegExp, + RegExpPrototypeTest, RegExpPrototypeToString, SafeStringIterator, - Set, + SafeMap, + SafeSet, SetPrototypeGetSize, SetPrototypeValues, String, + StringPrototypeCharCodeAt, + StringPrototypeIncludes, + StringPrototypePadEnd, + StringPrototypePadStart, + StringPrototypeRepeat, + StringPrototypeReplace, + StringPrototypeSlice, + StringPrototypeSplit, + StringPrototypeToLowerCase, + StringPrototypeTrim, StringPrototypeValueOf, SymbolPrototypeToString, SymbolPrototypeValueOf, @@ -120,8 +134,11 @@ const { NativeModule } = require('internal/bootstrap/loaders'); let hexSlice; -const builtInObjects = new Set( - ObjectGetOwnPropertyNames(global).filter((e) => /^[A-Z][a-zA-Z0-9]+$/.test(e)) +const builtInObjects = new SafeSet( + ArrayPrototypeFilter( + ObjectGetOwnPropertyNames(global), + (e) => RegExpPrototypeTest(/^[A-Z][a-zA-Z0-9]+$/, e) + ) ); // https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot @@ -430,7 +447,7 @@ function addQuotes(str, quotes) { return `'${str}'`; } -const escapeFn = (str) => meta[str.charCodeAt(0)]; +const escapeFn = (str) => meta[StringPrototypeCharCodeAt(str)]; // Escape control characters, single quotes and the backslash. // This is similar to JSON stringify escaping. @@ -458,10 +475,10 @@ function strEscape(str) { } // Some magic numbers that worked out fine while benchmarking with v8 6.0 - if (str.length < 5000 && !escapeTest.test(str)) + if (str.length < 5000 && !RegExpPrototypeTest(escapeTest, str)) return addQuotes(str, singleQuote); if (str.length > 100) { - str = str.replace(escapeReplace, escapeFn); + str = StringPrototypeReplace(str, escapeReplace, escapeFn); return addQuotes(str, singleQuote); } @@ -477,14 +494,14 @@ function strEscape(str) { if (last === i) { result += meta[point]; } else { - result += `${str.slice(last, i)}${meta[point]}`; + result += `${StringPrototypeSlice(str, last, i)}${meta[point]}`; } last = i + 1; } } if (last !== lastIndex) { - result += str.slice(last); + result += StringPrototypeSlice(str, last); } return addQuotes(result, singleQuote); } @@ -588,7 +605,7 @@ function addPrototypeProperties(ctx, main, obj, recurseTimes, output) { } if (depth === 0) { - keySet = new Set(); + keySet = new SafeSet(); } else { keys.forEach((key) => keySet.add(key)); } @@ -661,7 +678,7 @@ function getKeys(value, showHidden) { } if (symbols.length !== 0) { const filter = (key) => ObjectPrototypePropertyIsEnumerable(value, key); - keys.push(...symbols.filter(filter)); + ArrayPrototypePush(keys, ...ArrayPrototypeFilter(symbols, filter)); } } return keys; @@ -751,7 +768,8 @@ function formatValue(ctx, value, recurseTimes, typedArray) { if (ctx.seen.includes(value)) { let index = 1; if (ctx.circular === undefined) { - ctx.circular = new Map([[value, index]]); + ctx.circular = new SafeMap(); + ctx.circular.set(value, index); } else { index = ctx.circular.get(value); if (index === undefined) { @@ -924,11 +942,11 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { `{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`; } braces[0] = `${prefix}{`; - keys.unshift('byteLength'); + ArrayPrototypeUnshift(keys, 'byteLength'); } else if (isDataView(value)) { braces[0] = `${getPrefix(constructor, tag, 'DataView')}{`; // .buffer goes last, it's not a primitive like the others. - keys.unshift('byteLength', 'byteOffset', 'buffer'); + ArrayPrototypeUnshift(keys, 'byteLength', 'byteOffset', 'buffer'); } else if (isPromise(value)) { braces[0] = `${getPrefix(constructor, tag, 'Promise')}{`; formatter = formatPromise; @@ -1072,7 +1090,7 @@ function getBoxedBase(value, ctx, keys, constructor, tag) { } if (keys.length !== 0 || ctx.stylize === stylizeNoColor) return base; - return ctx.stylize(base, type.toLowerCase()); + return ctx.stylize(base, StringPrototypeToLowerCase(type)); } function getClassBase(value, constructor, tag) { @@ -1287,11 +1305,11 @@ function groupArrayElements(ctx, output, value) { lineMaxLength += separatorSpace; maxLineLength[i] = lineMaxLength; } - let order = 'padStart'; + let order = StringPrototypePadStart; if (value !== undefined) { for (let i = 0; i < output.length; i++) { if (typeof value[i] !== 'number' && typeof value[i] !== 'bigint') { - order = 'padEnd'; + order = StringPrototypePadEnd; break; } } @@ -1307,21 +1325,21 @@ function groupArrayElements(ctx, output, value) { // done line by line as some lines might contain more colors than // others. const padding = maxLineLength[j - i] + output[j].length - dataLen[j]; - str += `${output[j]}, `[order](padding, ' '); + str += order(`${output[j]}, `, padding, ' '); } - if (order === 'padStart') { + if (order === StringPrototypePadStart) { const padding = maxLineLength[j - i] + output[j].length - dataLen[j] - separatorSpace; - str += output[j].padStart(padding, ' '); + str += StringPrototypePadStart(output[j], padding, ' '); } else { str += output[j]; } - tmp.push(str); + ArrayPrototypePush(tmp, str); } if (ctx.maxArrayLength < output.length) { - tmp.push(output[outputLength]); + ArrayPrototypePush(tmp, output[outputLength]); } output = tmp; } @@ -1458,8 +1476,9 @@ function formatArrayBuffer(ctx, value) { } if (hexSlice === undefined) hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice); - let str = hexSlice(buffer, 0, MathMin(ctx.maxArrayLength, buffer.length)) - .replace(/(.{2})/g, '$1 ').trim(); + let str = StringPrototypeTrim(StringPrototypeReplace( + hexSlice(buffer, 0, MathMin(ctx.maxArrayLength, buffer.length)), + /(.{2})/g, '$1 ')); const remaining = buffer.length - ctx.maxArrayLength; if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; @@ -1508,7 +1527,7 @@ function formatTypedArray(value, length, ctx, ignored, recurseTimes) { 'buffer' ]) { const str = formatValue(ctx, value[key], recurseTimes, true); - output.push(`[${key}]: ${str}`); + ArrayPrototypePush(output, `[${key}]: ${str}`); } ctx.indentationLvl -= 2; } @@ -1519,7 +1538,7 @@ function formatSet(value, ctx, ignored, recurseTimes) { const output = []; ctx.indentationLvl += 2; for (const v of value) { - output.push(formatValue(ctx, v, recurseTimes)); + ArrayPrototypePush(output, formatValue(ctx, v, recurseTimes)); } ctx.indentationLvl -= 2; return output; @@ -1539,7 +1558,7 @@ function formatMap(value, ctx, ignored, recurseTimes) { function formatSetIterInner(ctx, recurseTimes, entries, state) { const maxArrayLength = MathMax(ctx.maxArrayLength, 0); const maxLength = MathMin(maxArrayLength, entries.length); - let output = new Array(maxLength); + const output = new Array(maxLength); ctx.indentationLvl += 2; for (let i = 0; i < maxLength; i++) { output[i] = formatValue(ctx, entries[i], recurseTimes); @@ -1549,11 +1568,12 @@ function formatSetIterInner(ctx, recurseTimes, entries, state) { // Sort all entries to have a halfway reliable output (if more entries than // retrieved ones exist, we can not reliably return the same output) if the // output is not sorted anyway. - output = output.sort(); + ArrayPrototypeSort(output); } const remaining = entries.length - maxLength; if (remaining > 0) { - output.push(`... ${remaining} more item${remaining > 1 ? 's' : ''}`); + ArrayPrototypePush(output, + `... ${remaining} more item${remaining > 1 ? 's' : ''}`); } return output; } @@ -1661,7 +1681,7 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc, (ctx.getters === 'get' && desc.set === undefined) || (ctx.getters === 'set' && desc.set !== undefined))) { try { - const tmp = ReflectApply(desc.get, original, []); + const tmp = FunctionPrototypeCall(desc.get, original); ctx.indentationLvl += 2; if (tmp === null) { str = `${s(`[${label}:`, sp)} ${s('null', 'null')}${s(']', sp)}`; @@ -1688,11 +1708,16 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc, return str; } if (typeof key === 'symbol') { - const tmp = key.toString().replace(strEscapeSequencesReplacer, escapeFn); + const tmp = StringPrototypeReplace( + SymbolPrototypeToString(key), + strEscapeSequencesReplacer, escapeFn + ); name = `[${ctx.stylize(tmp, 'symbol')}]`; } else if (desc.enumerable === false) { - name = `[${key.replace(strEscapeSequencesReplacer, escapeFn)}]`; - } else if (keyStrRegExp.test(key)) { + const tmp = StringPrototypeReplace(key, + strEscapeSequencesReplacer, escapeFn); + name = `[${tmp}]`; + } else if (RegExpPrototypeTest(keyStrRegExp, key)) { name = ctx.stylize(key, 'name'); } else { name = ctx.stylize(strEscape(key), 'string'); @@ -1721,7 +1746,7 @@ function isBelowBreakLength(ctx, output, start, base) { } } // Do not line up properties on the same line if `base` contains line breaks. - return base === '' || !base.includes('\n'); + return base === '' || !StringPrototypeIncludes(base, '\n'); } function reduceToSingleString( @@ -1764,7 +1789,7 @@ function reduceToSingleString( } } // Line up each entry on an individual line. - const indentation = `\n${' '.repeat(ctx.indentationLvl)}`; + const indentation = `\n${StringPrototypeRepeat(' ', ctx.indentationLvl)}`; return `${base ? `${base} ` : ''}${braces[0]}${indentation} ` + `${join(output, `,${indentation} `)}${indentation}${braces[1]}`; } @@ -1774,7 +1799,7 @@ function reduceToSingleString( return `${braces[0]}${base ? ` ${base}` : ''} ${join(output, ', ')} ` + braces[1]; } - const indentation = ' '.repeat(ctx.indentationLvl); + const indentation = StringPrototypeRepeat(' ', ctx.indentationLvl); // If the opening "brace" is too large, like in the case of "Set {", // we need to force the first item to be on the next line or the // items will not line up correctly. @@ -1816,7 +1841,8 @@ function hasBuiltInToString(value) { builtInObjects.has(descriptor.value.name); } -const firstErrorLine = (error) => error.message.split('\n')[0]; +const firstErrorLine = (error) => + StringPrototypeSplit(error.message, '\n', 1)[0]; let CIRCULAR_ERROR_MESSAGE; function tryStringify(arg) { try { @@ -1864,8 +1890,8 @@ function formatWithOptionsInternal(inspectOptions, ...args) { let lastPos = 0; for (let i = 0; i < first.length - 1; i++) { - if (first.charCodeAt(i) === 37) { // '%' - const nextChar = first.charCodeAt(++i); + if (StringPrototypeCharCodeAt(first, i) === 37) { // '%' + const nextChar = StringPrototypeCharCodeAt(first, ++i); if (a + 1 !== args.length) { switch (nextChar) { case 115: // 's' @@ -1936,19 +1962,19 @@ function formatWithOptionsInternal(inspectOptions, ...args) { tempStr = ''; break; case 37: // '%' - str += first.slice(lastPos, i); + str += StringPrototypeSlice(first, lastPos, i); lastPos = i + 1; continue; default: // Any other character is not a correct placeholder continue; } if (lastPos !== i - 1) { - str += first.slice(lastPos, i - 1); + str += StringPrototypeSlice(first, lastPos, i - 1); } str += tempStr; lastPos = i + 1; } else if (nextChar === 37) { - str += first.slice(lastPos, i); + str += StringPrototypeSlice(first, lastPos, i); lastPos = i + 1; } } @@ -1957,7 +1983,7 @@ function formatWithOptionsInternal(inspectOptions, ...args) { a++; join = ' '; if (lastPos < first.length) { - str += first.slice(lastPos); + str += StringPrototypeSlice(first, lastPos); } } } @@ -2005,9 +2031,9 @@ if (internalBinding('config').hasIntl) { if (removeControlChars) str = stripVTControlCharacters(str); - str = str.normalize('NFC'); + str = StringPrototypeNormalize(str, 'NFC'); for (const char of new SafeStringIterator(str)) { - const code = char.codePointAt(0); + const code = StringPrototypeCodePointAt(char, 0); if (isFullWidthCodePoint(code)) { width += 2; } else if (!isZeroWidthCodePoint(code)) { diff --git a/lib/internal/util/inspector.js b/lib/internal/util/inspector.js index 8d413b116fd0f2..cf8651c33ad6d0 100644 --- a/lib/internal/util/inspector.js +++ b/lib/internal/util/inspector.js @@ -1,6 +1,8 @@ 'use strict'; const { + ArrayPrototypeConcat, + FunctionPrototypeBind, ObjectDefineProperty, ObjectKeys, } = primordials; @@ -27,8 +29,10 @@ function installConsoleExtensions(commandLineApi) { const { makeRequireFunction } = require('internal/modules/cjs/helpers'); const consoleAPIModule = new CJSModule(''); const cwd = tryGetCwd(); - consoleAPIModule.paths = - CJSModule._nodeModulePaths(cwd).concat(CJSModule.globalPaths); + consoleAPIModule.paths = ArrayPrototypeConcat( + CJSModule._nodeModulePaths(cwd), + CJSModule.globalPaths + ); commandLineApi.require = makeRequireFunction(consoleAPIModule); } @@ -40,9 +44,12 @@ function wrapConsole(consoleFromNode, consoleFromVM) { // then wrap these two methods into one. Native wrapper will preserve // the original stack. if (consoleFromNode.hasOwnProperty(key)) { - consoleFromNode[key] = consoleCall.bind(consoleFromNode, - consoleFromVM[key], - consoleFromNode[key]); + consoleFromNode[key] = FunctionPrototypeBind( + consoleCall, + consoleFromNode, + consoleFromVM[key], + consoleFromNode[key] + ); ObjectDefineProperty(consoleFromNode[key], 'name', { value: key }); diff --git a/lib/util.js b/lib/util.js index 2d8687ac9c569a..abd1f6e663610e 100644 --- a/lib/util.js +++ b/lib/util.js @@ -23,8 +23,16 @@ const { ArrayIsArray, + ArrayPrototypeJoin, + ArrayPrototypePop, Date, + DatePrototypeGetDate, + DatePrototypeGetHours, + DatePrototypeGetMinutes, + DatePrototypeGetMonth, + DatePrototypeGetSeconds, Error, + FunctionPrototypeBind, NumberIsSafeInteger, ObjectDefineProperties, ObjectDefineProperty, @@ -33,6 +41,7 @@ const { ObjectPrototypeToString, ObjectSetPrototypeOf, ReflectApply, + StringPrototypePadStart, } = primordials; const { @@ -110,7 +119,7 @@ function isPrimitive(arg) { } function pad(n) { - return n.toString().padStart(2, '0'); + return StringPrototypePadStart(n.toString(), 2, '0'); } const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', @@ -119,10 +128,12 @@ const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', // 26 Feb 16:19:34 function timestamp() { const d = new Date(); - const time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); + const t = ArrayPrototypeJoin([ + pad(DatePrototypeGetHours(d)), + pad(DatePrototypeGetMinutes(d)), + pad(DatePrototypeGetSeconds(d)), + ], ':'); + return `${DatePrototypeGetDate(d)} ${months[DatePrototypeGetMonth(d)]} ${t}`; } let console; @@ -201,11 +212,11 @@ function callbackify(original) { // the promise is actually somehow related to the callback's execution // and that the callback throwing will reject the promise. function callbackified(...args) { - const maybeCb = args.pop(); + const maybeCb = ArrayPrototypePop(args); if (typeof maybeCb !== 'function') { throw new ERR_INVALID_ARG_TYPE('last argument', 'Function', maybeCb); } - const cb = (...args) => { ReflectApply(maybeCb, this, args); }; + const cb = FunctionPrototypeBind(maybeCb, this); // In true node style we process the callback on `nextTick` with all the // implications (stack, `uncaughtException`, `async_hooks`) ReflectApply(original, this, args) From 517a05b44869b273c000a6c62446e2d1dd50773c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 28 Dec 2020 16:39:35 +0100 Subject: [PATCH 2/2] fixup! util: refactor to use more primordials --- lib/internal/util/inspect.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 59f2b54013dcfa..2672ccb50bfa1c 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -52,7 +52,9 @@ const { SetPrototypeValues, String, StringPrototypeCharCodeAt, + StringPrototypeCodePointAt, StringPrototypeIncludes, + StringPrototypeNormalize, StringPrototypePadEnd, StringPrototypePadStart, StringPrototypeRepeat,