arcvision 0.2.14 → 0.2.15

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.
Files changed (134) hide show
  1. package/ARCVISION_DIRECTORY_STRUCTURE.md +104 -0
  2. package/CLI_STRUCTURE.md +110 -0
  3. package/CONFIGURATION.md +119 -0
  4. package/IMPLEMENTATION_SUMMARY.md +99 -0
  5. package/README.md +149 -89
  6. package/architecture.authority.ledger.json +46 -0
  7. package/arcvision-0.2.3.tgz +0 -0
  8. package/arcvision-0.2.4.tgz +0 -0
  9. package/arcvision-0.2.5.tgz +0 -0
  10. package/arcvision.context.diff.json +2181 -0
  11. package/arcvision.context.json +1021 -0
  12. package/arcvision.context.v1.json +2163 -0
  13. package/arcvision.context.v2.json +2173 -0
  14. package/arcvision_context/README.md +93 -0
  15. package/arcvision_context/architecture.authority.ledger.json +83 -0
  16. package/arcvision_context/arcvision.context.json +6884 -0
  17. package/debug-cycle-detection.js +56 -0
  18. package/dist/index.js +1626 -25
  19. package/docs/ENHANCED_ACCURACY_SAFETY_PROTOCOL.md +172 -0
  20. package/docs/accuracy-enhancement-artifacts/enhanced-validation-config.json +98 -0
  21. package/docs/acig-robustness-guide.md +164 -0
  22. package/docs/authoritative-gate-implementation.md +168 -0
  23. package/docs/cli-strengthening-summary.md +232 -0
  24. package/docs/invariant-system-summary.md +100 -0
  25. package/docs/invariant-system.md +112 -0
  26. package/generate_large_test.js +42 -0
  27. package/large_test_repo.json +1 -0
  28. package/output1.json +2163 -0
  29. package/output2.json +2163 -0
  30. package/package.json +46 -36
  31. package/scan_calcom_report.txt +0 -0
  32. package/scan_leafmint_report.txt +0 -0
  33. package/scan_output.txt +0 -0
  34. package/scan_trigger_report.txt +0 -0
  35. package/schema/arcvision_context_schema_v1.json +136 -1
  36. package/src/arcvision-guard.js +433 -0
  37. package/src/core/authority-core-detector.js +382 -0
  38. package/src/core/authority-ledger.js +300 -0
  39. package/src/core/blastRadius.js +299 -0
  40. package/src/core/call-resolver.js +196 -0
  41. package/src/core/change-evaluator.js +509 -0
  42. package/src/core/change-evaluator.js.backup +424 -0
  43. package/src/core/change-evaluator.ts +285 -0
  44. package/src/core/chunked-uploader.js +180 -0
  45. package/src/core/circular-dependency-detector.js +404 -0
  46. package/src/core/cli-error-handler.js +458 -0
  47. package/src/core/cli-validator.js +458 -0
  48. package/src/core/compression.js +64 -0
  49. package/src/core/context_builder.js +741 -0
  50. package/src/core/dependency-manager.js +134 -0
  51. package/src/core/di-detector.js +202 -0
  52. package/src/core/diff-analyzer.js +76 -0
  53. package/src/core/example-invariants.js +135 -0
  54. package/src/core/failure-mode-synthesizer.js +341 -0
  55. package/src/core/invariant-analyzer.js +294 -0
  56. package/src/core/invariant-detector.js +548 -0
  57. package/src/core/invariant-enforcer.js +171 -0
  58. package/src/core/invariant-evaluation-utils.js +172 -0
  59. package/src/core/invariant-hooks.js +152 -0
  60. package/src/core/invariant-integration-example.js +186 -0
  61. package/src/core/invariant-registry.js +298 -0
  62. package/src/core/invariant-registry.ts +100 -0
  63. package/src/core/invariant-types.js +66 -0
  64. package/src/core/invariants-index.js +88 -0
  65. package/src/core/method-tracker.js +170 -0
  66. package/src/core/override-handler.js +304 -0
  67. package/src/core/ownership-resolver.js +227 -0
  68. package/src/core/parser-enhanced.js +80 -0
  69. package/src/core/parser.js +610 -0
  70. package/src/core/path-resolver.js +240 -0
  71. package/src/core/pattern-matcher.js +246 -0
  72. package/src/core/progress-tracker.js +71 -0
  73. package/src/core/react-nextjs-detector.js +245 -0
  74. package/src/core/readme-generator.js +167 -0
  75. package/src/core/retry-handler.js +57 -0
  76. package/src/core/scanner.js +289 -0
  77. package/src/core/semantic-analyzer.js +204 -0
  78. package/src/core/structural-context-owner.js +442 -0
  79. package/src/core/symbol-indexer.js +164 -0
  80. package/src/core/tsconfig-utils.js +73 -0
  81. package/src/core/type-analyzer.js +272 -0
  82. package/src/core/watcher.js +18 -0
  83. package/src/core/workspace-scanner.js +88 -0
  84. package/src/engine/context_builder.js +280 -0
  85. package/src/engine/context_sorter.js +59 -0
  86. package/src/engine/context_validator.js +200 -0
  87. package/src/engine/id-generator.js +16 -0
  88. package/src/engine/pass1_facts.js +260 -0
  89. package/src/engine/pass2_semantics.js +333 -0
  90. package/src/engine/pass3_lifter.js +99 -0
  91. package/src/engine/pass4_signals.js +201 -0
  92. package/src/index.js +830 -0
  93. package/src/plugins/express-plugin.js +48 -0
  94. package/src/plugins/plugin-manager.js +58 -0
  95. package/src/plugins/react-plugin.js +54 -0
  96. package/temp_original.js +0 -0
  97. package/test/determinism-test.js +83 -0
  98. package/test-authoritative-context.js +53 -0
  99. package/test-real-authoritative-context.js +118 -0
  100. package/test-upload-enhancements.js +111 -0
  101. package/test_repos/allowed-clean-architecture/.arcvision/invariants.json +57 -0
  102. package/test_repos/allowed-clean-architecture/adapters/controllers/UserController.js +95 -0
  103. package/test_repos/allowed-clean-architecture/adapters/http/HttpServer.js +78 -0
  104. package/test_repos/allowed-clean-architecture/application/dtos/CreateUserRequest.js +37 -0
  105. package/test_repos/allowed-clean-architecture/application/services/UserService.js +61 -0
  106. package/test_repos/allowed-clean-architecture/arcvision_context/README.md +93 -0
  107. package/test_repos/allowed-clean-architecture/arcvision_context/arcvision.context.json +2796 -0
  108. package/test_repos/allowed-clean-architecture/domain/interfaces/UserRepository.js +25 -0
  109. package/test_repos/allowed-clean-architecture/domain/models/User.js +39 -0
  110. package/test_repos/allowed-clean-architecture/index.js +45 -0
  111. package/test_repos/allowed-clean-architecture/infrastructure/database/DatabaseConnection.js +56 -0
  112. package/test_repos/allowed-clean-architecture/infrastructure/repositories/InMemoryUserRepository.js +61 -0
  113. package/test_repos/allowed-clean-architecture/package.json +15 -0
  114. package/test_repos/blocked-legacy-monolith/.arcvision/invariants.json +78 -0
  115. package/test_repos/blocked-legacy-monolith/arcvision_context/README.md +93 -0
  116. package/test_repos/blocked-legacy-monolith/arcvision_context/arcvision.context.json +2882 -0
  117. package/test_repos/blocked-legacy-monolith/database/dbConnection.js +35 -0
  118. package/test_repos/blocked-legacy-monolith/index.js +38 -0
  119. package/test_repos/blocked-legacy-monolith/modules/emailService.js +31 -0
  120. package/test_repos/blocked-legacy-monolith/modules/paymentProcessor.js +37 -0
  121. package/test_repos/blocked-legacy-monolith/package.json +15 -0
  122. package/test_repos/blocked-legacy-monolith/shared/utils.js +19 -0
  123. package/test_repos/blocked-legacy-monolith/utils/helpers.js +23 -0
  124. package/test_repos/risky-microservices-concerns/.arcvision/invariants.json +69 -0
  125. package/test_repos/risky-microservices-concerns/arcvision_context/README.md +93 -0
  126. package/test_repos/risky-microservices-concerns/arcvision_context/arcvision.context.json +3070 -0
  127. package/test_repos/risky-microservices-concerns/common/utils.js +77 -0
  128. package/test_repos/risky-microservices-concerns/gateways/apiGateway.js +84 -0
  129. package/test_repos/risky-microservices-concerns/index.js +20 -0
  130. package/test_repos/risky-microservices-concerns/libs/deprecatedHelper.js +36 -0
  131. package/test_repos/risky-microservices-concerns/package.json +15 -0
  132. package/test_repos/risky-microservices-concerns/services/orderService.js +42 -0
  133. package/test_repos/risky-microservices-concerns/services/userService.js +48 -0
  134. package/verify_engine.js +116 -0
