@creact-labs/creact 0.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.
Files changed (103) hide show
  1. package/LICENSE +212 -0
  2. package/README.md +379 -0
  3. package/dist/cli/commands/BuildCommand.d.ts +40 -0
  4. package/dist/cli/commands/BuildCommand.js +151 -0
  5. package/dist/cli/commands/DeployCommand.d.ts +38 -0
  6. package/dist/cli/commands/DeployCommand.js +194 -0
  7. package/dist/cli/commands/DevCommand.d.ts +52 -0
  8. package/dist/cli/commands/DevCommand.js +385 -0
  9. package/dist/cli/commands/PlanCommand.d.ts +39 -0
  10. package/dist/cli/commands/PlanCommand.js +164 -0
  11. package/dist/cli/commands/index.d.ts +36 -0
  12. package/dist/cli/commands/index.js +43 -0
  13. package/dist/cli/core/ArgumentParser.d.ts +46 -0
  14. package/dist/cli/core/ArgumentParser.js +127 -0
  15. package/dist/cli/core/BaseCommand.d.ts +75 -0
  16. package/dist/cli/core/BaseCommand.js +95 -0
  17. package/dist/cli/core/CLIContext.d.ts +68 -0
  18. package/dist/cli/core/CLIContext.js +183 -0
  19. package/dist/cli/core/CommandRegistry.d.ts +64 -0
  20. package/dist/cli/core/CommandRegistry.js +89 -0
  21. package/dist/cli/core/index.d.ts +36 -0
  22. package/dist/cli/core/index.js +43 -0
  23. package/dist/cli/index.d.ts +35 -0
  24. package/dist/cli/index.js +100 -0
  25. package/dist/cli/output.d.ts +204 -0
  26. package/dist/cli/output.js +437 -0
  27. package/dist/cli/utils.d.ts +59 -0
  28. package/dist/cli/utils.js +76 -0
  29. package/dist/context/createContext.d.ts +90 -0
  30. package/dist/context/createContext.js +113 -0
  31. package/dist/context/index.d.ts +30 -0
  32. package/dist/context/index.js +35 -0
  33. package/dist/core/CReact.d.ts +409 -0
  34. package/dist/core/CReact.js +1127 -0
  35. package/dist/core/CloudDOMBuilder.d.ts +429 -0
  36. package/dist/core/CloudDOMBuilder.js +1198 -0
  37. package/dist/core/ContextDependencyTracker.d.ts +165 -0
  38. package/dist/core/ContextDependencyTracker.js +448 -0
  39. package/dist/core/ErrorRecoveryManager.d.ts +145 -0
  40. package/dist/core/ErrorRecoveryManager.js +443 -0
  41. package/dist/core/EventBus.d.ts +91 -0
  42. package/dist/core/EventBus.js +185 -0
  43. package/dist/core/ProviderOutputTracker.d.ts +211 -0
  44. package/dist/core/ProviderOutputTracker.js +476 -0
  45. package/dist/core/ReactiveUpdateQueue.d.ts +76 -0
  46. package/dist/core/ReactiveUpdateQueue.js +121 -0
  47. package/dist/core/Reconciler.d.ts +415 -0
  48. package/dist/core/Reconciler.js +1037 -0
  49. package/dist/core/RenderScheduler.d.ts +153 -0
  50. package/dist/core/RenderScheduler.js +519 -0
  51. package/dist/core/Renderer.d.ts +276 -0
  52. package/dist/core/Renderer.js +791 -0
  53. package/dist/core/Runtime.d.ts +246 -0
  54. package/dist/core/Runtime.js +640 -0
  55. package/dist/core/StateBindingManager.d.ts +121 -0
  56. package/dist/core/StateBindingManager.js +309 -0
  57. package/dist/core/StateMachine.d.ts +424 -0
  58. package/dist/core/StateMachine.js +787 -0
  59. package/dist/core/StructuralChangeDetector.d.ts +140 -0
  60. package/dist/core/StructuralChangeDetector.js +363 -0
  61. package/dist/core/Validator.d.ts +127 -0
  62. package/dist/core/Validator.js +279 -0
  63. package/dist/core/errors.d.ts +153 -0
  64. package/dist/core/errors.js +202 -0
  65. package/dist/core/index.d.ts +38 -0
  66. package/dist/core/index.js +64 -0
  67. package/dist/core/types.d.ts +263 -0
  68. package/dist/core/types.js +48 -0
  69. package/dist/hooks/context.d.ts +147 -0
  70. package/dist/hooks/context.js +334 -0
  71. package/dist/hooks/useContext.d.ts +113 -0
  72. package/dist/hooks/useContext.js +169 -0
  73. package/dist/hooks/useEffect.d.ts +105 -0
  74. package/dist/hooks/useEffect.js +540 -0
  75. package/dist/hooks/useInstance.d.ts +139 -0
  76. package/dist/hooks/useInstance.js +441 -0
  77. package/dist/hooks/useState.d.ts +120 -0
  78. package/dist/hooks/useState.js +298 -0
  79. package/dist/index.d.ts +46 -0
  80. package/dist/index.js +70 -0
  81. package/dist/jsx.d.ts +64 -0
  82. package/dist/jsx.js +76 -0
  83. package/dist/providers/DummyBackendProvider.d.ts +193 -0
  84. package/dist/providers/DummyBackendProvider.js +189 -0
  85. package/dist/providers/DummyCloudProvider.d.ts +128 -0
  86. package/dist/providers/DummyCloudProvider.js +157 -0
  87. package/dist/providers/IBackendProvider.d.ts +177 -0
  88. package/dist/providers/IBackendProvider.js +31 -0
  89. package/dist/providers/ICloudProvider.d.ts +146 -0
  90. package/dist/providers/ICloudProvider.js +31 -0
  91. package/dist/providers/index.d.ts +31 -0
  92. package/dist/providers/index.js +31 -0
  93. package/dist/test-event-callbacks.d.ts +0 -0
  94. package/dist/test-event-callbacks.js +1 -0
  95. package/dist/utils/Logger.d.ts +144 -0
  96. package/dist/utils/Logger.js +220 -0
  97. package/dist/utils/Output.d.ts +161 -0
  98. package/dist/utils/Output.js +401 -0
  99. package/dist/utils/deepEqual.d.ts +71 -0
  100. package/dist/utils/deepEqual.js +276 -0
  101. package/dist/utils/naming.d.ts +241 -0
  102. package/dist/utils/naming.js +376 -0
  103. package/package.json +87 -0
