Skip to content

Commit 0782a9d

Browse files
committed
refactor(shared): leave enforcement to follow-up
1 parent d1f58e9 commit 0782a9d

2 files changed

Lines changed: 19 additions & 98 deletions

File tree

scripts/check-dynamic-import-warts.mjs

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -74,41 +74,6 @@ function readDeclarationName(node) {
7474
return null;
7575
}
7676

77-
function unwrapExpression(node) {
78-
let current = node;
79-
while (
80-
ts.isParenthesizedExpression(current) ||
81-
ts.isAsExpression(current) ||
82-
ts.isTypeAssertionExpression(current) ||
83-
ts.isSatisfiesExpression(current)
84-
) {
85-
current = current.expression;
86-
}
87-
return current;
88-
}
89-
90-
function isCanonicalLazyLoaderExpression(node) {
91-
const expression = unwrapExpression(node);
92-
return (
93-
ts.isCallExpression(expression) &&
94-
ts.isIdentifier(expression.expression) &&
95-
expression.expression.text.startsWith("createLazy")
96-
);
97-
}
98-
99-
function containsDynamicImport(node) {
100-
let found = false;
101-
const visit = (current) => {
102-
if (ts.isCallExpression(current) && current.expression.kind === ts.SyntaxKind.ImportKeyword) {
103-
found = true;
104-
return;
105-
}
106-
ts.forEachChild(current, visit);
107-
};
108-
visit(node);
109-
return found;
110-
}
111-
11277
function isIgnoredTestHelperContent(content) {
11378
return /\bfrom\s+["']vitest["']/.test(content) || /\bfrom\s+["']@vitest\//.test(content);
11479
}
@@ -134,7 +99,6 @@ export function findDynamicImportAdvisories(content, fileName = "source.ts") {
13499
const staticRuntimeImports = new Map();
135100
const dynamicImports = new Map();
136101
const directExecuteImports = [];
137-
const manualMemoizers = [];
138102
const declarationStack = [];
139103

140104
const addLine = (map, specifier, line) => {
@@ -184,19 +148,6 @@ export function findDynamicImportAdvisories(content, fileName = "source.ts") {
184148
}
185149
}
186150

187-
if (
188-
ts.isBinaryExpression(node) &&
189-
node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken &&
190-
containsDynamicImport(node.right) &&
191-
!isCanonicalLazyLoaderExpression(node.right)
192-
) {
193-
manualMemoizers.push({
194-
line: toLine(sourceFile, node),
195-
reason:
196-
"hand-written dynamic import memoizer; use createLazyPromise or createLazyRuntimeModule",
197-
});
198-
}
199-
200151
ts.forEachChild(node, visit);
201152
if (declarationName) {
202153
declarationStack.pop();
@@ -205,7 +156,7 @@ export function findDynamicImportAdvisories(content, fileName = "source.ts") {
205156

206157
visit(sourceFile);
207158

208-
const advisories = [...directExecuteImports, ...manualMemoizers];
159+
const advisories = [...directExecuteImports];
209160
for (const [specifier, dynamicLines] of dynamicImports) {
210161
const staticLines = staticRuntimeImports.get(specifier);
211162
if (staticLines?.length) {
@@ -256,7 +207,6 @@ export async function collectDynamicImportAdvisories(options = {}) {
256207
*/
257208
export async function main(argv = process.argv.slice(2)) {
258209
const fail = argv.includes("--fail");
259-
const failManualMemoizers = argv.includes("--fail-manual-memoizers");
260210
const json = argv.includes("--json");
261211
const advisories = await collectDynamicImportAdvisories();
262212

@@ -275,14 +225,6 @@ export async function main(argv = process.argv.slice(2)) {
275225
if (fail && advisories.length > 0) {
276226
process.exit(1);
277227
}
278-
if (
279-
failManualMemoizers &&
280-
advisories.some((advisory) =>
281-
advisory.reason.startsWith("hand-written dynamic import memoizer"),
282-
)
283-
) {
284-
process.exit(1);
285-
}
286228
}
287229

288230
runAsScript(import.meta.url, main);

test/scripts/check-dynamic-import-warts.test.ts

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ describe("check-dynamic-import-warts", () => {
3737
}
3838
export { run } from "./runtime.js";
3939
`;
40-
expect(findDynamicImportAdvisories(source)).toContainEqual({
41-
line: 4,
42-
reason: 'runtime static + dynamic import of "./runtime.js" (static line 7)',
43-
});
40+
expect(findDynamicImportAdvisories(source)).toEqual([
41+
{
42+
line: 4,
43+
reason: 'runtime static + dynamic import of "./runtime.js" (static line 7)',
44+
},
45+
]);
4446
});
4547

4648
it("ignores type-only static re-exports", () => {
@@ -72,10 +74,12 @@ describe("check-dynamic-import-warts", () => {
7274
}
7375
export { type Runtime, createRuntime } from "./runtime.js";
7476
`;
75-
expect(findDynamicImportAdvisories(source)).toContainEqual({
76-
line: 4,
77-
reason: 'runtime static + dynamic import of "./runtime.js" (static line 7)',
78-
});
77+
expect(findDynamicImportAdvisories(source)).toEqual([
78+
{
79+
line: 4,
80+
reason: 'runtime static + dynamic import of "./runtime.js" (static line 7)',
81+
},
82+
]);
7983
});
8084

8185
it("ignores local export declarations without module specifiers", () => {
@@ -106,43 +110,14 @@ describe("check-dynamic-import-warts", () => {
106110
]);
107111
});
108112

109-
it("flags hand-written dynamic import memoizers", () => {
113+
it("ignores cached loader patterns", () => {
110114
const source = `
111115
let runtimePromise: Promise<typeof import("./runtime.js")> | undefined;
112116
function loadRuntime() {
113117
runtimePromise ??= import("./runtime.js");
114118
return runtimePromise;
115119
}
116120
`;
117-
expect(findDynamicImportAdvisories(source)).toContainEqual({
118-
line: 4,
119-
reason:
120-
"hand-written dynamic import memoizer; use createLazyPromise or createLazyRuntimeModule",
121-
});
122-
});
123-
124-
it("flags transformed and multi-import memoizers", () => {
125-
const source = `
126-
let runtimePromise: Promise<unknown> | undefined;
127-
function loadRuntime() {
128-
runtimePromise ??= Promise.all([
129-
import("./one.js"),
130-
import("./two.js"),
131-
]).then(([one, two]) => ({ one, two }));
132-
return runtimePromise;
133-
}
134-
`;
135-
expect(findDynamicImportAdvisories(source)).toContainEqual({
136-
line: 4,
137-
reason:
138-
"hand-written dynamic import memoizer; use createLazyPromise or createLazyRuntimeModule",
139-
});
140-
});
141-
142-
it("allows canonical lazy loader assignment", () => {
143-
const source = `
144-
state.loader ??= createLazyImportLoader(() => import("./runtime.js"));
145-
`;
146121
expect(findDynamicImportAdvisories(source)).toStrictEqual([]);
147122
});
148123

@@ -167,7 +142,11 @@ describe("check-dynamic-import-warts", () => {
167142

168143
it("allows execute paths that call cached loaders", () => {
169144
const source = `
170-
const loadRuntime = createLazyRuntimeModule(() => import("./runtime.js"));
145+
let runtimePromise: Promise<typeof import("./runtime.js")> | undefined;
146+
function loadRuntime() {
147+
runtimePromise ??= import("./runtime.js");
148+
return runtimePromise;
149+
}
171150
export function createTool() {
172151
return {
173152
execute: async () => await loadRuntime(),

0 commit comments

Comments
 (0)