@aiready/context-analyzer 0.19.15 → 0.19.17
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/.turbo/turbo-build.log +10 -10
- package/.turbo/turbo-test.log +20 -20
- package/README.md +6 -1
- package/dist/chunk-PVVMK56C.mjs +1793 -0
- package/dist/chunk-YYB6NZE3.mjs +1869 -0
- package/dist/cli.js +14 -41
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +1 -5
- package/dist/index.d.ts +1 -5
- package/dist/index.js +14 -43
- package/dist/index.mjs +1 -3
- package/package.json +2 -2
- package/src/ast-utils.ts +8 -3
- package/src/graph-builder.ts +15 -55
package/dist/cli.js
CHANGED
|
@@ -476,6 +476,9 @@ function singularize(word) {
|
|
|
476
476
|
function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
477
477
|
try {
|
|
478
478
|
const { exports: astExports } = (0, import_core.parseFileExports)(content, filePath);
|
|
479
|
+
if (astExports.length === 0 && !isTestFile(filePath)) {
|
|
480
|
+
return extractExports(content, filePath, domainOptions, fileImports);
|
|
481
|
+
}
|
|
479
482
|
return astExports.map((exp) => ({
|
|
480
483
|
name: exp.name,
|
|
481
484
|
type: exp.type,
|
|
@@ -490,7 +493,6 @@ function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
|
490
493
|
typeReferences: exp.typeReferences
|
|
491
494
|
}));
|
|
492
495
|
} catch (error) {
|
|
493
|
-
void error;
|
|
494
496
|
return extractExports(content, filePath, domainOptions, fileImports);
|
|
495
497
|
}
|
|
496
498
|
}
|
|
@@ -661,17 +663,24 @@ function buildDependencyGraph(files, options) {
|
|
|
661
663
|
const edges = /* @__PURE__ */ new Map();
|
|
662
664
|
const autoDetectedKeywords = options?.domainKeywords ?? extractDomainKeywordsFromPaths(files);
|
|
663
665
|
for (const { file, content } of files) {
|
|
664
|
-
const imports =
|
|
666
|
+
const { imports: astImports } = (0, import_core3.parseFileExports)(content, file);
|
|
667
|
+
const importSources = astImports.map((i) => i.source);
|
|
665
668
|
const exports2 = extractExportsWithAST(
|
|
666
669
|
content,
|
|
667
670
|
file,
|
|
668
671
|
{ domainKeywords: autoDetectedKeywords },
|
|
669
|
-
|
|
672
|
+
importSources
|
|
670
673
|
);
|
|
671
674
|
const tokenCost = (0, import_core3.estimateTokens)(content);
|
|
672
675
|
const linesOfCode = content.split("\n").length;
|
|
673
|
-
nodes.set(file, {
|
|
674
|
-
|
|
676
|
+
nodes.set(file, {
|
|
677
|
+
file,
|
|
678
|
+
imports: importSources,
|
|
679
|
+
exports: exports2,
|
|
680
|
+
tokenCost,
|
|
681
|
+
linesOfCode
|
|
682
|
+
});
|
|
683
|
+
edges.set(file, new Set(importSources));
|
|
675
684
|
}
|
|
676
685
|
const graph = { nodes, edges };
|
|
677
686
|
const coUsageMatrix = buildCoUsageMatrix(graph);
|
|
@@ -696,42 +705,6 @@ function buildDependencyGraph(files, options) {
|
|
|
696
705
|
}
|
|
697
706
|
return graph;
|
|
698
707
|
}
|
|
699
|
-
function extractImportsFromContent(content, filePath) {
|
|
700
|
-
const imports = [];
|
|
701
|
-
const isPython = filePath?.toLowerCase().endsWith(".py");
|
|
702
|
-
if (isPython) {
|
|
703
|
-
const pythonPatterns = [
|
|
704
|
-
/^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
|
|
705
|
-
/^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm
|
|
706
|
-
];
|
|
707
|
-
for (const pattern of pythonPatterns) {
|
|
708
|
-
let match;
|
|
709
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
710
|
-
const importPath = match[1];
|
|
711
|
-
if (importPath) {
|
|
712
|
-
const parts = importPath.split(",").map((p) => p.trim().split(/\s+as\s+/)[0]);
|
|
713
|
-
imports.push(...parts);
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
} else {
|
|
718
|
-
const patterns = [
|
|
719
|
-
/import\s+.*?\s+from\s+['"](.+?)['"]/g,
|
|
720
|
-
/import\s+['"](.+?)['"]/g,
|
|
721
|
-
/require\(['"](.+?)['"]\)/g
|
|
722
|
-
];
|
|
723
|
-
for (const pattern of patterns) {
|
|
724
|
-
let match;
|
|
725
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
726
|
-
const importPath = match[1];
|
|
727
|
-
if (importPath && !importPath.startsWith("node:")) {
|
|
728
|
-
imports.push(importPath);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
return [...new Set(imports)];
|
|
734
|
-
}
|
|
735
708
|
function calculateImportDepth(file, graph, visited = /* @__PURE__ */ new Set(), depth = 0) {
|
|
736
709
|
if (visited.has(file)) return depth;
|
|
737
710
|
const dependencies = graph.edges.get(file);
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -142,10 +142,6 @@ declare function extractDomainKeywordsFromPaths(files: FileContent[]): string[];
|
|
|
142
142
|
declare function buildDependencyGraph(files: FileContent[], options?: {
|
|
143
143
|
domainKeywords?: string[];
|
|
144
144
|
}): DependencyGraph;
|
|
145
|
-
/**
|
|
146
|
-
* Extract imports from file content
|
|
147
|
-
*/
|
|
148
|
-
declare function extractImportsFromContent(content: string, filePath?: string): string[];
|
|
149
145
|
/**
|
|
150
146
|
* Calculate the maximum depth of import tree for a file
|
|
151
147
|
*/
|
|
@@ -360,4 +356,4 @@ declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatr
|
|
|
360
356
|
*/
|
|
361
357
|
declare function analyzeContext(options: ContextAnalyzerOptions): Promise<ContextAnalysisResult[]>;
|
|
362
358
|
|
|
363
|
-
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports,
|
|
359
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
package/dist/index.d.ts
CHANGED
|
@@ -142,10 +142,6 @@ declare function extractDomainKeywordsFromPaths(files: FileContent[]): string[];
|
|
|
142
142
|
declare function buildDependencyGraph(files: FileContent[], options?: {
|
|
143
143
|
domainKeywords?: string[];
|
|
144
144
|
}): DependencyGraph;
|
|
145
|
-
/**
|
|
146
|
-
* Extract imports from file content
|
|
147
|
-
*/
|
|
148
|
-
declare function extractImportsFromContent(content: string, filePath?: string): string[];
|
|
149
145
|
/**
|
|
150
146
|
* Calculate the maximum depth of import tree for a file
|
|
151
147
|
*/
|
|
@@ -360,4 +356,4 @@ declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatr
|
|
|
360
356
|
*/
|
|
361
357
|
declare function analyzeContext(options: ContextAnalyzerOptions): Promise<ContextAnalysisResult[]>;
|
|
362
358
|
|
|
363
|
-
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports,
|
|
359
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, ContextAnalyzerProvider, type ContextSummary, type DependencyGraph, type DependencyNode, type DomainAssignment, type DomainSignals, type ExportInfo, type FileClassification, type ModuleCluster, type TypeDependency, adjustCohesionForClassification, adjustFragmentationForClassification, analyzeContext, analyzeIssues, buildCoUsageMatrix, buildDependencyGraph, buildTypeGraph, calculateCohesion, calculateContextBudget, calculateContextScore, calculateDirectoryDistance, calculateDomainConfidence, calculateEnhancedCohesion, calculateFragmentation, calculateImportDepth, calculatePathEntropy, calculateStructuralCohesionFromCoUsage, classifyFile, detectCircularDependencies, detectModuleClusters, extractDomainKeywordsFromPaths, extractExports, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
|
package/dist/index.js
CHANGED
|
@@ -267,7 +267,6 @@ __export(index_exports, {
|
|
|
267
267
|
detectModuleClusters: () => detectModuleClusters,
|
|
268
268
|
extractDomainKeywordsFromPaths: () => extractDomainKeywordsFromPaths,
|
|
269
269
|
extractExports: () => extractExports,
|
|
270
|
-
extractImportsFromContent: () => extractImportsFromContent,
|
|
271
270
|
findConsolidationCandidates: () => findConsolidationCandidates,
|
|
272
271
|
findSemanticClusters: () => findSemanticClusters,
|
|
273
272
|
generateSummary: () => generateSummary,
|
|
@@ -573,6 +572,9 @@ function findConsolidationCandidates(graph, coUsageMatrix, typeGraph, minCoUsage
|
|
|
573
572
|
function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
574
573
|
try {
|
|
575
574
|
const { exports: astExports } = (0, import_core.parseFileExports)(content, filePath);
|
|
575
|
+
if (astExports.length === 0 && !isTestFile(filePath)) {
|
|
576
|
+
return extractExports(content, filePath, domainOptions, fileImports);
|
|
577
|
+
}
|
|
576
578
|
return astExports.map((exp) => ({
|
|
577
579
|
name: exp.name,
|
|
578
580
|
type: exp.type,
|
|
@@ -587,7 +589,6 @@ function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
|
587
589
|
typeReferences: exp.typeReferences
|
|
588
590
|
}));
|
|
589
591
|
} catch (error) {
|
|
590
|
-
void error;
|
|
591
592
|
return extractExports(content, filePath, domainOptions, fileImports);
|
|
592
593
|
}
|
|
593
594
|
}
|
|
@@ -777,17 +778,24 @@ function buildDependencyGraph(files, options) {
|
|
|
777
778
|
const edges = /* @__PURE__ */ new Map();
|
|
778
779
|
const autoDetectedKeywords = options?.domainKeywords ?? extractDomainKeywordsFromPaths(files);
|
|
779
780
|
for (const { file, content } of files) {
|
|
780
|
-
const imports =
|
|
781
|
+
const { imports: astImports } = (0, import_core3.parseFileExports)(content, file);
|
|
782
|
+
const importSources = astImports.map((i) => i.source);
|
|
781
783
|
const exports2 = extractExportsWithAST(
|
|
782
784
|
content,
|
|
783
785
|
file,
|
|
784
786
|
{ domainKeywords: autoDetectedKeywords },
|
|
785
|
-
|
|
787
|
+
importSources
|
|
786
788
|
);
|
|
787
789
|
const tokenCost = (0, import_core3.estimateTokens)(content);
|
|
788
790
|
const linesOfCode = content.split("\n").length;
|
|
789
|
-
nodes.set(file, {
|
|
790
|
-
|
|
791
|
+
nodes.set(file, {
|
|
792
|
+
file,
|
|
793
|
+
imports: importSources,
|
|
794
|
+
exports: exports2,
|
|
795
|
+
tokenCost,
|
|
796
|
+
linesOfCode
|
|
797
|
+
});
|
|
798
|
+
edges.set(file, new Set(importSources));
|
|
791
799
|
}
|
|
792
800
|
const graph = { nodes, edges };
|
|
793
801
|
const coUsageMatrix = buildCoUsageMatrix(graph);
|
|
@@ -812,42 +820,6 @@ function buildDependencyGraph(files, options) {
|
|
|
812
820
|
}
|
|
813
821
|
return graph;
|
|
814
822
|
}
|
|
815
|
-
function extractImportsFromContent(content, filePath) {
|
|
816
|
-
const imports = [];
|
|
817
|
-
const isPython = filePath?.toLowerCase().endsWith(".py");
|
|
818
|
-
if (isPython) {
|
|
819
|
-
const pythonPatterns = [
|
|
820
|
-
/^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
|
|
821
|
-
/^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm
|
|
822
|
-
];
|
|
823
|
-
for (const pattern of pythonPatterns) {
|
|
824
|
-
let match;
|
|
825
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
826
|
-
const importPath = match[1];
|
|
827
|
-
if (importPath) {
|
|
828
|
-
const parts = importPath.split(",").map((p) => p.trim().split(/\s+as\s+/)[0]);
|
|
829
|
-
imports.push(...parts);
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
} else {
|
|
834
|
-
const patterns = [
|
|
835
|
-
/import\s+.*?\s+from\s+['"](.+?)['"]/g,
|
|
836
|
-
/import\s+['"](.+?)['"]/g,
|
|
837
|
-
/require\(['"](.+?)['"]\)/g
|
|
838
|
-
];
|
|
839
|
-
for (const pattern of patterns) {
|
|
840
|
-
let match;
|
|
841
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
842
|
-
const importPath = match[1];
|
|
843
|
-
if (importPath && !importPath.startsWith("node:")) {
|
|
844
|
-
imports.push(importPath);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
return [...new Set(imports)];
|
|
850
|
-
}
|
|
851
823
|
function calculateImportDepth(file, graph, visited = /* @__PURE__ */ new Set(), depth = 0) {
|
|
852
824
|
if (visited.has(file)) return depth;
|
|
853
825
|
const dependencies = graph.edges.get(file);
|
|
@@ -2079,7 +2051,6 @@ async function analyzeContext(options) {
|
|
|
2079
2051
|
detectModuleClusters,
|
|
2080
2052
|
extractDomainKeywordsFromPaths,
|
|
2081
2053
|
extractExports,
|
|
2082
|
-
extractImportsFromContent,
|
|
2083
2054
|
findConsolidationCandidates,
|
|
2084
2055
|
findSemanticClusters,
|
|
2085
2056
|
generateSummary,
|
package/dist/index.mjs
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
detectModuleClusters,
|
|
23
23
|
extractDomainKeywordsFromPaths,
|
|
24
24
|
extractExports,
|
|
25
|
-
extractImportsFromContent,
|
|
26
25
|
findConsolidationCandidates,
|
|
27
26
|
findSemanticClusters,
|
|
28
27
|
generateSummary,
|
|
@@ -44,7 +43,7 @@ import {
|
|
|
44
43
|
isTypeDefinition,
|
|
45
44
|
isUtilityModule,
|
|
46
45
|
mapScoreToRating
|
|
47
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-PVVMK56C.mjs";
|
|
48
47
|
export {
|
|
49
48
|
ContextAnalyzerProvider,
|
|
50
49
|
adjustCohesionForClassification,
|
|
@@ -69,7 +68,6 @@ export {
|
|
|
69
68
|
detectModuleClusters,
|
|
70
69
|
extractDomainKeywordsFromPaths,
|
|
71
70
|
extractExports,
|
|
72
|
-
extractImportsFromContent,
|
|
73
71
|
findConsolidationCandidates,
|
|
74
72
|
findSemanticClusters,
|
|
75
73
|
generateSummary,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiready/context-analyzer",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.17",
|
|
4
4
|
"description": "AI context window cost analysis - detect fragmented code, deep import chains, and expensive context budgets",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"commander": "^14.0.0",
|
|
50
50
|
"chalk": "^5.3.0",
|
|
51
51
|
"prompts": "^2.4.2",
|
|
52
|
-
"@aiready/core": "0.21.
|
|
52
|
+
"@aiready/core": "0.21.17"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^24.0.0",
|
package/src/ast-utils.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ExportInfo, DependencyNode, FileClassification } from './types';
|
|
|
3
3
|
import { inferDomain, extractExports } from './semantic-analysis';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Extract exports using AST parsing
|
|
6
|
+
* Extract exports using high-fidelity AST parsing across 5+ languages
|
|
7
7
|
*/
|
|
8
8
|
export function extractExportsWithAST(
|
|
9
9
|
content: string,
|
|
@@ -14,6 +14,12 @@ export function extractExportsWithAST(
|
|
|
14
14
|
try {
|
|
15
15
|
const { exports: astExports } = parseFileExports(content, filePath);
|
|
16
16
|
|
|
17
|
+
if (astExports.length === 0 && !isTestFile(filePath)) {
|
|
18
|
+
// If AST fails to find anything, we still use regex as a last resort
|
|
19
|
+
// ONLY for unknown file types or very complex macros
|
|
20
|
+
return extractExports(content, filePath, domainOptions, fileImports);
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
return astExports.map((exp) => ({
|
|
18
24
|
name: exp.name,
|
|
19
25
|
type: exp.type as any,
|
|
@@ -28,8 +34,7 @@ export function extractExportsWithAST(
|
|
|
28
34
|
typeReferences: (exp as any).typeReferences,
|
|
29
35
|
}));
|
|
30
36
|
} catch (error) {
|
|
31
|
-
|
|
32
|
-
// Fallback to regex-based extraction
|
|
37
|
+
// Ultimate fallback
|
|
33
38
|
return extractExports(content, filePath, domainOptions, fileImports);
|
|
34
39
|
}
|
|
35
40
|
}
|
package/src/graph-builder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { estimateTokens } from '@aiready/core';
|
|
1
|
+
import { estimateTokens, parseFileExports } from '@aiready/core';
|
|
2
2
|
import type { DependencyGraph, DependencyNode } from './types';
|
|
3
3
|
import {
|
|
4
4
|
buildCoUsageMatrix,
|
|
@@ -89,19 +89,29 @@ export function buildDependencyGraph(
|
|
|
89
89
|
options?.domainKeywords ?? extractDomainKeywordsFromPaths(files);
|
|
90
90
|
|
|
91
91
|
for (const { file, content } of files) {
|
|
92
|
-
|
|
92
|
+
// 1. Get high-fidelity AST-based imports & exports
|
|
93
|
+
const { imports: astImports } = parseFileExports(content, file);
|
|
94
|
+
const importSources = astImports.map((i) => i.source);
|
|
95
|
+
|
|
96
|
+
// 2. Wrap with platform-specific metadata (v0.11+)
|
|
93
97
|
const exports = extractExportsWithAST(
|
|
94
98
|
content,
|
|
95
99
|
file,
|
|
96
100
|
{ domainKeywords: autoDetectedKeywords },
|
|
97
|
-
|
|
101
|
+
importSources
|
|
98
102
|
);
|
|
99
103
|
|
|
100
104
|
const tokenCost = estimateTokens(content);
|
|
101
105
|
const linesOfCode = content.split('\n').length;
|
|
102
106
|
|
|
103
|
-
nodes.set(file, {
|
|
104
|
-
|
|
107
|
+
nodes.set(file, {
|
|
108
|
+
file,
|
|
109
|
+
imports: importSources,
|
|
110
|
+
exports,
|
|
111
|
+
tokenCost,
|
|
112
|
+
linesOfCode,
|
|
113
|
+
});
|
|
114
|
+
edges.set(file, new Set(importSources));
|
|
105
115
|
}
|
|
106
116
|
|
|
107
117
|
const graph: DependencyGraph = { nodes, edges };
|
|
@@ -131,56 +141,6 @@ export function buildDependencyGraph(
|
|
|
131
141
|
return graph;
|
|
132
142
|
}
|
|
133
143
|
|
|
134
|
-
/**
|
|
135
|
-
* Extract imports from file content
|
|
136
|
-
*/
|
|
137
|
-
export function extractImportsFromContent(
|
|
138
|
-
content: string,
|
|
139
|
-
filePath?: string
|
|
140
|
-
): string[] {
|
|
141
|
-
const imports: string[] = [];
|
|
142
|
-
const isPython = filePath?.toLowerCase().endsWith('.py');
|
|
143
|
-
|
|
144
|
-
if (isPython) {
|
|
145
|
-
const pythonPatterns = [
|
|
146
|
-
/^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
|
|
147
|
-
/^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm,
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
for (const pattern of pythonPatterns) {
|
|
151
|
-
let match;
|
|
152
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
153
|
-
const importPath = match[1];
|
|
154
|
-
if (importPath) {
|
|
155
|
-
// Handle multiple imports in one line: import os, sys
|
|
156
|
-
const parts = importPath
|
|
157
|
-
.split(',')
|
|
158
|
-
.map((p) => p.trim().split(/\s+as\s+/)[0]);
|
|
159
|
-
imports.push(...parts);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
} else {
|
|
164
|
-
const patterns = [
|
|
165
|
-
/import\s+.*?\s+from\s+['"](.+?)['"]/g,
|
|
166
|
-
/import\s+['"](.+?)['"]/g,
|
|
167
|
-
/require\(['"](.+?)['"]\)/g,
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
for (const pattern of patterns) {
|
|
171
|
-
let match;
|
|
172
|
-
while ((match = pattern.exec(content)) !== null) {
|
|
173
|
-
const importPath = match[1];
|
|
174
|
-
if (importPath && !importPath.startsWith('node:')) {
|
|
175
|
-
imports.push(importPath);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return [...new Set(imports)];
|
|
182
|
-
}
|
|
183
|
-
|
|
184
144
|
/**
|
|
185
145
|
* Calculate the maximum depth of import tree for a file
|
|
186
146
|
*/
|