entkapp 4.1.0 ā 4.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 +15 -2
- package/bin/cli.js +2 -2
- package/index.js +5 -5
- package/logo.png +0 -0
- package/package.json +7 -2
- package/src/api/HeadlessAPI.js +1 -1
- package/src/api/PluginSDK.js +1 -1
- package/src/ast/BarrelParser.js +1 -19
- package/src/ast/OxcAnalyzer.js +89 -83
- package/src/index.js +81 -55
- package/src/performance/WorkerTaskRunner.js +87 -0
- package/src/plugins/ecosystems/BackendServices.js +1 -1
- package/src/plugins/ecosystems/ModernFrameworks.js +1 -1
package/README.md
CHANGED
|
@@ -28,6 +28,19 @@ It represents the process of stripping away the unnecessary layers of a codebase
|
|
|
28
28
|
## š¦ Installation
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
npm install -
|
|
31
|
+
npm install -g entkapp
|
|
32
32
|
# or
|
|
33
|
-
pnpm add -
|
|
33
|
+
pnpm add -g entkapp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
```bash
|
|
38
|
+
npx entkapp
|
|
39
|
+
# or
|
|
40
|
+
entkapp
|
|
41
|
+
# and then
|
|
42
|
+
npx entkapp -r
|
|
43
|
+
# or
|
|
44
|
+
entkapp -r
|
|
45
|
+
# It is recommended to run with --no-fix tag on your first run!
|
|
46
|
+
```
|
package/bin/cli.js
CHANGED
|
@@ -28,7 +28,7 @@ async function bootstrap() {
|
|
|
28
28
|
program
|
|
29
29
|
.name('entkapp')
|
|
30
30
|
.description(ansis.cyan('Enterprise-Grade AST Syntax Refactoring & Self-Healing Engine'))
|
|
31
|
-
.version(packageJsonContent.version || '4.
|
|
31
|
+
.version(packageJsonContent.version || '4.2.0');
|
|
32
32
|
|
|
33
33
|
program
|
|
34
34
|
.option('-c, --cwd <path>', 'Specify the execution context root directory', process.cwd())
|
|
@@ -132,7 +132,7 @@ async function bootstrap() {
|
|
|
132
132
|
}, timeoutMs);
|
|
133
133
|
timeoutTimer.unref(); // Allow process to exit if work finishes
|
|
134
134
|
|
|
135
|
-
console.log(ansis.bold.green(`\nš¦ entkapp v${packageJsonContent.version || '4.
|
|
135
|
+
console.log(ansis.bold.green(`\nš¦ entkapp v${packageJsonContent.version || '4.2.0'} Engine Activation`));
|
|
136
136
|
console.log(ansis.dim('------------------------------------------------------------'));
|
|
137
137
|
console.log(`${ansis.bold('Target Workspace Root :')} ${ansis.blue(targetCwd)}`);
|
|
138
138
|
console.log(`${ansis.bold('Refactoring Mode :')} ${options.fix ? ansis.yellow('Active Fixing & Self-Healing Enabled') : ansis.gray('Dry-Run Reporting Only')}`);
|
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* ============================================================================
|
|
5
|
-
* š¦ entkapp v4.
|
|
5
|
+
* š¦ entkapp v4.2.0: Ultimate Enterprise Codebase Janitor & Self-Healing Engine
|
|
6
6
|
* ============================================================================
|
|
7
7
|
* * Eine hochgradig integrierte Code-Analyse- und Projektbootstrapping-Engine.
|
|
8
8
|
* Kombiniert rekursive Erreichbarkeitsanalysen (Reachability Graphs) auf
|
|
@@ -648,7 +648,7 @@ function smartPrepend(originalCode, declarationBlock) {
|
|
|
648
648
|
async function inspectNpmPackage(pkgName) {
|
|
649
649
|
try {
|
|
650
650
|
const response = await fetch(`https://registry.npmjs.org/${pkgName}/latest`, {
|
|
651
|
-
headers: { 'User-Agent': 'entkapp-dx-client/4.
|
|
651
|
+
headers: { 'User-Agent': 'entkapp-dx-client/4.2.0' },
|
|
652
652
|
signal: AbortSignal.timeout(4000)
|
|
653
653
|
});
|
|
654
654
|
if (response.status === 200) {
|
|
@@ -682,7 +682,7 @@ async function inspectNpmPackage(pkgName) {
|
|
|
682
682
|
async function fetchRemoteLicense(licenseKey) {
|
|
683
683
|
try {
|
|
684
684
|
const response = await fetch(`https://api.github.com/licenses/${licenseKey.toLowerCase()}`, {
|
|
685
|
-
headers: { 'User-Agent': 'entkapp-dx-client/4.
|
|
685
|
+
headers: { 'User-Agent': 'entkapp-dx-client/4.2.0' },
|
|
686
686
|
signal: AbortSignal.timeout(5000)
|
|
687
687
|
});
|
|
688
688
|
if (response.status === 200) {
|
|
@@ -1681,7 +1681,7 @@ function postProcessAnalysis(stats, graphEngine) {
|
|
|
1681
1681
|
// ============================================================
|
|
1682
1682
|
async function main() {
|
|
1683
1683
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
1684
|
-
console.log(`\nš¦ entkapp v4.
|
|
1684
|
+
console.log(`\nš¦ entkapp v4.2.0: Advanced Dependency Intelligence Engine\n`);
|
|
1685
1685
|
console.log(`Usage: npx entkapp [options]\n`);
|
|
1686
1686
|
console.log(`Options:`);
|
|
1687
1687
|
console.log(` -h, --help Show this comprehensive workspace helper panel`);
|
|
@@ -1766,7 +1766,7 @@ async function main() {
|
|
|
1766
1766
|
let detectedFrameworks = [];
|
|
1767
1767
|
|
|
1768
1768
|
console.log(`\n${'ā'.repeat(67)}`);
|
|
1769
|
-
console.log(`š entkapp v4.
|
|
1769
|
+
console.log(`š entkapp v4.2.0: Enterprise Graph Intelligence Analyzer`);
|
|
1770
1770
|
console.log(`${'ā'.repeat(67)}\n`);
|
|
1771
1771
|
|
|
1772
1772
|
const topLevelItems = fs.readdirSync(targetDir);
|
package/logo.png
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"name": "entkapp",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.2.0",
|
|
5
5
|
"description": "The Ultimate Enterprise Codebase Janitor. Faster than Knip with OXC integration, type-aware analysis, and automated structural healing. Fully standalone - solving what Knip cannot.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
@@ -64,7 +64,12 @@
|
|
|
64
64
|
"unresolved",
|
|
65
65
|
"unused",
|
|
66
66
|
"unused-packages",
|
|
67
|
-
"workspace"
|
|
67
|
+
"workspace",
|
|
68
|
+
"entkapp",
|
|
69
|
+
"cut",
|
|
70
|
+
"kapp",
|
|
71
|
+
"dreamlong",
|
|
72
|
+
"DreamLong"
|
|
68
73
|
],
|
|
69
74
|
"author": "DreamLongYT",
|
|
70
75
|
"license": "Apache-2.0",
|
package/src/api/HeadlessAPI.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================================
|
|
3
|
-
* Headless API for entkapp v4.
|
|
3
|
+
* Headless API for entkapp v4.2.0
|
|
4
4
|
* ============================================================================
|
|
5
5
|
* Provides a programmatic interface for integrating entkapp into
|
|
6
6
|
* custom workflows, CI/CD pipelines, and third-party tools.
|
package/src/api/PluginSDK.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================================
|
|
3
|
-
* Plugin SDK for entkapp v4.
|
|
3
|
+
* Plugin SDK for entkapp v4.2.0
|
|
4
4
|
* ============================================================================
|
|
5
5
|
* Provides utilities and helpers for developing custom plugins that extend
|
|
6
6
|
* entkapp's analysis and healing capabilities.
|
package/src/ast/BarrelParser.js
CHANGED
|
@@ -178,15 +178,6 @@ export class BarrelParser {
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
// Rule D: Sweep through anonymous star re-exports vectors (export * from 'module')
|
|
181
|
-
//
|
|
182
|
-
// Algorithm:
|
|
183
|
-
// 1. For each `export * from './child'`, recursively resolve the symbol in the child.
|
|
184
|
-
// 2. A non-barrel child immediately returns `{ originFile: childPath }` regardless of
|
|
185
|
-
// whether it actually declares the symbol. We therefore must verify that the
|
|
186
|
-
// returned origin file actually contains the symbol in its declaredLocalExports
|
|
187
|
-
// before accepting the result.
|
|
188
|
-
// 3. If the child is itself a barrel, the recursive call already performs the full
|
|
189
|
-
// chain walk, so we only need to verify the final origin.
|
|
190
181
|
for (const relativePath of spec.wildcardExports) {
|
|
191
182
|
const fullyResolvedPath = this.resolver.resolveModulePath(contextFilePath, relativePath);
|
|
192
183
|
|
|
@@ -195,24 +186,15 @@ export class BarrelParser {
|
|
|
195
186
|
fullyResolvedPath,
|
|
196
187
|
targetSymbolName,
|
|
197
188
|
activeProjectGraph,
|
|
198
|
-
new Set(protectionStack)
|
|
189
|
+
new Set(protectionStack)
|
|
199
190
|
);
|
|
200
191
|
|
|
201
192
|
if (!continuousResolutionTrace) continue;
|
|
202
|
-
if (continuousResolutionTrace.originFile === contextFilePath) continue;
|
|
203
193
|
|
|
204
|
-
// Verify that the resolved origin actually declares the symbol.
|
|
205
|
-
// This prevents a non-barrel sibling (e.g. constants.ts) from being
|
|
206
|
-
// incorrectly returned for a symbol it does not export (e.g. formatData).
|
|
207
194
|
const originSpec = await this.parseBarrelSpecification(continuousResolutionTrace.originFile);
|
|
208
195
|
if (originSpec.declaredLocalExports.has(continuousResolutionTrace.originSymbol)) {
|
|
209
196
|
return continuousResolutionTrace;
|
|
210
197
|
}
|
|
211
|
-
// The origin spec is itself a barrel (isBarrelInstance = true) and the
|
|
212
|
-
// recursive call already resolved through it ā accept the result.
|
|
213
|
-
if (originSpec.isBarrelInstance) {
|
|
214
|
-
return continuousResolutionTrace;
|
|
215
|
-
}
|
|
216
198
|
}
|
|
217
199
|
}
|
|
218
200
|
|
package/src/ast/OxcAnalyzer.js
CHANGED
|
@@ -3,20 +3,17 @@ export class OxcAnalyzer {
|
|
|
3
3
|
this.context = context;
|
|
4
4
|
this.oxc = null;
|
|
5
5
|
this.isAvailable = false;
|
|
6
|
-
// Initialization is handled via init() or lazily during parseFile
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
async init() {
|
|
10
9
|
if (this.isAvailable) return true;
|
|
11
10
|
try {
|
|
12
|
-
// In ESM, we use dynamic import()
|
|
13
11
|
const oxc = await import("oxc-parser");
|
|
14
12
|
this.oxc = oxc;
|
|
15
13
|
this.isAvailable = true;
|
|
16
14
|
return true;
|
|
17
15
|
} catch (e) {
|
|
18
16
|
try {
|
|
19
|
-
// Fallback for older node versions or specific bundling setups
|
|
20
17
|
const { createRequire } = await import('module');
|
|
21
18
|
const require = createRequire(import.meta.url);
|
|
22
19
|
this.oxc = require("oxc-parser");
|
|
@@ -25,7 +22,7 @@ export class OxcAnalyzer {
|
|
|
25
22
|
} catch (err) {
|
|
26
23
|
this.isAvailable = false;
|
|
27
24
|
if (this.context.verbose) {
|
|
28
|
-
console.warn("[OxcAnalyzer] oxc-parser not found or failed to load
|
|
25
|
+
console.warn("[OxcAnalyzer] oxc-parser not found or failed to load.");
|
|
29
26
|
}
|
|
30
27
|
return false;
|
|
31
28
|
}
|
|
@@ -39,24 +36,18 @@ export class OxcAnalyzer {
|
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
try {
|
|
42
|
-
if (this.context.verbose) {
|
|
43
|
-
console.log(`[OXC] Fast-parsing: ${filePath}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
39
|
const ast = this.oxc.parseSync(content, {
|
|
47
40
|
sourceType: "module",
|
|
48
41
|
sourceFilename: filePath,
|
|
49
42
|
ecmaVersion: "latest",
|
|
50
43
|
});
|
|
51
44
|
|
|
52
|
-
// Initialize new properties for JSX and Decorator analysis
|
|
53
45
|
fileNode.jsxComponents = new Set();
|
|
54
46
|
fileNode.jsxProps = new Set();
|
|
55
47
|
fileNode.decorators = new Set();
|
|
56
48
|
|
|
57
49
|
this.walkOxcAst(ast.program, fileNode, content);
|
|
58
50
|
|
|
59
|
-
// Compute line/column for each export start position
|
|
60
51
|
const lines = content.split('\n');
|
|
61
52
|
const getLineCol = (pos) => {
|
|
62
53
|
let count = 0;
|
|
@@ -100,19 +91,17 @@ export class OxcAnalyzer {
|
|
|
100
91
|
this.handleCallExpression(node, fileNode);
|
|
101
92
|
break;
|
|
102
93
|
case "JSXElement":
|
|
103
|
-
case "JSXFragment":
|
|
94
|
+
case "JSXFragment":
|
|
104
95
|
this.handleJsxElement(node, fileNode);
|
|
105
96
|
break;
|
|
106
97
|
case "Decorator":
|
|
107
98
|
this.handleDecorator(node, fileNode);
|
|
108
99
|
break;
|
|
109
100
|
case "StringLiteral":
|
|
110
|
-
// Track for secret scanning if it looks like a secret
|
|
111
101
|
fileNode.rawStringReferences.add(node.value);
|
|
112
102
|
break;
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
// Traverse children
|
|
116
105
|
for (const key in node) {
|
|
117
106
|
if (node[key] && typeof node[key] === "object") {
|
|
118
107
|
if (Array.isArray(node[key])) {
|
|
@@ -128,7 +117,6 @@ export class OxcAnalyzer {
|
|
|
128
117
|
const specifier = node.source.value;
|
|
129
118
|
fileNode.explicitImports.add(specifier);
|
|
130
119
|
|
|
131
|
-
// Track external package usage for dependency analysis
|
|
132
120
|
if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
|
|
133
121
|
fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
|
|
134
122
|
}
|
|
@@ -136,7 +124,7 @@ export class OxcAnalyzer {
|
|
|
136
124
|
if (node.specifiers) {
|
|
137
125
|
node.specifiers.forEach((spec) => {
|
|
138
126
|
if (spec.type === "ImportSpecifier") {
|
|
139
|
-
const importedName = spec.imported.name;
|
|
127
|
+
const importedName = spec.imported.name || (spec.imported.type === "Identifier" ? spec.imported.name : spec.imported.value);
|
|
140
128
|
fileNode.importedSymbols.add(`${specifier}:${importedName}`);
|
|
141
129
|
} else if (spec.type === "ImportDefaultSpecifier") {
|
|
142
130
|
fileNode.importedSymbols.add(`${specifier}:default`);
|
|
@@ -148,86 +136,83 @@ export class OxcAnalyzer {
|
|
|
148
136
|
}
|
|
149
137
|
|
|
150
138
|
handleExportDeclaration(node, fileNode, content) {
|
|
139
|
+
// 1. Default Exports
|
|
151
140
|
if (node.type === "ExportDefaultDeclaration") {
|
|
152
|
-
fileNode.internalExports.set("default", {
|
|
141
|
+
fileNode.internalExports.set("default", {
|
|
142
|
+
type: "default",
|
|
143
|
+
start: node.start,
|
|
144
|
+
end: node.end
|
|
145
|
+
});
|
|
153
146
|
return;
|
|
154
147
|
}
|
|
155
148
|
|
|
149
|
+
// 2. Re-export All: export * from 'mod' or export * as ns from 'mod'
|
|
156
150
|
if (node.type === "ExportAllDeclaration") {
|
|
157
|
-
const sourceSpecifier = node.source
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// Track external package usage from re-exports
|
|
164
|
-
if (!sourceSpecifier.startsWith('.') && !sourceSpecifier.startsWith('/')) {
|
|
165
|
-
fileNode.externalPackageUsage.add(this._extractPackageName(sourceSpecifier));
|
|
166
|
-
}
|
|
151
|
+
const sourceSpecifier = node.source.value;
|
|
152
|
+
fileNode.explicitImports.add(sourceSpecifier);
|
|
153
|
+
if (!sourceSpecifier.startsWith('.') && !sourceSpecifier.startsWith('/')) {
|
|
154
|
+
fileNode.externalPackageUsage.add(this._extractPackageName(sourceSpecifier));
|
|
155
|
+
}
|
|
167
156
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
if (node.exported) {
|
|
158
|
+
// export * as ns from 'mod'
|
|
159
|
+
const name = node.exported.name || (node.exported.type === "Identifier" ? node.exported.name : null);
|
|
160
|
+
if (name) {
|
|
161
|
+
fileNode.internalExports.set(name, {
|
|
162
|
+
type: "re-export-namespace",
|
|
163
|
+
source: sourceSpecifier,
|
|
164
|
+
originalName: "*",
|
|
165
|
+
start: node.start,
|
|
166
|
+
end: node.end
|
|
167
|
+
});
|
|
179
168
|
fileNode.importedSymbols.add(`${sourceSpecifier}:*`);
|
|
180
169
|
}
|
|
170
|
+
} else {
|
|
171
|
+
// export * from 'mod'
|
|
172
|
+
fileNode.internalExports.set("*", {
|
|
173
|
+
type: "re-export-all",
|
|
174
|
+
source: sourceSpecifier
|
|
175
|
+
});
|
|
176
|
+
fileNode.importedSymbols.add(`${sourceSpecifier}:*`);
|
|
181
177
|
}
|
|
182
178
|
return;
|
|
183
179
|
}
|
|
184
180
|
|
|
181
|
+
// 3. Named Exports & Re-exports with specifiers
|
|
185
182
|
if (node.source) {
|
|
186
|
-
// Re-export
|
|
183
|
+
// Re-export: export { x } from 'mod'
|
|
187
184
|
const specifier = node.source.value;
|
|
188
|
-
// Register re-export source as an explicit import
|
|
189
185
|
fileNode.explicitImports.add(specifier);
|
|
190
|
-
|
|
191
|
-
// Track external package usage from re-exports
|
|
192
186
|
if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
|
|
193
187
|
fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
|
|
194
188
|
}
|
|
195
189
|
|
|
196
190
|
if (node.specifiers) {
|
|
197
191
|
node.specifiers.forEach((spec) => {
|
|
198
|
-
const exportedName = spec.exported.name;
|
|
199
|
-
const localName = spec.local.name;
|
|
192
|
+
const exportedName = spec.exported.name || (spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value);
|
|
193
|
+
const localName = spec.local.name || (spec.local.type === "Identifier" ? spec.local.name : spec.local.value);
|
|
200
194
|
fileNode.internalExports.set(exportedName, {
|
|
201
195
|
type: "re-export",
|
|
202
196
|
source: specifier,
|
|
203
197
|
originalName: localName,
|
|
204
|
-
start:
|
|
205
|
-
end:
|
|
198
|
+
start: spec.start,
|
|
199
|
+
end: spec.end,
|
|
206
200
|
});
|
|
207
|
-
// Register as importedSymbol so barrel-tracer can resolve origin file
|
|
208
201
|
fileNode.importedSymbols.add(`${specifier}:${localName}`);
|
|
209
202
|
});
|
|
210
203
|
}
|
|
211
204
|
} else if (node.declaration) {
|
|
212
|
-
// Direct export
|
|
205
|
+
// Direct declaration export: export const x = 1, export function f() {}
|
|
213
206
|
const decl = node.declaration;
|
|
214
207
|
if (decl.type === "VariableDeclaration") {
|
|
215
208
|
decl.declarations.forEach((d) => {
|
|
216
|
-
|
|
217
|
-
fileNode.internalExports.set(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
fileNode.internalExports.set(p.value.name, { type: "variable", start: p.start, end: p.end });
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
} else if (d.id.type === "ArrayPattern") {
|
|
225
|
-
d.id.elements.forEach((e) => {
|
|
226
|
-
if (e && e.type === "Identifier") {
|
|
227
|
-
fileNode.internalExports.set(e.name, { type: "variable", start: e.start, end: e.end });
|
|
228
|
-
}
|
|
209
|
+
this._extractNamesFromPattern(d.id, (name) => {
|
|
210
|
+
fileNode.internalExports.set(name, {
|
|
211
|
+
type: "variable",
|
|
212
|
+
start: d.start,
|
|
213
|
+
end: d.end
|
|
229
214
|
});
|
|
230
|
-
}
|
|
215
|
+
});
|
|
231
216
|
});
|
|
232
217
|
} else if (decl.id && decl.id.name) {
|
|
233
218
|
let type = "unknown";
|
|
@@ -238,29 +223,50 @@ export class OxcAnalyzer {
|
|
|
238
223
|
else if (decl.type === "TSTypeAliasDeclaration") type = "type";
|
|
239
224
|
else if (decl.type === "TSModuleDeclaration") type = "namespace";
|
|
240
225
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
} else if (decl.type === "TSInterfaceDeclaration" || decl.type === "ClassDeclaration") {
|
|
247
|
-
exportInfo.members = decl.body.body.filter((m) => m.key && m.key.name).map((m) => m.key.name);
|
|
248
|
-
}
|
|
226
|
+
fileNode.internalExports.set(decl.id.name, {
|
|
227
|
+
type,
|
|
228
|
+
start: decl.start,
|
|
229
|
+
end: decl.end
|
|
230
|
+
});
|
|
249
231
|
}
|
|
250
232
|
} else if (node.specifiers) {
|
|
233
|
+
// Export existing locals: export { x, y as z }
|
|
251
234
|
node.specifiers.forEach((spec) => {
|
|
252
|
-
const exportedName = spec.exported.name;
|
|
253
|
-
const localName = spec.local.name;
|
|
235
|
+
const exportedName = spec.exported.name || (spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value);
|
|
236
|
+
const localName = spec.local.name || (spec.local.type === "Identifier" ? spec.local.name : spec.local.value);
|
|
254
237
|
fileNode.internalExports.set(exportedName, {
|
|
255
238
|
type: "export",
|
|
256
239
|
originalName: localName,
|
|
257
|
-
start:
|
|
258
|
-
end:
|
|
240
|
+
start: spec.start,
|
|
241
|
+
end: spec.end,
|
|
259
242
|
});
|
|
260
243
|
});
|
|
261
244
|
}
|
|
262
245
|
}
|
|
263
246
|
|
|
247
|
+
_extractNamesFromPattern(node, callback) {
|
|
248
|
+
if (!node) return;
|
|
249
|
+
if (node.type === "Identifier") {
|
|
250
|
+
callback(node.name);
|
|
251
|
+
} else if (node.type === "ObjectPattern") {
|
|
252
|
+
node.properties.forEach(p => {
|
|
253
|
+
if (p.type === "Property") {
|
|
254
|
+
this._extractNamesFromPattern(p.value, callback);
|
|
255
|
+
} else if (p.type === "RestElement") {
|
|
256
|
+
this._extractNamesFromPattern(p.argument, callback);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
} else if (node.type === "ArrayPattern") {
|
|
260
|
+
node.elements.forEach(e => {
|
|
261
|
+
if (e) this._extractNamesFromPattern(e, callback);
|
|
262
|
+
});
|
|
263
|
+
} else if (node.type === "AssignmentPattern") {
|
|
264
|
+
this._extractNamesFromPattern(node.left, callback);
|
|
265
|
+
} else if (node.type === "RestElement") {
|
|
266
|
+
this._extractNamesFromPattern(node.argument, callback);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
264
270
|
handleCallExpression(node, fileNode) {
|
|
265
271
|
// Dynamic import(): import('./module')
|
|
266
272
|
if (node.callee.type === "Import" && node.arguments.length > 0) {
|
|
@@ -269,11 +275,11 @@ export class OxcAnalyzer {
|
|
|
269
275
|
const specifier = arg.value;
|
|
270
276
|
fileNode.explicitImports.add(specifier);
|
|
271
277
|
fileNode.dynamicImports.add(specifier);
|
|
278
|
+
fileNode.importedSymbols.add(`${specifier}:*`); // Dynamic import usually consumes the whole namespace
|
|
272
279
|
if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
|
|
273
280
|
fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
|
|
274
281
|
}
|
|
275
282
|
} else {
|
|
276
|
-
// Non-literal dynamic import: record as calculated
|
|
277
283
|
if (fileNode.calculatedDynamicImports) {
|
|
278
284
|
fileNode.calculatedDynamicImports.push({ kind: arg.type, start: arg.start });
|
|
279
285
|
}
|
|
@@ -281,6 +287,7 @@ export class OxcAnalyzer {
|
|
|
281
287
|
} else if (node.callee.type === "Identifier" && node.callee.name === "require" && node.arguments.length > 0 && node.arguments[0].type === "StringLiteral") {
|
|
282
288
|
const specifier = node.arguments[0].value;
|
|
283
289
|
fileNode.explicitImports.add(specifier);
|
|
290
|
+
fileNode.importedSymbols.add(`${specifier}:*`);
|
|
284
291
|
if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
|
|
285
292
|
fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
|
|
286
293
|
}
|
|
@@ -291,6 +298,7 @@ export class OxcAnalyzer {
|
|
|
291
298
|
const getElementName = (nameNode) => {
|
|
292
299
|
if (nameNode.type === "JSXIdentifier") return nameNode.name;
|
|
293
300
|
if (nameNode.type === "JSXMemberExpression") return `${getElementName(nameNode.object)}.${nameNode.property.name}`;
|
|
301
|
+
if (nameNode.type === "JSXNamespacedName") return `${nameNode.namespace.name}:${nameNode.name.name}`;
|
|
294
302
|
return "unknown";
|
|
295
303
|
};
|
|
296
304
|
|
|
@@ -311,19 +319,17 @@ export class OxcAnalyzer {
|
|
|
311
319
|
handleDecorator(node, fileNode) {
|
|
312
320
|
const getDecoratorName = (expr) => {
|
|
313
321
|
if (expr.type === "Identifier") return expr.name;
|
|
314
|
-
if (expr.type === "CallExpression"
|
|
315
|
-
if (expr.type === "
|
|
322
|
+
if (expr.type === "CallExpression") return getDecoratorName(expr.callee);
|
|
323
|
+
if (expr.type === "MemberExpression") {
|
|
324
|
+
const prop = expr.property.name || expr.property.value;
|
|
325
|
+
return prop || "unknown";
|
|
326
|
+
}
|
|
316
327
|
return "unknown";
|
|
317
328
|
};
|
|
318
329
|
|
|
319
330
|
const decoratorName = getDecoratorName(node.expression);
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// Optionally, extract decorator arguments
|
|
323
|
-
if (node.expression.type === "CallExpression") {
|
|
324
|
-
node.expression.arguments.forEach(arg => {
|
|
325
|
-
// Further analysis of arguments can be done here if needed
|
|
326
|
-
});
|
|
331
|
+
if (decoratorName !== "unknown") {
|
|
332
|
+
fileNode.decorators.add(decoratorName);
|
|
327
333
|
}
|
|
328
334
|
}
|
|
329
335
|
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { OxcAnalyzer } from "./ast/OxcAnalyzer.js";
|
|
|
3
3
|
import { SecretScanner } from './ast/SecretScanner.js';
|
|
4
4
|
/**
|
|
5
5
|
* ============================================================================
|
|
6
|
-
* š¦ entkapp v4.
|
|
6
|
+
* š¦ entkapp v4.2.0: Unified Architectural Refactoring Orchestrator
|
|
7
7
|
* ============================================================================
|
|
8
8
|
* Main execution bridge managing multi-pass compilation cycles, semantic cross-linking,
|
|
9
9
|
* supply-chain validation audits, and automated structural healing rollbacks.
|
|
@@ -262,7 +262,11 @@ export class RefactoringEngine {
|
|
|
262
262
|
if (!this.context.unlistedDependencies) this.context.unlistedDependencies = [];
|
|
263
263
|
|
|
264
264
|
// Simple internal helper to guarantee matching forward slash strings across all platforms
|
|
265
|
-
const slashify = (p) =>
|
|
265
|
+
const slashify = (p) => {
|
|
266
|
+
if (!p) return p;
|
|
267
|
+
if (Array.isArray(p)) p = p[0];
|
|
268
|
+
return path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
269
|
+
};
|
|
266
270
|
|
|
267
271
|
if (this.context.projectGraph && typeof this.context.projectGraph.entries === 'function') {
|
|
268
272
|
for (const [filePath, fileNode] of this.context.projectGraph.entries()) {
|
|
@@ -271,12 +275,10 @@ export class RefactoringEngine {
|
|
|
271
275
|
const cleanFilePath = slashify(filePath);
|
|
272
276
|
|
|
273
277
|
// š ROOT DEPS HARVESTER SHADOW TRACKING:
|
|
274
|
-
// If external packages are parsed from ANY file node in the monorepo,
|
|
275
|
-
// ensure the auditor registries register their footprint so root checking works!
|
|
276
278
|
if (fileNode.externalPackageUsage) {
|
|
277
279
|
fileNode.externalPackageUsage.forEach(pkg => {
|
|
278
|
-
const relativeToRoot = path.relative(this.context.cwd, filePath);
|
|
279
|
-
if (relativeToRoot.startsWith('packages
|
|
280
|
+
const relativeToRoot = path.relative(this.context.cwd, filePath).replace(/\\/g, '/');
|
|
281
|
+
if (relativeToRoot.startsWith('packages/')) {
|
|
280
282
|
this.context.consumedWorkspacePackages.add(pkg);
|
|
281
283
|
} else {
|
|
282
284
|
this.context.consumedRootPackages.add(pkg);
|
|
@@ -294,17 +296,17 @@ export class RefactoringEngine {
|
|
|
294
296
|
if (!this.context.exportRegistry.has(cleanFilePath)) {
|
|
295
297
|
this.context.exportRegistry.set(cleanFilePath, new Set());
|
|
296
298
|
}
|
|
297
|
-
exportKeys.forEach(key =>
|
|
299
|
+
exportKeys.forEach(key => {
|
|
300
|
+
if (key !== '*') { // Don't track wildcard as a dead export symbol
|
|
301
|
+
this.context.exportRegistry.get(cleanFilePath).add(key);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
298
304
|
}
|
|
299
305
|
}
|
|
300
306
|
|
|
301
307
|
// 2. Gather cross-file usage tokens using unified slashes
|
|
302
|
-
if (fileNode.
|
|
303
|
-
const
|
|
304
|
-
? Array.from(fileNode.importedSymbols)
|
|
305
|
-
: (Array.isArray(fileNode.importedSymbols) ? fileNode.importedSymbols : []);
|
|
306
|
-
|
|
307
|
-
for (const symbolToken of symbolsArray) {
|
|
308
|
+
if (fileNode.importedSymbols) {
|
|
309
|
+
for (const symbolToken of fileNode.importedSymbols) {
|
|
308
310
|
if (typeof symbolToken !== 'string') continue;
|
|
309
311
|
|
|
310
312
|
const splitIndex = symbolToken.indexOf(':');
|
|
@@ -314,31 +316,20 @@ export class RefactoringEngine {
|
|
|
314
316
|
const symbolName = symbolToken.slice(splitIndex + 1);
|
|
315
317
|
|
|
316
318
|
let targetFile = null;
|
|
317
|
-
|
|
319
|
+
// If specifier is already an absolute path (resolved during linkDependencyGraph)
|
|
320
|
+
if (path.isAbsolute(specifier)) {
|
|
321
|
+
targetFile = specifier;
|
|
322
|
+
} else if (this.workspaceGraph && this.workspaceGraph.isLocalWorkspaceSpecifier(specifier)) {
|
|
318
323
|
const match = this.workspaceGraph.getWorkspacePackageMatch(specifier);
|
|
319
324
|
if (match && match.entryPoints && match.entryPoints.length > 0) {
|
|
320
|
-
targetFile =
|
|
325
|
+
targetFile = match.entryPoints[0];
|
|
321
326
|
}
|
|
322
327
|
} else if (specifier.startsWith('.')) {
|
|
323
|
-
targetFile =
|
|
324
|
-
|
|
325
|
-
// š COMPILE-TO-SOURCE EXTENSION SWAP:
|
|
326
|
-
// If a barrel file imports relative paths using compiled targets (like './used-fn.js'),
|
|
327
|
-
// replace the extension to check for active source components directly ('.ts' / '.tsx')
|
|
328
|
-
if (targetFile.endsWith('.js')) {
|
|
329
|
-
targetFile = targetFile.slice(0, -3);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (!path.extname(targetFile)) {
|
|
333
|
-
if (existsSync(targetFile + '.ts')) targetFile += '.ts';
|
|
334
|
-
else if (existsSync(targetFile + '.tsx')) targetFile += '.tsx';
|
|
335
|
-
else if (existsSync(targetFile + '.js')) targetFile += '.js';
|
|
336
|
-
}
|
|
328
|
+
targetFile = this.resolver.resolveModulePath(filePath, specifier);
|
|
337
329
|
}
|
|
338
330
|
|
|
339
331
|
if (targetFile) {
|
|
340
|
-
|
|
341
|
-
const cleanTargetFile = Array.isArray(targetFile) ? slashify(targetFile[0]) : slashify(targetFile);
|
|
332
|
+
const cleanTargetFile = slashify(targetFile);
|
|
342
333
|
this.context.importUsageRegistry.add(`${cleanTargetFile}:${symbolName}`);
|
|
343
334
|
}
|
|
344
335
|
}
|
|
@@ -478,16 +469,33 @@ export class RefactoringEngine {
|
|
|
478
469
|
}
|
|
479
470
|
if (isPackageEntryPoint) continue;
|
|
480
471
|
|
|
472
|
+
const originalNode = this.context.projectGraph.get(cleanExportedFile);
|
|
473
|
+
const unusedExportsInThisFile = [];
|
|
474
|
+
|
|
481
475
|
for (const symbol of exportsSet) {
|
|
482
476
|
const consumptionToken = `${cleanExportedFile}:${symbol}`;
|
|
483
477
|
if (!this.context.importUsageRegistry?.has(consumptionToken)) {
|
|
484
|
-
|
|
478
|
+
// Retrieve the real source location if available
|
|
479
|
+
const loc = (originalNode && originalNode.symbolSourceLocations) ? originalNode.symbolSourceLocations.get(symbol) || { line: 0 } : { line: 0 };
|
|
480
|
+
unusedExportsInThisFile.push({
|
|
485
481
|
symbol: symbol,
|
|
486
482
|
file: relativeExportedFile,
|
|
487
|
-
line:
|
|
483
|
+
line: loc.line
|
|
488
484
|
});
|
|
489
485
|
}
|
|
490
486
|
}
|
|
487
|
+
|
|
488
|
+
// --- NEW: Orphaned File Detection based on Export Coverage ---
|
|
489
|
+
// If every single export in this file is unused, and it's not an entry point,
|
|
490
|
+
// we suggest deleting the entire file instead of pruning individual exports.
|
|
491
|
+
if (unusedExportsInThisFile.length > 0 && unusedExportsInThisFile.length === exportsSet.size) {
|
|
492
|
+
if (!analysisSummary.orphanedFiles.includes(relativeExportedFile)) {
|
|
493
|
+
analysisSummary.orphanedFiles.push(relativeExportedFile);
|
|
494
|
+
}
|
|
495
|
+
} else {
|
|
496
|
+
// Otherwise, just append the individual dead exports as usual
|
|
497
|
+
analysisSummary.deadExports.push(...unusedExportsInThisFile);
|
|
498
|
+
}
|
|
491
499
|
}
|
|
492
500
|
}
|
|
493
501
|
analysisSummary.unlistedDependencies = this.context.unlistedDependencies || [];
|
|
@@ -598,34 +606,52 @@ export class RefactoringEngine {
|
|
|
598
606
|
}
|
|
599
607
|
|
|
600
608
|
async linkDependencyGraph() {
|
|
609
|
+
// Pass 1: Global Entry-Point Protection (Seeds)
|
|
610
|
+
// Mark all package entry points and explicit config entry points as library entries first.
|
|
611
|
+
const seeds = new Set();
|
|
612
|
+
|
|
613
|
+
// Add workspace entry points
|
|
614
|
+
if (this.workspaceGraph && this.workspaceGraph.packageManifests) {
|
|
615
|
+
for (const pkg of this.workspaceGraph.packageManifests.values()) {
|
|
616
|
+
if (pkg.entryPoints) {
|
|
617
|
+
pkg.entryPoints.forEach(ep => seeds.add(path.resolve(ep)));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Add explicit config entry points
|
|
623
|
+
if (this.context.entryPoints) {
|
|
624
|
+
this.context.entryPoints.forEach(ep => seeds.add(path.resolve(this.context.cwd, ep)));
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
for (const seedPath of seeds) {
|
|
628
|
+
if (this.context.projectGraph.has(seedPath)) {
|
|
629
|
+
this.context.projectGraph.get(seedPath).isLibraryEntry = true;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Pass 2: Edge Linking
|
|
601
634
|
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
602
|
-
//
|
|
635
|
+
// A. Explicit Imports (Files)
|
|
603
636
|
for (const specifier of node.explicitImports) {
|
|
604
637
|
const resolvedPath = this.resolver.resolveModulePath(filePath, specifier);
|
|
605
638
|
if (resolvedPath && this.context.projectGraph.has(resolvedPath)) {
|
|
606
|
-
this.context.projectGraph.get(resolvedPath)
|
|
639
|
+
const targetNode = this.context.projectGraph.get(resolvedPath);
|
|
640
|
+
targetNode.incomingEdges.add(filePath);
|
|
607
641
|
node.outgoingEdges.add(resolvedPath);
|
|
608
642
|
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
const
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Pass A.2: Mark package entry points as library entries
|
|
620
|
-
for (const pkg of this.workspaceGraph.packageManifests.values()) {
|
|
621
|
-
for (const entryPath of pkg.entryPoints) {
|
|
622
|
-
if (this.context.projectGraph.has(entryPath)) {
|
|
623
|
-
this.context.projectGraph.get(entryPath).isLibraryEntry = true;
|
|
643
|
+
// Re-export protection: If this file re-exports everything from another file,
|
|
644
|
+
// the target file should be treated as an entry point for its own exports.
|
|
645
|
+
const isReExportAll = Array.from(node.internalExports.values()).some(exp =>
|
|
646
|
+
(exp.type === "re-export-all" || exp.type === "re-export-namespace") && exp.source === specifier
|
|
647
|
+
);
|
|
648
|
+
if (isReExportAll) {
|
|
649
|
+
targetNode.isLibraryEntry = true;
|
|
624
650
|
}
|
|
625
651
|
}
|
|
626
652
|
}
|
|
627
653
|
|
|
628
|
-
//
|
|
654
|
+
// B. Symbol-level Linking (Tracing through barrels)
|
|
629
655
|
for (const specToken of node.importedSymbols) {
|
|
630
656
|
const delimiterIndex = specToken.indexOf(':');
|
|
631
657
|
if (delimiterIndex === -1) continue;
|
|
@@ -636,18 +662,18 @@ export class RefactoringEngine {
|
|
|
636
662
|
if (!resolvedPath) continue;
|
|
637
663
|
|
|
638
664
|
if (symbol === '*') {
|
|
639
|
-
// Wildcard import / re-export-all: add a direct edge to the resolved file.
|
|
640
665
|
if (this.context.projectGraph.has(resolvedPath)) {
|
|
641
666
|
this.context.projectGraph.get(resolvedPath).incomingEdges.add(filePath);
|
|
642
667
|
node.outgoingEdges.add(resolvedPath);
|
|
643
668
|
}
|
|
644
669
|
} else {
|
|
645
|
-
// Named import: trace through barrel files to the actual declaration origin.
|
|
646
670
|
const traceResolution = await this.barrelParser.determineSymbolDeclarationOrigin(resolvedPath, symbol, this.context.projectGraph);
|
|
647
671
|
if (traceResolution && this.context.projectGraph.has(traceResolution.originFile)) {
|
|
648
|
-
this.context.projectGraph.get(traceResolution.originFile)
|
|
672
|
+
const originNode = this.context.projectGraph.get(traceResolution.originFile);
|
|
673
|
+
originNode.incomingEdges.add(filePath);
|
|
649
674
|
node.outgoingEdges.add(traceResolution.originFile);
|
|
650
|
-
|
|
675
|
+
// Register the actual resolved symbol for dead export detection
|
|
676
|
+
node.importedSymbols.add(`${traceResolution.originFile}:${traceResolution.originSymbol}`);
|
|
651
677
|
}
|
|
652
678
|
}
|
|
653
679
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { parentPort, workerData } from 'worker_threads';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import { ASTAnalyzer } from '../ast/ASTAnalyzer.js';
|
|
4
|
+
import { OxcAnalyzer } from '../ast/OxcAnalyzer.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Worker Thread Execution Script
|
|
8
|
+
* Handles parallel AST parsing for a chunk of files and returns serialized results.
|
|
9
|
+
*/
|
|
10
|
+
async function runTask() {
|
|
11
|
+
const { files, contextOptions } = workerData;
|
|
12
|
+
const results = [];
|
|
13
|
+
|
|
14
|
+
// Create a minimal context for analyzers
|
|
15
|
+
const mockContext = {
|
|
16
|
+
verbose: contextOptions.verbose,
|
|
17
|
+
projectGraph: new Map(),
|
|
18
|
+
getOrCreateNode: (path) => ({
|
|
19
|
+
filePath: path,
|
|
20
|
+
explicitImports: new Set(),
|
|
21
|
+
dynamicImports: new Set(),
|
|
22
|
+
importedSymbols: new Set(),
|
|
23
|
+
rawStringReferences: new Set(),
|
|
24
|
+
instantiatedIdentifiers: new Set(),
|
|
25
|
+
propertyAccessChains: new Set(),
|
|
26
|
+
internalExports: new Map(),
|
|
27
|
+
securityThreats: [],
|
|
28
|
+
localSuppressedRules: new Set(),
|
|
29
|
+
externalPackageUsage: new Set(),
|
|
30
|
+
symbolSourceLocations: new Map(),
|
|
31
|
+
jsxComponents: new Set(),
|
|
32
|
+
jsxProps: new Set(),
|
|
33
|
+
decorators: new Set(),
|
|
34
|
+
isFrameworkContract: false
|
|
35
|
+
})
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const astAnalyzer = new ASTAnalyzer(mockContext);
|
|
39
|
+
const oxcAnalyzer = new OxcAnalyzer(mockContext);
|
|
40
|
+
|
|
41
|
+
for (const filePath of files) {
|
|
42
|
+
try {
|
|
43
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
44
|
+
const node = mockContext.getOrCreateNode(filePath);
|
|
45
|
+
|
|
46
|
+
// Use OXC if available, fallback to TS AST
|
|
47
|
+
if (oxcAnalyzer.isAvailable) {
|
|
48
|
+
await oxcAnalyzer.parseFile(filePath, content, node);
|
|
49
|
+
} else {
|
|
50
|
+
await astAnalyzer.parseFile(filePath, content, node);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Serialize the node data for transfer back to main thread
|
|
54
|
+
results.push({
|
|
55
|
+
filePath: node.filePath,
|
|
56
|
+
explicitImports: Array.from(node.explicitImports),
|
|
57
|
+
dynamicImports: Array.from(node.dynamicImports),
|
|
58
|
+
importedSymbols: Array.from(node.importedSymbols),
|
|
59
|
+
rawStringReferences: Array.from(node.rawStringReferences),
|
|
60
|
+
instantiatedIdentifiers: Array.from(node.instantiatedIdentifiers),
|
|
61
|
+
propertyAccessChains: Array.from(node.propertyAccessChains),
|
|
62
|
+
internalExports: Object.fromEntries(node.internalExports),
|
|
63
|
+
securityThreats: node.securityThreats,
|
|
64
|
+
localSuppressedRules: Array.from(node.localSuppressedRules),
|
|
65
|
+
externalPackageUsage: Array.from(node.externalPackageUsage),
|
|
66
|
+
symbolSourceLocations: Object.fromEntries(node.symbolSourceLocations),
|
|
67
|
+
jsxComponents: Array.from(node.jsxComponents),
|
|
68
|
+
jsxProps: Array.from(node.jsxProps),
|
|
69
|
+
decorators: Array.from(node.decorators),
|
|
70
|
+
isFrameworkContract: node.isFrameworkContract
|
|
71
|
+
});
|
|
72
|
+
} catch (err) {
|
|
73
|
+
if (contextOptions.verbose) {
|
|
74
|
+
console.error(`[Worker] Failed to parse ${filePath}: ${err.message}`);
|
|
75
|
+
}
|
|
76
|
+
// Push null to keep array indices if needed, or just skip
|
|
77
|
+
results.push(null);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
parentPort.postMessage(results);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
runTask().catch(err => {
|
|
85
|
+
console.error(`[Worker Critical Fault] ${err.stack}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================================
|
|
3
|
-
* Backend Services Plugins for entkapp v4.
|
|
3
|
+
* Backend Services Plugins for entkapp v4.2.0
|
|
4
4
|
* ============================================================================
|
|
5
5
|
* Built-in support for GraphQL, REST APIs, and Databases.
|
|
6
6
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================================
|
|
3
|
-
* Modern Frameworks Plugins for entkapp v4.
|
|
3
|
+
* Modern Frameworks Plugins for entkapp v4.2.0
|
|
4
4
|
* ============================================================================
|
|
5
5
|
* Built-in support for React, Vue, Svelte, and Angular.
|
|
6
6
|
*/
|