'use strict'; const { ArrayFrom, ArrayPrototypePush, ArrayPrototypeSlice, ArrayPrototypeSort, Error, ErrorCaptureStackTrace, FunctionPrototypeCall, ObjectDefineProperties, ObjectDefineProperty, ObjectFreeze, ObjectGetOwnPropertyDescriptor, ObjectGetOwnPropertyDescriptors, ObjectGetPrototypeOf, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, ObjectValues, Promise, ReflectApply, ReflectConstruct, RegExpPrototypeExec, RegExpPrototypeGetDotAll, RegExpPrototypeGetGlobal, RegExpPrototypeGetHasIndices, RegExpPrototypeGetIgnoreCase, RegExpPrototypeGetMultiline, RegExpPrototypeGetSource, RegExpPrototypeGetSticky, RegExpPrototypeGetUnicode, SafeMap, SafeSet, SafeWeakMap, SafeWeakRef, StringPrototypeReplace, StringPrototypeToLowerCase, StringPrototypeToUpperCase, Symbol, SymbolFor, SymbolReplace, SymbolSplit, } = primordials; const { codes: { ERR_NO_CRYPTO, ERR_NO_TYPESCRIPT, ERR_UNKNOWN_SIGNAL, }, isErrorStackTraceLimitWritable, overrideStackTrace, uvErrmapGet, } = require('internal/errors'); const { signals } = internalBinding('constants').os; const { guessHandleType: _guessHandleType, privateSymbols: { arrow_message_private_symbol, decorated_private_symbol, }, sleep: _sleep, } = internalBinding('util'); const { isNativeError, isPromise } = internalBinding('types'); const { getOptionValue } = require('internal/options'); const assert = require('internal/assert'); const { encodings } = internalBinding('string_decoder'); const noCrypto = !process.versions.openssl; const noTypeScript = !process.versions.amaro; const isWindows = process.platform === 'win32'; const isMacOS = process.platform === 'darwin'; const experimentalWarnings = new SafeSet(); const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex let uvBinding; function lazyUv() { uvBinding ??= internalBinding('uv'); return uvBinding; } function removeColors(str) { return StringPrototypeReplace(str, colorRegExp, ''); } function isError(e) { // An error could be an instance of Error while not being a native error // or could be from a different realm and not be instance of Error but still // be a native error. return isNativeError(e) || e instanceof Error; } // Keep a list of deprecation codes that have been warned on so we only warn on // each one once. const codesWarned = new SafeSet(); let validateString; function getDeprecationWarningEmitter( code, msg, deprecated, useEmitSync, shouldEmitWarning = () => true, ) { let warned = false; return function() { if (!warned && shouldEmitWarning()) { warned = true; if (code === 'ExperimentalWarning') { process.emitWarning(msg, code, deprecated); } else if (code !== undefined) { if (!codesWarned.has(code)) { const emitWarning = useEmitSync ? require('internal/process/warning').emitWarningSync : process.emitWarning; emitWarning(msg, 'DeprecationWarning', code, deprecated); codesWarned.add(code); } } else { process.emitWarning(msg, 'DeprecationWarning', deprecated); } } }; } function isPendingDeprecation() { return getOptionValue('--pending-deprecation') && !getOptionValue('--no-deprecation'); } // Internal deprecator for pending --pending-deprecation. This can be invoked // at snapshot building time as the warning permission is only queried at // run time. function pendingDeprecate(fn, msg, code) { const emitDeprecationWarning = getDeprecationWarningEmitter( code, msg, deprecated, false, isPendingDeprecation, ); function deprecated(...args) { emitDeprecationWarning(); return ReflectApply(fn, this, args); } return deprecated; } // Mark that a method should not be used. // Returns a modified function which warns once by default. // If --no-deprecation is set, then it is a no-op. function deprecate(fn, msg, code, useEmitSync) { // Lazy-load to avoid a circular dependency. if (validateString === undefined) ({ validateString } = require('internal/validators')); if (code !== undefined) validateString(code, 'code'); const emitDeprecationWarning = getDeprecationWarningEmitter( code, msg, deprecated, useEmitSync, ); function deprecated(...args) { // TODO(joyeecheung): use getOptionValue('--no-deprecation') instead. if (!process.noDeprecation) { emitDeprecationWarning(); } if (new.target) { return ReflectConstruct(fn, args, new.target); } return ReflectApply(fn, this, args); } // The wrapper will keep the same prototype as fn to maintain prototype chain ObjectSetPrototypeOf(deprecated, fn); if (fn.prototype) { // Setting this (rather than using Object.setPrototype, as above) ensures // that calling the unwrapped constructor gives an instanceof the wrapped // constructor. deprecated.prototype = fn.prototype; } return deprecated; } function deprecateInstantiation(target, code, ...args) { assert(typeof code === 'string'); getDeprecationWarningEmitter(code, `Instantiating ${target.name} without the 'new' keyword has been deprecated.`, target)(); return ReflectConstruct(target, args); } function decorateErrorStack(err) { if (!(isError(err) && err.stack) || err[decorated_private_symbol]) return; const arrow = err[arrow_message_private_symbol]; if (arrow) { err.stack = arrow + err.stack; err[decorated_private_symbol] = true; } } function assertCrypto() { if (noCrypto) throw new ERR_NO_CRYPTO(); } function assertTypeScript() { if (noTypeScript) throw new ERR_NO_TYPESCRIPT(); } /** * Move the "slow cases" to a separate function to make sure this function gets * inlined properly. That prioritizes the common case. * @param {unknown} enc * @returns {string | undefined} Returns undefined if there is no match. */ function normalizeEncoding(enc) { if (enc == null || enc === 'utf8' || enc === 'utf-8') return 'utf8'; return slowCases(enc); } function slowCases(enc) { switch (enc.length) { case 4: if (enc === 'UTF8') return 'utf8'; if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le'; enc = StringPrototypeToLowerCase(enc); if (enc === 'utf8') return 'utf8'; if (enc === 'ucs2') return 'utf16le'; break; case 3: if (enc === 'hex' || enc === 'HEX' || StringPrototypeToLowerCase(enc) === 'hex') return 'hex'; break; case 5: if (enc === 'ascii') return 'ascii'; if (enc === 'ucs-2') return 'utf16le'; if (enc === 'UTF-8') return 'utf8'; if (enc === 'ASCII') return 'ascii'; if (enc === 'UCS-2') return 'utf16le'; enc = StringPrototypeToLowerCase(enc); if (enc === 'utf-8') return 'utf8'; if (enc === 'ascii') return 'ascii'; if (enc === 'ucs-2') return 'utf16le'; break; case 6: if (enc === 'base64') return 'base64'; if (enc === 'latin1' || enc === 'binary') return 'latin1'; if (enc === 'BASE64') return 'base64'; if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1'; enc = StringPrototypeToLowerCase(enc); if (enc === 'base64') return 'base64'; if (enc === 'latin1' || enc === 'binary') return 'latin1'; break; case 7: if (enc === 'utf16le' || enc === 'UTF16LE' || StringPrototypeToLowerCase(enc) === 'utf16le') return 'utf16le'; break; case 8: if (enc === 'utf-16le' || enc === 'UTF-16LE' || StringPrototypeToLowerCase(enc) === 'utf-16le') return 'utf16le'; break; case 9: if (enc === 'base64url' || enc === 'BASE64URL' || StringPrototypeToLowerCase(enc) === 'base64url') return 'base64url'; break; default: if (enc === '') return 'utf8'; } } /** * @param {string} feature Feature name used in the warning message * @param {string} messagePrefix Prefix of the warning message * @param {string} code See documentation of process.emitWarning * @param {string} ctor See documentation of process.emitWarning */ function emitExperimentalWarning(feature, messagePrefix, code, ctor) { if (experimentalWarnings.has(feature)) return; experimentalWarnings.add(feature); let msg = `${feature} is an experimental feature and might change at any time`; if (messagePrefix) { msg = messagePrefix + msg; } process.emitWarning(msg, 'ExperimentalWarning', code, ctor); } function filterDuplicateStrings(items, low) { const map = new SafeMap(); for (let i = 0; i < items.length; i++) { const item = items[i]; const key = StringPrototypeToLowerCase(item); if (low) { map.set(key, key); } else { map.set(key, item); } } return ArrayPrototypeSort(ArrayFrom(map.values())); } function cachedResult(fn) { let result; return () => { if (result === undefined) result = fn(); return ArrayPrototypeSlice(result); }; } // Useful for Wrapping an ES6 Class with a constructor Function that // does not require the new keyword. For instance: // class A { constructor(x) {this.x = x;}} // const B = createClassWrapper(A); // B() instanceof A // true // B() instanceof B // true function createClassWrapper(type) { function fn(...args) { return ReflectConstruct(type, args, new.target || type); } // Mask the wrapper function name and length values ObjectDefineProperties(fn, { name: { __proto__: null, value: type.name }, length: { __proto__: null, value: type.length }, }); ObjectSetPrototypeOf(fn, type); fn.prototype = type.prototype; return fn; } let signalsToNamesMapping; function getSignalsToNamesMapping() { if (signalsToNamesMapping !== undefined) return signalsToNamesMapping; signalsToNamesMapping = { __proto__: null }; for (const key in signals) { signalsToNamesMapping[signals[key]] = key; } return signalsToNamesMapping; } function convertToValidSignal(signal) { if (typeof signal === 'number' && getSignalsToNamesMapping()[signal]) return signal; if (typeof signal === 'string') { const signalName = signals[StringPrototypeToUpperCase(signal)]; if (signalName) return signalName; } throw new ERR_UNKNOWN_SIGNAL(signal); } function getConstructorOf(obj) { while (obj) { const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor'); if (descriptor !== undefined && typeof descriptor.value === 'function' && descriptor.value.name !== '') { return descriptor.value; } obj = ObjectGetPrototypeOf(obj); } return null; } let cachedURL; let cachedCWD; /** * Get the current working directory while accounting for the possibility that it has been deleted. * `process.cwd()` can fail if the parent directory is deleted while the process runs. * @returns {URL} The current working directory or the volume root if it cannot be determined. */ function getCWDURL() { const { sep } = require('path'); const { pathToFileURL } = require('internal/url'); let cwd; try { // The implementation of `process.cwd()` already uses proper cache when it can. // It's a relatively cheap call performance-wise for the most common use case. cwd = process.cwd(); } catch { cachedURL ??= pathToFileURL(sep); } if (cwd != null && cwd !== cachedCWD) { cachedURL = pathToFileURL(cwd + sep); cachedCWD = cwd; } return cachedURL; } function getSystemErrorMessage(err) { return lazyUv().getErrorMessage(err); } function getSystemErrorName(err) { const entry = uvErrmapGet(err); return entry ? entry[0] : `Unknown system error ${err}`; } function getSystemErrorMap() { return lazyUv().getErrorMap(); } const kCustomPromisifiedSymbol = SymbolFor('nodejs.util.promisify.custom'); const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs'); let validateFunction; function promisify(original) { // Lazy-load to avoid a circular dependency. if (validateFunction === undefined) ({ validateFunction } = require('internal/validators')); validateFunction(original, 'original'); if (original[kCustomPromisifiedSymbol]) { const fn = original[kCustomPromisifiedSymbol]; validateFunction(fn, 'util.promisify.custom'); return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { __proto__: null, value: fn, enumerable: false, writable: false, configurable: true, }); } // Names to create an object from in case the callback receives multiple // arguments, e.g. ['bytesRead', 'buffer'] for fs.read. const argumentNames = original[kCustomPromisifyArgsSymbol]; function fn(...args) { return new Promise((resolve, reject) => { ArrayPrototypePush(args, (err, ...values) => { if (err) { return reject(err); } if (argumentNames !== undefined && values.length > 1) { const obj = {}; for (let i = 0; i < argumentNames.length; i++) obj[argumentNames[i]] = values[i]; resolve(obj); } else { resolve(values[0]); } }); if (isPromise(ReflectApply(original, this, args))) { process.emitWarning('Calling promisify on a function that returns a Promise is likely a mistake.', 'DeprecationWarning', 'DEP0174'); } }); } ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original)); ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { __proto__: null, value: fn, enumerable: false, writable: false, configurable: true, }); const descriptors = ObjectGetOwnPropertyDescriptors(original); const propertiesValues = ObjectValues(descriptors); for (let i = 0; i < propertiesValues.length; i++) { // We want to use null-prototype objects to not rely on globally mutable // %Object.prototype%. ObjectSetPrototypeOf(propertiesValues[i], null); } return ObjectDefineProperties(fn, descriptors); } promisify.custom = kCustomPromisifiedSymbol; // The built-in Array#join is slower in v8 6.0 function join(output, separator) { let str = ''; if (output.length !== 0) { const lastIndex = output.length - 1; for (let i = 0; i < lastIndex; i++) { // It is faster not to use a template string here str += output[i]; str += separator; } str += output[lastIndex]; } return str; } // As of V8 6.6, depending on the size of the array, this is anywhere // between 1.5-10x faster than the two-arg version of Array#splice() function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } const kNodeModulesRE = /^(?:.*)[\\/]node_modules[\\/]/; function isUnderNodeModules(filename) { return filename && (RegExpPrototypeExec(kNodeModulesRE, filename) !== null); } let getStructuredStackImpl; function lazyGetStructuredStack() { if (getStructuredStackImpl === undefined) { // Lazy-load to avoid a circular dependency. const { runInNewContext } = require('vm'); // Use `runInNewContext()` to get something tamper-proof and // side-effect-free. Since this is currently only used for a deprecated API // and module mocking, the perf implications should be okay. getStructuredStackImpl = runInNewContext(`(function() { try { Error.stackTraceLimit = Infinity; } catch {} return function structuredStack() { const e = new Error(); overrideStackTrace.set(e, (err, trace) => trace); return e.stack; }; })()`, { overrideStackTrace }, { filename: 'structured-stack' }); } return getStructuredStackImpl; } function getStructuredStack() { const getStructuredStackImpl = lazyGetStructuredStack(); return getStructuredStackImpl(); } function once(callback, { preserveReturnValue = false } = kEmptyObject) { let called = false; let returnValue; return function(...args) { if (called) return returnValue; called = true; const result = ReflectApply(callback, this, args); returnValue = preserveReturnValue ? result : undefined; return result; }; } let validateUint32; function sleep(msec) { // Lazy-load to avoid a circular dependency. if (validateUint32 === undefined) ({ validateUint32 } = require('internal/validators')); validateUint32(msec, 'msec'); _sleep(msec); } // https://heycam.github.io/webidl/#define-the-operations function defineOperation(target, name, method) { ObjectDefineProperty(target, name, { __proto__: null, writable: true, enumerable: true, configurable: true, value: method, }); } // https://heycam.github.io/webidl/#es-interfaces function exposeInterface(target, name, interfaceObject) { ObjectDefineProperty(target, name, { __proto__: null, writable: true, enumerable: false, configurable: true, value: interfaceObject, }); } // https://heycam.github.io/webidl/#es-namespaces function exposeNamespace(target, name, namespaceObject) { ObjectDefineProperty(target, name, { __proto__: null, writable: true, enumerable: false, configurable: true, value: namespaceObject, }); } function exposeGetterAndSetter(target, name, getter, setter = undefined) { ObjectDefineProperty(target, name, { __proto__: null, enumerable: false, configurable: true, get: getter, set: setter, }); } function defineLazyProperties(target, id, keys, enumerable = true) { const descriptors = { __proto__: null }; let mod; for (let i = 0; i < keys.length; i++) { const key = keys[i]; let lazyLoadedValue; function set(value) { ObjectDefineProperty(target, key, { __proto__: null, writable: true, value, }); } ObjectDefineProperty(set, 'name', { __proto__: null, value: `set ${key}`, }); function get() { mod ??= require(id); if (lazyLoadedValue === undefined) { lazyLoadedValue = mod[key]; set(lazyLoadedValue); } return lazyLoadedValue; } ObjectDefineProperty(get, 'name', { __proto__: null, value: `get ${key}`, }); descriptors[key] = { __proto__: null, configurable: true, enumerable, get, set, }; } ObjectDefineProperties(target, descriptors); } function defineReplaceableLazyAttribute(target, id, keys, writable = true, check) { let mod; for (let i = 0; i < keys.length; i++) { const key = keys[i]; let value; let setterCalled = false; function get() { if (check !== undefined) { FunctionPrototypeCall(check, this); } if (setterCalled) { return value; } mod ??= require(id); value ??= mod[key]; return value; } ObjectDefineProperty(get, 'name', { __proto__: null, value: `get ${key}`, }); function set(val) { setterCalled = true; value = val; } ObjectDefineProperty(set, 'name', { __proto__: null, value: `set ${key}`, }); ObjectDefineProperty(target, key, { __proto__: null, enumerable: true, configurable: true, get, set: writable ? set : undefined, }); } } function exposeLazyInterfaces(target, id, keys) { defineLazyProperties(target, id, keys, false); } let _DOMException; const lazyDOMExceptionClass = () => { _DOMException ??= internalBinding('messaging').DOMException; return _DOMException; }; const lazyDOMException = (message, name) => { _DOMException ??= internalBinding('messaging').DOMException; if (isErrorStackTraceLimitWritable()) { const limit = Error.stackTraceLimit; Error.stackTraceLimit = 0; const ex = new _DOMException(message, name); Error.stackTraceLimit = limit; ErrorCaptureStackTrace(ex, lazyDOMException); return ex; } return new _DOMException(message, name); }; const kEnumerableProperty = { __proto__: null }; kEnumerableProperty.enumerable = true; ObjectFreeze(kEnumerableProperty); const kEmptyObject = ObjectFreeze({ __proto__: null }); function filterOwnProperties(source, keys) { const filtered = { __proto__: null }; for (let i = 0; i < keys.length; i++) { const key = keys[i]; if (ObjectPrototypeHasOwnProperty(source, key)) { filtered[key] = source[key]; } } return filtered; } /** * Mimics `obj[key] = value` but ignoring potential prototype inheritance. * @param {any} obj * @param {string} key * @param {any} value * @returns {any} */ function setOwnProperty(obj, key, value) { return ObjectDefineProperty(obj, key, { __proto__: null, configurable: true, enumerable: true, value, writable: true, }); } let internalGlobal; function getInternalGlobal() { if (internalGlobal == null) { // Lazy-load to avoid a circular dependency. const { runInNewContext } = require('vm'); internalGlobal = runInNewContext('this', undefined, { contextName: 'internal' }); } return internalGlobal; } function SideEffectFreeRegExpPrototypeExec(regex, string) { const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal(); return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string); } const crossRealmRegexes = new SafeWeakMap(); function getCrossRealmRegex(regex) { const cached = crossRealmRegexes.get(regex); if (cached) return cached; let flagString = ''; if (RegExpPrototypeGetHasIndices(regex)) flagString += 'd'; if (RegExpPrototypeGetGlobal(regex)) flagString += 'g'; if (RegExpPrototypeGetIgnoreCase(regex)) flagString += 'i'; if (RegExpPrototypeGetMultiline(regex)) flagString += 'm'; if (RegExpPrototypeGetDotAll(regex)) flagString += 's'; if (RegExpPrototypeGetUnicode(regex)) flagString += 'u'; if (RegExpPrototypeGetSticky(regex)) flagString += 'y'; const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal(); const crossRealmRegex = new RegExpFromAnotherRealm(RegExpPrototypeGetSource(regex), flagString); crossRealmRegexes.set(regex, crossRealmRegex); return crossRealmRegex; } function SideEffectFreeRegExpPrototypeSymbolReplace(regex, string, replacement) { return getCrossRealmRegex(regex)[SymbolReplace](string, replacement); } function SideEffectFreeRegExpPrototypeSymbolSplit(regex, string, limit = undefined) { return getCrossRealmRegex(regex)[SymbolSplit](string, limit); } /** * Helper function to lazy-load an initialize-once value. * @template T Return value of initializer * @param {()=>T} initializer Initializer of the lazily loaded value. * @returns {()=>T} */ function getLazy(initializer) { let value; let initialized = false; return function() { if (initialized === false) { value = initializer(); initialized = true; } return value; }; } // Setup user-facing NODE_V8_COVERAGE environment variable that writes // ScriptCoverage objects to a specified directory. function setupCoverageHooks(dir) { const cwd = require('internal/process/execution').tryGetCwd(); const { resolve } = require('path'); const coverageDirectory = resolve(cwd, dir); const { sourceMapCacheToObject } = require('internal/source_map/source_map_cache'); if (process.features.inspector) { internalBinding('profiler').setCoverageDirectory(coverageDirectory); internalBinding('profiler').setSourceMapCacheGetter(sourceMapCacheToObject); } else { process.emitWarning('The inspector is disabled, ' + 'coverage could not be collected', 'Warning'); return ''; } return coverageDirectory; } const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN']; function guessHandleType(fd) { const type = _guessHandleType(fd); return handleTypes[type]; } class WeakReference { #weak = null; // eslint-disable-next-line no-unused-private-class-members #strong = null; #refCount = 0; constructor(object) { this.#weak = new SafeWeakRef(object); } incRef() { this.#refCount++; if (this.#refCount === 1) { const derefed = this.#weak.deref(); if (derefed !== undefined) { this.#strong = derefed; } } return this.#refCount; } decRef() { this.#refCount--; if (this.#refCount === 0) { this.#strong = null; } return this.#refCount; } get() { return this.#weak.deref(); } } const encodingsMap = { __proto__: null }; for (let i = 0; i < encodings.length; ++i) encodingsMap[encodings[i]] = i; module.exports = { getLazy, assertCrypto, assertTypeScript, cachedResult, convertToValidSignal, createClassWrapper, decorateErrorStack, defineOperation, defineLazyProperties, defineReplaceableLazyAttribute, deprecate, deprecateInstantiation, emitExperimentalWarning, encodingsMap, exposeInterface, exposeLazyInterfaces, exposeNamespace, exposeGetterAndSetter, filterDuplicateStrings, filterOwnProperties, getConstructorOf, getCWDURL, getInternalGlobal, getStructuredStack, getSystemErrorMap, getSystemErrorName, getSystemErrorMessage, guessHandleType, isError, isUnderNodeModules, isMacOS, isWindows, join, lazyDOMException, lazyDOMExceptionClass, normalizeEncoding, once, promisify, SideEffectFreeRegExpPrototypeExec, SideEffectFreeRegExpPrototypeSymbolReplace, SideEffectFreeRegExpPrototypeSymbolSplit, sleep, spliceOne, setupCoverageHooks, removeColors, // Symbol used to customize promisify conversion customPromisifyArgs: kCustomPromisifyArgsSymbol, // Symbol used to provide a custom inspect function for an object as an // alternative to using 'inspect' customInspectSymbol: SymbolFor('nodejs.util.inspect.custom'), // Used by the buffer module to capture an internal reference to the // default isEncoding implementation, just in case userland overrides it. kIsEncodingSymbol: Symbol('kIsEncodingSymbol'), kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol'), kEmptyObject, kEnumerableProperty, setOwnProperty, pendingDeprecate, WeakReference, };