mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
ef16319eff
util.promisify landed without using the module.exports = {} pattern. This fixes it up for consistency PR-URL: https://github.com/nodejs/node/pull/12998 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
282 lines
7.7 KiB
JavaScript
282 lines
7.7 KiB
JavaScript
'use strict';
|
|
|
|
const errors = require('internal/errors');
|
|
const binding = process.binding('util');
|
|
const signals = process.binding('constants').os.signals;
|
|
|
|
const { createPromise, promiseResolve, promiseReject } = binding;
|
|
|
|
const kArrowMessagePrivateSymbolIndex = binding['arrow_message_private_symbol'];
|
|
const kDecoratedPrivateSymbolIndex = binding['decorated_private_symbol'];
|
|
const noCrypto = !process.versions.openssl;
|
|
|
|
function isError(e) {
|
|
return objectToString(e) === '[object Error]' || e instanceof Error;
|
|
}
|
|
|
|
function objectToString(o) {
|
|
return Object.prototype.toString.call(o);
|
|
}
|
|
|
|
// 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) {
|
|
// Allow for deprecating things in the process of starting up.
|
|
if (global.process === undefined) {
|
|
return function(...args) {
|
|
return deprecate(fn, msg).apply(this, args);
|
|
};
|
|
}
|
|
|
|
if (process.noDeprecation === true) {
|
|
return fn;
|
|
}
|
|
|
|
if (code !== undefined && typeof code !== 'string')
|
|
throw new TypeError('`code` argument must be a string');
|
|
|
|
var warned = false;
|
|
function deprecated(...args) {
|
|
if (!warned) {
|
|
warned = true;
|
|
if (code !== undefined) {
|
|
process.emitWarning(msg, 'DeprecationWarning', code, deprecated);
|
|
} else {
|
|
process.emitWarning(msg, 'DeprecationWarning', deprecated);
|
|
}
|
|
}
|
|
if (new.target) {
|
|
return Reflect.construct(fn, args, new.target);
|
|
}
|
|
return fn.apply(this, args);
|
|
}
|
|
|
|
// The wrapper will keep the same prototype as fn to maintain prototype chain
|
|
Object.setPrototypeOf(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) ||
|
|
binding.getHiddenValue(err, kDecoratedPrivateSymbolIndex) === true)
|
|
return;
|
|
|
|
const arrow = binding.getHiddenValue(err, kArrowMessagePrivateSymbolIndex);
|
|
|
|
if (arrow) {
|
|
err.stack = arrow + err.stack;
|
|
binding.setHiddenValue(err, kDecoratedPrivateSymbolIndex, true);
|
|
}
|
|
}
|
|
|
|
function assertCrypto() {
|
|
if (noCrypto)
|
|
throw new Error('Node.js is not compiled with openssl crypto support');
|
|
}
|
|
|
|
// The loop should only run at most twice, retrying with lowercased enc
|
|
// if there is no match in the first pass.
|
|
// We use a loop instead of branching to retry with a helper
|
|
// function in order to avoid the performance hit.
|
|
// Return undefined if there is no match.
|
|
function normalizeEncoding(enc) {
|
|
if (!enc) return 'utf8';
|
|
var retried;
|
|
while (true) {
|
|
switch (enc) {
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
return 'utf8';
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
case 'utf16le':
|
|
case 'utf-16le':
|
|
return 'utf16le';
|
|
case 'latin1':
|
|
case 'binary':
|
|
return 'latin1';
|
|
case 'base64':
|
|
case 'ascii':
|
|
case 'hex':
|
|
return enc;
|
|
default:
|
|
if (retried) return; // undefined
|
|
enc = ('' + enc).toLowerCase();
|
|
retried = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function filterDuplicateStrings(items, low) {
|
|
const map = new Map();
|
|
for (var 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 Array.from(map.values()).sort();
|
|
}
|
|
|
|
function cachedResult(fn) {
|
|
var 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 Reflect.construct(type, args, new.target || type);
|
|
}
|
|
// Mask the wrapper function name and length values
|
|
Object.defineProperties(fn, {
|
|
name: {value: type.name},
|
|
length: {value: type.length}
|
|
});
|
|
Object.setPrototypeOf(fn, type);
|
|
fn.prototype = type.prototype;
|
|
return fn;
|
|
}
|
|
|
|
let signalsToNamesMapping;
|
|
function getSignalsToNamesMapping() {
|
|
if (signalsToNamesMapping !== undefined)
|
|
return signalsToNamesMapping;
|
|
|
|
signalsToNamesMapping = Object.create(null);
|
|
for (var 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 errors.Error('ERR_UNKNOWN_SIGNAL', signal);
|
|
}
|
|
|
|
function getConstructorOf(obj) {
|
|
while (obj) {
|
|
var descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor');
|
|
if (descriptor !== undefined &&
|
|
typeof descriptor.value === 'function' &&
|
|
descriptor.value.name !== '') {
|
|
return descriptor.value;
|
|
}
|
|
|
|
obj = Object.getPrototypeOf(obj);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
const kCustomPromisifiedSymbol = Symbol('util.promisify.custom');
|
|
const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs');
|
|
|
|
function promisify(orig) {
|
|
if (typeof orig !== 'function') {
|
|
const errors = require('internal/errors');
|
|
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'original', 'function');
|
|
}
|
|
|
|
if (orig[kCustomPromisifiedSymbol]) {
|
|
const fn = orig[kCustomPromisifiedSymbol];
|
|
if (typeof fn !== 'function') {
|
|
throw new TypeError('The [util.promisify.custom] property must be ' +
|
|
'a function');
|
|
}
|
|
Object.defineProperty(fn, kCustomPromisifiedSymbol, {
|
|
value: fn, enumerable: false, writable: false, configurable: true
|
|
});
|
|
return fn;
|
|
}
|
|
|
|
// Names to create an object from in case the callback receives multiple
|
|
// arguments, e.g. ['stdout', 'stderr'] for child_process.exec.
|
|
const argumentNames = orig[kCustomPromisifyArgsSymbol];
|
|
|
|
function fn(...args) {
|
|
const promise = createPromise();
|
|
try {
|
|
orig.call(this, ...args, (err, ...values) => {
|
|
if (err) {
|
|
promiseReject(promise, err);
|
|
} else if (argumentNames !== undefined && values.length > 1) {
|
|
const obj = {};
|
|
for (var i = 0; i < argumentNames.length; i++)
|
|
obj[argumentNames[i]] = values[i];
|
|
promiseResolve(promise, obj);
|
|
} else {
|
|
promiseResolve(promise, values[0]);
|
|
}
|
|
});
|
|
} catch (err) {
|
|
promiseReject(promise, err);
|
|
}
|
|
return promise;
|
|
}
|
|
|
|
Object.setPrototypeOf(fn, Object.getPrototypeOf(orig));
|
|
|
|
Object.defineProperty(fn, kCustomPromisifiedSymbol, {
|
|
value: fn, enumerable: false, writable: false, configurable: true
|
|
});
|
|
return Object.defineProperties(fn, Object.getOwnPropertyDescriptors(orig));
|
|
}
|
|
|
|
promisify.custom = kCustomPromisifiedSymbol;
|
|
|
|
module.exports = {
|
|
assertCrypto,
|
|
cachedResult,
|
|
convertToValidSignal,
|
|
createClassWrapper,
|
|
decorateErrorStack,
|
|
deprecate,
|
|
filterDuplicateStrings,
|
|
getConstructorOf,
|
|
isError,
|
|
normalizeEncoding,
|
|
objectToString,
|
|
promisify,
|
|
|
|
// 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('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('node.isEncoding')
|
|
};
|