@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
package/dist/utils/naming.js
DELETED
|
@@ -1,376 +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.generateResourceId = generateResourceId;
|
|
33
|
-
exports.toKebabCase = toKebabCase;
|
|
34
|
-
exports.getNodeName = getNodeName;
|
|
35
|
-
exports.validateIdUniqueness = validateIdUniqueness;
|
|
36
|
-
exports.normalizePathSegment = normalizePathSegment;
|
|
37
|
-
exports.normalizePath = normalizePath;
|
|
38
|
-
exports.formatPath = formatPath;
|
|
39
|
-
exports.parseResourceId = parseResourceId;
|
|
40
|
-
exports.generateBindingKey = generateBindingKey;
|
|
41
|
-
exports.parseBindingKey = parseBindingKey;
|
|
42
|
-
exports.generateStateOutputKey = generateStateOutputKey;
|
|
43
|
-
exports.isStateOutputKey = isStateOutputKey;
|
|
44
|
-
exports.isProviderOutputKey = isProviderOutputKey;
|
|
45
|
-
exports.parseStateOutputKey = parseStateOutputKey;
|
|
46
|
-
// REQ-01: Naming system for resource ID generation
|
|
47
|
-
// This module provides utilities for generating resource IDs from Fiber paths
|
|
48
|
-
/**
|
|
49
|
-
* Generate a resource ID from a Fiber path
|
|
50
|
-
*
|
|
51
|
-
* Converts a hierarchical path array into a dot-separated resource ID.
|
|
52
|
-
* Each path segment is converted to kebab-case for consistency.
|
|
53
|
-
*
|
|
54
|
-
* Examples:
|
|
55
|
-
* - ['registry', 'service'] → 'registry.service'
|
|
56
|
-
* - ['Registry', 'ServiceAPI'] → 'registry.service-api'
|
|
57
|
-
* - ['my-app', 'database'] → 'my-app.database'
|
|
58
|
-
*
|
|
59
|
-
* REQ-01: Resource ID generation from component hierarchy
|
|
60
|
-
*
|
|
61
|
-
* @param path - Hierarchical path segments
|
|
62
|
-
* @returns Dot-separated resource ID
|
|
63
|
-
*/
|
|
64
|
-
function generateResourceId(path) {
|
|
65
|
-
if (!path || path.length === 0) {
|
|
66
|
-
throw new Error('Cannot generate resource ID from empty path');
|
|
67
|
-
}
|
|
68
|
-
// Convert each segment to kebab-case and join with dots
|
|
69
|
-
return path.map((segment) => toKebabCase(segment)).join('.');
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Convert a string to kebab-case
|
|
73
|
-
*
|
|
74
|
-
* Handles various input formats:
|
|
75
|
-
* - PascalCase: 'RegistryStack' → 'registry-stack'
|
|
76
|
-
* - camelCase: 'serviceAPI' → 'service-api'
|
|
77
|
-
* - snake_case: 'my_service' → 'my-service'
|
|
78
|
-
* - spaces: 'My Service' → 'my-service'
|
|
79
|
-
* - Already kebab: 'my-service' → 'my-service'
|
|
80
|
-
*
|
|
81
|
-
* REQ-01: Kebab-case formatting for multi-word names
|
|
82
|
-
*
|
|
83
|
-
* @param str - String to convert
|
|
84
|
-
* @returns Kebab-case string
|
|
85
|
-
*/
|
|
86
|
-
function toKebabCase(str) {
|
|
87
|
-
if (!str || typeof str !== 'string') {
|
|
88
|
-
return '';
|
|
89
|
-
}
|
|
90
|
-
return (str
|
|
91
|
-
// Insert hyphen before uppercase letters (PascalCase/camelCase)
|
|
92
|
-
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
93
|
-
// Insert hyphen between letters and numbers
|
|
94
|
-
.replace(/([a-zA-Z])(\d)/g, '$1-$2')
|
|
95
|
-
.replace(/(\d)([a-zA-Z])/g, '$1-$2')
|
|
96
|
-
// Convert to lowercase
|
|
97
|
-
.toLowerCase()
|
|
98
|
-
// Replace spaces, underscores, slashes, and backslashes with hyphens
|
|
99
|
-
.replace(/[\s_\/\\]+/g, '-')
|
|
100
|
-
// Remove multiple consecutive hyphens
|
|
101
|
-
.replace(/-+/g, '-')
|
|
102
|
-
// Remove leading/trailing hyphens
|
|
103
|
-
.replace(/^-|-$/g, ''));
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Generate a node name from component type and key
|
|
107
|
-
*
|
|
108
|
-
* Priority order:
|
|
109
|
-
* 1. Custom key prop (highest priority, for identity)
|
|
110
|
-
* 2. Component function name or displayName
|
|
111
|
-
* 3. Type string (for intrinsic elements)
|
|
112
|
-
* 4. 'anonymous' (fallback)
|
|
113
|
-
* 5. Append siblingIndex if > 0 (for automatic position-based keys)
|
|
114
|
-
*
|
|
115
|
-
* Note: The props parameter is kept for future extensibility and for passing
|
|
116
|
-
* to child components during execution, but props are NOT used for node identity.
|
|
117
|
-
* Only the 'key' prop determines identity.
|
|
118
|
-
*
|
|
119
|
-
* REQ-01: Support custom keys via key prop
|
|
120
|
-
* REQ-6.9: Only key prop is used for identity, not name prop
|
|
121
|
-
* REQ-6.2: Automatic position-based keys for static JSX siblings
|
|
122
|
-
*
|
|
123
|
-
* @param type - Component type (function, class, or string)
|
|
124
|
-
* @param props - Component props (for component execution, not identity)
|
|
125
|
-
* @param key - Optional key prop (for identity)
|
|
126
|
-
* @param siblingIndex - Optional sibling index for automatic key generation
|
|
127
|
-
* @returns Node name in kebab-case
|
|
128
|
-
*/
|
|
129
|
-
function getNodeName(type, props = {}, key, siblingIndex) {
|
|
130
|
-
// Priority 1: Use key if provided (identity)
|
|
131
|
-
if (key !== undefined) {
|
|
132
|
-
return toKebabCase(String(key));
|
|
133
|
-
}
|
|
134
|
-
// Priority 2: Use component function name or displayName
|
|
135
|
-
let baseName;
|
|
136
|
-
if (typeof type === 'function') {
|
|
137
|
-
baseName = type.displayName || type.name || 'anonymous';
|
|
138
|
-
}
|
|
139
|
-
else if (typeof type === 'string') {
|
|
140
|
-
// Priority 3: Use string type as-is (intrinsic elements)
|
|
141
|
-
baseName = type;
|
|
142
|
-
}
|
|
143
|
-
else if (typeof type === 'symbol') {
|
|
144
|
-
// Priority 4: Handle Fragment (Symbol type)
|
|
145
|
-
baseName = 'fragment';
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
// Fallback
|
|
149
|
-
baseName = 'anonymous';
|
|
150
|
-
}
|
|
151
|
-
// Convert to kebab-case
|
|
152
|
-
const kebabName = toKebabCase(baseName);
|
|
153
|
-
// Priority 5: Append siblingIndex if provided and > 0
|
|
154
|
-
// Keep first sibling without suffix (index 0)
|
|
155
|
-
if (siblingIndex !== undefined && siblingIndex > 0) {
|
|
156
|
-
return `${kebabName}-${siblingIndex}`;
|
|
157
|
-
}
|
|
158
|
-
return kebabName;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Validate resource ID uniqueness within a scope
|
|
162
|
-
*
|
|
163
|
-
* Checks if a resource ID already exists in the given set.
|
|
164
|
-
* Throws an error if duplicate is found.
|
|
165
|
-
*
|
|
166
|
-
* REQ-01: Ensure IDs are unique within scope
|
|
167
|
-
*
|
|
168
|
-
* @param id - Resource ID to validate
|
|
169
|
-
* @param existingIds - Set of existing IDs in scope
|
|
170
|
-
* @param componentStack - Component stack for error reporting
|
|
171
|
-
* @throws Error if ID is not unique
|
|
172
|
-
*/
|
|
173
|
-
function validateIdUniqueness(id, existingIds, componentStack = []) {
|
|
174
|
-
if (existingIds.has(id)) {
|
|
175
|
-
const stackTrace = componentStack.length > 0 ? `\n in ${componentStack.join('\n in ')}` : '';
|
|
176
|
-
throw new Error(`Duplicate resource ID: '${id}'. ` +
|
|
177
|
-
`Each resource must have a unique ID within its scope. ` +
|
|
178
|
-
`Use the 'key' prop to differentiate components with the same name.${stackTrace}`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Normalize a path segment for consistent resource addressing
|
|
183
|
-
*
|
|
184
|
-
* Applies full kebab-case conversion for consistency:
|
|
185
|
-
* - Converts PascalCase/camelCase to kebab-case
|
|
186
|
-
* - Handles underscores, spaces, numbers
|
|
187
|
-
* - Trims whitespace
|
|
188
|
-
* - Removes leading/trailing hyphens
|
|
189
|
-
*
|
|
190
|
-
* @param segment - Path segment to normalize
|
|
191
|
-
* @returns Normalized segment in kebab-case
|
|
192
|
-
*/
|
|
193
|
-
function normalizePathSegment(segment) {
|
|
194
|
-
if (!segment || typeof segment !== 'string') {
|
|
195
|
-
return '';
|
|
196
|
-
}
|
|
197
|
-
// Use toKebabCase for full normalization
|
|
198
|
-
return toKebabCase(segment);
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Normalize an entire path for consistent resource addressing
|
|
202
|
-
*
|
|
203
|
-
* Converts all path segments to kebab-case for consistency.
|
|
204
|
-
*
|
|
205
|
-
* @param path - Path segments to normalize
|
|
206
|
-
* @returns Normalized path segments in kebab-case
|
|
207
|
-
*/
|
|
208
|
-
function normalizePath(path) {
|
|
209
|
-
return path.map(normalizePathSegment).filter((segment) => segment.length > 0);
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Format a path for human-readable display
|
|
213
|
-
*
|
|
214
|
-
* Examples:
|
|
215
|
-
* - ['registry', 'service'] → 'registry > service'
|
|
216
|
-
* - ['app', 'database', 'table'] → 'app > database > table'
|
|
217
|
-
*
|
|
218
|
-
* @param path - Path segments
|
|
219
|
-
* @returns Formatted path string
|
|
220
|
-
*/
|
|
221
|
-
function formatPath(path) {
|
|
222
|
-
return path.join(' > ');
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Parse a resource ID back into path segments
|
|
226
|
-
*
|
|
227
|
-
* Inverse of generateResourceId.
|
|
228
|
-
*
|
|
229
|
-
* Examples:
|
|
230
|
-
* - 'registry.service' → ['registry', 'service']
|
|
231
|
-
* - 'app.database.table' → ['app', 'database', 'table']
|
|
232
|
-
*
|
|
233
|
-
* @param id - Resource ID
|
|
234
|
-
* @returns Path segments
|
|
235
|
-
*/
|
|
236
|
-
function parseResourceId(id) {
|
|
237
|
-
if (!id || typeof id !== 'string') {
|
|
238
|
-
return [];
|
|
239
|
-
}
|
|
240
|
-
return id.split('.').filter((segment) => segment.length > 0);
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Generate a binding key for state-output binding tracking
|
|
244
|
-
*
|
|
245
|
-
* Creates a consistent key format for tracking bindings between
|
|
246
|
-
* component state and provider outputs.
|
|
247
|
-
*
|
|
248
|
-
* Examples:
|
|
249
|
-
* - ('registry.service', 'url') → 'registry.service.url'
|
|
250
|
-
* - ('app.database', 'connectionString') → 'app.database.connection-string'
|
|
251
|
-
*
|
|
252
|
-
* @param nodeId - CloudDOM node ID
|
|
253
|
-
* @param outputKey - Output key name
|
|
254
|
-
* @returns Binding key
|
|
255
|
-
*/
|
|
256
|
-
function generateBindingKey(nodeId, outputKey) {
|
|
257
|
-
if (!nodeId || !outputKey) {
|
|
258
|
-
throw new Error('Cannot generate binding key from empty nodeId or outputKey');
|
|
259
|
-
}
|
|
260
|
-
// Normalize the output key to kebab-case for consistency
|
|
261
|
-
const normalizedOutputKey = toKebabCase(outputKey);
|
|
262
|
-
return `${nodeId}.${normalizedOutputKey}`;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Parse a binding key back into nodeId and outputKey
|
|
266
|
-
*
|
|
267
|
-
* Inverse of generateBindingKey.
|
|
268
|
-
*
|
|
269
|
-
* Examples:
|
|
270
|
-
* - 'registry.service.url' → { nodeId: 'registry.service', outputKey: 'url' }
|
|
271
|
-
* - 'app.database.connection-string' → { nodeId: 'app.database', outputKey: 'connection-string' }
|
|
272
|
-
*
|
|
273
|
-
* @param bindingKey - Binding key
|
|
274
|
-
* @returns Object with nodeId and outputKey
|
|
275
|
-
*/
|
|
276
|
-
function parseBindingKey(bindingKey) {
|
|
277
|
-
if (!bindingKey || typeof bindingKey !== 'string') {
|
|
278
|
-
throw new Error('Cannot parse empty binding key');
|
|
279
|
-
}
|
|
280
|
-
const parts = bindingKey.split('.');
|
|
281
|
-
if (parts.length < 2) {
|
|
282
|
-
throw new Error(`Invalid binding key format: ${bindingKey}`);
|
|
283
|
-
}
|
|
284
|
-
// The last part is the output key, everything else is the node ID
|
|
285
|
-
const outputKey = parts.pop();
|
|
286
|
-
const nodeId = parts.join('.');
|
|
287
|
-
return { nodeId, outputKey };
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Generate a state output key for useState hooks
|
|
291
|
-
*
|
|
292
|
-
* REQ-3.1: Generate state keys without prefix (stored in separate state field)
|
|
293
|
-
*
|
|
294
|
-
* Creates a key for useState outputs. Uses 1-based indexing for consistency.
|
|
295
|
-
* State values are stored in the separate `state` field on CloudDOMNode,
|
|
296
|
-
* not in the `outputs` field, so no prefix is needed.
|
|
297
|
-
*
|
|
298
|
-
* Examples:
|
|
299
|
-
* - generateStateOutputKey(0) → 'state1'
|
|
300
|
-
* - generateStateOutputKey(1) → 'state2'
|
|
301
|
-
* - generateStateOutputKey(2) → 'state3'
|
|
302
|
-
*
|
|
303
|
-
* @param hookIndex - Zero-based hook index
|
|
304
|
-
* @returns State output key without prefix
|
|
305
|
-
*/
|
|
306
|
-
function generateStateOutputKey(hookIndex) {
|
|
307
|
-
if (hookIndex < 0 || !Number.isInteger(hookIndex)) {
|
|
308
|
-
throw new Error(`Invalid hook index: ${hookIndex}. Must be a non-negative integer.`);
|
|
309
|
-
}
|
|
310
|
-
// Use 1-based indexing for user-friendly naming (state1, state2, state3)
|
|
311
|
-
return `state${hookIndex + 1}`;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Check if an output key is a state output (matches state key format)
|
|
315
|
-
*
|
|
316
|
-
* REQ-3.1: Identify useState outputs by their key format (state1, state2, etc.)
|
|
317
|
-
*
|
|
318
|
-
* Examples:
|
|
319
|
-
* - isStateOutputKey('state1') → true
|
|
320
|
-
* - isStateOutputKey('state2') → true
|
|
321
|
-
* - isStateOutputKey('connectionUrl') → false
|
|
322
|
-
* - isStateOutputKey('vaultUrl') → false
|
|
323
|
-
*
|
|
324
|
-
* @param outputKey - Output key to check
|
|
325
|
-
* @returns True if the key is a state output
|
|
326
|
-
*/
|
|
327
|
-
function isStateOutputKey(outputKey) {
|
|
328
|
-
return typeof outputKey === 'string' && /^state\d+$/.test(outputKey);
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Check if an output key is a provider output (not a state key)
|
|
332
|
-
*
|
|
333
|
-
* REQ-3.1: Identify provider outputs by absence of state key format
|
|
334
|
-
*
|
|
335
|
-
* Examples:
|
|
336
|
-
* - isProviderOutputKey('connectionUrl') → true
|
|
337
|
-
* - isProviderOutputKey('vaultUrl') → true
|
|
338
|
-
* - isProviderOutputKey('state1') → false
|
|
339
|
-
* - isProviderOutputKey('state2') → false
|
|
340
|
-
*
|
|
341
|
-
* @param outputKey - Output key to check
|
|
342
|
-
* @returns True if the key is a provider output
|
|
343
|
-
*/
|
|
344
|
-
function isProviderOutputKey(outputKey) {
|
|
345
|
-
return typeof outputKey === 'string' && !isStateOutputKey(outputKey);
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Parse a state output key to extract the hook index
|
|
349
|
-
*
|
|
350
|
-
* Inverse of generateStateOutputKey.
|
|
351
|
-
*
|
|
352
|
-
* Examples:
|
|
353
|
-
* - parseStateOutputKey('state1') → 0
|
|
354
|
-
* - parseStateOutputKey('state2') → 1
|
|
355
|
-
* - parseStateOutputKey('state3') → 2
|
|
356
|
-
*
|
|
357
|
-
* @param stateOutputKey - State output key
|
|
358
|
-
* @returns Zero-based hook index
|
|
359
|
-
* @throws Error if the key is not a valid state output key
|
|
360
|
-
*/
|
|
361
|
-
function parseStateOutputKey(stateOutputKey) {
|
|
362
|
-
if (!isStateOutputKey(stateOutputKey)) {
|
|
363
|
-
throw new Error(`Invalid state output key: ${stateOutputKey}. Must match format 'state{N}'`);
|
|
364
|
-
}
|
|
365
|
-
// Extract the numeric part after 'state'
|
|
366
|
-
const match = stateOutputKey.match(/^state(\d+)$/);
|
|
367
|
-
if (!match) {
|
|
368
|
-
throw new Error(`Invalid state output key format: ${stateOutputKey}. Expected format: 'state{N}'`);
|
|
369
|
-
}
|
|
370
|
-
// Convert from 1-based to 0-based indexing
|
|
371
|
-
const hookIndex = parseInt(match[1], 10) - 1;
|
|
372
|
-
if (hookIndex < 0) {
|
|
373
|
-
throw new Error(`Invalid state output key: ${stateOutputKey}. Index must be positive.`);
|
|
374
|
-
}
|
|
375
|
-
return hookIndex;
|
|
376
|
-
}
|