'use strict'; const { ArrayFrom, ArrayIsArray, ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, ObjectGetOwnPropertyDescriptors, ObjectGetPrototypeOf, ObjectSetPrototypeOf, ReflectConstruct, } = primordials; const { codes: { ERR_INVALID_ARG_TYPE, ERR_NO_CRYPTO, ERR_UNKNOWN_SIGNAL }, uvErrmapGet, overrideStackTrace, } = require('internal/errors'); const { signals } = internalBinding('constants').os; const { getHiddenValue, setHiddenValue, arrow_message_private_symbol: kArrowMessagePrivateSymbolIndex, decorated_private_symbol: kDecoratedPrivateSymbolIndex, sleep: _sleep } = internalBinding('util'); const { isNativeError } = internalBinding('types'); const noCrypto = !process.versions.openssl; const experimentalWarnings = new Set(); const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex function removeColors(str) { return str.replace(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 Set(); // 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) { if (process.noDeprecation === true) { return fn; } if (code !== undefined && typeof code !== 'string') throw new ERR_INVALID_ARG_TYPE('code', 'string', code); let warned = false; function deprecated(...args) { if (!warned) { warned = true; if (code !== undefined) { if (!codesWarned.has(code)) { process.emitWarning(msg, 'DeprecationWarning', code, deprecated); codesWarned.add(code); } } else { process.emitWarning(msg, 'DeprecationWarning', deprecated); } } if (new.target) { return ReflectConstruct(fn, args, new.target); } return fn.apply(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 decorateErrorStack(err) { if (!(isError(err) && err.stack) || getHiddenValue(err, kDecoratedPrivateSymbolIndex) === true) return; const arrow = getHiddenValue(err, kArrowMessagePrivateSymbolIndex); if (arrow) { err.stack = arrow + err.stack; setHiddenValue(err, kDecoratedPrivateSymbolIndex, true); } } function assertCrypto() { if (noCrypto) throw new ERR_NO_CRYPTO(); } // Return undefined if there is no match. // Move the "slow cases" to a separate function to make sure this function gets // inlined properly. That prioritizes the common case. 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 = `${enc}`.toLowerCase(); if (enc === 'utf8') return 'utf8'; if (enc === 'ucs2') return 'utf16le'; break; case 3: if (enc === 'hex' || enc === 'HEX' || `${enc}`.toLowerCase() === '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 = `${enc}`.toLowerCase(); 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 = `${enc}`.toLowerCase(); if (enc === 'base64') return 'base64'; if (enc === 'latin1' || enc === 'binary') return 'latin1'; break; case 7: if (enc === 'utf16le' || enc === 'UTF16LE' || `${enc}`.toLowerCase() === 'utf16le') return 'utf16le'; break; case 8: if (enc === 'utf-16le' || enc === 'UTF-16LE' || `${enc}`.toLowerCase() === 'utf-16le') return 'utf16le'; break; default: if (enc === '') return 'utf8'; } } function emitExperimentalWarning(feature) { if (experimentalWarnings.has(feature)) return; const msg = `${feature} is an experimental feature. This feature could ` + 'change at any time'; experimentalWarnings.add(feature); process.emitWarning(msg, 'ExperimentalWarning'); } function filterDuplicateStrings(items, low) { const map = new Map(); for (let i = 0; i < items.length; i++) { const item = items[i]; const key = item.toLowerCase(); if (low) { map.set(key, key); } else { map.set(key, item); } } return ArrayFrom(map.values()).sort(); } function cachedResult(fn) { let result; return () => { if (result === undefined) result = fn(); return result.slice(); }; } // 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: { value: type.name }, length: { value: type.length } }); ObjectSetPrototypeOf(fn, type); fn.prototype = type.prototype; return fn; } let signalsToNamesMapping; function getSignalsToNamesMapping() { if (signalsToNamesMapping !== undefined) return signalsToNamesMapping; signalsToNamesMapping = ObjectCreate(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[signal.toUpperCase()]; 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; } function getSystemErrorName(err) { const entry = uvErrmapGet(err); return entry ? entry[0] : `Unknown system error ${err}`; } const kCustomPromisifiedSymbol = Symbol('util.promisify.custom'); const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs'); function promisify(original) { if (typeof original !== 'function') throw new ERR_INVALID_ARG_TYPE('original', 'Function', original); if (original[kCustomPromisifiedSymbol]) { const fn = original[kCustomPromisifiedSymbol]; if (typeof fn !== 'function') { throw new ERR_INVALID_ARG_TYPE('util.promisify.custom', 'Function', fn); } return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { 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) => { original.call(this, ...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]); } }); }); } ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original)); ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { value: fn, enumerable: false, writable: false, configurable: true }); return ObjectDefineProperties( fn, ObjectGetOwnPropertyDescriptors(original) ); } promisify.custom = kCustomPromisifiedSymbol; // The build-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[\\/]/; let getStructuredStack; function isInsideNodeModules() { if (getStructuredStack === 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, // the perf implications should be okay. getStructuredStack = runInNewContext(`(function() { Error.stackTraceLimit = Infinity; return function structuredStack() { const e = new Error(); overrideStackTrace.set(e, (err, trace) => trace); return e.stack; }; })()`, { overrideStackTrace }, { filename: 'structured-stack' }); } const stack = getStructuredStack(); // Iterate over all stack frames and look for the first one not coming // from inside Node.js itself: if (ArrayIsArray(stack)) { for (const frame of stack) { const filename = frame.getFileName(); // If a filename does not start with / or contain \, // it's likely from Node.js core. if (!/^\/|\\/.test(filename)) continue; return kNodeModulesRE.test(filename); } } return false; } function once(callback) { let called = false; return function(...args) { if (called) return; called = true; callback.apply(this, args); }; } let validateUint32; function sleep(msec) { // Lazy-load to avoid a circular dependency. if (validateUint32 === undefined) ({ validateUint32 } = require('internal/validators')); validateUint32(msec, 'msec'); _sleep(msec); } module.exports = { assertCrypto, cachedResult, convertToValidSignal, createClassWrapper, decorateErrorStack, deprecate, emitExperimentalWarning, filterDuplicateStrings, getConstructorOf, getSystemErrorName, isError, isInsideNodeModules, join, normalizeEncoding, once, promisify, sleep, spliceOne, 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: Symbol.for('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') };