entkapp 5.2.4 → 5.3.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/README.md +30 -37
- package/bin/cli.js +3 -3
- package/entkapp/config.json +18 -2
- package/entkapp/plugins/README.md +52 -12
- package/package.json +2 -2
- package/schema.json +87 -3
- package/src/ast/SecretScanner.js +112 -50
- package/src/index.js +36 -1
- package/src/resolution/ConfigLoader.js +88 -2
- package/src/resolution/DepencyResolver.js +15 -0
- package/src/resolution/DependencyProfiler.js +41 -23
- package/src/resolution/PathMapper.js +42 -9
- package/src/resolution/TSConfigLoader.js +96 -10
- package/src/resolution/WorkSpaceGraph.js +178 -3
- package/src/resolution/WorkspaceDiagnostic.js +137 -3
|
@@ -1,5 +1,139 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WorkspaceDiagnostic
|
|
6
|
+
* Performs health checks and architectural boundary enforcement for Monorepo workspaces.
|
|
7
|
+
* Detects cross-package import violations, version mismatches, and missing workspace declarations.
|
|
8
|
+
*/
|
|
1
9
|
export class WorkspaceDiagnostic {
|
|
2
|
-
constructor(context) {
|
|
3
|
-
|
|
4
|
-
|
|
10
|
+
constructor(context) {
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.findings = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async checkWorkspaceHealth() {
|
|
16
|
+
this.findings = [];
|
|
17
|
+
|
|
18
|
+
if (!this.context.isWorkspaceEnabled) return this.findings;
|
|
19
|
+
|
|
20
|
+
const rootPkgPath = this.context.cwd ? path.join(this.context.cwd, 'package.json') : null;
|
|
21
|
+
let rootPkg = {};
|
|
22
|
+
try {
|
|
23
|
+
if (rootPkgPath) rootPkg = JSON.parse(await fs.readFile(rootPkgPath, 'utf8'));
|
|
24
|
+
} catch (e) {}
|
|
25
|
+
|
|
26
|
+
// 1. Check for version mismatches across workspace packages
|
|
27
|
+
const versionMap = new Map(); // dep name -> { version, source }
|
|
28
|
+
for (const [dir, manifest] of (this.context.monorepoPackageRoots || new Set()).entries ? [] : (this.context.monorepoPackageRoots || [])) {
|
|
29
|
+
// iterate over monorepoPackageRoots as a Set
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Use workspaceGraph if available
|
|
33
|
+
if (this.context.workspaceGraph && this.context.workspaceGraph.packageManifests) {
|
|
34
|
+
for (const [dir, manifest] of this.context.workspaceGraph.packageManifests.entries()) {
|
|
35
|
+
const allDeps = {
|
|
36
|
+
...manifest.dependencies,
|
|
37
|
+
...manifest.devDependencies
|
|
38
|
+
};
|
|
39
|
+
for (const [dep, version] of Object.entries(allDeps)) {
|
|
40
|
+
if (!versionMap.has(dep)) {
|
|
41
|
+
versionMap.set(dep, []);
|
|
42
|
+
}
|
|
43
|
+
versionMap.get(dep).push({ version, source: manifest.name || dir });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Report version mismatches
|
|
48
|
+
for (const [dep, usages] of versionMap.entries()) {
|
|
49
|
+
const uniqueVersions = new Set(usages.map(u => u.version));
|
|
50
|
+
if (uniqueVersions.size > 1) {
|
|
51
|
+
this.findings.push({
|
|
52
|
+
type: 'version-mismatch',
|
|
53
|
+
severity: 'warning',
|
|
54
|
+
message: `Dependency "${dep}" has conflicting versions across workspace packages: ${[...uniqueVersions].join(', ')}`,
|
|
55
|
+
packages: usages.map(u => u.source)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 2. Check for missing workspace package declarations in root
|
|
61
|
+
for (const [dir, manifest] of this.context.workspaceGraph.packageManifests.entries()) {
|
|
62
|
+
if (!manifest.name) continue;
|
|
63
|
+
const rootDeps = {
|
|
64
|
+
...rootPkg.dependencies,
|
|
65
|
+
...rootPkg.devDependencies,
|
|
66
|
+
...rootPkg.peerDependencies
|
|
67
|
+
};
|
|
68
|
+
// If the workspace package is referenced in root deps but not as "workspace:*"
|
|
69
|
+
if (rootDeps[manifest.name] && !rootDeps[manifest.name].startsWith('workspace:')) {
|
|
70
|
+
this.findings.push({
|
|
71
|
+
type: 'workspace-declaration-missing',
|
|
72
|
+
severity: 'info',
|
|
73
|
+
message: `Workspace package "${manifest.name}" is referenced in root package.json without "workspace:" protocol`,
|
|
74
|
+
packages: ['root', manifest.name]
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 3. Check for packages that have no entry points defined
|
|
80
|
+
for (const [dir, manifest] of this.context.workspaceGraph.packageManifests.entries()) {
|
|
81
|
+
if (!manifest.entryPoints || manifest.entryPoints.length === 0) {
|
|
82
|
+
this.findings.push({
|
|
83
|
+
type: 'missing-entry-point',
|
|
84
|
+
severity: 'warning',
|
|
85
|
+
message: `Workspace package "${manifest.name || dir}" has no entry points (main/module/exports) defined in package.json`,
|
|
86
|
+
packages: [manifest.name || dir]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this.findings;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
enforceBoundaries(filePath, imports) {
|
|
96
|
+
const violations = [];
|
|
97
|
+
if (!this.context.isWorkspaceEnabled) return violations;
|
|
98
|
+
if (!this.context.workspaceGraph || !this.context.workspaceGraph.packageManifests) return violations;
|
|
99
|
+
|
|
100
|
+
// Determine which workspace package this file belongs to
|
|
101
|
+
let sourcePackage = null;
|
|
102
|
+
for (const [dir, manifest] of this.context.workspaceGraph.packageManifests.entries()) {
|
|
103
|
+
if (filePath.startsWith(dir + '/') || filePath.startsWith(dir + '\\')) {
|
|
104
|
+
sourcePackage = manifest;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!sourcePackage) return violations;
|
|
110
|
+
|
|
111
|
+
// Check each import
|
|
112
|
+
for (const specifier of imports) {
|
|
113
|
+
if (!specifier || specifier.startsWith('.') || specifier.startsWith('/')) continue;
|
|
114
|
+
|
|
115
|
+
// Check if the import is a workspace package
|
|
116
|
+
if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier)) {
|
|
117
|
+
const targetManifest = this.context.workspaceGraph.getWorkspacePackageMatch(specifier);
|
|
118
|
+
if (targetManifest && targetManifest.name) {
|
|
119
|
+
// Check if the target package is declared as a dependency of the source package
|
|
120
|
+
const sourceDeps = {
|
|
121
|
+
...sourcePackage.dependencies,
|
|
122
|
+
...sourcePackage.devDependencies,
|
|
123
|
+
...sourcePackage.peerDependencies
|
|
124
|
+
};
|
|
125
|
+
if (!sourceDeps[targetManifest.name]) {
|
|
126
|
+
violations.push({
|
|
127
|
+
type: 'undeclared-workspace-dependency',
|
|
128
|
+
severity: 'error',
|
|
129
|
+
message: `Package "${sourcePackage.name}" imports "${specifier}" but "${targetManifest.name}" is not declared as a dependency`,
|
|
130
|
+
file: filePath
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return violations;
|
|
138
|
+
}
|
|
5
139
|
}
|