pkg-scaffold 2.3.0 → 3.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.
@@ -0,0 +1,325 @@
1
+ import ts from 'typescript';
2
+ import fs from 'fs/promises';
3
+ import crypto from 'crypto';
4
+
5
+ /**
6
+ * Enterprise AST Syntax Walker & Feature Extractor
7
+ * Utilizes the official TypeScript Compiler infrastructure to execute deeply nested
8
+ * node classification without falling back to high-risk regular expression approximations.
9
+ */
10
+ export class ASTAnalyzer {
11
+ constructor(context) {
12
+ this.context = context;
13
+ // Standard high-entropy baseline selectors for AST variable tracking
14
+ this.entropyThreshold = 4.3;
15
+ }
16
+
17
+ /**
18
+ * Parses target file data into an isolated AST representation and populates metadata structures.
19
+ * @param {string} filePath - Absolute path to on-disk component
20
+ * @param {Object} fileNode - In-memory structural graph reference node
21
+ */
22
+ async processFile(filePath, fileNode) {
23
+ try {
24
+ const sourceText = await fs.readFile(filePath, 'utf8');
25
+
26
+ // Configure target extraction structures to parse TS, JSX, and modern TC39 specifications
27
+ const sourceFile = ts.createSourceFile(
28
+ filePath,
29
+ sourceText,
30
+ ts.ScriptTarget.Latest,
31
+ true, // Ensure parent pointers are bound to allow localized subtree walking
32
+ this.getScriptKind(filePath)
33
+ );
34
+
35
+ this.extractTopLevelJSDocSuppreessions(sourceFile, fileNode);
36
+ this.walkNode(sourceFile, sourceFile, fileNode);
37
+
38
+ return true;
39
+ } catch (parseError) {
40
+ if (this.context.verbose) {
41
+ console.error(`[AST Open Error] Failed compilation validation mapping on element: ${filePath}. Reason: ${parseError.message}`);
42
+ }
43
+ return false;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Primary node walker loop executing atomic switch classifications.
49
+ * Challenge #7: Resolves conditional/destructured references to prevent cascading breakages.
50
+ */
51
+ walkNode(sourceFile, node, fileNode) {
52
+ if (!node) return;
53
+
54
+ switch (node.kind) {
55
+ // Handle Explicit Named or Absolute Star Namespace Imports
56
+ case ts.SyntaxKind.ImportDeclaration: {
57
+ if (node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
58
+ const specifier = node.moduleSpecifier.text;
59
+ fileNode.explicitImports.add(specifier);
60
+
61
+ if (node.importClause) {
62
+ // Trace named bounds: import { activeToken } from 'module';
63
+ if (node.importClause.namedBindings) {
64
+ if (ts.isNamedImports(node.importClause.namedBindings)) {
65
+ node.importClause.namedBindings.elements.forEach(element => {
66
+ const importedName = element.name.text;
67
+ const propertyName = element.propertyName ? element.propertyName.text : importedName;
68
+ fileNode.importedSymbols.add(`${specifier}:${propertyName}`);
69
+ });
70
+ } else if (ts.isNamespaceImport(node.importClause.namedBindings)) {
71
+ // Tracking total wildcard imports: import * as layout from 'module';
72
+ fileNode.importedSymbols.add(`${specifier}:*`);
73
+ }
74
+ }
75
+ // Trace default bounds: import React from 'react';
76
+ if (node.importClause.name) {
77
+ fileNode.importedSymbols.add(`${specifier}:default`);
78
+ }
79
+ }
80
+ }
81
+ break;
82
+ }
83
+
84
+ // Handle Explicit Namespace Requirements: import config = require('./config');
85
+ case ts.SyntaxKind.ImportEqualsDeclaration: {
86
+ if (node.moduleReference && ts.isExternalModuleReference(node.moduleReference)) {
87
+ if (node.moduleReference.expression && ts.isStringLiteral(node.moduleReference.expression)) {
88
+ fileNode.explicitImports.add(node.moduleReference.expression.text);
89
+ }
90
+ }
91
+ break;
92
+ }
93
+
94
+ // Challenge #1: Tracking dynamic expressions e.g., import('./chunks/' + variant)
95
+ case ts.SyntaxKind.CallExpression: {
96
+ if (node.expression && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
97
+ const firstArgument = node.arguments[0];
98
+ if (firstArgument) {
99
+ if (ts.isStringLiteral(firstArgument)) {
100
+ fileNode.explicitImports.add(firstArgument.text);
101
+ fileNode.dynamicImports.add(firstArgument.text);
102
+ } else {
103
+ // Deeply trace runtime calculated variables within the import parameters call
104
+ const stringPatterns = [];
105
+ this.traceStringExpressions(firstArgument, stringPatterns);
106
+ fileNode.calculatedDynamicImports.push({
107
+ rawText: firstArgument.getText(sourceFile),
108
+ heuristics: stringPatterns,
109
+ position: node.getStart(sourceFile)
110
+ });
111
+ }
112
+ }
113
+ }
114
+ break;
115
+ }
116
+
117
+ // Handle Variable Declaration Assignments & Challenge #11 (AST Secret Scanning)
118
+ case ts.SyntaxKind.VariableDeclaration: {
119
+ if (node.name && ts.isIdentifier(node.name)) {
120
+ this.auditAssignmentSafety(node.name.text, node.initializer, fileNode, sourceFile);
121
+ } else if (node.name && (ts.isObjectBindingPattern(node.name) || ts.isArrayBindingPattern(node.name))) {
122
+ // Flatten binding properties to map destructured usage accurately
123
+ node.name.elements.forEach(element => {
124
+ if (element.name && ts.isIdentifier(element.name)) {
125
+ this.auditAssignmentSafety(element.name.text, null, fileNode, sourceFile);
126
+ }
127
+ });
128
+ }
129
+ break;
130
+ }
131
+
132
+ // Handle Named Function Node Exports Matrix Configurations
133
+ // If the function carries both ExportKeyword AND DefaultKeyword modifiers, it is an
134
+ // `export default function` declaration. In that case the canonical export name is
135
+ // 'default', not the function's identifier, so that barrel-file tracing (which looks
136
+ // up 'default' when following `export { default as X } from './y'`) resolves correctly.
137
+ case ts.SyntaxKind.FunctionDeclaration: {
138
+ if (this.hasExportModifier(node)) {
139
+ const isDefaultExport = node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.DefaultKeyword);
140
+ if (isDefaultExport) {
141
+ // Register under 'default'; also store the real name as referencedSymbol for diagnostics
142
+ const realName = node.name && ts.isIdentifier(node.name) ? node.name.text : 'anonymous';
143
+ fileNode.internalExports.set('default', { type: 'default-function', referencedSymbol: realName, start: node.getStart(sourceFile), end: node.getEnd() });
144
+ } else if (node.name && ts.isIdentifier(node.name)) {
145
+ fileNode.internalExports.set(node.name.text, { type: 'function', start: node.getStart(sourceFile), end: node.getEnd() });
146
+ }
147
+ }
148
+ break;
149
+ }
150
+
151
+ // Handle Structural Class Definitions and Class Export Signatures
152
+ case ts.SyntaxKind.ClassDeclaration: {
153
+ if (this.hasExportModifier(node)) {
154
+ const isDefaultExport = node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.DefaultKeyword);
155
+ if (isDefaultExport) {
156
+ const realName = node.name && ts.isIdentifier(node.name) ? node.name.text : 'anonymous';
157
+ fileNode.internalExports.set('default', { type: 'default-class', referencedSymbol: realName, start: node.getStart(sourceFile), end: node.getEnd() });
158
+ } else if (node.name && ts.isIdentifier(node.name)) {
159
+ fileNode.internalExports.set(node.name.text, { type: 'class', start: node.getStart(sourceFile), end: node.getEnd() });
160
+ }
161
+ }
162
+ break;
163
+ }
164
+
165
+ // Handle Interface Definitions (Crucial for Challenge #10: Type Integrity Mapping)
166
+ case ts.SyntaxKind.InterfaceDeclaration: {
167
+ if (node.name && ts.isIdentifier(node.name)) {
168
+ const name = node.name.text;
169
+ if (this.hasExportModifier(node)) {
170
+ fileNode.internalExports.set(name, { type: 'interface', start: node.getStart(sourceFile), end: node.getEnd() });
171
+ }
172
+ }
173
+ break;
174
+ }
175
+
176
+ // Handle Type Invocations and Declarations Aliases
177
+ case ts.SyntaxKind.TypeAliasDeclaration: {
178
+ if (node.name && ts.isIdentifier(node.name)) {
179
+ const name = node.name.text;
180
+ if (this.hasExportModifier(node)) {
181
+ fileNode.internalExports.set(name, { type: 'type-alias', start: node.getStart(sourceFile), end: node.getEnd() });
182
+ }
183
+ }
184
+ break;
185
+ }
186
+
187
+ // Handle Explicit Export Assignments: export default baselineConfiguration;
188
+ case ts.SyntaxKind.ExportAssignment: {
189
+ const name = node.expression ? node.expression.getText(sourceFile) : 'default';
190
+ fileNode.internalExports.set('default', {
191
+ type: 'default-assignment',
192
+ referencedSymbol: name,
193
+ start: node.getStart(sourceFile),
194
+ end: node.getEnd()
195
+ });
196
+ break;
197
+ }
198
+
199
+ // Handle Arbitrary String References to catch deep framework routing or dynamic keys
200
+ case ts.SyntaxKind.StringLiteral: {
201
+ const text = node.text;
202
+ if (text.length > 2 && text.length < 120) {
203
+ fileNode.rawStringReferences.add(text);
204
+ }
205
+ break;
206
+ }
207
+
208
+ // Track general identifiers to register references to mapped import keys
209
+ case ts.SyntaxKind.Identifier: {
210
+ const idText = node.text;
211
+ // Avoid adding declarations to usage logs to keep verification accurate
212
+ if (!this.isNodeDeclarationName(node)) {
213
+ fileNode.instantiatedIdentifiers.add(idText);
214
+ }
215
+ break;
216
+ }
217
+ }
218
+
219
+ // Traverse recursively down the Node structural tree
220
+ ts.forEachChild(node, child => this.walkNode(sourceFile, child, fileNode));
221
+ }
222
+
223
+ /**
224
+ * Challenge #1: Evaluates math operations and template configurations inside dynamic imports.
225
+ */
226
+ traceStringExpressions(node, collector) {
227
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
228
+ this.traceStringExpressions(node.left, collector);
229
+ this.traceStringExpressions(node.right, collector);
230
+ } else if (ts.isStringLiteral(node)) {
231
+ collector.push({ type: 'literal', val: node.text });
232
+ } else if (ts.isTemplateExpression(node)) {
233
+ if (node.head) collector.push({ type: 'template-slice', val: node.head.text });
234
+ node.templateSpans.forEach(span => {
235
+ collector.push({ type: 'dynamic-var', val: span.expression.getText() });
236
+ if (span.literal) collector.push({ type: 'template-slice', val: span.literal.text });
237
+ });
238
+ } else {
239
+ collector.push({ type: 'computed-variable', val: node.getText() });
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Challenge #11: AST Secret Scanning. Evaluates entropy and patterns directly via assignments.
245
+ */
246
+ auditAssignmentSafety(variableName, initializer, fileNode, sourceFile) {
247
+ // Process variable mapping target indicators first
248
+ if (this.hasExportModifier(variableName.parent)) {
249
+ fileNode.internalExports.set(variableName.text, { type: 'variable', start: variableName.parent.getStart(sourceFile), end: variableName.parent.getEnd() });
250
+ }
251
+
252
+ if (!initializer || !ts.isStringLiteral(initializer)) return;
253
+ const value = initializer.text;
254
+
255
+ // Challenge #11 Heuristic validation parameters matching variable patterns or contents values
256
+ const isSuspiciousKeyName = /api_?key|secret|token|password|auth_?token|private_?key/i.test(variableName);
257
+ const entropy = this.calculateShannonEntropy(value);
258
+
259
+ if ((isSuspiciousKeyName && value.length > 8) || (entropy > this.entropyThreshold && value.length > 16)) {
260
+ fileNode.securityThreats.push({
261
+ identifier: variableName,
262
+ entropy: parseFloat(entropy.toFixed(2)),
263
+ position: initializer.getStart(sourceFile),
264
+ riskCode: 'HIGH_RISK_SECRET_LEAK'
265
+ });
266
+ }
267
+ }
268
+
269
+ calculateShannonEntropy(str) {
270
+ const map = {};
271
+ for (let i = 0; i < str.length; i++) {
272
+ const char = str[i];
273
+ map[char] = (map[char] || 0) + 1;
274
+ }
275
+ let entropy = 0;
276
+ for (const char in map) {
277
+ const p = map[char] / str.length;
278
+ entropy -= p * Math.log2(p);
279
+ }
280
+ return entropy;
281
+ }
282
+
283
+ /**
284
+ * Challenge #18 & #8: Parse JSDoc suppression blocks right out of code statements.
285
+ */
286
+ extractTopLevelJSDocSuppreessions(sourceFile, fileNode) {
287
+ const fullText = sourceFile.text;
288
+ // Scan all comments in the file for @scaffold-suppress
289
+ const commentRegex = /\/\*\*?[\s\S]*?\*\/|\/\/.*/g;
290
+ let match;
291
+ while ((match = commentRegex.exec(fullText)) !== null) {
292
+ const comment = match[0];
293
+ const suppressMatches = comment.match(/@scaffold-suppress\s+([a-zA-Z0-9_\-*:]+)/g);
294
+ if (suppressMatches) {
295
+ suppressMatches.forEach(m => {
296
+ const directive = m.replace('@scaffold-suppress', '').trim();
297
+ fileNode.localSuppressedRules.add(directive);
298
+ });
299
+ }
300
+ }
301
+ }
302
+
303
+ hasExportModifier(node) {
304
+ if (!node || !node.modifiers) return false;
305
+ return node.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
306
+ }
307
+
308
+ isNodeDeclarationName(node) {
309
+ const parent = node.parent;
310
+ if (!parent) return false;
311
+ if (ts.isVariableDeclaration(parent) && parent.name === node) return true;
312
+ if (ts.isFunctionDeclaration(parent) && parent.name === node) return true;
313
+ if (ts.isClassDeclaration(parent) && parent.name === node) return true;
314
+ if (ts.isInterfaceDeclaration(parent) && parent.name === node) return true;
315
+ if (ts.isImportSpecifier(parent) && parent.name === node) return true;
316
+ return false;
317
+ }
318
+
319
+ getScriptKind(filePath) {
320
+ if (filePath.endsWith('.ts')) return ts.ScriptKind.TS;
321
+ if (filePath.endsWith('.tsx')) return ts.ScriptKind.TSX;
322
+ if (filePath.endsWith('.jsx')) return ts.ScriptKind.JSX;
323
+ return ts.ScriptKind.JS;
324
+ }
325
+ }
@@ -0,0 +1,189 @@
1
+ import ts from 'typescript';
2
+ import fs from 'fs/promises';
3
+
4
+ /**
5
+ * Enterprise Wildcard Optimization & Flattening Layer for Barrel Operations
6
+ * Traces unreferenced paths through redistribution entries.
7
+ */
8
+ export class BarrelParser {
9
+ constructor(context, resolver) {
10
+ this.context = context;
11
+ this.resolver = resolver;
12
+ this.cachedSpecifications = new Map();
13
+ }
14
+
15
+ /**
16
+ * Compiles the structural export layout for a specific index or barrel target.
17
+ * @param {string} filePath - Absolute path to on-disk target element
18
+ */
19
+ async parseBarrelSpecification(filePath) {
20
+ if (this.cachedSpecifications.has(filePath)) {
21
+ return this.cachedSpecifications.get(filePath);
22
+ }
23
+
24
+ const specification = {
25
+ isBarrelInstance: false,
26
+ wildcardExports: new Set(), // export * from './module';
27
+ namespacedWildcardExports: new Map(), // export * as Utils from './module';
28
+ forwardedNamedExports: new Map(), // export { token as alias } from './module';
29
+ declaredLocalExports: new Set() // export const a = 1;
30
+ };
31
+
32
+ try {
33
+ const code = await fs.readFile(filePath, 'utf8');
34
+ const sourceFile = ts.createSourceFile(filePath, code, ts.ScriptTarget.Latest, true);
35
+
36
+ this.harvestExportSignatures(sourceFile, specification);
37
+
38
+ if (specification.wildcardExports.size > 0 ||
39
+ specification.namespacedWildcardExports.size > 0 ||
40
+ specification.forwardedNamedExports.size > 0) {
41
+ specification.isBarrelInstance = true;
42
+ }
43
+
44
+ this.cachedSpecifications.set(filePath, specification);
45
+ return specification;
46
+ } catch {
47
+ return specification; // Error state defaults to safe boundaries layout manifest
48
+ }
49
+ }
50
+
51
+ harvestExportSignatures(node, spec) {
52
+ if (!node) return;
53
+
54
+ switch (node.kind) {
55
+ case ts.SyntaxKind.ExportDeclaration: {
56
+ const targetSpecifier = node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)
57
+ ? node.moduleSpecifier.text
58
+ : null;
59
+
60
+ if (targetSpecifier) {
61
+ if (!node.exportClause) {
62
+ // Standard Wildcard Transfer: export * from './module';
63
+ spec.wildcardExports.add(targetSpecifier);
64
+ } else if (ts.isNamespaceExport(node.exportClause)) {
65
+ // Namespaced Wildcard Transfer: export * as Core from './module';
66
+ const namespaceAlias = node.exportClause.name.text;
67
+ spec.namespacedWildcardExports.set(namespaceAlias, targetSpecifier);
68
+ } else if (ts.isNamedExports(node.exportClause)) {
69
+ // Selective Re-export Forwarding: export { x, y as z } from './module';
70
+ node.exportClause.elements.forEach(element => {
71
+ const originalSymbol = element.propertyName ? element.propertyName.text : element.name.text;
72
+ const exposedAlias = element.name.text;
73
+ spec.forwardedNamedExports.set(exposedAlias, {
74
+ targetModule: targetSpecifier,
75
+ sourceSymbol: originalSymbol
76
+ });
77
+ });
78
+ }
79
+ }
80
+ break;
81
+ }
82
+
83
+ // Track items declared directly within the file boundary
84
+ case ts.SyntaxKind.FunctionDeclaration:
85
+ case ts.SyntaxKind.ClassDeclaration:
86
+ case ts.SyntaxKind.InterfaceDeclaration:
87
+ case ts.SyntaxKind.TypeAliasDeclaration:
88
+ case ts.SyntaxKind.EnumDeclaration: {
89
+ if (node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
90
+ if (node.name && ts.isIdentifier(node.name)) {
91
+ spec.declaredLocalExports.add(node.name.text);
92
+ }
93
+ }
94
+ break;
95
+ }
96
+
97
+ case ts.SyntaxKind.VariableStatement: {
98
+ if (node.modifiers && node.modifiers.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
99
+ node.declarationList.declarations.forEach(decl => {
100
+ if (ts.isIdentifier(decl.name)) {
101
+ spec.declaredLocalExports.add(decl.name.text);
102
+ }
103
+ });
104
+ }
105
+ break;
106
+ }
107
+
108
+ // Track default exports declared directly within the file boundary:
109
+ // Handles both `export default function foo()` and `export default expression`.
110
+ // The canonical symbol name stored is 'default' so that forwardedNamedExports
111
+ // entries whose sourceSymbol is 'default' can resolve correctly via Rule A.
112
+ case ts.SyntaxKind.ExportAssignment: {
113
+ // ExportAssignment covers `export default <expr>` (isExportEquals === false)
114
+ // as well as `export = <expr>` (isExportEquals === true, CommonJS style).
115
+ // We register 'default' for both to ensure the barrel tracer can settle here.
116
+ spec.declaredLocalExports.add('default');
117
+ break;
118
+ }
119
+ }
120
+
121
+ ts.forEachChild(node, child => this.harvestExportSignatures(child, spec));
122
+ }
123
+
124
+ /**
125
+ * Challenge #3 Resolution Logic. Unwraps nested redistribution links to find origin source nodes.
126
+ * @param {string} contextFilePath - Current position filename vector pointer
127
+ * @param {string} targetSymbolName - Targeted semantic variable signature name
128
+ * @param {Map} activeProjectGraph - Global active module maps directory registry
129
+ * @param {Set} [protectionStack] - Avoids cyclic validation traps inside self-referencing links
130
+ */
131
+ async determineSymbolDeclarationOrigin(contextFilePath, targetSymbolName, activeProjectGraph, protectionStack = new Set()) {
132
+ if (protectionStack.has(contextFilePath)) {
133
+ return { originFile: contextFilePath, originSymbol: targetSymbolName };
134
+ }
135
+ protectionStack.add(contextFilePath);
136
+
137
+ const spec = await this.parseBarrelSpecification(contextFilePath);
138
+ if (!spec.isBarrelInstance) {
139
+ return { originFile: contextFilePath, originSymbol: targetSymbolName };
140
+ }
141
+
142
+ // Rule A: Settle boundary immediately if local declaration matches token signature name
143
+ if (spec.declaredLocalExports.has(targetSymbolName)) {
144
+ return { originFile: contextFilePath, originSymbol: targetSymbolName };
145
+ }
146
+
147
+ // Rule B: Evaluate explicit named re-export mappings
148
+ if (spec.forwardedNamedExports.has(targetSymbolName)) {
149
+ const routingRule = spec.forwardedNamedExports.get(targetSymbolName);
150
+ const fullyResolvedPath = this.resolver.resolveModulePath(contextFilePath, routingRule.targetModule);
151
+ return this.determineSymbolDeclarationOrigin(fullyResolvedPath, routingRule.sourceSymbol, activeProjectGraph, protectionStack);
152
+ }
153
+
154
+ // Rule C: Evaluate structural namespace alias groupings
155
+ if (spec.namespacedWildcardExports.has(targetSymbolName)) {
156
+ const relativeModule = spec.namespacedWildcardExports.get(targetSymbolName);
157
+ const fullyResolvedPath = this.resolver.resolveModulePath(contextFilePath, relativeModule);
158
+ return { originFile: fullyResolvedPath, originSymbol: '*' };
159
+ }
160
+
161
+ // Rule D: Sweep through anonymous star re-exports vectors
162
+ for (const relativePath of spec.wildcardExports) {
163
+ const fullyResolvedPath = this.resolver.resolveModulePath(contextFilePath, relativePath);
164
+
165
+ // Look inside the graph metadata map configuration to verify child target availability
166
+ const targetSubSpec = await this.parseBarrelSpecification(fullyResolvedPath);
167
+
168
+ if (targetSubSpec.declaredLocalExports.has(targetSymbolName) ||
169
+ targetSubSpec.forwardedNamedExports.has(targetSymbolName)) {
170
+ return this.determineSymbolDeclarationOrigin(fullyResolvedPath, targetSymbolName, activeProjectGraph, protectionStack);
171
+ }
172
+
173
+ // Dynamic recursive trace for multi-tier nested barrel file layouts
174
+ if (targetSubSpec.isBarrelInstance) {
175
+ const continuousResolutionTrace = await this.determineSymbolDeclarationOrigin(
176
+ fullyResolvedPath,
177
+ targetSymbolName,
178
+ activeProjectGraph,
179
+ protectionStack
180
+ );
181
+ if (continuousResolutionTrace && continuousResolutionTrace.originFile !== fullyResolvedPath) {
182
+ return continuousResolutionTrace;
183
+ }
184
+ }
185
+ }
186
+
187
+ return { originFile: contextFilePath, originSymbol: targetSymbolName };
188
+ }
189
+ }
@@ -0,0 +1,155 @@
1
+ import path from 'path';
2
+ import fs from 'fs/promises';
3
+
4
+ /**
5
+ * Ecosystem Entry Point Manifest & Dynamic Framework Router Heuristic Validator
6
+ * Intercepts implicit conventions to handle cases where direct import statements are absent.
7
+ */
8
+ export class MagicDetector {
9
+ constructor(context) {
10
+ this.context = context;
11
+ this.manifestSchemaRules = this.compileEcosystemSchemaMatrices();
12
+ }
13
+
14
+ /**
15
+ * Compiles explicit layout definitions to handle various web development environments.
16
+ */
17
+ compileEcosystemSchemaMatrices() {
18
+ return {
19
+ nextjs: {
20
+ configFiles: ['next.config.js', 'next.config.mjs', 'next.config.ts'],
21
+ routePatterns: [
22
+ /\/pages\/api\//,
23
+ /\/pages\/[a-zA-Z0-9_\-\[\]]+/i,
24
+ /\/app\/([\w\-\[\]]+\/)+(page|route|layout|loading|error|not-found)\.(ts|tsx|js|jsx)$/
25
+ ],
26
+ requiredSystemContracts: ['default', 'getServerSideProps', 'getStaticProps', 'getStaticPaths', 'generateMetadata', 'middleware']
27
+ },
28
+ nuxt: {
29
+ configFiles: ['nuxt.config.js', 'nuxt.config.ts'],
30
+ routePatterns: [
31
+ /\/pages\//,
32
+ /\/server\/(api|routes|middleware)\//,
33
+ /\/components\/[a-zA-Z0-9_\-\/]+\.vue$/
34
+ ],
35
+ requiredSystemContracts: ['default']
36
+ },
37
+ remix: {
38
+ configFiles: ['remix.config.js', 'vite.config.js', 'vite.config.ts'],
39
+ routePatterns: [
40
+ /\/app\/routes\//,
41
+ /\/app\/root\.(tsx|jsx)$/
42
+ ],
43
+ requiredSystemContracts: ['default', 'loader', 'action', 'meta', 'links']
44
+ },
45
+ sveltekit: {
46
+ configFiles: ['svelte.config.js', 'vite.config.ts'],
47
+ routePatterns: [
48
+ /\+page\.(svelte|ts|js)$/,
49
+ /\+page\.server\.(ts|js)$/,
50
+ /\+layout\.(svelte|ts|js)$/,
51
+ /\+server\.(ts|js)$/
52
+ ],
53
+ requiredSystemContracts: ['load', 'actions', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH']
54
+ },
55
+ astro: {
56
+ configFiles: ['astro.config.mjs', 'astro.config.cjs', 'astro.config.ts'],
57
+ routePatterns: [
58
+ /\/src\/pages\/.*\.astro$/,
59
+ /\/src\/pages\/.*\.(ts|js)$/
60
+ ],
61
+ requiredSystemContracts: ['default', 'getStaticPaths']
62
+ }
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Audits the project context to map active micro-framework ecosystems.
68
+ * @param {string} baseContextDirectory - Root file workspace context execution vector path
69
+ */
70
+ async identifyActiveProjectEcosystems(baseContextDirectory) {
71
+ const activeFrameworkFlags = [];
72
+
73
+ for (const [frameworkKey, criteria] of Object.entries(this.manifestSchemaRules)) {
74
+ for (const configFile of criteria.configFiles) {
75
+ try {
76
+ await fs.access(path.join(baseContextDirectory, configFile));
77
+ activeFrameworkFlags.push(frameworkKey);
78
+ break; // Stop scanning once config criteria is found
79
+ } catch {
80
+ // File path criteria absent; proceed to standard verification loops
81
+ }
82
+ }
83
+ }
84
+
85
+ // Universal infrastructure overrides (testing platforms and common bundlers)
86
+ activeFrameworkFlags.push('universal-tooling-vectors');
87
+ return activeFrameworkFlags;
88
+ }
89
+
90
+ /**
91
+ * Assesses if a file path acts as an implicit route entry point.
92
+ */
93
+ isImplicitlyRequiredByEcosystem(absolutePath, activeFrameworks) {
94
+ const normalizedSystemPath = absolutePath.replace(/\\/g, '/');
95
+
96
+ for (const framework of activeFrameworks) {
97
+ const frameworkRules = this.manifestSchemaRules[framework];
98
+ if (!frameworkRules) continue;
99
+
100
+ const matchesPattern = frameworkRules.routePatterns.some(regex => regex.test(normalizedSystemPath));
101
+ if (matchesPattern) return true;
102
+ }
103
+
104
+ // Apply baseline platform rules (Test suites, lint parameters, continuous integration files)
105
+ if (this.isCoreToolingSuiteElement(normalizedSystemPath)) {
106
+ return true;
107
+ }
108
+
109
+ return false;
110
+ }
111
+
112
+ isCoreToolingSuiteElement(normalizedPath) {
113
+ // Testing and execution matrices rules configuration keys
114
+ if (/\.(test|spec|e2e|cy)\.(js|ts|tsx|jsx|stories\.tsx|stories\.ts)$/i.test(normalizedPath)) return true;
115
+
116
+ // Testing tools and structural environment frameworks configuration keys
117
+ const testEnvironments = [
118
+ 'jest.config.', 'vitest.config.', 'playwright.config.', 'cypress.config.',
119
+ 'webpack.config.', 'vite.config.', 'rollup.config.', 'tailwind.config.',
120
+ '.eslintrc.', 'prettier.config.', '.postcssrc.', 'postcss.config.',
121
+ 'bin/cli.js', 'index.js', 'WorkerTaskRunner.js'
122
+ ];
123
+
124
+ return testEnvironments.some(matchPattern => normalizedPath.includes(matchPattern));
125
+ }
126
+
127
+ /**
128
+ * Challenge #4 Framework Overrides. Protects interface boundaries from false positive report flags.
129
+ */
130
+ injectVirtualConsumerEdges(filePath, fileNode, activeFrameworks) {
131
+ if (!this.isImplicitlyRequiredByEcosystem(filePath, activeFrameworks)) return;
132
+
133
+ // Retain entry point elements within memory to keep verification safe
134
+ fileNode.isLibraryEntry = true;
135
+
136
+ // Apply dynamic exports coverage metrics based on active platform contracts
137
+ const normalizedPath = filePath.replace(/\\/g, '/');
138
+
139
+ for (const framework of activeFrameworks) {
140
+ const frameworkRules = this.manifestSchemaRules[framework];
141
+ if (!frameworkRules) continue;
142
+
143
+ // If the file path matches the active framework schema, protect its interface keywords
144
+ const appliesToFramework = frameworkRules.routePatterns.some(regex => regex.test(normalizedPath));
145
+ if (appliesToFramework) {
146
+ frameworkRules.requiredSystemContracts.forEach(contractMethodToken => {
147
+ if (fileNode.internalExports.has(contractMethodToken)) {
148
+ // Emulate active local reference linkages to protect the export
149
+ fileNode.instantiatedIdentifiers.add(contractMethodToken);
150
+ }
151
+ });
152
+ }
153
+ }
154
+ }
155
+ }