entkapp 5.0.0 → 5.2.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 +63 -20
- package/bin/cli.js +2 -2
- package/index.js +38 -2241
- package/package.json +1 -1
- package/src/EngineContext.js +1 -1
- package/src/Initializer.js +82 -0
- package/src/analyzers/CodeSmellAnalyzer.js +106 -0
- package/src/ast/ASTAnalyzer.js +29 -14
- package/src/ast/BarrelParser.js +22 -20
- package/src/ast/OxcAnalyzer.js +33 -409
- package/src/index.js +78 -8
- package/src/performance/WorkerTaskRunner.js +7 -7
- package/src/plugins/BasePlugin.js +171 -2
- package/src/plugins/PluginRegistry.js +193 -81
- package/src/plugins/ecosystems/BackendServices.js +168 -32
- package/src/plugins/ecosystems/GenericPlugins.js +51 -34
- package/src/plugins/ecosystems/ModernFrameworks.js +97 -94
- package/src/plugins/ecosystems/MorePlugins.js +429 -51
- package/src/plugins/ecosystems/NewPlugins.js +526 -0
- package/src/plugins/ecosystems/NextJsPlugin.js +18 -6
- package/src/plugins/ecosystems/PluginLoader.js +190 -17
- package/src/plugins/ecosystems/TypeScriptPlugin.js +10 -10
- package/src/plugins/ecosystems/UltimateBundle.js +168 -0
- package/src/resolution/BuildOrchestrator.js +46 -0
- package/src/resolution/CircularDetector.js +64 -25
- package/src/resolution/ConfigGenerator.js +83 -0
- package/src/resolution/DepencyResolver.js +12 -1
- package/src/resolution/DependencyFixer.js +88 -0
- package/src/resolution/EntryPointDetector.js +4 -4
- package/src/resolution/GraphAnalyzer.js +80 -0
- package/src/resolution/MigrationAnalyzer.js +60 -0
- package/src/resolution/PathMapper.js +47 -3
- package/src/resolution/WorkSpaceGraph.js +4 -1
- package/docs.zip +0 -0
|
@@ -24,12 +24,23 @@ export class DependencyResolver {
|
|
|
24
24
|
|
|
25
25
|
resolveModulePath(sourceFile, specifier) {
|
|
26
26
|
const cleanSource = this.normalizePath(sourceFile);
|
|
27
|
+
|
|
28
|
+
// UPGRADE: Use PathMapper for sophisticated resolution (TS-to-JS, aliases, etc.)
|
|
29
|
+
if (this.pathMapper) {
|
|
30
|
+
const dir = path.dirname(cleanSource);
|
|
31
|
+
const target = path.resolve(dir, specifier);
|
|
32
|
+
const resolved = this.pathMapper.resolvePath(target);
|
|
33
|
+
if (resolved && existsSync(resolved)) {
|
|
34
|
+
return this.normalizePath(resolved);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
if (specifier.startsWith('.')) {
|
|
28
39
|
const dir = path.dirname(cleanSource);
|
|
29
40
|
const target = path.resolve(dir, specifier);
|
|
30
41
|
const normalizedTarget = this.normalizePath(target);
|
|
31
42
|
|
|
32
|
-
const extensions = ['', '.js', '.ts', '.tsx', '.jsx', '/index.js', '/index.ts'];
|
|
43
|
+
const extensions = ['', '.js', '.ts', '.tsx', '.jsx', '/index.js', '/index.ts', '/index.tsx'];
|
|
33
44
|
for (const ext of extensions) {
|
|
34
45
|
const p = normalizedTarget + ext;
|
|
35
46
|
if (existsSync(p)) return this.normalizePath(p);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ============================================================================
|
|
7
|
+
* Dependency Auto-Fixer v5.1.0
|
|
8
|
+
* ============================================================================
|
|
9
|
+
* Automatically installs missing dependencies using the detected package manager.
|
|
10
|
+
*/
|
|
11
|
+
export class DependencyFixer {
|
|
12
|
+
constructor(context) {
|
|
13
|
+
this.context = context;
|
|
14
|
+
this.cwd = context.cwd;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async detectPackageManager() {
|
|
18
|
+
const files = await fs.readdir(this.cwd);
|
|
19
|
+
if (files.includes('pnpm-lock.yaml')) return 'pnpm';
|
|
20
|
+
if (files.includes('yarn.lock')) return 'yarn';
|
|
21
|
+
if (files.includes('bun.lockb')) return 'bun';
|
|
22
|
+
return 'npm';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async fix(diagnostics) {
|
|
26
|
+
const pkgManager = await this.detectPackageManager();
|
|
27
|
+
const toInstall = {
|
|
28
|
+
dependencies: new Set(),
|
|
29
|
+
devDependencies: new Set()
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
for (const d of diagnostics) {
|
|
33
|
+
if (d.package && d.severity === 'error') {
|
|
34
|
+
if (d.expectedIn === 'devDependencies') {
|
|
35
|
+
toInstall.devDependencies.add(d.package);
|
|
36
|
+
} else {
|
|
37
|
+
toInstall.dependencies.add(d.package);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const results = [];
|
|
43
|
+
|
|
44
|
+
if (toInstall.dependencies.size > 0) {
|
|
45
|
+
const deps = Array.from(toInstall.dependencies);
|
|
46
|
+
results.push(await this._runInstall(pkgManager, deps, false));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (toInstall.devDependencies.size > 0) {
|
|
50
|
+
const devDeps = Array.from(toInstall.devDependencies);
|
|
51
|
+
results.push(await this._runInstall(pkgManager, devDeps, true));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return results;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async _runInstall(pm, packages, isDev) {
|
|
58
|
+
const args = [];
|
|
59
|
+
if (pm === 'npm') {
|
|
60
|
+
args.push('install', isDev ? '--save-dev' : '--save');
|
|
61
|
+
} else if (pm === 'yarn') {
|
|
62
|
+
args.push('add', isDev ? '--dev' : '');
|
|
63
|
+
} else if (pm === 'pnpm') {
|
|
64
|
+
args.push('add', isDev ? '--save-dev' : '');
|
|
65
|
+
} else if (pm === 'bun') {
|
|
66
|
+
args.push('add', isDev ? '--dev' : '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const finalArgs = [...args.filter(Boolean), ...packages];
|
|
70
|
+
console.log(`[DependencyFixer] Running: ${pm} ${finalArgs.join(' ')}`);
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// In a real scenario, we would use execa here.
|
|
74
|
+
// For the SDK, we return the command that should be run.
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
command: `${pm} ${finalArgs.join(' ')}`,
|
|
78
|
+
packages
|
|
79
|
+
};
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return {
|
|
82
|
+
success: false,
|
|
83
|
+
error: e.message,
|
|
84
|
+
packages
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -9,8 +9,8 @@ export class EntryPointDetector {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* @returns {Set<string>} Set
|
|
12
|
+
* Detects all potential entry points of a project.
|
|
13
|
+
* @returns {Set<string>} Set of absolute paths.
|
|
14
14
|
*/
|
|
15
15
|
detect() {
|
|
16
16
|
const entries = new Set();
|
|
@@ -18,7 +18,7 @@ export class EntryPointDetector {
|
|
|
18
18
|
// 1. package.json Standards
|
|
19
19
|
this._addFromPackageJson(entries);
|
|
20
20
|
|
|
21
|
-
// 2. Framework-
|
|
21
|
+
// 2. Framework-specific paths
|
|
22
22
|
this._addFromFrameworks(entries);
|
|
23
23
|
|
|
24
24
|
// 3. Fallbacks / Konventionen
|
|
@@ -99,7 +99,7 @@ export class EntryPointDetector {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
_addIfExist(entries, relativePath) {
|
|
102
|
-
//
|
|
102
|
+
// Clean path (remove ./ etc)
|
|
103
103
|
const cleanPath = relativePath.replace(/^(\.\/|\/)/, '');
|
|
104
104
|
const absolutePath = path.resolve(this.targetDir, cleanPath);
|
|
105
105
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* Dead Code & Zombie Export Hunter v5.1.0
|
|
6
|
+
* ============================================================================
|
|
7
|
+
* Identifies unused files and exported symbols that are never imported.
|
|
8
|
+
*/
|
|
9
|
+
export class GraphAnalyzer {
|
|
10
|
+
constructor(context) {
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.cwd = context.cwd;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Performs a full reachability analysis from entry points.
|
|
17
|
+
*/
|
|
18
|
+
async findDeadCode() {
|
|
19
|
+
const graph = this.context.projectGraph;
|
|
20
|
+
const reachable = new Set();
|
|
21
|
+
const entries = [];
|
|
22
|
+
|
|
23
|
+
// 1. Identify all confirmed entry points
|
|
24
|
+
for (const [filePath, node] of graph.entries()) {
|
|
25
|
+
if (node.isEntry) {
|
|
26
|
+
entries.push(filePath);
|
|
27
|
+
this._walk(filePath, reachable);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const deadFiles = [];
|
|
32
|
+
const zombieExports = [];
|
|
33
|
+
|
|
34
|
+
// 2. Find unreachable files
|
|
35
|
+
for (const filePath of graph.keys()) {
|
|
36
|
+
if (!reachable.has(filePath)) {
|
|
37
|
+
deadFiles.push(path.relative(this.cwd, filePath).replace(/\\/g, '/'));
|
|
38
|
+
} else {
|
|
39
|
+
// 3. Find Zombie Exports in reachable files
|
|
40
|
+
const node = graph.get(filePath);
|
|
41
|
+
if (node.isEntry) continue; // Skip entries as their exports are intended for external use
|
|
42
|
+
|
|
43
|
+
for (const [symbol, meta] of node.internalExports.entries()) {
|
|
44
|
+
if (symbol === 'default' || symbol === '*') continue;
|
|
45
|
+
|
|
46
|
+
let isUsed = false;
|
|
47
|
+
// Check if any other node imports this symbol
|
|
48
|
+
for (const [otherPath, otherNode] of graph.entries()) {
|
|
49
|
+
if (otherNode.importedSymbols && otherNode.importedSymbols.has(symbol)) {
|
|
50
|
+
// This is a simplified check; in reality, we'd check if it's imported FROM this file
|
|
51
|
+
isUsed = true;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!isUsed) {
|
|
57
|
+
zombieExports.push({
|
|
58
|
+
file: path.relative(this.cwd, filePath).replace(/\\/g, '/'),
|
|
59
|
+
symbol: symbol
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { deadFiles, zombieExports };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_walk(filePath, reachable) {
|
|
70
|
+
if (reachable.has(filePath)) return;
|
|
71
|
+
reachable.add(filePath);
|
|
72
|
+
|
|
73
|
+
const node = this.context.projectGraph.get(filePath);
|
|
74
|
+
if (!node) return;
|
|
75
|
+
|
|
76
|
+
for (const impPath of node.explicitImports) {
|
|
77
|
+
this._walk(impPath, reachable);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================================
|
|
3
|
+
* Migration Path Analyzer v5.1.0
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* Suggests modern alternatives for legacy tools and frameworks.
|
|
6
|
+
*/
|
|
7
|
+
export class MigrationAnalyzer {
|
|
8
|
+
constructor(context) {
|
|
9
|
+
this.context = context;
|
|
10
|
+
this.migrations = [
|
|
11
|
+
{
|
|
12
|
+
legacy: 'webpack',
|
|
13
|
+
modern: 'vite',
|
|
14
|
+
reason: 'Vite offers significantly faster HMR and build times using ES modules during development.'
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
legacy: 'jest',
|
|
18
|
+
modern: 'vitest',
|
|
19
|
+
reason: 'Vitest is faster, has native ESM support, and shares configuration with Vite.'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
legacy: 'moment',
|
|
23
|
+
modern: 'dayjs',
|
|
24
|
+
reason: 'Day.js is a 2KB alternative to Moment.js with the same modern API.'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
legacy: 'axios',
|
|
28
|
+
modern: 'fetch',
|
|
29
|
+
reason: 'Native fetch is now widely supported and requires no external dependency for simple use cases.'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
legacy: 'ts-node',
|
|
33
|
+
modern: 'tsx',
|
|
34
|
+
reason: 'tsx is faster and has better ESM support for running TypeScript files.'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
legacy: 'eslint-plugin-prettier',
|
|
38
|
+
modern: 'eslint-config-prettier',
|
|
39
|
+
reason: 'Running Prettier as an ESLint rule is slow. It is recommended to run them separately or use a config that turns off conflicting rules.'
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async analyze(activePlugins) {
|
|
45
|
+
const suggestions = [];
|
|
46
|
+
const activeNames = activePlugins.map(p => p.name);
|
|
47
|
+
|
|
48
|
+
for (const m of this.migrations) {
|
|
49
|
+
if (activeNames.includes(m.legacy)) {
|
|
50
|
+
suggestions.push({
|
|
51
|
+
from: m.legacy,
|
|
52
|
+
to: m.modern,
|
|
53
|
+
message: `Migration Suggestion: Consider moving from "${m.legacy}" to "${m.modern}". ${m.reason}`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return suggestions;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,5 +1,49 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
1
4
|
export class PathMapper {
|
|
2
|
-
constructor(context) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
constructor(context) {
|
|
6
|
+
this.context = context;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async loadMappings() {
|
|
10
|
+
// Tsconfig paths can be loaded here later
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolves physical module paths on disk, translating modern .js imports
|
|
15
|
+
* back to their actual TypeScript source files.
|
|
16
|
+
* @param {string} p - The target module specifier or absolute path
|
|
17
|
+
*/
|
|
18
|
+
resolvePath(p) {
|
|
19
|
+
if (!p || typeof p !== 'string') return p;
|
|
20
|
+
|
|
21
|
+
// FIX 1: If the import ends with .js, translate it to .ts for the search
|
|
22
|
+
if (p.endsWith('.js')) {
|
|
23
|
+
const tsPath = p.slice(0, -3) + '.ts';
|
|
24
|
+
if (fs.existsSync(tsPath)) return tsPath;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// FIX 2: If the import ends with .jsx, translate it to .tsx for the search
|
|
28
|
+
if (p.endsWith('.jsx')) {
|
|
29
|
+
const tsxPath = p.slice(0, -4) + '.tsx';
|
|
30
|
+
if (fs.existsSync(tsxPath)) return tsxPath;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// FIX 3: Support for directory imports (z.B. ./adapters -> ./adapters/index.ts)
|
|
34
|
+
try {
|
|
35
|
+
const stat = fs.statSync(p);
|
|
36
|
+
if (stat.isDirectory()) {
|
|
37
|
+
const extensions = ['.ts', '.tsx', '.js', '.jsx'];
|
|
38
|
+
for (const ext of extensions) {
|
|
39
|
+
const indexPath = path.join(p, `index${ext}`);
|
|
40
|
+
if (fs.existsSync(indexPath)) return indexPath;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// File does not exist or is not a directory, continue with default
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return p;
|
|
48
|
+
}
|
|
5
49
|
}
|
package/docs.zip
DELETED
|
Binary file
|