entkapp 4.5.1 β 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +4 -4
- 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 +481 -252
- package/src/ast/AdvancedAnalysis.js +6 -5
- package/src/ast/BarrelParser.js +39 -30
- package/src/ast/DeadCodeDetector.js +30 -18
- package/src/ast/MagicDetector.js +1 -1
- package/src/ast/OxcAnalyzer.js +335 -273
- package/src/index.js +279 -365
- 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 +44 -44
- package/src/resolution/ConfigLoader.js +2 -85
- package/src/resolution/DepencyResolver.js +28 -121
- package/src/resolution/EntryPointDetector.js +134 -0
- package/src/resolution/PathMapper.js +31 -107
- package/src/resolution/TSConfigLoader.js +76 -0
- package/src/resolution/WorkSpaceGraph.js +6 -472
- 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,77 @@ 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
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
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
|
-
});
|
|
566
|
+
const manifests = this.workspaceGraph?.packageManifests;
|
|
567
|
+
if (manifests) {
|
|
568
|
+
for (const [_, metadata] of manifests.entries()) {
|
|
569
|
+
if (metadata.entryPoints && metadata.entryPoints.map(p => slashifyLocal(p)).includes(cleanAbsPath)) {
|
|
570
|
+
isPackageEntryPoint = true;
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
589
573
|
}
|
|
590
574
|
}
|
|
591
|
-
|
|
575
|
+
return !isPackageEntryPoint;
|
|
576
|
+
});
|
|
592
577
|
}
|
|
593
578
|
analysisSummary.unlistedDependencies = this.context.unlistedDependencies || [];
|
|
594
579
|
|
|
595
|
-
|
|
596
|
-
const
|
|
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
|
|
580
|
+
const advancedResults = this.advancedAnalysis.runAll(this.context.projectGraph, this.workspaceGraph?.packageManifests || new Map());
|
|
581
|
+
const cycles = cyclesResult;
|
|
650
582
|
|
|
651
583
|
const structuralModificationsStaged =
|
|
652
584
|
analysisSummary.orphanedFiles.length > 0 ||
|
|
@@ -672,31 +604,25 @@ export class RefactoringEngine {
|
|
|
672
604
|
|
|
673
605
|
if (analysisSummary.unusedDependencies && analysisSummary.unusedDependencies.length > 0) {
|
|
674
606
|
console.log(ansis.bold(` π¦ Remove ${analysisSummary.unusedDependencies.length} unused dependencies:`));
|
|
675
|
-
analysisSummary.unusedDependencies.forEach(d => {
|
|
676
|
-
|
|
677
|
-
|
|
607
|
+
analysisSummary.unusedDependencies.forEach(d => console.log(ansis.dim(` β’ ${d.package} (${d.type} in ${d.manifest})`)));
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
if (analysisSummary.missingDependencies && analysisSummary.missingDependencies.length > 0) {
|
|
611
|
+
console.log(ansis.bold(` π¦ Add ${analysisSummary.missingDependencies.length} missing dependencies:`));
|
|
612
|
+
analysisSummary.missingDependencies.forEach(dep => console.log(ansis.dim(` β’ ${dep} (detected via source usage)`)));
|
|
678
613
|
}
|
|
679
614
|
|
|
680
|
-
// π¨ TARGET BUG 2: Print Alert layout warning for your unlisted package detections!
|
|
681
615
|
if (analysisSummary.unlistedDependencies && analysisSummary.unlistedDependencies.length > 0) {
|
|
682
616
|
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
|
-
});
|
|
617
|
+
analysisSummary.unlistedDependencies.forEach(u => console.log(ansis.dim(` β’ ${u.package} is imported in ${u.file} but missing from ${u.manifest}`)));
|
|
686
618
|
}
|
|
687
619
|
|
|
688
620
|
if (cycles.length > 0) {
|
|
689
621
|
console.log(ansis.bold.magenta(` π Circular Dependencies Detected (${cycles.length}):`));
|
|
690
622
|
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
|
-
}
|
|
623
|
+
const relativeCycle = cycle.map(p => path.relative(this.context.cwd, p).replace(/\\/g, '/'));
|
|
697
624
|
console.log(ansis.dim(` β’ Cycle #${idx + 1}: ${relativeCycle.join(' -> ')}`));
|
|
698
625
|
});
|
|
699
|
-
console.log(ansis.italic.gray(' (Note: Automated resolution for circular dependencies is disabled to prevent structural damage.)'));
|
|
700
626
|
}
|
|
701
627
|
|
|
702
628
|
console.log(ansis.dim('------------------------------------------------------------'));
|
|
@@ -709,7 +635,6 @@ export class RefactoringEngine {
|
|
|
709
635
|
}
|
|
710
636
|
|
|
711
637
|
if (proceed) {
|
|
712
|
-
// Execute healing lifecycle (git-state-capture -> apply -> verify -> commit/rollback)
|
|
713
638
|
await this.selfHealer.runSelfHealingLifecycle(async () => {
|
|
714
639
|
for (const relPath of analysisSummary.orphanedFiles) {
|
|
715
640
|
const absPath = path.resolve(this.context.cwd, relPath);
|
|
@@ -729,8 +654,6 @@ export class RefactoringEngine {
|
|
|
729
654
|
const nextText = await this.sourceRewriter.stripNamedExportSignature(absPath, unusedExport.symbol, meta);
|
|
730
655
|
await this.txManager.stageWrite(absPath, nextText);
|
|
731
656
|
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
657
|
}
|
|
735
658
|
}
|
|
736
659
|
});
|
|
@@ -753,7 +676,6 @@ export class RefactoringEngine {
|
|
|
753
676
|
|
|
754
677
|
async _generateVisualization(graph) {
|
|
755
678
|
console.log(ansis.bold.green('\nπ [VISUALIZER] Generating Interactive Execution Graph...'));
|
|
756
|
-
|
|
757
679
|
const nodes = [];
|
|
758
680
|
const edges = [];
|
|
759
681
|
const fileToIndex = new Map();
|
|
@@ -776,57 +698,11 @@ export class RefactoringEngine {
|
|
|
776
698
|
const fromId = fileToIndex.get(file);
|
|
777
699
|
node.outgoingEdges.forEach(edgeFile => {
|
|
778
700
|
const toId = fileToIndex.get(edgeFile);
|
|
779
|
-
if (toId) {
|
|
780
|
-
edges.push({ from: fromId, to: toId, arrows: 'to' });
|
|
781
|
-
}
|
|
701
|
+
if (toId) edges.push({ from: fromId, to: toId, arrows: 'to' });
|
|
782
702
|
});
|
|
783
703
|
}
|
|
784
704
|
|
|
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>`;
|
|
705
|
+
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
706
|
|
|
831
707
|
const http = await import('http');
|
|
832
708
|
const server = http.createServer((req, res) => {
|
|
@@ -837,13 +713,11 @@ export class RefactoringEngine {
|
|
|
837
713
|
const port = 3000;
|
|
838
714
|
server.listen(port, () => {
|
|
839
715
|
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
716
|
});
|
|
842
717
|
|
|
843
718
|
return new Promise((resolve) => {
|
|
844
719
|
process.on('SIGINT', () => {
|
|
845
720
|
server.close();
|
|
846
|
-
console.log(ansis.bold.red('\nπ Web Viewer stopped.'));
|
|
847
721
|
resolve();
|
|
848
722
|
});
|
|
849
723
|
});
|
|
@@ -855,7 +729,6 @@ export class RefactoringEngine {
|
|
|
855
729
|
const res = path.resolve(dir, entry.name);
|
|
856
730
|
if (entry.isDirectory()) {
|
|
857
731
|
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
732
|
await this.discoverSourceFiles(res, fileList);
|
|
860
733
|
} else {
|
|
861
734
|
const ext = path.extname(entry.name);
|
|
@@ -867,75 +740,146 @@ export class RefactoringEngine {
|
|
|
867
740
|
}
|
|
868
741
|
|
|
869
742
|
async linkDependencyGraph() {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
743
|
+
const slashify = (p) => {
|
|
744
|
+
let abs = path.resolve(this.context.cwd, p).replace(/\\/g, '/');
|
|
745
|
+
if (/^[a-z]:\//i.test(abs)) {
|
|
746
|
+
abs = abs.charAt(0).toUpperCase() + abs.slice(1);
|
|
873
747
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
748
|
+
return abs;
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// =========================================================================
|
|
752
|
+
// π PHASE 1: SAUBERE KANTEN-VERKNΓPFUNG (Zuerst das Netz spinnen!)
|
|
753
|
+
// =========================================================================
|
|
754
|
+
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
755
|
+
const cleanSrcPath = slashify(filePath);
|
|
756
|
+
|
|
757
|
+
// Pass A: Link all explicit and dynamic imports safely
|
|
758
|
+
const allDirectImports = new Set([...node.explicitImports, ...node.dynamicImports]);
|
|
759
|
+
for (const specifier of allDirectImports) {
|
|
760
|
+
if (specifier.startsWith('__DYNAMIC_PATTERN__:')) continue;
|
|
761
|
+
if (this.context.verbose) console.log(`[Linker-DEBUG] Attempting to resolve ${specifier} from ${cleanSrcPath}`);
|
|
762
|
+
try {
|
|
763
|
+
const resolvedPath = this.resolver.resolveModulePath(cleanSrcPath, specifier);
|
|
764
|
+
if (this.context.verbose) console.log(`[Linker-DEBUG] Resolved to: ${resolvedPath}`);
|
|
765
|
+
if (resolvedPath && this.context.projectGraph.has(resolvedPath)) {
|
|
766
|
+
const cleanTargetPath = slashify(resolvedPath);
|
|
767
|
+
this.context.projectGraph.get(cleanTargetPath).incomingEdges.add(cleanSrcPath);
|
|
768
|
+
node.outgoingEdges.add(cleanTargetPath);
|
|
880
769
|
}
|
|
881
|
-
|
|
882
|
-
|
|
770
|
+
} catch (e) {}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Pass B: Link named-symbol imports through barrel/re-export chains safely
|
|
774
|
+
for (const specToken of node.importedSymbols) {
|
|
775
|
+
try {
|
|
776
|
+
const delimiterIndex = specToken.lastIndexOf(':');
|
|
777
|
+
if (delimiterIndex === -1) continue;
|
|
778
|
+
const specifier = specToken.slice(0, delimiterIndex);
|
|
779
|
+
const symbol = specToken.slice(delimiterIndex + 1);
|
|
883
780
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
if (
|
|
889
|
-
|
|
781
|
+
const resolvedPath = this.resolver.resolveModulePath(cleanSrcPath, specifier);
|
|
782
|
+
if (!resolvedPath) continue;
|
|
783
|
+
const cleanResolvedPath = slashify(resolvedPath);
|
|
784
|
+
|
|
785
|
+
if (symbol === '*') {
|
|
786
|
+
if (this.context.projectGraph.has(cleanResolvedPath)) {
|
|
787
|
+
this.context.projectGraph.get(cleanResolvedPath).incomingEdges.add(cleanSrcPath);
|
|
788
|
+
node.outgoingEdges.add(cleanResolvedPath);
|
|
789
|
+
|
|
790
|
+
const targetNode = this.context.projectGraph.get(cleanResolvedPath);
|
|
791
|
+
for (const [expName, expMeta] of targetNode.internalExports.entries()) {
|
|
792
|
+
if (expMeta.type === 're-export-all' || expMeta.type === 're-export') {
|
|
793
|
+
const nestedPath = this.resolver.resolveModulePath(cleanResolvedPath, expMeta.source || expMeta.originalName);
|
|
794
|
+
if (nestedPath && this.context.projectGraph.has(slashify(nestedPath))) {
|
|
795
|
+
this.context.projectGraph.get(slashify(nestedPath)).incomingEdges.add(cleanResolvedPath);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
} else {
|
|
801
|
+
const traceResolution = await this.barrelParser.determineSymbolDeclarationOrigin(cleanResolvedPath, symbol, this.context.projectGraph);
|
|
802
|
+
if (traceResolution && traceResolution.originFile) {
|
|
803
|
+
const cleanOriginFile = slashify(traceResolution.originFile);
|
|
804
|
+
if (this.context.projectGraph.has(cleanOriginFile)) {
|
|
805
|
+
this.context.projectGraph.get(cleanOriginFile).incomingEdges.add(cleanSrcPath);
|
|
806
|
+
node.outgoingEdges.add(cleanOriginFile);
|
|
807
|
+
if (!this.context.importUsageRegistry) this.context.importUsageRegistry = new Set();
|
|
808
|
+
this.context.importUsageRegistry.add(`${cleanOriginFile}:${traceResolution.originSymbol}`);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
890
811
|
}
|
|
891
|
-
}
|
|
812
|
+
} catch (e) {}
|
|
892
813
|
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// =========================================================================
|
|
817
|
+
// π PHASE 2: SELEKTIVE ENTRY POINT IMMUNITΓT (Erst jetzt Heuristik prΓΌfen!)
|
|
818
|
+
// =========================================================================
|
|
819
|
+
const potentialEntryPoints = new Set();
|
|
820
|
+
let hasManifestEntries = false;
|
|
893
821
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
822
|
+
try {
|
|
823
|
+
const pkgPath = path.join(this.context.cwd, 'package.json');
|
|
824
|
+
if (existsSync(pkgPath)) {
|
|
825
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
826
|
+
const packageEntries = this.workspaceGraph.calculatePackageExportsEntries(pkg, this.context.cwd);
|
|
827
|
+
if (packageEntries.length > 0) {
|
|
828
|
+
hasManifestEntries = true;
|
|
829
|
+
for (const absEntry of packageEntries) {
|
|
830
|
+
potentialEntryPoints.add(slashify(absEntry));
|
|
899
831
|
}
|
|
900
832
|
}
|
|
901
833
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
834
|
+
} catch (e) {}
|
|
835
|
+
|
|
836
|
+
if (!hasManifestEntries && this.context.entryPoints.length === 0) {
|
|
837
|
+
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'];
|
|
838
|
+
for (const indexFile of rootIndexFiles) potentialEntryPoints.add(slashify(indexFile));
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
const protectedFiles = new Set();
|
|
842
|
+
for (const [filePath] of this.context.projectGraph.entries()) {
|
|
843
|
+
const fileName = path.basename(filePath);
|
|
844
|
+
if (/\.(test|spec|e2e)\.(ts|js|tsx|jsx)$/.test(fileName) || filePath.includes('/__tests__/') || filePath.includes('/tests/') || /\.(config|rc)\.(ts|js|mjs|cjs)$/.test(fileName)) {
|
|
845
|
+
protectedFiles.add(slashify(filePath));
|
|
910
846
|
}
|
|
847
|
+
}
|
|
911
848
|
|
|
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}`);
|
|
849
|
+
// JETZT haben die Kanten verlΓ€ssliche incomingEdges-GrΓΆΓen!
|
|
850
|
+
for (const [filePath, node] of this.context.projectGraph.entries()) {
|
|
851
|
+
const absPath = slashify(filePath);
|
|
852
|
+
const isProtected = protectedFiles.has(absPath);
|
|
853
|
+
const isManifestEntry = potentialEntryPoints.has(absPath);
|
|
854
|
+
|
|
855
|
+
const hasNoIncoming = node.incomingEdges.size === 0;
|
|
856
|
+
const hasOutgoing = node.outgoingEdges.size > 0 || node.externalPackageUsage.size > 0 || node.dynamicImports.size > 0;
|
|
857
|
+
|
|
858
|
+
let isExplicitlyDeclared = isManifestEntry;
|
|
859
|
+
if (!isExplicitlyDeclared) {
|
|
860
|
+
const cleanAbsPath = absPath.replace(/\.[^/.]+$/, "");
|
|
861
|
+
for (const candidate of potentialEntryPoints) {
|
|
862
|
+
if (candidate.replace(/\.[^/.]+$/, "") === cleanAbsPath) {
|
|
863
|
+
isExplicitlyDeclared = true;
|
|
864
|
+
break;
|
|
936
865
|
}
|
|
937
866
|
}
|
|
938
867
|
}
|
|
868
|
+
|
|
869
|
+
const usesItsImports = node.instantiatedIdentifiers && node.instantiatedIdentifiers.size > 0;
|
|
870
|
+
const isLikelyBarrel = !isExplicitlyDeclared && (node.isPureBarrel || node.isBarrel || (!usesItsImports && hasOutgoing));
|
|
871
|
+
|
|
872
|
+
let finalIsEntry = false;
|
|
873
|
+
if (isProtected || isExplicitlyDeclared) {
|
|
874
|
+
finalIsEntry = true;
|
|
875
|
+
} else if (!hasManifestEntries && hasNoIncoming && hasOutgoing && !isLikelyBarrel) {
|
|
876
|
+
finalIsEntry = true;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
node.isEntry = finalIsEntry;
|
|
880
|
+
if (finalIsEntry && this.context.options.verbose) {
|
|
881
|
+
console.log(`π― [ENTRY POINT CONFIRMED] Wurzel gesichert: ${path.relative(this.context.cwd, absPath)}`);
|
|
882
|
+
}
|
|
939
883
|
}
|
|
940
884
|
}
|
|
941
885
|
|
|
@@ -943,12 +887,9 @@ export class RefactoringEngine {
|
|
|
943
887
|
try {
|
|
944
888
|
const text = await fs.readFile(packageJsonPath, 'utf8');
|
|
945
889
|
const data = JSON.parse(text);
|
|
946
|
-
const prodDeps = Object.keys(data.dependencies || {});
|
|
947
|
-
const devDeps = Object.keys(data.devDependencies || {});
|
|
948
|
-
|
|
949
890
|
this.context.manifestDependencies.set(packageJsonPath, {
|
|
950
|
-
dependencies:
|
|
951
|
-
devDependencies:
|
|
891
|
+
dependencies: Object.keys(data.dependencies || {}),
|
|
892
|
+
devDependencies: Object.keys(data.devDependencies || {}),
|
|
952
893
|
peerDependencies: Object.keys(data.peerDependencies || {}),
|
|
953
894
|
optionalDependencies: Object.keys(data.optionalDependencies || {})
|
|
954
895
|
});
|
|
@@ -961,29 +902,6 @@ export class RefactoringEngine {
|
|
|
961
902
|
console.log(`β±οΈ Analysis Duration: ${summary.executionDuration}`);
|
|
962
903
|
console.log(`π Total Files Scanned: ${summary.totalFilesProcessed}`);
|
|
963
904
|
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
905
|
console.log(ansis.dim('\n------------------------------------------------------------\n'));
|
|
988
906
|
}
|
|
989
907
|
|
|
@@ -991,20 +909,16 @@ export class RefactoringEngine {
|
|
|
991
909
|
if (cachedRecord.explicitImports) cachedRecord.explicitImports.forEach(i => node.explicitImports.add(i));
|
|
992
910
|
if (cachedRecord.dynamicImports) cachedRecord.dynamicImports.forEach(i => node.dynamicImports.add(i));
|
|
993
911
|
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
|
-
}
|
|
912
|
+
if (cachedRecord.internalExports) Object.entries(cachedRecord.internalExports).forEach(([k, v]) => node.internalExports.set(k, v));
|
|
913
|
+
if (cachedRecord.symbolSourceLocations) Object.entries(cachedRecord.symbolSourceLocations).forEach(([k, v]) => node.symbolSourceLocations.set(k, v));
|
|
1000
914
|
if (cachedRecord.externalPackageUsage) cachedRecord.externalPackageUsage.forEach(p => node.externalPackageUsage.add(p));
|
|
1001
915
|
if (cachedRecord.rawStringReferences) cachedRecord.rawStringReferences.forEach(r => node.rawStringReferences.add(r));
|
|
1002
916
|
if (cachedRecord.instantiatedIdentifiers) cachedRecord.instantiatedIdentifiers.forEach(id => node.instantiatedIdentifiers.add(id));
|
|
1003
917
|
if (cachedRecord.propertyAccessChains) cachedRecord.propertyAccessChains.forEach(c => node.propertyAccessChains.add(c));
|
|
1004
918
|
if (cachedRecord.localSuppressedRules) cachedRecord.localSuppressedRules.forEach(r => node.localSuppressedRules.add(r));
|
|
1005
|
-
if (cachedRecord.calculatedDynamicImports) node.calculatedDynamicImports = cachedRecord.calculatedDynamicImports;
|
|
1006
919
|
if (cachedRecord.isLibraryEntry !== undefined) node.isLibraryEntry = cachedRecord.isLibraryEntry;
|
|
1007
920
|
if (cachedRecord.isEntry !== undefined) node.isEntry = cachedRecord.isEntry;
|
|
1008
|
-
if (cachedRecord.
|
|
921
|
+
if (cachedRecord.calculatedDynamicImports) node.calculatedDynamicImports = cachedRecord.calculatedDynamicImports;
|
|
922
|
+
if (cachedRecord.globImports) node.globImports = cachedRecord.globImports;
|
|
1009
923
|
}
|
|
1010
924
|
}
|