@aiready/context-analyzer 0.9.4 → 0.9.5

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.
Files changed (75) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/.turbo/turbo-test.log +21 -9
  3. package/README.md +8 -0
  4. package/dist/__tests__/analyzer.test.d.ts +2 -0
  5. package/dist/__tests__/analyzer.test.d.ts.map +1 -0
  6. package/dist/__tests__/analyzer.test.js +157 -0
  7. package/dist/__tests__/analyzer.test.js.map +1 -0
  8. package/dist/__tests__/auto-detection.test.d.ts +2 -0
  9. package/dist/__tests__/auto-detection.test.d.ts.map +1 -0
  10. package/dist/__tests__/auto-detection.test.js +132 -0
  11. package/dist/__tests__/auto-detection.test.js.map +1 -0
  12. package/dist/__tests__/enhanced-cohesion.test.d.ts +2 -0
  13. package/dist/__tests__/enhanced-cohesion.test.d.ts.map +1 -0
  14. package/dist/__tests__/enhanced-cohesion.test.js +109 -0
  15. package/dist/__tests__/enhanced-cohesion.test.js.map +1 -0
  16. package/dist/__tests__/fragmentation-advanced.test.d.ts +2 -0
  17. package/dist/__tests__/fragmentation-advanced.test.d.ts.map +1 -0
  18. package/dist/__tests__/fragmentation-advanced.test.js +50 -0
  19. package/dist/__tests__/fragmentation-advanced.test.js.map +1 -0
  20. package/dist/__tests__/fragmentation-coupling.test.d.ts +2 -0
  21. package/dist/__tests__/fragmentation-coupling.test.d.ts.map +1 -0
  22. package/dist/__tests__/fragmentation-coupling.test.js +52 -0
  23. package/dist/__tests__/fragmentation-coupling.test.js.map +1 -0
  24. package/dist/__tests__/fragmentation-log.test.d.ts +2 -0
  25. package/dist/__tests__/fragmentation-log.test.d.ts.map +1 -0
  26. package/dist/__tests__/fragmentation-log.test.js +33 -0
  27. package/dist/__tests__/fragmentation-log.test.js.map +1 -0
  28. package/dist/__tests__/scoring.test.d.ts +2 -0
  29. package/dist/__tests__/scoring.test.d.ts.map +1 -0
  30. package/dist/__tests__/scoring.test.js +118 -0
  31. package/dist/__tests__/scoring.test.js.map +1 -0
  32. package/dist/__tests__/structural-cohesion.test.d.ts +2 -0
  33. package/dist/__tests__/structural-cohesion.test.d.ts.map +1 -0
  34. package/dist/__tests__/structural-cohesion.test.js +29 -0
  35. package/dist/__tests__/structural-cohesion.test.js.map +1 -0
  36. package/dist/analyzer.d.ts +100 -0
  37. package/dist/analyzer.d.ts.map +1 -0
  38. package/dist/analyzer.js +701 -0
  39. package/dist/analyzer.js.map +1 -0
  40. package/dist/analyzers/python-context.d.ts +38 -0
  41. package/dist/analyzers/python-context.d.ts.map +1 -0
  42. package/dist/analyzers/python-context.js +232 -0
  43. package/dist/analyzers/python-context.js.map +1 -0
  44. package/dist/chunk-BD4NWUVG.mjs +1242 -0
  45. package/dist/cli.d.ts.map +1 -0
  46. package/dist/cli.js +139 -13
  47. package/dist/cli.js.map +1 -0
  48. package/dist/cli.mjs +1 -1
  49. package/dist/index.d.mts +3 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +139 -13
  53. package/dist/index.js.map +1 -0
  54. package/dist/index.mjs +1 -1
  55. package/dist/scoring.d.ts +13 -0
  56. package/dist/scoring.d.ts.map +1 -0
  57. package/dist/scoring.js +133 -0
  58. package/dist/scoring.js.map +1 -0
  59. package/dist/semantic-analysis.d.ts +44 -0
  60. package/dist/semantic-analysis.d.ts.map +1 -0
  61. package/dist/semantic-analysis.js +241 -0
  62. package/dist/semantic-analysis.js.map +1 -0
  63. package/dist/types.d.ts +117 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +2 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +2 -2
  68. package/src/__tests__/fragmentation-advanced.test.ts +60 -0
  69. package/src/__tests__/fragmentation-coupling.test.ts +62 -0
  70. package/src/__tests__/fragmentation-log.test.ts +38 -0
  71. package/src/__tests__/structural-cohesion.test.ts +32 -0
  72. package/src/analyzer.ts +193 -18
  73. package/src/index.ts +34 -2
  74. package/src/types.ts +3 -0
  75. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,52 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildDependencyGraph, detectModuleClusters, calculateFragmentation, } from '../analyzer';
