testplane
Version:
Tests framework based on mocha and wdio
181 lines • 6.66 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerReplModuleHooks = void 0;
const nodeModule = __importStar(require("node:module"));
const commander_1 = require("@gemini-testing/commander");
const node_fs_1 = require("node:fs");
const node_path_1 = __importDefault(require("node:path"));
const node_url_1 = require("node:url");
const pirates_1 = require("pirates");
const repl_options_1 = require("../cli/repl-options");
const repl_instrumentation_1 = require("./repl-instrumentation");
const logger = __importStar(require("./logger"));
const TESTPLANE_REPL_MODULE_HOOK = Symbol.for("testplane.repl.module.hook");
const TRANSFORM_CODE_EXTENSIONS = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"];
const registerReplModuleHooks = () => {
const processWithHook = process;
if (processWithHook[TESTPLANE_REPL_MODULE_HOOK]) {
return;
}
const program = (0, repl_options_1.addReplOptions)(new commander_1.Command("testplane").allowUnknownOption().option("-h, --help"));
program.parse(process.argv);
if (!(0, repl_options_1.isReplModeEnabled)(program)) {
return;
}
const hook = registerNodeModuleHooks() || registerPiratesHook();
processWithHook[TESTPLANE_REPL_MODULE_HOOK] = hook;
};
exports.registerReplModuleHooks = registerReplModuleHooks;
function registerNodeModuleHooks() {
const registerHooks = nodeModule.registerHooks;
if (typeof registerHooks !== "function") {
return null;
}
const hooks = registerHooks({
load(url, context, nextLoad) {
let result;
try {
result = nextLoad(url, context);
}
catch (err) {
// https://github.com/nodejs/node/issues/57327
// Fixed for REPL instrumentation in Node 24.13.0; older versions mishandle CJS sources with mixed sync/async hooks.
return instrumentLoadAfterFailedLoad(url, context, err);
}
return instrumentLoadResult(url, result);
},
});
return { revert: () => hooks.deregister() };
}
function registerPiratesHook() {
const revert = (0, pirates_1.addHook)((code, sourceFile) => safeInstrumentRepl(code, sourceFile), {
exts: TRANSFORM_CODE_EXTENSIONS,
ignoreNodeModules: true,
});
return { revert };
}
function instrumentLoadAfterFailedLoad(url, context, err) {
const sourceFile = getSourceFileFromUrl(url);
if (!isInvalidLoadSourceError(err) || !sourceFile || !shouldReadSourceFile(sourceFile)) {
throw err;
}
const source = readSourceFile(sourceFile);
if (source === null) {
throw err;
}
return {
format: getFallbackFormat(context, sourceFile),
shortCircuit: true,
source: shouldHandleSourceFile(sourceFile) ? safeInstrumentRepl(source, sourceFile) : source,
};
}
function instrumentLoadResult(url, result) {
const sourceFile = getSourceFileFromUrl(url);
if (!sourceFile || !shouldHandleSourceFile(sourceFile)) {
return result;
}
const resultSource = result.source;
const source = resultSource === null || resultSource === undefined
? readSourceFile(sourceFile)
: moduleSourceToString(resultSource);
if (source === null) {
return result;
}
return { ...result, source: safeInstrumentRepl(source, sourceFile) };
}
function safeInstrumentRepl(source, sourceFile) {
try {
return (0, repl_instrumentation_1.instrumentReplIfNeeded)(source, sourceFile);
}
catch (err) {
logger.warn(`Failed to instrument ${sourceFile} for REPL mode: ${err.message}.`);
return source;
}
}
function readSourceFile(sourceFile) {
try {
return (0, node_fs_1.readFileSync)(sourceFile, "utf8");
}
catch {
return null;
}
}
function isInvalidLoadSourceError(err) {
if (!(err instanceof Error)) {
return false;
}
const error = err;
return (error.code === "ERR_INVALID_RETURN_PROPERTY_VALUE" &&
error.message.includes('"source"') &&
error.message.includes('"load" hook'));
}
function shouldReadSourceFile(sourceFile) {
return TRANSFORM_CODE_EXTENSIONS.includes(node_path_1.default.extname(sourceFile));
}
function getFallbackFormat(context, sourceFile) {
if (context.format) {
return context.format;
}
switch (node_path_1.default.extname(sourceFile)) {
case ".mjs":
return "module";
case ".mts":
return "module-typescript";
case ".ts":
case ".tsx":
case ".cts":
return "commonjs-typescript";
default:
return "commonjs";
}
}
function getSourceFileFromUrl(url) {
try {
return url.startsWith("file:") ? (0, node_url_1.fileURLToPath)(url) : null;
}
catch {
return null;
}
}
function shouldHandleSourceFile(sourceFile) {
return shouldReadSourceFile(sourceFile) && !sourceFile.includes(`${node_path_1.default.sep}node_modules${node_path_1.default.sep}`);
}
function moduleSourceToString(source) {
if (typeof source === "string") {
return source;
}
if (source instanceof ArrayBuffer) {
return Buffer.from(source).toString();
}
if (ArrayBuffer.isView(source)) {
return Buffer.from(source.buffer, source.byteOffset, source.byteLength).toString();
}
return null;
}
//# sourceMappingURL=repl-module-hooks.js.map