mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(verifiers): load shared source without compiler processes (#7012)
This commit is contained in:
1 parent
bff03bfc97
commit
1184819cb9
3 files changed
+349
-13
No files matched your search
@@ -1,17 +1,114 @@
|
||||
import { createRequire } from "node:module";
|
||||
import { statSync } from "node:fs";
|
||||
import { registerHooks, stripTypeScriptTypes } from "node:module";
|
||||
import { extname, isAbsolute, relative, sep } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
|
||||
const requireFromTsx = createRequire(import.meta.resolve("tsx/package.json"));
|
||||
let imports = 0;
|
||||
const sourceRoots = [
|
||||
fileURLToPath(new URL("../../src/", import.meta.url)),
|
||||
fileURLToPath(new URL("./", import.meta.url)),
|
||||
];
|
||||
let hooks;
|
||||
|
||||
/** Load a verifier's source graph, then release the transform service that loaded it. */
|
||||
export async function importVerifierSource(url, parent) {
|
||||
const { tsImport } = await import("tsx/esm/api");
|
||||
imports++;
|
||||
const ownedSourcePath = (url) => {
|
||||
if (!url.startsWith("file:")) return undefined;
|
||||
const path = fileURLToPath(url);
|
||||
return sourceRoots.some((root) => {
|
||||
const selected = relative(root, path);
|
||||
return (
|
||||
selected !== ".." &&
|
||||
!selected.startsWith(`..${sep}`) &&
|
||||
!isAbsolute(selected)
|
||||
);
|
||||
})
|
||||
? path
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const errorCode = (cause) =>
|
||||
typeof cause === "object" && cause !== null && "code" in cause
|
||||
? cause.code
|
||||
: undefined;
|
||||
|
||||
const javascriptFormat = (format) =>
|
||||
format === "module-typescript"
|
||||
? "module"
|
||||
: format === "commonjs-typescript"
|
||||
? "commonjs"
|
||||
: format;
|
||||
|
||||
const sourceResolution = (resolution) => {
|
||||
const path = ownedSourcePath(resolution.url);
|
||||
return path !== undefined && [".ts", ".mts"].includes(extname(path))
|
||||
? { ...resolution, format: javascriptFormat(resolution.format) }
|
||||
: resolution;
|
||||
};
|
||||
|
||||
const resolveSource = (specifier, context, nextResolve) => {
|
||||
try {
|
||||
return await tsImport(url, parent);
|
||||
} finally {
|
||||
// tsx's esbuild service otherwise outlives every owned command and appears
|
||||
// as a surviving verifier descendant on a cold transform cache.
|
||||
if (--imports === 0) requireFromTsx("esbuild").stop();
|
||||
return sourceResolution(nextResolve(specifier, context));
|
||||
} catch (cause) {
|
||||
if (
|
||||
errorCode(cause) !== "ERR_MODULE_NOT_FOUND" ||
|
||||
context.parentURL === undefined ||
|
||||
ownedSourcePath(context.parentURL) === undefined ||
|
||||
!(specifier.startsWith("./") || specifier.startsWith("../"))
|
||||
)
|
||||
throw cause;
|
||||
const selected = new URL(specifier, context.parentURL);
|
||||
const path = ownedSourcePath(selected.href);
|
||||
if (path === undefined) throw cause;
|
||||
const extension = extname(path);
|
||||
if (extension !== ".js" && extension !== ".mjs") throw cause;
|
||||
const source =
|
||||
path.slice(0, -extension.length) + (extension === ".js" ? ".ts" : ".mts");
|
||||
try {
|
||||
if (!statSync(source).isFile()) throw cause;
|
||||
} catch (failure) {
|
||||
if (["ENOENT", "ENOTDIR"].includes(errorCode(failure))) throw cause;
|
||||
throw failure;
|
||||
}
|
||||
const candidate = pathToFileURL(source);
|
||||
candidate.search = selected.search;
|
||||
candidate.hash = selected.hash;
|
||||
return sourceResolution(nextResolve(candidate.href, context));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const loadSource = (url, context, nextLoad) => {
|
||||
const path = ownedSourcePath(url);
|
||||
if (path === undefined || ![".ts", ".mts"].includes(extname(path)))
|
||||
return nextLoad(url, context);
|
||||
const loaded = nextLoad(url, context);
|
||||
const format = javascriptFormat(loaded.format);
|
||||
if (format !== "module" && format !== "commonjs") return loaded;
|
||||
let source;
|
||||
if (typeof loaded.source === "string") source = loaded.source;
|
||||
else if (ArrayBuffer.isView(loaded.source))
|
||||
source = Buffer.from(
|
||||
loaded.source.buffer,
|
||||
loaded.source.byteOffset,
|
||||
loaded.source.byteLength,
|
||||
).toString("utf8");
|
||||
else if (loaded.source instanceof ArrayBuffer)
|
||||
source = Buffer.from(loaded.source).toString("utf8");
|
||||
else throw new TypeError(`Verifier module source was unavailable: ${url}`);
|
||||
return {
|
||||
...loaded,
|
||||
format,
|
||||
source: stripTypeScriptTypes(source, {
|
||||
mode: "transform",
|
||||
sourceMap: true,
|
||||
sourceUrl: url,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Import this checkout's verifier source without starting a compiler process.
|
||||
* One process-lifetime hook and Node's URL-keyed module cache share the source
|
||||
* graph across owners. No transformed output is cached across Node versions.
|
||||
*/
|
||||
export const importVerifierSource = async (url, parent) => {
|
||||
hooks ??= registerHooks({ resolve: resolveSource, load: loadSource });
|
||||
return import(new URL(url, parent).href);
|
||||
};
|
||||
Reference in new issue
Block a user