@@ -0,0 +1,289 @@
1
+ const path = require('path');
2
+ const { loadTSConfig } = require('./tsconfig-utils');
3
+ const { WorkspaceScanner } = require('./workspace-scanner');
4
+
5
+ // Import new engine passes
6
+ const { executePass1 } = require('../engine/pass1_facts');
7
+ const { executePass2 } = require('../engine/pass2_semantics');
8
+ const { executePass3 } = require('../engine/pass3_lifter');
9
+ const { executePass4 } = require('../engine/pass4_signals');
10
+
11
+ // Import authority core detection
12
+ const { detectAuthorityCores, detectHiddenCoupling, detectArchitecturalArchetype } = require('./authority-core-detector');
13
+
14
+ // Import structural context ownership
15
+ const { generateAuthoritativeContext } = require('./structural-context-owner');
16
+
17
+ // Import invariant detector
18
+ const { InvariantDetector } = require('./invariant-detector');
19
+
20
+ // Import invariant analyzer
21
+ const { InvariantAnalyzer } = require('./invariant-analyzer');
22
+
23
+ // Import git utilities
24
+ const { spawnSync } = require('child_process');
25
+
26
+ const { buildContext } = require('./context_builder');
27
+ const { validateContext } = require('../engine/context_validator');
28
+ const { sortContext } = require('../engine/context_sorter');
29
+
30
+ /**
31
+ * Main Scanner Entry Point
32
+ * Orchestrates the 4-pass structural analysis
33
+ */
34
+ async function scan(directory) {
35
+ console.log(`\n🚀 ARCVISION STRUCTURAL ENGINE (4-PASS)`);
36
+ console.log(` Target: ${directory}\n`);
37
+
38
+ try {
39
+ const start = Date.now();
40
+
41
+ // --- PRE-SCAN: WORKSPACE DISCOVERY ---
42
+ // Establish global resolution context
43
+ const workspaceScanner = new WorkspaceScanner(directory);
44
+ const workspaceContext = workspaceScanner.scan();
45
+
46
+ // --- PASS 1: FACTS ---
47
+ // Extract raw syntactic facts from files
48
+ const rawNodes = await executePass1(directory);
49
+
50
+ // --- PASS 2: SEMANTICS ---
51
+ // Resolve dependencies, DI, and method calls
52
+ const semanticData = await executePass2(rawNodes, directory, workspaceContext);
53
+
54
+ // --- PASS 3: LIFTING ---
55
+ // Infer structural roles (Service, Store, etc.)
56
+ const liftedData = await executePass3(semanticData);
57
+
58
+ // --- PASS 4: SIGNALS ---
59
+ // Compute graph metrics (Blast Radius, etc.)
60
+ const structuralContext = await executePass4(liftedData);
61
+
62
+ const { nodes, edges, contextSurface, symbols, invariants, ownership, failure_modes, decision_guidance } = structuralContext;
63
+
64
+ console.log(`\n🔍 Analysis Complete (${Date.now() - start}ms)`);
65
+ console.log(` Nodes: ${nodes.length}`);
66
+ console.log(` Edges: ${edges.length}`);
67
+ console.log(` Symbols: ${symbols ? symbols.length : 0}`);
68
+
69
+ // Report parsing errors if any occurred
70
+ if (global.parserErrors && global.parserErrors.length > 0) {
71
+ const uniqueErrors = new Map();
72
+ global.parserErrors.forEach(err => {
73
+ const key = `${err.error}`;
74
+ if (!uniqueErrors.has(key)) {
75
+ uniqueErrors.set(key, { count: 0, examples: [] });
76
+ }
77
+ const errorGroup = uniqueErrors.get(key);
78
+ errorGroup.count++;
79
+ if (errorGroup.examples.length < 3) {
80
+ errorGroup.examples.push(`${err.file}:${err.line}:${err.column}`);
81
+ }
82
+ });
83
+
84
+ console.log(`\n⚠️ Parsing Issues Detected (${global.parserErrors.length} files affected):`);
85
+ uniqueErrors.forEach((info, errorType) => {
86
+ console.log(` ${info.count} files: ${errorType}`);
87
+ info.examples.forEach(example => {
88
+ console.log(` - ${example}`);
89
+ });
90
+ if (info.examples.length < info.count) {
91
+ console.log(` ... and ${info.count - info.examples.length} more`);
92
+ }
93
+ });
94
+
95
+ // Clear errors for next run
96
+ delete global.parserErrors;
97
+ }
98
+
99
+ // --- AUTHORITATIVE STRUCTURAL CONTEXT GENERATION ---
100
+
101
+ // Generate the canonical structural context that ArcVision owns
102
+ const authoritativeContext = generateAuthoritativeContext(structuralContext, {
103
+ projectName: path.basename(directory),
104
+ rootPath: path.resolve(directory),
105
+ commitHash: getGitCommitHash(directory),
106
+ timestamp: new Date().toISOString(),
107
+ version: process.env.npm_package_version || '0.1.0'
108
+ });
109
+
110
+ // Extract specific insights from authoritative context
111
+ const authorityCores = authoritativeContext.structural_context.authority_cores;
112
+ const structuralHubs = authoritativeContext.structural_context.structural_hubs;
113
+ const couplingPatterns = authoritativeContext.structural_context.coupling_patterns;
114
+ const architecturalBoundaries = authoritativeContext.structural_context.architectural_boundaries;
115
+ const structuralInvariants = authoritativeContext.structural_context.structural_invariants;
116
+
117
+ // Legacy format for backward compatibility
118
+ const hiddenCoupling = couplingPatterns;
119
+ const archetype = authoritativeContext.system_identity.architectural_archetype || {
120
+ type: 'general_purpose',
121
+ confidence: 'low',
122
+ description: 'General purpose application',
123
+ authorityPattern: 'distributed_authority'
124
+ };
125
+ const completenessMetrics = authoritativeContext.reliability_indicators.analysis_coverage;
126
+
127
+ // --- DETECT SYSTEM INVARIANTS ---
128
+
129
+ // Detect invariants in the scanned repository
130
+ const invariantDetector = new InvariantDetector();
131
+ const detectedInvariants = await invariantDetector.detectInvariants(
132
+ { nodes, edges },
133
+ directory
134
+ );
135
+
136
+ // Only analyze if we found invariants
137
+ let invariantAnalysis = null;
138
+ let architecturalHealth = null;
139
+
140
+ if (detectedInvariants && detectedInvariants.length > 0) {
141
+ // Analyze the detected invariants
142
+ const invariantAnalyzer = new InvariantAnalyzer();
143
+ invariantAnalysis = invariantAnalyzer.analyzeInvariants(detectedInvariants, {
144
+ directory,
145
+ projectName: path.basename(directory),
146
+ nodeCount: nodes.length,
147
+ edgeCount: edges.length
148
+ });
149
+
150
+ // Assess architectural health based on invariants
151
+ architecturalHealth = invariantAnalyzer.assessArchitecturalHealth(detectedInvariants, {
152
+ directory,
153
+ projectName: path.basename(directory)
154
+ });
155
+ } else {
156
+ // Even if no invariants are detected, create a baseline analysis
157
+ const invariantAnalyzer = new InvariantAnalyzer();
158
+ invariantAnalysis = invariantAnalyzer.analyzeInvariants([], {
159
+ directory,
160
+ projectName: path.basename(directory),
161
+ nodeCount: nodes.length,
162
+ edgeCount: edges.length
163
+ });
164
+
165
+ architecturalHealth = invariantAnalyzer.assessArchitecturalHealth([], {
166
+ directory,
167
+ projectName: path.basename(directory)
168
+ });
169
+ }
170
+
171
+ // --- FINAL BUILD & VALIDATION ---
172
+
173
+ // Build the final context object conforming to the schema
174
+ const contextOptions = {
175
+ directory: directory,
176
+ projectName: path.basename(directory),
177
+ contextSurface: contextSurface,
178
+ arcvisionVersion: process.env.npm_package_version || '0.1.0', // Pass version from package.json
179
+ authorityCores,
180
+ hiddenCoupling,
181
+ archetype,
182
+ completenessMetrics,
183
+ // New authoritative context fields
184
+ structuralHubs,
185
+ architecturalBoundaries,
186
+ structuralInvariants,
187
+ authoritativeContext,
188
+ // Include detected invariants
189
+ detectedInvariants,
190
+ // Include invariant analysis results
191
+ invariantAnalysis,
192
+ // Include architectural health assessment
193
+ architecturalHealth,
194
+ // Pass additional metadata
195
+ commitHash: getGitCommitHash(directory),
196
+ rootPath: path.resolve(directory)
197
+ };
198
+
199
+ // Prepare context options without archetype initially
200
+ const { archetype: originalArchetype, ...otherContextOptions } = contextOptions;
201
+
202
+ const finalContextOptions = {
203
+ directory: directory,
204
+ projectName: path.basename(directory),
205
+ language: 'javascript',
206
+ // Include symbols in options
207
+ symbols: symbols,
208
+ ...otherContextOptions,
209
+ // Include new canonical sections from Pass 4
210
+ invariants,
211
+ ownership,
212
+ failure_modes,
213
+ decision_guidance
214
+ };
215
+
216
+ // Explicitly set archetype to ensure it's a proper object
217
+ if (originalArchetype && typeof originalArchetype === 'object' &&
218
+ originalArchetype.type && originalArchetype.confidence) {
219
+ finalContextOptions.archetype = originalArchetype;
220
+ } else {
221
+ finalContextOptions.archetype = {
222
+ type: 'general_purpose',
223
+ confidence: 'low',
224
+ description: 'General purpose application',
225
+ authorityPattern: 'distributed_authority'
226
+ };
227
+ }
228
+
229
+ // Build context and ensure archetype is properly set
230
+ let context = buildContext(nodes, edges, finalContextOptions);
231
+
232
+ // Make sure archetype is set properly in the system section
233
+ if (!context.system.archetype || context.system.archetype === null) {
234
+ context.system.archetype = finalContextOptions.archetype || {
235
+ type: 'general_purpose',
236
+ confidence: 'low',
237
+ description: 'General purpose application',
238
+ authorityPattern: 'distributed_authority'
239
+ };
240
+ }
241
+
242
+ console.log(' Validating structural context...');
243
+
244
+ // Validate against JSON schema
245
+ let validation = validateContext(context);
246
+
247
+ if (!validation.valid) {
248
+ console.warn(' ⚠️ Validation Issues Found:');
249
+ validation.errors.forEach(e => console.warn(' -', e));
250
+ console.warn(' ⚠️ Proceeding despite validation issues to see results');
251
+ // Continue processing instead of throwing error
252
+ // throw new Error("Context validation failed");
253
+ }
254
+
255
+ // Deterministic sort for consistent hashing/snapshots
256
+ const sortedContext = sortContext(context);
257
+
258
+ console.log(' ✅ Context Verified & Ready');
259
+
260
+ return sortedContext;
261
+
262
+ } catch (err) {
263
+ console.error('❌ Scanner Failed:', err);
264
+ throw err;
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Get git commit hash for the repository
270
+ * @param {string} directory - Repository directory
271
+ * @returns {string} Commit hash or 'unknown'
272
+ */
273
+ function getGitCommitHash(directory) {
274
+ try {
275
+ const result = spawnSync('git', ['rev-parse', 'HEAD'], {
276
+ cwd: directory,
277
+ stdio: ['pipe', 'pipe', 'pipe']
278
+ });
279
+
280
+ if (result.status === 0) {
281
+ return result.stdout.toString().trim();
282
+ }
283
+ return 'unknown';
284
+ } catch (error) {
285
+ return 'unknown';
286
+ }
287
+ }
288
+
289
+ module.exports = { scan, getGitCommitHash };
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Semantic Analyzer
3
+ *
4
+ * Builds cross-file symbol resolution and tracks actual usage of imported symbols.
5
+ * This enables detection of which files actually USE imported functions/classes,
6
+ * not just which files import them.
7
+ */
8
+
9
+ /**
10
+ * Build a global symbol table from all file exports
11
+ * @param {Array} nodes - All scanned file nodes with metadata
12
+ * @returns {Map} Symbol table mapping symbol names to their source files
13
+ */
14
+ function buildSymbolTable(nodes) {
15
+ const symbolTable = new Map();
16
+
17
+ nodes.forEach(node => {
18
+ const filePath = node.id;
19
+ const metadata = node.metadata;
20
+
21
+ if (!metadata) return;
22
+
23
+ // Register all exports from this file
24
+ if (metadata.exports && Array.isArray(metadata.exports)) {
25
+ metadata.exports.forEach(exp => {
26
+ const symbolName = exp.name;
27
+ if (!symbolTable.has(symbolName)) {
28
+ symbolTable.set(symbolName, []);
29
+ }
30
+ symbolTable.get(symbolName).push({
31
+ file: filePath,
32
+ type: exp.type,
33
+ loc: exp.loc
34
+ });
35
+ });
36
+ }
37
+
38
+ // Register all functions
39
+ if (metadata.functions && Array.isArray(metadata.functions)) {
40
+ metadata.functions.forEach(func => {
41
+ const symbolName = func.name;
42
+ if (!symbolTable.has(symbolName)) {
43
+ symbolTable.set(symbolName, []);
44
+ }
45
+ symbolTable.get(symbolName).push({
46
+ file: filePath,
47
+ type: 'function',
48
+ loc: func.loc
49
+ });
50
+ });
51
+ }
52
+
53
+ // Register all classes
54
+ if (metadata.classes && Array.isArray(metadata.classes)) {
55
+ metadata.classes.forEach(cls => {
56
+ const symbolName = cls.name;
57
+ if (!symbolTable.has(symbolName)) {
58
+ symbolTable.set(symbolName, []);
59
+ }
60
+ symbolTable.get(symbolName).push({
61
+ file: filePath,
62
+ type: 'class',
63
+ loc: cls.loc
64
+ });
65
+ });
66
+ }
67
+ });
68
+
69
+ return symbolTable;
70
+ }
71
+
72
+ /**
73
+ * Resolve symbol usage to their definitions
74
+ * @param {Object} node - File node with metadata
75
+ * @param {Map} symbolTable - Global symbol table
76
+ * @returns {Array} Array of resolved symbol usages
77
+ */
78
+ function resolveSymbolUsage(node, symbolTable) {
79
+ const resolvedUsages = [];
80
+ const metadata = node.metadata;
81
+
82
+ if (!metadata) return resolvedUsages;
83
+
84
+ // Track which symbols this file imports
85
+ const importedSymbols = new Map();
86
+ if (metadata.imports && Array.isArray(metadata.imports)) {
87
+ metadata.imports.forEach(imp => {
88
+ if (imp.specifiers && Array.isArray(imp.specifiers)) {
89
+ imp.specifiers.forEach(spec => {
90
+ const localName = spec.local || spec.imported || spec;
91
+ const importedName = spec.imported || spec.local || spec;
92
+ importedSymbols.set(localName, {
93
+ source: imp.source,
94
+ originalName: importedName
95
+ });
96
+ });
97
+ }
98
+ });
99
+ }
100
+
101
+ // Check function calls against imported symbols
102
+ if (metadata.functionCalls && Array.isArray(metadata.functionCalls)) {
103
+ metadata.functionCalls.forEach(call => {
104
+ const callName = call.name;
105
+ if (importedSymbols.has(callName)) {
106
+ const importInfo = importedSymbols.get(callName);
107
+ resolvedUsages.push({
108
+ type: 'function_call',
109
+ symbol: callName,
110
+ source: importInfo.source,
111
+ loc: call.loc
112
+ });
113
+ }
114
+ });
115
+ }
116
+
117
+ // Check constructor calls against imported symbols
118
+ if (metadata.constructorCalls && Array.isArray(metadata.constructorCalls)) {
119
+ metadata.constructorCalls.forEach(call => {
120
+ const className = call.className;
121
+ if (importedSymbols.has(className)) {
122
+ const importInfo = importedSymbols.get(className);
123
+ resolvedUsages.push({
124
+ type: 'constructor_call',
125
+ symbol: className,
126
+ source: importInfo.source,
127
+ loc: call.loc
128
+ });
129
+ }
130
+ });
131
+ }
132
+
133
+ // Check component usage (React/JSX)
134
+ if (metadata.componentUsage && Array.isArray(metadata.componentUsage)) {
135
+ metadata.componentUsage.forEach(comp => {
136
+ const componentName = comp.component;
137
+ if (importedSymbols.has(componentName)) {
138
+ const importInfo = importedSymbols.get(componentName);
139
+ resolvedUsages.push({
140
+ type: 'component_usage',
141
+ symbol: componentName,
142
+ source: importInfo.source,
143
+ loc: comp.loc
144
+ });
145
+ }
146
+ });
147
+ }
148
+
149
+ return resolvedUsages;
150
+ }
151
+
152
+ /**
153
+ * Track cross-file references and build usage edges
154
+ * @param {Array} nodes - All scanned file nodes
155
+ * @param {Map} symbolTable - Global symbol table
156
+ * @returns {Array} Array of usage edges
157
+ */
158
+ function trackCrossFileReferences(nodes, symbolTable) {
159
+ const usageEdges = [];
160
+
161
+ nodes.forEach(node => {
162
+ const filePath = node.id;
163
+ const resolvedUsages = resolveSymbolUsage(node, symbolTable);
164
+
165
+ resolvedUsages.forEach(usage => {
166
+ // Create an edge from this file to the source of the symbol
167
+ usageEdges.push({
168
+ source: filePath,
169
+ target: usage.source,
170
+ type: usage.type,
171
+ symbol: usage.symbol,
172
+ loc: usage.loc
173
+ });
174
+ });
175
+ });
176
+
177
+ return usageEdges;
178
+ }
179
+
180
+ /**
181
+ * Analyze semantic relationships in the codebase
182
+ * @param {Array} nodes - All scanned file nodes
183
+ * @returns {Object} Semantic analysis results
184
+ */
185
+ function analyzeSemantics(nodes) {
186
+ const symbolTable = buildSymbolTable(nodes);
187
+ const usageEdges = trackCrossFileReferences(nodes, symbolTable);
188
+
189
+ return {
190
+ symbolTable,
191
+ usageEdges,
192
+ stats: {
193
+ totalSymbols: symbolTable.size,
194
+ totalUsages: usageEdges.length
195
+ }
196
+ };
197
+ }
198
+
199
+ module.exports = {
200
+ buildSymbolTable,
201
+ resolveSymbolUsage,
202
+ trackCrossFileReferences,
203
+ analyzeSemantics
204
+ };