@tanstack/start-plugin-core 1.169.17 → 1.169.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/import-protection/analysis.d.ts +5 -5
- package/dist/esm/import-protection/analysis.js +13 -9
- package/dist/esm/import-protection/analysis.js.map +1 -1
- package/dist/esm/import-protection/rewrite.js +5 -3
- package/dist/esm/import-protection/rewrite.js.map +1 -1
- package/dist/esm/import-protection/sourceLocation.d.ts +3 -2
- package/dist/esm/import-protection/sourceLocation.js +1 -0
- package/dist/esm/import-protection/sourceLocation.js.map +1 -1
- package/dist/esm/rsbuild/import-protection.js +9 -6
- package/dist/esm/rsbuild/import-protection.js.map +1 -1
- package/dist/esm/rsbuild/plugin.js +1 -0
- package/dist/esm/rsbuild/plugin.js.map +1 -1
- package/dist/esm/start-compiler/compiler.d.ts +4 -2
- package/dist/esm/start-compiler/compiler.js +8 -4
- package/dist/esm/start-compiler/compiler.js.map +1 -1
- package/dist/esm/vite/import-protection-plugin/plugin.js +4 -3
- package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -1
- package/package.json +8 -8
- package/src/import-protection/analysis.ts +22 -10
- package/src/import-protection/rewrite.ts +4 -5
- package/src/import-protection/sourceLocation.ts +4 -2
- package/src/rsbuild/import-protection.ts +7 -5
- package/src/rsbuild/plugin.ts +3 -0
- package/src/start-compiler/compiler.ts +13 -3
- package/src/vite/import-protection-plugin/plugin.ts +4 -3
- package/dist/esm/import-protection/ast.d.ts +0 -3
- package/dist/esm/import-protection/ast.js +0 -9
- package/dist/esm/import-protection/ast.js.map +0 -1
- package/src/import-protection/ast.ts +0 -7
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LineIndex, TransformResult } from './sourceLocation.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ParseAstResult } from '@tanstack/router-utils';
|
|
3
3
|
export type UsagePos = {
|
|
4
4
|
line: number;
|
|
5
5
|
column0: number;
|
|
@@ -11,7 +11,7 @@ type ImportBindingInfo = {
|
|
|
11
11
|
};
|
|
12
12
|
type UsageCacheKey = `${BoundaryEnv | 'post'}::${string}`;
|
|
13
13
|
export type ImportAnalysis = {
|
|
14
|
-
ast:
|
|
14
|
+
ast: ParseAstResult;
|
|
15
15
|
lineIndex: LineIndex;
|
|
16
16
|
importSourcesInOrder: Array<string>;
|
|
17
17
|
importSpecifierLocationIndex: Map<string, number>;
|
|
@@ -23,12 +23,12 @@ export type ImportAnalysis = {
|
|
|
23
23
|
export declare function isValidExportName(name: string): boolean;
|
|
24
24
|
export declare function getOrCreateImportAnalysis(result: TransformResult): ImportAnalysis;
|
|
25
25
|
export declare function getImportSourcesFromResult(result: TransformResult): Array<string>;
|
|
26
|
-
export declare function getImportSources(code: string): Array<string>;
|
|
26
|
+
export declare function getImportSources(code: string, filename?: string): Array<string>;
|
|
27
27
|
export declare function getImportSpecifierLocationFromResult(result: TransformResult, source: string): number;
|
|
28
28
|
export declare function getMockExportNamesBySourceFromResult(result: TransformResult): Map<string, Array<string>>;
|
|
29
|
-
export declare function getMockExportNamesBySource(code: string): Map<string, Array<string>>;
|
|
29
|
+
export declare function getMockExportNamesBySource(code: string, filename?: string): Map<string, Array<string>>;
|
|
30
30
|
export declare function getNamedExportsFromResult(result: TransformResult): Array<string>;
|
|
31
|
-
export declare function getNamedExports(code: string): Array<string>;
|
|
31
|
+
export declare function getNamedExports(code: string, filename?: string): Array<string>;
|
|
32
32
|
export declare function findPostCompileUsagePosFromResult(result: TransformResult, source: string): UsagePos | undefined;
|
|
33
33
|
export declare function findPostCompileUsagePos(code: string, source: string): UsagePos | undefined;
|
|
34
34
|
export declare function findOriginalUnsafeUsagePosFromResult(result: TransformResult, source: string, envType: BoundaryEnv): UsagePos | undefined;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getOrCreate } from "./utils.js";
|
|
2
|
-
import { parseImportProtectionAst } from "./ast.js";
|
|
3
2
|
import { buildLineIndex } from "./sourceLocation.js";
|
|
4
3
|
import * as t from "@babel/types";
|
|
4
|
+
import { parseAst } from "@tanstack/router-utils";
|
|
5
5
|
//#region src/import-protection/analysis.ts
|
|
6
|
-
function makeTransientResult(code) {
|
|
6
|
+
function makeTransientResult(code, filename) {
|
|
7
7
|
return {
|
|
8
8
|
code,
|
|
9
|
+
filename,
|
|
9
10
|
map: void 0,
|
|
10
11
|
originalCode: void 0
|
|
11
12
|
};
|
|
@@ -49,7 +50,10 @@ function isValidExportName(name) {
|
|
|
49
50
|
return true;
|
|
50
51
|
}
|
|
51
52
|
function buildImportAnalysis(result) {
|
|
52
|
-
const ast = result.parsedAst ??
|
|
53
|
+
const ast = result.parsedAst ?? parseAst({
|
|
54
|
+
code: result.code,
|
|
55
|
+
filename: result.filename
|
|
56
|
+
});
|
|
53
57
|
result.parsedAst = ast;
|
|
54
58
|
const importSourcesInOrder = [];
|
|
55
59
|
const importSpecifierLocationIndex = /* @__PURE__ */ new Map();
|
|
@@ -170,8 +174,8 @@ function getOrCreateImportAnalysis(result) {
|
|
|
170
174
|
function getImportSourcesFromResult(result) {
|
|
171
175
|
return getOrCreateImportAnalysis(result).importSourcesInOrder;
|
|
172
176
|
}
|
|
173
|
-
function getImportSources(code) {
|
|
174
|
-
return getImportSourcesFromResult(makeTransientResult(code));
|
|
177
|
+
function getImportSources(code, filename) {
|
|
178
|
+
return getImportSourcesFromResult(makeTransientResult(code, filename));
|
|
175
179
|
}
|
|
176
180
|
function getImportSpecifierLocationFromResult(result, source) {
|
|
177
181
|
return getOrCreateImportAnalysis(result).importSpecifierLocationIndex.get(source) ?? -1;
|
|
@@ -179,14 +183,14 @@ function getImportSpecifierLocationFromResult(result, source) {
|
|
|
179
183
|
function getMockExportNamesBySourceFromResult(result) {
|
|
180
184
|
return getOrCreateImportAnalysis(result).mockExportNamesBySource;
|
|
181
185
|
}
|
|
182
|
-
function getMockExportNamesBySource(code) {
|
|
183
|
-
return getMockExportNamesBySourceFromResult(makeTransientResult(code));
|
|
186
|
+
function getMockExportNamesBySource(code, filename) {
|
|
187
|
+
return getMockExportNamesBySourceFromResult(makeTransientResult(code, filename));
|
|
184
188
|
}
|
|
185
189
|
function getNamedExportsFromResult(result) {
|
|
186
190
|
return getOrCreateImportAnalysis(result).namedExports;
|
|
187
191
|
}
|
|
188
|
-
function getNamedExports(code) {
|
|
189
|
-
return getNamedExportsFromResult(makeTransientResult(code));
|
|
192
|
+
function getNamedExports(code, filename) {
|
|
193
|
+
return getNamedExportsFromResult(makeTransientResult(code, filename));
|
|
190
194
|
}
|
|
191
195
|
function isCompilerSafeBoundaryCall(call, fnNode, envType) {
|
|
192
196
|
if (!call.arguments.some((arg) => arg === fnNode)) return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analysis.js","names":[],"sources":["../../../src/import-protection/analysis.ts"],"sourcesContent":["import * as t from '@babel/types'\n\nimport { parseImportProtectionAst } from './ast'\nimport { buildLineIndex } from './sourceLocation'\nimport { getOrCreate } from './utils'\nimport type { LineIndex, TransformResult } from './sourceLocation'\nimport type { ParsedAst } from './ast'\n\nexport type UsagePos = { line: number; column0: number }\n\ntype BoundaryEnv = 'client' | 'server'\n\ntype ImportBindingInfo = {\n importedLocalNames: Set<string>\n memberBindingToSource: Map<string, string>\n}\n\ntype UsageCacheKey = `${BoundaryEnv | 'post'}::${string}`\n\nexport type ImportAnalysis = {\n ast: ParsedAst\n lineIndex: LineIndex\n importSourcesInOrder: Array<string>\n importSpecifierLocationIndex: Map<string, number>\n importBindingsBySource: Map<string, ImportBindingInfo>\n mockExportNamesBySource: Map<string, Array<string>>\n namedExports: Array<string>\n usageByKey: Map<UsageCacheKey, UsagePos | null>\n}\n\nfunction makeTransientResult(code: string): TransformResult {\n return {\n code,\n map: undefined,\n originalCode: undefined,\n }\n}\n\nfunction getModuleExportName(node: t.Identifier | t.StringLiteral): string {\n return t.isIdentifier(node) ? node.name : node.value\n}\n\nfunction getStringLiteralValueStart(node: t.StringLiteral): number {\n if (node.start == null) {\n return -1\n }\n\n const raw = node.extra?.raw\n if (typeof raw === 'string' && (raw.startsWith(\"'\") || raw.startsWith('\"'))) {\n return node.start + 1\n }\n\n return node.start\n}\n\nfunction isTypeOnlyImportDeclaration(node: t.ImportDeclaration): boolean {\n if (node.importKind === 'type') return true\n if (node.specifiers.length === 0) return false\n\n return node.specifiers.every(\n (specifier) =>\n t.isImportSpecifier(specifier) && specifier.importKind === 'type',\n )\n}\n\nfunction isTypeOnlyExportNamedDeclaration(\n node: t.ExportNamedDeclaration,\n): boolean {\n if (node.exportKind === 'type') return true\n if (!node.source || node.declaration || node.specifiers.length === 0) {\n return false\n }\n\n return node.specifiers.every(\n (specifier) =>\n t.isExportSpecifier(specifier) && specifier.exportKind === 'type',\n )\n}\n\nfunction collectIdentifiersFromPattern(\n pattern: t.LVal,\n add: (name: string) => void,\n): void {\n if (t.isIdentifier(pattern)) {\n add(pattern.name)\n } else if (t.isObjectPattern(pattern)) {\n for (const prop of pattern.properties) {\n if (t.isRestElement(prop)) {\n collectIdentifiersFromPattern(prop.argument as t.LVal, add)\n } else {\n collectIdentifiersFromPattern(prop.value as t.LVal, add)\n }\n }\n } else if (t.isArrayPattern(pattern)) {\n for (const elem of pattern.elements) {\n if (elem) collectIdentifiersFromPattern(elem as t.LVal, add)\n }\n } else if (t.isAssignmentPattern(pattern)) {\n collectIdentifiersFromPattern(pattern.left, add)\n } else if (t.isRestElement(pattern)) {\n collectIdentifiersFromPattern(pattern.argument as t.LVal, add)\n }\n}\n\nexport function isValidExportName(name: string): boolean {\n if (name === 'default' || name.length === 0) return false\n const first = name.charCodeAt(0)\n if (\n !(\n (first >= 65 && first <= 90) ||\n (first >= 97 && first <= 122) ||\n first === 95 ||\n first === 36\n )\n )\n return false\n for (let i = 1; i < name.length; i++) {\n const ch = name.charCodeAt(i)\n if (\n !(\n (ch >= 65 && ch <= 90) ||\n (ch >= 97 && ch <= 122) ||\n (ch >= 48 && ch <= 57) ||\n ch === 95 ||\n ch === 36\n )\n )\n return false\n }\n return true\n}\n\nfunction buildImportAnalysis(result: TransformResult): ImportAnalysis {\n const ast = result.parsedAst ?? parseImportProtectionAst(result.code)\n result.parsedAst = ast\n\n const importSourcesInOrder: Array<string> = []\n const importSpecifierLocationIndex = new Map<string, number>()\n const importBindingsBySource = new Map<string, ImportBindingInfo>()\n const mockNamesBySource = new Map<string, Set<string>>()\n const namedExports = new Set<string>()\n\n const getBindingInfo = (source: string): ImportBindingInfo =>\n getOrCreate(importBindingsBySource, source, () => ({\n importedLocalNames: new Set<string>(),\n memberBindingToSource: new Map<string, string>(),\n }))\n\n const addSpecifierLocation = (node: t.StringLiteral) => {\n importSourcesInOrder.push(node.value)\n\n const index = getStringLiteralValueStart(node)\n if (index === -1) {\n return\n }\n\n const prev = importSpecifierLocationIndex.get(node.value)\n if (prev == null || index < prev) {\n importSpecifierLocationIndex.set(node.value, index)\n }\n }\n\n const addMockName = (source: string, name: string) => {\n if (name === 'default' || name.length === 0) return\n getOrCreate(mockNamesBySource, source, () => new Set<string>()).add(name)\n }\n\n const addNamedExport = (name: string) => {\n if (name !== 'default' && name.length > 0) {\n namedExports.add(name)\n }\n }\n\n const visit = (node: t.Node): void => {\n if (t.isImportDeclaration(node)) {\n const isTypeOnly = isTypeOnlyImportDeclaration(node)\n if (!isTypeOnly) {\n addSpecifierLocation(node.source)\n const source = node.source.value\n const bindingInfo = getBindingInfo(source)\n for (const specifier of node.specifiers) {\n if (t.isImportNamespaceSpecifier(specifier)) {\n bindingInfo.importedLocalNames.add(specifier.local.name)\n bindingInfo.memberBindingToSource.set(specifier.local.name, source)\n continue\n }\n\n if (t.isImportDefaultSpecifier(specifier)) {\n bindingInfo.importedLocalNames.add(specifier.local.name)\n bindingInfo.memberBindingToSource.set(specifier.local.name, source)\n continue\n }\n\n if (!t.isImportSpecifier(specifier)) continue\n if (specifier.importKind === 'type') continue\n\n bindingInfo.importedLocalNames.add(specifier.local.name)\n const importedName = getModuleExportName(specifier.imported)\n if (importedName !== 'default') {\n addMockName(source, importedName)\n }\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n const isTypeOnly = isTypeOnlyExportNamedDeclaration(node)\n if (!isTypeOnly && node.source && t.isStringLiteral(node.source)) {\n addSpecifierLocation(node.source)\n }\n\n if (!isTypeOnly && node.source?.value) {\n const source = node.source.value\n for (const specifier of node.specifiers) {\n if (!t.isExportSpecifier(specifier)) continue\n if (specifier.exportKind === 'type') continue\n addMockName(source, getModuleExportName(specifier.local))\n }\n }\n\n if (!isTypeOnly) {\n if (node.declaration) {\n const decl = node.declaration\n if (t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) {\n if (decl.id?.name) addNamedExport(decl.id.name)\n } else if (t.isVariableDeclaration(decl)) {\n for (const d of decl.declarations) {\n collectIdentifiersFromPattern(d.id as t.LVal, addNamedExport)\n }\n }\n }\n\n for (const specifier of node.specifiers) {\n if (!t.isExportSpecifier(specifier)) continue\n if (specifier.exportKind === 'type') continue\n const exportedName = getModuleExportName(specifier.exported)\n addNamedExport(exportedName)\n }\n }\n } else if (t.isExportAllDeclaration(node)) {\n if (node.exportKind !== 'type') {\n addSpecifierLocation(node.source)\n }\n } else if (t.isImportExpression(node)) {\n if (t.isStringLiteral(node.source)) {\n addSpecifierLocation(node.source)\n }\n } else if (t.isCallExpression(node) && t.isImport(node.callee)) {\n const sourceNode = node.arguments[0]\n if (t.isStringLiteral(sourceNode)) {\n addSpecifierLocation(sourceNode)\n }\n } else if (\n t.isMemberExpression(node) ||\n t.isOptionalMemberExpression(node)\n ) {\n const object = node.object\n if (t.isIdentifier(object)) {\n for (const [source, bindingInfo] of importBindingsBySource) {\n if (!bindingInfo.memberBindingToSource.has(object.name)) {\n continue\n }\n\n const property = node.property\n if (!node.computed && t.isIdentifier(property)) {\n addMockName(source, property.name)\n } else if (node.computed && t.isStringLiteral(property)) {\n addMockName(source, property.value)\n }\n }\n }\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n visit(item as t.Node)\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n visit(child as t.Node)\n }\n }\n }\n\n visit(ast.program)\n\n const mockExportNamesBySource = new Map<string, Array<string>>()\n for (const [source, names] of mockNamesBySource) {\n mockExportNamesBySource.set(source, Array.from(names).sort())\n }\n\n const lineIndex = result.lineIndex ?? buildLineIndex(result.code)\n result.lineIndex = lineIndex\n\n const analysis = {\n ast,\n lineIndex,\n importSourcesInOrder,\n importSpecifierLocationIndex,\n importBindingsBySource,\n mockExportNamesBySource,\n namedExports: Array.from(namedExports).sort(),\n usageByKey: new Map(),\n }\n\n return analysis\n}\n\nexport function getOrCreateImportAnalysis(\n result: TransformResult,\n): ImportAnalysis {\n if (!result.analysis) {\n result.analysis = buildImportAnalysis(result)\n }\n\n return result.analysis\n}\n\nexport function getImportSourcesFromResult(\n result: TransformResult,\n): Array<string> {\n return getOrCreateImportAnalysis(result).importSourcesInOrder\n}\n\nexport function getImportSources(code: string): Array<string> {\n return getImportSourcesFromResult(makeTransientResult(code))\n}\n\nexport function getImportSpecifierLocationFromResult(\n result: TransformResult,\n source: string,\n): number {\n return (\n getOrCreateImportAnalysis(result).importSpecifierLocationIndex.get(\n source,\n ) ?? -1\n )\n}\n\nexport function getMockExportNamesBySourceFromResult(\n result: TransformResult,\n): Map<string, Array<string>> {\n return getOrCreateImportAnalysis(result).mockExportNamesBySource\n}\n\nexport function getMockExportNamesBySource(\n code: string,\n): Map<string, Array<string>> {\n return getMockExportNamesBySourceFromResult(makeTransientResult(code))\n}\n\nexport function getNamedExportsFromResult(\n result: TransformResult,\n): Array<string> {\n return getOrCreateImportAnalysis(result).namedExports\n}\n\nexport function getNamedExports(code: string): Array<string> {\n return getNamedExportsFromResult(makeTransientResult(code))\n}\n\nfunction isCompilerSafeBoundaryCall(\n call: t.CallExpression,\n fnNode: t.Function,\n envType: BoundaryEnv,\n): boolean {\n const directArgument = call.arguments.some((arg) => arg === fnNode)\n if (!directArgument) {\n return false\n }\n\n const callee = call.callee\n\n if (t.isIdentifier(callee)) {\n return envType === 'client'\n ? callee.name === 'createServerOnlyFn'\n : callee.name === 'createClientOnlyFn'\n }\n\n if (!t.isMemberExpression(callee) || callee.computed) {\n return false\n }\n\n if (!t.isIdentifier(callee.property)) {\n return false\n }\n\n const prop = callee.property.name\n const rootName = getCalleeRootName(callee.object)\n\n if (envType === 'client') {\n if (prop === 'handler') {\n return rootName === 'createServerFn' || /ServerFn$/.test(rootName ?? '')\n }\n\n if (prop === 'server') {\n return (\n rootName === 'createMiddleware' ||\n rootName === 'createIsomorphicFn' ||\n /Middleware$/.test(rootName ?? '')\n )\n }\n\n return false\n }\n\n if (prop === 'client') {\n return rootName === 'createIsomorphicFn'\n }\n\n return false\n}\n\nfunction getCalleeRootName(\n node: t.Expression | t.Super | t.V8IntrinsicIdentifier,\n): string | undefined {\n if (t.isIdentifier(node)) {\n return node.name\n }\n\n if (t.isCallExpression(node)) {\n return getCalleeRootName(node.callee)\n }\n\n if (t.isMemberExpression(node)) {\n return getCalleeRootName(node.object)\n }\n\n return undefined\n}\n\nfunction getBoundNamesFromPattern(pattern: t.LVal, out: Set<string>): void {\n if (t.isIdentifier(pattern)) {\n out.add(pattern.name)\n } else if (t.isObjectPattern(pattern)) {\n for (const prop of pattern.properties) {\n if (t.isRestElement(prop)) {\n getBoundNamesFromPattern(prop.argument as t.LVal, out)\n } else {\n getBoundNamesFromPattern(prop.value as t.LVal, out)\n }\n }\n } else if (t.isArrayPattern(pattern)) {\n for (const elem of pattern.elements) {\n if (elem) getBoundNamesFromPattern(elem as t.LVal, out)\n }\n } else if (t.isAssignmentPattern(pattern)) {\n getBoundNamesFromPattern(pattern.left, out)\n } else if (t.isRestElement(pattern)) {\n getBoundNamesFromPattern(pattern.argument as t.LVal, out)\n }\n}\n\nfunction addPatternBindingsIfTracked(\n pattern: t.LVal,\n tracked: Set<string>,\n out: Set<string>,\n): void {\n const names = new Set<string>()\n getBoundNamesFromPattern(pattern, names)\n for (const name of names) {\n if (tracked.has(name)) {\n out.add(name)\n }\n }\n}\n\nfunction collectHoistedVarBindings(\n node: t.Node,\n tracked: Set<string>,\n out: Set<string>,\n isRoot = true,\n): void {\n if (!isRoot && t.isFunction(node)) {\n return\n }\n\n if (t.isVariableDeclaration(node) && node.kind === 'var') {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, out)\n }\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n collectHoistedVarBindings(item as t.Node, tracked, out, false)\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n collectHoistedVarBindings(child as t.Node, tracked, out, false)\n }\n }\n}\n\nfunction collectProgramBindings(\n program: t.Program,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n for (const node of program.body) {\n if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)\n }\n continue\n }\n\n if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {\n if (node.id && tracked.has(node.id.name)) {\n bindings.add(node.id.name)\n }\n }\n }\n\n return bindings\n}\n\nfunction collectBlockBindings(\n block: t.BlockStatement,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n for (const node of block.body) {\n if (t.isVariableDeclaration(node) && node.kind !== 'var') {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)\n }\n continue\n }\n\n if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {\n if (node.id && tracked.has(node.id.name)) {\n bindings.add(node.id.name)\n }\n }\n }\n\n return bindings\n}\n\nfunction collectFunctionBindings(\n fn: t.Function,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n if (\n (t.isFunctionDeclaration(fn) || t.isFunctionExpression(fn)) &&\n fn.id &&\n tracked.has(fn.id.name)\n ) {\n bindings.add(fn.id.name)\n }\n\n for (const param of fn.params) {\n addPatternBindingsIfTracked(param as t.LVal, tracked, bindings)\n }\n\n if (t.isBlockStatement(fn.body)) {\n collectHoistedVarBindings(fn.body, tracked, bindings)\n }\n\n return bindings\n}\n\ntype UsageWalkContext = {\n parents: Array<t.Node>\n scopeStack: Array<Set<string>>\n}\n\nfunction isShadowedByScope(\n name: string,\n scopeStack: Array<Set<string>>,\n): boolean {\n for (let i = scopeStack.length - 1; i >= 0; i--) {\n if (scopeStack[i]?.has(name)) {\n return true\n }\n }\n return false\n}\n\nfunction isBindingIdentifierInParent(\n node: t.Identifier,\n parent: t.Node | undefined,\n): boolean {\n if (!parent) return false\n\n if (t.isImportSpecifier(parent) || t.isImportDefaultSpecifier(parent)) {\n return parent.local === node\n }\n if (t.isImportNamespaceSpecifier(parent)) {\n return parent.local === node\n }\n if (t.isFunctionDeclaration(parent) || t.isFunctionExpression(parent)) {\n return (\n parent.id === node || parent.params.includes(node as unknown as t.Pattern)\n )\n }\n if (t.isArrowFunctionExpression(parent)) {\n return parent.params.includes(node as unknown as t.Pattern)\n }\n if (t.isClassDeclaration(parent) || t.isClassExpression(parent)) {\n return parent.id === node\n }\n if (t.isVariableDeclarator(parent)) {\n return parent.id === node\n }\n if (t.isCatchClause(parent)) {\n return parent.param === node\n }\n\n return false\n}\n\nfunction isInsideCompilerSafeBoundaryNodes(\n parents: Array<t.Node>,\n envType: BoundaryEnv,\n): boolean {\n for (let i = parents.length - 1; i >= 0; i--) {\n const node = parents[i]!\n if (!t.isFunction(node)) {\n continue\n }\n\n const call = parents[i - 1]\n if (\n call &&\n t.isCallExpression(call) &&\n isCompilerSafeBoundaryCall(call, node, envType)\n ) {\n return true\n }\n }\n\n return false\n}\n\nfunction findUsagePosInAnalysis(\n result: TransformResult,\n source: string,\n envType?: BoundaryEnv,\n): UsagePos | undefined {\n const analysis = getOrCreateImportAnalysis(result)\n const cacheKey: UsageCacheKey = `${envType ?? 'post'}::${source}`\n if (analysis.usageByKey.has(cacheKey)) {\n return analysis.usageByKey.get(cacheKey) ?? undefined\n }\n\n const imported =\n analysis.importBindingsBySource.get(source)?.importedLocalNames\n if (!imported || imported.size === 0) {\n analysis.usageByKey.set(cacheKey, null)\n return undefined\n }\n\n let preferred: UsagePos | undefined\n let anyUsage: UsagePos | undefined\n\n const visit = (node: t.Node, ctx: UsageWalkContext): void => {\n if (preferred && anyUsage) {\n return\n }\n\n if (t.isProgram(node)) {\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [...ctx.scopeStack, collectProgramBindings(node, imported)],\n }\n for (const child of node.body) {\n visit(child, nextCtx)\n }\n return\n }\n\n if (t.isFunction(node)) {\n const functionCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [\n ...ctx.scopeStack,\n collectFunctionBindings(node, imported),\n ],\n }\n\n visit(node.body, functionCtx)\n return\n }\n\n if (t.isBlockStatement(node)) {\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [...ctx.scopeStack, collectBlockBindings(node, imported)],\n }\n for (const child of node.body) {\n visit(child, nextCtx)\n }\n return\n }\n\n if (t.isCatchClause(node)) {\n const bindings = new Set<string>()\n if (node.param) {\n addPatternBindingsIfTracked(node.param as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.body, nextCtx)\n return\n }\n\n if (\n t.isForStatement(node) &&\n t.isVariableDeclaration(node.init) &&\n node.init.kind !== 'var'\n ) {\n const bindings = new Set<string>()\n for (const decl of node.init.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.init, nextCtx)\n if (node.test) visit(node.test, nextCtx)\n if (node.update) visit(node.update, nextCtx)\n visit(node.body, nextCtx)\n return\n }\n\n if (\n (t.isForInStatement(node) || t.isForOfStatement(node)) &&\n t.isVariableDeclaration(node.left) &&\n node.left.kind !== 'var'\n ) {\n const bindings = new Set<string>()\n for (const decl of node.left.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.left, nextCtx)\n visit(node.right, nextCtx)\n visit(node.body, nextCtx)\n return\n }\n\n const nextParents = [...ctx.parents, node]\n\n if (t.isIdentifier(node)) {\n const parent = ctx.parents[ctx.parents.length - 1]\n if (imported.has(node.name)) {\n if (!isBindingIdentifierInParent(node, parent)) {\n if (\n !(\n t.isObjectProperty(parent) &&\n parent.key === node &&\n !parent.computed &&\n !parent.shorthand\n ) &&\n !(\n t.isObjectMethod(parent) &&\n parent.key === node &&\n !parent.computed\n ) &&\n !(t.isExportSpecifier(parent) && parent.exported === node) &&\n !isShadowedByScope(node.name, ctx.scopeStack) &&\n !(\n envType && isInsideCompilerSafeBoundaryNodes(ctx.parents, envType)\n )\n ) {\n const loc = node.loc?.start\n if (loc) {\n const pos: UsagePos = { line: loc.line, column0: loc.column }\n const isPreferred =\n (t.isCallExpression(parent) && parent.callee === node) ||\n (t.isNewExpression(parent) && parent.callee === node) ||\n ((t.isMemberExpression(parent) ||\n t.isOptionalMemberExpression(parent)) &&\n parent.object === node)\n\n if (isPreferred) {\n preferred ||= pos\n } else {\n anyUsage ||= pos\n }\n }\n }\n }\n }\n }\n\n if (t.isImportDeclaration(node)) {\n return\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n visit(item as t.Node, {\n parents: nextParents,\n scopeStack: ctx.scopeStack,\n })\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n visit(child as t.Node, {\n parents: nextParents,\n scopeStack: ctx.scopeStack,\n })\n }\n }\n }\n\n visit(analysis.ast.program, {\n parents: [],\n scopeStack: [],\n })\n\n const pos = preferred ?? anyUsage ?? null\n analysis.usageByKey.set(cacheKey, pos)\n return pos ?? undefined\n}\n\nexport function findPostCompileUsagePosFromResult(\n result: TransformResult,\n source: string,\n): UsagePos | undefined {\n return findUsagePosInAnalysis(result, source)\n}\n\nexport function findPostCompileUsagePos(\n code: string,\n source: string,\n): UsagePos | undefined {\n return findPostCompileUsagePosFromResult(makeTransientResult(code), source)\n}\n\nexport function findOriginalUnsafeUsagePosFromResult(\n result: TransformResult,\n source: string,\n envType: BoundaryEnv,\n): UsagePos | undefined {\n return findUsagePosInAnalysis(result, source, envType)\n}\n\nexport function findOriginalUnsafeUsagePos(\n code: string,\n source: string,\n envType: BoundaryEnv,\n): UsagePos | undefined {\n return findOriginalUnsafeUsagePosFromResult(\n makeTransientResult(code),\n source,\n envType,\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analysis.js","names":[],"sources":["../../../src/import-protection/analysis.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { parseAst } from '@tanstack/router-utils'\n\nimport { buildLineIndex } from './sourceLocation'\nimport { getOrCreate } from './utils'\nimport type { LineIndex, TransformResult } from './sourceLocation'\nimport type { ParseAstResult } from '@tanstack/router-utils'\n\nexport type UsagePos = { line: number; column0: number }\n\ntype BoundaryEnv = 'client' | 'server'\n\ntype ImportBindingInfo = {\n importedLocalNames: Set<string>\n memberBindingToSource: Map<string, string>\n}\n\ntype UsageCacheKey = `${BoundaryEnv | 'post'}::${string}`\n\nexport type ImportAnalysis = {\n ast: ParseAstResult\n lineIndex: LineIndex\n importSourcesInOrder: Array<string>\n importSpecifierLocationIndex: Map<string, number>\n importBindingsBySource: Map<string, ImportBindingInfo>\n mockExportNamesBySource: Map<string, Array<string>>\n namedExports: Array<string>\n usageByKey: Map<UsageCacheKey, UsagePos | null>\n}\n\nfunction makeTransientResult(code: string, filename?: string): TransformResult {\n return {\n code,\n filename,\n map: undefined,\n originalCode: undefined,\n }\n}\n\nfunction getModuleExportName(node: t.Identifier | t.StringLiteral): string {\n return t.isIdentifier(node) ? node.name : node.value\n}\n\nfunction getStringLiteralValueStart(node: t.StringLiteral): number {\n if (node.start == null) {\n return -1\n }\n\n const raw = node.extra?.raw\n if (typeof raw === 'string' && (raw.startsWith(\"'\") || raw.startsWith('\"'))) {\n return node.start + 1\n }\n\n return node.start\n}\n\nfunction isTypeOnlyImportDeclaration(node: t.ImportDeclaration): boolean {\n if (node.importKind === 'type') return true\n if (node.specifiers.length === 0) return false\n\n return node.specifiers.every(\n (specifier) =>\n t.isImportSpecifier(specifier) && specifier.importKind === 'type',\n )\n}\n\nfunction isTypeOnlyExportNamedDeclaration(\n node: t.ExportNamedDeclaration,\n): boolean {\n if (node.exportKind === 'type') return true\n if (!node.source || node.declaration || node.specifiers.length === 0) {\n return false\n }\n\n return node.specifiers.every(\n (specifier) =>\n t.isExportSpecifier(specifier) && specifier.exportKind === 'type',\n )\n}\n\nfunction collectIdentifiersFromPattern(\n pattern: t.LVal,\n add: (name: string) => void,\n): void {\n if (t.isIdentifier(pattern)) {\n add(pattern.name)\n } else if (t.isObjectPattern(pattern)) {\n for (const prop of pattern.properties) {\n if (t.isRestElement(prop)) {\n collectIdentifiersFromPattern(prop.argument as t.LVal, add)\n } else {\n collectIdentifiersFromPattern(prop.value as t.LVal, add)\n }\n }\n } else if (t.isArrayPattern(pattern)) {\n for (const elem of pattern.elements) {\n if (elem) collectIdentifiersFromPattern(elem as t.LVal, add)\n }\n } else if (t.isAssignmentPattern(pattern)) {\n collectIdentifiersFromPattern(pattern.left, add)\n } else if (t.isRestElement(pattern)) {\n collectIdentifiersFromPattern(pattern.argument as t.LVal, add)\n }\n}\n\nexport function isValidExportName(name: string): boolean {\n if (name === 'default' || name.length === 0) return false\n const first = name.charCodeAt(0)\n if (\n !(\n (first >= 65 && first <= 90) ||\n (first >= 97 && first <= 122) ||\n first === 95 ||\n first === 36\n )\n )\n return false\n for (let i = 1; i < name.length; i++) {\n const ch = name.charCodeAt(i)\n if (\n !(\n (ch >= 65 && ch <= 90) ||\n (ch >= 97 && ch <= 122) ||\n (ch >= 48 && ch <= 57) ||\n ch === 95 ||\n ch === 36\n )\n )\n return false\n }\n return true\n}\n\nfunction buildImportAnalysis(result: TransformResult): ImportAnalysis {\n const ast =\n result.parsedAst ??\n parseAst({ code: result.code, filename: result.filename })\n result.parsedAst = ast\n\n const importSourcesInOrder: Array<string> = []\n const importSpecifierLocationIndex = new Map<string, number>()\n const importBindingsBySource = new Map<string, ImportBindingInfo>()\n const mockNamesBySource = new Map<string, Set<string>>()\n const namedExports = new Set<string>()\n\n const getBindingInfo = (source: string): ImportBindingInfo =>\n getOrCreate(importBindingsBySource, source, () => ({\n importedLocalNames: new Set<string>(),\n memberBindingToSource: new Map<string, string>(),\n }))\n\n const addSpecifierLocation = (node: t.StringLiteral) => {\n importSourcesInOrder.push(node.value)\n\n const index = getStringLiteralValueStart(node)\n if (index === -1) {\n return\n }\n\n const prev = importSpecifierLocationIndex.get(node.value)\n if (prev == null || index < prev) {\n importSpecifierLocationIndex.set(node.value, index)\n }\n }\n\n const addMockName = (source: string, name: string) => {\n if (name === 'default' || name.length === 0) return\n getOrCreate(mockNamesBySource, source, () => new Set<string>()).add(name)\n }\n\n const addNamedExport = (name: string) => {\n if (name !== 'default' && name.length > 0) {\n namedExports.add(name)\n }\n }\n\n const visit = (node: t.Node): void => {\n if (t.isImportDeclaration(node)) {\n const isTypeOnly = isTypeOnlyImportDeclaration(node)\n if (!isTypeOnly) {\n addSpecifierLocation(node.source)\n const source = node.source.value\n const bindingInfo = getBindingInfo(source)\n for (const specifier of node.specifiers) {\n if (t.isImportNamespaceSpecifier(specifier)) {\n bindingInfo.importedLocalNames.add(specifier.local.name)\n bindingInfo.memberBindingToSource.set(specifier.local.name, source)\n continue\n }\n\n if (t.isImportDefaultSpecifier(specifier)) {\n bindingInfo.importedLocalNames.add(specifier.local.name)\n bindingInfo.memberBindingToSource.set(specifier.local.name, source)\n continue\n }\n\n if (!t.isImportSpecifier(specifier)) continue\n if (specifier.importKind === 'type') continue\n\n bindingInfo.importedLocalNames.add(specifier.local.name)\n const importedName = getModuleExportName(specifier.imported)\n if (importedName !== 'default') {\n addMockName(source, importedName)\n }\n }\n }\n } else if (t.isExportNamedDeclaration(node)) {\n const isTypeOnly = isTypeOnlyExportNamedDeclaration(node)\n if (!isTypeOnly && node.source && t.isStringLiteral(node.source)) {\n addSpecifierLocation(node.source)\n }\n\n if (!isTypeOnly && node.source?.value) {\n const source = node.source.value\n for (const specifier of node.specifiers) {\n if (!t.isExportSpecifier(specifier)) continue\n if (specifier.exportKind === 'type') continue\n addMockName(source, getModuleExportName(specifier.local))\n }\n }\n\n if (!isTypeOnly) {\n if (node.declaration) {\n const decl = node.declaration\n if (t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) {\n if (decl.id?.name) addNamedExport(decl.id.name)\n } else if (t.isVariableDeclaration(decl)) {\n for (const d of decl.declarations) {\n collectIdentifiersFromPattern(d.id as t.LVal, addNamedExport)\n }\n }\n }\n\n for (const specifier of node.specifiers) {\n if (!t.isExportSpecifier(specifier)) continue\n if (specifier.exportKind === 'type') continue\n const exportedName = getModuleExportName(specifier.exported)\n addNamedExport(exportedName)\n }\n }\n } else if (t.isExportAllDeclaration(node)) {\n if (node.exportKind !== 'type') {\n addSpecifierLocation(node.source)\n }\n } else if (t.isImportExpression(node)) {\n if (t.isStringLiteral(node.source)) {\n addSpecifierLocation(node.source)\n }\n } else if (t.isCallExpression(node) && t.isImport(node.callee)) {\n const sourceNode = node.arguments[0]\n if (t.isStringLiteral(sourceNode)) {\n addSpecifierLocation(sourceNode)\n }\n } else if (\n t.isMemberExpression(node) ||\n t.isOptionalMemberExpression(node)\n ) {\n const object = node.object\n if (t.isIdentifier(object)) {\n for (const [source, bindingInfo] of importBindingsBySource) {\n if (!bindingInfo.memberBindingToSource.has(object.name)) {\n continue\n }\n\n const property = node.property\n if (!node.computed && t.isIdentifier(property)) {\n addMockName(source, property.name)\n } else if (node.computed && t.isStringLiteral(property)) {\n addMockName(source, property.value)\n }\n }\n }\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n visit(item as t.Node)\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n visit(child as t.Node)\n }\n }\n }\n\n visit(ast.program)\n\n const mockExportNamesBySource = new Map<string, Array<string>>()\n for (const [source, names] of mockNamesBySource) {\n mockExportNamesBySource.set(source, Array.from(names).sort())\n }\n\n const lineIndex = result.lineIndex ?? buildLineIndex(result.code)\n result.lineIndex = lineIndex\n\n const analysis = {\n ast,\n lineIndex,\n importSourcesInOrder,\n importSpecifierLocationIndex,\n importBindingsBySource,\n mockExportNamesBySource,\n namedExports: Array.from(namedExports).sort(),\n usageByKey: new Map(),\n }\n\n return analysis\n}\n\nexport function getOrCreateImportAnalysis(\n result: TransformResult,\n): ImportAnalysis {\n if (!result.analysis) {\n result.analysis = buildImportAnalysis(result)\n }\n\n return result.analysis\n}\n\nexport function getImportSourcesFromResult(\n result: TransformResult,\n): Array<string> {\n return getOrCreateImportAnalysis(result).importSourcesInOrder\n}\n\nexport function getImportSources(\n code: string,\n filename?: string,\n): Array<string> {\n return getImportSourcesFromResult(makeTransientResult(code, filename))\n}\n\nexport function getImportSpecifierLocationFromResult(\n result: TransformResult,\n source: string,\n): number {\n return (\n getOrCreateImportAnalysis(result).importSpecifierLocationIndex.get(\n source,\n ) ?? -1\n )\n}\n\nexport function getMockExportNamesBySourceFromResult(\n result: TransformResult,\n): Map<string, Array<string>> {\n return getOrCreateImportAnalysis(result).mockExportNamesBySource\n}\n\nexport function getMockExportNamesBySource(\n code: string,\n filename?: string,\n): Map<string, Array<string>> {\n return getMockExportNamesBySourceFromResult(\n makeTransientResult(code, filename),\n )\n}\n\nexport function getNamedExportsFromResult(\n result: TransformResult,\n): Array<string> {\n return getOrCreateImportAnalysis(result).namedExports\n}\n\nexport function getNamedExports(\n code: string,\n filename?: string,\n): Array<string> {\n return getNamedExportsFromResult(makeTransientResult(code, filename))\n}\n\nfunction isCompilerSafeBoundaryCall(\n call: t.CallExpression,\n fnNode: t.Function,\n envType: BoundaryEnv,\n): boolean {\n const directArgument = call.arguments.some((arg) => arg === fnNode)\n if (!directArgument) {\n return false\n }\n\n const callee = call.callee\n\n if (t.isIdentifier(callee)) {\n return envType === 'client'\n ? callee.name === 'createServerOnlyFn'\n : callee.name === 'createClientOnlyFn'\n }\n\n if (!t.isMemberExpression(callee) || callee.computed) {\n return false\n }\n\n if (!t.isIdentifier(callee.property)) {\n return false\n }\n\n const prop = callee.property.name\n const rootName = getCalleeRootName(callee.object)\n\n if (envType === 'client') {\n if (prop === 'handler') {\n return rootName === 'createServerFn' || /ServerFn$/.test(rootName ?? '')\n }\n\n if (prop === 'server') {\n return (\n rootName === 'createMiddleware' ||\n rootName === 'createIsomorphicFn' ||\n /Middleware$/.test(rootName ?? '')\n )\n }\n\n return false\n }\n\n if (prop === 'client') {\n return rootName === 'createIsomorphicFn'\n }\n\n return false\n}\n\nfunction getCalleeRootName(\n node: t.Expression | t.Super | t.V8IntrinsicIdentifier,\n): string | undefined {\n if (t.isIdentifier(node)) {\n return node.name\n }\n\n if (t.isCallExpression(node)) {\n return getCalleeRootName(node.callee)\n }\n\n if (t.isMemberExpression(node)) {\n return getCalleeRootName(node.object)\n }\n\n return undefined\n}\n\nfunction getBoundNamesFromPattern(pattern: t.LVal, out: Set<string>): void {\n if (t.isIdentifier(pattern)) {\n out.add(pattern.name)\n } else if (t.isObjectPattern(pattern)) {\n for (const prop of pattern.properties) {\n if (t.isRestElement(prop)) {\n getBoundNamesFromPattern(prop.argument as t.LVal, out)\n } else {\n getBoundNamesFromPattern(prop.value as t.LVal, out)\n }\n }\n } else if (t.isArrayPattern(pattern)) {\n for (const elem of pattern.elements) {\n if (elem) getBoundNamesFromPattern(elem as t.LVal, out)\n }\n } else if (t.isAssignmentPattern(pattern)) {\n getBoundNamesFromPattern(pattern.left, out)\n } else if (t.isRestElement(pattern)) {\n getBoundNamesFromPattern(pattern.argument as t.LVal, out)\n }\n}\n\nfunction addPatternBindingsIfTracked(\n pattern: t.LVal,\n tracked: Set<string>,\n out: Set<string>,\n): void {\n const names = new Set<string>()\n getBoundNamesFromPattern(pattern, names)\n for (const name of names) {\n if (tracked.has(name)) {\n out.add(name)\n }\n }\n}\n\nfunction collectHoistedVarBindings(\n node: t.Node,\n tracked: Set<string>,\n out: Set<string>,\n isRoot = true,\n): void {\n if (!isRoot && t.isFunction(node)) {\n return\n }\n\n if (t.isVariableDeclaration(node) && node.kind === 'var') {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, out)\n }\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n collectHoistedVarBindings(item as t.Node, tracked, out, false)\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n collectHoistedVarBindings(child as t.Node, tracked, out, false)\n }\n }\n}\n\nfunction collectProgramBindings(\n program: t.Program,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n for (const node of program.body) {\n if (t.isVariableDeclaration(node)) {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)\n }\n continue\n }\n\n if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {\n if (node.id && tracked.has(node.id.name)) {\n bindings.add(node.id.name)\n }\n }\n }\n\n return bindings\n}\n\nfunction collectBlockBindings(\n block: t.BlockStatement,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n for (const node of block.body) {\n if (t.isVariableDeclaration(node) && node.kind !== 'var') {\n for (const decl of node.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, tracked, bindings)\n }\n continue\n }\n\n if (t.isFunctionDeclaration(node) || t.isClassDeclaration(node)) {\n if (node.id && tracked.has(node.id.name)) {\n bindings.add(node.id.name)\n }\n }\n }\n\n return bindings\n}\n\nfunction collectFunctionBindings(\n fn: t.Function,\n tracked: Set<string>,\n): Set<string> {\n const bindings = new Set<string>()\n\n if (\n (t.isFunctionDeclaration(fn) || t.isFunctionExpression(fn)) &&\n fn.id &&\n tracked.has(fn.id.name)\n ) {\n bindings.add(fn.id.name)\n }\n\n for (const param of fn.params) {\n addPatternBindingsIfTracked(param as t.LVal, tracked, bindings)\n }\n\n if (t.isBlockStatement(fn.body)) {\n collectHoistedVarBindings(fn.body, tracked, bindings)\n }\n\n return bindings\n}\n\ntype UsageWalkContext = {\n parents: Array<t.Node>\n scopeStack: Array<Set<string>>\n}\n\nfunction isShadowedByScope(\n name: string,\n scopeStack: Array<Set<string>>,\n): boolean {\n for (let i = scopeStack.length - 1; i >= 0; i--) {\n if (scopeStack[i]?.has(name)) {\n return true\n }\n }\n return false\n}\n\nfunction isBindingIdentifierInParent(\n node: t.Identifier,\n parent: t.Node | undefined,\n): boolean {\n if (!parent) return false\n\n if (t.isImportSpecifier(parent) || t.isImportDefaultSpecifier(parent)) {\n return parent.local === node\n }\n if (t.isImportNamespaceSpecifier(parent)) {\n return parent.local === node\n }\n if (t.isFunctionDeclaration(parent) || t.isFunctionExpression(parent)) {\n return (\n parent.id === node || parent.params.includes(node as unknown as t.Pattern)\n )\n }\n if (t.isArrowFunctionExpression(parent)) {\n return parent.params.includes(node as unknown as t.Pattern)\n }\n if (t.isClassDeclaration(parent) || t.isClassExpression(parent)) {\n return parent.id === node\n }\n if (t.isVariableDeclarator(parent)) {\n return parent.id === node\n }\n if (t.isCatchClause(parent)) {\n return parent.param === node\n }\n\n return false\n}\n\nfunction isInsideCompilerSafeBoundaryNodes(\n parents: Array<t.Node>,\n envType: BoundaryEnv,\n): boolean {\n for (let i = parents.length - 1; i >= 0; i--) {\n const node = parents[i]!\n if (!t.isFunction(node)) {\n continue\n }\n\n const call = parents[i - 1]\n if (\n call &&\n t.isCallExpression(call) &&\n isCompilerSafeBoundaryCall(call, node, envType)\n ) {\n return true\n }\n }\n\n return false\n}\n\nfunction findUsagePosInAnalysis(\n result: TransformResult,\n source: string,\n envType?: BoundaryEnv,\n): UsagePos | undefined {\n const analysis = getOrCreateImportAnalysis(result)\n const cacheKey: UsageCacheKey = `${envType ?? 'post'}::${source}`\n if (analysis.usageByKey.has(cacheKey)) {\n return analysis.usageByKey.get(cacheKey) ?? undefined\n }\n\n const imported =\n analysis.importBindingsBySource.get(source)?.importedLocalNames\n if (!imported || imported.size === 0) {\n analysis.usageByKey.set(cacheKey, null)\n return undefined\n }\n\n let preferred: UsagePos | undefined\n let anyUsage: UsagePos | undefined\n\n const visit = (node: t.Node, ctx: UsageWalkContext): void => {\n if (preferred && anyUsage) {\n return\n }\n\n if (t.isProgram(node)) {\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [...ctx.scopeStack, collectProgramBindings(node, imported)],\n }\n for (const child of node.body) {\n visit(child, nextCtx)\n }\n return\n }\n\n if (t.isFunction(node)) {\n const functionCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [\n ...ctx.scopeStack,\n collectFunctionBindings(node, imported),\n ],\n }\n\n visit(node.body, functionCtx)\n return\n }\n\n if (t.isBlockStatement(node)) {\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: [...ctx.scopeStack, collectBlockBindings(node, imported)],\n }\n for (const child of node.body) {\n visit(child, nextCtx)\n }\n return\n }\n\n if (t.isCatchClause(node)) {\n const bindings = new Set<string>()\n if (node.param) {\n addPatternBindingsIfTracked(node.param as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.body, nextCtx)\n return\n }\n\n if (\n t.isForStatement(node) &&\n t.isVariableDeclaration(node.init) &&\n node.init.kind !== 'var'\n ) {\n const bindings = new Set<string>()\n for (const decl of node.init.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.init, nextCtx)\n if (node.test) visit(node.test, nextCtx)\n if (node.update) visit(node.update, nextCtx)\n visit(node.body, nextCtx)\n return\n }\n\n if (\n (t.isForInStatement(node) || t.isForOfStatement(node)) &&\n t.isVariableDeclaration(node.left) &&\n node.left.kind !== 'var'\n ) {\n const bindings = new Set<string>()\n for (const decl of node.left.declarations) {\n addPatternBindingsIfTracked(decl.id as t.LVal, imported, bindings)\n }\n const nextCtx = {\n parents: [...ctx.parents, node],\n scopeStack: bindings.size\n ? [...ctx.scopeStack, bindings]\n : ctx.scopeStack,\n }\n visit(node.left, nextCtx)\n visit(node.right, nextCtx)\n visit(node.body, nextCtx)\n return\n }\n\n const nextParents = [...ctx.parents, node]\n\n if (t.isIdentifier(node)) {\n const parent = ctx.parents[ctx.parents.length - 1]\n if (imported.has(node.name)) {\n if (!isBindingIdentifierInParent(node, parent)) {\n if (\n !(\n t.isObjectProperty(parent) &&\n parent.key === node &&\n !parent.computed &&\n !parent.shorthand\n ) &&\n !(\n t.isObjectMethod(parent) &&\n parent.key === node &&\n !parent.computed\n ) &&\n !(t.isExportSpecifier(parent) && parent.exported === node) &&\n !isShadowedByScope(node.name, ctx.scopeStack) &&\n !(\n envType && isInsideCompilerSafeBoundaryNodes(ctx.parents, envType)\n )\n ) {\n const loc = node.loc?.start\n if (loc) {\n const pos: UsagePos = { line: loc.line, column0: loc.column }\n const isPreferred =\n (t.isCallExpression(parent) && parent.callee === node) ||\n (t.isNewExpression(parent) && parent.callee === node) ||\n ((t.isMemberExpression(parent) ||\n t.isOptionalMemberExpression(parent)) &&\n parent.object === node)\n\n if (isPreferred) {\n preferred ||= pos\n } else {\n anyUsage ||= pos\n }\n }\n }\n }\n }\n }\n\n if (t.isImportDeclaration(node)) {\n return\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n visit(item as t.Node, {\n parents: nextParents,\n scopeStack: ctx.scopeStack,\n })\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n visit(child as t.Node, {\n parents: nextParents,\n scopeStack: ctx.scopeStack,\n })\n }\n }\n }\n\n visit(analysis.ast.program, {\n parents: [],\n scopeStack: [],\n })\n\n const pos = preferred ?? anyUsage ?? null\n analysis.usageByKey.set(cacheKey, pos)\n return pos ?? undefined\n}\n\nexport function findPostCompileUsagePosFromResult(\n result: TransformResult,\n source: string,\n): UsagePos | undefined {\n return findUsagePosInAnalysis(result, source)\n}\n\nexport function findPostCompileUsagePos(\n code: string,\n source: string,\n): UsagePos | undefined {\n return findPostCompileUsagePosFromResult(makeTransientResult(code), source)\n}\n\nexport function findOriginalUnsafeUsagePosFromResult(\n result: TransformResult,\n source: string,\n envType: BoundaryEnv,\n): UsagePos | undefined {\n return findUsagePosInAnalysis(result, source, envType)\n}\n\nexport function findOriginalUnsafeUsagePos(\n code: string,\n source: string,\n envType: BoundaryEnv,\n): UsagePos | undefined {\n return findOriginalUnsafeUsagePosFromResult(\n makeTransientResult(code),\n source,\n envType,\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MOCK_MODULE_ID } from "./constants.js";
|
|
2
|
-
import { parseImportProtectionAst } from "./ast.js";
|
|
3
2
|
import * as t from "@babel/types";
|
|
4
|
-
import { generateFromAst } from "@tanstack/router-utils";
|
|
3
|
+
import { generateFromAst, parseAst } from "@tanstack/router-utils";
|
|
5
4
|
//#region src/import-protection/rewrite.ts
|
|
6
5
|
function getModuleExportName(node) {
|
|
7
6
|
return t.isIdentifier(node) ? node.name : node.value;
|
|
@@ -47,7 +46,10 @@ function createInternalReexportVarName(localName, mockIndex, usedNames) {
|
|
|
47
46
|
* export { x as y } from 'denied' -> export const y = mock.x
|
|
48
47
|
*/
|
|
49
48
|
function rewriteDeniedImports(code, id, deniedSources, getMockModuleId = () => MOCK_MODULE_ID) {
|
|
50
|
-
return rewriteDeniedImportsFromAst(
|
|
49
|
+
return rewriteDeniedImportsFromAst(parseAst({
|
|
50
|
+
code,
|
|
51
|
+
filename: id
|
|
52
|
+
}), id, deniedSources, getMockModuleId);
|
|
51
53
|
}
|
|
52
54
|
function rewriteDeniedImportsFromAst(ast, id, deniedSources, getMockModuleId = () => MOCK_MODULE_ID) {
|
|
53
55
|
let modified = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rewrite.js","names":[],"sources":["../../../src/import-protection/rewrite.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { generateFromAst } from '@tanstack/router-utils'\n\nimport { parseImportProtectionAst } from './ast'\nimport { MOCK_MODULE_ID } from './constants'\nimport type { ParsedAst } from './ast'\nimport type { SourceMapLike } from './sourceLocation'\n\nfunction getModuleExportName(node: t.Identifier | t.StringLiteral): string {\n return t.isIdentifier(node) ? node.name : node.value\n}\n\nfunction toMemberExpressionProperty(name: string): {\n property: t.Identifier | t.StringLiteral\n computed: boolean\n} {\n return t.isValidIdentifier(name)\n ? { property: t.identifier(name), computed: false }\n : { property: t.stringLiteral(name), computed: true }\n}\n\nfunction toModuleExportNameNode(name: string): t.Identifier | t.StringLiteral {\n return t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name)\n}\n\nfunction createInternalReexportVarName(\n localName: string,\n mockIndex: number,\n usedNames: Set<string>,\n): string {\n const baseName = t.isValidIdentifier(localName)\n ? `__tss_reexport_${localName}`\n : `__tss_reexport_${mockIndex}`\n\n let candidate = baseName\n let suffix = 0\n while (usedNames.has(candidate)) {\n suffix++\n candidate = `${baseName}_${suffix}`\n }\n\n usedNames.add(candidate)\n return candidate\n}\n\n/**\n * Rewrite static imports/re-exports from denied sources using Babel AST transforms.\n *\n * Transforms:\n * import { a as b, c } from 'denied'\n * Into:\n * import __tss_deny_0 from 'tanstack-start-import-protection:mock'\n * const b = __tss_deny_0.a\n * const c = __tss_deny_0.c\n *\n * Also handles:\n * import def from 'denied' -> import def from mock\n * import * as ns from 'denied' -> import ns from mock\n * export { x } from 'denied' -> export const x = mock.x\n * export * from 'denied' -> removed\n * export { x as y } from 'denied' -> export const y = mock.x\n */\nexport function rewriteDeniedImports(\n code: string,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n return rewriteDeniedImportsFromAst(\n parseImportProtectionAst(code),\n id,\n deniedSources,\n getMockModuleId,\n )\n}\n\nfunction rewriteDeniedImportsFromAst(\n ast: ParsedAst,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n let modified = false\n let mockCounter = 0\n\n // Walk program body in reverse so splice indices stay valid\n for (let i = ast.program.body.length - 1; i >= 0; i--) {\n const node = ast.program.body[i]!\n\n if (t.isImportDeclaration(node)) {\n if (node.importKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockVar = `__tss_deny_${mockCounter++}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n\n for (const specifier of node.specifiers) {\n if (\n t.isImportDefaultSpecifier(specifier) ||\n t.isImportNamespaceSpecifier(specifier)\n ) {\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.identifier(mockVar),\n ),\n ]),\n )\n } else if (t.isImportSpecifier(specifier)) {\n if (specifier.importKind === 'type') continue\n const importedName = getModuleExportName(specifier.imported)\n const memberProperty = toMemberExpressionProperty(importedName)\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.memberExpression(\n t.identifier(mockVar),\n memberProperty.property,\n memberProperty.computed,\n ),\n ),\n ]),\n )\n }\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportNamedDeclaration(node) && node.source) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockIndex = mockCounter++\n const mockVar = `__tss_deny_${mockIndex}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n const usedInternalVars = new Set<string>()\n const exportSpecifiers: Array<{\n localName: string\n exportedName: string\n }> = []\n for (const specifier of node.specifiers) {\n if (t.isExportSpecifier(specifier)) {\n if (specifier.exportKind === 'type') continue\n const localName = getModuleExportName(specifier.local)\n const exportedName = getModuleExportName(specifier.exported)\n const memberProperty = toMemberExpressionProperty(localName)\n\n const internalVar = createInternalReexportVarName(\n localName,\n mockIndex,\n usedInternalVars,\n )\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(internalVar),\n t.memberExpression(\n t.identifier(mockVar),\n memberProperty.property,\n memberProperty.computed,\n ),\n ),\n ]),\n )\n exportSpecifiers.push({ localName: internalVar, exportedName })\n }\n }\n\n if (exportSpecifiers.length > 0) {\n replacements.push(\n t.exportNamedDeclaration(\n null,\n exportSpecifiers.map((s) =>\n t.exportSpecifier(\n t.identifier(s.localName),\n toModuleExportNameNode(s.exportedName),\n ),\n ),\n ),\n )\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n ast.program.body.splice(i, 1)\n modified = true\n continue\n }\n }\n\n if (!modified) return undefined\n\n const result = generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n\n return {\n code: result.code,\n ...(result.map ? { map: result.map as SourceMapLike } : {}),\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rewrite.js","names":[],"sources":["../../../src/import-protection/rewrite.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { generateFromAst, parseAst } from '@tanstack/router-utils'\n\nimport { MOCK_MODULE_ID } from './constants'\nimport type { SourceMapLike } from './sourceLocation'\nimport type { ParseAstResult } from '@tanstack/router-utils'\n\nfunction getModuleExportName(node: t.Identifier | t.StringLiteral): string {\n return t.isIdentifier(node) ? node.name : node.value\n}\n\nfunction toMemberExpressionProperty(name: string): {\n property: t.Identifier | t.StringLiteral\n computed: boolean\n} {\n return t.isValidIdentifier(name)\n ? { property: t.identifier(name), computed: false }\n : { property: t.stringLiteral(name), computed: true }\n}\n\nfunction toModuleExportNameNode(name: string): t.Identifier | t.StringLiteral {\n return t.isValidIdentifier(name) ? t.identifier(name) : t.stringLiteral(name)\n}\n\nfunction createInternalReexportVarName(\n localName: string,\n mockIndex: number,\n usedNames: Set<string>,\n): string {\n const baseName = t.isValidIdentifier(localName)\n ? `__tss_reexport_${localName}`\n : `__tss_reexport_${mockIndex}`\n\n let candidate = baseName\n let suffix = 0\n while (usedNames.has(candidate)) {\n suffix++\n candidate = `${baseName}_${suffix}`\n }\n\n usedNames.add(candidate)\n return candidate\n}\n\n/**\n * Rewrite static imports/re-exports from denied sources using Babel AST transforms.\n *\n * Transforms:\n * import { a as b, c } from 'denied'\n * Into:\n * import __tss_deny_0 from 'tanstack-start-import-protection:mock'\n * const b = __tss_deny_0.a\n * const c = __tss_deny_0.c\n *\n * Also handles:\n * import def from 'denied' -> import def from mock\n * import * as ns from 'denied' -> import ns from mock\n * export { x } from 'denied' -> export const x = mock.x\n * export * from 'denied' -> removed\n * export { x as y } from 'denied' -> export const y = mock.x\n */\nexport function rewriteDeniedImports(\n code: string,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n return rewriteDeniedImportsFromAst(\n parseAst({ code, filename: id }),\n id,\n deniedSources,\n getMockModuleId,\n )\n}\n\nfunction rewriteDeniedImportsFromAst(\n ast: ParseAstResult,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n let modified = false\n let mockCounter = 0\n\n // Walk program body in reverse so splice indices stay valid\n for (let i = ast.program.body.length - 1; i >= 0; i--) {\n const node = ast.program.body[i]!\n\n if (t.isImportDeclaration(node)) {\n if (node.importKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockVar = `__tss_deny_${mockCounter++}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n\n for (const specifier of node.specifiers) {\n if (\n t.isImportDefaultSpecifier(specifier) ||\n t.isImportNamespaceSpecifier(specifier)\n ) {\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.identifier(mockVar),\n ),\n ]),\n )\n } else if (t.isImportSpecifier(specifier)) {\n if (specifier.importKind === 'type') continue\n const importedName = getModuleExportName(specifier.imported)\n const memberProperty = toMemberExpressionProperty(importedName)\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.memberExpression(\n t.identifier(mockVar),\n memberProperty.property,\n memberProperty.computed,\n ),\n ),\n ]),\n )\n }\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportNamedDeclaration(node) && node.source) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockIndex = mockCounter++\n const mockVar = `__tss_deny_${mockIndex}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n const usedInternalVars = new Set<string>()\n const exportSpecifiers: Array<{\n localName: string\n exportedName: string\n }> = []\n for (const specifier of node.specifiers) {\n if (t.isExportSpecifier(specifier)) {\n if (specifier.exportKind === 'type') continue\n const localName = getModuleExportName(specifier.local)\n const exportedName = getModuleExportName(specifier.exported)\n const memberProperty = toMemberExpressionProperty(localName)\n\n const internalVar = createInternalReexportVarName(\n localName,\n mockIndex,\n usedInternalVars,\n )\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(internalVar),\n t.memberExpression(\n t.identifier(mockVar),\n memberProperty.property,\n memberProperty.computed,\n ),\n ),\n ]),\n )\n exportSpecifiers.push({ localName: internalVar, exportedName })\n }\n }\n\n if (exportSpecifiers.length > 0) {\n replacements.push(\n t.exportNamedDeclaration(\n null,\n exportSpecifiers.map((s) =>\n t.exportSpecifier(\n t.identifier(s.localName),\n toModuleExportNameNode(s.exportedName),\n ),\n ),\n ),\n )\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n ast.program.body.splice(i, 1)\n modified = true\n continue\n }\n }\n\n if (!modified) return undefined\n\n const result = generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n\n return {\n code: result.code,\n ...(result.map ? { map: result.map as SourceMapLike } : {}),\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ImportAnalysis } from './analysis.js';
|
|
2
|
-
import { ParsedAst } from './ast.js';
|
|
3
2
|
import { Loc } from './trace.js';
|
|
3
|
+
import { ParseAstResult } from '@tanstack/router-utils';
|
|
4
4
|
/**
|
|
5
5
|
* Minimal source-map shape used throughout the import-protection plugin.
|
|
6
6
|
*/
|
|
@@ -15,12 +15,13 @@ export interface SourceMapLike {
|
|
|
15
15
|
}
|
|
16
16
|
export interface TransformResult {
|
|
17
17
|
code: string;
|
|
18
|
+
filename?: string;
|
|
18
19
|
map: SourceMapLike | undefined;
|
|
19
20
|
originalCode: string | undefined;
|
|
20
21
|
originalResult?: TransformResult;
|
|
21
22
|
/** Precomputed line index for `code` (index → line/col). */
|
|
22
23
|
lineIndex?: LineIndex;
|
|
23
|
-
parsedAst?:
|
|
24
|
+
parsedAst?: ParseAstResult;
|
|
24
25
|
analysis?: ImportAnalysis;
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
@@ -168,6 +168,7 @@ function getOrCreateOriginalTransformResult(result) {
|
|
|
168
168
|
if (!result.originalCode) return;
|
|
169
169
|
if (!result.originalResult) result.originalResult = {
|
|
170
170
|
code: result.originalCode,
|
|
171
|
+
filename: result.filename,
|
|
171
172
|
map: void 0,
|
|
172
173
|
originalCode: result.originalCode
|
|
173
174
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sourceLocation.js","names":[],"sources":["../../../src/import-protection/sourceLocation.ts"],"sourcesContent":["import { SourceMapConsumer } from 'source-map'\nimport * as path from 'pathe'\n\nimport {\n findOriginalUnsafeUsagePosFromResult,\n findPostCompileUsagePosFromResult,\n getImportSpecifierLocationFromResult,\n} from './analysis'\nimport { getOrCreate, normalizeFilePath } from './utils'\nimport type { ImportAnalysis } from './analysis'\nimport type { ParsedAst } from './ast'\nimport type { Loc } from './trace'\nimport type { RawSourceMap } from 'source-map'\n\n// Source-map type compatible with both Rollup's SourceMap and source-map's\n// RawSourceMap. Structural type avoids version: number vs string mismatch.\n\n/**\n * Minimal source-map shape used throughout the import-protection plugin.\n */\nexport interface SourceMapLike {\n file?: string\n sourceRoot?: string\n version: number | string\n sources: Array<string>\n names: Array<string>\n sourcesContent?: Array<string | null>\n mappings: string\n}\n\n// Transform result provider (replaces ctx.load() which doesn't work in dev)\nexport interface TransformResult {\n code: string\n map: SourceMapLike | undefined\n originalCode: string | undefined\n originalResult?: TransformResult\n /** Precomputed line index for `code` (index → line/col). */\n lineIndex?: LineIndex\n parsedAst?: ParsedAst\n analysis?: ImportAnalysis\n}\n\n/**\n * Provides the transformed code and composed sourcemap for a module.\n *\n * Populated from a late-running transform hook. By the time `resolveId`\n * fires for an import, the importer has already been fully transformed.\n */\nexport interface TransformResultProvider {\n getTransformResult: (id: string) => TransformResult | undefined\n}\n\nexport interface ImportSpecifierLocationIndex {\n find: FindImportSpecifierLocationIndex\n}\n\n// Index → line/column conversion\n\nexport type LineIndex = {\n offsets: Array<number>\n}\n\nexport function buildLineIndex(code: string): LineIndex {\n const offsets: Array<number> = [0]\n for (let i = 0; i < code.length; i++) {\n if (code.charCodeAt(i) === 10) {\n offsets.push(i + 1)\n }\n }\n return { offsets }\n}\n\nfunction upperBound(values: Array<number>, x: number): number {\n let lo = 0\n let hi = values.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (values[mid]! <= x) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\nfunction indexToLineColWithIndex(\n lineIndex: LineIndex,\n idx: number,\n): { line: number; column0: number } {\n const offsets = lineIndex.offsets\n const ub = upperBound(offsets, idx)\n const lineIdx = Math.max(0, ub - 1)\n const line = lineIdx + 1\n\n const lineStart = offsets[lineIdx] ?? 0\n return { line, column0: Math.max(0, idx - lineStart) }\n}\n\nexport function indexToLineColumn(\n lineIndex: LineIndex,\n idx: number,\n): { line: number; column: number } {\n const { line, column0 } = indexToLineColWithIndex(lineIndex, idx)\n return {\n line,\n column: column0 + 1,\n }\n}\n\nexport function normalizeSourceMap(map: SourceMapLike | null | undefined):\n | {\n version: number\n file: string\n sourceRoot?: string\n sources: Array<string>\n names: Array<string>\n sourcesContent?: Array<string>\n mappings: string\n }\n | undefined {\n if (!map) {\n return undefined\n }\n\n return {\n ...map,\n version: Number(map.version),\n file: map.file ?? '',\n names: Array.isArray(map.names) ? map.names : [],\n sourcesContent:\n map.sourcesContent?.map((value) => value ?? '') ?? undefined,\n }\n}\n\n/**\n * Pick the most-likely original source text for `importerFile` from\n * a sourcemap that may contain multiple sources.\n */\nexport function pickOriginalCodeFromSourcesContent(\n map: SourceMapLike | undefined,\n importerFile: string,\n root: string,\n): string | undefined {\n if (!map?.sourcesContent || map.sources.length === 0) {\n return undefined\n }\n\n const file = normalizeFilePath(importerFile)\n const sourceRoot = map.sourceRoot\n const fileSeg = file.split('/').filter(Boolean)\n\n const resolveBase = sourceRoot ? path.resolve(root, sourceRoot) : root\n\n let bestIdx = -1\n let bestScore = -1\n\n for (let i = 0; i < map.sources.length; i++) {\n const content = map.sourcesContent[i]\n if (typeof content !== 'string') continue\n\n const src = map.sources[i] ?? ''\n\n const normalizedSrc = normalizeFilePath(src)\n if (normalizedSrc === file) {\n return content\n }\n\n let resolved: string\n if (!src) {\n resolved = ''\n } else if (path.isAbsolute(src)) {\n resolved = normalizeFilePath(src)\n } else {\n resolved = normalizeFilePath(path.resolve(resolveBase, src))\n }\n if (resolved === file) {\n return content\n }\n\n // Count matching path segments from the end.\n const normalizedSrcSeg = normalizedSrc.split('/').filter(Boolean)\n const resolvedSeg =\n resolved !== normalizedSrc\n ? resolved.split('/').filter(Boolean)\n : normalizedSrcSeg\n const score = Math.max(\n segmentSuffixScore(normalizedSrcSeg, fileSeg),\n segmentSuffixScore(resolvedSeg, fileSeg),\n )\n\n if (score > bestScore) {\n bestScore = score\n bestIdx = i\n }\n }\n\n if (bestIdx !== -1 && bestScore >= 1) {\n return map.sourcesContent[bestIdx] ?? undefined\n }\n\n return map.sourcesContent[0] ?? undefined\n}\n\n/** Count matching path segments from the end of `aSeg` against `bSeg`. */\nfunction segmentSuffixScore(aSeg: Array<string>, bSeg: Array<string>): number {\n let score = 0\n for (\n let i = aSeg.length - 1, j = bSeg.length - 1;\n i >= 0 && j >= 0;\n i--, j--\n ) {\n if (aSeg[i] !== bSeg[j]) break\n score++\n }\n return score\n}\n\nasync function mapGeneratedToOriginal(\n map: SourceMapLike | undefined,\n generated: { line: number; column0: number },\n fallbackFile: string,\n): Promise<Loc> {\n const fallback: Loc = {\n file: fallbackFile,\n line: generated.line,\n column: generated.column0 + 1,\n }\n\n if (!map) {\n return fallback\n }\n\n const consumer = await getSourceMapConsumer(map)\n if (!consumer) return fallback\n\n try {\n const orig = consumer.originalPositionFor({\n line: generated.line,\n column: generated.column0,\n })\n if (orig.line != null && orig.column != null) {\n return {\n file: orig.source ? normalizeFilePath(orig.source) : fallbackFile,\n line: orig.line,\n column: orig.column + 1,\n }\n }\n } catch {\n // Malformed sourcemap\n }\n\n return fallback\n}\n\nconst consumerCache = new WeakMap<object, Promise<SourceMapConsumer | null>>()\n\nfunction toRawSourceMap(map: SourceMapLike): RawSourceMap {\n return {\n ...map,\n file: map.file ?? '',\n version: Number(map.version),\n sourcesContent: map.sourcesContent?.map((s) => s ?? '') ?? [],\n }\n}\n\nasync function getSourceMapConsumer(\n map: SourceMapLike,\n): Promise<SourceMapConsumer | null> {\n const cached = consumerCache.get(map)\n if (cached) return cached\n\n const promise = (async () => {\n try {\n return await new SourceMapConsumer(toRawSourceMap(map))\n } catch {\n return null\n }\n })()\n\n consumerCache.set(map, promise)\n return promise\n}\n\nexport type ImportLocEntry = { file?: string; line: number; column: number }\n\n/**\n * Cache for import statement locations with reverse index for O(1)\n * invalidation by file. Keys: `${importerFile}::${source}`.\n */\nexport class ImportLocCache {\n private cache = new Map<string, ImportLocEntry | null>()\n private reverseIndex = new Map<string, Set<string>>()\n\n has(key: string): boolean {\n return this.cache.has(key)\n }\n\n get(key: string): ImportLocEntry | null | undefined {\n return this.cache.get(key)\n }\n\n set(key: string, value: ImportLocEntry | null): void {\n this.cache.set(key, value)\n const file = key.slice(0, key.indexOf('::'))\n getOrCreate(this.reverseIndex, file, () => new Set()).add(key)\n }\n\n clear(): void {\n this.cache.clear()\n this.reverseIndex.clear()\n }\n\n /** Remove all cache entries where the importer matches `file`. */\n deleteByFile(file: string): void {\n const keys = this.reverseIndex.get(file)\n if (keys) {\n for (const key of keys) {\n this.cache.delete(key)\n }\n this.reverseIndex.delete(file)\n }\n }\n}\n\nexport type FindImportSpecifierLocationIndex = (\n result: TransformResult,\n source: string,\n) => number\n\nexport function getOrCreateOriginalTransformResult(\n result: TransformResult,\n): TransformResult | undefined {\n if (!result.originalCode) {\n return undefined\n }\n\n if (!result.originalResult) {\n result.originalResult = {\n code: result.originalCode,\n map: undefined,\n originalCode: result.originalCode,\n }\n }\n\n return result.originalResult\n}\n\nexport function createImportSpecifierLocationIndex(): ImportSpecifierLocationIndex {\n return {\n find(result: TransformResult, source: string): number {\n if (!result.code.includes(source)) {\n return -1\n }\n\n return getImportSpecifierLocationFromResult(result, source)\n },\n }\n}\n\n/**\n * Find the location of an import statement in a transformed module\n * by searching the post-transform code and mapping back via sourcemap.\n * Results are cached in `importLocCache`.\n */\nexport async function findImportStatementLocationFromTransformed(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n importLocCache: ImportLocCache,\n findImportSpecifierLocationIndex: FindImportSpecifierLocationIndex,\n): Promise<Loc | undefined> {\n const importerFile = normalizeFilePath(importerId)\n const cacheKey = `${importerFile}::${source}`\n if (importLocCache.has(cacheKey)) {\n return importLocCache.get(cacheKey) ?? undefined\n }\n\n try {\n const res = provider.getTransformResult(importerId)\n if (!res) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const { map } = res\n\n const lineIndex =\n res.lineIndex ?? (res.lineIndex = buildLineIndex(res.code))\n\n const idx = findImportSpecifierLocationIndex(res, source)\n if (idx === -1) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const generated = indexToLineColWithIndex(lineIndex, idx)\n const loc = await mapGeneratedToOriginal(map, generated, importerFile)\n importLocCache.set(cacheKey, loc)\n return loc\n } catch {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n}\n\n/**\n * Find the first post-compile usage location for a denied import specifier.\n * Best-effort: searches transformed code for non-import uses of imported\n * bindings and maps back to original source via sourcemap.\n */\nexport async function findPostCompileUsageLocation(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n): Promise<Loc | undefined> {\n try {\n const importerFile = normalizeFilePath(importerId)\n const res = provider.getTransformResult(importerId)\n if (!res) return undefined\n const { code, map } = res\n\n if (!res.lineIndex) {\n res.lineIndex = buildLineIndex(code)\n }\n\n const pos = findPostCompileUsagePosFromResult(res, source)\n if (!pos) return undefined\n\n return await mapGeneratedToOriginal(map, pos, importerFile)\n } catch {\n return undefined\n }\n}\n\n/**\n * Best-effort original-source usage lookup for cases where a later transform\n * removes or rewrites the import from emitted code but preserves the original\n * source in `sourcesContent`.\n */\nexport function findOriginalUsageLocation(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n envType?: 'client' | 'server',\n): Loc | undefined {\n try {\n const importerFile = normalizeFilePath(importerId)\n const res = provider.getTransformResult(importerId)\n if (!res) return undefined\n const originalResult = getOrCreateOriginalTransformResult(res)\n if (!originalResult) return undefined\n\n const pos = envType\n ? findOriginalUnsafeUsagePosFromResult(originalResult, source, envType)\n : findPostCompileUsagePosFromResult(originalResult, source)\n if (!pos) return undefined\n\n return {\n file: importerFile,\n line: pos.line,\n column: pos.column0 + 1,\n }\n } catch {\n return undefined\n }\n}\n\n/**\n * Annotate each trace hop with the location of the import that created the\n * edge (file:line:col). Skips steps that already have a location.\n */\nexport async function addTraceImportLocations(\n provider: TransformResultProvider,\n trace: Array<{\n file: string\n specifier?: string\n line?: number\n column?: number\n }>,\n importLocCache: ImportLocCache,\n findImportSpecifierLocationIndex: FindImportSpecifierLocationIndex,\n): Promise<void> {\n for (const step of trace) {\n if (!step.specifier) continue\n if (step.line != null && step.column != null) continue\n const loc = await findImportStatementLocationFromTransformed(\n provider,\n step.file,\n step.specifier,\n importLocCache,\n findImportSpecifierLocationIndex,\n )\n if (!loc) continue\n step.line = loc.line\n step.column = loc.column\n }\n}\n\n// Code snippet extraction (vitest-style context around a location)\n\nexport interface CodeSnippet {\n /** Source lines with line numbers, e.g. `[\" 6 | import { getSecret } from './secret.server'\", ...]` */\n lines: Array<string>\n /** The highlighted line (1-indexed original line number) */\n highlightLine: number\n /** Clickable file:line reference */\n location: string\n}\n\n/**\n * Build a vitest-style code snippet showing lines surrounding a location.\n *\n * Prefers `originalCode` from the sourcemap's sourcesContent; falls back\n * to transformed code when unavailable.\n */\nexport function buildCodeSnippet(\n provider: TransformResultProvider,\n moduleId: string,\n loc: Loc,\n contextLines: number = 2,\n): CodeSnippet | undefined {\n try {\n const importerFile = normalizeFilePath(moduleId)\n const res = provider.getTransformResult(moduleId)\n if (!res) return undefined\n\n const sourceCode = res.originalCode ?? res.code\n const targetLine = loc.line // 1-indexed\n const targetCol = loc.column // 1-indexed\n\n if (targetLine < 1) return undefined\n\n const allLines = sourceCode.split('\\n')\n // Strip trailing \\r from \\r\\n line endings\n for (let i = 0; i < allLines.length; i++) {\n const line = allLines[i]!\n if (line.endsWith('\\r')) allLines[i] = line.slice(0, -1)\n }\n\n const wantStart = Math.max(1, targetLine - contextLines)\n const wantEnd = Math.min(allLines.length, targetLine + contextLines)\n\n if (targetLine > allLines.length) return undefined\n\n const lines = allLines.slice(wantStart - 1, wantEnd)\n const gutterWidth = String(wantEnd).length\n\n const sourceFile = loc.file ?? importerFile\n const snippetLines: Array<string> = []\n for (let i = 0; i < lines.length; i++) {\n const ln = wantStart + i\n const lineContent = lines[i]!\n const lineNumStr = String(ln).padStart(gutterWidth, ' ')\n const marker = ln === targetLine ? '>' : ' '\n snippetLines.push(` ${marker} ${lineNumStr} | ${lineContent}`)\n\n if (ln === targetLine && targetCol > 0) {\n const padding = ' '.repeat(targetCol - 1)\n snippetLines.push(` ${' '.repeat(gutterWidth)} | ${padding}^`)\n }\n }\n\n return {\n lines: snippetLines,\n highlightLine: targetLine,\n location: `${sourceFile}:${targetLine}:${targetCol}`,\n }\n } catch {\n return undefined\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sourceLocation.js","names":[],"sources":["../../../src/import-protection/sourceLocation.ts"],"sourcesContent":["import { SourceMapConsumer } from 'source-map'\nimport * as path from 'pathe'\n\nimport {\n findOriginalUnsafeUsagePosFromResult,\n findPostCompileUsagePosFromResult,\n getImportSpecifierLocationFromResult,\n} from './analysis'\nimport { getOrCreate, normalizeFilePath } from './utils'\nimport type { ImportAnalysis } from './analysis'\nimport type { Loc } from './trace'\nimport type { ParseAstResult } from '@tanstack/router-utils'\nimport type { RawSourceMap } from 'source-map'\n\n// Source-map type compatible with both Rollup's SourceMap and source-map's\n// RawSourceMap. Structural type avoids version: number vs string mismatch.\n\n/**\n * Minimal source-map shape used throughout the import-protection plugin.\n */\nexport interface SourceMapLike {\n file?: string\n sourceRoot?: string\n version: number | string\n sources: Array<string>\n names: Array<string>\n sourcesContent?: Array<string | null>\n mappings: string\n}\n\n// Transform result provider (replaces ctx.load() which doesn't work in dev)\nexport interface TransformResult {\n code: string\n filename?: string\n map: SourceMapLike | undefined\n originalCode: string | undefined\n originalResult?: TransformResult\n /** Precomputed line index for `code` (index → line/col). */\n lineIndex?: LineIndex\n parsedAst?: ParseAstResult\n analysis?: ImportAnalysis\n}\n\n/**\n * Provides the transformed code and composed sourcemap for a module.\n *\n * Populated from a late-running transform hook. By the time `resolveId`\n * fires for an import, the importer has already been fully transformed.\n */\nexport interface TransformResultProvider {\n getTransformResult: (id: string) => TransformResult | undefined\n}\n\nexport interface ImportSpecifierLocationIndex {\n find: FindImportSpecifierLocationIndex\n}\n\n// Index → line/column conversion\n\nexport type LineIndex = {\n offsets: Array<number>\n}\n\nexport function buildLineIndex(code: string): LineIndex {\n const offsets: Array<number> = [0]\n for (let i = 0; i < code.length; i++) {\n if (code.charCodeAt(i) === 10) {\n offsets.push(i + 1)\n }\n }\n return { offsets }\n}\n\nfunction upperBound(values: Array<number>, x: number): number {\n let lo = 0\n let hi = values.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (values[mid]! <= x) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\nfunction indexToLineColWithIndex(\n lineIndex: LineIndex,\n idx: number,\n): { line: number; column0: number } {\n const offsets = lineIndex.offsets\n const ub = upperBound(offsets, idx)\n const lineIdx = Math.max(0, ub - 1)\n const line = lineIdx + 1\n\n const lineStart = offsets[lineIdx] ?? 0\n return { line, column0: Math.max(0, idx - lineStart) }\n}\n\nexport function indexToLineColumn(\n lineIndex: LineIndex,\n idx: number,\n): { line: number; column: number } {\n const { line, column0 } = indexToLineColWithIndex(lineIndex, idx)\n return {\n line,\n column: column0 + 1,\n }\n}\n\nexport function normalizeSourceMap(map: SourceMapLike | null | undefined):\n | {\n version: number\n file: string\n sourceRoot?: string\n sources: Array<string>\n names: Array<string>\n sourcesContent?: Array<string>\n mappings: string\n }\n | undefined {\n if (!map) {\n return undefined\n }\n\n return {\n ...map,\n version: Number(map.version),\n file: map.file ?? '',\n names: Array.isArray(map.names) ? map.names : [],\n sourcesContent:\n map.sourcesContent?.map((value) => value ?? '') ?? undefined,\n }\n}\n\n/**\n * Pick the most-likely original source text for `importerFile` from\n * a sourcemap that may contain multiple sources.\n */\nexport function pickOriginalCodeFromSourcesContent(\n map: SourceMapLike | undefined,\n importerFile: string,\n root: string,\n): string | undefined {\n if (!map?.sourcesContent || map.sources.length === 0) {\n return undefined\n }\n\n const file = normalizeFilePath(importerFile)\n const sourceRoot = map.sourceRoot\n const fileSeg = file.split('/').filter(Boolean)\n\n const resolveBase = sourceRoot ? path.resolve(root, sourceRoot) : root\n\n let bestIdx = -1\n let bestScore = -1\n\n for (let i = 0; i < map.sources.length; i++) {\n const content = map.sourcesContent[i]\n if (typeof content !== 'string') continue\n\n const src = map.sources[i] ?? ''\n\n const normalizedSrc = normalizeFilePath(src)\n if (normalizedSrc === file) {\n return content\n }\n\n let resolved: string\n if (!src) {\n resolved = ''\n } else if (path.isAbsolute(src)) {\n resolved = normalizeFilePath(src)\n } else {\n resolved = normalizeFilePath(path.resolve(resolveBase, src))\n }\n if (resolved === file) {\n return content\n }\n\n // Count matching path segments from the end.\n const normalizedSrcSeg = normalizedSrc.split('/').filter(Boolean)\n const resolvedSeg =\n resolved !== normalizedSrc\n ? resolved.split('/').filter(Boolean)\n : normalizedSrcSeg\n const score = Math.max(\n segmentSuffixScore(normalizedSrcSeg, fileSeg),\n segmentSuffixScore(resolvedSeg, fileSeg),\n )\n\n if (score > bestScore) {\n bestScore = score\n bestIdx = i\n }\n }\n\n if (bestIdx !== -1 && bestScore >= 1) {\n return map.sourcesContent[bestIdx] ?? undefined\n }\n\n return map.sourcesContent[0] ?? undefined\n}\n\n/** Count matching path segments from the end of `aSeg` against `bSeg`. */\nfunction segmentSuffixScore(aSeg: Array<string>, bSeg: Array<string>): number {\n let score = 0\n for (\n let i = aSeg.length - 1, j = bSeg.length - 1;\n i >= 0 && j >= 0;\n i--, j--\n ) {\n if (aSeg[i] !== bSeg[j]) break\n score++\n }\n return score\n}\n\nasync function mapGeneratedToOriginal(\n map: SourceMapLike | undefined,\n generated: { line: number; column0: number },\n fallbackFile: string,\n): Promise<Loc> {\n const fallback: Loc = {\n file: fallbackFile,\n line: generated.line,\n column: generated.column0 + 1,\n }\n\n if (!map) {\n return fallback\n }\n\n const consumer = await getSourceMapConsumer(map)\n if (!consumer) return fallback\n\n try {\n const orig = consumer.originalPositionFor({\n line: generated.line,\n column: generated.column0,\n })\n if (orig.line != null && orig.column != null) {\n return {\n file: orig.source ? normalizeFilePath(orig.source) : fallbackFile,\n line: orig.line,\n column: orig.column + 1,\n }\n }\n } catch {\n // Malformed sourcemap\n }\n\n return fallback\n}\n\nconst consumerCache = new WeakMap<object, Promise<SourceMapConsumer | null>>()\n\nfunction toRawSourceMap(map: SourceMapLike): RawSourceMap {\n return {\n ...map,\n file: map.file ?? '',\n version: Number(map.version),\n sourcesContent: map.sourcesContent?.map((s) => s ?? '') ?? [],\n }\n}\n\nasync function getSourceMapConsumer(\n map: SourceMapLike,\n): Promise<SourceMapConsumer | null> {\n const cached = consumerCache.get(map)\n if (cached) return cached\n\n const promise = (async () => {\n try {\n return await new SourceMapConsumer(toRawSourceMap(map))\n } catch {\n return null\n }\n })()\n\n consumerCache.set(map, promise)\n return promise\n}\n\nexport type ImportLocEntry = { file?: string; line: number; column: number }\n\n/**\n * Cache for import statement locations with reverse index for O(1)\n * invalidation by file. Keys: `${importerFile}::${source}`.\n */\nexport class ImportLocCache {\n private cache = new Map<string, ImportLocEntry | null>()\n private reverseIndex = new Map<string, Set<string>>()\n\n has(key: string): boolean {\n return this.cache.has(key)\n }\n\n get(key: string): ImportLocEntry | null | undefined {\n return this.cache.get(key)\n }\n\n set(key: string, value: ImportLocEntry | null): void {\n this.cache.set(key, value)\n const file = key.slice(0, key.indexOf('::'))\n getOrCreate(this.reverseIndex, file, () => new Set()).add(key)\n }\n\n clear(): void {\n this.cache.clear()\n this.reverseIndex.clear()\n }\n\n /** Remove all cache entries where the importer matches `file`. */\n deleteByFile(file: string): void {\n const keys = this.reverseIndex.get(file)\n if (keys) {\n for (const key of keys) {\n this.cache.delete(key)\n }\n this.reverseIndex.delete(file)\n }\n }\n}\n\nexport type FindImportSpecifierLocationIndex = (\n result: TransformResult,\n source: string,\n) => number\n\nexport function getOrCreateOriginalTransformResult(\n result: TransformResult,\n): TransformResult | undefined {\n if (!result.originalCode) {\n return undefined\n }\n\n if (!result.originalResult) {\n result.originalResult = {\n code: result.originalCode,\n filename: result.filename,\n map: undefined,\n originalCode: result.originalCode,\n }\n }\n\n return result.originalResult\n}\n\nexport function createImportSpecifierLocationIndex(): ImportSpecifierLocationIndex {\n return {\n find(result: TransformResult, source: string): number {\n if (!result.code.includes(source)) {\n return -1\n }\n\n return getImportSpecifierLocationFromResult(result, source)\n },\n }\n}\n\n/**\n * Find the location of an import statement in a transformed module\n * by searching the post-transform code and mapping back via sourcemap.\n * Results are cached in `importLocCache`.\n */\nexport async function findImportStatementLocationFromTransformed(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n importLocCache: ImportLocCache,\n findImportSpecifierLocationIndex: FindImportSpecifierLocationIndex,\n): Promise<Loc | undefined> {\n const importerFile = normalizeFilePath(importerId)\n const cacheKey = `${importerFile}::${source}`\n if (importLocCache.has(cacheKey)) {\n return importLocCache.get(cacheKey) ?? undefined\n }\n\n try {\n const res = provider.getTransformResult(importerId)\n if (!res) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const { map } = res\n\n const lineIndex =\n res.lineIndex ?? (res.lineIndex = buildLineIndex(res.code))\n\n const idx = findImportSpecifierLocationIndex(res, source)\n if (idx === -1) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const generated = indexToLineColWithIndex(lineIndex, idx)\n const loc = await mapGeneratedToOriginal(map, generated, importerFile)\n importLocCache.set(cacheKey, loc)\n return loc\n } catch {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n}\n\n/**\n * Find the first post-compile usage location for a denied import specifier.\n * Best-effort: searches transformed code for non-import uses of imported\n * bindings and maps back to original source via sourcemap.\n */\nexport async function findPostCompileUsageLocation(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n): Promise<Loc | undefined> {\n try {\n const importerFile = normalizeFilePath(importerId)\n const res = provider.getTransformResult(importerId)\n if (!res) return undefined\n const { code, map } = res\n\n if (!res.lineIndex) {\n res.lineIndex = buildLineIndex(code)\n }\n\n const pos = findPostCompileUsagePosFromResult(res, source)\n if (!pos) return undefined\n\n return await mapGeneratedToOriginal(map, pos, importerFile)\n } catch {\n return undefined\n }\n}\n\n/**\n * Best-effort original-source usage lookup for cases where a later transform\n * removes or rewrites the import from emitted code but preserves the original\n * source in `sourcesContent`.\n */\nexport function findOriginalUsageLocation(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n envType?: 'client' | 'server',\n): Loc | undefined {\n try {\n const importerFile = normalizeFilePath(importerId)\n const res = provider.getTransformResult(importerId)\n if (!res) return undefined\n const originalResult = getOrCreateOriginalTransformResult(res)\n if (!originalResult) return undefined\n\n const pos = envType\n ? findOriginalUnsafeUsagePosFromResult(originalResult, source, envType)\n : findPostCompileUsagePosFromResult(originalResult, source)\n if (!pos) return undefined\n\n return {\n file: importerFile,\n line: pos.line,\n column: pos.column0 + 1,\n }\n } catch {\n return undefined\n }\n}\n\n/**\n * Annotate each trace hop with the location of the import that created the\n * edge (file:line:col). Skips steps that already have a location.\n */\nexport async function addTraceImportLocations(\n provider: TransformResultProvider,\n trace: Array<{\n file: string\n specifier?: string\n line?: number\n column?: number\n }>,\n importLocCache: ImportLocCache,\n findImportSpecifierLocationIndex: FindImportSpecifierLocationIndex,\n): Promise<void> {\n for (const step of trace) {\n if (!step.specifier) continue\n if (step.line != null && step.column != null) continue\n const loc = await findImportStatementLocationFromTransformed(\n provider,\n step.file,\n step.specifier,\n importLocCache,\n findImportSpecifierLocationIndex,\n )\n if (!loc) continue\n step.line = loc.line\n step.column = loc.column\n }\n}\n\n// Code snippet extraction (vitest-style context around a location)\n\nexport interface CodeSnippet {\n /** Source lines with line numbers, e.g. `[\" 6 | import { getSecret } from './secret.server'\", ...]` */\n lines: Array<string>\n /** The highlighted line (1-indexed original line number) */\n highlightLine: number\n /** Clickable file:line reference */\n location: string\n}\n\n/**\n * Build a vitest-style code snippet showing lines surrounding a location.\n *\n * Prefers `originalCode` from the sourcemap's sourcesContent; falls back\n * to transformed code when unavailable.\n */\nexport function buildCodeSnippet(\n provider: TransformResultProvider,\n moduleId: string,\n loc: Loc,\n contextLines: number = 2,\n): CodeSnippet | undefined {\n try {\n const importerFile = normalizeFilePath(moduleId)\n const res = provider.getTransformResult(moduleId)\n if (!res) return undefined\n\n const sourceCode = res.originalCode ?? res.code\n const targetLine = loc.line // 1-indexed\n const targetCol = loc.column // 1-indexed\n\n if (targetLine < 1) return undefined\n\n const allLines = sourceCode.split('\\n')\n // Strip trailing \\r from \\r\\n line endings\n for (let i = 0; i < allLines.length; i++) {\n const line = allLines[i]!\n if (line.endsWith('\\r')) allLines[i] = line.slice(0, -1)\n }\n\n const wantStart = Math.max(1, targetLine - contextLines)\n const wantEnd = Math.min(allLines.length, targetLine + contextLines)\n\n if (targetLine > allLines.length) return undefined\n\n const lines = allLines.slice(wantStart - 1, wantEnd)\n const gutterWidth = String(wantEnd).length\n\n const sourceFile = loc.file ?? importerFile\n const snippetLines: Array<string> = []\n for (let i = 0; i < lines.length; i++) {\n const ln = wantStart + i\n const lineContent = lines[i]!\n const lineNumStr = String(ln).padStart(gutterWidth, ' ')\n const marker = ln === targetLine ? '>' : ' '\n snippetLines.push(` ${marker} ${lineNumStr} | ${lineContent}`)\n\n if (ln === targetLine && targetCol > 0) {\n const padding = ' '.repeat(targetCol - 1)\n snippetLines.push(` ${' '.repeat(gutterWidth)} | ${padding}^`)\n }\n }\n\n return {\n lines: snippetLines,\n highlightLine: targetLine,\n location: `${sourceFile}:${targetLine}:${targetCol}`,\n }\n } catch {\n return undefined\n }\n}\n"],"mappings":"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"}
|
|
@@ -197,10 +197,12 @@ async function buildTransformResultProvider(opts) {
|
|
|
197
197
|
const map = normalizeSourceMap(sourceAndMap.map);
|
|
198
198
|
const file = getModuleFile(module);
|
|
199
199
|
const resource = getModuleResource(module);
|
|
200
|
+
const originalCode = map?.sourcesContent ? pickOriginalCodeFromSourcesContent(map, resource ?? file, opts.root) ?? (resource ? await opts.loadOriginalCode(resource) : void 0) : resource ? await opts.loadOriginalCode(resource) : void 0;
|
|
200
201
|
const result = {
|
|
201
202
|
code,
|
|
203
|
+
filename: resource ?? file,
|
|
202
204
|
map,
|
|
203
|
-
originalCode
|
|
205
|
+
originalCode,
|
|
204
206
|
lineIndex: buildLineIndex(code)
|
|
205
207
|
};
|
|
206
208
|
if (!hasTransformResult(cache, file)) addTransformResult(cache, file, result);
|
|
@@ -334,7 +336,7 @@ async function getMarkerKindForFile(opts) {
|
|
|
334
336
|
cached = (async () => {
|
|
335
337
|
const code = opts.provider.getTransformResult(opts.file)?.originalCode ?? await opts.loadOriginalCode(opts.file);
|
|
336
338
|
if (!code) return;
|
|
337
|
-
const imports = getImportSources(code);
|
|
339
|
+
const imports = getImportSources(code, opts.file);
|
|
338
340
|
const hasServerOnly = imports.some((source) => opts.config.markerSpecifiers.serverOnly.has(source));
|
|
339
341
|
const hasClientOnly = imports.some((source) => opts.config.markerSpecifiers.clientOnly.has(source));
|
|
340
342
|
if (hasServerOnly && !hasClientOnly) return "server";
|
|
@@ -489,14 +491,15 @@ function registerImportProtection(api, opts) {
|
|
|
489
491
|
if (!shouldCheckImportProtectionImporter(config, file)) return ctx.code;
|
|
490
492
|
const matchers = getRulesForEnvironment(config, envName);
|
|
491
493
|
const relativeFile = getImportProtectionRelativePath(config.root, file);
|
|
492
|
-
const importSources = getImportSources(ctx.code);
|
|
494
|
+
const importSources = getImportSources(ctx.code, file);
|
|
493
495
|
const transformedImportSources = new Set(importSources);
|
|
494
496
|
const transformInputFileSystem = shared.inputFileSystems[envName];
|
|
495
497
|
const loadOriginalCodeForTransform = transformInputFileSystem ? (target) => loadOriginalCodeFromInputFileSystem(transformInputFileSystem, target) : () => Promise.resolve(void 0);
|
|
496
498
|
const originalCode = config.command === "build" ? await loadOriginalCode(fileReadCache, file, loadOriginalCodeForTransform) : void 0;
|
|
497
|
-
const buildImportSources = originalCode ? getImportSources(originalCode) : [];
|
|
499
|
+
const buildImportSources = originalCode ? getImportSources(originalCode, file) : [];
|
|
498
500
|
const buildTransformResult = config.command === "build" ? {
|
|
499
501
|
code: ctx.code,
|
|
502
|
+
filename: file,
|
|
500
503
|
map: void 0,
|
|
501
504
|
originalCode,
|
|
502
505
|
lineIndex: buildLineIndex(ctx.code)
|
|
@@ -514,7 +517,7 @@ function registerImportProtection(api, opts) {
|
|
|
514
517
|
if (checkFileDenial(relativeFile, matchers) || envType === "client" && markerKind === "server" || envType === "server" && markerKind === "client") {
|
|
515
518
|
let exportNames = [];
|
|
516
519
|
try {
|
|
517
|
-
exportNames = getNamedExports(ctx.code);
|
|
520
|
+
exportNames = getNamedExports(ctx.code, file);
|
|
518
521
|
} catch {
|
|
519
522
|
exportNames = [];
|
|
520
523
|
}
|
|
@@ -532,7 +535,7 @@ function registerImportProtection(api, opts) {
|
|
|
532
535
|
const deniedSpecifierReplacements = /* @__PURE__ */ new Map();
|
|
533
536
|
const exportsBySource = (() => {
|
|
534
537
|
try {
|
|
535
|
-
return getMockExportNamesBySource(ctx.code);
|
|
538
|
+
return getMockExportNamesBySource(ctx.code, file);
|
|
536
539
|
} catch {
|
|
537
540
|
return /* @__PURE__ */ new Map();
|
|
538
541
|
}
|