// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. import { validateFunction, validateString } from "./validators.js"; import { normalizeEncoding, slowCases } from "./normalize_encoding.js"; export { normalizeEncoding, slowCases }; export const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom"); export const kEnumerableProperty = Object.create(null); kEnumerableProperty.enumerable = true; export function once(callback) { let called = false; return function (...args) { if (called) return; called = true; Reflect.apply(callback, this, args); }; } export function createDeferredPromise() { let resolve; let reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } // 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. export function deprecate(fn, msg, code) { // TODO(kt3k): Uncomment this // if (process.noDeprecation === true) { // return fn; // } if (code !== undefined) { validateString(code, "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 Reflect.construct(fn, args, new.target); } return Reflect.apply(fn, 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; } // In addition to being accessible through util.promisify.custom, // this symbol is registered globally and can be accessed in any environment as // Symbol.for('nodejs.util.promisify.custom'). export const kCustomPromisifiedSymbol = Symbol.for("nodejs.util.promisify.custom"); // This is an internal Node symbol used by functions returning multiple // arguments, e.g. ['bytesRead', 'buffer'] for fs.read(). const kCustomPromisifyArgsSymbol = Symbol.for( "nodejs.util.promisify.customArgs", ); export const customPromisifyArgs = kCustomPromisifyArgsSymbol; export function promisify( original, ) { validateFunction(original, "original"); if (original[kCustomPromisifiedSymbol]) { const fn = original[kCustomPromisifiedSymbol]; validateFunction(fn, "util.promisify.custom"); return Object.defineProperty(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) => { args.push((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]); } }); try { Reflect.apply(original, this, args); } catch (err) { return reject(err); } }); } Object.setPrototypeOf(fn, Object.getPrototypeOf(original)); Object.defineProperty(fn, kCustomPromisifiedSymbol, { value: fn, enumerable: false, writable: false, configurable: true, }); return Object.defineProperties( fn, Object.getOwnPropertyDescriptors(original), ); } promisify.custom = kCustomPromisifiedSymbol; const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex export function removeColors(str) { return String.prototype.replace(str, colorRegExp, ''); } export 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 e instanceof Error; } export default { createDeferredPromise, customInspectSymbol, kEnumerableProperty, normalizeEncoding, once, deprecate, promisify, removeColors, isError };