3
+ describe('fragmentation coupling discount', () => {
4
+ it('does not apply discount when files have no shared imports', () => {
5
+ const files = [
6
+ {
7
+ file: 'src/billing/a.ts',
8
+ content: `export const getBillingA = 1;`,
9
+ },
10
+ {
11
+ file: 'src/api/billing/b.ts',
12
+ content: `export const getBillingB = 2;`,
13
+ },
14
+ {
15
+ file: 'lib/billing/c.ts',
16
+ content: `export const getBillingC = 3;`,
17
+ },
18
+ ];
19
+ const graph = buildDependencyGraph(files);
20
+ const clusters = detectModuleClusters(graph);
21
+ const cluster = clusters.find((c) => c.domain === 'billing');
22
+ expect(cluster).toBeDefined();
23
+ const base = calculateFragmentation(files.map(f => f.file), 'billing');
24
+ // With no import similarity the coupling discount should be 0 -> fragmentation unchanged
25
+ expect(cluster.fragmentationScore).toBeCloseTo(base, 6);
26
+ });
27
+ it('applies up-to-20% discount when files share identical imports', () => {
28
+ const files = [
29
+ {
30
+ file: 'src/billing/a.ts',
31
+ content: `import { shared } from 'shared/module';\nexport const getBillingA = 1;`,
32
+ },
33
+ {
34
+ file: 'src/api/billing/b.ts',
35
+ content: `import { shared } from 'shared/module';\nexport const getBillingB = 2;`,
36
+ },
37
+ {
38
+ file: 'lib/billing/c.ts',
39
+ content: `import { shared } from 'shared/module';\nexport const getBillingC = 3;`,
40
+ },
41
+ ];
42
+ const graph = buildDependencyGraph(files);
43
+ const clusters = detectModuleClusters(graph);
44
+ const cluster = clusters.find((c) => c.domain === 'billing');
45
+ expect(cluster).toBeDefined();
46
+ const base = calculateFragmentation(files.map(f => f.file), 'billing');
47
+ const expected = base * 0.8; // full cohesion => 20% discount
48
+ // Allow small FP tolerance
49
+ expect(cluster.fragmentationScore).toBeCloseTo(expected, 6);
50
+ });
51
+ });
52
+ //# sourceMappingURL=fragmentation-coupling.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragmentation-coupling.test.js","sourceRoot":"","sources":["../../src/__tests__/fragmentation-coupling.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,KAAK,GAAG;YACZ;gBACE,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,+BAA+B;aACzC;YACD;gBACE,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,+BAA+B;aACzC;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,+BAA+B;aACzC;SACF,CAAC;QAEF,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC7D,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QAE9B,MAAM,IAAI,GAAG,sBAAsB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;QACvE,yFAAyF;QACzF,MAAM,CAAC,OAAQ,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,KAAK,GAAG;YACZ;gBACE,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,wEAAwE;aAClF;YACD;gBACE,IAAI,EAAE,sBAAsB;gBAC5B,OAAO,EAAE,wEAAwE;aAClF;YACD;gBACE,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,wEAAwE;aAClF;SACF,CAAC;QAEF,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAC7D,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QAE9B,MAAM,IAAI,GAAG,sBAAsB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC,gCAAgC;QAE7D,2BAA2B;QAC3B,MAAM,CAAC,OAAQ,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fragmentation-log.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragmentation-log.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fragmentation-log.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateFragmentation } from '../analyzer';
3
+ describe('calculateFragmentation (log scale option)', () => {
4
+ it('returns 0 for single file regardless of option', () => {
5
+ const files = ['src/user/user.ts'];
6
+ expect(calculateFragmentation(files, 'user')).toBe(0);
7
+ expect(calculateFragmentation(files, 'user', { useLogScale: true })).toBe(0);
8
+ });
9
+ it('matches linear formula when not using log scale', () => {
10
+ const files = [
11
+ 'a/one.ts',
12
+ 'b/two.ts',
13
+ 'c/three.ts',
14
+ 'd/four.ts',
15
+ ];
16
+ const uniqueDirs = 4;
17
+ const linear = (uniqueDirs - 1) / (files.length - 1);
18
+ expect(calculateFragmentation(files, 'domain')).toBeCloseTo(linear);
19
+ });
20
+ it('computes normalized log-based fragmentation when requested', () => {
21
+ const files = [
22
+ 'src/group/a.ts',
23
+ 'src/group/b.ts',
24
+ 'src/group/c.ts',
25
+ 'lib/other/d.ts',
26
+ 'tools/x/e.ts',
27
+ ];
28
+ const dirs = new Set(files.map((f) => f.split('/').slice(0, -1).join('/'))).size;
29
+ const expected = Math.log(dirs) / Math.log(files.length);
30
+ expect(calculateFragmentation(files, 'domain', { useLogScale: true })).toBeCloseTo(expected, 6);
31
+ });
32
+ });
33
+ //# sourceMappingURL=fragmentation-log.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragmentation-log.test.js","sourceRoot":"","sources":["../../src/__tests__/fragmentation-log.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAErD,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;IACzD,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,KAAK,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACnC,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG;YACZ,UAAU;YACV,UAAU;YACV,YAAY;YACZ,WAAW;SACZ,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,CAAC;QACrB,MAAM,MAAM,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,KAAK,GAAG;YACZ,gBAAgB;YAChB,gBAAgB;YAChB,gBAAgB;YAChB,gBAAgB;YAChB,cAAc;SACf,CAAC;QAEF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACjF,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAEzD,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scoring.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/scoring.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,118 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateContextScore } from '../scoring';
3
+ describe('Context Scoring', () => {
4
+ describe('calculateContextScore', () => {
5
+ it('should return perfect score for ideal metrics', () => {
6
+ const summary = {
7
+ avgContextBudget: 3000, // < 5000
8
+ maxContextBudget: 4000,
9
+ avgImportDepth: 3, // < 5
10
+ maxImportDepth: 4,
11
+ avgFragmentation: 0.2, // < 0.3
12
+ criticalIssues: 0,
13
+ majorIssues: 0,
14
+ minorIssues: 0,
15
+ };
16
+ const result = calculateContextScore(summary);
17
+ expect(result.score).toBeGreaterThanOrEqual(90);
18
+ expect(result.toolName).toBe('context-analyzer');
19
+ expect(result.recommendations).toHaveLength(0);
20
+ });
21
+ it('should penalize high context budget', () => {
22
+ const summary = {
23
+ avgContextBudget: 15000, // High
24
+ maxContextBudget: 20000,
25
+ avgImportDepth: 3,
26
+ maxImportDepth: 5,
27
+ avgFragmentation: 0.2,
28
+ criticalIssues: 0,
29
+ majorIssues: 0,
30
+ minorIssues: 0,
31
+ };
32
+ const result = calculateContextScore(summary);
33
+ expect(result.score).toBeLessThan(70);
34
+ expect(result.factors.some(f => f.name === 'Context Budget')).toBe(true);
35
+ expect(result.recommendations.length).toBeGreaterThan(0);
36
+ });
37
+ it('should penalize deep import chains', () => {
38
+ const summary = {
39
+ avgContextBudget: 4000,
40
+ maxContextBudget: 5000,
41
+ avgImportDepth: 12, // Deep
42
+ maxImportDepth: 15,
43
+ avgFragmentation: 0.2,
44
+ criticalIssues: 0,
45
+ majorIssues: 0,
46
+ minorIssues: 0,
47
+ };
48
+ const result = calculateContextScore(summary);
49
+ // With depth=12: depthScore=30, rawScore=(100*0.4)+(30*0.3)+(100*0.3)=79
50
+ expect(result.score).toBe(79);
51
+ expect(result.factors.some(f => f.name === 'Import Depth')).toBe(true);
52
+ expect(result.recommendations.some(r => r.action.includes('import chains'))).toBe(true);
53
+ });
54
+ it('should penalize high fragmentation', () => {
55
+ const summary = {
56
+ avgContextBudget: 4000,
57
+ maxContextBudget: 5000,
58
+ avgImportDepth: 3,
59
+ maxImportDepth: 5,
60
+ avgFragmentation: 0.7, // High fragmentation
61
+ criticalIssues: 0,
62
+ majorIssues: 0,
63
+ minorIssues: 0,
64
+ };
65
+ const result = calculateContextScore(summary);
66
+ expect(result.score).toBeLessThan(80); // Adjusted threshold
67
+ expect(result.factors.some(f => f.name === 'Fragmentation')).toBe(true);
68
+ });
69
+ it('should apply critical issue penalties', () => {
70
+ const summary = {
71
+ avgContextBudget: 4000,
72
+ maxContextBudget: 5000,
73
+ avgImportDepth: 3,
74
+ maxImportDepth: 5,
75
+ avgFragmentation: 0.2,
76
+ criticalIssues: 5, // Critical issues present
77
+ majorIssues: 0,
78
+ minorIssues: 0,
79
+ };
80
+ const result = calculateContextScore(summary);
81
+ // Perfect subscores=100, minus 5*10=50 critical penalty = 50
82
+ expect(result.score).toBe(50);
83
+ expect(result.factors.some(f => f.name === 'Critical Issues')).toBe(true);
84
+ });
85
+ it('should handle extreme max budget penalty', () => {
86
+ const summary = {
87
+ avgContextBudget: 4000,
88
+ maxContextBudget: 25000, // Extreme single file
89
+ avgImportDepth: 3,
90
+ maxImportDepth: 5,
91
+ avgFragmentation: 0.2,
92
+ criticalIssues: 0,
93
+ majorIssues: 0,
94
+ minorIssues: 0,
95
+ };
96
+ const result = calculateContextScore(summary);
97
+ expect(result.factors.some(f => f.name === 'Extreme File Detected')).toBe(true);
98
+ expect(result.recommendations.some(r => r.action.includes('Split large file'))).toBe(true);
99
+ });
100
+ it('should combine multiple penalties correctly', () => {
101
+ const summary = {
102
+ avgContextBudget: 12000, // High
103
+ maxContextBudget: 15000,
104
+ avgImportDepth: 10, // Deep
105
+ maxImportDepth: 12,
106
+ avgFragmentation: 0.6, // High
107
+ criticalIssues: 2,
108
+ majorIssues: 5,
109
+ minorIssues: 10,
110
+ };
111
+ const result = calculateContextScore(summary);
112
+ expect(result.score).toBeLessThan(40);
113
+ expect(result.factors.length).toBeGreaterThan(3);
114
+ expect(result.recommendations.length).toBeGreaterThan(0);
115
+ });
116
+ });
117
+ });
118
+ //# sourceMappingURL=scoring.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.test.js","sourceRoot":"","sources":["../../src/__tests__/scoring.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=structural-cohesion.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-cohesion.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/structural-cohesion.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateStructuralCohesionFromCoUsage } from '../analyzer';
3
+ describe('calculateStructuralCohesionFromCoUsage', () => {
4
+ it('returns 1 when no co-usage data present', () => {
5
+ const score = calculateStructuralCohesionFromCoUsage('missing', undefined);
6
+ expect(score).toBe(1);
7
+ });
8
+ it('returns 1 when co-usage only with a single file', () => {
9
+ const coUsage = new Map();
10
+ coUsage.set('a', new Map([['b', 10]]));
11
+ const score = calculateStructuralCohesionFromCoUsage('a', coUsage);
12
+ expect(score).toBe(1);
13
+ });
14
+ it('returns ~0 when co-usage is perfectly balanced across two files', () => {
15
+ const coUsage = new Map();
16
+ coUsage.set('a', new Map([['b', 5], ['c', 5]]));
17
+ const score = calculateStructuralCohesionFromCoUsage('a', coUsage);
18
+ // Balanced distribution => entropy == 1 (for 2 items) => cohesion ~= 0
19
+ expect(score).toBeCloseTo(0, 3);
20
+ });
21
+ it('returns intermediate value for skewed distribution', () => {
22
+ const coUsage = new Map();
23
+ coUsage.set('a', new Map([['b', 8], ['c', 2]]));
24
+ const score = calculateStructuralCohesionFromCoUsage('a', coUsage);
25
+ // Expected approx 0.279
26
+ expect(score).toBeCloseTo(0.279, 2);
27
+ });
28
+ });
29
+ //# sourceMappingURL=structural-cohesion.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-cohesion.test.js","sourceRoot":"","sources":["../../src/__tests__/structural-cohesion.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,sCAAsC,EAAE,MAAM,aAAa,CAAA;AAEpE,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,KAAK,GAAG,sCAAsC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAC1E,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA+B,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACtC,MAAM,KAAK,GAAG,sCAAsC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAClE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,OAAO,GAAG,IAAI,GAAG,EAA+B,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,sCAAsC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAClE,uEAAuE;QACvE,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,EAA+B,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,sCAAsC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAClE,wBAAwB;QACxB,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,100 @@
1
+ import type { DependencyGraph, ExportInfo, ModuleCluster } from './types';
2
+ interface FileContent {
3
+ file: string;
4
+ content: string;
5
+ }
6
+ /**
7
+ * Build a dependency graph from file contents
8
+ */
9
+ export declare function buildDependencyGraph(files: FileContent[]): DependencyGraph;
10
+ /**
11
+ * Calculate the maximum depth of import tree for a file
12
+ */
13
+ export declare function calculateImportDepth(file: string, graph: DependencyGraph, visited?: Set<string>, depth?: number): number;
14
+ /**
15
+ * Get all transitive dependencies for a file
16
+ */
17
+ export declare function getTransitiveDependencies(file: string, graph: DependencyGraph, visited?: Set<string>): string[];
18
+ /**
19
+ * Calculate total context budget (tokens needed to understand this file)
20
+ */
21
+ export declare function calculateContextBudget(file: string, graph: DependencyGraph): number;
22
+ /**
23
+ * Detect circular dependencies
24
+ */
25
+ export declare function detectCircularDependencies(graph: DependencyGraph): string[][];
26
+ /**
27
+ * Calculate cohesion score (how related are exports in a file)
28
+ * Uses enhanced calculation combining domain-based and import-based analysis
29
+ * @param exports - Array of export information
30
+ * @param filePath - Optional file path for context-aware scoring
31
+ */
32
+ export declare function calculateCohesion(exports: ExportInfo[], filePath?: string, options?: {
33
+ coUsageMatrix?: Map<string, Map<string, number>>;
34
+ weights?: {
35
+ importBased?: number;
36
+ structural?: number;
37
+ domainBased?: number;
38
+ };
39
+ }): number;
40
+ /**
41
+ * Calculate fragmentation score (how scattered is a domain)
42
+ */
43
+ export declare function calculateFragmentation(files: string[], domain: string, options?: {
44
+ useLogScale?: boolean;
45
+ logBase?: number;
46
+ }): number;
47
+ /**
48
+ * Calculate path entropy for a set of files.
49
+ * Returns a normalized entropy in [0,1], where 0 = all files in one directory,
50
+ * and 1 = files are evenly distributed across directories.
51
+ */
52
+ export declare function calculatePathEntropy(files: string[]): number;
53
+ /**
54
+ * Calculate directory-distance metric based on common ancestor depth.
55
+ * For each file pair compute depth(commonAncestor) and normalize by the
56
+ * maximum path depth between the two files. Returns value in [0,1] where
57
+ * 0 means all pairs share a deep common ancestor (low fragmentation) and
58
+ * 1 means they share only the root (high fragmentation).
59
+ */
60
+ export declare function calculateDirectoryDistance(files: string[]): number;
61
+ /**
62
+ * Group files by domain to detect module clusters
63
+ */
64
+ export declare function detectModuleClusters(graph: DependencyGraph, options?: {
65
+ useLogScale?: boolean;
66
+ }): ModuleCluster[];
67
+ /**
68
+ * Extract exports using AST parsing (enhanced version)
69
+ * Falls back to regex if AST parsing fails
70
+ */
71
+ export declare function extractExportsWithAST(content: string, filePath: string, domainOptions?: {
72
+ domainKeywords?: string[];
73
+ }, fileImports?: string[]): ExportInfo[];
74
+ /**
75
+ * Calculate enhanced cohesion score using both domain inference and import similarity
76
+ *
77
+ * This combines:
78
+ * 1. Domain-based cohesion (entropy of inferred domains)
79
+ * 2. Import-based cohesion (Jaccard similarity of shared imports)
80
+ *
81
+ * Weight: 60% import-based, 40% domain-based (import analysis is more reliable)
82
+ */
83
+ export declare function calculateEnhancedCohesion(exports: ExportInfo[], filePath?: string, options?: {
84
+ coUsageMatrix?: Map<string, Map<string, number>>;
85
+ weights?: {
86
+ importBased?: number;
87
+ structural?: number;
88
+ domainBased?: number;
89
+ };
90
+ }): number;
91
+ /**
92
+ * Calculate structural cohesion for a file based on co-usage patterns.
93
+ * Uses the co-usage distribution (files commonly imported alongside this file)
94
+ * and computes an entropy-based cohesion score in [0,1].
95
+ * - 1 => highly cohesive (imports mostly appear together with a small set)
96
+ * - 0 => maximally fragmented (imports appear uniformly across many partners)
97
+ */
98
+ export declare function calculateStructuralCohesionFromCoUsage(file: string, coUsageMatrix?: Map<string, Map<string, number>>): number;
99
+ export {};
100
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}