@creact-labs/creact 0.1.8 → 0.2.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 (146) hide show
  1. package/README.md +73 -22
  2. package/dist/cli.d.ts +11 -0
  3. package/dist/cli.js +88 -0
  4. package/dist/index.d.ts +19 -44
  5. package/dist/index.js +20 -68
  6. package/dist/jsx/index.d.ts +2 -0
  7. package/dist/jsx/index.js +1 -0
  8. package/dist/jsx/jsx-dev-runtime.d.ts +4 -0
  9. package/dist/jsx/jsx-dev-runtime.js +4 -0
  10. package/dist/jsx/jsx-runtime.d.ts +38 -0
  11. package/dist/jsx/jsx-runtime.js +38 -0
  12. package/dist/jsx/types.d.ts +12 -0
  13. package/dist/jsx/types.js +4 -0
  14. package/dist/primitives/context.d.ts +34 -0
  15. package/dist/primitives/context.js +63 -0
  16. package/dist/primitives/index.d.ts +3 -0
  17. package/dist/primitives/index.js +3 -0
  18. package/dist/primitives/instance.d.ts +72 -0
  19. package/dist/primitives/instance.js +235 -0
  20. package/dist/primitives/store.d.ts +22 -0
  21. package/dist/primitives/store.js +97 -0
  22. package/dist/provider/backend.d.ts +110 -0
  23. package/dist/provider/backend.js +37 -0
  24. package/dist/provider/interface.d.ts +48 -0
  25. package/dist/provider/interface.js +39 -0
  26. package/dist/reactive/effect.d.ts +11 -0
  27. package/dist/reactive/effect.js +42 -0
  28. package/dist/reactive/index.d.ts +3 -0
  29. package/dist/reactive/index.js +3 -0
  30. package/dist/reactive/signal.d.ts +32 -0
  31. package/dist/reactive/signal.js +60 -0
  32. package/dist/reactive/tracking.d.ts +41 -0
  33. package/dist/reactive/tracking.js +161 -0
  34. package/dist/runtime/fiber.d.ts +21 -0
  35. package/dist/runtime/fiber.js +16 -0
  36. package/dist/runtime/index.d.ts +4 -0
  37. package/dist/runtime/index.js +4 -0
  38. package/dist/runtime/reconcile.d.ts +66 -0
  39. package/dist/runtime/reconcile.js +210 -0
  40. package/dist/runtime/render.d.ts +42 -0
  41. package/dist/runtime/render.js +231 -0
  42. package/dist/runtime/run.d.ts +119 -0
  43. package/dist/runtime/run.js +334 -0
  44. package/dist/runtime/state-machine.d.ts +95 -0
  45. package/dist/runtime/state-machine.js +209 -0
  46. package/dist/types.d.ts +13 -0
  47. package/dist/types.js +4 -0
  48. package/package.json +11 -24
  49. package/dist/cli/commands/BuildCommand.d.ts +0 -40
  50. package/dist/cli/commands/BuildCommand.js +0 -151
  51. package/dist/cli/commands/DeployCommand.d.ts +0 -38
  52. package/dist/cli/commands/DeployCommand.js +0 -194
  53. package/dist/cli/commands/DevCommand.d.ts +0 -52
  54. package/dist/cli/commands/DevCommand.js +0 -394
  55. package/dist/cli/commands/PlanCommand.d.ts +0 -39
  56. package/dist/cli/commands/PlanCommand.js +0 -164
  57. package/dist/cli/commands/index.d.ts +0 -36
  58. package/dist/cli/commands/index.js +0 -43
  59. package/dist/cli/core/ArgumentParser.d.ts +0 -46
  60. package/dist/cli/core/ArgumentParser.js +0 -127
  61. package/dist/cli/core/BaseCommand.d.ts +0 -75
  62. package/dist/cli/core/BaseCommand.js +0 -95
  63. package/dist/cli/core/CLIContext.d.ts +0 -68
  64. package/dist/cli/core/CLIContext.js +0 -183
  65. package/dist/cli/core/CommandRegistry.d.ts +0 -64
  66. package/dist/cli/core/CommandRegistry.js +0 -89
  67. package/dist/cli/core/index.d.ts +0 -36
  68. package/dist/cli/core/index.js +0 -43
  69. package/dist/cli/index.d.ts +0 -35
  70. package/dist/cli/index.js +0 -100
  71. package/dist/cli/output.d.ts +0 -204
  72. package/dist/cli/output.js +0 -437
  73. package/dist/cli/utils.d.ts +0 -59
  74. package/dist/cli/utils.js +0 -76
  75. package/dist/context/createContext.d.ts +0 -90
  76. package/dist/context/createContext.js +0 -113
  77. package/dist/context/index.d.ts +0 -30
  78. package/dist/context/index.js +0 -35
  79. package/dist/core/CReact.d.ts +0 -409
  80. package/dist/core/CReact.js +0 -1151
  81. package/dist/core/CloudDOMBuilder.d.ts +0 -447
  82. package/dist/core/CloudDOMBuilder.js +0 -1234
  83. package/dist/core/ContextDependencyTracker.d.ts +0 -165
  84. package/dist/core/ContextDependencyTracker.js +0 -448
  85. package/dist/core/ErrorRecoveryManager.d.ts +0 -145
  86. package/dist/core/ErrorRecoveryManager.js +0 -443
  87. package/dist/core/EventBus.d.ts +0 -91
  88. package/dist/core/EventBus.js +0 -185
  89. package/dist/core/ProviderOutputTracker.d.ts +0 -211
  90. package/dist/core/ProviderOutputTracker.js +0 -476
  91. package/dist/core/ReactiveUpdateQueue.d.ts +0 -76
  92. package/dist/core/ReactiveUpdateQueue.js +0 -121
  93. package/dist/core/Reconciler.d.ts +0 -415
  94. package/dist/core/Reconciler.js +0 -1044
  95. package/dist/core/RenderScheduler.d.ts +0 -153
  96. package/dist/core/RenderScheduler.js +0 -519
  97. package/dist/core/Renderer.d.ts +0 -336
  98. package/dist/core/Renderer.js +0 -944
  99. package/dist/core/Runtime.d.ts +0 -246
  100. package/dist/core/Runtime.js +0 -640
  101. package/dist/core/StateBindingManager.d.ts +0 -121
  102. package/dist/core/StateBindingManager.js +0 -309
  103. package/dist/core/StateMachine.d.ts +0 -441
  104. package/dist/core/StateMachine.js +0 -883
  105. package/dist/core/StructuralChangeDetector.d.ts +0 -140
  106. package/dist/core/StructuralChangeDetector.js +0 -363
  107. package/dist/core/Validator.d.ts +0 -127
  108. package/dist/core/Validator.js +0 -279
  109. package/dist/core/errors.d.ts +0 -153
  110. package/dist/core/errors.js +0 -202
  111. package/dist/core/index.d.ts +0 -38
  112. package/dist/core/index.js +0 -64
  113. package/dist/core/types.d.ts +0 -265
  114. package/dist/core/types.js +0 -48
  115. package/dist/hooks/context.d.ts +0 -147
  116. package/dist/hooks/context.js +0 -334
  117. package/dist/hooks/useContext.d.ts +0 -113
  118. package/dist/hooks/useContext.js +0 -169
  119. package/dist/hooks/useEffect.d.ts +0 -105
  120. package/dist/hooks/useEffect.js +0 -540
  121. package/dist/hooks/useInstance.d.ts +0 -139
  122. package/dist/hooks/useInstance.js +0 -455
  123. package/dist/hooks/useState.d.ts +0 -120
  124. package/dist/hooks/useState.js +0 -298
  125. package/dist/jsx.d.ts +0 -143
  126. package/dist/jsx.js +0 -76
  127. package/dist/providers/DummyBackendProvider.d.ts +0 -193
  128. package/dist/providers/DummyBackendProvider.js +0 -189
  129. package/dist/providers/DummyCloudProvider.d.ts +0 -128
  130. package/dist/providers/DummyCloudProvider.js +0 -157
  131. package/dist/providers/IBackendProvider.d.ts +0 -177
  132. package/dist/providers/IBackendProvider.js +0 -31
  133. package/dist/providers/ICloudProvider.d.ts +0 -230
  134. package/dist/providers/ICloudProvider.js +0 -31
  135. package/dist/providers/index.d.ts +0 -31
  136. package/dist/providers/index.js +0 -31
  137. package/dist/test-event-callbacks.d.ts +0 -0
  138. package/dist/test-event-callbacks.js +0 -1
  139. package/dist/utils/Logger.d.ts +0 -144
  140. package/dist/utils/Logger.js +0 -220
  141. package/dist/utils/Output.d.ts +0 -161
  142. package/dist/utils/Output.js +0 -401
  143. package/dist/utils/deepEqual.d.ts +0 -71
  144. package/dist/utils/deepEqual.js +0 -276
  145. package/dist/utils/naming.d.ts +0 -241
  146. package/dist/utils/naming.js +0 -376
