mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
115 lines
3.7 KiB
JavaScript
115 lines
3.7 KiB
JavaScript
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 sourceRoots = [
|
|
fileURLToPath(new URL("../../src/", import.meta.url)),
|
|
fileURLToPath(new URL("./", import.meta.url)),
|
|
];
|
|
let hooks;
|
|
|
|
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 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);
|
|
};
|