• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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