You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Below is a **“mental model”** of the Zero-UI variant extractor. distilled so that *another* human (or LLM) can reason about, extend, or safely refactor the code-base.
1
+
Below is a **“mental model”** of the Zero-UI variant extractor. distilled so that _another_ human (or LLM) can reason about, extend, or safely refactor the code-base.
2
2
3
3
---
4
4
5
5
## 1. Top-level goal
6
6
7
-
***Locate every call** to a user-supplied React hook
7
+
-**Locate every call** to a user-supplied React hook
* Statically discover **all possible string values** that flow into
13
-
`stateKey`, `initialValue`, and `setterFn()` arguments.
14
-
*`stateKey` can resolve to a local static string.
15
-
*`initialValue` is the same rule as above.
16
-
*`setterFn()` argument is many forms allowed (see table 3.1) but **must be resolvable**; otherwise the value is ignored (silent) *unless* it looked resolvable but failed inside the helpers, in which case a targeted error is thrown.
17
-
* Imported bindings are never allowed - the dev must re-cast them through a local `const`.
18
12
13
+
- Statically discover **all possible string values** that flow into
14
+
`stateKey`, `initialValue`, and `setterFn()` arguments.
15
+
-`stateKey` can resolve to a local static string.
16
+
-`initialValue` is the same rule as above.
17
+
-`setterFn()` argument is many forms allowed (see table 3.1) but **must be resolvable**; otherwise the value is ignored (silent) _unless_ it looked resolvable but failed inside the helpers, in which case a targeted error is thrown.
18
+
- Imported bindings are never allowed - the dev must re-cast them through a local `const`.
19
19
20
-
* Report the result as a list of `VariantData` objects.
20
+
- Report the result as a list of `VariantData` objects.
| **Pass 1 - `collectUseUISetters`** | 1. Traverse the AST once.<br>2. For each `useUI()` destructuring:<br>• validate shapes & count.<br>• resolve the **state key** and **initial value** with **`literalFromNode`** (see rules below).<br>• grab the **binding** of the setter variable. | `SetterMeta[]` = `{ binding, setterName, stateKey, initialValue }[]` |
37
-
| **Pass 2 - `harvestSetterValues`** | 1. For every `binding.referencePaths` (i.e. every place the setter is used)<br>2. Only keep `CallExpression`s: `setX(…)`<br>3. Examine the first argument:<br>• direct literal / identifier / template → resolve via `literalFromNode`.<br>• conditional `cond?a:b`→ resolve both arms.<br>• logical fallback `a \|\|b`, `a??b` → resolve each side.<br> arrow / function bodies → collect every returned expression and resolve.<br>4. Add every successfully-resolved string to a `Set` bucket **per stateKey**. | `Map< stateKey, Set<string> >` |
|**Pass 1 - `collectUseUISetters`**| 1. Traverse the AST once.<br>2. For each `useUI()` destructuring:<br>• validate shapes & count.<br>• resolve the **state key** and **initial value** with **`literalFromNode`** (see rules below).<br>• grab the **binding** of the setter variable. |`SetterMeta[]` = `{ binding, setterName, stateKey, initialValue }[]`|
37
+
|**Pass 2 - `harvestSetterValues`**| 1. For every `binding.referencePaths` (i.e. every place the setter is used)<br>2. Only keep `CallExpression`s: `setX(…)`<br>3. Examine the first argument:<br>• direct literal / identifier / template → resolve via `literalFromNode`.<br>• conditional `cond ? a : b` → resolve both arms.<br>• logical fallback `a \|\| b`, `a ?? b` → resolve each side.<br> arrow / function bodies → collect every returned expression and resolve.<br>4. Add every successfully-resolved string to a `Set` bucket **per stateKey**. |`Map< stateKey, Set<string> >`|
38
38
39
39
`normalizeVariants` just converts that map back into the
| **`resolveTemplateLiteral`** | Ensures every `${expr}` itself resolves to a string via `literalFromNode`.|
75
-
| **`resolveLocalConstIdentifier`** | Maps an `Identifier` → its `const` initializer *if* that initializer is an accepted string/ template. Rejects imported bindings with a *single* descriptive error.|
76
-
| **`resolveMemberExpression`** | Static walk of `obj.prop`, `obj['prop']`, `obj?.prop`, etc. Works through `asconst`, optional-chaining, arrays, numbers, nested chains. Throws if any hop can't be resolved. |
77
-
| **`literalFromNode`** | Router that calls the above; memoised (`WeakMap`) so each AST node is evaluated once.|
|**`resolveTemplateLiteral`**| Ensures every `${expr}` itself resolves to a string via `literalFromNode`.|
75
+
|**`resolveLocalConstIdentifier`**| Maps an `Identifier` → its `const` initializer _if_ that initializer is an accepted string/ template. Rejects imported bindings with a _single_ descriptive error.|
76
+
|**`resolveMemberExpression`**| Static walk of `obj.prop`, `obj['prop']`, `obj?.prop`, etc. Works through `as const`, optional-chaining, arrays, numbers, nested chains. Throws if any hop can't be resolved. |
77
+
|**`literalFromNode`**| Router that calls the above; memoised (`WeakMap`) so each AST node is evaluated once.|
78
78
79
-
All helpers accept `opts:{ throwOnFail, source, hook }` so *contextual*
79
+
All helpers accept `opts:{ throwOnFail, source, hook }` so _contextual_
80
80
error messages can be emitted with **`throwCodeFrame`**
81
81
(using `@babel/code-frame` to show a coloured snippet).
82
82
83
83
---
84
84
85
85
## 4. Validation rules (why errors occur)
86
86
87
-
| Position in `useUI` | Allowed value | Example error |
| **initialValue (arg 1)** | Same rule as above. | `Initialvaluecannotberesolved …` |
91
-
| **setter argument** | Many forms allowed (see table 3.1) but **must be resolvable**; otherwise the value is ignored (silent) *unless* it looked resolvable but failed inside the helpers, in which case a targeted error is thrown. | |
87
+
| Position in `useUI`| Allowed value | Example error|
|**stateKey (arg 0)**|_Local_ static string|`State key cannot be resolved at build-time.`|
90
+
|**initialValue (arg 1)**| Same rule as above. |`Initial value cannot be resolved …`|
91
+
|**setter argument**| Many forms allowed (see table 3.1) but **must be resolvable**; otherwise the value is ignored (silent) _unless_ it looked resolvable but failed inside the helpers, in which case a targeted error is thrown. ||
92
92
93
93
Imported bindings are never allowed - the dev must re-cast them
94
94
through a local `const`.
@@ -97,50 +97,50 @@ through a local `const`.
97
97
98
98
## 5. Optional-chain & optional-member details
99
99
100
-
* The updated `resolveMemberExpression` loop iterates while
100
+
- The updated `resolveMemberExpression` loop iterates while
0 commit comments