mirror of
https://github.com/nodejs/node.git
synced 2025-05-22 03:47:11 +00:00

This commit adds code coverage functionality to the node:test module. When node:test is used in conjunction with the new --test-coverage CLI flag, a coverage report is created when the test runner finishes. The coverage summary is forwarded to any test runner reporters so that the display can be customized as desired. This new functionality is compatible with the existing NODE_V8_COVERAGE environment variable as well. There are still several limitations, which will be addressed in subsequent pull requests: - Coverage is only reported for a single process. It is possible to merge coverage reports together. Once this is done, the --test flag will be supported as well. - Source maps are not currently supported. - Excluding specific files or directories from the coverage report is not currently supported. Node core modules and node_modules/ are excluded though. PR-URL: https://github.com/nodejs/node/pull/46017 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
794 lines
21 KiB
JavaScript
794 lines
21 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ArrayBufferPrototypeGetByteLength,
|
|
ArrayFrom,
|
|
ArrayIsArray,
|
|
ArrayPrototypePush,
|
|
ArrayPrototypeSlice,
|
|
ArrayPrototypeSort,
|
|
Error,
|
|
FunctionPrototypeCall,
|
|
ObjectCreate,
|
|
ObjectDefineProperties,
|
|
ObjectDefineProperty,
|
|
ObjectGetOwnPropertyDescriptor,
|
|
ObjectGetOwnPropertyDescriptors,
|
|
ObjectGetPrototypeOf,
|
|
ObjectFreeze,
|
|
ObjectPrototypeHasOwnProperty,
|
|
ObjectSetPrototypeOf,
|
|
ObjectValues,
|
|
Promise,
|
|
ReflectApply,
|
|
ReflectConstruct,
|
|
RegExpPrototypeExec,
|
|
RegExpPrototypeGetDotAll,
|
|
RegExpPrototypeGetGlobal,
|
|
RegExpPrototypeGetHasIndices,
|
|
RegExpPrototypeGetIgnoreCase,
|
|
RegExpPrototypeGetMultiline,
|
|
RegExpPrototypeGetSticky,
|
|
RegExpPrototypeGetUnicode,
|
|
RegExpPrototypeGetSource,
|
|
SafeMap,
|
|
SafeSet,
|
|
SafeWeakMap,
|
|
StringPrototypeReplace,
|
|
StringPrototypeToLowerCase,
|
|
StringPrototypeToUpperCase,
|
|
Symbol,
|
|
SymbolFor,
|
|
SymbolReplace,
|
|
SymbolSplit,
|
|
} = primordials;
|
|
|
|
const {
|
|
hideStackFrames,
|
|
codes: {
|
|
ERR_NO_CRYPTO,
|
|
ERR_UNKNOWN_SIGNAL
|
|
},
|
|
uvErrmapGet,
|
|
overrideStackTrace,
|
|
} = require('internal/errors');
|
|
const { signals } = internalBinding('constants').os;
|
|
const {
|
|
isArrayBufferDetached: _isArrayBufferDetached,
|
|
privateSymbols: {
|
|
arrow_message_private_symbol,
|
|
decorated_private_symbol,
|
|
},
|
|
sleep: _sleep,
|
|
toUSVString: _toUSVString,
|
|
} = internalBinding('util');
|
|
const { isNativeError } = internalBinding('types');
|
|
|
|
const noCrypto = !process.versions.openssl;
|
|
|
|
const experimentalWarnings = new SafeSet();
|
|
|
|
const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex
|
|
|
|
const unpairedSurrogateRe =
|
|
/(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])/;
|
|
function toUSVString(val) {
|
|
const str = `${val}`;
|
|
// As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are
|
|
// slower than `unpairedSurrogateRe.exec()`.
|
|
const match = RegExpPrototypeExec(unpairedSurrogateRe, str);
|
|
if (!match)
|
|
return str;
|
|
return _toUSVString(str, match.index);
|
|
}
|
|
|
|
let uvBinding;
|
|
|
|
function lazyUv() {
|
|
uvBinding ??= internalBinding('uv');
|
|
return uvBinding;
|
|
}
|
|
|
|
function removeColors(str) {
|
|
return StringPrototypeReplace(str, 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 SafeSet();
|
|
|
|
let validateString;
|
|
|
|
// 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, useEmitSync) {
|
|
if (process.noDeprecation === true) {
|
|
return fn;
|
|
}
|
|
|
|
// Lazy-load to avoid a circular dependency.
|
|
if (validateString === undefined)
|
|
({ validateString } = require('internal/validators'));
|
|
|
|
if (code !== undefined)
|
|
validateString(code, 'code');
|
|
|
|
let warned = false;
|
|
function deprecated(...args) {
|
|
if (!warned) {
|
|
warned = true;
|
|
if (code !== undefined) {
|
|
if (!codesWarned.has(code)) {
|
|
const emitWarning = useEmitSync ?
|
|
require('internal/process/warning').emitWarningSync :
|
|
process.emitWarning;
|
|
emitWarning(msg, 'DeprecationWarning', code, deprecated);
|
|
codesWarned.add(code);
|
|
}
|
|
} else {
|
|
process.emitWarning(msg, 'DeprecationWarning', deprecated);
|
|
}
|
|
}
|
|
if (new.target) {
|
|
return ReflectConstruct(fn, args, new.target);
|
|
}
|
|
return ReflectApply(fn, 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) || err[decorated_private_symbol])
|
|
return;
|
|
|
|
const arrow = err[arrow_message_private_symbol];
|
|
|
|
if (arrow) {
|
|
err.stack = arrow + err.stack;
|
|
err[decorated_private_symbol] = 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;
|
|
case 9:
|
|
if (enc === 'base64url' || enc === 'BASE64URL' ||
|
|
`${enc}`.toLowerCase() === 'base64url')
|
|
return 'base64url';
|
|
break;
|
|
default:
|
|
if (enc === '') return 'utf8';
|
|
}
|
|
}
|
|
|
|
function emitExperimentalWarning(feature) {
|
|
if (experimentalWarnings.has(feature)) return;
|
|
const msg = `${feature} is an experimental feature and might change at any time`;
|
|
experimentalWarnings.add(feature);
|
|
process.emitWarning(msg, 'ExperimentalWarning');
|
|
}
|
|
|
|
function filterDuplicateStrings(items, low) {
|
|
const map = new SafeMap();
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
const key = StringPrototypeToLowerCase(item);
|
|
if (low) {
|
|
map.set(key, key);
|
|
} else {
|
|
map.set(key, item);
|
|
}
|
|
}
|
|
return ArrayPrototypeSort(ArrayFrom(map.values()));
|
|
}
|
|
|
|
function cachedResult(fn) {
|
|
let result;
|
|
return () => {
|
|
if (result === undefined)
|
|
result = fn();
|
|
return ArrayPrototypeSlice(result);
|
|
};
|
|
}
|
|
|
|
// 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: { __proto__: null, value: type.name },
|
|
length: { __proto__: null, 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[StringPrototypeToUpperCase(signal)];
|
|
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}`;
|
|
}
|
|
|
|
function getSystemErrorMap() {
|
|
return lazyUv().getErrorMap();
|
|
}
|
|
|
|
const kCustomPromisifiedSymbol = SymbolFor('nodejs.util.promisify.custom');
|
|
const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs');
|
|
|
|
let validateFunction;
|
|
|
|
function promisify(original) {
|
|
// Lazy-load to avoid a circular dependency.
|
|
if (validateFunction === undefined)
|
|
({ validateFunction } = require('internal/validators'));
|
|
|
|
validateFunction(original, 'original');
|
|
|
|
if (original[kCustomPromisifiedSymbol]) {
|
|
const fn = original[kCustomPromisifiedSymbol];
|
|
|
|
validateFunction(fn, 'util.promisify.custom');
|
|
|
|
return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, {
|
|
__proto__: null,
|
|
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) => {
|
|
ArrayPrototypePush(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]);
|
|
}
|
|
});
|
|
ReflectApply(original, this, args);
|
|
});
|
|
}
|
|
|
|
ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original));
|
|
|
|
ObjectDefineProperty(fn, kCustomPromisifiedSymbol, {
|
|
__proto__: null,
|
|
value: fn, enumerable: false, writable: false, configurable: true
|
|
});
|
|
|
|
const descriptors = ObjectGetOwnPropertyDescriptors(original);
|
|
const propertiesValues = ObjectValues(descriptors);
|
|
for (let i = 0; i < propertiesValues.length; i++) {
|
|
// We want to use null-prototype objects to not rely on globally mutable
|
|
// %Object.prototype%.
|
|
ObjectSetPrototypeOf(propertiesValues[i], null);
|
|
}
|
|
return ObjectDefineProperties(fn, descriptors);
|
|
}
|
|
|
|
promisify.custom = kCustomPromisifiedSymbol;
|
|
|
|
// The built-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() {
|
|
try { Error.stackTraceLimit = Infinity; } catch {}
|
|
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 (RegExpPrototypeExec(/^\/|\\/, filename) === null)
|
|
continue;
|
|
return RegExpPrototypeExec(kNodeModulesRE, filename) !== null;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function once(callback) {
|
|
let called = false;
|
|
return function(...args) {
|
|
if (called) return;
|
|
called = true;
|
|
return ReflectApply(callback, 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);
|
|
}
|
|
|
|
function createDeferredPromise() {
|
|
let resolve;
|
|
let reject;
|
|
const promise = new Promise((res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
});
|
|
|
|
return { promise, resolve, reject };
|
|
}
|
|
|
|
// https://heycam.github.io/webidl/#define-the-operations
|
|
function defineOperation(target, name, method) {
|
|
ObjectDefineProperty(target, name, {
|
|
__proto__: null,
|
|
writable: true,
|
|
enumerable: true,
|
|
configurable: true,
|
|
value: method
|
|
});
|
|
}
|
|
|
|
// https://heycam.github.io/webidl/#es-interfaces
|
|
function exposeInterface(target, name, interfaceObject) {
|
|
ObjectDefineProperty(target, name, {
|
|
__proto__: null,
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: true,
|
|
value: interfaceObject
|
|
});
|
|
}
|
|
|
|
function defineLazyProperties(target, id, keys, enumerable = true) {
|
|
const descriptors = { __proto__: null };
|
|
let mod;
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
let lazyLoadedValue;
|
|
function set(value) {
|
|
ObjectDefineProperty(target, key, {
|
|
__proto__: null,
|
|
writable: true,
|
|
value,
|
|
});
|
|
}
|
|
ObjectDefineProperty(set, 'name', {
|
|
__proto__: null,
|
|
value: `set ${key}`,
|
|
});
|
|
function get() {
|
|
mod ??= require(id);
|
|
if (lazyLoadedValue === undefined) {
|
|
lazyLoadedValue = mod[key];
|
|
set(lazyLoadedValue);
|
|
}
|
|
return lazyLoadedValue;
|
|
}
|
|
ObjectDefineProperty(get, 'name', {
|
|
__proto__: null,
|
|
value: `get ${key}`,
|
|
});
|
|
descriptors[key] = {
|
|
__proto__: null,
|
|
configurable: true,
|
|
enumerable,
|
|
get,
|
|
set,
|
|
};
|
|
}
|
|
ObjectDefineProperties(target, descriptors);
|
|
}
|
|
|
|
function defineReplaceableLazyAttribute(target, id, keys, writable = true, check) {
|
|
let mod;
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
let value;
|
|
let setterCalled = false;
|
|
|
|
function get() {
|
|
if (check !== undefined) {
|
|
FunctionPrototypeCall(check, this);
|
|
}
|
|
if (setterCalled) {
|
|
return value;
|
|
}
|
|
mod ??= require(id);
|
|
value ??= mod[key];
|
|
return value;
|
|
}
|
|
|
|
ObjectDefineProperty(get, 'name', {
|
|
__proto__: null,
|
|
value: `get ${key}`,
|
|
});
|
|
|
|
function set(val) {
|
|
setterCalled = true;
|
|
value = val;
|
|
}
|
|
ObjectDefineProperty(set, 'name', {
|
|
__proto__: null,
|
|
value: `set ${key}`,
|
|
});
|
|
|
|
ObjectDefineProperty(target, key, {
|
|
__proto__: null,
|
|
enumerable: true,
|
|
configurable: true,
|
|
get,
|
|
set: writable ? set : undefined,
|
|
});
|
|
}
|
|
}
|
|
|
|
function exposeLazyInterfaces(target, id, keys) {
|
|
defineLazyProperties(target, id, keys, false);
|
|
}
|
|
|
|
let _DOMException;
|
|
const lazyDOMExceptionClass = () => {
|
|
_DOMException ??= internalBinding('messaging').DOMException;
|
|
return _DOMException;
|
|
};
|
|
|
|
const lazyDOMException = hideStackFrames((message, name) => {
|
|
_DOMException ??= internalBinding('messaging').DOMException;
|
|
return new _DOMException(message, name);
|
|
});
|
|
|
|
const kEnumerableProperty = ObjectCreate(null);
|
|
kEnumerableProperty.enumerable = true;
|
|
ObjectFreeze(kEnumerableProperty);
|
|
|
|
const kEmptyObject = ObjectFreeze(ObjectCreate(null));
|
|
|
|
function filterOwnProperties(source, keys) {
|
|
const filtered = ObjectCreate(null);
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const key = keys[i];
|
|
if (ObjectPrototypeHasOwnProperty(source, key)) {
|
|
filtered[key] = source[key];
|
|
}
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
|
|
/**
|
|
* Mimics `obj[key] = value` but ignoring potential prototype inheritance.
|
|
* @param {any} obj
|
|
* @param {string} key
|
|
* @param {any} value
|
|
* @returns {any}
|
|
*/
|
|
function setOwnProperty(obj, key, value) {
|
|
return ObjectDefineProperty(obj, key, {
|
|
__proto__: null,
|
|
configurable: true,
|
|
enumerable: true,
|
|
value,
|
|
writable: true,
|
|
});
|
|
}
|
|
|
|
let internalGlobal;
|
|
function getInternalGlobal() {
|
|
if (internalGlobal == null) {
|
|
// Lazy-load to avoid a circular dependency.
|
|
const { runInNewContext } = require('vm');
|
|
internalGlobal = runInNewContext('this', undefined, { contextName: 'internal' });
|
|
}
|
|
return internalGlobal;
|
|
}
|
|
|
|
function SideEffectFreeRegExpPrototypeExec(regex, string) {
|
|
const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
|
|
return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string);
|
|
}
|
|
|
|
const crossRelmRegexes = new SafeWeakMap();
|
|
function getCrossRelmRegex(regex) {
|
|
const cached = crossRelmRegexes.get(regex);
|
|
if (cached) return cached;
|
|
|
|
let flagString = '';
|
|
if (RegExpPrototypeGetHasIndices(regex)) flagString += 'd';
|
|
if (RegExpPrototypeGetGlobal(regex)) flagString += 'g';
|
|
if (RegExpPrototypeGetIgnoreCase(regex)) flagString += 'i';
|
|
if (RegExpPrototypeGetMultiline(regex)) flagString += 'm';
|
|
if (RegExpPrototypeGetDotAll(regex)) flagString += 's';
|
|
if (RegExpPrototypeGetUnicode(regex)) flagString += 'u';
|
|
if (RegExpPrototypeGetSticky(regex)) flagString += 'y';
|
|
|
|
const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
|
|
const crossRelmRegex = new RegExpFromAnotherRealm(RegExpPrototypeGetSource(regex), flagString);
|
|
crossRelmRegexes.set(regex, crossRelmRegex);
|
|
return crossRelmRegex;
|
|
}
|
|
|
|
function SideEffectFreeRegExpPrototypeSymbolReplace(regex, string, replacement) {
|
|
return getCrossRelmRegex(regex)[SymbolReplace](string, replacement);
|
|
}
|
|
|
|
function SideEffectFreeRegExpPrototypeSymbolSplit(regex, string, limit = undefined) {
|
|
return getCrossRelmRegex(regex)[SymbolSplit](string, limit);
|
|
}
|
|
|
|
|
|
function isArrayBufferDetached(value) {
|
|
if (ArrayBufferPrototypeGetByteLength(value) === 0) {
|
|
return _isArrayBufferDetached(value);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Helper function to lazy-load an initialize-once value.
|
|
* @template T Return value of initializer
|
|
* @param {()=>T} initializer Initializer of the lazily loaded value.
|
|
* @returns {()=>T}
|
|
*/
|
|
function getLazy(initializer) {
|
|
let value;
|
|
let initialized = false;
|
|
return function() {
|
|
if (initialized === false) {
|
|
value = initializer();
|
|
initialized = true;
|
|
}
|
|
return value;
|
|
};
|
|
}
|
|
|
|
// Setup user-facing NODE_V8_COVERAGE environment variable that writes
|
|
// ScriptCoverage objects to a specified directory.
|
|
function setupCoverageHooks(dir) {
|
|
const cwd = require('internal/process/execution').tryGetCwd();
|
|
const { resolve } = require('path');
|
|
const coverageDirectory = resolve(cwd, dir);
|
|
const { sourceMapCacheToObject } =
|
|
require('internal/source_map/source_map_cache');
|
|
|
|
if (process.features.inspector) {
|
|
internalBinding('profiler').setCoverageDirectory(coverageDirectory);
|
|
internalBinding('profiler').setSourceMapCacheGetter(sourceMapCacheToObject);
|
|
} else {
|
|
process.emitWarning('The inspector is disabled, ' +
|
|
'coverage could not be collected',
|
|
'Warning');
|
|
return '';
|
|
}
|
|
return coverageDirectory;
|
|
}
|
|
|
|
module.exports = {
|
|
getLazy,
|
|
assertCrypto,
|
|
cachedResult,
|
|
convertToValidSignal,
|
|
createClassWrapper,
|
|
createDeferredPromise,
|
|
decorateErrorStack,
|
|
defineOperation,
|
|
defineLazyProperties,
|
|
defineReplaceableLazyAttribute,
|
|
deprecate,
|
|
emitExperimentalWarning,
|
|
exposeInterface,
|
|
exposeLazyInterfaces,
|
|
filterDuplicateStrings,
|
|
filterOwnProperties,
|
|
getConstructorOf,
|
|
getInternalGlobal,
|
|
getSystemErrorMap,
|
|
getSystemErrorName,
|
|
isArrayBufferDetached,
|
|
isError,
|
|
isInsideNodeModules,
|
|
join,
|
|
lazyDOMException,
|
|
lazyDOMExceptionClass,
|
|
normalizeEncoding,
|
|
once,
|
|
promisify,
|
|
SideEffectFreeRegExpPrototypeExec,
|
|
SideEffectFreeRegExpPrototypeSymbolReplace,
|
|
SideEffectFreeRegExpPrototypeSymbolSplit,
|
|
sleep,
|
|
spliceOne,
|
|
setupCoverageHooks,
|
|
toUSVString,
|
|
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: SymbolFor('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'),
|
|
|
|
kEmptyObject,
|
|
kEnumerableProperty,
|
|
setOwnProperty,
|
|
};
|