@@ -0,0 +1,140 @@
1
+ /**
2
+
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+
5
+ * you may not use this file except in compliance with the License.
6
+
7
+ * You may obtain a copy of the License at
8
+
9
+ *
10
+
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ *
14
+
15
+ * Unless required by applicable law or agreed to in writing, software
16
+
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+
21
+ * See the License for the specific language governing permissions and
22
+
23
+ * limitations under the License.
24
+
25
+ *
26
+
27
+ * Copyright 2025 Daniel Coutinho Ribeiro
28
+
29
+ */
30
+ import { FiberNode, CloudDOMNode, CReactEvents } from './types';
31
+ /**
32
+ * Structural change types for CloudDOM topology changes
33
+ */
34
+ export type StructuralChangeType = 'resource-added' | 'resource-removed' | 'resource-moved' | 'topology-changed';
35
+ /**
36
+ * Structural change event
37
+ */
38
+ export interface StructuralChange {
39
+ type: StructuralChangeType;
40
+ nodeId: string;
41
+ path: string[];
42
+ previousPath?: string[];
43
+ affectedFibers: FiberNode[];
44
+ metadata?: Record<string, any>;
45
+ }
46
+ /**
47
+ * StructuralChangeDetector - Detects CloudDOM topology changes
48
+ *
49
+ * Key Features:
50
+ * - Detect conditional useInstance calls (resources appearing/disappearing)
51
+ * - Track resource hierarchy changes
52
+ * - Trigger re-renders for affected components
53
+ * - Integrate with deployment planning for dynamic updates
54
+ */
55
+ export declare class StructuralChangeDetector {
56
+ private previousSnapshot?;
57
+ private eventHooks?;
58
+ constructor(eventHooks?: CReactEvents);
59
+ /**
60
+ * Detect structural changes between previous and current CloudDOM
61
+ * This is the main method called after each render to detect topology changes
62
+ *
63
+ * @param previousCloudDOM - Previous CloudDOM state
64
+ * @param currentCloudDOM - Current CloudDOM state
65
+ * @param currentFiber - Current fiber tree for affected component tracking
66
+ * @returns Array of structural changes detected
67
+ */
68
+ detectStructuralChanges(previousCloudDOM: CloudDOMNode[], currentCloudDOM: CloudDOMNode[], currentFiber: FiberNode): StructuralChange[];
69
+ /**
70
+ * Create a topology snapshot of CloudDOM for comparison
71
+ */
72
+ private createTopologySnapshot;
73
+ /**
74
+ * Detect newly added resources (conditional useInstance calls that became active)
75
+ */
76
+ private detectAddedResources;
77
+ /**
78
+ * Detect removed resources (conditional useInstance calls that became inactive)
79
+ */
80
+ private detectRemovedResources;
81
+ /**
82
+ * Detect moved resources (useInstance calls that changed hierarchy position)
83
+ */
84
+ private detectMovedResources;
85
+ /**
86
+ * Find fiber nodes that correspond to a specific path
87
+ */
88
+ private findFibersForPath;
89
+ /**
90
+ * Check if a fiber path matches or is related to a target path
91
+ */
92
+ private isPathMatch;
93
+ /**
94
+ * Check if two paths are equal
95
+ */
96
+ private pathsEqual;
97
+ /**
98
+ * Find all fibers affected by structural changes
99
+ */
100
+ private findAffectedFibers;
101
+ /**
102
+ * Generate a simple hash for hierarchy comparison
103
+ */
104
+ private generateHash;
105
+ /**
106
+ * Emit structural change events for observability
107
+ */
108
+ private emitStructuralChangeEvents;
109
+ /**
110
+ * Trigger re-renders for components affected by structural changes
111
+ * This integrates with the RenderScheduler to schedule re-renders
112
+ *
113
+ * @param changes - Structural changes detected
114
+ * @param renderScheduler - RenderScheduler instance to schedule re-renders
115
+ */
116
+ triggerStructuralReRenders(changes: StructuralChange[], renderScheduler: any): void;
117
+ /**
118
+ * Check if structural changes require deployment plan updates
119
+ * This helps determine if the deployment needs to be re-planned
120
+ *
121
+ * @param changes - Structural changes detected
122
+ * @returns True if deployment planning should be updated
123
+ */
124
+ requiresDeploymentPlanUpdate(changes: StructuralChange[]): boolean;
125
+ /**
126
+ * Get statistics about structural changes for monitoring
127
+ */
128
+ getChangeStats(changes: StructuralChange[]): {
129
+ totalChanges: number;
130
+ addedResources: number;
131
+ removedResources: number;
132
+ movedResources: number;
133
+ topologyChanges: number;
134
+ affectedFibers: number;
135
+ };
136
+ /**
137
+ * Clear previous snapshot (for testing/cleanup)
138
+ */
139
+ clearSnapshot(): void;
140
+ }
@@ -0,0 +1,363 @@
1
+ "use strict";
2
+ /**
3
+
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+
6
+ * you may not use this file except in compliance with the License.
7
+
8
+ * You may obtain a copy of the License at
9
+
10
+ *
11
+
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+
14
+ *
15
+
16
+ * Unless required by applicable law or agreed to in writing, software
17
+
18
+ * distributed under the License is distributed on an "AS IS" BASIS,
19
+
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+
22
+ * See the License for the specific language governing permissions and
23
+
24
+ * limitations under the License.
25
+
26
+ *
27
+
28
+ * Copyright 2025 Daniel Coutinho Ribeiro
29
+
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.StructuralChangeDetector = void 0;
33
+ const Logger_1 = require("../utils/Logger");
34
+ const logger = Logger_1.LoggerFactory.getLogger('clouddom');
35
+ /**
36
+ * StructuralChangeDetector - Detects CloudDOM topology changes
37
+ *
38
+ * Key Features:
39
+ * - Detect conditional useInstance calls (resources appearing/disappearing)
40
+ * - Track resource hierarchy changes
41
+ * - Trigger re-renders for affected components
42
+ * - Integrate with deployment planning for dynamic updates
43
+ */
44
+ class StructuralChangeDetector {
45
+ constructor(eventHooks) {
46
+ this.eventHooks = eventHooks;
47
+ }
48
+ /**
49
+ * Detect structural changes between previous and current CloudDOM
50
+ * This is the main method called after each render to detect topology changes
51
+ *
52
+ * @param previousCloudDOM - Previous CloudDOM state
53
+ * @param currentCloudDOM - Current CloudDOM state
54
+ * @param currentFiber - Current fiber tree for affected component tracking
55
+ * @returns Array of structural changes detected
56
+ */
57
+ detectStructuralChanges(previousCloudDOM, currentCloudDOM, currentFiber) {
58
+ const changes = [];
59
+ // Create snapshots for comparison
60
+ const previousSnapshot = this.createTopologySnapshot(previousCloudDOM);
61
+ const currentSnapshot = this.createTopologySnapshot(currentCloudDOM);
62
+ // Detect added resources
63
+ const addedChanges = this.detectAddedResources(previousSnapshot, currentSnapshot, currentFiber);
64
+ changes.push(...addedChanges);
65
+ // Detect removed resources
66
+ const removedChanges = this.detectRemovedResources(previousSnapshot, currentSnapshot, currentFiber);
67
+ changes.push(...removedChanges);
68
+ // Detect moved resources
69
+ const movedChanges = this.detectMovedResources(previousSnapshot, currentSnapshot, currentFiber);
70
+ changes.push(...movedChanges);
71
+ // Detect overall topology changes
72
+ if (previousSnapshot.hierarchyHash !== currentSnapshot.hierarchyHash) {
73
+ const topologyChange = {
74
+ type: 'topology-changed',
75
+ nodeId: 'root',
76
+ path: [],
77
+ affectedFibers: this.findAffectedFibers(currentFiber, changes),
78
+ metadata: {
79
+ previousHash: previousSnapshot.hierarchyHash,
80
+ currentHash: currentSnapshot.hierarchyHash,
81
+ totalChanges: changes.length,
82
+ },
83
+ };
84
+ changes.push(topologyChange);
85
+ }
86
+ // Store current snapshot for next comparison
87
+ this.previousSnapshot = currentSnapshot;
88
+ // Emit events for observability
89
+ if (changes.length > 0) {
90
+ this.emitStructuralChangeEvents(changes);
91
+ }
92
+ return changes;
93
+ }
94
+ /**
95
+ * Create a topology snapshot of CloudDOM for comparison
96
+ */
97
+ createTopologySnapshot(cloudDOM) {
98
+ const nodeIds = new Set();
99
+ const nodePaths = new Map();
100
+ const nodeTypes = new Map();
101
+ const hierarchyElements = [];
102
+ const walkNodes = (nodes, depth = 0) => {
103
+ for (const node of nodes) {
104
+ nodeIds.add(node.id);
105
+ nodePaths.set(node.id, [...node.path]);
106
+ nodeTypes.set(node.id, node.construct);
107
+ // Add to hierarchy hash elements
108
+ hierarchyElements.push(`${depth}:${node.id}:${node.construct?.name || 'unknown'}`);
109
+ if (node.children && node.children.length > 0) {
110
+ walkNodes(node.children, depth + 1);
111
+ }
112
+ }
113
+ };
114
+ walkNodes(cloudDOM);
115
+ // Create hierarchy hash for quick comparison
116
+ const hierarchyHash = this.generateHash(hierarchyElements.sort().join('|'));
117
+ return {
118
+ nodeIds,
119
+ nodePaths,
120
+ nodeTypes,
121
+ hierarchyHash,
122
+ timestamp: Date.now(),
123
+ };
124
+ }
125
+ /**
126
+ * Detect newly added resources (conditional useInstance calls that became active)
127
+ */
128
+ detectAddedResources(previous, current, fiber) {
129
+ const changes = [];
130
+ for (const nodeId of current.nodeIds) {
131
+ if (!previous.nodeIds.has(nodeId)) {
132
+ const path = current.nodePaths.get(nodeId) || [];
133
+ const affectedFibers = this.findFibersForPath(fiber, path);
134
+ changes.push({
135
+ type: 'resource-added',
136
+ nodeId,
137
+ path,
138
+ affectedFibers,
139
+ metadata: {
140
+ construct: current.nodeTypes.get(nodeId)?.name || 'unknown',
141
+ timestamp: Date.now(),
142
+ },
143
+ });
144
+ }
145
+ }
146
+ return changes;
147
+ }
148
+ /**
149
+ * Detect removed resources (conditional useInstance calls that became inactive)
150
+ */
151
+ detectRemovedResources(previous, current, fiber) {
152
+ const changes = [];
153
+ for (const nodeId of previous.nodeIds) {
154
+ if (!current.nodeIds.has(nodeId)) {
155
+ const path = previous.nodePaths.get(nodeId) || [];
156
+ const affectedFibers = this.findFibersForPath(fiber, path);
157
+ changes.push({
158
+ type: 'resource-removed',
159
+ nodeId,
160
+ path,
161
+ affectedFibers,
162
+ metadata: {
163
+ construct: previous.nodeTypes.get(nodeId)?.name || 'unknown',
164
+ timestamp: Date.now(),
165
+ },
166
+ });
167
+ }
168
+ }
169
+ return changes;
170
+ }
171
+ /**
172
+ * Detect moved resources (useInstance calls that changed hierarchy position)
173
+ */
174
+ detectMovedResources(previous, current, fiber) {
175
+ const changes = [];
176
+ for (const nodeId of current.nodeIds) {
177
+ if (previous.nodeIds.has(nodeId)) {
178
+ const previousPath = previous.nodePaths.get(nodeId);
179
+ const currentPath = current.nodePaths.get(nodeId);
180
+ if (previousPath && currentPath && !this.pathsEqual(previousPath, currentPath)) {
181
+ const affectedFibers = [
182
+ ...this.findFibersForPath(fiber, previousPath),
183
+ ...this.findFibersForPath(fiber, currentPath),
184
+ ];
185
+ changes.push({
186
+ type: 'resource-moved',
187
+ nodeId,
188
+ path: currentPath,
189
+ previousPath,
190
+ affectedFibers,
191
+ metadata: {
192
+ construct: current.nodeTypes.get(nodeId)?.name || 'unknown',
193
+ from: previousPath.join('.'),
194
+ to: currentPath.join('.'),
195
+ timestamp: Date.now(),
196
+ },
197
+ });
198
+ }
199
+ }
200
+ }
201
+ return changes;
202
+ }
203
+ /**
204
+ * Find fiber nodes that correspond to a specific path
205
+ */
206
+ findFibersForPath(fiber, targetPath) {
207
+ const matchingFibers = [];
208
+ const walkFiber = (currentFiber) => {
209
+ // Check if this fiber's path matches or is a parent of the target path
210
+ if (this.isPathMatch(currentFiber.path, targetPath)) {
211
+ matchingFibers.push(currentFiber);
212
+ }
213
+ // Recursively check children
214
+ if (currentFiber.children && currentFiber.children.length > 0) {
215
+ for (const child of currentFiber.children) {
216
+ walkFiber(child);
217
+ }
218
+ }
219
+ };
220
+ walkFiber(fiber);
221
+ return matchingFibers;
222
+ }
223
+ /**
224
+ * Check if a fiber path matches or is related to a target path
225
+ */
226
+ isPathMatch(fiberPath, targetPath) {
227
+ // Exact match
228
+ if (this.pathsEqual(fiberPath, targetPath)) {
229
+ return true;
230
+ }
231
+ // Fiber is parent of target (target path starts with fiber path)
232
+ if (targetPath.length > fiberPath.length) {
233
+ return fiberPath.every((segment, index) => segment === targetPath[index]);
234
+ }
235
+ // Fiber is child of target (fiber path starts with target path)
236
+ if (fiberPath.length > targetPath.length) {
237
+ return targetPath.every((segment, index) => segment === fiberPath[index]);
238
+ }
239
+ return false;
240
+ }
241
+ /**
242
+ * Check if two paths are equal
243
+ */
244
+ pathsEqual(path1, path2) {
245
+ if (path1.length !== path2.length) {
246
+ return false;
247
+ }
248
+ return path1.every((segment, index) => segment === path2[index]);
249
+ }
250
+ /**
251
+ * Find all fibers affected by structural changes
252
+ */
253
+ findAffectedFibers(fiber, changes) {
254
+ const affectedFibers = new Set();
255
+ for (const change of changes) {
256
+ change.affectedFibers.forEach((f) => affectedFibers.add(f));
257
+ }
258
+ return Array.from(affectedFibers);
259
+ }
260
+ /**
261
+ * Generate a simple hash for hierarchy comparison
262
+ */
263
+ generateHash(input) {
264
+ let hash = 0;
265
+ for (let i = 0; i < input.length; i++) {
266
+ const char = input.charCodeAt(i);
267
+ hash = (hash << 5) - hash + char;
268
+ hash = hash & hash; // Convert to 32-bit integer
269
+ }
270
+ return hash.toString(36);
271
+ }
272
+ /**
273
+ * Emit structural change events for observability
274
+ */
275
+ emitStructuralChangeEvents(changes) {
276
+ if (!this.eventHooks) {
277
+ return;
278
+ }
279
+ for (const change of changes) {
280
+ // Emit custom event for structural changes
281
+ if (this.eventHooks.onStructuralChange) {
282
+ this.eventHooks.onStructuralChange(change);
283
+ }
284
+ // Also emit as general events for affected fibers
285
+ for (const fiber of change.affectedFibers) {
286
+ this.eventHooks.onFiberReRenderScheduled?.(fiber, 'structural-change');
287
+ }
288
+ }
289
+ logger.debug(`Detected ${changes.length} structural changes:`, changes);
290
+ }
291
+ /**
292
+ * Trigger re-renders for components affected by structural changes
293
+ * This integrates with the RenderScheduler to schedule re-renders
294
+ *
295
+ * @param changes - Structural changes detected
296
+ * @param renderScheduler - RenderScheduler instance to schedule re-renders
297
+ */
298
+ triggerStructuralReRenders(changes, renderScheduler) {
299
+ const affectedFibers = new Set();
300
+ // Collect all affected fibers
301
+ for (const change of changes) {
302
+ change.affectedFibers.forEach((fiber) => affectedFibers.add(fiber));
303
+ }
304
+ // Schedule re-renders for affected fibers
305
+ for (const fiber of affectedFibers) {
306
+ renderScheduler.schedule(fiber, 'structural-change');
307
+ }
308
+ logger.debug(`Scheduled re-renders for ${affectedFibers.size} fibers due to structural changes`);
309
+ }
310
+ /**
311
+ * Check if structural changes require deployment plan updates
312
+ * This helps determine if the deployment needs to be re-planned
313
+ *
314
+ * @param changes - Structural changes detected
315
+ * @returns True if deployment planning should be updated
316
+ */
317
+ requiresDeploymentPlanUpdate(changes) {
318
+ // Any resource addition, removal, or move requires deployment plan update
319
+ return changes.some((change) => change.type === 'resource-added' ||
320
+ change.type === 'resource-removed' ||
321
+ change.type === 'resource-moved');
322
+ }
323
+ /**
324
+ * Get statistics about structural changes for monitoring
325
+ */
326
+ getChangeStats(changes) {
327
+ const stats = {
328
+ totalChanges: changes.length,
329
+ addedResources: 0,
330
+ removedResources: 0,
331
+ movedResources: 0,
332
+ topologyChanges: 0,
333
+ affectedFibers: 0,
334
+ };
335
+ const allAffectedFibers = new Set();
336
+ for (const change of changes) {
337
+ switch (change.type) {
338
+ case 'resource-added':
339
+ stats.addedResources++;
340
+ break;
341
+ case 'resource-removed':
342
+ stats.removedResources++;
343
+ break;
344
+ case 'resource-moved':
345
+ stats.movedResources++;
346
+ break;
347
+ case 'topology-changed':
348
+ stats.topologyChanges++;
349
+ break;
350
+ }
351
+ change.affectedFibers.forEach((fiber) => allAffectedFibers.add(fiber));
352
+ }
353
+ stats.affectedFibers = allAffectedFibers.size;
354
+ return stats;
355
+ }
356
+ /**
357
+ * Clear previous snapshot (for testing/cleanup)
358
+ */
359
+ clearSnapshot() {
360
+ this.previousSnapshot = undefined;
361
+ }
362
+ }
363
+ exports.StructuralChangeDetector = StructuralChangeDetector;
@@ -0,0 +1,127 @@
1
+ /**
2
+
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+
5
+ * you may not use this file except in compliance with the License.
6
+
7
+ * You may obtain a copy of the License at
8
+
9
+ *
10
+
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ *
14
+
15
+ * Unless required by applicable law or agreed to in writing, software
16
+
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+
19
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+
21
+ * See the License for the specific language governing permissions and
22
+
23
+ * limitations under the License.
24
+
25
+ *
26
+
27
+ * Copyright 2025 Daniel Coutinho Ribeiro
28
+
29
+ */
30
+ import { FiberNode } from './types';
31
+ /**
32
+ * Validation error with component stack trace
33
+ * REQ-NF-03.1: Enhanced error messages with file and line trace
34
+ */
35
+ export declare class ValidationError extends Error {
36
+ componentStack: string[];
37
+ filePath?: string | undefined;
38
+ lineNumber?: number | undefined;
39
+ constructor(message: string, componentStack: string[], filePath?: string | undefined, lineNumber?: number | undefined);
40
+ /**
41
+ * Get a quick summary of the error for dev tools
42
+ * REQ-NF-03.1: Enhanced error messages
43
+ */
44
+ get summary(): string;
45
+ private formatError;
46
+ }
47
+ /**
48
+ * Validator validates Fiber tree before committing to CloudDOM
49
+ *
50
+ * Validation checks:
51
+ * - Required props are present
52
+ * - Context is available when useStackContext is called
53
+ * - Resource IDs are unique
54
+ * - No circular dependencies
55
+ *
56
+ * No dependencies injected - pure validation logic
57
+ */
58
+ export declare class Validator {
59
+ /**
60
+ * Validate a Fiber tree
61
+ *
62
+ * @param fiber - Root Fiber node to validate
63
+ * @throws ValidationError if validation fails
64
+ */
65
+ validate(fiber: FiberNode | null): void;
66
+ /**
67
+ * Validate a single Fiber node and its children
68
+ *
69
+ * @param node - Fiber node to validate
70
+ * @param componentStack - Stack of component names for error reporting
71
+ * @param resourceIds - Set of resource IDs seen so far
72
+ * @param visitedPaths - Set of visited paths for circular dependency detection
73
+ */
74
+ private validateNode;
75
+ /**
76
+ * Validate that required props are present
77
+ * REQ-07.1: Required props validation
78
+ *
79
+ * @param node - Fiber node to validate
80
+ * @param componentStack - Component stack for error reporting
81
+ */
82
+ private validateRequiredProps;
83
+ /**
84
+ * Validate that context is available when useStackContext is called
85
+ * REQ-07.2: Context validation
86
+ *
87
+ * @param node - Fiber node that uses context
88
+ * @param componentStack - Component stack for error reporting
89
+ */
90
+ private validateContextAvailable;
91
+ /**
92
+ * Get required props for a component type
93
+ *
94
+ * Checks for:
95
+ * - Static requiredProps property
96
+ * - PropTypes (if available)
97
+ * - TypeScript metadata (future enhancement)
98
+ *
99
+ * @param type - Component type
100
+ * @returns Array of required prop names
101
+ */
102
+ private getRequiredProps;
103
+ /**
104
+ * Get component name for error reporting
105
+ *
106
+ * @param node - Fiber node
107
+ * @returns Component name
108
+ */
109
+ private getComponentName;
110
+ /**
111
+ * Get file path from Fiber node (if available)
112
+ *
113
+ * In a real implementation, this would use source maps or
114
+ * stack trace analysis to determine the file path.
115
+ *
116
+ * @param node - Fiber node
117
+ * @returns File path or undefined
118
+ */
119
+ private getFilePath;
120
+ /**
121
+ * Get line number from Fiber node (if available)
122
+ *
123
+ * @param node - Fiber node
124
+ * @returns Line number or undefined
125
+ */
126
+ private getLineNumber;
127
+ }