entkapp 4.5.0 β 5.0.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/bin/cli.js +4 -4
- package/docs.zip +0 -0
- package/entkapp/config.json +0 -1
- package/package.json +5 -6
- package/src/EngineContext.js +276 -78
- package/src/analyzers/OxcAnalyzer.js +8 -380
- package/src/api/HeadlessAPI.js +1 -1
- package/src/api/PluginSDK.js +23 -187
- package/src/ast/ASTAnalyzer.js +467 -253
- package/src/ast/AdvancedAnalysis.js +6 -5
- package/src/ast/BarrelParser.js +23 -16
- package/src/ast/DeadCodeDetector.js +30 -18
- package/src/ast/MagicDetector.js +1 -1
- package/src/ast/OxcAnalyzer.js +328 -264
- package/src/index.js +272 -361
- package/src/performance/GraphCache.js +21 -2
- package/src/performance/WorkerPool.js +11 -1
- package/src/performance/WorkerTaskRunner.js +72 -25
- package/src/plugins/PluginRegistry.js +5 -16
- package/src/plugins/ecosystems/GenericPlugins.js +61 -0
- package/src/refractor/TransactionManager.js +3 -136
- package/src/refractor/TypeIntegrity.js +2 -73
- package/src/resolution/CircularDetector.js +27 -66
- package/src/resolution/ConfigLoader.js +2 -85
- package/src/resolution/DepencyResolver.js +20 -124
- package/src/resolution/EntryPointDetector.js +134 -0
- package/src/resolution/PathMapper.js +3 -123
- package/src/resolution/TSConfigLoader.js +76 -0
- package/src/resolution/WorkSpaceGraph.js +4 -473
- package/src/resolution/WorkspaceDiagnostic.js +3 -57
- package/src/plugins/KnipAdapter.js +0 -106
package/src/index.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { DeadCodeDetector } from "./ast/DeadCodeDetector.js";
|
|
2
1
|
import { OxcAnalyzer } from "./ast/OxcAnalyzer.js";
|
|
3
2
|
import { SecretScanner } from './ast/SecretScanner.js';
|
|
4
3
|
import { AdvancedAnalysis } from './ast/AdvancedAnalysis.js';
|
|
5
4
|
import { WorkspaceDiagnostic } from './resolution/WorkspaceDiagnostic.js';
|
|
5
|
+
import { DeadCodeDetector } from './ast/DeadCodeDetector.js';
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* ============================================================================
|
|
8
|
-
* π¦ entkapp v4.
|
|
9
|
+
* π¦ entkapp v4.6.0: Unified Architectural Refactoring Orchestrator
|
|
9
10
|
* ============================================================================
|
|
10
11
|
* Main execution bridge managing multi-pass compilation cycles, semantic cross-linking,
|
|
11
12
|
* supply-chain validation audits, and automated structural healing rollbacks.
|
|
13
|
+
* Production-ready linear orchestration engine.
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import fs from 'fs/promises';
|
|
@@ -54,6 +56,7 @@ export class RefactoringEngine {
|
|
|
54
56
|
this.context.entryPoints = options.entryPoints || [];
|
|
55
57
|
this.context.exclude = options.exclude || [];
|
|
56
58
|
this.context.rules = options.rules || {};
|
|
59
|
+
|
|
57
60
|
// Stage 2: Initialize File Mappers and Multi-Package Graph Networks
|
|
58
61
|
this.pathMapper = new PathMapper(this.context);
|
|
59
62
|
this.workspaceGraph = new WorkspaceGraph(this.context);
|
|
@@ -78,10 +81,12 @@ export class RefactoringEngine {
|
|
|
78
81
|
this.workerPool = new WorkerPool(this.context);
|
|
79
82
|
this.gitSandbox = new GitSandbox(this.context);
|
|
80
83
|
this.selfHealer = new SelfHealer(this.context, this.txManager, this.gitSandbox);
|
|
84
|
+
|
|
81
85
|
// Stage 6: Secret / hardcoded credential scanner
|
|
82
86
|
this.secretScanner = new SecretScanner();
|
|
83
87
|
this.advancedAnalysis = new AdvancedAnalysis(this.context);
|
|
84
88
|
this.workspaceDiagnostic = new WorkspaceDiagnostic(this.context);
|
|
89
|
+
this.deadCodeDetector = new DeadCodeDetector(this.context);
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
/**
|
|
@@ -103,20 +108,34 @@ export class RefactoringEngine {
|
|
|
103
108
|
await this.oxcAnalyzer.init();
|
|
104
109
|
await this.pathMapper.loadMappings(this.context.tsconfigFilename);
|
|
105
110
|
|
|
106
|
-
// Always attempt workspace mesh initialization
|
|
107
|
-
// configuration and flip `context.isWorkspaceEnabled` when found.
|
|
111
|
+
// Always attempt workspace mesh initialization
|
|
108
112
|
console.log(ansis.dim('π Probing for monorepo workspace configuration...'));
|
|
109
113
|
await this.workspaceGraph.initializeWorkspaceMesh();
|
|
110
114
|
if (this.context.isWorkspaceEnabled) {
|
|
111
115
|
console.log(ansis.dim('π Monorepo workspace detected β mapping package mesh layers...'));
|
|
112
116
|
}
|
|
113
117
|
|
|
118
|
+
// UPGRADE: Always clear cache for fresh analysis run
|
|
119
|
+
await this.cacheManager.clearCache();
|
|
120
|
+
|
|
114
121
|
// Load asset fingerprints from disk cache to maximize cold-start performance
|
|
115
122
|
const cacheManifest = await this.cacheManager.loadCacheManifest();
|
|
116
123
|
|
|
117
124
|
// Pass 2: Recursively crawl directories to compile target codebase files list
|
|
118
|
-
const
|
|
119
|
-
await this.discoverSourceFiles(this.context.cwd,
|
|
125
|
+
const rawFileList = [];
|
|
126
|
+
await this.discoverSourceFiles(this.context.cwd, rawFileList);
|
|
127
|
+
|
|
128
|
+
// UPGRADE: De-duplicate and normalize file list to prevent massive count inflation
|
|
129
|
+
const slashifyInternal = (p) => {
|
|
130
|
+
let abs = path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
131
|
+
if (/^[a-z]:\//i.test(abs)) {
|
|
132
|
+
abs = abs.charAt(0).toUpperCase() + abs.slice(1);
|
|
133
|
+
}
|
|
134
|
+
return abs;
|
|
135
|
+
};
|
|
136
|
+
const uniqueFiles = new Set(rawFileList.map(f => slashifyInternal(f)));
|
|
137
|
+
const fileList = Array.from(uniqueFiles);
|
|
138
|
+
|
|
120
139
|
this.context.metrics.totalFilesScanned = fileList.length;
|
|
121
140
|
|
|
122
141
|
// Identify meta-framework setups (Next.js, Remix, Nuxt, etc.)
|
|
@@ -138,17 +157,42 @@ export class RefactoringEngine {
|
|
|
138
157
|
parallelParseCompleted = await this.workerPool.parallelAnalyzeCodebase(sourceCodeFilesList, this);
|
|
139
158
|
}
|
|
140
159
|
|
|
160
|
+
// =========================================================================
|
|
161
|
+
// π GESETZ 1: EXKLUSIVE WURZEL-GARANTIE AUS MANIFEST EXTRAHIEREN
|
|
162
|
+
// =========================================================================
|
|
163
|
+
let localManifestMainEntryPoint = null;
|
|
164
|
+
try {
|
|
165
|
+
const pkgPath = path.join(this.context.cwd, 'package.json');
|
|
166
|
+
if (existsSync(pkgPath)) {
|
|
167
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
168
|
+
if (pkg.main) {
|
|
169
|
+
localManifestMainEntryPoint = path.resolve(this.context.cwd, pkg.main).replace(/\\/g, '/');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch (e) {}
|
|
173
|
+
|
|
174
|
+
// =========================================================================
|
|
175
|
+
// π PRIMARY FILE-PARSING LIFECYCLE LOOP
|
|
176
|
+
// =========================================================================
|
|
141
177
|
for (const filePath of sourceCodeFilesList) {
|
|
142
|
-
const
|
|
143
|
-
const
|
|
178
|
+
const absFilePath = slashifyInternal(filePath);
|
|
179
|
+
const node = this.context.getOrCreateNode(absFilePath);
|
|
180
|
+
const currentHash = await this.cacheManager.computeHash(absFilePath);
|
|
144
181
|
node.contentHash = currentHash;
|
|
145
182
|
|
|
183
|
+
// --- MANIFEST ENTRY ABSOLUTE IMMUNITΓT ---
|
|
184
|
+
if (localManifestMainEntryPoint && absFilePath === localManifestMainEntryPoint) {
|
|
185
|
+
node.isEntry = true;
|
|
186
|
+
if (this.context.verbose) {
|
|
187
|
+
console.log(ansis.bold.green(`[WURZEL-GARANTIE] ${filePath} sofort als unantastbarer Entry Point verankert.`));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
146
191
|
const isFileCached = cacheManifest[filePath] && cacheManifest[filePath].hash === currentHash;
|
|
147
192
|
|
|
148
193
|
if (isFileCached) {
|
|
149
194
|
this.context.metrics.cacheHits++;
|
|
150
195
|
this.hydrateNodeFromCache(node, cacheManifest[filePath]);
|
|
151
|
-
// Re-run secret scan even on cached files (secrets may change without AST change)
|
|
152
196
|
try {
|
|
153
197
|
const cachedContent = await fs.readFile(filePath, 'utf8');
|
|
154
198
|
const secretFindings = this.secretScanner.scanFileContent(filePath, cachedContent);
|
|
@@ -159,10 +203,23 @@ export class RefactoringEngine {
|
|
|
159
203
|
} catch { /* unreadable file β skip */ }
|
|
160
204
|
} else if (!parallelParseCompleted) {
|
|
161
205
|
this.context.metrics.cacheMisses++;
|
|
162
|
-
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
206
|
+
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
207
|
+
|
|
208
|
+
let success = false;
|
|
163
209
|
if (this.oxcAnalyzer.isAvailable) {
|
|
164
|
-
await this.oxcAnalyzer.parseFile(filePath, fileContent, node);
|
|
165
|
-
}
|
|
210
|
+
success = await this.oxcAnalyzer.parseFile(filePath, fileContent, node);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// UPGRADE: Improved fallback logic for CommonJS files
|
|
214
|
+
const hasImportExportKeywords = fileContent.includes('import') || fileContent.includes('export');
|
|
215
|
+
const hasCommonJSKeywords = fileContent.includes('require') || fileContent.includes('module.exports') || fileContent.includes('exports.');
|
|
216
|
+
const oxcFailedToFindDependencies = node.explicitImports.size === 0 && node.internalExports.size === 0;
|
|
217
|
+
|
|
218
|
+
// Fallback to TS parser if:
|
|
219
|
+
// 1. OXC failed completely, OR
|
|
220
|
+
// 2. OXC found no dependencies but file has import/export keywords, OR
|
|
221
|
+
// 3. OXC found no dependencies but file has CommonJS keywords
|
|
222
|
+
if (!success || (oxcFailedToFindDependencies && (hasImportExportKeywords || hasCommonJSKeywords))) {
|
|
166
223
|
await this.analyzer.parseFile(filePath, fileContent, node);
|
|
167
224
|
}
|
|
168
225
|
// Secret scan on freshly parsed content
|
|
@@ -176,20 +233,18 @@ export class RefactoringEngine {
|
|
|
176
233
|
await this.magicDetector.injectVirtualConsumerEdges(filePath, node, activeFrameworkEcosystems);
|
|
177
234
|
|
|
178
235
|
// Fix: Explicitly protect entry points defined in local configuration
|
|
179
|
-
const
|
|
236
|
+
const slashifyLocal = (p) => path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
180
237
|
if (this.context.entryPoints && this.context.entryPoints.some(ep => {
|
|
181
|
-
const absEp =
|
|
238
|
+
const absEp = slashifyLocal(ep);
|
|
182
239
|
const cleanAbsEp = absEp.replace(/\.[^/.]+$/, "");
|
|
183
|
-
const cleanFilePath =
|
|
184
|
-
return absEp ===
|
|
240
|
+
const cleanFilePath = slashifyLocal(filePath).replace(/\.[^/.]+$/, "");
|
|
241
|
+
return absEp === slashifyLocal(filePath) || cleanAbsEp === cleanFilePath;
|
|
185
242
|
})) {
|
|
186
|
-
node.
|
|
243
|
+
node.isEntry = true;
|
|
187
244
|
}
|
|
188
|
-
|
|
189
|
-
}
|
|
245
|
+
} // π HIER SCHLIESST DIE DATEI-SCHLEIFE JETZT SAUBER UND KORREKT!
|
|
190
246
|
|
|
191
247
|
// Fix: Automatically mark active ecosystem packages as used.
|
|
192
|
-
// Maps internal plugin names to their canonical npm package names.
|
|
193
248
|
const pluginToPackageMap = {
|
|
194
249
|
'typescript': 'typescript',
|
|
195
250
|
'vitest': 'vitest',
|
|
@@ -215,18 +270,35 @@ export class RefactoringEngine {
|
|
|
215
270
|
}
|
|
216
271
|
});
|
|
217
272
|
|
|
218
|
-
//
|
|
219
|
-
//
|
|
273
|
+
// =========================================================================
|
|
274
|
+
// π ZWEITER DEBUG SENSOR: ImmunitΓ€ts-Verifikation nach dem Parsen
|
|
275
|
+
// =========================================================================
|
|
276
|
+
console.log(ansis.bold.magenta('\nπ [DEBUG] Zustand der Entry-Points nach dem Parsen:'));
|
|
277
|
+
let entryCount = 0;
|
|
278
|
+
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
279
|
+
if (node.isEntry) {
|
|
280
|
+
entryCount++;
|
|
281
|
+
const rel = path.relative(this.context.cwd, filePath).replace(/\\/g, '/');
|
|
282
|
+
console.log(ansis.green(` β’ π ERKANNT ALS ENTRY: ${rel}`));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (entryCount === 0) {
|
|
286
|
+
console.log(ansis.bold.red(' π¨ ALARM: Keine einzige Datei wurde als Entry Point markiert!'));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Markiere Workspace-Pakete als genutzt, um Fehlalarme im Manifest-Auditor zu blockieren
|
|
220
290
|
if (this.context.isWorkspaceEnabled) {
|
|
221
291
|
this.workspaceGraph.markWorkspacePackagesAsUsed();
|
|
222
292
|
}
|
|
223
293
|
|
|
224
|
-
// Pass 4:
|
|
294
|
+
// Pass 4: Berechne Graph-Kanten und verknΓΌpfe Import-Verbindungen
|
|
225
295
|
console.log(ansis.dim('π Linking graph edges and checking structural usage paths...'));
|
|
226
296
|
if (this.context.verbose) {
|
|
227
297
|
console.log(`[Linker] Starting dependency graph linkage for ${this.context.projectGraph.size} nodes.`);
|
|
228
298
|
}
|
|
229
|
-
|
|
299
|
+
|
|
300
|
+
await this.linkDependencyGraph(); // π Wird jetzt exakt ein einziges Mal gestartet!
|
|
301
|
+
|
|
230
302
|
if (this.context.verbose) {
|
|
231
303
|
const totalEdges = Array.from(this.context.projectGraph.values()).reduce((sum, node) => sum + node.outgoingEdges.size, 0);
|
|
232
304
|
console.log(`[Linker] Completed linkage. Total edges created: ${totalEdges}`);
|
|
@@ -243,51 +315,25 @@ export class RefactoringEngine {
|
|
|
243
315
|
console.warn(ansis.bold.yellow(`\nβ οΈ Detected ${cyclesResult.length} circular dependencies:`));
|
|
244
316
|
this.circularDetector.formatCycles().forEach(c => console.log(ansis.dim(` β’ ${c}`)));
|
|
245
317
|
}
|
|
246
|
-
|
|
318
|
+
|
|
247
319
|
// Pass 4b: Report hardcoded secrets
|
|
248
320
|
console.log(ansis.dim("π Scanning for hardcoded secrets..."));
|
|
249
321
|
const allSecrets = this.context.allSecretFindings || [];
|
|
250
|
-
|
|
322
|
+
|
|
323
|
+
if (this.context.allSecretFindings) {
|
|
324
|
+
const uniqueSecrets = new Map();
|
|
325
|
+
this.context.allSecretFindings.forEach(s => {
|
|
326
|
+
const key = `${s.file}:${s.line}:${s.type}`;
|
|
327
|
+
if (!uniqueSecrets.has(key)) uniqueSecrets.set(key, s);
|
|
328
|
+
});
|
|
329
|
+
this.context.allSecretFindings = Array.from(uniqueSecrets.values());
|
|
251
330
|
}
|
|
252
331
|
|
|
253
332
|
// NEW: Advanced Program Analysis (CFG, Data Flow, Taint Tracking)
|
|
254
333
|
console.log(ansis.dim("π§ Performing advanced program analysis..."));
|
|
255
334
|
for (const [filePath, fileNode] of this.context.projectGraph.entries()) {
|
|
256
|
-
|
|
257
|
-
// In a real scenario, we'd need the actual AST object here.
|
|
258
|
-
const ast = fileNode.ast || {}; // Assuming AST is stored in fileNode
|
|
335
|
+
const ast = fileNode.ast || {};
|
|
259
336
|
this.advancedAnalysis.buildCFG(filePath, ast);
|
|
260
|
-
// this.advancedAnalysis.handleComputedExports(fileNode, ast);
|
|
261
|
-
// const unreachableCode = this.advancedAnalysis.analyzeReachability(filePath);
|
|
262
|
-
// if (unreachableCode.length > 0) {
|
|
263
|
-
// console.log(ansis.yellow(` β οΈ Unreachable code detected in ${path.relative(this.context.cwd, filePath)}: ${unreachableCode.length} blocks`));
|
|
264
|
-
// }
|
|
265
|
-
// const taintFindings = this.advancedAnalysis.performTaintAnalysis(filePath, ast);
|
|
266
|
-
// if (taintFindings.length > 0) {
|
|
267
|
-
// console.log(ansis.red(` π¨ Taint violations detected in ${path.relative(this.context.cwd, filePath)}: ${taintFindings.length} findings`));
|
|
268
|
-
// taintFindings.forEach(f => console.log(ansis.dim(` β’ ${f.type} at ${f.file}:${f.line} (Sink: ${f.sink})`)));
|
|
269
|
-
// this.context.allSecretFindings.push(...taintFindings); // Add taint findings to overall secrets
|
|
270
|
-
// }
|
|
271
|
-
|
|
272
|
-
// Detect unused members
|
|
273
|
-
// const unusedMembers = this.advancedAnalysis.detectUnusedMembers(fileNode);
|
|
274
|
-
// if (unusedMembers.length > 0) {
|
|
275
|
-
// console.log(ansis.yellow(` β οΈ Unused members detected in ${path.relative(this.context.cwd, filePath)}:`));
|
|
276
|
-
// unusedMembers.forEach(m => console.log(ansis.dim(` β’ ${m.member}: ${m.message}`)));
|
|
277
|
-
// }
|
|
278
|
-
|
|
279
|
-
// NEW: Type-Jail Analysis
|
|
280
|
-
// const typeJailViolations = this.workspaceDiagnostic.analyzeTypeJail(fileNode);
|
|
281
|
-
// if (typeJailViolations.length > 0) {
|
|
282
|
-
// console.log(ansis.yellow(` β οΈ Type-Jail violations in ${path.relative(this.context.cwd, filePath)}:`));
|
|
283
|
-
// typeJailViolations.forEach(v => console.log(ansis.dim(` β’ ${v.message}`)));
|
|
284
|
-
// }
|
|
285
|
-
|
|
286
|
-
// NEW: Ghost Code Detection
|
|
287
|
-
// const ghostExports = this.advancedAnalysis.detectGhostCode(fileNode, this.context.projectGraph);
|
|
288
|
-
// if (ghostExports.length > 0) {
|
|
289
|
-
// console.log(ansis.yellow(` π» Ghost exports detected in ${path.relative(this.context.cwd, filePath)}: [${ghostExports.join(', ')}]`));
|
|
290
|
-
// }
|
|
291
337
|
}
|
|
292
338
|
|
|
293
339
|
// NEW: Workspace Diagnostic & Architecture Enforcement
|
|
@@ -298,8 +344,6 @@ export class RefactoringEngine {
|
|
|
298
344
|
workspaceHealthFindings.forEach(f => console.log(ansis.dim(` β’ ${f.message}`)));
|
|
299
345
|
}
|
|
300
346
|
|
|
301
|
-
// Placeholder for boundary enforcement, would need to pass actual import data
|
|
302
|
-
// For each file, iterate its imports and check against rules
|
|
303
347
|
for (const [filePath, fileNode] of this.context.projectGraph.entries()) {
|
|
304
348
|
const boundaryViolations = this.workspaceDiagnostic.enforceBoundaries(filePath, Array.from(fileNode.explicitImports));
|
|
305
349
|
if (boundaryViolations.length > 0) {
|
|
@@ -308,15 +352,6 @@ export class RefactoringEngine {
|
|
|
308
352
|
}
|
|
309
353
|
}
|
|
310
354
|
|
|
311
|
-
// Placeholder for Hotspot analysis
|
|
312
|
-
// const hotspots = await this.workspaceDiagnostic.identifyHotspots(this.context.projectGraph, /* git history data */);
|
|
313
|
-
// if (hotspots.length > 0) {
|
|
314
|
-
// console.log(ansis.bold.magenta(`\nπ₯ Code Hotspots identified:`));
|
|
315
|
-
// hotspots.forEach(h => console.log(ansis.dim(` β’ ${h.file}: Complexity ${h.complexity}, Change Frequency ${h.changeFrequency}`)));
|
|
316
|
-
// }
|
|
317
|
-
|
|
318
|
-
// End of new advanced analysis integrations
|
|
319
|
-
|
|
320
355
|
if (allSecrets.length > 0) {
|
|
321
356
|
const criticalSecrets = allSecrets.filter(s => s.severity === 'CRITICAL');
|
|
322
357
|
const otherSecrets = allSecrets.filter(s => s.severity !== 'CRITICAL');
|
|
@@ -339,17 +374,12 @@ export class RefactoringEngine {
|
|
|
339
374
|
}
|
|
340
375
|
|
|
341
376
|
// Pass 5: Compile metrics summary and print diagnostics report
|
|
342
|
-
|
|
343
|
-
// =========================================================================
|
|
344
|
-
// π‘οΈ UNIFORM SLASH GRAPH EDGE RECONCILIATION LAYER (FINAL STABLE PRODUCTION)
|
|
345
|
-
// =========================================================================
|
|
346
377
|
if (!this.context.exportRegistry) this.context.exportRegistry = new Map();
|
|
347
378
|
if (!this.context.importUsageRegistry) this.context.importUsageRegistry = new Set();
|
|
348
379
|
if (!this.context.consumedRootPackages) this.context.consumedRootPackages = new Set();
|
|
349
380
|
if (!this.context.consumedWorkspacePackages) this.context.consumedWorkspacePackages = new Set();
|
|
350
381
|
if (!this.context.unlistedDependencies) this.context.unlistedDependencies = [];
|
|
351
382
|
|
|
352
|
-
// Simple internal helper to guarantee matching forward slash strings across all platforms
|
|
353
383
|
const slashify = (p) => path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
354
384
|
|
|
355
385
|
if (this.context.projectGraph && typeof this.context.projectGraph.entries === 'function') {
|
|
@@ -358,9 +388,6 @@ export class RefactoringEngine {
|
|
|
358
388
|
|
|
359
389
|
const cleanFilePath = slashify(filePath);
|
|
360
390
|
|
|
361
|
-
// π ROOT DEPS HARVESTER SHADOW TRACKING:
|
|
362
|
-
// If external packages are parsed from ANY file node in the monorepo,
|
|
363
|
-
// ensure the auditor registries register their footprint so root checking works!
|
|
364
391
|
if (fileNode.externalPackageUsage) {
|
|
365
392
|
fileNode.externalPackageUsage.forEach(pkg => {
|
|
366
393
|
const relativeToRoot = path.relative(this.context.cwd, filePath);
|
|
@@ -372,7 +399,6 @@ export class RefactoringEngine {
|
|
|
372
399
|
});
|
|
373
400
|
}
|
|
374
401
|
|
|
375
|
-
// 1. Gather all file exports using unified slashes
|
|
376
402
|
if (fileNode.internalExports) {
|
|
377
403
|
const exportKeys = typeof fileNode.internalExports.keys === 'function'
|
|
378
404
|
? Array.from(fileNode.internalExports.keys())
|
|
@@ -386,7 +412,6 @@ export class RefactoringEngine {
|
|
|
386
412
|
}
|
|
387
413
|
}
|
|
388
414
|
|
|
389
|
-
// 2. Gather cross-file usage tokens using unified slashes
|
|
390
415
|
if (fileNode.explicitImports && fileNode.importedSymbols) {
|
|
391
416
|
const symbolsArray = typeof fileNode.importedSymbols.forEach === 'function'
|
|
392
417
|
? Array.from(fileNode.importedSymbols)
|
|
@@ -395,16 +420,7 @@ export class RefactoringEngine {
|
|
|
395
420
|
for (const symbolToken of symbolsArray) {
|
|
396
421
|
if (typeof symbolToken !== 'string') continue;
|
|
397
422
|
|
|
398
|
-
// Fix: Use lastIndexOf for Windows paths (C:/path:symbol)
|
|
399
|
-
// We need to be careful with C:\path... where the second colon is the separator
|
|
400
423
|
let splitIndex = symbolToken.lastIndexOf(':');
|
|
401
|
-
|
|
402
|
-
// If the colon is part of a Windows drive (e.g., index 1), look for another one
|
|
403
|
-
if (splitIndex === 1 && symbolToken.length > 2 && /^[a-zA-Z]$/.test(symbolToken[0])) {
|
|
404
|
-
// This is a drive letter, the actual separator must be elsewhere (though unlikely in this format)
|
|
405
|
-
// But in 'C:/path:symbol', lastIndexOf(':') should already point to the correct one.
|
|
406
|
-
}
|
|
407
|
-
|
|
408
424
|
if (splitIndex === -1) continue;
|
|
409
425
|
|
|
410
426
|
const specifier = symbolToken.slice(0, splitIndex);
|
|
@@ -419,9 +435,6 @@ export class RefactoringEngine {
|
|
|
419
435
|
} else if (specifier.startsWith('.')) {
|
|
420
436
|
targetFile = path.resolve(path.dirname(filePath), specifier);
|
|
421
437
|
|
|
422
|
-
// π COMPILE-TO-SOURCE EXTENSION SWAP:
|
|
423
|
-
// If a barrel file imports relative paths using compiled targets (like './used-fn.js'),
|
|
424
|
-
// replace the extension to check for active source components directly ('.ts' / '.tsx')
|
|
425
438
|
if (targetFile.endsWith('.js')) {
|
|
426
439
|
targetFile = targetFile.slice(0, -3);
|
|
427
440
|
}
|
|
@@ -434,7 +447,6 @@ export class RefactoringEngine {
|
|
|
434
447
|
}
|
|
435
448
|
|
|
436
449
|
if (targetFile) {
|
|
437
|
-
// Enforce uniform forward slash formats on targets
|
|
438
450
|
const cleanTargetFile = Array.isArray(targetFile) ? slashify(targetFile[0]) : slashify(targetFile);
|
|
439
451
|
this.context.importUsageRegistry.add(`${cleanTargetFile}:${symbolName}`);
|
|
440
452
|
}
|
|
@@ -443,17 +455,14 @@ export class RefactoringEngine {
|
|
|
443
455
|
}
|
|
444
456
|
}
|
|
445
457
|
|
|
446
|
-
// π UNLISTED AUDITOR FALLBACK REMAPPING LAYER
|
|
447
458
|
if (this.workspaceGraph && this.workspaceGraph.packageManifests) {
|
|
448
459
|
for (const [_, metadata] of this.workspaceGraph.packageManifests.entries()) {
|
|
449
460
|
if (this.context.projectGraph) {
|
|
450
461
|
for (const [filePath, fileNode] of this.context.projectGraph.entries()) {
|
|
451
|
-
|
|
452
462
|
const cleanRelative = path.relative(metadata.rootDirectory, filePath).replace(/\\/g, '/');
|
|
453
463
|
|
|
454
464
|
if (!cleanRelative.startsWith('..') && !cleanRelative.startsWith('/') && fileNode.explicitImports) {
|
|
455
465
|
try {
|
|
456
|
-
// Switched to native sync token
|
|
457
466
|
const localManifest = JSON.parse(readFileSync(metadata.manifestPath, 'utf8'));
|
|
458
467
|
const localDeps = new Set([
|
|
459
468
|
...Object.keys(localManifest.dependencies || {}),
|
|
@@ -465,7 +474,6 @@ export class RefactoringEngine {
|
|
|
465
474
|
if (specifier.startsWith('.') || specifier.startsWith('/')) return;
|
|
466
475
|
const basePkg = specifier.startsWith('@') ? specifier.split('/').slice(0, 2).join('/') : specifier.split('/')[0];
|
|
467
476
|
|
|
468
|
-
// Ensure lookups scan local package configurations only
|
|
469
477
|
if (!localDeps.has(basePkg)) {
|
|
470
478
|
const alreadyFlagged = this.context.unlistedDependencies.some(u => u.package === basePkg && u.file === filePath);
|
|
471
479
|
if (!alreadyFlagged) {
|
|
@@ -478,7 +486,6 @@ export class RefactoringEngine {
|
|
|
478
486
|
}
|
|
479
487
|
});
|
|
480
488
|
} catch (error) {
|
|
481
|
-
// Dev logging fallback just in case JSON.parse hits bad layout characters
|
|
482
489
|
if (this.context.options.verbose) {
|
|
483
490
|
console.error(ansis.red(` β Manifest Parsing Exception: ${error.message}`));
|
|
484
491
|
}
|
|
@@ -489,12 +496,8 @@ export class RefactoringEngine {
|
|
|
489
496
|
}
|
|
490
497
|
}
|
|
491
498
|
|
|
492
|
-
// =========================================================================
|
|
493
|
-
// π‘οΈ ROOT GRAPH EDGE RECONCILIATION: Filter entry points directly inside context
|
|
494
|
-
// =========================================================================
|
|
495
499
|
if (this.workspaceGraph && this.workspaceGraph.packageManifests && this.context.orphanedFiles) {
|
|
496
500
|
const verifiedSeeds = new Set();
|
|
497
|
-
|
|
498
501
|
for (const [_, metadata] of this.workspaceGraph.packageManifests.entries()) {
|
|
499
502
|
if (metadata.entryPoints) {
|
|
500
503
|
metadata.entryPoints.forEach(absolutePath => {
|
|
@@ -505,148 +508,74 @@ export class RefactoringEngine {
|
|
|
505
508
|
|
|
506
509
|
this.context.orphanedFiles = this.context.orphanedFiles.filter(flaggedFile => {
|
|
507
510
|
const absoluteFlaggedPath = slashify(flaggedFile);
|
|
508
|
-
|
|
509
|
-
return !isAGraphSeed;
|
|
511
|
+
return !verifiedSeeds.has(absoluteFlaggedPath);
|
|
510
512
|
});
|
|
511
513
|
}
|
|
512
514
|
|
|
513
|
-
// =========================================================================
|
|
514
|
-
// π PERMANENT COMPREHENSIVE ENGINE TELEMETRY DEBUG SENSOR
|
|
515
|
-
// =========================================================================
|
|
516
515
|
if (this.context?.options?.debug || this.context?.options?.verbose) {
|
|
517
516
|
console.log('\nπ [DEBUG METRICS] Evaluating Analyzer State Matrix:');
|
|
518
517
|
console.log(` β’ OXC Analyzer available & active: ${!!this.oxcAnalyzer?.isAvailable}`);
|
|
519
|
-
if (!this.oxcAnalyzer?.isAvailable && this.context?.options?.verbose) {
|
|
520
|
-
console.log(ansis.yellow(` β οΈ OXC could not be initialized. Check if 'oxc-parser' is installed.`));
|
|
521
|
-
}
|
|
522
518
|
console.log(` β’ Fast Mode execution flag state: ${!!this.context?.options?.fastMode}`);
|
|
523
519
|
console.log(` β’ Total files logged in exportRegistry: ${this.context?.exportRegistry ? this.context.exportRegistry.size : 0}`);
|
|
524
520
|
console.log(` β’ Total tracking tokens inside importUsageRegistry: ${this.context?.importUsageRegistry ? this.context.importUsageRegistry.size : 0}`);
|
|
525
521
|
console.log(` β’ Total unlisted dependencies intercepted: ${this.context?.unlistedDependencies ? this.context.unlistedDependencies.length : 0}`);
|
|
526
|
-
console.log(` β’ Consumed root external package names: [${Array.from(this.context?.consumedRootPackages || []).join(', ')}]`);
|
|
527
|
-
console.log(` β’ Consumed workspace package names: [${Array.from(this.context?.consumedWorkspacePackages || []).join(', ')}]`);
|
|
528
522
|
console.log('------------------------------------------------------------\n');
|
|
529
523
|
}
|
|
530
524
|
|
|
531
525
|
const analysisSummary = await this.context.generateSummaryReport();
|
|
532
526
|
analysisSummary.hardcodedSecrets = allSecrets;
|
|
533
527
|
|
|
534
|
-
//
|
|
528
|
+
// const reachabilityResults = this.deadCodeDetector.detectDeadCode(this.context.projectGraph);
|
|
529
|
+
// analysisSummary.orphanedFiles = reachabilityResults.deadFiles.map(f => path.relative(this.context.cwd, f));
|
|
530
|
+
|
|
531
|
+
/* if (reachabilityResults.deadExports.length > 0) {
|
|
532
|
+
analysisSummary.deadExports = analysisSummary.deadExports.filter(de => {
|
|
533
|
+
return !analysisSummary.orphanedFiles.includes(de.file);
|
|
534
|
+
});
|
|
535
|
+
}*/
|
|
536
|
+
|
|
535
537
|
try {
|
|
536
538
|
const rootPkgPath = path.join(this.context.cwd, 'package.json');
|
|
537
539
|
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf8'));
|
|
538
540
|
const rootDeps = Object.keys(rootPkg.dependencies || {});
|
|
539
541
|
|
|
540
542
|
for (const dep of rootDeps) {
|
|
541
|
-
// Fix: Evaluate both root and workspace tracking sets to find shadowed root dependencies
|
|
542
543
|
const usedInRoot = this.context.consumedRootPackages?.has(dep);
|
|
543
544
|
const usedInWorkspaces = this.context.consumedWorkspacePackages?.has(dep);
|
|
544
545
|
|
|
545
546
|
if (!usedInRoot && usedInWorkspaces) {
|
|
546
|
-
const structuralViolation = {
|
|
547
|
-
package: dep,
|
|
548
|
-
type: 'dependency',
|
|
549
|
-
manifest: 'package.json'
|
|
550
|
-
};
|
|
551
|
-
|
|
547
|
+
const structuralViolation = { package: dep, type: 'dependency', manifest: 'package.json' };
|
|
552
548
|
if (!analysisSummary.unusedDependencies) analysisSummary.unusedDependencies = [];
|
|
553
549
|
const alreadyLogged = analysisSummary.unusedDependencies.some(d => d.package === dep);
|
|
554
|
-
if (!alreadyLogged)
|
|
555
|
-
analysisSummary.unusedDependencies.push(structuralViolation);
|
|
556
|
-
}
|
|
550
|
+
if (!alreadyLogged) analysisSummary.unusedDependencies.push(structuralViolation);
|
|
557
551
|
}
|
|
558
552
|
}
|
|
559
553
|
} catch (e) {}
|
|
560
554
|
|
|
561
|
-
|
|
562
|
-
analysisSummary.deadExports = [];
|
|
555
|
+
const slashifyLocal = (p) => p ? path.resolve(this.context.cwd, p).replace(/\\/g, '/') : '';
|
|
563
556
|
if (this.context.exportRegistry && this.workspaceGraph) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
557
|
+
analysisSummary.deadExports = (analysisSummary.deadExports || []).filter(de => {
|
|
558
|
+
if (!de || !de.file) return false;
|
|
559
|
+
const absPath = path.resolve(this.context.cwd, de.file);
|
|
560
|
+
const cleanAbsPath = slashifyLocal(absPath);
|
|
561
|
+
const node = this.context.projectGraph.get(cleanAbsPath);
|
|
571
562
|
|
|
563
|
+
if (node && (node.isLibraryEntry || node.isEntry)) return false;
|
|
564
|
+
|
|
572
565
|
let isPackageEntryPoint = false;
|
|
573
566
|
for (const [_, metadata] of this.workspaceGraph.packageManifests.entries()) {
|
|
574
|
-
if (metadata.entryPoints.map(p =>
|
|
567
|
+
if (metadata.entryPoints && metadata.entryPoints.map(p => slashifyLocal(p)).includes(cleanAbsPath)) {
|
|
575
568
|
isPackageEntryPoint = true;
|
|
576
569
|
break;
|
|
577
570
|
}
|
|
578
571
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
for (const symbol of exportsSet) {
|
|
582
|
-
const consumptionToken = `${cleanExportedFile}:${symbol}`;
|
|
583
|
-
if (!this.context.importUsageRegistry?.has(consumptionToken)) {
|
|
584
|
-
analysisSummary.deadExports.push({
|
|
585
|
-
symbol: symbol,
|
|
586
|
-
file: relativeExportedFile,
|
|
587
|
-
line: 7
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
}
|
|
572
|
+
return !isPackageEntryPoint;
|
|
573
|
+
});
|
|
592
574
|
}
|
|
593
575
|
analysisSummary.unlistedDependencies = this.context.unlistedDependencies || [];
|
|
594
576
|
|
|
595
|
-
// NEW: Advanced Program Analysis v4.5.0 (JIT, Topology, SAST)
|
|
596
577
|
const advancedResults = this.advancedAnalysis.runAll(this.context.projectGraph, this.workspaceGraph.packageManifests);
|
|
597
|
-
|
|
598
|
-
if (this.context.options.verbose) {
|
|
599
|
-
if (advancedResults.jitWarnings.length > 0) {
|
|
600
|
-
console.log(ansis.bold.yellow(`\nβ‘ JIT Optimization Warnings (${advancedResults.jitWarnings.length}):`));
|
|
601
|
-
advancedResults.jitWarnings.forEach(w => console.log(ansis.yellow(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
602
|
-
}
|
|
603
|
-
if (advancedResults.securityFindings.length > 0) {
|
|
604
|
-
console.log(ansis.bold.red(`\nπ‘οΈ Security Vulnerabilities (${advancedResults.securityFindings.length}):`));
|
|
605
|
-
advancedResults.securityFindings.forEach(w => console.log(ansis.red(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
606
|
-
}
|
|
607
|
-
if (advancedResults.topologyWarnings.length > 0) {
|
|
608
|
-
console.log(ansis.bold.blue(`\nπ Topology & Reachability Warnings (${advancedResults.topologyWarnings.length}):`));
|
|
609
|
-
advancedResults.topologyWarnings.forEach(w => console.log(ansis.blue(` β’ [${w.type}] ${w.message} (${w.file})`)));
|
|
610
|
-
}
|
|
611
|
-
if (advancedResults.integrityWarnings.length > 0) {
|
|
612
|
-
console.log(ansis.bold.cyan(`\nπ Config Integrity Checks (${advancedResults.integrityWarnings.length}):`));
|
|
613
|
-
advancedResults.integrityWarnings.forEach(w => console.log(ansis.cyan(` β’ [${w.type}] ${w.message} (${w.file})`)));
|
|
614
|
-
}
|
|
615
|
-
if (advancedResults.leakWarnings.length > 0) {
|
|
616
|
-
console.log(ansis.bold.magenta(`\nπ§ Event Leak Risk Analysis (${advancedResults.leakWarnings.length}):`));
|
|
617
|
-
advancedResults.leakWarnings.forEach(w => console.log(ansis.magenta(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
618
|
-
}
|
|
619
|
-
if (advancedResults.binaryWarnings.length > 0) {
|
|
620
|
-
console.log(ansis.bold.white(`\nποΈ Binary Shaking Audit (${advancedResults.binaryWarnings.length}):`));
|
|
621
|
-
advancedResults.binaryWarnings.forEach(w => console.log(ansis.white(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
622
|
-
}
|
|
623
|
-
if (advancedResults.sandboxViolations.length > 0) {
|
|
624
|
-
console.log(ansis.bold.bgRed.white(`\nπ§± Architectural Sandbox Violations (${advancedResults.sandboxViolations.length}):`));
|
|
625
|
-
advancedResults.sandboxViolations.forEach(w => console.log(ansis.red(` β’ [${w.type}] ${w.message} (${w.file})`)));
|
|
626
|
-
}
|
|
627
|
-
if (advancedResults.dereferenceWarnings.length > 0) {
|
|
628
|
-
console.log(ansis.bold.bgBlack.red(`\nπ₯ Guaranteed Runtime Exceptions (${advancedResults.dereferenceWarnings.length}):`));
|
|
629
|
-
advancedResults.dereferenceWarnings.forEach(w => console.log(ansis.red(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
630
|
-
}
|
|
631
|
-
if (advancedResults.cloneFindings.length > 0) {
|
|
632
|
-
console.log(ansis.bold.bgCyan.black(`\nπ― Structural AST Clones Detected (${advancedResults.cloneFindings.length}):`));
|
|
633
|
-
advancedResults.cloneFindings.forEach(w => console.log(ansis.cyan(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
634
|
-
}
|
|
635
|
-
if (advancedResults.scopeWarnings.length > 0) {
|
|
636
|
-
console.log(ansis.bold.bgGreen.black(`\nπ Scope Minimization Suggestions (${advancedResults.scopeWarnings.length}):`));
|
|
637
|
-
advancedResults.scopeWarnings.forEach(w => console.log(ansis.green(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
638
|
-
}
|
|
639
|
-
if (advancedResults.loopWarnings.length > 0) {
|
|
640
|
-
console.log(ansis.bold.bgYellow.black(`\nπ Infinite Execution Proofs (${advancedResults.loopWarnings.length}):`));
|
|
641
|
-
advancedResults.loopWarnings.forEach(w => console.log(ansis.yellow(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
642
|
-
}
|
|
643
|
-
if (advancedResults.configWarnings.length > 0) {
|
|
644
|
-
console.log(ansis.bold.bgBlue.white(`\nπ§Ό Configuration Sanitizer (${advancedResults.configWarnings.length}):`));
|
|
645
|
-
advancedResults.configWarnings.forEach(w => console.log(ansis.blue(` β’ [${w.type}] ${w.message} (${w.file}:${w.line})`)));
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
const cycles = cyclesResult; // Use the already detected cycles
|
|
578
|
+
const cycles = cyclesResult;
|
|
650
579
|
|
|
651
580
|
const structuralModificationsStaged =
|
|
652
581
|
analysisSummary.orphanedFiles.length > 0 ||
|
|
@@ -672,31 +601,25 @@ export class RefactoringEngine {
|
|
|
672
601
|
|
|
673
602
|
if (analysisSummary.unusedDependencies && analysisSummary.unusedDependencies.length > 0) {
|
|
674
603
|
console.log(ansis.bold(` π¦ Remove ${analysisSummary.unusedDependencies.length} unused dependencies:`));
|
|
675
|
-
analysisSummary.unusedDependencies.forEach(d => {
|
|
676
|
-
|
|
677
|
-
|
|
604
|
+
analysisSummary.unusedDependencies.forEach(d => console.log(ansis.dim(` β’ ${d.package} (${d.type} in ${d.manifest})`)));
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (analysisSummary.missingDependencies && analysisSummary.missingDependencies.length > 0) {
|
|
608
|
+
console.log(ansis.bold(` π¦ Add ${analysisSummary.missingDependencies.length} missing dependencies:`));
|
|
609
|
+
analysisSummary.missingDependencies.forEach(dep => console.log(ansis.dim(` β’ ${dep} (detected via source usage)`)));
|
|
678
610
|
}
|
|
679
611
|
|
|
680
|
-
// π¨ TARGET BUG 2: Print Alert layout warning for your unlisted package detections!
|
|
681
612
|
if (analysisSummary.unlistedDependencies && analysisSummary.unlistedDependencies.length > 0) {
|
|
682
613
|
console.log(ansis.bold.red(` β οΈ Missing Declarations (Unlisted Packages Detected):`));
|
|
683
|
-
analysisSummary.unlistedDependencies.forEach(u => {
|
|
684
|
-
console.log(ansis.dim(` β’ ${u.package} is imported in ${u.file} but missing from ${u.manifest}`));
|
|
685
|
-
});
|
|
614
|
+
analysisSummary.unlistedDependencies.forEach(u => console.log(ansis.dim(` β’ ${u.package} is imported in ${u.file} but missing from ${u.manifest}`)));
|
|
686
615
|
}
|
|
687
616
|
|
|
688
617
|
if (cycles.length > 0) {
|
|
689
618
|
console.log(ansis.bold.magenta(` π Circular Dependencies Detected (${cycles.length}):`));
|
|
690
619
|
cycles.forEach((cycle, idx) => {
|
|
691
|
-
|
|
692
|
-
const relativeCycle = cycle.map(p => path.relative(this.context.cwd, p));
|
|
693
|
-
// Close the cycle visually by adding the first element at the end
|
|
694
|
-
if (relativeCycle.length > 0) {
|
|
695
|
-
relativeCycle.push(relativeCycle[0]);
|
|
696
|
-
}
|
|
620
|
+
const relativeCycle = cycle.map(p => path.relative(this.context.cwd, p).replace(/\\/g, '/'));
|
|
697
621
|
console.log(ansis.dim(` β’ Cycle #${idx + 1}: ${relativeCycle.join(' -> ')}`));
|
|
698
622
|
});
|
|
699
|
-
console.log(ansis.italic.gray(' (Note: Automated resolution for circular dependencies is disabled to prevent structural damage.)'));
|
|
700
623
|
}
|
|
701
624
|
|
|
702
625
|
console.log(ansis.dim('------------------------------------------------------------'));
|
|
@@ -709,7 +632,6 @@ export class RefactoringEngine {
|
|
|
709
632
|
}
|
|
710
633
|
|
|
711
634
|
if (proceed) {
|
|
712
|
-
// Execute healing lifecycle (git-state-capture -> apply -> verify -> commit/rollback)
|
|
713
635
|
await this.selfHealer.runSelfHealingLifecycle(async () => {
|
|
714
636
|
for (const relPath of analysisSummary.orphanedFiles) {
|
|
715
637
|
const absPath = path.resolve(this.context.cwd, relPath);
|
|
@@ -729,8 +651,6 @@ export class RefactoringEngine {
|
|
|
729
651
|
const nextText = await this.sourceRewriter.stripNamedExportSignature(absPath, unusedExport.symbol, meta);
|
|
730
652
|
await this.txManager.stageWrite(absPath, nextText);
|
|
731
653
|
await this.typeIntegrity.synchronizeDeclarationFile(absPath, unusedExport.symbol);
|
|
732
|
-
} else if (this.context.verbose) {
|
|
733
|
-
console.log(ansis.gray(`π‘οΈ Preserving symbol export [${unusedExport.symbol}] due to: ${safetyVerdict.blockReason}`));
|
|
734
654
|
}
|
|
735
655
|
}
|
|
736
656
|
});
|
|
@@ -753,7 +673,6 @@ export class RefactoringEngine {
|
|
|
753
673
|
|
|
754
674
|
async _generateVisualization(graph) {
|
|
755
675
|
console.log(ansis.bold.green('\nπ [VISUALIZER] Generating Interactive Execution Graph...'));
|
|
756
|
-
|
|
757
676
|
const nodes = [];
|
|
758
677
|
const edges = [];
|
|
759
678
|
const fileToIndex = new Map();
|
|
@@ -776,57 +695,11 @@ export class RefactoringEngine {
|
|
|
776
695
|
const fromId = fileToIndex.get(file);
|
|
777
696
|
node.outgoingEdges.forEach(edgeFile => {
|
|
778
697
|
const toId = fileToIndex.get(edgeFile);
|
|
779
|
-
if (toId) {
|
|
780
|
-
edges.push({ from: fromId, to: toId, arrows: 'to' });
|
|
781
|
-
}
|
|
698
|
+
if (toId) edges.push({ from: fromId, to: toId, arrows: 'to' });
|
|
782
699
|
});
|
|
783
700
|
}
|
|
784
701
|
|
|
785
|
-
const html =
|
|
786
|
-
<!DOCTYPE html>
|
|
787
|
-
<html>
|
|
788
|
-
<head>
|
|
789
|
-
<title>entkapp Execution Graph</title>
|
|
790
|
-
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
|
|
791
|
-
<style type="text/css">
|
|
792
|
-
body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background-color: #2d3436; color: #dfe6e9; font-family: sans-serif; }
|
|
793
|
-
#network { width: 100%; height: 100%; }
|
|
794
|
-
#header { position: absolute; top: 10px; left: 10px; z-index: 10; pointer-events: none; }
|
|
795
|
-
h1 { margin: 0; font-size: 1.5rem; color: #fab1a0; }
|
|
796
|
-
.legend { margin-top: 5px; font-size: 0.9rem; }
|
|
797
|
-
.legend-item { display: inline-block; margin-right: 15px; }
|
|
798
|
-
.dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; }
|
|
799
|
-
</style>
|
|
800
|
-
</head>
|
|
801
|
-
<body>
|
|
802
|
-
<div id="header">
|
|
803
|
-
<h1>entkapp Execution Graph</h1>
|
|
804
|
-
<div class="legend">
|
|
805
|
-
<div class="legend-item"><span class="dot" style="background-color: #ff7675; border-radius: 0; transform: rotate(45deg);"></span> Entry Point</div>
|
|
806
|
-
<div class="legend-item"><span class="dot" style="background-color: #74b9ff;"></span> Module</div>
|
|
807
|
-
</div>
|
|
808
|
-
</div>
|
|
809
|
-
<div id="network"></div>
|
|
810
|
-
<script type="text/javascript">
|
|
811
|
-
const nodes = new vis.DataSet(${JSON.stringify(nodes)});
|
|
812
|
-
const edges = new vis.DataSet(${JSON.stringify(edges)});
|
|
813
|
-
const container = document.getElementById('network');
|
|
814
|
-
const data = { nodes, edges };
|
|
815
|
-
const options = {
|
|
816
|
-
nodes: { font: { color: '#dfe6e9', size: 14 } },
|
|
817
|
-
edges: { color: { color: '#636e72', highlight: '#fab1a0' }, width: 2 },
|
|
818
|
-
physics: {
|
|
819
|
-
forceAtlas2Based: { gravitationalConstant: -50, centralGravity: 0.01, springLength: 100, springConstant: 0.08 },
|
|
820
|
-
maxVelocity: 50,
|
|
821
|
-
solver: 'forceAtlas2Based',
|
|
822
|
-
timestep: 0.35,
|
|
823
|
-
stabilization: { iterations: 150 }
|
|
824
|
-
}
|
|
825
|
-
};
|
|
826
|
-
new vis.Network(container, data, options);
|
|
827
|
-
</script>
|
|
828
|
-
</body>
|
|
829
|
-
</html>`;
|
|
702
|
+
const html = `<!DOCTYPE html><html><head><title>entkapp Execution Graph</title><script src="https://unpkg.com"></script><style>body,html{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background-color:#2d3436;color:#dfe6e9;font-family:sans-serif;}#network{width:100%;height:100%;}#header{position:absolute;top:10px;left:10px;z-index:10;pointer-events:none;}h1{margin:0;font-size:1.5rem;color:#fab1a0;}.legend{margin-top:5px;font-size:0.9rem;}.legend-item{display:inline-block;margin-right:15px;}.dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:5px;}</style></head><body><div id="header"><h1>entkapp Execution Graph</h1><div class="legend"><div class="legend-item"><span class="dot" style="background-color:#ff7675;border-radius:0;transform:rotate(45deg);"></span> Entry Point</div><div class="legend-item"><span class="dot" style="background-color:#74b9ff;"></span> Module</div></div></div><div id="network"></div><script>const nodes=new vis.DataSet(${JSON.stringify(nodes)});const edges=new vis.DataSet(${JSON.stringify(edges)});const container=document.getElementById('network');const data={nodes,edges};const options={nodes:{font:{color:'#dfe6e9',size:14}},edges:{color:{color:'#636e72',highlight:#fab1a0},width:2},physics:{forceAtlas2Based:{gravitationalConstant:-50,centralGravity:0.01,springLength:100,springConstant:0.08},maxVelocity:50,solver:'forceAtlas2Based',timestep:0.35,stabilization:{iterations:150}}};new vis.Network(container,data,options);</script></body></html>`;
|
|
830
703
|
|
|
831
704
|
const http = await import('http');
|
|
832
705
|
const server = http.createServer((req, res) => {
|
|
@@ -837,13 +710,11 @@ export class RefactoringEngine {
|
|
|
837
710
|
const port = 3000;
|
|
838
711
|
server.listen(port, () => {
|
|
839
712
|
console.log(ansis.bold.cyan(`\nπ Web Viewer active at: http://localhost:${port}`));
|
|
840
|
-
console.log(ansis.yellow('Press Ctrl+C to terminate the session and continue...'));
|
|
841
713
|
});
|
|
842
714
|
|
|
843
715
|
return new Promise((resolve) => {
|
|
844
716
|
process.on('SIGINT', () => {
|
|
845
717
|
server.close();
|
|
846
|
-
console.log(ansis.bold.red('\nπ Web Viewer stopped.'));
|
|
847
718
|
resolve();
|
|
848
719
|
});
|
|
849
720
|
});
|
|
@@ -855,7 +726,6 @@ export class RefactoringEngine {
|
|
|
855
726
|
const res = path.resolve(dir, entry.name);
|
|
856
727
|
if (entry.isDirectory()) {
|
|
857
728
|
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.entkapp-cache') continue;
|
|
858
|
-
if (this.context.verbose) console.log(ansis.dim(`π Scanning deep folder: ${res}`));
|
|
859
729
|
await this.discoverSourceFiles(res, fileList);
|
|
860
730
|
} else {
|
|
861
731
|
const ext = path.extname(entry.name);
|
|
@@ -867,75 +737,146 @@ export class RefactoringEngine {
|
|
|
867
737
|
}
|
|
868
738
|
|
|
869
739
|
async linkDependencyGraph() {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
740
|
+
const slashify = (p) => {
|
|
741
|
+
let abs = path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
742
|
+
if (/^[a-z]:\//i.test(abs)) {
|
|
743
|
+
abs = abs.charAt(0).toUpperCase() + abs.slice(1);
|
|
873
744
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
745
|
+
return abs;
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// =========================================================================
|
|
749
|
+
// π PHASE 1: SAUBERE KANTEN-VERKNΓPFUNG (Zuerst das Netz spinnen!)
|
|
750
|
+
// =========================================================================
|
|
751
|
+
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
752
|
+
const cleanSrcPath = slashify(filePath);
|
|
753
|
+
|
|
754
|
+
// Pass A: Link all explicit and dynamic imports safely
|
|
755
|
+
const allDirectImports = new Set([...node.explicitImports, ...node.dynamicImports]);
|
|
756
|
+
for (const specifier of allDirectImports) {
|
|
757
|
+
if (specifier.startsWith('__DYNAMIC_PATTERN__:')) continue;
|
|
758
|
+
if (this.context.verbose) console.log(`[Linker-DEBUG] Attempting to resolve ${specifier} from ${cleanSrcPath}`);
|
|
759
|
+
try {
|
|
760
|
+
const resolvedPath = this.resolver.resolveModulePath(cleanSrcPath, specifier);
|
|
761
|
+
if (this.context.verbose) console.log(`[Linker-DEBUG] Resolved to: ${resolvedPath}`);
|
|
762
|
+
if (resolvedPath && this.context.projectGraph.has(resolvedPath)) {
|
|
763
|
+
const cleanTargetPath = slashify(resolvedPath);
|
|
764
|
+
this.context.projectGraph.get(cleanTargetPath).incomingEdges.add(cleanSrcPath);
|
|
765
|
+
node.outgoingEdges.add(cleanTargetPath);
|
|
880
766
|
}
|
|
881
|
-
|
|
882
|
-
|
|
767
|
+
} catch (e) {}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Pass B: Link named-symbol imports through barrel/re-export chains safely
|
|
771
|
+
for (const specToken of node.importedSymbols) {
|
|
772
|
+
try {
|
|
773
|
+
const delimiterIndex = specToken.lastIndexOf(':');
|
|
774
|
+
if (delimiterIndex === -1) continue;
|
|
775
|
+
const specifier = specToken.slice(0, delimiterIndex);
|
|
776
|
+
const symbol = specToken.slice(delimiterIndex + 1);
|
|
883
777
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
if (
|
|
889
|
-
|
|
778
|
+
const resolvedPath = this.resolver.resolveModulePath(cleanSrcPath, specifier);
|
|
779
|
+
if (!resolvedPath) continue;
|
|
780
|
+
const cleanResolvedPath = slashify(resolvedPath);
|
|
781
|
+
|
|
782
|
+
if (symbol === '*') {
|
|
783
|
+
if (this.context.projectGraph.has(cleanResolvedPath)) {
|
|
784
|
+
this.context.projectGraph.get(cleanResolvedPath).incomingEdges.add(cleanSrcPath);
|
|
785
|
+
node.outgoingEdges.add(cleanResolvedPath);
|
|
786
|
+
|
|
787
|
+
const targetNode = this.context.projectGraph.get(cleanResolvedPath);
|
|
788
|
+
for (const [expName, expMeta] of targetNode.internalExports.entries()) {
|
|
789
|
+
if (expMeta.type === 're-export-all' || expMeta.type === 're-export') {
|
|
790
|
+
const nestedPath = this.resolver.resolveModulePath(cleanResolvedPath, expMeta.source || expMeta.originalName);
|
|
791
|
+
if (nestedPath && this.context.projectGraph.has(slashify(nestedPath))) {
|
|
792
|
+
this.context.projectGraph.get(slashify(nestedPath)).incomingEdges.add(cleanResolvedPath);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
} else {
|
|
798
|
+
const traceResolution = await this.barrelParser.determineSymbolDeclarationOrigin(cleanResolvedPath, symbol, this.context.projectGraph);
|
|
799
|
+
if (traceResolution && traceResolution.originFile) {
|
|
800
|
+
const cleanOriginFile = slashify(traceResolution.originFile);
|
|
801
|
+
if (this.context.projectGraph.has(cleanOriginFile)) {
|
|
802
|
+
this.context.projectGraph.get(cleanOriginFile).incomingEdges.add(cleanSrcPath);
|
|
803
|
+
node.outgoingEdges.add(cleanOriginFile);
|
|
804
|
+
if (!this.context.importUsageRegistry) this.context.importUsageRegistry = new Set();
|
|
805
|
+
this.context.importUsageRegistry.add(`${cleanOriginFile}:${traceResolution.originSymbol}`);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
890
808
|
}
|
|
891
|
-
}
|
|
809
|
+
} catch (e) {}
|
|
892
810
|
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// =========================================================================
|
|
814
|
+
// π PHASE 2: SELEKTIVE ENTRY POINT IMMUNITΓT (Erst jetzt Heuristik prΓΌfen!)
|
|
815
|
+
// =========================================================================
|
|
816
|
+
const potentialEntryPoints = new Set();
|
|
817
|
+
let hasManifestEntries = false;
|
|
893
818
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
819
|
+
try {
|
|
820
|
+
const pkgPath = path.join(this.context.cwd, 'package.json');
|
|
821
|
+
if (existsSync(pkgPath)) {
|
|
822
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
823
|
+
const packageEntries = this.workspaceGraph.calculatePackageExportsEntries(pkg, this.context.cwd);
|
|
824
|
+
if (packageEntries.length > 0) {
|
|
825
|
+
hasManifestEntries = true;
|
|
826
|
+
for (const absEntry of packageEntries) {
|
|
827
|
+
potentialEntryPoints.add(slashify(absEntry));
|
|
899
828
|
}
|
|
900
829
|
}
|
|
901
830
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
831
|
+
} catch (e) {}
|
|
832
|
+
|
|
833
|
+
if (!hasManifestEntries && this.context.entryPoints.length === 0) {
|
|
834
|
+
const rootIndexFiles = ['src/index.ts', 'src/index.js', 'src/index.tsx', 'src/index.jsx', 'index.ts', 'index.js', 'src/main.ts', 'src/main.js', 'main.ts', 'main.js'];
|
|
835
|
+
for (const indexFile of rootIndexFiles) potentialEntryPoints.add(slashify(indexFile));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const protectedFiles = new Set();
|
|
839
|
+
for (const [filePath] of this.context.projectGraph.entries()) {
|
|
840
|
+
const fileName = path.basename(filePath);
|
|
841
|
+
if (/\.(test|spec|e2e)\.(ts|js|tsx|jsx)$/.test(fileName) || filePath.includes('/__tests__/') || filePath.includes('/tests/') || /\.(config|rc)\.(ts|js|mjs|cjs)$/.test(fileName)) {
|
|
842
|
+
protectedFiles.add(slashify(filePath));
|
|
910
843
|
}
|
|
844
|
+
}
|
|
911
845
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
if (
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
} else {
|
|
930
|
-
// Named import: trace through barrel files to the actual declaration origin.
|
|
931
|
-
const traceResolution = await this.barrelParser.determineSymbolDeclarationOrigin(resolvedPath, symbol, this.context.projectGraph);
|
|
932
|
-
if (traceResolution && this.context.projectGraph.has(traceResolution.originFile)) {
|
|
933
|
-
this.context.projectGraph.get(traceResolution.originFile).incomingEdges.add(filePath);
|
|
934
|
-
node.outgoingEdges.add(traceResolution.originFile);
|
|
935
|
-
node.importedSymbols.add(`${traceResolution.originFile}:${traceResolution.symbolName}`);
|
|
846
|
+
// JETZT haben die Kanten verlΓ€ssliche incomingEdges-GrΓΆΓen!
|
|
847
|
+
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
848
|
+
const absPath = slashify(filePath);
|
|
849
|
+
const isProtected = protectedFiles.has(absPath);
|
|
850
|
+
const isManifestEntry = potentialEntryPoints.has(absPath);
|
|
851
|
+
|
|
852
|
+
const hasNoIncoming = node.incomingEdges.size === 0;
|
|
853
|
+
const hasOutgoing = node.outgoingEdges.size > 0 || node.externalPackageUsage.size > 0 || node.dynamicImports.size > 0;
|
|
854
|
+
|
|
855
|
+
let isExplicitlyDeclared = isManifestEntry;
|
|
856
|
+
if (!isExplicitlyDeclared) {
|
|
857
|
+
const cleanAbsPath = absPath.replace(/\.[^/.]+$/, "");
|
|
858
|
+
for (const candidate of potentialEntryPoints) {
|
|
859
|
+
if (candidate.replace(/\.[^/.]+$/, "") === cleanAbsPath) {
|
|
860
|
+
isExplicitlyDeclared = true;
|
|
861
|
+
break;
|
|
936
862
|
}
|
|
937
863
|
}
|
|
938
864
|
}
|
|
865
|
+
|
|
866
|
+
const usesItsImports = node.instantiatedIdentifiers && node.instantiatedIdentifiers.size > 0;
|
|
867
|
+
const isLikelyBarrel = !isExplicitlyDeclared && (node.isPureBarrel || node.isBarrel || (!usesItsImports && hasOutgoing));
|
|
868
|
+
|
|
869
|
+
let finalIsEntry = false;
|
|
870
|
+
if (isProtected || isExplicitlyDeclared) {
|
|
871
|
+
finalIsEntry = true;
|
|
872
|
+
} else if (!hasManifestEntries && hasNoIncoming && hasOutgoing && !isLikelyBarrel) {
|
|
873
|
+
finalIsEntry = true;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
node.isEntry = finalIsEntry;
|
|
877
|
+
if (finalIsEntry && this.context.options.verbose) {
|
|
878
|
+
console.log(`π― [ENTRY POINT CONFIRMED] Wurzel gesichert: ${path.relative(this.context.cwd, absPath)}`);
|
|
879
|
+
}
|
|
939
880
|
}
|
|
940
881
|
}
|
|
941
882
|
|
|
@@ -943,12 +884,9 @@ export class RefactoringEngine {
|
|
|
943
884
|
try {
|
|
944
885
|
const text = await fs.readFile(packageJsonPath, 'utf8');
|
|
945
886
|
const data = JSON.parse(text);
|
|
946
|
-
const prodDeps = Object.keys(data.dependencies || {});
|
|
947
|
-
const devDeps = Object.keys(data.devDependencies || {});
|
|
948
|
-
|
|
949
887
|
this.context.manifestDependencies.set(packageJsonPath, {
|
|
950
|
-
dependencies:
|
|
951
|
-
devDependencies:
|
|
888
|
+
dependencies: Object.keys(data.dependencies || {}),
|
|
889
|
+
devDependencies: Object.keys(data.devDependencies || {}),
|
|
952
890
|
peerDependencies: Object.keys(data.peerDependencies || {}),
|
|
953
891
|
optionalDependencies: Object.keys(data.optionalDependencies || {})
|
|
954
892
|
});
|
|
@@ -961,29 +899,6 @@ export class RefactoringEngine {
|
|
|
961
899
|
console.log(`β±οΈ Analysis Duration: ${summary.executionDuration}`);
|
|
962
900
|
console.log(`π Total Files Scanned: ${summary.totalFilesProcessed}`);
|
|
963
901
|
console.log(`πΎ Cache Optimization: ${summary.graphCacheOptimization.ratio} hits`);
|
|
964
|
-
|
|
965
|
-
console.log(ansis.bold('\nπ Structural Integrity:'));
|
|
966
|
-
const secretCount = (summary.structuralIssuesDetected.hardcodedSecrets || []).length;
|
|
967
|
-
if (summary.structuralIssuesDetected.deadFiles.length === 0 &&
|
|
968
|
-
summary.structuralIssuesDetected.deadExports.length === 0 &&
|
|
969
|
-
summary.structuralIssuesDetected.unusedDependencies.length === 0 &&
|
|
970
|
-
secretCount === 0) {
|
|
971
|
-
console.log(ansis.green(' β
No major structural debt detected.'));
|
|
972
|
-
} else {
|
|
973
|
-
if (summary.structuralIssuesDetected.deadFiles.length > 0) {
|
|
974
|
-
console.log(ansis.red(` β Found ${summary.structuralIssuesDetected.deadFiles.length} orphaned/dead files.`));
|
|
975
|
-
}
|
|
976
|
-
if (summary.structuralIssuesDetected.deadExports.length > 0) {
|
|
977
|
-
console.log(ansis.yellow(` β οΈ Found ${summary.structuralIssuesDetected.deadExports.length} unused named exports.`));
|
|
978
|
-
}
|
|
979
|
-
if (summary.structuralIssuesDetected.unusedDependencies.length > 0) {
|
|
980
|
-
console.log(ansis.yellow(` π¦ Found ${summary.structuralIssuesDetected.unusedDependencies.length} unused dependencies.`));
|
|
981
|
-
}
|
|
982
|
-
if (secretCount > 0) {
|
|
983
|
-
console.log(ansis.red(` π Found ${secretCount} hardcoded secret(s) / credential(s).`));
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
902
|
console.log(ansis.dim('\n------------------------------------------------------------\n'));
|
|
988
903
|
}
|
|
989
904
|
|
|
@@ -991,20 +906,16 @@ export class RefactoringEngine {
|
|
|
991
906
|
if (cachedRecord.explicitImports) cachedRecord.explicitImports.forEach(i => node.explicitImports.add(i));
|
|
992
907
|
if (cachedRecord.dynamicImports) cachedRecord.dynamicImports.forEach(i => node.dynamicImports.add(i));
|
|
993
908
|
if (cachedRecord.importedSymbols) cachedRecord.importedSymbols.forEach(s => node.importedSymbols.add(s));
|
|
994
|
-
if (cachedRecord.internalExports)
|
|
995
|
-
|
|
996
|
-
}
|
|
997
|
-
if (cachedRecord.symbolSourceLocations) {
|
|
998
|
-
Object.entries(cachedRecord.symbolSourceLocations).forEach(([k, v]) => node.symbolSourceLocations.set(k, v));
|
|
999
|
-
}
|
|
909
|
+
if (cachedRecord.internalExports) Object.entries(cachedRecord.internalExports).forEach(([k, v]) => node.internalExports.set(k, v));
|
|
910
|
+
if (cachedRecord.symbolSourceLocations) Object.entries(cachedRecord.symbolSourceLocations).forEach(([k, v]) => node.symbolSourceLocations.set(k, v));
|
|
1000
911
|
if (cachedRecord.externalPackageUsage) cachedRecord.externalPackageUsage.forEach(p => node.externalPackageUsage.add(p));
|
|
1001
912
|
if (cachedRecord.rawStringReferences) cachedRecord.rawStringReferences.forEach(r => node.rawStringReferences.add(r));
|
|
1002
913
|
if (cachedRecord.instantiatedIdentifiers) cachedRecord.instantiatedIdentifiers.forEach(id => node.instantiatedIdentifiers.add(id));
|
|
1003
914
|
if (cachedRecord.propertyAccessChains) cachedRecord.propertyAccessChains.forEach(c => node.propertyAccessChains.add(c));
|
|
1004
915
|
if (cachedRecord.localSuppressedRules) cachedRecord.localSuppressedRules.forEach(r => node.localSuppressedRules.add(r));
|
|
1005
|
-
if (cachedRecord.calculatedDynamicImports) node.calculatedDynamicImports = cachedRecord.calculatedDynamicImports;
|
|
1006
916
|
if (cachedRecord.isLibraryEntry !== undefined) node.isLibraryEntry = cachedRecord.isLibraryEntry;
|
|
1007
917
|
if (cachedRecord.isEntry !== undefined) node.isEntry = cachedRecord.isEntry;
|
|
1008
|
-
if (cachedRecord.
|
|
918
|
+
if (cachedRecord.calculatedDynamicImports) node.calculatedDynamicImports = cachedRecord.calculatedDynamicImports;
|
|
919
|
+
if (cachedRecord.globImports) node.globImports = cachedRecord.globImports;
|
|
1009
920
|
}
|
|
1010
921
|
}
|