@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.
- package/README.md +73 -22
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +88 -0
- package/dist/index.d.ts +19 -44
- package/dist/index.js +20 -68
- package/dist/jsx/index.d.ts +2 -0
- package/dist/jsx/index.js +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +4 -0
- package/dist/jsx/jsx-dev-runtime.js +4 -0
- package/dist/jsx/jsx-runtime.d.ts +38 -0
- package/dist/jsx/jsx-runtime.js +38 -0
- package/dist/jsx/types.d.ts +12 -0
- package/dist/jsx/types.js +4 -0
- package/dist/primitives/context.d.ts +34 -0
- package/dist/primitives/context.js +63 -0
- package/dist/primitives/index.d.ts +3 -0
- package/dist/primitives/index.js +3 -0
- package/dist/primitives/instance.d.ts +72 -0
- package/dist/primitives/instance.js +235 -0
- package/dist/primitives/store.d.ts +22 -0
- package/dist/primitives/store.js +97 -0
- package/dist/provider/backend.d.ts +110 -0
- package/dist/provider/backend.js +37 -0
- package/dist/provider/interface.d.ts +48 -0
- package/dist/provider/interface.js +39 -0
- package/dist/reactive/effect.d.ts +11 -0
- package/dist/reactive/effect.js +42 -0
- package/dist/reactive/index.d.ts +3 -0
- package/dist/reactive/index.js +3 -0
- package/dist/reactive/signal.d.ts +32 -0
- package/dist/reactive/signal.js +60 -0
- package/dist/reactive/tracking.d.ts +41 -0
- package/dist/reactive/tracking.js +161 -0
- package/dist/runtime/fiber.d.ts +21 -0
- package/dist/runtime/fiber.js +16 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/reconcile.d.ts +66 -0
- package/dist/runtime/reconcile.js +210 -0
- package/dist/runtime/render.d.ts +42 -0
- package/dist/runtime/render.js +231 -0
- package/dist/runtime/run.d.ts +119 -0
- package/dist/runtime/run.js +334 -0
- package/dist/runtime/state-machine.d.ts +95 -0
- package/dist/runtime/state-machine.js +209 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.js +4 -0
- package/package.json +11 -24
- package/dist/cli/commands/BuildCommand.d.ts +0 -40
- package/dist/cli/commands/BuildCommand.js +0 -151
- package/dist/cli/commands/DeployCommand.d.ts +0 -38
- package/dist/cli/commands/DeployCommand.js +0 -194
- package/dist/cli/commands/DevCommand.d.ts +0 -52
- package/dist/cli/commands/DevCommand.js +0 -394
- package/dist/cli/commands/PlanCommand.d.ts +0 -39
- package/dist/cli/commands/PlanCommand.js +0 -164
- package/dist/cli/commands/index.d.ts +0 -36
- package/dist/cli/commands/index.js +0 -43
- package/dist/cli/core/ArgumentParser.d.ts +0 -46
- package/dist/cli/core/ArgumentParser.js +0 -127
- package/dist/cli/core/BaseCommand.d.ts +0 -75
- package/dist/cli/core/BaseCommand.js +0 -95
- package/dist/cli/core/CLIContext.d.ts +0 -68
- package/dist/cli/core/CLIContext.js +0 -183
- package/dist/cli/core/CommandRegistry.d.ts +0 -64
- package/dist/cli/core/CommandRegistry.js +0 -89
- package/dist/cli/core/index.d.ts +0 -36
- package/dist/cli/core/index.js +0 -43
- package/dist/cli/index.d.ts +0 -35
- package/dist/cli/index.js +0 -100
- package/dist/cli/output.d.ts +0 -204
- package/dist/cli/output.js +0 -437
- package/dist/cli/utils.d.ts +0 -59
- package/dist/cli/utils.js +0 -76
- package/dist/context/createContext.d.ts +0 -90
- package/dist/context/createContext.js +0 -113
- package/dist/context/index.d.ts +0 -30
- package/dist/context/index.js +0 -35
- package/dist/core/CReact.d.ts +0 -409
- package/dist/core/CReact.js +0 -1151
- package/dist/core/CloudDOMBuilder.d.ts +0 -447
- package/dist/core/CloudDOMBuilder.js +0 -1234
- package/dist/core/ContextDependencyTracker.d.ts +0 -165
- package/dist/core/ContextDependencyTracker.js +0 -448
- package/dist/core/ErrorRecoveryManager.d.ts +0 -145
- package/dist/core/ErrorRecoveryManager.js +0 -443
- package/dist/core/EventBus.d.ts +0 -91
- package/dist/core/EventBus.js +0 -185
- package/dist/core/ProviderOutputTracker.d.ts +0 -211
- package/dist/core/ProviderOutputTracker.js +0 -476
- package/dist/core/ReactiveUpdateQueue.d.ts +0 -76
- package/dist/core/ReactiveUpdateQueue.js +0 -121
- package/dist/core/Reconciler.d.ts +0 -415
- package/dist/core/Reconciler.js +0 -1044
- package/dist/core/RenderScheduler.d.ts +0 -153
- package/dist/core/RenderScheduler.js +0 -519
- package/dist/core/Renderer.d.ts +0 -336
- package/dist/core/Renderer.js +0 -944
- package/dist/core/Runtime.d.ts +0 -246
- package/dist/core/Runtime.js +0 -640
- package/dist/core/StateBindingManager.d.ts +0 -121
- package/dist/core/StateBindingManager.js +0 -309
- package/dist/core/StateMachine.d.ts +0 -441
- package/dist/core/StateMachine.js +0 -883
- package/dist/core/StructuralChangeDetector.d.ts +0 -140
- package/dist/core/StructuralChangeDetector.js +0 -363
- package/dist/core/Validator.d.ts +0 -127
- package/dist/core/Validator.js +0 -279
- package/dist/core/errors.d.ts +0 -153
- package/dist/core/errors.js +0 -202
- package/dist/core/index.d.ts +0 -38
- package/dist/core/index.js +0 -64
- package/dist/core/types.d.ts +0 -265
- package/dist/core/types.js +0 -48
- package/dist/hooks/context.d.ts +0 -147
- package/dist/hooks/context.js +0 -334
- package/dist/hooks/useContext.d.ts +0 -113
- package/dist/hooks/useContext.js +0 -169
- package/dist/hooks/useEffect.d.ts +0 -105
- package/dist/hooks/useEffect.js +0 -540
- package/dist/hooks/useInstance.d.ts +0 -139
- package/dist/hooks/useInstance.js +0 -455
- package/dist/hooks/useState.d.ts +0 -120
- package/dist/hooks/useState.js +0 -298
- package/dist/jsx.d.ts +0 -143
- package/dist/jsx.js +0 -76
- package/dist/providers/DummyBackendProvider.d.ts +0 -193
- package/dist/providers/DummyBackendProvider.js +0 -189
- package/dist/providers/DummyCloudProvider.d.ts +0 -128
- package/dist/providers/DummyCloudProvider.js +0 -157
- package/dist/providers/IBackendProvider.d.ts +0 -177
- package/dist/providers/IBackendProvider.js +0 -31
- package/dist/providers/ICloudProvider.d.ts +0 -230
- package/dist/providers/ICloudProvider.js +0 -31
- package/dist/providers/index.d.ts +0 -31
- package/dist/providers/index.js +0 -31
- package/dist/test-event-callbacks.d.ts +0 -0
- package/dist/test-event-callbacks.js +0 -1
- package/dist/utils/Logger.d.ts +0 -144
- package/dist/utils/Logger.js +0 -220
- package/dist/utils/Output.d.ts +0 -161
- package/dist/utils/Output.js +0 -401
- package/dist/utils/deepEqual.d.ts +0 -71
- package/dist/utils/deepEqual.js +0 -276
- package/dist/utils/naming.d.ts +0 -241
- 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;
|