






















@@ -13,10 +13,8 @@ import {
1313diffInventoryEntries,
1414normalizeRepoPath,
1515resolveRepoSpecifier,
16-visitModuleSpecifiers,
1716writeLine,
1817} from "./lib/guard-inventory-utils.mjs";
19-import { toLine } from "./lib/ts-guard-utils.mjs";
20182119const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
2220const extensionsRoot = path.join(repoRoot, BUNDLED_PLUGIN_ROOT_DIR);
@@ -49,7 +47,7 @@ const baselinePathByMode = {
4947};
50485149let allInventoryByModePromise;
52-let parsedExtensionSourceFilesPromise;
50+let extensionModuleReferencesPromise;
53515452const ruleTextByMode = {
5553"src-outside-plugin-sdk":
@@ -97,36 +95,26 @@ async function collectExtensionSourceFiles(rootDir) {
9795);
9896}
9997100-async function collectParsedExtensionSourceFiles() {
101-if (!parsedExtensionSourceFilesPromise) {
102-parsedExtensionSourceFilesPromise = (async () => {
98+async function collectExtensionModuleReferences() {
99+if (!extensionModuleReferencesPromise) {
100+extensionModuleReferencesPromise = (async () => {
103101const files = await collectExtensionSourceFiles(extensionsRoot);
104-const parsed = await Promise.all(
102+const referenced = await Promise.all(
105103files.map(async (filePath) => {
106104const source = await fs.readFile(filePath, "utf8");
107105if (!mayContainModuleSpecifier(source)) {
108106return null;
109107}
110-const scriptKind =
111-filePath.endsWith(".tsx") || filePath.endsWith(".jsx")
112- ? ts.ScriptKind.TSX
113- : ts.ScriptKind.TS;
114108return {
115109 filePath,
116-sourceFile: ts.createSourceFile(
117-filePath,
118-source,
119-ts.ScriptTarget.Latest,
120-true,
121-scriptKind,
122-),
110+references: collectModuleReferences(source),
123111};
124112}),
125113);
126-return parsed.filter(Boolean);
114+return referenced.filter((entry) => entry && entry.references.length > 0);
127115})();
128116}
129-return await parsedExtensionSourceFilesPromise;
117+return await extensionModuleReferencesPromise;
130118}
131119132120function mayContainModuleSpecifier(source) {
@@ -137,6 +125,49 @@ function mayContainModuleSpecifier(source) {
137125);
138126}
139127128+function collectModuleReferences(source) {
129+const lineStarts = computeLineStarts(source);
130+return ts.preProcessFile(source, true, true).importedFiles.map((reference) => ({
131+kind: inferModuleReferenceKind(source, reference.pos),
132+line: lineFromPosition(lineStarts, reference.pos),
133+specifier: reference.fileName,
134+}));
135+}
136+137+function computeLineStarts(source) {
138+const lineStarts = [0];
139+for (let index = 0; index < source.length; index += 1) {
140+if (source.charCodeAt(index) === 10) {
141+lineStarts.push(index + 1);
142+}
143+}
144+return lineStarts;
145+}
146+147+function lineFromPosition(lineStarts, position) {
148+let low = 0;
149+let high = lineStarts.length - 1;
150+while (low <= high) {
151+const middle = Math.floor((low + high) / 2);
152+if (lineStarts[middle] <= position) {
153+low = middle + 1;
154+} else {
155+high = middle - 1;
156+}
157+}
158+return high + 1;
159+}
160+161+function inferModuleReferenceKind(source, specifierStart) {
162+const importIndex = source.lastIndexOf("import", specifierStart);
163+const exportIndex = source.lastIndexOf("export", specifierStart);
164+if (exportIndex > importIndex) {
165+return "export";
166+}
167+const importPrefix = source.slice(importIndex, specifierStart);
168+return /\bimport\s*\(\s*["']?$/.test(importPrefix) ? "dynamic-import" : "import";
169+}
170+140171function resolveExtensionRoot(filePath) {
141172const relativePath = normalizeRepoPath(repoRoot, filePath);
142173const segments = relativePath.split("/");
@@ -198,7 +229,7 @@ function shouldReport(mode, resolvedPath) {
198229return !resolvedPath.startsWith("src/plugin-sdk/");
199230}
200231201-function collectEntriesByModeFromSourceFile(sourceFile, filePath) {
232+function collectEntriesByModeFromModuleReferences(filePath, references) {
202233const entriesByMode = {
203234"src-outside-plugin-sdk": [],
204235"plugin-sdk-internal": [],
@@ -207,11 +238,11 @@ function collectEntriesByModeFromSourceFile(sourceFile, filePath) {
207238const extensionRoot = resolveExtensionRoot(filePath);
208239const relativeFile = normalizeRepoPath(repoRoot, filePath);
209240210-function push(kind, specifierNode, specifier) {
241+function push(kind, line, specifier) {
211242const resolvedPath = resolveRepoSpecifier(repoRoot, specifier, filePath);
212243const baseEntry = {
213244file: relativeFile,
214-line: toLine(sourceFile, specifierNode),
245+ line,
215246 kind,
216247 specifier,
217248 resolvedPath,
@@ -237,9 +268,9 @@ function collectEntriesByModeFromSourceFile(sourceFile, filePath) {
237268}
238269}
239270240-visitModuleSpecifiers(ts, sourceFile, ({ kind, specifier, specifierNode }) => {
241-push(kind, specifierNode, specifier);
242-});
271+for (const { kind, line, specifier } of references) {
272+push(kind, line, specifier);
273+}
243274return entriesByMode;
244275}
245276@@ -249,14 +280,14 @@ export async function collectExtensionPluginSdkBoundaryInventory(mode) {
249280}
250281if (!allInventoryByModePromise) {
251282allInventoryByModePromise = (async () => {
252-const files = await collectParsedExtensionSourceFiles();
283+const files = await collectExtensionModuleReferences();
253284const inventoryByMode = {
254285"src-outside-plugin-sdk": [],
255286"plugin-sdk-internal": [],
256287"relative-outside-package": [],
257288};
258-for (const { filePath, sourceFile } of files) {
259-const entriesByMode = collectEntriesByModeFromSourceFile(sourceFile, filePath);
289+for (const { filePath, references } of files) {
290+const entriesByMode = collectEntriesByModeFromModuleReferences(filePath, references);
260291for (const inventoryMode of MODES) {
261292inventoryByMode[inventoryMode].push(...entriesByMode[inventoryMode]);
262293}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。