@aiready/context-analyzer 0.6.0 → 0.7.1
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 +11 -6
- package/README.md +5 -3
- package/SEMANTIC-VALIDATION.md +235 -0
- package/dist/chunk-AEK3MZC5.mjs +709 -0
- package/dist/chunk-DMRZMS2U.mjs +964 -0
- package/dist/chunk-HQNHM2X7.mjs +997 -0
- package/dist/chunk-I54HL4FZ.mjs +781 -0
- package/dist/chunk-IRWCPDWD.mjs +779 -0
- package/dist/chunk-PVVCCE6W.mjs +755 -0
- package/dist/chunk-RYIB5CWD.mjs +781 -0
- package/dist/cli.js +234 -16
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +90 -1
- package/dist/index.d.ts +90 -1
- package/dist/index.js +311 -18
- package/dist/index.mjs +17 -3
- package/package.json +2 -2
- package/src/__tests__/auto-detection.test.ts +156 -0
- package/src/analyzer.ts +182 -18
- package/src/index.ts +34 -2
- package/src/semantic-analysis.ts +287 -0
- package/src/types.ts +33 -1
- package/COHESION-IMPROVEMENTS.md +0 -202
package/dist/cli.js
CHANGED
|
@@ -31,12 +31,176 @@ var import_core2 = require("@aiready/core");
|
|
|
31
31
|
|
|
32
32
|
// src/analyzer.ts
|
|
33
33
|
var import_core = require("@aiready/core");
|
|
34
|
+
|
|
35
|
+
// src/semantic-analysis.ts
|
|
36
|
+
function buildCoUsageMatrix(graph) {
|
|
37
|
+
const coUsageMatrix = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const [sourceFile, node] of graph.nodes) {
|
|
39
|
+
const imports = node.imports;
|
|
40
|
+
for (let i = 0; i < imports.length; i++) {
|
|
41
|
+
const fileA = imports[i];
|
|
42
|
+
if (!coUsageMatrix.has(fileA)) {
|
|
43
|
+
coUsageMatrix.set(fileA, /* @__PURE__ */ new Map());
|
|
44
|
+
}
|
|
45
|
+
for (let j = i + 1; j < imports.length; j++) {
|
|
46
|
+
const fileB = imports[j];
|
|
47
|
+
const fileAUsage = coUsageMatrix.get(fileA);
|
|
48
|
+
fileAUsage.set(fileB, (fileAUsage.get(fileB) || 0) + 1);
|
|
49
|
+
if (!coUsageMatrix.has(fileB)) {
|
|
50
|
+
coUsageMatrix.set(fileB, /* @__PURE__ */ new Map());
|
|
51
|
+
}
|
|
52
|
+
const fileBUsage = coUsageMatrix.get(fileB);
|
|
53
|
+
fileBUsage.set(fileA, (fileBUsage.get(fileA) || 0) + 1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return coUsageMatrix;
|
|
58
|
+
}
|
|
59
|
+
function buildTypeGraph(graph) {
|
|
60
|
+
const typeGraph = /* @__PURE__ */ new Map();
|
|
61
|
+
for (const [file, node] of graph.nodes) {
|
|
62
|
+
for (const exp of node.exports) {
|
|
63
|
+
if (exp.typeReferences) {
|
|
64
|
+
for (const typeRef of exp.typeReferences) {
|
|
65
|
+
if (!typeGraph.has(typeRef)) {
|
|
66
|
+
typeGraph.set(typeRef, /* @__PURE__ */ new Set());
|
|
67
|
+
}
|
|
68
|
+
typeGraph.get(typeRef).add(file);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return typeGraph;
|
|
74
|
+
}
|
|
75
|
+
function calculateDomainConfidence(signals) {
|
|
76
|
+
const weights = {
|
|
77
|
+
coUsage: 0.35,
|
|
78
|
+
// Strongest signal: actual usage patterns
|
|
79
|
+
typeReference: 0.3,
|
|
80
|
+
// Strong signal: shared types
|
|
81
|
+
exportName: 0.15,
|
|
82
|
+
// Medium signal: identifier semantics
|
|
83
|
+
importPath: 0.1,
|
|
84
|
+
// Weaker signal: path structure
|
|
85
|
+
folderStructure: 0.1
|
|
86
|
+
// Weakest signal: organization convention
|
|
87
|
+
};
|
|
88
|
+
let confidence = 0;
|
|
89
|
+
if (signals.coUsage) confidence += weights.coUsage;
|
|
90
|
+
if (signals.typeReference) confidence += weights.typeReference;
|
|
91
|
+
if (signals.exportName) confidence += weights.exportName;
|
|
92
|
+
if (signals.importPath) confidence += weights.importPath;
|
|
93
|
+
if (signals.folderStructure) confidence += weights.folderStructure;
|
|
94
|
+
return confidence;
|
|
95
|
+
}
|
|
96
|
+
function inferDomainFromSemantics(file, exportName, graph, coUsageMatrix, typeGraph, exportTypeRefs) {
|
|
97
|
+
const assignments = [];
|
|
98
|
+
const domainSignals = /* @__PURE__ */ new Map();
|
|
99
|
+
const coUsages = coUsageMatrix.get(file) || /* @__PURE__ */ new Map();
|
|
100
|
+
const strongCoUsages = Array.from(coUsages.entries()).filter(([_, count]) => count >= 3).map(([coFile]) => coFile);
|
|
101
|
+
for (const coFile of strongCoUsages) {
|
|
102
|
+
const coNode = graph.nodes.get(coFile);
|
|
103
|
+
if (coNode) {
|
|
104
|
+
for (const exp of coNode.exports) {
|
|
105
|
+
if (exp.inferredDomain && exp.inferredDomain !== "unknown") {
|
|
106
|
+
const domain = exp.inferredDomain;
|
|
107
|
+
if (!domainSignals.has(domain)) {
|
|
108
|
+
domainSignals.set(domain, {
|
|
109
|
+
coUsage: false,
|
|
110
|
+
typeReference: false,
|
|
111
|
+
exportName: false,
|
|
112
|
+
importPath: false,
|
|
113
|
+
folderStructure: false
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
domainSignals.get(domain).coUsage = true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (exportTypeRefs) {
|
|
122
|
+
for (const typeRef of exportTypeRefs) {
|
|
123
|
+
const filesWithType = typeGraph.get(typeRef);
|
|
124
|
+
if (filesWithType) {
|
|
125
|
+
for (const typeFile of filesWithType) {
|
|
126
|
+
if (typeFile !== file) {
|
|
127
|
+
const typeNode = graph.nodes.get(typeFile);
|
|
128
|
+
if (typeNode) {
|
|
129
|
+
for (const exp of typeNode.exports) {
|
|
130
|
+
if (exp.inferredDomain && exp.inferredDomain !== "unknown") {
|
|
131
|
+
const domain = exp.inferredDomain;
|
|
132
|
+
if (!domainSignals.has(domain)) {
|
|
133
|
+
domainSignals.set(domain, {
|
|
134
|
+
coUsage: false,
|
|
135
|
+
typeReference: false,
|
|
136
|
+
exportName: false,
|
|
137
|
+
importPath: false,
|
|
138
|
+
folderStructure: false
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
domainSignals.get(domain).typeReference = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const [domain, signals] of domainSignals) {
|
|
151
|
+
const confidence = calculateDomainConfidence(signals);
|
|
152
|
+
if (confidence >= 0.3) {
|
|
153
|
+
assignments.push({ domain, confidence, signals });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
assignments.sort((a, b) => b.confidence - a.confidence);
|
|
157
|
+
return assignments;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/analyzer.ts
|
|
161
|
+
function extractDomainKeywordsFromPaths(files) {
|
|
162
|
+
const folderNames = /* @__PURE__ */ new Set();
|
|
163
|
+
for (const { file } of files) {
|
|
164
|
+
const segments = file.split("/");
|
|
165
|
+
const skipFolders = /* @__PURE__ */ new Set(["src", "lib", "dist", "build", "node_modules", "test", "tests", "__tests__", "spec", "e2e", "scripts", "components", "utils", "helpers", "util", "helper", "api", "apis"]);
|
|
166
|
+
for (const segment of segments) {
|
|
167
|
+
const normalized = segment.toLowerCase();
|
|
168
|
+
if (normalized && !skipFolders.has(normalized) && !normalized.includes(".")) {
|
|
169
|
+
const singular = singularize(normalized);
|
|
170
|
+
folderNames.add(singular);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return Array.from(folderNames);
|
|
175
|
+
}
|
|
176
|
+
function singularize(word) {
|
|
177
|
+
const irregulars = {
|
|
178
|
+
people: "person",
|
|
179
|
+
children: "child",
|
|
180
|
+
men: "man",
|
|
181
|
+
women: "woman"
|
|
182
|
+
};
|
|
183
|
+
if (irregulars[word]) {
|
|
184
|
+
return irregulars[word];
|
|
185
|
+
}
|
|
186
|
+
if (word.endsWith("ies")) {
|
|
187
|
+
return word.slice(0, -3) + "y";
|
|
188
|
+
}
|
|
189
|
+
if (word.endsWith("ses")) {
|
|
190
|
+
return word.slice(0, -2);
|
|
191
|
+
}
|
|
192
|
+
if (word.endsWith("s") && word.length > 3) {
|
|
193
|
+
return word.slice(0, -1);
|
|
194
|
+
}
|
|
195
|
+
return word;
|
|
196
|
+
}
|
|
34
197
|
function buildDependencyGraph(files) {
|
|
35
198
|
const nodes = /* @__PURE__ */ new Map();
|
|
36
199
|
const edges = /* @__PURE__ */ new Map();
|
|
200
|
+
const autoDetectedKeywords = extractDomainKeywordsFromPaths(files);
|
|
37
201
|
for (const { file, content } of files) {
|
|
38
202
|
const imports = extractImportsFromContent(content);
|
|
39
|
-
const exports2 = extractExportsWithAST(content, file);
|
|
203
|
+
const exports2 = extractExportsWithAST(content, file, { domainKeywords: autoDetectedKeywords }, imports);
|
|
40
204
|
const tokenCost = (0, import_core.estimateTokens)(content);
|
|
41
205
|
const linesOfCode = content.split("\n").length;
|
|
42
206
|
nodes.set(file, {
|
|
@@ -48,7 +212,28 @@ function buildDependencyGraph(files) {
|
|
|
48
212
|
});
|
|
49
213
|
edges.set(file, new Set(imports));
|
|
50
214
|
}
|
|
51
|
-
|
|
215
|
+
const graph = { nodes, edges };
|
|
216
|
+
const coUsageMatrix = buildCoUsageMatrix(graph);
|
|
217
|
+
const typeGraph = buildTypeGraph(graph);
|
|
218
|
+
graph.coUsageMatrix = coUsageMatrix;
|
|
219
|
+
graph.typeGraph = typeGraph;
|
|
220
|
+
for (const [file, node] of nodes) {
|
|
221
|
+
for (const exp of node.exports) {
|
|
222
|
+
const semanticAssignments = inferDomainFromSemantics(
|
|
223
|
+
file,
|
|
224
|
+
exp.name,
|
|
225
|
+
graph,
|
|
226
|
+
coUsageMatrix,
|
|
227
|
+
typeGraph,
|
|
228
|
+
exp.typeReferences
|
|
229
|
+
);
|
|
230
|
+
exp.domains = semanticAssignments;
|
|
231
|
+
if (semanticAssignments.length > 0) {
|
|
232
|
+
exp.inferredDomain = semanticAssignments[0].domain;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return graph;
|
|
52
237
|
}
|
|
53
238
|
function extractImportsFromContent(content) {
|
|
54
239
|
const imports = [];
|
|
@@ -64,7 +249,7 @@ function extractImportsFromContent(content) {
|
|
|
64
249
|
let match;
|
|
65
250
|
while ((match = pattern.exec(content)) !== null) {
|
|
66
251
|
const importPath = match[1];
|
|
67
|
-
if (importPath && !importPath.startsWith("
|
|
252
|
+
if (importPath && !importPath.startsWith("node:")) {
|
|
68
253
|
imports.push(importPath);
|
|
69
254
|
}
|
|
70
255
|
}
|
|
@@ -204,7 +389,7 @@ function detectModuleClusters(graph) {
|
|
|
204
389
|
}
|
|
205
390
|
return clusters.sort((a, b) => b.fragmentationScore - a.fragmentationScore);
|
|
206
391
|
}
|
|
207
|
-
function extractExports(content) {
|
|
392
|
+
function extractExports(content, filePath, domainOptions, fileImports) {
|
|
208
393
|
const exports2 = [];
|
|
209
394
|
const patterns = [
|
|
210
395
|
/export\s+function\s+(\w+)/g,
|
|
@@ -227,15 +412,20 @@ function extractExports(content) {
|
|
|
227
412
|
while ((match = pattern.exec(content)) !== null) {
|
|
228
413
|
const name = match[1] || "default";
|
|
229
414
|
const type = types[index];
|
|
230
|
-
const inferredDomain = inferDomain(name);
|
|
415
|
+
const inferredDomain = inferDomain(name, filePath, domainOptions, fileImports);
|
|
231
416
|
exports2.push({ name, type, inferredDomain });
|
|
232
417
|
}
|
|
233
418
|
});
|
|
234
419
|
return exports2;
|
|
235
420
|
}
|
|
236
|
-
function inferDomain(name) {
|
|
421
|
+
function inferDomain(name, filePath, domainOptions, fileImports) {
|
|
237
422
|
const lower = name.toLowerCase();
|
|
238
|
-
const
|
|
423
|
+
const tokens = Array.from(
|
|
424
|
+
new Set(
|
|
425
|
+
lower.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^a-z0-9]+/gi, " ").split(" ").filter(Boolean)
|
|
426
|
+
)
|
|
427
|
+
);
|
|
428
|
+
const defaultKeywords = [
|
|
239
429
|
"authentication",
|
|
240
430
|
"authorization",
|
|
241
431
|
"payment",
|
|
@@ -252,14 +442,11 @@ function inferDomain(name) {
|
|
|
252
442
|
"config",
|
|
253
443
|
"model",
|
|
254
444
|
"view",
|
|
255
|
-
"auth"
|
|
256
|
-
"api",
|
|
257
|
-
"helper",
|
|
258
|
-
"util"
|
|
445
|
+
"auth"
|
|
259
446
|
];
|
|
447
|
+
const domainKeywords = domainOptions?.domainKeywords && domainOptions.domainKeywords.length ? [...domainOptions.domainKeywords, ...defaultKeywords] : defaultKeywords;
|
|
260
448
|
for (const keyword of domainKeywords) {
|
|
261
|
-
|
|
262
|
-
if (wordBoundaryPattern.test(name)) {
|
|
449
|
+
if (tokens.includes(keyword)) {
|
|
263
450
|
return keyword;
|
|
264
451
|
}
|
|
265
452
|
}
|
|
@@ -268,6 +455,37 @@ function inferDomain(name) {
|
|
|
268
455
|
return keyword;
|
|
269
456
|
}
|
|
270
457
|
}
|
|
458
|
+
if (fileImports && fileImports.length > 0) {
|
|
459
|
+
for (const importPath of fileImports) {
|
|
460
|
+
const allSegments = importPath.split("/");
|
|
461
|
+
const relevantSegments = allSegments.filter((s) => {
|
|
462
|
+
if (!s) return false;
|
|
463
|
+
if (s === "." || s === "..") return false;
|
|
464
|
+
if (s.startsWith("@") && s.length === 1) return false;
|
|
465
|
+
return true;
|
|
466
|
+
}).map((s) => s.startsWith("@") ? s.slice(1) : s);
|
|
467
|
+
for (const segment of relevantSegments) {
|
|
468
|
+
const segLower = segment.toLowerCase();
|
|
469
|
+
const singularSegment = singularize(segLower);
|
|
470
|
+
for (const keyword of domainKeywords) {
|
|
471
|
+
if (singularSegment === keyword || segLower === keyword || segLower.includes(keyword)) {
|
|
472
|
+
return keyword;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (filePath) {
|
|
479
|
+
const pathSegments = filePath.toLowerCase().split("/");
|
|
480
|
+
for (const segment of pathSegments) {
|
|
481
|
+
const singularSegment = singularize(segment);
|
|
482
|
+
for (const keyword of domainKeywords) {
|
|
483
|
+
if (singularSegment === keyword || segment === keyword || segment.includes(keyword)) {
|
|
484
|
+
return keyword;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
271
489
|
return "unknown";
|
|
272
490
|
}
|
|
273
491
|
function generateConsolidationPlan(domain, files, targetFiles) {
|
|
@@ -296,18 +514,18 @@ function generateConsolidationPlan(domain, files, targetFiles) {
|
|
|
296
514
|
);
|
|
297
515
|
return plan;
|
|
298
516
|
}
|
|
299
|
-
function extractExportsWithAST(content, filePath) {
|
|
517
|
+
function extractExportsWithAST(content, filePath, domainOptions, fileImports) {
|
|
300
518
|
try {
|
|
301
519
|
const { exports: astExports } = (0, import_core.parseFileExports)(content, filePath);
|
|
302
520
|
return astExports.map((exp) => ({
|
|
303
521
|
name: exp.name,
|
|
304
522
|
type: exp.type,
|
|
305
|
-
inferredDomain: inferDomain(exp.name),
|
|
523
|
+
inferredDomain: inferDomain(exp.name, filePath, domainOptions, fileImports),
|
|
306
524
|
imports: exp.imports,
|
|
307
525
|
dependencies: exp.dependencies
|
|
308
526
|
}));
|
|
309
527
|
} catch (error) {
|
|
310
|
-
return extractExports(content);
|
|
528
|
+
return extractExports(content, filePath, domainOptions, fileImports);
|
|
311
529
|
}
|
|
312
530
|
}
|
|
313
531
|
function calculateEnhancedCohesion(exports2, filePath) {
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -66,6 +66,95 @@ interface ContextSummary {
|
|
|
66
66
|
severity: string;
|
|
67
67
|
}>;
|
|
68
68
|
}
|
|
69
|
+
interface DependencyGraph {
|
|
70
|
+
nodes: Map<string, DependencyNode>;
|
|
71
|
+
edges: Map<string, Set<string>>;
|
|
72
|
+
coUsageMatrix?: Map<string, Map<string, number>>;
|
|
73
|
+
typeGraph?: Map<string, Set<string>>;
|
|
74
|
+
}
|
|
75
|
+
interface DependencyNode {
|
|
76
|
+
file: string;
|
|
77
|
+
imports: string[];
|
|
78
|
+
exports: ExportInfo[];
|
|
79
|
+
tokenCost: number;
|
|
80
|
+
linesOfCode: number;
|
|
81
|
+
exportedBy?: string[];
|
|
82
|
+
sharedTypes?: string[];
|
|
83
|
+
}
|
|
84
|
+
interface ExportInfo {
|
|
85
|
+
name: string;
|
|
86
|
+
type: 'function' | 'class' | 'const' | 'type' | 'interface' | 'default';
|
|
87
|
+
inferredDomain?: string;
|
|
88
|
+
domains?: DomainAssignment[];
|
|
89
|
+
imports?: string[];
|
|
90
|
+
dependencies?: string[];
|
|
91
|
+
typeReferences?: string[];
|
|
92
|
+
}
|
|
93
|
+
interface DomainAssignment {
|
|
94
|
+
domain: string;
|
|
95
|
+
confidence: number;
|
|
96
|
+
signals: DomainSignals;
|
|
97
|
+
}
|
|
98
|
+
interface DomainSignals {
|
|
99
|
+
folderStructure: boolean;
|
|
100
|
+
importPath: boolean;
|
|
101
|
+
typeReference: boolean;
|
|
102
|
+
coUsage: boolean;
|
|
103
|
+
exportName: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface CoUsageData {
|
|
106
|
+
file: string;
|
|
107
|
+
coImportedWith: Map<string, number>;
|
|
108
|
+
sharedImporters: string[];
|
|
109
|
+
}
|
|
110
|
+
interface TypeDependency {
|
|
111
|
+
typeName: string;
|
|
112
|
+
definedIn: string;
|
|
113
|
+
usedBy: string[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build co-usage matrix: track which files are imported together
|
|
118
|
+
*
|
|
119
|
+
* Files frequently imported together likely belong to the same semantic domain
|
|
120
|
+
*/
|
|
121
|
+
declare function buildCoUsageMatrix(graph: DependencyGraph): Map<string, Map<string, number>>;
|
|
122
|
+
/**
|
|
123
|
+
* Extract type dependencies from AST exports
|
|
124
|
+
*
|
|
125
|
+
* Files that share types are semantically related
|
|
126
|
+
*/
|
|
127
|
+
declare function buildTypeGraph(graph: DependencyGraph): Map<string, Set<string>>;
|
|
128
|
+
/**
|
|
129
|
+
* Find semantic clusters using co-usage patterns
|
|
130
|
+
*
|
|
131
|
+
* Files with high co-usage counts belong in the same cluster
|
|
132
|
+
*/
|
|
133
|
+
declare function findSemanticClusters(coUsageMatrix: Map<string, Map<string, number>>, minCoUsage?: number): Map<string, string[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Calculate confidence score for domain assignment based on multiple signals
|
|
136
|
+
*/
|
|
137
|
+
declare function calculateDomainConfidence(signals: DomainSignals): number;
|
|
138
|
+
/**
|
|
139
|
+
* Infer domain from semantic analysis (co-usage + types)
|
|
140
|
+
*
|
|
141
|
+
* This replaces the folder-based heuristic with actual code relationships
|
|
142
|
+
*/
|
|
143
|
+
declare function inferDomainFromSemantics(file: string, exportName: string, graph: DependencyGraph, coUsageMatrix: Map<string, Map<string, number>>, typeGraph: Map<string, Set<string>>, exportTypeRefs?: string[]): DomainAssignment[];
|
|
144
|
+
/**
|
|
145
|
+
* Get co-usage data for a specific file
|
|
146
|
+
*/
|
|
147
|
+
declare function getCoUsageData(file: string, coUsageMatrix: Map<string, Map<string, number>>): CoUsageData;
|
|
148
|
+
/**
|
|
149
|
+
* Find files that should be consolidated based on semantic similarity
|
|
150
|
+
*
|
|
151
|
+
* High co-usage + shared types = strong consolidation candidate
|
|
152
|
+
*/
|
|
153
|
+
declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatrix: Map<string, Map<string, number>>, typeGraph: Map<string, Set<string>>, minCoUsage?: number, minSharedTypes?: number): Array<{
|
|
154
|
+
files: string[];
|
|
155
|
+
reason: string;
|
|
156
|
+
strength: number;
|
|
157
|
+
}>;
|
|
69
158
|
|
|
70
159
|
/**
|
|
71
160
|
* Generate smart defaults for context analysis based on repository size
|
|
@@ -81,4 +170,4 @@ declare function analyzeContext(options: ContextAnalyzerOptions): Promise<Contex
|
|
|
81
170
|
*/
|
|
82
171
|
declare function generateSummary(results: ContextAnalysisResult[]): ContextSummary;
|
|
83
172
|
|
|
84
|
-
export { type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type ModuleCluster, analyzeContext, generateSummary, getSmartDefaults };
|
|
173
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type DomainAssignment, type DomainSignals, type ModuleCluster, type TypeDependency, analyzeContext, buildCoUsageMatrix, buildTypeGraph, calculateDomainConfidence, findConsolidationCandidates, findSemanticClusters, generateSummary, getCoUsageData, getSmartDefaults, inferDomainFromSemantics };
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,95 @@ interface ContextSummary {
|
|
|
66
66
|
severity: string;
|
|
67
67
|
}>;
|
|
68
68
|
}
|
|
69
|
+
interface DependencyGraph {
|
|
70
|
+
nodes: Map<string, DependencyNode>;
|
|
71
|
+
edges: Map<string, Set<string>>;
|
|
72
|
+
coUsageMatrix?: Map<string, Map<string, number>>;
|
|
73
|
+
typeGraph?: Map<string, Set<string>>;
|
|
74
|
+
}
|
|
75
|
+
interface DependencyNode {
|
|
76
|
+
file: string;
|
|
77
|
+
imports: string[];
|
|
78
|
+
exports: ExportInfo[];
|
|
79
|
+
tokenCost: number;
|
|
80
|
+
linesOfCode: number;
|
|
81
|
+
exportedBy?: string[];
|
|
82
|
+
sharedTypes?: string[];
|
|
83
|
+
}
|
|
84
|
+
interface ExportInfo {
|
|
85
|
+
name: string;
|
|
86
|
+
type: 'function' | 'class' | 'const' | 'type' | 'interface' | 'default';
|
|
87
|
+
inferredDomain?: string;
|
|
88
|
+
domains?: DomainAssignment[];
|
|
89
|
+
imports?: string[];
|
|
90
|
+
dependencies?: string[];
|
|
91
|
+
typeReferences?: string[];
|
|
92
|
+
}
|
|
93
|
+
interface DomainAssignment {
|
|
94
|
+
domain: string;
|
|
95
|
+
confidence: number;
|
|
96
|
+
signals: DomainSignals;
|
|
97
|
+
}
|
|
98
|
+
interface DomainSignals {
|
|
99
|
+
folderStructure: boolean;
|
|
100
|
+
importPath: boolean;
|
|
101
|
+
typeReference: boolean;
|
|
102
|
+
coUsage: boolean;
|
|
103
|
+
exportName: boolean;
|
|
104
|
+
}
|
|
105
|
+
interface CoUsageData {
|
|
106
|
+
file: string;
|
|
107
|
+
coImportedWith: Map<string, number>;
|
|
108
|
+
sharedImporters: string[];
|
|
109
|
+
}
|
|
110
|
+
interface TypeDependency {
|
|
111
|
+
typeName: string;
|
|
112
|
+
definedIn: string;
|
|
113
|
+
usedBy: string[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build co-usage matrix: track which files are imported together
|
|
118
|
+
*
|
|
119
|
+
* Files frequently imported together likely belong to the same semantic domain
|
|
120
|
+
*/
|
|
121
|
+
declare function buildCoUsageMatrix(graph: DependencyGraph): Map<string, Map<string, number>>;
|
|
122
|
+
/**
|
|
123
|
+
* Extract type dependencies from AST exports
|
|
124
|
+
*
|
|
125
|
+
* Files that share types are semantically related
|
|
126
|
+
*/
|
|
127
|
+
declare function buildTypeGraph(graph: DependencyGraph): Map<string, Set<string>>;
|
|
128
|
+
/**
|
|
129
|
+
* Find semantic clusters using co-usage patterns
|
|
130
|
+
*
|
|
131
|
+
* Files with high co-usage counts belong in the same cluster
|
|
132
|
+
*/
|
|
133
|
+
declare function findSemanticClusters(coUsageMatrix: Map<string, Map<string, number>>, minCoUsage?: number): Map<string, string[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Calculate confidence score for domain assignment based on multiple signals
|
|
136
|
+
*/
|
|
137
|
+
declare function calculateDomainConfidence(signals: DomainSignals): number;
|
|
138
|
+
/**
|
|
139
|
+
* Infer domain from semantic analysis (co-usage + types)
|
|
140
|
+
*
|
|
141
|
+
* This replaces the folder-based heuristic with actual code relationships
|
|
142
|
+
*/
|
|
143
|
+
declare function inferDomainFromSemantics(file: string, exportName: string, graph: DependencyGraph, coUsageMatrix: Map<string, Map<string, number>>, typeGraph: Map<string, Set<string>>, exportTypeRefs?: string[]): DomainAssignment[];
|
|
144
|
+
/**
|
|
145
|
+
* Get co-usage data for a specific file
|
|
146
|
+
*/
|
|
147
|
+
declare function getCoUsageData(file: string, coUsageMatrix: Map<string, Map<string, number>>): CoUsageData;
|
|
148
|
+
/**
|
|
149
|
+
* Find files that should be consolidated based on semantic similarity
|
|
150
|
+
*
|
|
151
|
+
* High co-usage + shared types = strong consolidation candidate
|
|
152
|
+
*/
|
|
153
|
+
declare function findConsolidationCandidates(graph: DependencyGraph, coUsageMatrix: Map<string, Map<string, number>>, typeGraph: Map<string, Set<string>>, minCoUsage?: number, minSharedTypes?: number): Array<{
|
|
154
|
+
files: string[];
|
|
155
|
+
reason: string;
|
|
156
|
+
strength: number;
|
|
157
|
+
}>;
|
|
69
158
|
|
|
70
159
|
/**
|
|
71
160
|
* Generate smart defaults for context analysis based on repository size
|
|
@@ -81,4 +170,4 @@ declare function analyzeContext(options: ContextAnalyzerOptions): Promise<Contex
|
|
|
81
170
|
*/
|
|
82
171
|
declare function generateSummary(results: ContextAnalysisResult[]): ContextSummary;
|
|
83
172
|
|
|
84
|
-
export { type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type ModuleCluster, analyzeContext, generateSummary, getSmartDefaults };
|
|
173
|
+
export { type CoUsageData, type ContextAnalysisResult, type ContextAnalyzerOptions, type ContextSummary, type DomainAssignment, type DomainSignals, type ModuleCluster, type TypeDependency, analyzeContext, buildCoUsageMatrix, buildTypeGraph, calculateDomainConfidence, findConsolidationCandidates, findSemanticClusters, generateSummary, getCoUsageData, getSmartDefaults, inferDomainFromSemantics };
|