@aiready/context-analyzer 0.19.16 → 0.19.18

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/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 = extractImportsFromContent(content, file);
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
- imports
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, { file, imports, exports: exports2, tokenCost, linesOfCode });
674
- edges.set(file, new Set(imports));
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,90 +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
- const isJava = filePath?.toLowerCase().endsWith(".java");
703
- const isCSharp = filePath?.toLowerCase().endsWith(".cs");
704
- const isGo = filePath?.toLowerCase().endsWith(".go");
705
- if (isPython) {
706
- const pythonPatterns = [
707
- /^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
708
- /^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm
709
- ];
710
- for (const pattern of pythonPatterns) {
711
- let match;
712
- while ((match = pattern.exec(content)) !== null) {
713
- const importPath = match[1];
714
- if (importPath) {
715
- const parts = importPath.split(",").map((p) => p.trim().split(/\s+as\s+/)[0]);
716
- imports.push(...parts);
717
- }
718
- }
719
- }
720
- } else if (isJava) {
721
- const javaPatterns = [/^\s*import\s+(?:static\s+)?([a-zA-Z0-9_.]+)/gm];
722
- for (const pattern of javaPatterns) {
723
- let match;
724
- while ((match = pattern.exec(content)) !== null) {
725
- const importPath = match[1];
726
- if (importPath) {
727
- const cleanPath = importPath.endsWith(".*") ? importPath.slice(0, -2) : importPath;
728
- imports.push(cleanPath);
729
- }
730
- }
731
- }
732
- } else if (isCSharp) {
733
- const csharpPatterns = [
734
- /^\s*using\s+(?:static\s+)?(?:[a-zA-Z0-9_.]+\s*=\s*)?([a-zA-Z0-9_.]+);/gm
735
- ];
736
- for (const pattern of csharpPatterns) {
737
- let match;
738
- while ((match = pattern.exec(content)) !== null) {
739
- const importPath = match[1];
740
- if (importPath) {
741
- imports.push(importPath);
742
- }
743
- }
744
- }
745
- } else if (isGo) {
746
- const goPatterns = [
747
- /^\s*import\s+"([^"]+)"/gm,
748
- /^\s*import\s+\(\s*([^)]+)\)/gm
749
- ];
750
- for (const pattern of goPatterns) {
751
- let match;
752
- while ((match = pattern.exec(content)) !== null) {
753
- if (pattern.source.includes("\\(")) {
754
- const block = match[1];
755
- const lines = block.split("\n");
756
- for (const line of lines) {
757
- const lineMatch = /"([^"]+)"/.exec(line);
758
- if (lineMatch) imports.push(lineMatch[1]);
759
- }
760
- } else {
761
- if (match[1]) imports.push(match[1]);
762
- }
763
- }
764
- }
765
- } else {
766
- const patterns = [
767
- /import\s+.*?\s+from\s+['"](.+?)['"]/g,
768
- /import\s+['"](.+?)['"]/g,
769
- /require\(['"](.+?)['"]\)/g
770
- ];
771
- for (const pattern of patterns) {
772
- let match;
773
- while ((match = pattern.exec(content)) !== null) {
774
- const importPath = match[1];
775
- if (importPath && !importPath.startsWith("node:")) {
776
- imports.push(importPath);
777
- }
778
- }
779
- }
780
- }
781
- return [...new Set(imports)];
782
- }
783
708
  function calculateImportDepth(file, graph, visited = /* @__PURE__ */ new Set(), depth = 0) {
784
709
  if (visited.has(file)) return depth;
785
710
  const dependencies = graph.edges.get(file);
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  analyzeContext,
4
4
  generateSummary
5
- } from "./chunk-YYB6NZE3.mjs";
5
+ } from "./chunk-PVVMK56C.mjs";
6
6
 
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
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, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
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, extractImportsFromContent, findConsolidationCandidates, findSemanticClusters, generateSummary, getClassificationRecommendations, getCoUsageData, getGeneralRecommendations, getSmartDefaults, getTransitiveDependencies, inferDomain, inferDomainFromSemantics, isBarrelExport, isConfigFile, isEmailTemplate, isLambdaHandler, isNextJsPage, isParserFile, isServiceFile, isSessionFile, isTypeDefinition, isUtilityModule, mapScoreToRating };
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 = extractImportsFromContent(content, file);
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
- imports
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, { file, imports, exports: exports2, tokenCost, linesOfCode });
790
- edges.set(file, new Set(imports));
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,90 +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
- const isJava = filePath?.toLowerCase().endsWith(".java");
819
- const isCSharp = filePath?.toLowerCase().endsWith(".cs");
820
- const isGo = filePath?.toLowerCase().endsWith(".go");
821
- if (isPython) {
822
- const pythonPatterns = [
823
- /^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
824
- /^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm
825
- ];
826
- for (const pattern of pythonPatterns) {
827
- let match;
828
- while ((match = pattern.exec(content)) !== null) {
829
- const importPath = match[1];
830
- if (importPath) {
831
- const parts = importPath.split(",").map((p) => p.trim().split(/\s+as\s+/)[0]);
832
- imports.push(...parts);
833
- }
834
- }
835
- }
836
- } else if (isJava) {
837
- const javaPatterns = [/^\s*import\s+(?:static\s+)?([a-zA-Z0-9_.]+)/gm];
838
- for (const pattern of javaPatterns) {
839
- let match;
840
- while ((match = pattern.exec(content)) !== null) {
841
- const importPath = match[1];
842
- if (importPath) {
843
- const cleanPath = importPath.endsWith(".*") ? importPath.slice(0, -2) : importPath;
844
- imports.push(cleanPath);
845
- }
846
- }
847
- }
848
- } else if (isCSharp) {
849
- const csharpPatterns = [
850
- /^\s*using\s+(?:static\s+)?(?:[a-zA-Z0-9_.]+\s*=\s*)?([a-zA-Z0-9_.]+);/gm
851
- ];
852
- for (const pattern of csharpPatterns) {
853
- let match;
854
- while ((match = pattern.exec(content)) !== null) {
855
- const importPath = match[1];
856
- if (importPath) {
857
- imports.push(importPath);
858
- }
859
- }
860
- }
861
- } else if (isGo) {
862
- const goPatterns = [
863
- /^\s*import\s+"([^"]+)"/gm,
864
- /^\s*import\s+\(\s*([^)]+)\)/gm
865
- ];
866
- for (const pattern of goPatterns) {
867
- let match;
868
- while ((match = pattern.exec(content)) !== null) {
869
- if (pattern.source.includes("\\(")) {
870
- const block = match[1];
871
- const lines = block.split("\n");
872
- for (const line of lines) {
873
- const lineMatch = /"([^"]+)"/.exec(line);
874
- if (lineMatch) imports.push(lineMatch[1]);
875
- }
876
- } else {
877
- if (match[1]) imports.push(match[1]);
878
- }
879
- }
880
- }
881
- } else {
882
- const patterns = [
883
- /import\s+.*?\s+from\s+['"](.+?)['"]/g,
884
- /import\s+['"](.+?)['"]/g,
885
- /require\(['"](.+?)['"]\)/g
886
- ];
887
- for (const pattern of patterns) {
888
- let match;
889
- while ((match = pattern.exec(content)) !== null) {
890
- const importPath = match[1];
891
- if (importPath && !importPath.startsWith("node:")) {
892
- imports.push(importPath);
893
- }
894
- }
895
- }
896
- }
897
- return [...new Set(imports)];
898
- }
899
823
  function calculateImportDepth(file, graph, visited = /* @__PURE__ */ new Set(), depth = 0) {
900
824
  if (visited.has(file)) return depth;
901
825
  const dependencies = graph.edges.get(file);
@@ -2127,7 +2051,6 @@ async function analyzeContext(options) {
2127
2051
  detectModuleClusters,
2128
2052
  extractDomainKeywordsFromPaths,
2129
2053
  extractExports,
2130
- extractImportsFromContent,
2131
2054
  findConsolidationCandidates,
2132
2055
  findSemanticClusters,
2133
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-YYB6NZE3.mjs";
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.16",
3
+ "version": "0.19.18",
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.16"
52
+ "@aiready/core": "0.21.18"
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 with fallback to regex
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
- void error;
32
- // Fallback to regex-based extraction
37
+ // Ultimate fallback
33
38
  return extractExports(content, filePath, domainOptions, fileImports);
34
39
  }
35
40
  }
@@ -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
- const imports = extractImportsFromContent(content, file);
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
- imports
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, { file, imports, exports, tokenCost, linesOfCode });
104
- edges.set(file, new Set(imports));
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,112 +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
- const isJava = filePath?.toLowerCase().endsWith('.java');
144
- const isCSharp = filePath?.toLowerCase().endsWith('.cs');
145
- const isGo = filePath?.toLowerCase().endsWith('.go');
146
-
147
- if (isPython) {
148
- const pythonPatterns = [
149
- /^\s*import\s+([a-zA-Z0-9_., ]+)/gm,
150
- /^\s*from\s+([a-zA-Z0-9_.]+)\s+import/gm,
151
- ];
152
-
153
- for (const pattern of pythonPatterns) {
154
- let match;
155
- while ((match = pattern.exec(content)) !== null) {
156
- const importPath = match[1];
157
- if (importPath) {
158
- // Handle multiple imports in one line: import os, sys
159
- const parts = importPath
160
- .split(',')
161
- .map((p) => p.trim().split(/\s+as\s+/)[0]);
162
- imports.push(...parts);
163
- }
164
- }
165
- }
166
- } else if (isJava) {
167
- const javaPatterns = [/^\s*import\s+(?:static\s+)?([a-zA-Z0-9_.]+)/gm];
168
-
169
- for (const pattern of javaPatterns) {
170
- let match;
171
- while ((match = pattern.exec(content)) !== null) {
172
- const importPath = match[1];
173
- if (importPath) {
174
- // Handle wildcard imports: import java.util.*; -> java.util
175
- const cleanPath = importPath.endsWith('.*')
176
- ? importPath.slice(0, -2)
177
- : importPath;
178
- imports.push(cleanPath);
179
- }
180
- }
181
- }
182
- } else if (isCSharp) {
183
- const csharpPatterns = [
184
- /^\s*using\s+(?:static\s+)?(?:[a-zA-Z0-9_.]+\s*=\s*)?([a-zA-Z0-9_.]+);/gm,
185
- ];
186
-
187
- for (const pattern of csharpPatterns) {
188
- let match;
189
- while ((match = pattern.exec(content)) !== null) {
190
- const importPath = match[1];
191
- if (importPath) {
192
- imports.push(importPath);
193
- }
194
- }
195
- }
196
- } else if (isGo) {
197
- const goPatterns = [
198
- /^\s*import\s+"([^"]+)"/gm,
199
- /^\s*import\s+\(\s*([^)]+)\)/gm,
200
- ];
201
-
202
- for (const pattern of goPatterns) {
203
- let match;
204
- while ((match = pattern.exec(content)) !== null) {
205
- if (pattern.source.includes('\\(')) {
206
- // Block import
207
- const block = match[1];
208
- const lines = block.split('\n');
209
- for (const line of lines) {
210
- const lineMatch = /"([^"]+)"/.exec(line);
211
- if (lineMatch) imports.push(lineMatch[1]);
212
- }
213
- } else {
214
- // Single import
215
- if (match[1]) imports.push(match[1]);
216
- }
217
- }
218
- }
219
- } else {
220
- const patterns = [
221
- /import\s+.*?\s+from\s+['"](.+?)['"]/g,
222
- /import\s+['"](.+?)['"]/g,
223
- /require\(['"](.+?)['"]\)/g,
224
- ];
225
-
226
- for (const pattern of patterns) {
227
- let match;
228
- while ((match = pattern.exec(content)) !== null) {
229
- const importPath = match[1];
230
- if (importPath && !importPath.startsWith('node:')) {
231
- imports.push(importPath);
232
- }
233
- }
234
- }
235
- }
236
-
237
- return [...new Set(imports)];
238
- }
239
-
240
144
  /**
241
145
  * Calculate the maximum depth of import tree for a file
242
146
  */