mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(javascript): exclude erased imports from runtime bindings (#6994)
This commit is contained in:
@@ -160,6 +160,11 @@ describe("TypeScript type-only module links", () => {
|
||||
export type { hiddenFunction };
|
||||
`);
|
||||
|
||||
expect(ir.bindings.map(({ name }) => name).sort()).toEqual([
|
||||
"hiddenFunction",
|
||||
"value",
|
||||
]);
|
||||
|
||||
const externalLinks = ir.moduleLinks
|
||||
.filter(({ specifier }) => specifier !== null)
|
||||
.map(
|
||||
|
||||
@@ -80,6 +80,8 @@ import {
|
||||
} from "./javascriptSemanticAmbientWrites.js";
|
||||
import {
|
||||
hasUncertainTypeOnlyModuleSideEffect,
|
||||
isTypeOnlyImportDeclaration,
|
||||
isTypeOnlyImportSpecifier,
|
||||
semanticImportEqualsSpecifier,
|
||||
} from "./javascriptModuleDeclaration.js";
|
||||
import {
|
||||
@@ -2038,7 +2040,10 @@ const bindImports = (
|
||||
scope: JavaScriptSemanticScopeState,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): void => {
|
||||
if (isTypeOnlyImportDeclaration(node)) return;
|
||||
for (const specifier of node.specifiers) {
|
||||
if (t.isImportSpecifier(specifier) && isTypeOnlyImportSpecifier(specifier))
|
||||
continue;
|
||||
const importedPath = t.isImportDefaultSpecifier(specifier)
|
||||
? ["default"]
|
||||
: t.isImportNamespaceSpecifier(specifier)
|
||||
@@ -2053,12 +2058,7 @@ const bindImports = (
|
||||
definitionNode: specifier.local,
|
||||
initializer: null,
|
||||
directOrigin: { specifier: node.source.value, importedPath },
|
||||
runtimeImport:
|
||||
node.importKind !== "type" &&
|
||||
node.importKind !== "typeof" &&
|
||||
(!t.isImportSpecifier(specifier) ||
|
||||
(specifier.importKind !== "type" &&
|
||||
specifier.importKind !== "typeof")),
|
||||
runtimeImport: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1192,16 +1192,7 @@ const provenanceForBindingInitializers = (
|
||||
: "Catch binding provenance depends on the thrown value.",
|
||||
);
|
||||
if (binding.directOrigins.length > 0)
|
||||
return binding.kind === "import" &&
|
||||
!binding.runtimeImport &&
|
||||
binding.directOrigins.every(
|
||||
({ resolutionMode }) => resolutionMode !== "require",
|
||||
)
|
||||
? semanticAmbiguousProvenance(
|
||||
binding.directOrigins,
|
||||
"A type-only import does not establish a runtime module value.",
|
||||
)
|
||||
: semanticOriginsProvenance(binding.directOrigins);
|
||||
return semanticOriginsProvenance(binding.directOrigins);
|
||||
if (binding.initializers.length === 0) return semanticLocalProvenance();
|
||||
if (binding.initializers.length > 1)
|
||||
return semanticAmbiguousProvenance(
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { expect } from "vitest";
|
||||
import { runInNewContext } from "node:vm";
|
||||
|
||||
import { transformSync } from "esbuild";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import type { JavaScriptApplicationGraph } from "../../../src/domain/javascript/javascriptApplicationGraph.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
@@ -6,6 +9,37 @@ import { cliTest } from "../../support/cli/cliFixture.js";
|
||||
import { analyzeJavaScriptDirectory } from "../../support/cli/javascriptApplication.js";
|
||||
import { writeFixtureFiles } from "../../support/javascriptApplicationFixture.js";
|
||||
|
||||
const typeOnlyWorkerImports = [
|
||||
'import type { Worker } from "node:worker_threads";',
|
||||
'import { type Worker } from "node:worker_threads";',
|
||||
];
|
||||
|
||||
it.each(typeOnlyWorkerImports)(
|
||||
"preserves the ambient Worker at runtime after erasing %s",
|
||||
(prefix) => {
|
||||
const workerUrls: string[] = [];
|
||||
const { code } = transformSync(
|
||||
`${prefix}\nnew Worker(new URL("./worker.js", import.meta.url));`,
|
||||
{
|
||||
loader: "ts",
|
||||
format: "iife",
|
||||
define: {
|
||||
"import.meta.url": JSON.stringify("file:///fixture/main.ts"),
|
||||
},
|
||||
},
|
||||
);
|
||||
runInNewContext(code, {
|
||||
URL,
|
||||
Worker: class {
|
||||
constructor(url: URL) {
|
||||
workerUrls.push(url.href);
|
||||
}
|
||||
},
|
||||
});
|
||||
expect(workerUrls).toEqual(["file:///fixture/worker.js"]);
|
||||
},
|
||||
);
|
||||
|
||||
const workerReferences = (graph: JavaScriptApplicationGraph) =>
|
||||
graph.nodes
|
||||
.filter(({ kind }) => kind === "worker")
|
||||
@@ -84,6 +118,12 @@ cliTest(
|
||||
suffix: "",
|
||||
resolves: true,
|
||||
},
|
||||
...typeOnlyWorkerImports.map((prefix) => ({
|
||||
prefix,
|
||||
constructor: "new Worker",
|
||||
suffix: "",
|
||||
resolves: true,
|
||||
})),
|
||||
...[
|
||||
["class Worker {}", "new Worker", ""],
|
||||
["globalThis.Worker = Fake;", "new Worker", ""],
|
||||
@@ -94,16 +134,6 @@ cliTest(
|
||||
["const custom = { Worker: class {} };", "new custom.Worker", ""],
|
||||
["function start(window) {", "new window.Worker", "}"],
|
||||
["function start(globalThis) {", "new globalThis.Worker", "}"],
|
||||
[
|
||||
'import type { Worker } from "node:worker_threads";',
|
||||
"new Worker",
|
||||
"",
|
||||
],
|
||||
[
|
||||
'import { type Worker } from "node:worker_threads";',
|
||||
"new Worker",
|
||||
"",
|
||||
],
|
||||
[
|
||||
'import type * as threads from "node:worker_threads";',
|
||||
"new threads.Worker",
|
||||
|
||||
Reference in New Issue
Block a user