@girardelli/architect 1.2.1 → 2.1.0
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/README.md +111 -112
- package/dist/agent-generator.d.ts +95 -0
- package/dist/agent-generator.d.ts.map +1 -0
- package/dist/agent-generator.js +1295 -0
- package/dist/agent-generator.js.map +1 -0
- package/dist/cli.js +76 -2
- package/dist/cli.js.map +1 -1
- package/dist/html-reporter.d.ts +26 -4
- package/dist/html-reporter.d.ts.map +1 -1
- package/dist/html-reporter.js +832 -33
- package/dist/html-reporter.js.map +1 -1
- package/dist/index.d.ts +26 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +85 -8
- package/dist/index.js.map +1 -1
- package/dist/refactor-engine.d.ts +18 -0
- package/dist/refactor-engine.d.ts.map +1 -0
- package/dist/refactor-engine.js +86 -0
- package/dist/refactor-engine.js.map +1 -0
- package/dist/refactor-reporter.d.ts +20 -0
- package/dist/refactor-reporter.d.ts.map +1 -0
- package/dist/refactor-reporter.js +389 -0
- package/dist/refactor-reporter.js.map +1 -0
- package/dist/rules/barrel-optimizer.d.ts +13 -0
- package/dist/rules/barrel-optimizer.d.ts.map +1 -0
- package/dist/rules/barrel-optimizer.js +77 -0
- package/dist/rules/barrel-optimizer.js.map +1 -0
- package/dist/rules/dead-code-detector.d.ts +21 -0
- package/dist/rules/dead-code-detector.d.ts.map +1 -0
- package/dist/rules/dead-code-detector.js +117 -0
- package/dist/rules/dead-code-detector.js.map +1 -0
- package/dist/rules/hub-splitter.d.ts +13 -0
- package/dist/rules/hub-splitter.d.ts.map +1 -0
- package/dist/rules/hub-splitter.js +110 -0
- package/dist/rules/hub-splitter.js.map +1 -0
- package/dist/rules/import-organizer.d.ts +13 -0
- package/dist/rules/import-organizer.d.ts.map +1 -0
- package/dist/rules/import-organizer.js +85 -0
- package/dist/rules/import-organizer.js.map +1 -0
- package/dist/rules/module-grouper.d.ts +13 -0
- package/dist/rules/module-grouper.d.ts.map +1 -0
- package/dist/rules/module-grouper.js +110 -0
- package/dist/rules/module-grouper.js.map +1 -0
- package/dist/scorer.d.ts +12 -0
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +61 -17
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-generator.ts +1401 -0
- package/src/cli.ts +83 -2
- package/src/html-reporter.ts +872 -35
- package/src/index.ts +108 -9
- package/src/refactor-engine.ts +117 -0
- package/src/refactor-reporter.ts +408 -0
- package/src/rules/barrel-optimizer.ts +97 -0
- package/src/rules/dead-code-detector.ts +132 -0
- package/src/rules/hub-splitter.ts +123 -0
- package/src/rules/import-organizer.ts +98 -0
- package/src/rules/module-grouper.ts +124 -0
- package/src/scorer.ts +63 -17
- package/src/types.ts +52 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnalysisReport, RefactorRule, RefactorStep } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Hub Splitter Rule (Tier 1)
|
|
4
|
+
* Detects files with many connections and generates split plans.
|
|
5
|
+
* A "hub" is a file that many other files depend on, creating tight coupling.
|
|
6
|
+
*/
|
|
7
|
+
export declare class HubSplitterRule implements RefactorRule {
|
|
8
|
+
name: string;
|
|
9
|
+
tier: 1;
|
|
10
|
+
analyze(report: AnalysisReport, projectPath: string): RefactorStep[];
|
|
11
|
+
private groupDependents;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=hub-splitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-splitter.d.ts","sourceRoot":"","sources":["../../src/rules/hub-splitter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAExF;;;;GAIG;AACH,qBAAa,eAAgB,YAAW,YAAY;IAClD,IAAI,SAAkB;IACtB,IAAI,EAAG,CAAC,CAAU;IAElB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE;IA4FpE,OAAO,CAAC,eAAe;CAkBxB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { basename, dirname } from 'path';
|
|
2
|
+
/**
|
|
3
|
+
* Hub Splitter Rule (Tier 1)
|
|
4
|
+
* Detects files with many connections and generates split plans.
|
|
5
|
+
* A "hub" is a file that many other files depend on, creating tight coupling.
|
|
6
|
+
*/
|
|
7
|
+
export class HubSplitterRule {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.name = 'hub-splitter';
|
|
10
|
+
this.tier = 1;
|
|
11
|
+
}
|
|
12
|
+
analyze(report, projectPath) {
|
|
13
|
+
const steps = [];
|
|
14
|
+
// Count connections per node
|
|
15
|
+
const connectionCount = {};
|
|
16
|
+
for (const edge of report.dependencyGraph.edges) {
|
|
17
|
+
if (!connectionCount[edge.from])
|
|
18
|
+
connectionCount[edge.from] = { incoming: [], outgoing: [] };
|
|
19
|
+
if (!connectionCount[edge.to])
|
|
20
|
+
connectionCount[edge.to] = { incoming: [], outgoing: [] };
|
|
21
|
+
connectionCount[edge.from].outgoing.push(edge.to);
|
|
22
|
+
connectionCount[edge.to].incoming.push(edge.from);
|
|
23
|
+
}
|
|
24
|
+
// Find hubs (5+ incoming connections, not barrel files)
|
|
25
|
+
const barrelFiles = new Set(['__init__.py', 'index.ts', 'index.js', 'index.tsx', 'mod.rs']);
|
|
26
|
+
for (const [file, connections] of Object.entries(connectionCount)) {
|
|
27
|
+
const fileName = basename(file);
|
|
28
|
+
if (barrelFiles.has(fileName))
|
|
29
|
+
continue;
|
|
30
|
+
if (connections.incoming.length < 5)
|
|
31
|
+
continue;
|
|
32
|
+
const operations = [];
|
|
33
|
+
// Determine if this is a dot-notation module or a real file
|
|
34
|
+
const isDotNotation = !file.includes('/') && !file.includes('\\');
|
|
35
|
+
const moduleName = isDotNotation
|
|
36
|
+
? file.split('.').pop() || file
|
|
37
|
+
: fileName.replace(/\.[^.]+$/, '');
|
|
38
|
+
const moduleDir = isDotNotation
|
|
39
|
+
? file.split('.').slice(0, -1).join('/')
|
|
40
|
+
: dirname(file);
|
|
41
|
+
const ext = isDotNotation ? 'py' : (fileName.split('.').pop() || 'py');
|
|
42
|
+
// Analyze what dependents import to suggest groupings
|
|
43
|
+
const dependentGroups = this.groupDependents(connections.incoming);
|
|
44
|
+
// Suggest splitting into domain modules
|
|
45
|
+
if (dependentGroups.length >= 2) {
|
|
46
|
+
for (const group of dependentGroups) {
|
|
47
|
+
const newFileName = `${moduleName}_${group.name}.${ext}`;
|
|
48
|
+
const newPath = moduleDir ? `${moduleDir}/${newFileName}` : newFileName;
|
|
49
|
+
operations.push({
|
|
50
|
+
type: 'CREATE',
|
|
51
|
+
path: newPath,
|
|
52
|
+
description: `Create \`${newFileName}\` with functionality used by: ${group.dependents.join(', ')}`,
|
|
53
|
+
content: ext === 'py'
|
|
54
|
+
? `"""${moduleName}_${group.name} — extracted from ${moduleName}."""\n# Used by: ${group.dependents.join(', ')}\n`
|
|
55
|
+
: `// ${moduleName}_${group.name} — extracted from ${moduleName}\n// Used by: ${group.dependents.join(', ')}\n`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Update imports in all dependents
|
|
59
|
+
for (const dependent of connections.incoming) {
|
|
60
|
+
operations.push({
|
|
61
|
+
type: 'MODIFY',
|
|
62
|
+
path: dependent,
|
|
63
|
+
description: `Update imports in \`${basename(dependent)}\` to use new split modules`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Mark original for refactoring
|
|
67
|
+
operations.push({
|
|
68
|
+
type: 'MODIFY',
|
|
69
|
+
path: isDotNotation ? `${moduleDir}/${moduleName}.${ext}` : file,
|
|
70
|
+
description: `Refactor \`${moduleName}.${ext}\` — extract grouped functionality to new modules`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (operations.length > 0) {
|
|
74
|
+
steps.push({
|
|
75
|
+
id: 0,
|
|
76
|
+
tier: 1,
|
|
77
|
+
rule: this.name,
|
|
78
|
+
priority: connections.incoming.length >= 8 ? 'CRITICAL' : 'HIGH',
|
|
79
|
+
title: `Split hub file: ${moduleName}.${ext}`,
|
|
80
|
+
description: `\`${file}\` has ${connections.incoming.length} incoming connections. ` +
|
|
81
|
+
`Split into ${dependentGroups.length} focused modules to reduce coupling.`,
|
|
82
|
+
rationale: `High fan-in (${connections.incoming.length} files depend on this) creates a bottleneck. ` +
|
|
83
|
+
`Changes to this file ripple to ${connections.incoming.length} other files. ` +
|
|
84
|
+
`Splitting by usage pattern reduces blast radius.`,
|
|
85
|
+
operations,
|
|
86
|
+
scoreImpact: [
|
|
87
|
+
{ metric: 'coupling', before: report.score.breakdown.coupling, after: Math.min(95, report.score.breakdown.coupling + 15) },
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return steps;
|
|
93
|
+
}
|
|
94
|
+
groupDependents(dependents) {
|
|
95
|
+
// Group by top-level directory
|
|
96
|
+
const groups = {};
|
|
97
|
+
for (const dep of dependents) {
|
|
98
|
+
const parts = dep.includes('/') ? dep.split('/') : dep.split('.');
|
|
99
|
+
const groupName = parts.length >= 2 ? parts[parts.length - 2] : 'core';
|
|
100
|
+
if (!groups[groupName])
|
|
101
|
+
groups[groupName] = [];
|
|
102
|
+
groups[groupName].push(basename(dep));
|
|
103
|
+
}
|
|
104
|
+
return Object.entries(groups).map(([name, deps]) => ({
|
|
105
|
+
name,
|
|
106
|
+
dependents: deps,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=hub-splitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hub-splitter.js","sourceRoot":"","sources":["../../src/rules/hub-splitter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnalysisReport, RefactorRule, RefactorStep } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Import Organizer Rule (Tier 1)
|
|
4
|
+
* Detects files that import from too many different modules (cross-boundary).
|
|
5
|
+
* Suggests dependency injection or facade patterns.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ImportOrganizerRule implements RefactorRule {
|
|
8
|
+
name: string;
|
|
9
|
+
tier: 1;
|
|
10
|
+
analyze(report: AnalysisReport, projectPath: string): RefactorStep[];
|
|
11
|
+
private generateFacadeContent;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=import-organizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-organizer.d.ts","sourceRoot":"","sources":["../../src/rules/import-organizer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAExF;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,YAAY;IACtD,IAAI,SAAsB;IAC1B,IAAI,EAAG,CAAC,CAAU;IAElB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE;IAuEpE,OAAO,CAAC,qBAAqB;CAc9B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { basename, dirname } from 'path';
|
|
2
|
+
/**
|
|
3
|
+
* Import Organizer Rule (Tier 1)
|
|
4
|
+
* Detects files that import from too many different modules (cross-boundary).
|
|
5
|
+
* Suggests dependency injection or facade patterns.
|
|
6
|
+
*/
|
|
7
|
+
export class ImportOrganizerRule {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.name = 'import-organizer';
|
|
10
|
+
this.tier = 1;
|
|
11
|
+
}
|
|
12
|
+
analyze(report, projectPath) {
|
|
13
|
+
const steps = [];
|
|
14
|
+
// Find files that import from many different directories
|
|
15
|
+
const crossBoundary = {};
|
|
16
|
+
for (const edge of report.dependencyGraph.edges) {
|
|
17
|
+
const fromDir = dirname(edge.from);
|
|
18
|
+
const toDir = dirname(edge.to);
|
|
19
|
+
if (!crossBoundary[edge.from]) {
|
|
20
|
+
crossBoundary[edge.from] = { targets: new Set(), dirs: new Set() };
|
|
21
|
+
}
|
|
22
|
+
crossBoundary[edge.from].targets.add(edge.to);
|
|
23
|
+
if (fromDir !== toDir) {
|
|
24
|
+
crossBoundary[edge.from].dirs.add(toDir);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Files importing from 3+ different directories
|
|
28
|
+
const violators = Object.entries(crossBoundary)
|
|
29
|
+
.filter(([_, data]) => data.dirs.size >= 3)
|
|
30
|
+
.sort((a, b) => b[1].dirs.size - a[1].dirs.size);
|
|
31
|
+
for (const [file, data] of violators) {
|
|
32
|
+
const operations = [];
|
|
33
|
+
const fileName = basename(file);
|
|
34
|
+
const fileDir = dirname(file);
|
|
35
|
+
// Suggest creating a facade/service layer
|
|
36
|
+
const ext = fileName.split('.').pop() || 'py';
|
|
37
|
+
const nameBase = fileName.replace(/\.[^.]+$/, '');
|
|
38
|
+
const facadePath = `${fileDir}/${nameBase}_deps.${ext}`;
|
|
39
|
+
operations.push({
|
|
40
|
+
type: 'CREATE',
|
|
41
|
+
path: facadePath,
|
|
42
|
+
description: `Create dependency facade \`${basename(facadePath)}\` — centralizes ${data.dirs.size} cross-module imports`,
|
|
43
|
+
content: this.generateFacadeContent(ext, Array.from(data.targets), Array.from(data.dirs)),
|
|
44
|
+
});
|
|
45
|
+
operations.push({
|
|
46
|
+
type: 'MODIFY',
|
|
47
|
+
path: file,
|
|
48
|
+
description: `Refactor \`${fileName}\` to import from local facade instead of ${data.dirs.size} different modules`,
|
|
49
|
+
});
|
|
50
|
+
steps.push({
|
|
51
|
+
id: 0,
|
|
52
|
+
tier: 1,
|
|
53
|
+
rule: this.name,
|
|
54
|
+
priority: data.dirs.size >= 5 ? 'HIGH' : 'MEDIUM',
|
|
55
|
+
title: `Reduce cross-boundary imports: ${fileName}`,
|
|
56
|
+
description: `\`${file}\` imports from ${data.dirs.size} different modules: ` +
|
|
57
|
+
`${Array.from(data.dirs).map((d) => `\`${d}\``).join(', ')}. ` +
|
|
58
|
+
`Consider using a facade or dependency injection.`,
|
|
59
|
+
rationale: `Files with imports scattered across many modules have high afferent coupling. ` +
|
|
60
|
+
`A facade centralizes these dependencies, making the file easier to test (mock one facade) ` +
|
|
61
|
+
`and reducing the impact of changes in dependent modules.`,
|
|
62
|
+
operations,
|
|
63
|
+
scoreImpact: [
|
|
64
|
+
{ metric: 'cohesion', before: report.score.breakdown.cohesion, after: Math.min(95, report.score.breakdown.cohesion + 5) },
|
|
65
|
+
{ metric: 'coupling', before: report.score.breakdown.coupling, after: Math.min(95, report.score.breakdown.coupling + 5) },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return steps;
|
|
70
|
+
}
|
|
71
|
+
generateFacadeContent(ext, targets, dirs) {
|
|
72
|
+
if (ext === 'py') {
|
|
73
|
+
const imports = targets
|
|
74
|
+
.map((t) => `# from ${t.replace(/\//g, '.')} import ...`)
|
|
75
|
+
.join('\n');
|
|
76
|
+
return `"""Dependency facade — centralizes cross-module imports."""\n\n${imports}\n\n# Re-export what ${dirs.length} modules need\n`;
|
|
77
|
+
}
|
|
78
|
+
// JS/TS
|
|
79
|
+
const imports = targets
|
|
80
|
+
.map((t) => `// export { ... } from '${t}';`)
|
|
81
|
+
.join('\n');
|
|
82
|
+
return `/**\n * Dependency facade — centralizes cross-module imports.\n */\n\n${imports}\n`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=import-organizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-organizer.js","sourceRoot":"","sources":["../../src/rules/import-organizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnalysisReport, RefactorRule, RefactorStep } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Module Grouper Rule (Tier 1)
|
|
4
|
+
* Analyzes which files are frequently imported together and suggests
|
|
5
|
+
* grouping them into cohesive modules/packages.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ModuleGrouperRule implements RefactorRule {
|
|
8
|
+
name: string;
|
|
9
|
+
tier: 1;
|
|
10
|
+
analyze(report: AnalysisReport, projectPath: string): RefactorStep[];
|
|
11
|
+
private suggestModuleName;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=module-grouper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-grouper.d.ts","sourceRoot":"","sources":["../../src/rules/module-grouper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AAExF;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IACpD,IAAI,SAAoB;IACxB,IAAI,EAAG,CAAC,CAAU;IAElB,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE;IAqGpE,OAAO,CAAC,iBAAiB;CAU1B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { basename, dirname, join } from 'path';
|
|
2
|
+
/**
|
|
3
|
+
* Module Grouper Rule (Tier 1)
|
|
4
|
+
* Analyzes which files are frequently imported together and suggests
|
|
5
|
+
* grouping them into cohesive modules/packages.
|
|
6
|
+
*/
|
|
7
|
+
export class ModuleGrouperRule {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.name = 'module-grouper';
|
|
10
|
+
this.tier = 1;
|
|
11
|
+
}
|
|
12
|
+
analyze(report, projectPath) {
|
|
13
|
+
const steps = [];
|
|
14
|
+
// Build co-import matrix: which files are imported together?
|
|
15
|
+
const coImportCount = {};
|
|
16
|
+
// For each source file, see what it imports
|
|
17
|
+
const importsBySource = {};
|
|
18
|
+
for (const edge of report.dependencyGraph.edges) {
|
|
19
|
+
if (!importsBySource[edge.from])
|
|
20
|
+
importsBySource[edge.from] = [];
|
|
21
|
+
importsBySource[edge.from].push(edge.to);
|
|
22
|
+
}
|
|
23
|
+
// Count co-imports
|
|
24
|
+
for (const [source, targets] of Object.entries(importsBySource)) {
|
|
25
|
+
for (let i = 0; i < targets.length; i++) {
|
|
26
|
+
for (let j = i + 1; j < targets.length; j++) {
|
|
27
|
+
const a = targets[i];
|
|
28
|
+
const b = targets[j];
|
|
29
|
+
if (!coImportCount[a])
|
|
30
|
+
coImportCount[a] = {};
|
|
31
|
+
if (!coImportCount[b])
|
|
32
|
+
coImportCount[b] = {};
|
|
33
|
+
coImportCount[a][b] = (coImportCount[a][b] || 0) + 1;
|
|
34
|
+
coImportCount[b][a] = (coImportCount[b][a] || 0) + 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Find clusters: files that are always imported together
|
|
39
|
+
const clusters = [];
|
|
40
|
+
const visited = new Set();
|
|
41
|
+
for (const [fileA, partners] of Object.entries(coImportCount)) {
|
|
42
|
+
if (visited.has(fileA))
|
|
43
|
+
continue;
|
|
44
|
+
const strongPartners = Object.entries(partners)
|
|
45
|
+
.filter(([_, count]) => count >= 2)
|
|
46
|
+
.sort((a, b) => b[1] - a[1]);
|
|
47
|
+
if (strongPartners.length >= 2) {
|
|
48
|
+
const cluster = [fileA, ...strongPartners.map(([f]) => f)];
|
|
49
|
+
const inSameDir = cluster.every((f) => dirname(f) === dirname(cluster[0]));
|
|
50
|
+
// Only suggest if NOT already in the same directory
|
|
51
|
+
if (!inSameDir) {
|
|
52
|
+
const score = strongPartners.reduce((sum, [_, c]) => sum + c, 0);
|
|
53
|
+
clusters.push({ files: cluster, coImportScore: score });
|
|
54
|
+
cluster.forEach((f) => visited.add(f));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Generate steps for each cluster
|
|
59
|
+
for (const cluster of clusters.slice(0, 3)) {
|
|
60
|
+
const operations = [];
|
|
61
|
+
const clusterName = this.suggestModuleName(cluster.files);
|
|
62
|
+
const targetDir = `${dirname(cluster.files[0])}/${clusterName}`;
|
|
63
|
+
// Create new module directory
|
|
64
|
+
operations.push({
|
|
65
|
+
type: 'CREATE',
|
|
66
|
+
path: `${targetDir}/__init__.py`,
|
|
67
|
+
description: `Create new module \`${clusterName}/\` to group ${cluster.files.length} co-dependent files`,
|
|
68
|
+
content: `"""Module ${clusterName} — grouped by co-import pattern."""\n`,
|
|
69
|
+
});
|
|
70
|
+
// Move files
|
|
71
|
+
for (const file of cluster.files) {
|
|
72
|
+
const newPath = join(targetDir, basename(file));
|
|
73
|
+
operations.push({
|
|
74
|
+
type: 'MOVE',
|
|
75
|
+
path: file,
|
|
76
|
+
newPath,
|
|
77
|
+
description: `Move \`${basename(file)}\` → \`${clusterName}/${basename(file)}\``,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
steps.push({
|
|
81
|
+
id: 0,
|
|
82
|
+
tier: 1,
|
|
83
|
+
rule: this.name,
|
|
84
|
+
priority: 'MEDIUM',
|
|
85
|
+
title: `Group co-dependent files into \`${clusterName}/\``,
|
|
86
|
+
description: `Files ${cluster.files.map((f) => `\`${basename(f)}\``).join(', ')} ` +
|
|
87
|
+
`are frequently imported together (co-import score: ${cluster.coImportScore}). ` +
|
|
88
|
+
`Grouping them improves cohesion.`,
|
|
89
|
+
rationale: `Files that are frequently imported together belong in the same module. ` +
|
|
90
|
+
`This improves discoverability and reduces the cognitive load of understanding ` +
|
|
91
|
+
`which files work together.`,
|
|
92
|
+
operations,
|
|
93
|
+
scoreImpact: [
|
|
94
|
+
{ metric: 'cohesion', before: report.score.breakdown.cohesion, after: Math.min(95, report.score.breakdown.cohesion + 10) },
|
|
95
|
+
{ metric: 'modularity', before: report.score.breakdown.modularity, after: Math.min(95, report.score.breakdown.modularity + 5) },
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return steps;
|
|
100
|
+
}
|
|
101
|
+
suggestModuleName(files) {
|
|
102
|
+
// Try to infer a common theme from filenames
|
|
103
|
+
const names = files.map((f) => basename(f).replace(/\.[^.]+$/, '').toLowerCase());
|
|
104
|
+
const commonParts = names[0].split(/[_-]/).filter((part) => names.every((n) => n.includes(part)));
|
|
105
|
+
if (commonParts.length > 0)
|
|
106
|
+
return commonParts[0];
|
|
107
|
+
return 'shared';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=module-grouper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-grouper.js","sourceRoot":"","sources":["../../src/rules/module-grouper.ts"],"names":[],"mappings":"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"}
|
package/dist/scorer.d.ts
CHANGED
|
@@ -4,11 +4,23 @@ export declare class ArchitectureScorer {
|
|
|
4
4
|
private coupling;
|
|
5
5
|
private cohesion;
|
|
6
6
|
private layering;
|
|
7
|
+
/**
|
|
8
|
+
* Barrel/index files that naturally have many connections and should be
|
|
9
|
+
* excluded from coupling max-edge penalty calculations.
|
|
10
|
+
*/
|
|
11
|
+
private static readonly BARREL_FILES;
|
|
7
12
|
score(edges: DependencyEdge[], antiPatterns: AntiPattern[], totalFiles: number): ArchitectureScore;
|
|
8
13
|
private calculateModularity;
|
|
9
14
|
private calculateCoupling;
|
|
10
15
|
private findNodeWithMaxEdges;
|
|
11
16
|
private calculateCohesion;
|
|
17
|
+
/**
|
|
18
|
+
* Determines if a dependency is "internal" (cohesive).
|
|
19
|
+
* Two files are considered cohesive if they share the same top-level
|
|
20
|
+
* package/directory (e.g., deepguard/cli.py → deepguard/analyzer.py).
|
|
21
|
+
* This is crucial for Python flat packages where all files live in
|
|
22
|
+
* one directory but ARE cohesive.
|
|
23
|
+
*/
|
|
12
24
|
private isInternalDependency;
|
|
13
25
|
private calculateLayering;
|
|
14
26
|
}
|
package/dist/scorer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAkB,MAAM,YAAY,CAAC;AAG5F,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,QAAQ,CAAa;IAE7B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAGjC;IAEH,KAAK,CACH,KAAK,EAAE,cAAc,EAAE,EACvB,YAAY,EAAE,WAAW,EAAE,EAC3B,UAAU,EAAE,MAAM,GACjB,iBAAiB;IA2DpB,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,iBAAiB;IAwCzB,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,iBAAiB;IA4BzB;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,iBAAiB;CAsB1B"}
|
package/dist/scorer.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { basename } from 'path';
|
|
1
2
|
export class ArchitectureScorer {
|
|
2
3
|
constructor() {
|
|
3
4
|
this.modularity = 0;
|
|
@@ -78,27 +79,44 @@ export class ArchitectureScorer {
|
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
calculateCoupling(edges, totalFiles) {
|
|
81
|
-
if (totalFiles === 0) {
|
|
82
|
+
if (totalFiles === 0 || totalFiles === 1) {
|
|
82
83
|
this.coupling = 50;
|
|
83
84
|
return;
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
+
// Exclude barrel/index files from max-edge calculation —
|
|
87
|
+
// they naturally have many connections by design.
|
|
88
|
+
const nonBarrelEdges = edges.filter((e) => {
|
|
89
|
+
const fromFile = basename(e.from);
|
|
90
|
+
const toFile = basename(e.to);
|
|
91
|
+
return !ArchitectureScorer.BARREL_FILES.has(fromFile) &&
|
|
92
|
+
!ArchitectureScorer.BARREL_FILES.has(toFile);
|
|
93
|
+
});
|
|
94
|
+
const nodeWithMaxEdges = this.findNodeWithMaxEdges(nonBarrelEdges);
|
|
86
95
|
const maxEdgeCount = nodeWithMaxEdges ? nodeWithMaxEdges.count : 0;
|
|
87
|
-
|
|
88
|
-
|
|
96
|
+
// Use non-barrel file count for ratio calculation
|
|
97
|
+
const effectiveFiles = Math.max(totalFiles - 1, 1);
|
|
98
|
+
const couplingRatio = maxEdgeCount / effectiveFiles;
|
|
99
|
+
// More granular thresholds
|
|
100
|
+
if (couplingRatio < 0.15) {
|
|
89
101
|
this.coupling = 95;
|
|
90
102
|
}
|
|
91
|
-
else if (couplingRatio < 0.
|
|
103
|
+
else if (couplingRatio < 0.25) {
|
|
92
104
|
this.coupling = 85;
|
|
93
105
|
}
|
|
94
|
-
else if (couplingRatio < 0.
|
|
95
|
-
this.coupling =
|
|
106
|
+
else if (couplingRatio < 0.35) {
|
|
107
|
+
this.coupling = 75;
|
|
108
|
+
}
|
|
109
|
+
else if (couplingRatio < 0.5) {
|
|
110
|
+
this.coupling = 65;
|
|
96
111
|
}
|
|
97
|
-
else if (couplingRatio < 0.
|
|
112
|
+
else if (couplingRatio < 0.7) {
|
|
98
113
|
this.coupling = 50;
|
|
99
114
|
}
|
|
115
|
+
else if (couplingRatio < 0.85) {
|
|
116
|
+
this.coupling = 35;
|
|
117
|
+
}
|
|
100
118
|
else {
|
|
101
|
-
this.coupling =
|
|
119
|
+
this.coupling = 20;
|
|
102
120
|
}
|
|
103
121
|
}
|
|
104
122
|
findNodeWithMaxEdges(edges) {
|
|
@@ -124,26 +142,44 @@ export class ArchitectureScorer {
|
|
|
124
142
|
}
|
|
125
143
|
const internalEdges = edges.filter((e) => this.isInternalDependency(e.from, e.to)).length;
|
|
126
144
|
const cohesionRatio = internalEdges / edges.length;
|
|
127
|
-
|
|
145
|
+
// More granular thresholds
|
|
146
|
+
if (cohesionRatio > 0.8) {
|
|
128
147
|
this.cohesion = 95;
|
|
129
148
|
}
|
|
130
|
-
else if (cohesionRatio > 0.
|
|
131
|
-
this.cohesion =
|
|
149
|
+
else if (cohesionRatio > 0.6) {
|
|
150
|
+
this.cohesion = 85;
|
|
151
|
+
}
|
|
152
|
+
else if (cohesionRatio > 0.45) {
|
|
153
|
+
this.cohesion = 75;
|
|
132
154
|
}
|
|
133
155
|
else if (cohesionRatio > 0.3) {
|
|
134
156
|
this.cohesion = 65;
|
|
135
157
|
}
|
|
136
|
-
else if (cohesionRatio > 0.
|
|
137
|
-
this.cohesion =
|
|
158
|
+
else if (cohesionRatio > 0.15) {
|
|
159
|
+
this.cohesion = 50;
|
|
138
160
|
}
|
|
139
161
|
else {
|
|
140
162
|
this.cohesion = 30;
|
|
141
163
|
}
|
|
142
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Determines if a dependency is "internal" (cohesive).
|
|
167
|
+
* Two files are considered cohesive if they share the same top-level
|
|
168
|
+
* package/directory (e.g., deepguard/cli.py → deepguard/analyzer.py).
|
|
169
|
+
* This is crucial for Python flat packages where all files live in
|
|
170
|
+
* one directory but ARE cohesive.
|
|
171
|
+
*/
|
|
143
172
|
isInternalDependency(from, to) {
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
|
|
173
|
+
const fromParts = from.split('/');
|
|
174
|
+
const toParts = to.split('/');
|
|
175
|
+
// If both are in root (no directory), they're cohesive
|
|
176
|
+
if (fromParts.length <= 1 && toParts.length <= 1)
|
|
177
|
+
return true;
|
|
178
|
+
// Compare top-level directory (package name)
|
|
179
|
+
// e.g., "deepguard/cli.py" and "deepguard/analyzer.py" → same package
|
|
180
|
+
const fromTopLevel = fromParts.length > 1 ? fromParts[0] : '';
|
|
181
|
+
const toTopLevel = toParts.length > 1 ? toParts[0] : '';
|
|
182
|
+
return fromTopLevel === toTopLevel;
|
|
147
183
|
}
|
|
148
184
|
calculateLayering(antiPatterns) {
|
|
149
185
|
const layeringViolations = antiPatterns.filter((p) => p.name === 'Leaky Abstraction' ||
|
|
@@ -169,4 +205,12 @@ export class ArchitectureScorer {
|
|
|
169
205
|
}
|
|
170
206
|
}
|
|
171
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Barrel/index files that naturally have many connections and should be
|
|
210
|
+
* excluded from coupling max-edge penalty calculations.
|
|
211
|
+
*/
|
|
212
|
+
ArchitectureScorer.BARREL_FILES = new Set([
|
|
213
|
+
'__init__.py', 'index.ts', 'index.js', 'index.tsx', 'index.jsx',
|
|
214
|
+
'mod.rs', '__init__.pyi',
|
|
215
|
+
]);
|
|
172
216
|
//# sourceMappingURL=scorer.js.map
|
package/dist/scorer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -103,4 +103,55 @@ export interface ParsedImport {
|
|
|
103
103
|
isDefault: boolean;
|
|
104
104
|
isNamespace: boolean;
|
|
105
105
|
}
|
|
106
|
+
export interface RefactoringPlan {
|
|
107
|
+
timestamp: string;
|
|
108
|
+
projectPath: string;
|
|
109
|
+
currentScore: ArchitectureScore;
|
|
110
|
+
estimatedScoreAfter: {
|
|
111
|
+
overall: number;
|
|
112
|
+
breakdown: Record<string, number>;
|
|
113
|
+
};
|
|
114
|
+
steps: RefactorStep[];
|
|
115
|
+
totalOperations: number;
|
|
116
|
+
tier1Steps: number;
|
|
117
|
+
tier2Steps: number;
|
|
118
|
+
}
|
|
119
|
+
export interface RefactorStep {
|
|
120
|
+
id: number;
|
|
121
|
+
tier: 1 | 2;
|
|
122
|
+
rule: string;
|
|
123
|
+
priority: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW';
|
|
124
|
+
title: string;
|
|
125
|
+
description: string;
|
|
126
|
+
rationale: string;
|
|
127
|
+
operations: FileOperation[];
|
|
128
|
+
scoreImpact: {
|
|
129
|
+
metric: string;
|
|
130
|
+
before: number;
|
|
131
|
+
after: number;
|
|
132
|
+
}[];
|
|
133
|
+
codePreview?: string;
|
|
134
|
+
}
|
|
135
|
+
export interface FileOperation {
|
|
136
|
+
type: 'CREATE' | 'MOVE' | 'MODIFY' | 'DELETE';
|
|
137
|
+
path: string;
|
|
138
|
+
newPath?: string;
|
|
139
|
+
content?: string;
|
|
140
|
+
diff?: string;
|
|
141
|
+
description: string;
|
|
142
|
+
}
|
|
143
|
+
export interface CodeSymbol {
|
|
144
|
+
name: string;
|
|
145
|
+
type: 'function' | 'class' | 'variable' | 'import' | 'export';
|
|
146
|
+
startLine: number;
|
|
147
|
+
endLine: number;
|
|
148
|
+
lines: number;
|
|
149
|
+
dependencies: string[];
|
|
150
|
+
usedBy: string[];
|
|
151
|
+
}
|
|
152
|
+
export interface RefactorRule {
|
|
153
|
+
name: string;
|
|
154
|
+
tier: 1 | 2;
|
|
155
|
+
analyze(report: AnalysisReport, projectPath: string): RefactorStep[];
|
|
156
|
+
}
|
|
106
157
|
//# sourceMappingURL=types.d.ts.map
|