mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 18:22:42 +00:00
fix(javascript): preserve TypeScript loader and dependency semantics
Share loader selection across static findings and module relationships: CTS static imports and re-exports use CommonJS lookup while dynamic imports retain ESM lookup. Retain runtime import-equals dependencies, bindings, and exported names; do not resolve require file-URL strings as local artifacts. Restore import-map descriptions in CLI help. Validated resolver and semantic tests, application reconstruction boundaries, and CLI help. Installed TypeScript NodeNext emission and Node require behavior were checked independently. Refs #2056, #2057, #2058, #2053.
This commit is contained in:
1 parent
966f7cc84b
commit
e4532b5376
8 files changed
+242
-13
No files matched your search
@@ -22,7 +22,10 @@ import {
|
||||
astObservationEvidence,
|
||||
staticInferenceEvidence,
|
||||
} from "./JavaScriptArtifactGraphEvidence.js";
|
||||
import { resolveArtifactPathByContext } from "./JavaScriptArtifactPathResolution.js";
|
||||
import {
|
||||
moduleKindForJavaScriptReference,
|
||||
resolveArtifactPathByContext,
|
||||
} from "./JavaScriptArtifactPathResolution.js";
|
||||
|
||||
type StaticReference = JavaScriptStaticAnalysis["references"][number];
|
||||
type StaticEndpoint = JavaScriptStaticAnalysis["endpoints"][number];
|
||||
@@ -400,12 +403,11 @@ const resolveReference = (
|
||||
specifier,
|
||||
sourcePath,
|
||||
context.filesByPath,
|
||||
reference.kind === "require"
|
||||
? "require"
|
||||
: reference.kind === "static-import" ||
|
||||
reference.kind === "dynamic-import"
|
||||
? "import"
|
||||
: undefined,
|
||||
reference.kind === "require" ||
|
||||
reference.kind === "static-import" ||
|
||||
reference.kind === "dynamic-import"
|
||||
? moduleKindForJavaScriptReference(sourcePath, reference.kind)
|
||||
: undefined,
|
||||
);
|
||||
if (path === null) return null;
|
||||
const file = context.filesByPath.get(path);
|
||||
|
||||
@@ -576,6 +576,27 @@ describe("contextual JavaScript artifact path resolution", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("CommonJS file URL resolution", () => {
|
||||
it("keeps file URL resolution specific to the import loader", () => {
|
||||
const files = fileMap([file("entry.cjs", "root"), file("dep.cjs", "root")]);
|
||||
const input = {
|
||||
declaredPath: "file:///dep.cjs",
|
||||
sourcePath: "entry.cjs",
|
||||
context: "module-specifier" as const,
|
||||
files,
|
||||
};
|
||||
|
||||
expect(resolve({ ...input, moduleKind: "require" })).toMatchObject({
|
||||
resolution_status: "external",
|
||||
resolved_path: null,
|
||||
});
|
||||
expect(resolve({ ...input, moduleKind: "import" })).toMatchObject({
|
||||
resolution_status: "resolved",
|
||||
resolved_path: "dep.cjs",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("contextual JavaScript package path resolution", () => {
|
||||
it("follows package entrypoints beyond the former recursion ceiling", () => {
|
||||
const files = fileMap([
|
||||
|
||||
@@ -64,6 +64,17 @@ export interface ResolveArtifactPathInput {
|
||||
readonly moduleKind?: "import" | "require";
|
||||
}
|
||||
|
||||
/** Loader selected by a source-level JavaScript module reference. */
|
||||
export const moduleKindForJavaScriptReference = (
|
||||
sourcePath: string,
|
||||
referenceKind: "static-import" | "dynamic-import" | "require",
|
||||
): "import" | "require" =>
|
||||
referenceKind === "require" ||
|
||||
(referenceKind === "static-import" &&
|
||||
posix.extname(sourcePath).toLowerCase() === ".cts")
|
||||
? "require"
|
||||
: "import";
|
||||
|
||||
const EXTENSIONS = [
|
||||
".js",
|
||||
".cjs",
|
||||
@@ -189,7 +200,12 @@ const contextualCandidate = (
|
||||
if (context === "html-reference") return htmlCandidate(input);
|
||||
if (context === "module-specifier") {
|
||||
const fileUrl = fileUrlPath(declared);
|
||||
if (fileUrl !== undefined) return fileUrl;
|
||||
if (fileUrl !== undefined)
|
||||
return input.moduleKind === "require"
|
||||
? unresolvedCandidate("external", [
|
||||
"Node CommonJS require specifiers do not resolve file URLs as local artifacts.",
|
||||
])
|
||||
: fileUrl;
|
||||
if (hasScheme(declared))
|
||||
return unresolvedCandidate("external", [
|
||||
"URL and Node builtin schemes are outside static artifact module resolution.",
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
staticInferenceEvidence,
|
||||
} from "./JavaScriptArtifactGraphEvidence.js";
|
||||
import {
|
||||
moduleKindForJavaScriptReference,
|
||||
resolveArtifactPathByContext,
|
||||
type ArtifactPathResolution,
|
||||
} from "./JavaScriptArtifactPathResolution.js";
|
||||
@@ -275,10 +276,12 @@ const resolveModuleTarget = (
|
||||
sourcePath: input.file.path,
|
||||
context: "module-specifier",
|
||||
files: input.context.filesByPath,
|
||||
moduleKind:
|
||||
moduleKind: moduleKindForJavaScriptReference(
|
||||
input.file.path,
|
||||
input.link.kind === "require" || input.link.kind === "commonjs-export"
|
||||
? "require"
|
||||
: "import",
|
||||
: "static-import",
|
||||
),
|
||||
});
|
||||
if (resolution.resolution_status !== "resolved")
|
||||
return {
|
||||
@@ -423,8 +426,8 @@ const moduleFormat = (
|
||||
ir: JavaScriptModuleSemanticIr,
|
||||
): "commonjs" | "esm" | "mixed" | "unknown" => {
|
||||
const extension = posix.extname(path).toLowerCase();
|
||||
if (extension === ".mjs") return "esm";
|
||||
if (extension === ".cjs") return "commonjs";
|
||||
if (extension === ".mjs" || extension === ".mts") return "esm";
|
||||
if (extension === ".cjs" || extension === ".cts") return "commonjs";
|
||||
const esm = ir.moduleLinks.some(({ kind }) =>
|
||||
["import", "export", "re-export"].includes(kind),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user