@@ -1,165 +0,0 @@
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, CReactEvents } from './types';
31
- /**
32
- * ContextDependencyTracker - Manages context dependencies and change detection
33
- *
34
- * Key Features:
35
- * - Track which components consume which contexts
36
- * - Detect context value changes
37
- * - Trigger re-renders only for components with output-bound context values
38
- * - Integrate with StateBindingManager for selective reactivity
39
- *
40
- * Optimizations:
41
- * - Uses Map<FiberNode, number[]> instead of Set<object> for stable identity
42
- * - Smart equality checking with structural hashing
43
- * - Direct StateBindingManager integration
44
- * - Event hooks for observability
45
- */
46
- export declare class ContextDependencyTracker {
47
- private contextConsumers;
48
- private contextValues;
49
- private previousContextValues;
50
- private fiberContexts;
51
- private valueHashCache;
52
- private eventHooks?;
53
- private stateBindingManager?;
54
- constructor(eventHooks?: CReactEvents);
55
- /**
56
- * Set StateBindingManager reference for direct integration
57
- */
58
- setStateBindingManager(stateBindingManager: any): void;
59
- /**
60
- * Track that a component is consuming a context
61
- * Called by enhanced useContext hook
62
- * Uses stable Map<FiberNode, number[]> for reliable cleanup
63
- */
64
- trackContextConsumption(contextId: symbol, fiber: FiberNode, hookIndex?: number): void;
65
- /**
66
- * Update context value and detect changes with rollback support
67
- * Called when a context provider value changes
68
- * Returns fibers that need re-rendering due to the change
69
- */
70
- updateContextValue(contextId: symbol, newValue: any): FiberNode[];
71
- /**
72
- * Rollback context value to previous state
73
- * Used when provider update fails (e.g., backend error)
74
- *
75
- * @param contextId - Context to rollback
76
- * @returns True if rollback was successful, false if no previous value exists
77
- */
78
- rollbackContextValue(contextId: symbol): boolean;
79
- /**
80
- * Get previous context value (for debugging/inspection)
81
- */
82
- getPreviousContextValue(contextId: symbol): any;
83
- /**
84
- * Check if a context value is bound to provider output
85
- * Direct integration with StateBindingManager for accurate detection
86
- */
87
- private isContextValueBoundToOutput;
88
- /**
89
- * Check if a fiber has any output bindings (fallback method)
90
- * This is used when StateBindingManager is not available
91
- */
92
- private hasOutputBindings;
93
- /**
94
- * Get current context value
95
- */
96
- getContextValue(contextId: symbol): any;
97
- /**
98
- * Set initial context value (when provider is first rendered)
99
- */
100
- setInitialContextValue(contextId: symbol, value: any): void;
101
- /**
102
- * Remove context dependencies for a fiber (cleanup)
103
- * O(n) stable operation with Map-based storage
104
- */
105
- removeContextDependenciesForFiber(fiber: FiberNode): void;
106
- /**
107
- * Remove all consumers for a context (when provider is unmounted)
108
- * Safe iteration to avoid mid-loop deletion issues
109
- */
110
- removeContextConsumers(contextId: symbol): void;
111
- /**
112
- * Get all consumers for a context (for debugging)
113
- */
114
- getContextConsumers(contextId: symbol): Array<{
115
- fiber: FiberNode;
116
- hookIndices: number[];
117
- }>;
118
- /**
119
- * Get all contexts consumed by a fiber (for debugging)
120
- */
121
- getFiberContexts(fiber: FiberNode): symbol[];
122
- /**
123
- * Get statistics about context dependencies
124
- */
125
- getContextStats(): {
126
- totalContexts: number;
127
- totalConsumers: number;
128
- contextsWithConsumers: number;
129
- totalHookBindings: number;
130
- };
131
- /**
132
- * Clear all context dependencies (for testing/cleanup)
133
- */
134
- clearAllDependencies(): void;
135
- /**
136
- * Smart equality check for context values
137
- * Uses shallow equality by default with structural hashing for complex objects
138
- */
139
- private smartEqual;
140
- /**
141
- * Shallow equality check for objects
142
- */
143
- private shallowEqual;
144
- /**
145
- * Structural hash-based equality for complex objects
146
- * Uses WeakMap caching for performance
147
- */
148
- private structuralHashEqual;
149
- /**
150
- * Get structural hash of an object with caching
151
- */
152
- private getStructuralHash;
153
- /**
154
- * Generate structural hash using JSON.stringify with sorted keys
155
- */
156
- private generateStructuralHash;
157
- /**
158
- * Recursively sort object keys for consistent hashing
159
- */
160
- private sortObjectKeys;
161
- /**
162
- * Deep equality check (fallback method)
163
- */
164
- private deepEqual;
165
- }
@@ -1,448 +0,0 @@
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.ContextDependencyTracker = void 0;
33
- /**
34
- * ContextDependencyTracker - Manages context dependencies and change detection
35
- *
36
- * Key Features:
37
- * - Track which components consume which contexts
38
- * - Detect context value changes
39
- * - Trigger re-renders only for components with output-bound context values
40
- * - Integrate with StateBindingManager for selective reactivity
41
- *
42
- * Optimizations:
43
- * - Uses Map<FiberNode, number[]> instead of Set<object> for stable identity
44
- * - Smart equality checking with structural hashing
45
- * - Direct StateBindingManager integration
46
- * - Event hooks for observability
47
- */
48
- class ContextDependencyTracker {
49
- constructor(eventHooks) {
50
- // Map context ID to consuming fibers and their hook indices (stable identity)
51
- this.contextConsumers = new Map();
52
- // Map context ID to current value for change detection
53
- this.contextValues = new Map();
54
- // Map context ID to previous value for rollback capability
55
- this.previousContextValues = new Map();
56
- // Map fiber to consumed contexts for cleanup
57
- this.fiberContexts = new WeakMap();
58
- // Structural hash cache for performance
59
- this.valueHashCache = new WeakMap();
60
- this.eventHooks = eventHooks;
61
- }
62
- /**
63
- * Set StateBindingManager reference for direct integration
64
- */
65
- setStateBindingManager(stateBindingManager) {
66
- this.stateBindingManager = stateBindingManager;
67
- }
68
- /**
69
- * Track that a component is consuming a context
70
- * Called by enhanced useContext hook
71
- * Uses stable Map<FiberNode, number[]> for reliable cleanup
72
- */
73
- trackContextConsumption(contextId, fiber, hookIndex) {
74
- // Track consumer with stable identity
75
- if (!this.contextConsumers.has(contextId)) {
76
- this.contextConsumers.set(contextId, new Map());
77
- }
78
- const fiberMap = this.contextConsumers.get(contextId);
79
- if (!fiberMap.has(fiber)) {
80
- fiberMap.set(fiber, []);
81
- }
82
- // Add hook index if provided and not already tracked
83
- if (hookIndex !== undefined) {
84
- const hookIndices = fiberMap.get(fiber);
85
- if (!hookIndices.includes(hookIndex)) {
86
- hookIndices.push(hookIndex);
87
- }
88
- }
89
- // Track fiber's contexts for cleanup
90
- if (!this.fiberContexts.has(fiber)) {
91
- this.fiberContexts.set(fiber, new Set());
92
- }
93
- this.fiberContexts.get(fiber).add(contextId);
94
- }
95
- /**
96
- * Update context value and detect changes with rollback support
97
- * Called when a context provider value changes
98
- * Returns fibers that need re-rendering due to the change
99
- */
100
- updateContextValue(contextId, newValue) {
101
- const previousValue = this.contextValues.get(contextId);
102
- // Check if value actually changed using smart equality
103
- if (this.smartEqual(previousValue, newValue)) {
104
- return []; // No change, no re-renders needed
105
- }
106
- // Store previous value for potential rollback
107
- if (previousValue !== undefined) {
108
- this.previousContextValues.set(contextId, previousValue);
109
- }
110
- // Emit context update event for observability
111
- this.eventHooks?.onContextUpdate?.(contextId, previousValue, newValue);
112
- // Update stored value
113
- this.contextValues.set(contextId, newValue);
114
- // Find consuming fibers that need re-rendering
115
- const fiberMap = this.contextConsumers.get(contextId);
116
- if (!fiberMap) {
117
- return [];
118
- }
119
- const affectedFibers = [];
120
- // Iterate over fibers with stable identity
121
- Array.from(fiberMap.entries()).forEach(([fiber, hookIndices]) => {
122
- // Check each hook index for output binding
123
- for (const hookIndex of hookIndices) {
124
- // Only trigger re-render if the context value is bound to output
125
- // This implements the requirement: "only to states binded to output"
126
- if (this.isContextValueBoundToOutput(fiber, contextId, hookIndex)) {
127
- affectedFibers.push(fiber);
128
- break; // Only add fiber once, even if multiple hooks are bound
129
- }
130
- }
131
- });
132
- return affectedFibers;
133
- }
134
- /**
135
- * Rollback context value to previous state
136
- * Used when provider update fails (e.g., backend error)
137
- *
138
- * @param contextId - Context to rollback
139
- * @returns True if rollback was successful, false if no previous value exists
140
- */
141
- rollbackContextValue(contextId) {
142
- const previousValue = this.previousContextValues.get(contextId);
143
- if (previousValue === undefined) {
144
- return false; // No previous value to rollback to
145
- }
146
- // Restore previous value
147
- this.contextValues.set(contextId, previousValue);
148
- // Clear the rollback value
149
- this.previousContextValues.delete(contextId);
150
- // Emit rollback event for observability
151
- this.eventHooks?.onContextUpdate?.(contextId, this.contextValues.get(contextId), previousValue);
152
- return true;
153
- }
154
- /**
155
- * Get previous context value (for debugging/inspection)
156
- */
157
- getPreviousContextValue(contextId) {
158
- return this.previousContextValues.get(contextId);
159
- }
160
- /**
161
- * Check if a context value is bound to provider output
162
- * Direct integration with StateBindingManager for accurate detection
163
- */
164
- isContextValueBoundToOutput(fiber, contextId, hookIndex) {
165
- // Direct StateBindingManager integration
166
- if (this.stateBindingManager) {
167
- return this.stateBindingManager.isFiberBoundToOutput?.(fiber, contextId, hookIndex) ?? false;
168
- }
169
- // Fallback: check if fiber has any output bindings
170
- return this.hasOutputBindings(fiber);
171
- }
172
- /**
173
- * Check if a fiber has any output bindings (fallback method)
174
- * This is used when StateBindingManager is not available
175
- */
176
- hasOutputBindings(fiber) {
177
- // Check if fiber has cloudDOMNodes (indicates it uses useInstance)
178
- if (fiber.cloudDOMNodes && fiber.cloudDOMNodes.length > 0) {
179
- return true;
180
- }
181
- // Check if fiber has state that could be bound to outputs
182
- if (fiber.hooks && fiber.hooks.length > 0) {
183
- return true;
184
- }
185
- return false;
186
- }
187
- /**
188
- * Get current context value
189
- */
190
- getContextValue(contextId) {
191
- return this.contextValues.get(contextId);
192
- }
193
- /**
194
- * Set initial context value (when provider is first rendered)
195
- */
196
- setInitialContextValue(contextId, value) {
197
- if (!this.contextValues.has(contextId)) {
198
- this.contextValues.set(contextId, value);
199
- }
200
- }
201
- /**
202
- * Remove context dependencies for a fiber (cleanup)
203
- * O(n) stable operation with Map-based storage
204
- */
205
- removeContextDependenciesForFiber(fiber) {
206
- const contexts = this.fiberContexts.get(fiber);
207
- if (!contexts) {
208
- return;
209
- }
210
- // Remove fiber from all context consumer lists (stable cleanup)
211
- Array.from(contexts).forEach((contextId) => {
212
- const fiberMap = this.contextConsumers.get(contextId);
213
- if (fiberMap) {
214
- // Direct fiber removal with Map
215
- fiberMap.delete(fiber);
216
- // Clean up empty consumer maps
217
- if (fiberMap.size === 0) {
218
- this.contextConsumers.delete(contextId);
219
- }
220
- }
221
- });
222
- // Remove fiber's context tracking
223
- this.fiberContexts.delete(fiber);
224
- }
225
- /**
226
- * Remove all consumers for a context (when provider is unmounted)
227
- * Safe iteration to avoid mid-loop deletion issues
228
- */
229
- removeContextConsumers(contextId) {
230
- const fiberMap = this.contextConsumers.get(contextId);
231
- if (fiberMap) {
232
- // Convert to array first to avoid mid-loop deletion issues
233
- const fibers = Array.from(fiberMap.keys());
234
- // Remove context from each fiber's tracking
235
- fibers.forEach((fiber) => {
236
- const fiberContexts = this.fiberContexts.get(fiber);
237
- if (fiberContexts) {
238
- fiberContexts.delete(contextId);
239
- if (fiberContexts.size === 0) {
240
- this.fiberContexts.delete(fiber);
241
- }
242
- }
243
- });
244
- }
245
- // Remove context tracking
246
- this.contextConsumers.delete(contextId);
247
- this.contextValues.delete(contextId);
248
- }
249
- /**
250
- * Get all consumers for a context (for debugging)
251
- */
252
- getContextConsumers(contextId) {
253
- const fiberMap = this.contextConsumers.get(contextId);
254
- if (!fiberMap) {
255
- return [];
256
- }
257
- return Array.from(fiberMap.entries()).map(([fiber, hookIndices]) => ({
258
- fiber,
259
- hookIndices: [...hookIndices],
260
- }));
261
- }
262
- /**
263
- * Get all contexts consumed by a fiber (for debugging)
264
- */
265
- getFiberContexts(fiber) {
266
- const contexts = this.fiberContexts.get(fiber);
267
- return contexts ? Array.from(contexts) : [];
268
- }
269
- /**
270
- * Get statistics about context dependencies
271
- */
272
- getContextStats() {
273
- let totalConsumers = 0;
274
- let contextsWithConsumers = 0;
275
- let totalHookBindings = 0;
276
- Array.from(this.contextConsumers.values()).forEach((fiberMap) => {
277
- totalConsumers += fiberMap.size;
278
- if (fiberMap.size > 0) {
279
- contextsWithConsumers++;
280
- }
281
- // Count total hook bindings
282
- Array.from(fiberMap.values()).forEach((hookIndices) => {
283
- totalHookBindings += hookIndices.length;
284
- });
285
- });
286
- return {
287
- totalContexts: this.contextValues.size,
288
- totalConsumers,
289
- contextsWithConsumers,
290
- totalHookBindings,
291
- };
292
- }
293
- /**
294
- * Clear all context dependencies (for testing/cleanup)
295
- */
296
- clearAllDependencies() {
297
- this.contextConsumers.clear();
298
- this.contextValues.clear();
299
- // Note: WeakMap doesn't have clear(), but clearing the other maps
300
- // will effectively orphan the WeakMap entries for GC
301
- }
302
- /**
303
- * Smart equality check for context values
304
- * Uses shallow equality by default with structural hashing for complex objects
305
- */
306
- smartEqual(a, b) {
307
- // Fast path: reference equality
308
- if (a === b)
309
- return true;
310
- // Handle null/undefined
311
- if (a == null || b == null)
312
- return a === b;
313
- // Different types are not equal
314
- if (typeof a !== typeof b)
315
- return false;
316
- // Primitives
317
- if (typeof a !== 'object')
318
- return a === b;
319
- // Try shallow equality first (common case for infrastructure contexts)
320
- if (this.shallowEqual(a, b))
321
- return true;
322
- // Fall back to structural hash comparison for complex objects
323
- return this.structuralHashEqual(a, b);
324
- }
325
- /**
326
- * Shallow equality check for objects
327
- */
328
- shallowEqual(a, b) {
329
- if (Array.isArray(a) !== Array.isArray(b))
330
- return false;
331
- if (Array.isArray(a)) {
332
- if (a.length !== b.length)
333
- return false;
334
- for (let i = 0; i < a.length; i++) {
335
- if (a[i] !== b[i])
336
- return false;
337
- }
338
- return true;
339
- }
340
- const keysA = Object.keys(a);
341
- const keysB = Object.keys(b);
342
- if (keysA.length !== keysB.length)
343
- return false;
344
- for (const key of keysA) {
345
- if (!keysB.includes(key) || a[key] !== b[key])
346
- return false;
347
- }
348
- return true;
349
- }
350
- /**
351
- * Structural hash-based equality for complex objects
352
- * Uses WeakMap caching for performance
353
- */
354
- structuralHashEqual(a, b) {
355
- try {
356
- const hashA = this.getStructuralHash(a);
357
- const hashB = this.getStructuralHash(b);
358
- return hashA === hashB;
359
- }
360
- catch {
361
- // Fallback to deep equality if hashing fails
362
- return this.deepEqual(a, b);
363
- }
364
- }
365
- /**
366
- * Get structural hash of an object with caching
367
- */
368
- getStructuralHash(obj) {
369
- if (typeof obj !== 'object' || obj === null) {
370
- return String(obj);
371
- }
372
- // Check cache first
373
- if (this.valueHashCache.has(obj)) {
374
- return this.valueHashCache.get(obj);
375
- }
376
- // Generate hash
377
- const hash = this.generateStructuralHash(obj);
378
- this.valueHashCache.set(obj, hash);
379
- return hash;
380
- }
381
- /**
382
- * Generate structural hash using JSON.stringify with sorted keys
383
- */
384
- generateStructuralHash(obj) {
385
- try {
386
- // Sort keys for consistent hashing
387
- const sortedObj = this.sortObjectKeys(obj);
388
- return JSON.stringify(sortedObj);
389
- }
390
- catch {
391
- // Fallback for non-serializable objects
392
- return `[object ${obj.constructor?.name || 'Object'}]`;
393
- }
394
- }
395
- /**
396
- * Recursively sort object keys for consistent hashing
397
- */
398
- sortObjectKeys(obj) {
399
- if (obj === null || typeof obj !== 'object') {
400
- return obj;
401
- }
402
- if (Array.isArray(obj)) {
403
- return obj.map((item) => this.sortObjectKeys(item));
404
- }
405
- const sorted = {};
406
- const keys = Object.keys(obj).sort();
407
- for (const key of keys) {
408
- sorted[key] = this.sortObjectKeys(obj[key]);
409
- }
410
- return sorted;
411
- }
412
- /**
413
- * Deep equality check (fallback method)
414
- */
415
- deepEqual(a, b) {
416
- if (a === b)
417
- return true;
418
- if (a == null || b == null)
419
- return a === b;
420
- if (typeof a !== typeof b)
421
- return false;
422
- if (typeof a !== 'object')
423
- return a === b;
424
- if (Array.isArray(a) !== Array.isArray(b))
425
- return false;
426
- if (Array.isArray(a)) {
427
- if (a.length !== b.length)
428
- return false;
429
- for (let i = 0; i < a.length; i++) {
430
- if (!this.deepEqual(a[i], b[i]))
431
- return false;
432
- }
433
- return true;
434
- }
435
- const keysA = Object.keys(a);
436
- const keysB = Object.keys(b);
437
- if (keysA.length !== keysB.length)
438
- return false;
439
- for (const key of keysA) {
440
- if (!keysB.includes(key))
441
- return false;
442
- if (!this.deepEqual(a[key], b[key]))
443
- return false;
444
- }
445
- return true;
446
- }
447
- }
448
- exports.ContextDependencyTracker = ContextDependencyTracker;