1'use strict'; 2 3const { 4 ArrayFrom, 5 ArrayIsArray, 6 Error, 7 Map, 8 ObjectCreate, 9 ObjectDefineProperties, 10 ObjectDefineProperty, 11 ObjectGetOwnPropertyDescriptor, 12 ObjectGetOwnPropertyDescriptors, 13 ObjectGetPrototypeOf, 14 ObjectSetPrototypeOf, 15 Promise, 16 ReflectConstruct, 17 RegExpPrototypeExec, 18 Set, 19 Symbol, 20 SymbolFor, 21} = primordials; 22 23const { 24 toUSVString: _toUSVString, 25} = internalBinding('url'); 26 27const { 28 codes: { 29 ERR_NO_CRYPTO, 30 ERR_UNKNOWN_SIGNAL 31 }, 32 uvErrmapGet, 33 overrideStackTrace, 34} = require('internal/errors'); 35const { signals } = internalBinding('constants').os; 36const { 37 getHiddenValue, 38 setHiddenValue, 39 arrow_message_private_symbol: kArrowMessagePrivateSymbolIndex, 40 decorated_private_symbol: kDecoratedPrivateSymbolIndex, 41 sleep: _sleep 42} = internalBinding('util'); 43const { isNativeError } = internalBinding('types'); 44 45const noCrypto = !process.versions.openssl; 46 47const experimentalWarnings = new Set(); 48 49const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex 50 51const unpairedSurrogateRe = 52 /(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])/; 53function toUSVString(val) { 54 const str = `${val}`; 55 // As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are 56 // slower than `unpairedSurrogateRe.exec()`. 57 const match = RegExpPrototypeExec(unpairedSurrogateRe, str); 58 if (!match) 59 return str; 60 return _toUSVString(str, match.index); 61} 62 63let uvBinding; 64 65function lazyUv() { 66 uvBinding = uvBinding ?? internalBinding('uv'); 67 return uvBinding; 68} 69 70function removeColors(str) { 71 return str.replace(colorRegExp, ''); 72} 73 74function isError(e) { 75 // An error could be an instance of Error while not being a native error 76 // or could be from a different realm and not be instance of Error but still 77 // be a native error. 78 return isNativeError(e) || e instanceof Error; 79} 80 81// Keep a list of deprecation codes that have been warned on so we only warn on 82// each one once. 83const codesWarned = new Set(); 84 85let validateString; 86 87// Mark that a method should not be used. 88// Returns a modified function which warns once by default. 89// If --no-deprecation is set, then it is a no-op. 90function deprecate(fn, msg, code) { 91 if (process.noDeprecation === true) { 92 return fn; 93 } 94 95 // Lazy-load to avoid a circular dependency. 96 if (validateString === undefined) 97 ({ validateString } = require('internal/validators')); 98 99 if (code !== undefined) 100 validateString(code, 'code'); 101 102 let warned = false; 103 function deprecated(...args) { 104 if (!warned) { 105 warned = true; 106 if (code !== undefined) { 107 if (!codesWarned.has(code)) { 108 process.emitWarning(msg, 'DeprecationWarning', code, deprecated); 109 codesWarned.add(code); 110 } 111 } else { 112 process.emitWarning(msg, 'DeprecationWarning', deprecated); 113 } 114 } 115 if (new.target) { 116 return ReflectConstruct(fn, args, new.target); 117 } 118 return fn.apply(this, args); 119 } 120 121 // The wrapper will keep the same prototype as fn to maintain prototype chain 122 ObjectSetPrototypeOf(deprecated, fn); 123 if (fn.prototype) { 124 // Setting this (rather than using Object.setPrototype, as above) ensures 125 // that calling the unwrapped constructor gives an instanceof the wrapped 126 // constructor. 127 deprecated.prototype = fn.prototype; 128 } 129 130 return deprecated; 131} 132 133function decorateErrorStack(err) { 134 if (!(isError(err) && err.stack) || 135 getHiddenValue(err, kDecoratedPrivateSymbolIndex) === true) 136 return; 137 138 const arrow = getHiddenValue(err, kArrowMessagePrivateSymbolIndex); 139 140 if (arrow) { 141 err.stack = arrow + err.stack; 142 setHiddenValue(err, kDecoratedPrivateSymbolIndex, true); 143 } 144} 145 146function assertCrypto() { 147 if (noCrypto) 148 throw new ERR_NO_CRYPTO(); 149} 150 151// Return undefined if there is no match. 152// Move the "slow cases" to a separate function to make sure this function gets 153// inlined properly. That prioritizes the common case. 154function normalizeEncoding(enc) { 155 if (enc == null || enc === 'utf8' || enc === 'utf-8') return 'utf8'; 156 return slowCases(enc); 157} 158 159function slowCases(enc) { 160 switch (enc.length) { 161 case 4: 162 if (enc === 'UTF8') return 'utf8'; 163 if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le'; 164 enc = `${enc}`.toLowerCase(); 165 if (enc === 'utf8') return 'utf8'; 166 if (enc === 'ucs2') return 'utf16le'; 167 break; 168 case 3: 169 if (enc === 'hex' || enc === 'HEX' || `${enc}`.toLowerCase() === 'hex') 170 return 'hex'; 171 break; 172 case 5: 173 if (enc === 'ascii') return 'ascii'; 174 if (enc === 'ucs-2') return 'utf16le'; 175 if (enc === 'UTF-8') return 'utf8'; 176 if (enc === 'ASCII') return 'ascii'; 177 if (enc === 'UCS-2') return 'utf16le'; 178 enc = `${enc}`.toLowerCase(); 179 if (enc === 'utf-8') return 'utf8'; 180 if (enc === 'ascii') return 'ascii'; 181 if (enc === 'ucs-2') return 'utf16le'; 182 break; 183 case 6: 184 if (enc === 'base64') return 'base64'; 185 if (enc === 'latin1' || enc === 'binary') return 'latin1'; 186 if (enc === 'BASE64') return 'base64'; 187 if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1'; 188 enc = `${enc}`.toLowerCase(); 189 if (enc === 'base64') return 'base64'; 190 if (enc === 'latin1' || enc === 'binary') return 'latin1'; 191 break; 192 case 7: 193 if (enc === 'utf16le' || enc === 'UTF16LE' || 194 `${enc}`.toLowerCase() === 'utf16le') 195 return 'utf16le'; 196 break; 197 case 8: 198 if (enc === 'utf-16le' || enc === 'UTF-16LE' || 199 `${enc}`.toLowerCase() === 'utf-16le') 200 return 'utf16le'; 201 break; 202 case 9: 203 if (enc === 'base64url' || enc === 'BASE64URL' || 204 `${enc}`.toLowerCase() === 'base64url') 205 return 'base64url'; 206 break; 207 default: 208 if (enc === '') return 'utf8'; 209 } 210} 211 212function emitExperimentalWarning(feature) { 213 if (experimentalWarnings.has(feature)) return; 214 const msg = `${feature} is an experimental feature. This feature could ` + 215 'change at any time'; 216 experimentalWarnings.add(feature); 217 process.emitWarning(msg, 'ExperimentalWarning'); 218} 219 220function filterDuplicateStrings(items, low) { 221 const map = new Map(); 222 for (let i = 0; i < items.length; i++) { 223 const item = items[i]; 224 const key = item.toLowerCase(); 225 if (low) { 226 map.set(key, key); 227 } else { 228 map.set(key, item); 229 } 230 } 231 return ArrayFrom(map.values()).sort(); 232} 233 234function cachedResult(fn) { 235 let result; 236 return () => { 237 if (result === undefined) 238 result = fn(); 239 return result.slice(); 240 }; 241} 242 243// Useful for Wrapping an ES6 Class with a constructor Function that 244// does not require the new keyword. For instance: 245// class A { constructor(x) {this.x = x;}} 246// const B = createClassWrapper(A); 247// B() instanceof A // true 248// B() instanceof B // true 249function createClassWrapper(type) { 250 function fn(...args) { 251 return ReflectConstruct(type, args, new.target || type); 252 } 253 // Mask the wrapper function name and length values 254 ObjectDefineProperties(fn, { 255 name: { value: type.name }, 256 length: { value: type.length } 257 }); 258 ObjectSetPrototypeOf(fn, type); 259 fn.prototype = type.prototype; 260 return fn; 261} 262 263let signalsToNamesMapping; 264function getSignalsToNamesMapping() { 265 if (signalsToNamesMapping !== undefined) 266 return signalsToNamesMapping; 267 268 signalsToNamesMapping = ObjectCreate(null); 269 for (const key in signals) { 270 signalsToNamesMapping[signals[key]] = key; 271 } 272 273 return signalsToNamesMapping; 274} 275 276function convertToValidSignal(signal) { 277 if (typeof signal === 'number' && getSignalsToNamesMapping()[signal]) 278 return signal; 279 280 if (typeof signal === 'string') { 281 const signalName = signals[signal.toUpperCase()]; 282 if (signalName) return signalName; 283 } 284 285 throw new ERR_UNKNOWN_SIGNAL(signal); 286} 287 288function getConstructorOf(obj) { 289 while (obj) { 290 const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor'); 291 if (descriptor !== undefined && 292 typeof descriptor.value === 'function' && 293 descriptor.value.name !== '') { 294 return descriptor.value; 295 } 296 297 obj = ObjectGetPrototypeOf(obj); 298 } 299 300 return null; 301} 302 303function getSystemErrorName(err) { 304 const entry = uvErrmapGet(err); 305 return entry ? entry[0] : `Unknown system error ${err}`; 306} 307 308function getSystemErrorMap() { 309 return lazyUv().getErrorMap(); 310} 311 312const kCustomPromisifiedSymbol = SymbolFor('nodejs.util.promisify.custom'); 313const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs'); 314 315let validateFunction; 316 317function promisify(original) { 318 // Lazy-load to avoid a circular dependency. 319 if (validateFunction === undefined) 320 ({ validateFunction } = require('internal/validators')); 321 322 validateFunction(original, 'original'); 323 324 if (original[kCustomPromisifiedSymbol]) { 325 const fn = original[kCustomPromisifiedSymbol]; 326 327 validateFunction(fn, 'util.promisify.custom'); 328 329 return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { 330 value: fn, enumerable: false, writable: false, configurable: true 331 }); 332 } 333 334 // Names to create an object from in case the callback receives multiple 335 // arguments, e.g. ['bytesRead', 'buffer'] for fs.read. 336 const argumentNames = original[kCustomPromisifyArgsSymbol]; 337 338 function fn(...args) { 339 return new Promise((resolve, reject) => { 340 original.call(this, ...args, (err, ...values) => { 341 if (err) { 342 return reject(err); 343 } 344 if (argumentNames !== undefined && values.length > 1) { 345 const obj = {}; 346 for (let i = 0; i < argumentNames.length; i++) 347 obj[argumentNames[i]] = values[i]; 348 resolve(obj); 349 } else { 350 resolve(values[0]); 351 } 352 }); 353 }); 354 } 355 356 ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original)); 357 358 ObjectDefineProperty(fn, kCustomPromisifiedSymbol, { 359 value: fn, enumerable: false, writable: false, configurable: true 360 }); 361 return ObjectDefineProperties( 362 fn, 363 ObjectGetOwnPropertyDescriptors(original) 364 ); 365} 366 367promisify.custom = kCustomPromisifiedSymbol; 368 369// The built-in Array#join is slower in v8 6.0 370function join(output, separator) { 371 let str = ''; 372 if (output.length !== 0) { 373 const lastIndex = output.length - 1; 374 for (let i = 0; i < lastIndex; i++) { 375 // It is faster not to use a template string here 376 str += output[i]; 377 str += separator; 378 } 379 str += output[lastIndex]; 380 } 381 return str; 382} 383 384// As of V8 6.6, depending on the size of the array, this is anywhere 385// between 1.5-10x faster than the two-arg version of Array#splice() 386function spliceOne(list, index) { 387 for (; index + 1 < list.length; index++) 388 list[index] = list[index + 1]; 389 list.pop(); 390} 391 392const kNodeModulesRE = /^(.*)[\\/]node_modules[\\/]/; 393 394let getStructuredStack; 395 396function isInsideNodeModules() { 397 if (getStructuredStack === undefined) { 398 // Lazy-load to avoid a circular dependency. 399 const { runInNewContext } = require('vm'); 400 // Use `runInNewContext()` to get something tamper-proof and 401 // side-effect-free. Since this is currently only used for a deprecated API, 402 // the perf implications should be okay. 403 getStructuredStack = runInNewContext(`(function() { 404 Error.stackTraceLimit = Infinity; 405 return function structuredStack() { 406 const e = new Error(); 407 overrideStackTrace.set(e, (err, trace) => trace); 408 return e.stack; 409 }; 410 })()`, { overrideStackTrace }, { filename: 'structured-stack' }); 411 } 412 413 const stack = getStructuredStack(); 414 415 // Iterate over all stack frames and look for the first one not coming 416 // from inside Node.js itself: 417 if (ArrayIsArray(stack)) { 418 for (const frame of stack) { 419 const filename = frame.getFileName(); 420 // If a filename does not start with / or contain \, 421 // it's likely from Node.js core. 422 if (!/^\/|\\/.test(filename)) 423 continue; 424 return kNodeModulesRE.test(filename); 425 } 426 } 427 return false; 428} 429 430function once(callback) { 431 let called = false; 432 return function(...args) { 433 if (called) return; 434 called = true; 435 callback.apply(this, args); 436 }; 437} 438 439let validateUint32; 440 441function sleep(msec) { 442 // Lazy-load to avoid a circular dependency. 443 if (validateUint32 === undefined) 444 ({ validateUint32 } = require('internal/validators')); 445 446 validateUint32(msec, 'msec'); 447 _sleep(msec); 448} 449 450function createDeferredPromise() { 451 let resolve; 452 let reject; 453 const promise = new Promise((res, rej) => { 454 resolve = res; 455 reject = rej; 456 }); 457 458 return { promise, resolve, reject }; 459} 460 461module.exports = { 462 assertCrypto, 463 cachedResult, 464 convertToValidSignal, 465 createClassWrapper, 466 createDeferredPromise, 467 decorateErrorStack, 468 deprecate, 469 emitExperimentalWarning, 470 filterDuplicateStrings, 471 getConstructorOf, 472 getSystemErrorMap, 473 getSystemErrorName, 474 isError, 475 isInsideNodeModules, 476 join, 477 normalizeEncoding, 478 once, 479 promisify, 480 sleep, 481 spliceOne, 482 toUSVString, 483 removeColors, 484 485 // Symbol used to customize promisify conversion 486 customPromisifyArgs: kCustomPromisifyArgsSymbol, 487 488 // Symbol used to provide a custom inspect function for an object as an 489 // alternative to using 'inspect' 490 customInspectSymbol: SymbolFor('nodejs.util.inspect.custom'), 491 492 // Used by the buffer module to capture an internal reference to the 493 // default isEncoding implementation, just in case userland overrides it. 494 kIsEncodingSymbol: Symbol('kIsEncodingSymbol'), 495 kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol') 496}; 497