From 642d699fc261591d84f2b882a5327d7023cc8801 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 27 Jun 2022 17:16:06 +0200 Subject: [PATCH] lib: refactor to avoid unsafe regex primordials PR-URL: https://github.com/nodejs/node/pull/43475 Reviewed-By: Geoffrey Booth Reviewed-By: Stephen Belanger --- lib/_http_client.js | 4 +- lib/_http_common.js | 6 +- lib/_http_outgoing.js | 6 +- lib/_http_server.js | 8 +- lib/_tls_wrap.js | 17 ++-- lib/assert.js | 15 ++-- lib/buffer.js | 6 +- lib/child_process.js | 4 +- lib/internal/blob.js | 6 +- lib/internal/cluster/primary.js | 6 +- lib/internal/console/constructor.js | 4 +- lib/internal/debugger/inspect.js | 11 ++- lib/internal/debugger/inspect_repl.js | 8 +- lib/internal/dns/utils.js | 10 +-- lib/internal/errors.js | 10 +-- lib/internal/fs/utils.js | 4 +- lib/internal/http2/core.js | 4 +- lib/internal/main/print_help.js | 13 +-- lib/internal/modules/cjs/loader.js | 10 +-- lib/internal/modules/esm/formats.js | 6 +- lib/internal/modules/esm/module_job.js | 21 +++-- lib/internal/modules/esm/resolve.js | 13 +-- lib/internal/policy/manifest.js | 17 ++-- lib/internal/policy/sri.js | 3 +- lib/internal/process/per_thread.js | 4 +- lib/internal/readline/interface.js | 20 ++--- lib/internal/readline/utils.js | 11 ++- lib/internal/repl/history.js | 4 +- lib/internal/repl/utils.js | 14 ++-- .../source_map/prepare_stack_trace.js | 4 +- lib/internal/source_map/source_map_cache.js | 8 +- lib/internal/tty.js | 10 +-- lib/internal/util.js | 5 +- lib/internal/util/inspect.js | 26 +++--- lib/internal/validators.js | 4 +- lib/internal/worker.js | 4 +- lib/repl.js | 79 ++++++++++--------- lib/tls.js | 9 +-- test/parallel/test-errors-systemerror.js | 2 +- 39 files changed, 209 insertions(+), 207 deletions(-) diff --git a/lib/_http_client.js b/lib/_http_client.js index 003f08a774cb0b..9c50af5a57e7d1 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -31,7 +31,7 @@ const { ObjectKeys, ObjectSetPrototypeOf, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, String, StringPrototypeCharCodeAt, StringPrototypeIncludes, @@ -169,7 +169,7 @@ function ClientRequest(input, options, cb) { if (options.path) { const path = String(options.path); - if (RegExpPrototypeTest(INVALID_PATH_REGEX, path)) + if (RegExpPrototypeExec(INVALID_PATH_REGEX, path) !== null) throw new ERR_UNESCAPED_CHARACTERS('Request path'); } diff --git a/lib/_http_common.js b/lib/_http_common.js index d2819492aa6f23..0b324ae231e6ff 100644 --- a/lib/_http_common.js +++ b/lib/_http_common.js @@ -24,7 +24,7 @@ const { MathMin, Symbol, - RegExpPrototypeTest, + RegExpPrototypeExec, } = primordials; const { setImmediate } = require('timers'); @@ -218,7 +218,7 @@ const tokenRegExp = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/; * See https://tools.ietf.org/html/rfc7230#section-3.2.6 */ function checkIsHttpToken(val) { - return RegExpPrototypeTest(tokenRegExp, val); + return RegExpPrototypeExec(tokenRegExp, val) !== null; } const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; @@ -229,7 +229,7 @@ const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; * field-vchar = VCHAR / obs-text */ function checkInvalidHeaderChar(val) { - return RegExpPrototypeTest(headerCharRegex, val); + return RegExpPrototypeExec(headerCharRegex, val) !== null; } function cleanParser(parser) { diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index e02b86e8a84929..006ac437a14938 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -33,7 +33,7 @@ const { ObjectValues, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeSet, StringPrototypeToLowerCase, Symbol, @@ -542,7 +542,7 @@ function matchHeader(self, state, field, value) { case 'connection': state.connection = true; self._removedConnection = false; - if (RegExpPrototypeTest(RE_CONN_CLOSE, value)) + if (RegExpPrototypeExec(RE_CONN_CLOSE, value) !== null) self._last = true; else self.shouldKeepAlive = true; @@ -550,7 +550,7 @@ function matchHeader(self, state, field, value) { case 'transfer-encoding': state.te = true; self._removedTE = false; - if (RegExpPrototypeTest(RE_TE_CHUNKED, value)) + if (RegExpPrototypeExec(RE_TE_CHUNKED, value) !== null) self.chunkedEncoding = true; break; case 'content-length': diff --git a/lib/_http_server.js b/lib/_http_server.js index 17f0fb7010b2a3..80039b3e7a26b6 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -26,7 +26,7 @@ const { Error, ObjectKeys, ObjectSetPrototypeOf, - RegExpPrototypeTest, + RegExpPrototypeExec, Symbol, SymbolFor, } = primordials; @@ -191,8 +191,8 @@ function ServerResponse(req) { this._expect_continue = false; if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) { - this.useChunkedEncodingByDefault = RegExpPrototypeTest(chunkExpression, - req.headers.te); + this.useChunkedEncodingByDefault = RegExpPrototypeExec(chunkExpression, + req.headers.te) !== null; this.shouldKeepAlive = false; } @@ -957,7 +957,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { } else if (req.headers.expect !== undefined) { handled = true; - if (RegExpPrototypeTest(continueExpression, req.headers.expect)) { + if (RegExpPrototypeExec(continueExpression, req.headers.expect) !== null) { res._expect_continue = true; if (server.listenerCount('checkContinue') > 0) { diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index be2c82698715e7..eda0c0987f9446 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -31,8 +31,9 @@ const { ObjectSetPrototypeOf, ReflectApply, RegExp, - RegExpPrototypeTest, - StringPrototypeReplace, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, + StringPrototypeReplaceAll, StringPrototypeSlice, Symbol, SymbolFor, @@ -426,8 +427,8 @@ function onerror(err) { owner.destroy(err); } else if (owner._tlsOptions?.isServer && owner._rejectUnauthorized && - RegExpPrototypeTest(/peer did not return a certificate/, - err.message)) { + RegExpPrototypeExec(/peer did not return a certificate/, + err.message) !== null) { // Ignore server's authorization errors owner.destroy(); } else { @@ -1448,9 +1449,9 @@ Server.prototype.addContext = function(servername, context) { throw new ERR_TLS_REQUIRED_SERVER_NAME(); } - const re = new RegExp('^' + StringPrototypeReplace( - StringPrototypeReplace(servername, /([.^$+?\-\\[\]{}])/g, '\\$1'), - /\*/g, '[^.]*' + const re = new RegExp('^' + StringPrototypeReplaceAll( + RegExpPrototypeSymbolReplace(/([.^$+?\-\\[\]{}])/g, servername, '\\$1'), + '*', '[^.]*' ) + '$'); ArrayPrototypePush(this._contexts, [re, tls.createSecureContext(context).context]); @@ -1474,7 +1475,7 @@ function SNICallback(servername, callback) { for (let i = contexts.length - 1; i >= 0; --i) { const elem = contexts[i]; - if (RegExpPrototypeTest(elem[0], servername)) { + if (RegExpPrototypeExec(elem[0], servername) !== null) { callback(null, elem[1]); return; } diff --git a/lib/assert.js b/lib/assert.js index 2c7cf369a87af2..fc3127f3bf4214 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -35,7 +35,8 @@ const { ObjectKeys, ObjectPrototypeIsPrototypeOf, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, SafeMap, String, StringPrototypeCharCodeAt, @@ -345,7 +346,7 @@ function getErrMessage(message, fn) { // Always normalize indentation, otherwise the message could look weird. if (StringPrototypeIncludes(message, '\n')) { if (EOL === '\r\n') { - message = StringPrototypeReplace(message, /\r\n/g, '\n'); + message = RegExpPrototypeSymbolReplace(/\r\n/g, message, '\n'); } const frames = StringPrototypeSplit(message, '\n'); message = ArrayPrototypeShift(frames); @@ -606,7 +607,7 @@ class Comparison { if (actual !== undefined && typeof actual[key] === 'string' && isRegExp(obj[key]) && - RegExpPrototypeTest(obj[key], actual[key])) { + RegExpPrototypeExec(obj[key], actual[key]) !== null) { this[key] = actual[key]; } else { this[key] = obj[key]; @@ -652,7 +653,7 @@ function expectedException(actual, expected, message, fn) { // Handle regular expressions. if (isRegExp(expected)) { const str = String(actual); - if (RegExpPrototypeTest(expected, str)) + if (RegExpPrototypeExec(expected, str) !== null) return; if (!message) { @@ -687,7 +688,7 @@ function expectedException(actual, expected, message, fn) { for (const key of keys) { if (typeof actual[key] === 'string' && isRegExp(expected[key]) && - RegExpPrototypeTest(expected[key], actual[key])) { + RegExpPrototypeExec(expected[key], actual[key]) !== null) { continue; } compareExceptionKey(actual, expected, key, message, keys, fn); @@ -851,7 +852,7 @@ function hasMatchingError(actual, expected) { if (typeof expected !== 'function') { if (isRegExp(expected)) { const str = String(actual); - return RegExpPrototypeTest(expected, str); + return RegExpPrototypeExec(expected, str) !== null; } throw new ERR_INVALID_ARG_TYPE( 'expected', ['Function', 'RegExp'], expected @@ -1000,7 +1001,7 @@ function internalMatch(string, regexp, message, fn) { } const match = fn === assert.match; if (typeof string !== 'string' || - RegExpPrototypeTest(regexp, string) !== match) { + RegExpPrototypeExec(regexp, string) !== null !== match) { if (message instanceof Error) { throw message; } diff --git a/lib/buffer.js b/lib/buffer.js index 96d303d3b2f588..874b9b5595985c 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -37,8 +37,8 @@ const { ObjectDefineProperties, ObjectDefineProperty, ObjectSetPrototypeOf, + RegExpPrototypeSymbolReplace, StringPrototypeCharCodeAt, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeToLowerCase, StringPrototypeTrim, @@ -840,8 +840,8 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) { const max = INSPECT_MAX_BYTES; const actualMax = MathMin(max, this.length); const remaining = this.length - max; - let str = StringPrototypeTrim(StringPrototypeReplace( - this.hexSlice(0, actualMax), /(.{2})/g, '$1 ')); + let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace( + /(.{2})/g, this.hexSlice(0, actualMax), '$1 ')); if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; // Inspect special properties as well, if possible. diff --git a/lib/child_process.js b/lib/child_process.js index 388cbc68dbd0b0..77b9ff35ff6ea7 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -36,7 +36,7 @@ const { ObjectAssign, ObjectDefineProperty, ObjectPrototypeHasOwnProperty, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeSet, StringPrototypeSlice, StringPrototypeToUpperCase, @@ -592,7 +592,7 @@ function normalizeSpawnArguments(file, args, options) { else file = process.env.comspec || 'cmd.exe'; // '/d /s /c' is used only for cmd.exe. - if (RegExpPrototypeTest(/^(?:.*\\)?cmd(?:\.exe)?$/i, file)) { + if (RegExpPrototypeExec(/^(?:.*\\)?cmd(?:\.exe)?$/i, file) !== null) { args = ['/d', '/s', '/c', `"${command}"`]; windowsVerbatimArguments = true; } else { diff --git a/lib/internal/blob.js b/lib/internal/blob.js index 6607eccf490980..4fef013f087cec 100644 --- a/lib/internal/blob.js +++ b/lib/internal/blob.js @@ -9,8 +9,8 @@ const { PromiseReject, SafePromisePrototypeFinally, ReflectConstruct, + RegExpPrototypeExec, RegExpPrototypeSymbolReplace, - RegExpPrototypeTest, StringPrototypeToLowerCase, StringPrototypeSplit, Symbol, @@ -164,7 +164,7 @@ class Blob { this[kLength] = length; type = `${type}`; - this[kType] = RegExpPrototypeTest(disallowedTypeCharacters, type) ? + this[kType] = RegExpPrototypeExec(disallowedTypeCharacters, type) !== null ? '' : StringPrototypeToLowerCase(type); // eslint-disable-next-line no-constructor-return @@ -246,7 +246,7 @@ class Blob { end |= 0; contentType = `${contentType}`; - if (RegExpPrototypeTest(disallowedTypeCharacters, contentType)) { + if (RegExpPrototypeExec(disallowedTypeCharacters, contentType) !== null) { contentType = ''; } else { contentType = StringPrototypeToLowerCase(contentType); diff --git a/lib/internal/cluster/primary.js b/lib/internal/cluster/primary.js index 69e97eb8a6837f..3940d094e7b76d 100644 --- a/lib/internal/cluster/primary.js +++ b/lib/internal/cluster/primary.js @@ -6,7 +6,7 @@ const { ArrayPrototypeSome, ObjectKeys, ObjectValues, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeMap, StringPrototypeStartsWith, } = primordials; @@ -121,8 +121,8 @@ function createWorkerProcess(id, env) { const nodeOptions = process.env.NODE_OPTIONS || ''; if (ArrayPrototypeSome(execArgv, - (arg) => RegExpPrototypeTest(debugArgRegex, arg)) || - RegExpPrototypeTest(debugArgRegex, nodeOptions)) { + (arg) => RegExpPrototypeExec(debugArgRegex, arg) !== null) || + RegExpPrototypeExec(debugArgRegex, nodeOptions) !== null) { let inspectPort; if ('inspectPort' in cluster.settings) { if (typeof cluster.settings.inspectPort === 'function') diff --git a/lib/internal/console/constructor.js b/lib/internal/console/constructor.js index bba2784bb92d44..d8434f2311a375 100644 --- a/lib/internal/console/constructor.js +++ b/lib/internal/console/constructor.js @@ -24,13 +24,13 @@ const { ReflectApply, ReflectConstruct, ReflectOwnKeys, + RegExpPrototypeSymbolReplace, SafeArrayIterator, SafeMap, SafeWeakMap, StringPrototypeIncludes, StringPrototypePadStart, StringPrototypeRepeat, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, Symbol, @@ -279,7 +279,7 @@ ObjectDefineProperties(Console.prototype, { if (groupIndent.length !== 0) { if (StringPrototypeIncludes(string, '\n')) { - string = StringPrototypeReplace(string, /\n/g, `\n${groupIndent}`); + string = RegExpPrototypeSymbolReplace(/\n/g, string, `\n${groupIndent}`); } string = groupIndent + string; } diff --git a/lib/internal/debugger/inspect.js b/lib/internal/debugger/inspect.js index cb5ffa8cef5720..e5211c285bd5eb 100644 --- a/lib/internal/debugger/inspect.js +++ b/lib/internal/debugger/inspect.js @@ -15,9 +15,8 @@ const { PromisePrototypeThen, PromiseResolve, Proxy, - RegExpPrototypeSymbolMatch, + RegExpPrototypeExec, RegExpPrototypeSymbolSplit, - RegExpPrototypeTest, StringPrototypeEndsWith, StringPrototypeSplit, } = primordials; @@ -91,7 +90,7 @@ async function runScript(script, scriptArgs, inspectHost, inspectPort, return new Promise((resolve) => { function waitForListenHint(text) { output += text; - const debug = RegExpPrototypeSymbolMatch(debugRegex, output); + const debug = RegExpPrototypeExec(debugRegex, output); if (debug) { const host = debug[1]; const port = Number(debug[2]); @@ -282,8 +281,8 @@ function parseArgv(args) { let script = target; let scriptArgs = args; - const hostMatch = RegExpPrototypeSymbolMatch(/^([^:]+):(\d+)$/, target); - const portMatch = RegExpPrototypeSymbolMatch(/^--port=(\d+)$/, target); + const hostMatch = RegExpPrototypeExec(/^([^:]+):(\d+)$/, target); + const portMatch = RegExpPrototypeExec(/^--port=(\d+)$/, target); if (hostMatch) { // Connecting to remote debugger @@ -296,7 +295,7 @@ function parseArgv(args) { port = Number(portMatch[1]); script = args[0]; scriptArgs = ArrayPrototypeSlice(args, 1); - } else if (args.length === 1 && RegExpPrototypeTest(/^\d+$/, args[0]) && + } else if (args.length === 1 && RegExpPrototypeExec(/^\d+$/, args[0]) !== null && target === '-p') { // Start debugger against a given pid const pid = Number(args[0]); diff --git a/lib/internal/debugger/inspect_repl.js b/lib/internal/debugger/inspect_repl.js index 1a40b1757524e0..bfc11990e0ddf0 100644 --- a/lib/internal/debugger/inspect_repl.js +++ b/lib/internal/debugger/inspect_repl.js @@ -28,7 +28,7 @@ const { PromiseResolve, ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, - RegExpPrototypeSymbolMatch, + RegExpPrototypeExec, RegExpPrototypeSymbolReplace, SafeMap, SafePromiseAll, @@ -113,7 +113,7 @@ takeHeapSnapshot(filepath = 'node.heapsnapshot') const FUNCTION_NAME_PATTERN = /^(?:function\*? )?([^(\s]+)\(/; function extractFunctionName(description) { const fnNameMatch = - RegExpPrototypeSymbolMatch(FUNCTION_NAME_PATTERN, description); + RegExpPrototypeExec(FUNCTION_NAME_PATTERN, description); return fnNameMatch ? `: ${fnNameMatch[1]}` : ''; } @@ -170,7 +170,7 @@ function markSourceColumn(sourceText, position, useColors) { function extractErrorMessage(stack) { if (!stack) return ''; - const m = RegExpPrototypeSymbolMatch(/^\w+: ([^\n]+)/, stack); + const m = RegExpPrototypeExec(/^\w+: ([^\n]+)/, stack); return m?.[1] ?? stack; } @@ -574,7 +574,7 @@ function createRepl(inspector) { function prepareControlCode(input) { if (input === '\n') return lastCommand; // Add parentheses: exec process.title => exec("process.title"); - const match = RegExpPrototypeSymbolMatch(/^\s*(?:exec|p)\s+([^\n]*)/, input); + const match = RegExpPrototypeExec(/^\s*(?:exec|p)\s+([^\n]*)/, input); if (match) { lastCommand = `exec(${JSONStringify(match[1])})`; } else { diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js index 511be2bb457b34..06de00174b709e 100644 --- a/lib/internal/dns/utils.js +++ b/lib/internal/dns/utils.js @@ -7,8 +7,8 @@ const { ArrayPrototypePush, FunctionPrototypeBind, NumberParseInt, - StringPrototypeMatch, - StringPrototypeReplace, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, } = primordials; const errors = require('internal/errors'); @@ -86,7 +86,7 @@ class Resolver { if (ipVersion !== 0) return ArrayPrototypePush(newSet, [ipVersion, serv, IANA_DNS_PORT]); - const match = StringPrototypeMatch(serv, IPv6RE); + const match = RegExpPrototypeExec(IPv6RE, serv); // Check for an IPv6 in brackets. if (match) { @@ -94,13 +94,13 @@ class Resolver { if (ipVersion !== 0) { const port = NumberParseInt( - StringPrototypeReplace(serv, addrSplitRE, '$2')) || IANA_DNS_PORT; + RegExpPrototypeSymbolReplace(addrSplitRE, serv, '$2')) || IANA_DNS_PORT; return ArrayPrototypePush(newSet, [ipVersion, match[1], port]); } } // addr::port - const addrSplitMatch = StringPrototypeMatch(serv, addrSplitRE); + const addrSplitMatch = RegExpPrototypeExec(addrSplitRE, serv); if (addrSplitMatch) { const hostIP = addrSplitMatch[1]; diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 9714faeeba5ecf..80d894d124c682 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -42,14 +42,13 @@ const { ObjectPrototypeHasOwnProperty, RangeError, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeArrayIterator, SafeMap, SafeWeakMap, String, StringPrototypeEndsWith, StringPrototypeIncludes, - StringPrototypeMatch, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -438,8 +437,9 @@ function getMessage(key, args, self) { return ReflectApply(msg, self, args); } - const expectedLength = - (StringPrototypeMatch(msg, /%[dfijoOs]/g) || []).length; + const regex = /%[dfijoOs]/g; + let expectedLength = 0; + while (RegExpPrototypeExec(regex, msg) !== null) expectedLength++; assert( expectedLength === args.length, `Code: ${key}; The provided arguments length (${args.length}) does not ` + @@ -1200,7 +1200,7 @@ E('ERR_INVALID_ARG_TYPE', 'All expected entries have to be of type string'); if (ArrayPrototypeIncludes(kTypes, value)) { ArrayPrototypePush(types, StringPrototypeToLowerCase(value)); - } else if (RegExpPrototypeTest(classRegExp, value)) { + } else if (RegExpPrototypeExec(classRegExp, value) !== null) { ArrayPrototypePush(instances, value); } else { assert(value !== 'object', diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index 2e5e21342c8797..d1e521426f0bd3 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -18,9 +18,9 @@ const { ObjectSetPrototypeOf, ReflectApply, ReflectOwnKeys, + RegExpPrototypeSymbolReplace, StringPrototypeEndsWith, StringPrototypeIncludes, - StringPrototypeReplace, Symbol, TypedArrayPrototypeIncludes, } = primordials; @@ -397,7 +397,7 @@ function preprocessSymlinkDestination(path, type, linkPath) { return pathModule.toNamespacedPath(path); } // Windows symlinks don't tolerate forward slashes. - return StringPrototypeReplace(path, /\//g, '\\'); + return RegExpPrototypeSymbolReplace(/\//g, path, '\\'); } // Constructor for file stats. diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index ab5b2d11900093..16503ba8e098ed 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -23,7 +23,7 @@ const { ReflectGet, ReflectGetPrototypeOf, ReflectSet, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeArrayIterator, SafeMap, SafeSet, @@ -1660,7 +1660,7 @@ class ServerHttp2Session extends Http2Session { } validateString(alt, 'alt'); - if (!RegExpPrototypeTest(kQuotedString, alt)) + if (RegExpPrototypeExec(kQuotedString, alt) === null) throw new ERR_INVALID_CHAR('alt'); // Max length permitted for ALTSVC diff --git a/lib/internal/main/print_help.js b/lib/internal/main/print_help.js index 6aa422c657b2d0..a2cee4b0567649 100644 --- a/lib/internal/main/print_help.js +++ b/lib/internal/main/print_help.js @@ -8,11 +8,11 @@ const { MathMax, ObjectKeys, RegExp, + RegExpPrototypeSymbolReplace, StringPrototypeLocaleCompare, StringPrototypeSlice, StringPrototypeTrimLeft, StringPrototypeRepeat, - StringPrototypeReplace, SafeMap, } = primordials; @@ -77,14 +77,15 @@ const envVars = new SafeMap(ArrayPrototypeConcat([ function indent(text, depth) { - return StringPrototypeReplace(text, /^/gm, StringPrototypeRepeat(' ', depth)); + return RegExpPrototypeSymbolReplace(/^/gm, text, StringPrototypeRepeat(' ', depth)); } function fold(text, width) { - return StringPrototypeReplace(text, - new RegExp(`([^\n]{0,${width}})( |$)`, 'g'), - (_, newLine, end) => - newLine + (end === ' ' ? '\n' : '')); + return RegExpPrototypeSymbolReplace( + new RegExp(`([^\n]{0,${width}})( |$)`, 'g'), + text, + (_, newLine, end) => newLine + (end === ' ' ? '\n' : '') + ); } function getArgDescription(type) { diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 163fd00bd57995..f1971c40a447b2 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -50,7 +50,6 @@ const { ReflectApply, ReflectSet, RegExpPrototypeExec, - RegExpPrototypeTest, SafeMap, SafeSet, SafeWeakMap, @@ -60,7 +59,6 @@ const { StringPrototypeEndsWith, StringPrototypeLastIndexOf, StringPrototypeIndexOf, - StringPrototypeMatch, StringPrototypeRepeat, StringPrototypeSlice, StringPrototypeSplit, @@ -81,7 +79,7 @@ const { maybeCacheSourceMap, } = require('internal/source_map/source_map_cache'); const { pathToFileURL, fileURLToPath, isURLInstance } = require('internal/url'); -const { deprecate } = require('internal/util'); +const { deprecate, kEmptyObject } = require('internal/util'); const vm = require('vm'); const assert = require('internal/assert'); const fs = require('fs'); @@ -485,7 +483,7 @@ const EXPORTS_PATTERN = /^((?:@[^/\\%]+\/)?[^./\\%][^/\\%]*)(\/.*)?$/; function resolveExports(nmPath, request) { // The implementation's behavior is meant to mirror resolution in ESM. const { 1: name, 2: expansion = '' } = - StringPrototypeMatch(request, EXPORTS_PATTERN) || []; + RegExpPrototypeExec(EXPORTS_PATTERN, request) || kEmptyObject; if (!name) return; const pkgPath = path.resolve(nmPath, name); @@ -522,7 +520,7 @@ Module._findPath = function(request, paths, isMain) { StringPrototypeCharCodeAt(request, request.length - 1) === CHAR_FORWARD_SLASH; if (!trailingSlash) { - trailingSlash = RegExpPrototypeTest(trailingSlashRegex, request); + trailingSlash = RegExpPrototypeExec(trailingSlashRegex, request) !== null; } // For each path @@ -963,7 +961,7 @@ Module._resolveFilename = function(request, parent, isMain, options) { function finalizeEsmResolution(match, request, parentPath, pkgPath) { const { resolved, exact } = match; - if (RegExpPrototypeTest(encodedSepRegEx, resolved)) + if (RegExpPrototypeExec(encodedSepRegEx, resolved) !== null) throw new ERR_INVALID_MODULE_SPECIFIER( resolved, 'must not include encoded "/" or "\\" characters', parentPath); const filename = fileURLToPath(resolved); diff --git a/lib/internal/modules/esm/formats.js b/lib/internal/modules/esm/formats.js index f9da01402e7f62..f71e6ae689c277 100644 --- a/lib/internal/modules/esm/formats.js +++ b/lib/internal/modules/esm/formats.js @@ -1,7 +1,7 @@ 'use strict'; const { - RegExpPrototypeTest, + RegExpPrototypeExec, } = primordials; const { getOptionValue } = require('internal/options'); @@ -35,10 +35,10 @@ if (experimentalWasmModules) { */ function mimeToFormat(mime) { if ( - RegExpPrototypeTest( + RegExpPrototypeExec( /\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i, mime - ) + ) !== null ) return 'module'; if (mime === 'application/json') return 'json'; if (experimentalWasmModules && mime === 'application/wasm') return 'wasm'; diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index 2df2c40495e7bc..3a2ec7343a1d53 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -10,12 +10,11 @@ const { PromiseResolve, PromisePrototypeCatch, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, SafePromiseAll, SafeSet, StringPrototypeIncludes, - StringPrototypeMatch, - StringPrototypeReplace, StringPrototypeSplit, StringPrototypeStartsWith, } = primordials; @@ -133,14 +132,14 @@ class ModuleJob { StringPrototypeIncludes(e.message, ' does not provide an export named')) { const splitStack = StringPrototypeSplit(e.stack, '\n'); - const parentFileUrl = StringPrototypeReplace( - splitStack[0], + const parentFileUrl = RegExpPrototypeSymbolReplace( /:\d+$/, + splitStack[0], '' ); - const { 1: childSpecifier, 2: name } = StringPrototypeMatch( - e.message, - /module '(.*)' does not provide an export named '(.+)'/); + const { 1: childSpecifier, 2: name } = RegExpPrototypeExec( + /module '(.*)' does not provide an export named '(.+)'/, + e.message); const { url: childFileURL } = await this.loader.resolve( childSpecifier, parentFileUrl, ); @@ -161,9 +160,9 @@ class ModuleJob { // line which causes the error. For multi-line import statements we // cannot generate an equivalent object destructuring assignment by // just parsing the error stack. - const oneLineNamedImports = StringPrototypeMatch(importStatement, /{.*}/); + const oneLineNamedImports = RegExpPrototypeExec(/{.*}/, importStatement); const destructuringAssignment = oneLineNamedImports && - StringPrototypeReplace(oneLineNamedImports, /\s+as\s+/g, ': '); + RegExpPrototypeSymbolReplace(/\s+as\s+/g, oneLineNamedImports, ': '); e.message = `Named export '${name}' not found. The requested module` + ` '${childSpecifier}' is a CommonJS module, which may not support` + ' all module.exports as named exports.\nCommonJS modules can ' + @@ -203,7 +202,7 @@ class ModuleJob { const packageConfig = StringPrototypeStartsWith(this.module.url, 'file://') && - RegExpPrototypeTest(/\.js(\?[^#]*)?(#.*)?$/, this.module.url) && + RegExpPrototypeExec(/\.js(\?[^#]*)?(#.*)?$/, this.module.url) !== null && require('internal/modules/esm/resolve') .getPackageScopeConfig(this.module.url); if (packageConfig.type === 'module') { diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index e9147aa83de800..fc5dcd6863dc35 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -13,7 +13,6 @@ const { RegExp, RegExpPrototypeExec, RegExpPrototypeSymbolReplace, - RegExpPrototypeTest, SafeMap, SafeSet, String, @@ -21,6 +20,7 @@ const { StringPrototypeIncludes, StringPrototypeIndexOf, StringPrototypeLastIndexOf, + StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -394,7 +394,7 @@ const encodedSepRegEx = /%2F|%5C/i; * @returns {URL | undefined} */ function finalizeResolution(resolved, base, preserveSymlinks) { - if (RegExpPrototypeTest(encodedSepRegEx, resolved.pathname)) + if (RegExpPrototypeExec(encodedSepRegEx, resolved.pathname) !== null) throw new ERR_INVALID_MODULE_SPECIFIER( resolved.pathname, 'must not include encoded "/" or "\\" characters', fileURLToPath(base)); @@ -523,7 +523,7 @@ function resolvePackageTargetString( throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); } - if (RegExpPrototypeTest(invalidSegmentRegEx, StringPrototypeSlice(target, 2))) + if (RegExpPrototypeExec(invalidSegmentRegEx, StringPrototypeSlice(target, 2)) !== null) throwInvalidPackageTarget(match, target, packageJSONUrl, internal, base); const resolved = new URL(target, packageJSONUrl); @@ -535,8 +535,11 @@ function resolvePackageTargetString( if (subpath === '') return resolved; - if (RegExpPrototypeTest(invalidSegmentRegEx, subpath)) - throwInvalidSubpath(match + subpath, packageJSONUrl, internal, base); + if (RegExpPrototypeExec(invalidSegmentRegEx, subpath) !== null) { + const request = pattern ? + StringPrototypeReplace(match, '*', () => subpath) : match + subpath; + throwInvalidSubpath(request, packageJSONUrl, internal, base); + } if (pattern) { return new URL( diff --git a/lib/internal/policy/manifest.js b/lib/internal/policy/manifest.js index a0cd9707a2c7d5..062e1ba219bbe8 100644 --- a/lib/internal/policy/manifest.js +++ b/lib/internal/policy/manifest.js @@ -10,12 +10,11 @@ const { ObjectKeys, ObjectSetPrototypeOf, RegExpPrototypeExec, - RegExpPrototypeTest, SafeMap, SafeSet, + RegExpPrototypeSymbolReplace, StringPrototypeEndsWith, StringPrototypeStartsWith, - StringPrototypeReplace, Symbol, uncurryThis, } = primordials; @@ -202,7 +201,7 @@ class DependencyMapperInstance { let ret; if (parsedURLs && parsedURLs.has(to)) { ret = parsedURLs.get(to); - } else if (RegExpPrototypeTest(kRelativeURLStringPattern, to)) { + } else if (RegExpPrototypeExec(kRelativeURLStringPattern, to) !== null) { ret = resolve(to, manifest.href); } else { ret = resolve(to); @@ -301,7 +300,7 @@ function findScopeHREF(href, scopeStore, allowSame) { if (href !== '') { // default URL parser does some stuff to special urls... skip if this is // just the protocol - if (RegExpPrototypeTest(/^[^:]*[:]$/, href)) { + if (RegExpPrototypeExec(/^[^:]*[:]$/, href) !== null) { protocol = href; } else { let currentURL = new URL(href); @@ -669,7 +668,7 @@ module.exports = ObjectFreeze({ Manifest }); */ function canonicalizeSpecifier(specifier, base) { try { - if (RegExpPrototypeTest(kRelativeURLStringPattern, specifier)) { + if (RegExpPrototypeExec(kRelativeURLStringPattern, specifier) !== null) { return resolve(specifier, base).href; } return resolve(specifier).href; @@ -690,13 +689,13 @@ const emptyOrProtocolOrResolve = (resourceHREF, base) => { if (resourceHREF === '') return ''; if (StringPrototypeEndsWith(resourceHREF, ':')) { // URL parse will trim these anyway, save the compute - resourceHREF = StringPrototypeReplace( - resourceHREF, + resourceHREF = RegExpPrototypeSymbolReplace( // eslint-disable-next-line /^[\x00-\x1F\x20]|\x09\x0A\x0D|[\x00-\x1F\x20]$/g, + resourceHREF, '' ); - if (RegExpPrototypeTest(/^[a-zA-Z][a-zA-Z+\-.]*:$/, resourceHREF)) { + if (RegExpPrototypeExec(/^[a-zA-Z][a-zA-Z+\-.]*:$/, resourceHREF) !== null) { return resourceHREF; } } @@ -718,7 +717,7 @@ const resolve = (originalHREF, base) => { parsedURLs = parsedURLs ?? new SafeMap(); if (parsedURLs.has(originalHREF)) { return parsedURLs.get(originalHREF); - } else if (RegExpPrototypeTest(kRelativeURLStringPattern, originalHREF)) { + } else if (RegExpPrototypeExec(kRelativeURLStringPattern, originalHREF) !== null) { const resourceURL = new URL(originalHREF, base); parsedURLs.set(resourceURL.href, resourceURL); return resourceURL; diff --git a/lib/internal/policy/sri.js b/lib/internal/policy/sri.js index 0d8c24e89ae8aa..72f7798ce4f333 100644 --- a/lib/internal/policy/sri.js +++ b/lib/internal/policy/sri.js @@ -10,7 +10,6 @@ const { ObjectSetPrototypeOf, RegExp, RegExpPrototypeExec, - RegExpPrototypeTest, StringPrototypeSlice, } = primordials; @@ -62,7 +61,7 @@ const parse = (str) => { } if (prevIndex !== str.length) { - if (!RegExpPrototypeTest(kAllWSP, StringPrototypeSlice(str, prevIndex))) { + if (RegExpPrototypeExec(kAllWSP, StringPrototypeSlice(str, prevIndex)) === null) { throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex); } } diff --git a/lib/internal/process/per_thread.js b/lib/internal/process/per_thread.js index f80d078444047c..c2be274659e6c7 100644 --- a/lib/internal/process/per_thread.js +++ b/lib/internal/process/per_thread.js @@ -17,7 +17,7 @@ const { ObjectFreeze, ObjectDefineProperty, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeArrayIterator, Set, SetPrototypeEntries, @@ -340,7 +340,7 @@ function buildAllowedFlags() { // not. if (typeof key === 'string') { key = StringPrototypeReplace(key, replaceUnderscoresRegex, '-'); - if (RegExpPrototypeTest(leadingDashesRegex, key)) { + if (RegExpPrototypeExec(leadingDashesRegex, key) !== null) { key = StringPrototypeReplace(key, trailingValuesRegex, ''); return ArrayPrototypeIncludes(this[kInternal].array, key); } diff --git a/lib/internal/readline/interface.js b/lib/internal/readline/interface.js index 63383658879095..1431ae792825cf 100644 --- a/lib/internal/readline/interface.js +++ b/lib/internal/readline/interface.js @@ -19,12 +19,12 @@ const { NumberIsFinite, NumberIsNaN, ObjectSetPrototypeOf, - RegExpPrototypeTest, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, + RegExpPrototypeSymbolSplit, StringPrototypeCodePointAt, StringPrototypeEndsWith, - StringPrototypeMatch, StringPrototypeRepeat, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -551,12 +551,12 @@ class Interface extends InterfaceConstructor { this[kSawReturnAt] && DateNow() - this[kSawReturnAt] <= this.crlfDelay ) { - string = StringPrototypeReplace(string, /^\n/, ''); + string = RegExpPrototypeSymbolReplace(/^\n/, string, ''); this[kSawReturnAt] = 0; } // Run test() on the new string chunk, not on the entire line buffer. - const newPartContainsEnding = RegExpPrototypeTest(lineEnding, string); + const newPartContainsEnding = RegExpPrototypeExec(lineEnding, string) !== null; if (this[kLine_buffer]) { string = this[kLine_buffer] + string; @@ -694,7 +694,7 @@ class Interface extends InterfaceConstructor { ArrayPrototypeReverse(ArrayFrom(leading)), '' ); - const match = StringPrototypeMatch(reversed, /^\s*(?:[^\w\s]+|\w+)?/); + const match = RegExpPrototypeExec(/^\s*(?:[^\w\s]+|\w+)?/, reversed); this[kMoveCursor](-match[0].length); } } @@ -702,7 +702,7 @@ class Interface extends InterfaceConstructor { [kWordRight]() { if (this.cursor < this.line.length) { const trailing = StringPrototypeSlice(this.line, this.cursor); - const match = StringPrototypeMatch(trailing, /^(?:\s+|[^\w\s]+|\w+)\s*/); + const match = RegExpPrototypeExec(/^(?:\s+|[^\w\s]+|\w+)\s*/, trailing); this[kMoveCursor](match[0].length); } } @@ -744,7 +744,7 @@ class Interface extends InterfaceConstructor { ArrayPrototypeReverse(ArrayFrom(leading)), '' ); - const match = StringPrototypeMatch(reversed, /^\s*(?:[^\w\s]+|\w+)?/); + const match = RegExpPrototypeExec(/^\s*(?:[^\w\s]+|\w+)?/, reversed); leading = StringPrototypeSlice( leading, 0, @@ -761,7 +761,7 @@ class Interface extends InterfaceConstructor { [kDeleteWordRight]() { if (this.cursor < this.line.length) { const trailing = StringPrototypeSlice(this.line, this.cursor); - const match = StringPrototypeMatch(trailing, /^(?:\s+|\W+|\w+)\s*/); + const match = RegExpPrototypeExec(/^(?:\s+|\W+|\w+)\s*/, trailing); this.line = StringPrototypeSlice(this.line, 0, this.cursor) + StringPrototypeSlice(trailing, match[0].length); @@ -1164,7 +1164,7 @@ class Interface extends InterfaceConstructor { // falls through default: if (typeof s === 'string' && s) { - const lines = StringPrototypeSplit(s, /\r\n|\n|\r/); + const lines = RegExpPrototypeSymbolSplit(/\r\n|\n|\r/, s); for (let i = 0, len = lines.length; i < len; i++) { if (i > 0) { this[kLine](); diff --git a/lib/internal/readline/utils.js b/lib/internal/readline/utils.js index 98679494a3e64b..83609b71fb5974 100644 --- a/lib/internal/readline/utils.js +++ b/lib/internal/readline/utils.js @@ -3,11 +3,10 @@ const { ArrayPrototypeSlice, ArrayPrototypeSort, - RegExpPrototypeTest, + RegExpPrototypeExec, StringFromCharCode, StringPrototypeCharCodeAt, StringPrototypeCodePointAt, - StringPrototypeMatch, StringPrototypeSlice, StringPrototypeToLowerCase, Symbol, @@ -190,11 +189,11 @@ function* emitKeys(stream) { const cmd = StringPrototypeSlice(s, cmdStart); let match; - if ((match = StringPrototypeMatch(cmd, /^(\d\d?)(;(\d))?([~^$])$/))) { + if ((match = RegExpPrototypeExec(/^(\d\d?)(;(\d))?([~^$])$/, cmd))) { code += match[1] + match[4]; modifier = (match[3] || 1) - 1; } else if ( - (match = StringPrototypeMatch(cmd, /^((\d;)?(\d))?([A-Za-z])$/)) + (match = RegExpPrototypeExec(/^((\d;)?(\d))?([A-Za-z])$/, cmd)) ) { code += match[4]; modifier = (match[3] || 1) - 1; @@ -340,10 +339,10 @@ function* emitKeys(stream) { StringPrototypeCharCodeAt(ch) + StringPrototypeCharCodeAt('a') - 1 ); key.ctrl = true; - } else if (RegExpPrototypeTest(/^[0-9A-Za-z]$/, ch)) { + } else if (RegExpPrototypeExec(/^[0-9A-Za-z]$/, ch) !== null) { // Letter, number, shift+letter key.name = StringPrototypeToLowerCase(ch); - key.shift = RegExpPrototypeTest(/^[A-Z]$/, ch); + key.shift = RegExpPrototypeExec(/^[A-Z]$/, ch) !== null; key.meta = escaped; } else if (escaped) { // Escape sequence timeout diff --git a/lib/internal/repl/history.js b/lib/internal/repl/history.js index 74ef94e81070dc..9300283e0015cc 100644 --- a/lib/internal/repl/history.js +++ b/lib/internal/repl/history.js @@ -4,7 +4,7 @@ const { ArrayPrototypeJoin, Boolean, FunctionPrototype, - StringPrototypeSplit, + RegExpPrototypeSymbolSplit, StringPrototypeTrim, } = primordials; @@ -90,7 +90,7 @@ function setupHistory(repl, historyPath, ready) { } if (data) { - repl.history = StringPrototypeSplit(data, /[\n\r]+/, repl.historySize); + repl.history = RegExpPrototypeSymbolSplit(/[\n\r]+/, data, repl.historySize); } else { repl.history = []; } diff --git a/lib/internal/repl/utils.js b/lib/internal/repl/utils.js index ee8c54be5bb5c3..9e55b79fc7e86c 100644 --- a/lib/internal/repl/utils.js +++ b/lib/internal/repl/utils.js @@ -7,13 +7,13 @@ const { Boolean, FunctionPrototypeBind, MathMin, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeSet, SafeStringIterator, StringPrototypeEndsWith, StringPrototypeIndexOf, StringPrototypeLastIndexOf, - StringPrototypeReplace, + StringPrototypeReplaceAll, StringPrototypeSlice, StringPrototypeStartsWith, StringPrototypeToLowerCase, @@ -68,7 +68,7 @@ function isRecoverableError(e, code) { // curly brace with parenthesis. Note: only the open parenthesis is added // here as the point is to test for potentially valid but incomplete // expressions. - if (RegExpPrototypeTest(/^\s*\{/, code) && + if (RegExpPrototypeExec(/^\s*\{/, code) !== null && isRecoverableError(e, `(${code}`)) return true; @@ -114,8 +114,8 @@ function isRecoverableError(e, code) { const token = StringPrototypeSlice(this.input, this.lastTokStart, this.pos); // See https://www.ecma-international.org/ecma-262/#sec-line-terminators - if (RegExpPrototypeTest(/\\(?:\r\n?|\n|\u2028|\u2029)$/, - token)) { + if (RegExpPrototypeExec(/\\(?:\r\n?|\n|\u2028|\u2029)$/, + token) !== null) { recoverable = true; } } @@ -288,9 +288,9 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) { function isInStrictMode(repl) { return repl.replMode === REPL_MODE_STRICT || ArrayPrototypeIncludes( ArrayPrototypeMap(process.execArgv, - (e) => StringPrototypeReplace( + (e) => StringPrototypeReplaceAll( StringPrototypeToLowerCase(e), - /_/g, + '_', '-' )), '--use-strict'); diff --git a/lib/internal/source_map/prepare_stack_trace.js b/lib/internal/source_map/prepare_stack_trace.js index 8420bd230fa2e9..55dc8b344f8be6 100644 --- a/lib/internal/source_map/prepare_stack_trace.js +++ b/lib/internal/source_map/prepare_stack_trace.js @@ -5,9 +5,9 @@ const { ArrayPrototypeJoin, ArrayPrototypeMap, ErrorPrototypeToString, + RegExpPrototypeSymbolSplit, StringPrototypeRepeat, StringPrototypeSlice, - StringPrototypeSplit, StringPrototypeStartsWith, SafeStringIterator, } = primordials; @@ -157,7 +157,7 @@ function getErrorSource( sourceMap.payload, originalSourcePathNoScheme ); - const lines = StringPrototypeSplit(source, /\r?\n/, originalLine + 1); + const lines = RegExpPrototypeSymbolSplit(/\r?\n/, source, originalLine + 1); const line = lines[originalLine]; if (!line) return exceptionLine; diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index bc212b27ff8670..c7770e7a6c733b 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -8,8 +8,8 @@ const { ObjectGetOwnPropertyDescriptor, ObjectPrototypeHasOwnProperty, RegExpPrototypeExec, + RegExpPrototypeSymbolSplit, SafeMap, - StringPrototypeMatch, StringPrototypeSplit, } = primordials; @@ -87,9 +87,9 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo debug(err); return; } - const match = StringPrototypeMatch( + const match = RegExpPrototypeExec( + /\/[*/]#\s+sourceMappingURL=(?[^\s]+)/, content, - /\/[*/]#\s+sourceMappingURL=(?[^\s]+)/ ); if (match) { const data = dataFromUrl(filename, match.groups.sourceMappingURL); @@ -169,7 +169,7 @@ function lineLengths(content) { // We purposefully keep \r as part of the line-length calculation, in // cases where there is a \r\n separator, so that this can be taken into // account in coverage calculations. - return ArrayPrototypeMap(StringPrototypeSplit(content, /\n|\u2028|\u2029/), (line) => { + return ArrayPrototypeMap(RegExpPrototypeSymbolSplit(/\n|\u2028|\u2029/, content), (line) => { return line.length; }); } diff --git a/lib/internal/tty.js b/lib/internal/tty.js index 5abf0b908b02cc..4f285e92829637 100644 --- a/lib/internal/tty.js +++ b/lib/internal/tty.js @@ -24,7 +24,7 @@ const { ArrayPrototypeSome, - RegExpPrototypeTest, + RegExpPrototypeExec, StringPrototypeSplit, StringPrototypeToLowerCase, } = primordials; @@ -174,14 +174,14 @@ function getColorDepth(env = process.env) { } if ('TEAMCITY_VERSION' in env) { - return RegExpPrototypeTest(/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/, env.TEAMCITY_VERSION) ? + return RegExpPrototypeExec(/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/, env.TEAMCITY_VERSION) !== null ? COLORS_16 : COLORS_2; } switch (env.TERM_PROGRAM) { case 'iTerm.app': if (!env.TERM_PROGRAM_VERSION || - RegExpPrototypeTest(/^[0-2]\./, env.TERM_PROGRAM_VERSION) + RegExpPrototypeExec(/^[0-2]\./, env.TERM_PROGRAM_VERSION) !== null ) { return COLORS_256; } @@ -198,7 +198,7 @@ function getColorDepth(env = process.env) { } if (env.TERM) { - if (RegExpPrototypeTest(/^xterm-256/, env.TERM)) { + if (RegExpPrototypeExec(/^xterm-256/, env.TERM) !== null) { return COLORS_256; } @@ -208,7 +208,7 @@ function getColorDepth(env = process.env) { return TERM_ENVS[termEnv]; } if (ArrayPrototypeSome(TERM_ENVS_REG_EXP, - (term) => RegExpPrototypeTest(term, termEnv))) { + (term) => RegExpPrototypeExec(term, termEnv) !== null)) { return COLORS_16; } } diff --git a/lib/internal/util.js b/lib/internal/util.js index b90a769f4828ff..ea6d19683fed45 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -19,7 +19,6 @@ const { ReflectApply, ReflectConstruct, RegExpPrototypeExec, - RegExpPrototypeTest, SafeMap, SafeSet, StringPrototypeReplace, @@ -430,9 +429,9 @@ function isInsideNodeModules() { const filename = frame.getFileName(); // If a filename does not start with / or contain \, // it's likely from Node.js core. - if (!RegExpPrototypeTest(/^\/|\\/, filename)) + if (RegExpPrototypeExec(/^\/|\\/, filename) === null) continue; - return RegExpPrototypeTest(kNodeModulesRE, filename); + return RegExpPrototypeExec(kNodeModulesRE, filename) !== null; } } return false; diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 17d567eb9db368..f38df74ed6af15 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -49,7 +49,8 @@ const { ObjectSetPrototypeOf, ReflectOwnKeys, RegExp, - RegExpPrototypeTest, + RegExpPrototypeExec, + RegExpPrototypeSymbolReplace, RegExpPrototypeToString, SafeStringIterator, SafeMap, @@ -64,7 +65,6 @@ const { StringPrototypePadEnd, StringPrototypePadStart, StringPrototypeRepeat, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeToLowerCase, @@ -153,7 +153,7 @@ function pathToFileUrlHref(filepath) { const builtInObjects = new SafeSet( ArrayPrototypeFilter( ObjectGetOwnPropertyNames(globalThis), - (e) => RegExpPrototypeTest(/^[A-Z][a-zA-Z0-9]+$/, e) + (e) => RegExpPrototypeExec(/^[A-Z][a-zA-Z0-9]+$/, e) !== null ) ); @@ -502,10 +502,10 @@ function strEscape(str) { } // Some magic numbers that worked out fine while benchmarking with v8 6.0 - if (str.length < 5000 && !RegExpPrototypeTest(escapeTest, str)) + if (str.length < 5000 && RegExpPrototypeExec(escapeTest, str) === null) return addQuotes(str, singleQuote); if (str.length > 100) { - str = StringPrototypeReplace(str, escapeReplace, escapeFn); + str = RegExpPrototypeSymbolReplace(escapeReplace, str, escapeFn); return addQuotes(str, singleQuote); } @@ -1694,9 +1694,10 @@ function formatArrayBuffer(ctx, value) { } if (hexSlice === undefined) hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice); - let str = StringPrototypeTrim(StringPrototypeReplace( + let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace( + /(.{2})/g, hexSlice(buffer, 0, MathMin(ctx.maxArrayLength, buffer.length)), - /(.{2})/g, '$1 ')); + '$1 ')); const remaining = buffer.length - ctx.maxArrayLength; if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; @@ -1928,18 +1929,19 @@ function formatProperty(ctx, value, recurseTimes, key, type, desc, return str; } if (typeof key === 'symbol') { - const tmp = StringPrototypeReplace( + const tmp = RegExpPrototypeSymbolReplace( + strEscapeSequencesReplacer, SymbolPrototypeToString(key), - strEscapeSequencesReplacer, escapeFn + escapeFn ); name = `[${ctx.stylize(tmp, 'symbol')}]`; } else if (key === '__proto__') { name = "['__proto__']"; } else if (desc.enumerable === false) { - const tmp = StringPrototypeReplace(key, - strEscapeSequencesReplacer, escapeFn); + const tmp = RegExpPrototypeSymbolReplace( + strEscapeSequencesReplacer, key, escapeFn); name = `[${tmp}]`; - } else if (RegExpPrototypeTest(keyStrRegExp, key)) { + } else if (RegExpPrototypeExec(keyStrRegExp, key) !== null) { name = ctx.stylize(key, 'name'); } else { name = ctx.stylize(strEscape(key), 'string'); diff --git a/lib/internal/validators.js b/lib/internal/validators.js index 8144a8a5306371..e633040ac3d452 100644 --- a/lib/internal/validators.js +++ b/lib/internal/validators.js @@ -9,7 +9,7 @@ const { NumberMAX_SAFE_INTEGER, NumberMIN_SAFE_INTEGER, NumberParseInt, - RegExpPrototypeTest, + RegExpPrototypeExec, String, StringPrototypeToUpperCase, StringPrototypeTrim, @@ -59,7 +59,7 @@ const modeDesc = 'must be a 32-bit unsigned integer or an octal string'; function parseFileMode(value, name, def) { value ??= def; if (typeof value === 'string') { - if (!RegExpPrototypeTest(octalReg, value)) { + if (RegExpPrototypeExec(octalReg, value) === null) { throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc); } value = NumberParseInt(value, 8); diff --git a/lib/internal/worker.js b/lib/internal/worker.js index 0cede10ca4bf9b..8e396195209b83 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -13,7 +13,7 @@ const { Promise, PromiseResolve, ReflectApply, - RegExpPrototypeTest, + RegExpPrototypeExec, SafeArrayIterator, SafeMap, String, @@ -158,7 +158,7 @@ class Worker extends EventEmitter { filename ); } else if (path.isAbsolute(filename) || - RegExpPrototypeTest(/^\.\.?[\\/]/, filename)) { + RegExpPrototypeExec(/^\.\.?[\\/]/, filename) !== null) { filename = path.resolve(filename); url = pathToFileURL(filename); } else { diff --git a/lib/repl.js b/lib/repl.js index 3d0980dd25d4e2..8a0533191c3970 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -78,17 +78,15 @@ const { RegExp, RegExpPrototypeExec, RegExpPrototypeSymbolReplace, - RegExpPrototypeTest, SafePromiseRace, + RegExpPrototypeSymbolSplit, SafeSet, SafeWeakSet, StringPrototypeCharAt, StringPrototypeCodePointAt, StringPrototypeEndsWith, StringPrototypeIncludes, - StringPrototypeMatch, StringPrototypeRepeat, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -423,8 +421,8 @@ function REPLServer(prompt, // to wrap it in parentheses, so that it will be interpreted as // an expression. Note that if the above condition changes, // lib/internal/repl/utils.js needs to be changed to match. - if (RegExpPrototypeTest(/^\s*{/, code) && - !RegExpPrototypeTest(/;\s*$/, code)) { + if (RegExpPrototypeExec(/^\s*{/, code) !== null && + RegExpPrototypeExec(/;\s*$/, code) === null) { code = `(${StringPrototypeTrim(code)})\n`; wrappedCmd = true; } @@ -499,7 +497,7 @@ function REPLServer(prompt, while (true) { try { if (self.replMode === module.exports.REPL_MODE_STRICT && - !RegExpPrototypeTest(/^\s*$/, code)) { + RegExpPrototypeExec(/^\s*$/, code) === null) { // "void 0" keeps the repl from returning "use strict" as the result // value for statements and declarations that don't return a value. code = `'use strict'; void 0;\n${code}`; @@ -683,22 +681,24 @@ function REPLServer(prompt, if (e.stack) { if (e.name === 'SyntaxError') { // Remove stack trace. - e.stack = StringPrototypeReplace(StringPrototypeReplace(e.stack, - /^REPL\d+:\d+\r?\n/, ''), - /^\s+at\s.*\n?/gm, ''); + e.stack = RegExpPrototypeSymbolReplace( + /^\s+at\s.*\n?/gm, + RegExpPrototypeSymbolReplace(/^REPL\d+:\d+\r?\n/, e.stack, ''), + ''); const importErrorStr = 'Cannot use import statement outside a ' + 'module'; if (StringPrototypeIncludes(e.message, importErrorStr)) { e.message = 'Cannot use import statement inside the Node.js ' + 'REPL, alternatively use dynamic import'; - e.stack = StringPrototypeReplace(e.stack, - /SyntaxError:.*\n/, - `SyntaxError: ${e.message}\n`); + e.stack = RegExpPrototypeSymbolReplace( + /SyntaxError:.*\n/, + e.stack, + `SyntaxError: ${e.message}\n`); } } else if (self.replMode === module.exports.REPL_MODE_STRICT) { - e.stack = StringPrototypeReplace( - e.stack, + e.stack = RegExpPrototypeSymbolReplace( /(\s+at\s+REPL\d+:)(\d+)/, + e.stack, (_, pre, line) => pre + (line - 1) ); } @@ -728,13 +728,13 @@ function REPLServer(prompt, if (errStack === '') { errStack = self.writer(e); } - const lines = StringPrototypeSplit(errStack, /(?<=\n)/); + const lines = RegExpPrototypeSymbolSplit(/(?<=\n)/, errStack); let matched = false; errStack = ''; ArrayPrototypeForEach(lines, (line) => { if (!matched && - RegExpPrototypeTest(/^\[?([A-Z][a-z0-9_]*)*Error/, line)) { + RegExpPrototypeExec(/^\[?([A-Z][a-z0-9_]*)*Error/, line) !== null) { errStack += writer.options.breakLength >= line.length ? `Uncaught ${line}` : `Uncaught:\n${line}`; @@ -862,7 +862,7 @@ function REPLServer(prompt, // code alignment const matches = self._sawKeyPress ? - StringPrototypeMatch(cmd, /^\s+/) : null; + RegExpPrototypeExec(/^\s+/, cmd) : null; if (matches) { const prefix = matches[0]; self.write(prefix); @@ -882,7 +882,7 @@ function REPLServer(prompt, if (StringPrototypeCharAt(trimmedCmd, 0) === '.' && StringPrototypeCharAt(trimmedCmd, 1) !== '.' && NumberIsNaN(NumberParseFloat(trimmedCmd))) { - const matches = StringPrototypeMatch(trimmedCmd, /^\.([^\s]+)\s*(.*)$/); + const matches = RegExpPrototypeExec(/^\.([^\s]+)\s*(.*)$/, trimmedCmd); const keyword = matches && matches[1]; const rest = matches && matches[2]; if (ReflectApply(_parseREPLKeyword, self, [keyword, rest]) === true) { @@ -1262,9 +1262,9 @@ function gracefulReaddir(...args) { } } -function completeFSFunctions(line) { +function completeFSFunctions(match) { let baseName = ''; - let filePath = StringPrototypeMatch(line, fsAutoCompleteRE)[1]; + let filePath = match[1]; let fileList = gracefulReaddir(filePath, { withFileTypes: true }); if (!fileList) { @@ -1303,16 +1303,17 @@ function complete(line, callback) { line = StringPrototypeTrimLeft(line); let filter = ''; + + let match; // REPL commands (e.g. ".break"). - if (RegExpPrototypeTest(/^\s*\.(\w*)$/, line)) { + if ((match = RegExpPrototypeExec(/^\s*\.(\w*)$/, line)) !== null) { ArrayPrototypePush(completionGroups, ObjectKeys(this.commands)); - completeOn = StringPrototypeMatch(line, /^\s*\.(\w*)$/)[1]; + completeOn = match[1]; if (completeOn.length) { filter = completeOn; } - } else if (RegExpPrototypeTest(requireRE, line)) { + } else if ((match = RegExpPrototypeExec(requireRE, line)) !== null) { // require('...') - const match = StringPrototypeMatch(line, requireRE); completeOn = match[1]; filter = completeOn; if (this.allowBlockingCompletions) { @@ -1329,7 +1330,7 @@ function complete(line, callback) { group = ['./', '../']; } else if (completeOn === '..') { group = ['../']; - } else if (RegExpPrototypeTest(/^\.\.?\//, completeOn)) { + } else if (RegExpPrototypeExec(/^\.\.?\//, completeOn) !== null) { paths = [process.cwd()]; } else { paths = ArrayPrototypeConcat(module.paths, CJSModule.globalPaths); @@ -1339,7 +1340,7 @@ function complete(line, callback) { dir = path.resolve(dir, subdir); const dirents = gracefulReaddir(dir, { withFileTypes: true }) || []; ArrayPrototypeForEach(dirents, (dirent) => { - if (RegExpPrototypeTest(versionedFileNamesRe, dirent.name) || + if (RegExpPrototypeExec(versionedFileNamesRe, dirent.name) !== null || dirent.name === '.npm') { // Exclude versioned names that 'npm' installs. return; @@ -1369,9 +1370,8 @@ function complete(line, callback) { } ArrayPrototypePush(completionGroups, _builtinLibs, nodeSchemeBuiltinLibs); - } else if (RegExpPrototypeTest(importRE, line)) { + } else if ((match = RegExpPrototypeExec(importRE, line)) !== null) { // import('...') - const match = StringPrototypeMatch(line, importRE); completeOn = match[1]; filter = completeOn; if (this.allowBlockingCompletions) { @@ -1392,7 +1392,7 @@ function complete(line, callback) { group = ['./', '../']; } else if (completeOn === '..') { group = ['../']; - } else if (RegExpPrototypeTest(/^\.\.?\//, completeOn)) { + } else if (RegExpPrototypeExec(/^\.\.?\//, completeOn) !== null) { paths = [process.cwd()]; } else { paths = ArrayPrototypeSlice(module.paths); @@ -1404,7 +1404,7 @@ function complete(line, callback) { const dirents = gracefulReaddir(dir, { withFileTypes: true }) || []; ArrayPrototypeForEach(dirents, (dirent) => { const { name } = dirent; - if (RegExpPrototypeTest(versionedFileNamesRe, name) || + if (RegExpPrototypeExec(versionedFileNamesRe, name) !== null || name === '.npm') { // Exclude versioned names that 'npm' installs. return; @@ -1437,9 +1437,9 @@ function complete(line, callback) { } ArrayPrototypePush(completionGroups, _builtinLibs, nodeSchemeBuiltinLibs); - } else if (RegExpPrototypeTest(fsAutoCompleteRE, line) && + } else if ((match = RegExpPrototypeExec(fsAutoCompleteRE, line)) !== null && this.allowBlockingCompletions) { - ({ 0: completionGroups, 1: completeOn } = completeFSFunctions(line)); + ({ 0: completionGroups, 1: completeOn } = completeFSFunctions(match)); // Handle variable member lookup. // We support simple chained expressions like the following (no function // calls, etc.). That is for simplicity and also because we *eval* that @@ -1451,7 +1451,7 @@ function complete(line, callback) { // foo<|> # all scope vars with filter 'foo' // foo.<|> # completions for 'foo' with filter '' } else if (line.length === 0 || - RegExpPrototypeTest(/\w|\.|\$/, line[line.length - 1])) { + RegExpPrototypeExec(/\w|\.|\$/, line[line.length - 1]) !== null) { const { 0: match } = RegExpPrototypeExec(simpleExpressionRE, line) || ['']; if (line.length !== 0 && !match) { completionGroupsLoaded(); @@ -1640,14 +1640,17 @@ function _memory(cmd) { // I need to know "depth." // Because I can not tell the difference between a } that // closes an object literal and a } that closes a function + const countMatches = (regex, str) => { + let count = 0; + while (RegExpPrototypeExec(regex, str) !== null) count++; + return count; + }; // Going down is { and ( e.g. function() { // going up is } and ) - let dw = StringPrototypeMatch(cmd, /[{(]/g); - let up = StringPrototypeMatch(cmd, /[})]/g); - up = up ? up.length : 0; - dw = dw ? dw.length : 0; - let depth = dw - up; + const dw = countMatches(/[{(]/g, cmd); + const up = countMatches(/[})]/g, cmd); + let depth = dw.length - up.length; if (depth) { (function workIt() { diff --git a/lib/tls.js b/lib/tls.js index 78e62091657b1a..1ada006635d4d3 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -34,13 +34,12 @@ const { ObjectDefineProperty, ObjectFreeze, RegExpPrototypeExec, - RegExpPrototypeTest, + RegExpPrototypeSymbolReplace, StringFromCharCode, StringPrototypeCharCodeAt, StringPrototypeEndsWith, StringPrototypeIncludes, StringPrototypeIndexOf, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -161,7 +160,7 @@ exports.convertALPNProtocols = function convertALPNProtocols(protocols, out) { }; function unfqdn(host) { - return StringPrototypeReplace(host, /[.]$/, ''); + return RegExpPrototypeSymbolReplace(/[.]$/, host, ''); } // String#toLowerCase() is locale-sensitive so we use @@ -172,7 +171,7 @@ function toLowerCase(c) { function splitHost(host) { return StringPrototypeSplit( - StringPrototypeReplace(unfqdn(host), /[A-Z]/g, toLowerCase), + RegExpPrototypeSymbolReplace(/[A-Z]/g, unfqdn(host), toLowerCase), '.' ); } @@ -195,7 +194,7 @@ function check(hostParts, pattern, wildcards) { // good way to detect their encoding or normalize them so we simply // reject them. Control characters and blanks are rejected as well // because nothing good can come from accepting them. - const isBad = (s) => RegExpPrototypeTest(/[^\u0021-\u007F]/u, s); + const isBad = (s) => RegExpPrototypeExec(/[^\u0021-\u007F]/u, s) !== null; if (ArrayPrototypeSome(patternParts, isBad)) return false; diff --git a/test/parallel/test-errors-systemerror.js b/test/parallel/test-errors-systemerror.js index 2a20588e75b386..38afbd4aa7d164 100644 --- a/test/parallel/test-errors-systemerror.js +++ b/test/parallel/test-errors-systemerror.js @@ -9,7 +9,7 @@ assert.throws( () => { new SystemError(); }, { name: 'TypeError', - message: 'String.prototype.match called on null or undefined' + message: "Cannot read properties of undefined (reading 'syscall')", } );