@aiready/context-analyzer 0.19.16 → 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 +11 -11
- package/.turbo/turbo-test.log +20 -20
- package/README.md +6 -1
- package/dist/chunk-PVVMK56C.mjs +1793 -0
- package/dist/cli.js +14 -89
- 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 -91
- package/dist/index.mjs +1 -3
- package/package.json +2 -2
- package/src/ast-utils.ts +8 -3
- package/src/graph-builder.ts +15 -111
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,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
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,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-
|
|
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,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
|
*/
|