@yahoo/uds-create-config 1.1.1

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 (130) hide show
  1. package/dist/AssetGroup.d.ts +77 -0
  2. package/dist/AssetGroup.js +125 -0
  3. package/dist/Component.d.ts +308 -0
  4. package/dist/Component.js +896 -0
  5. package/dist/ComponentGroup.d.ts +20 -0
  6. package/dist/ComponentGroup.js +46 -0
  7. package/dist/CompositeStyle.d.ts +27 -0
  8. package/dist/CompositeStyle.js +52 -0
  9. package/dist/Config.d.ts +423 -0
  10. package/dist/Config.js +1429 -0
  11. package/dist/Mode.d.ts +41 -0
  12. package/dist/Mode.js +81 -0
  13. package/dist/Modifier.d.ts +51 -0
  14. package/dist/Modifier.js +97 -0
  15. package/dist/MotionDef.d.ts +49 -0
  16. package/dist/MotionDef.js +97 -0
  17. package/dist/Props.d.ts +317 -0
  18. package/dist/Props.js +35 -0
  19. package/dist/Provider.d.ts +20 -0
  20. package/dist/Provider.js +14 -0
  21. package/dist/StyleProp.d.ts +112 -0
  22. package/dist/StyleProp.js +197 -0
  23. package/dist/Token.d.ts +55 -0
  24. package/dist/Token.js +112 -0
  25. package/dist/TokenGroup.d.ts +32 -0
  26. package/dist/TokenGroup.js +68 -0
  27. package/dist/asset-kind.d.ts +55 -0
  28. package/dist/asset-kind.js +29 -0
  29. package/dist/brands.d.ts +30 -0
  30. package/dist/brands.js +20 -0
  31. package/dist/captureCallerPath.d.ts +48 -0
  32. package/dist/captureCallerPath.js +95 -0
  33. package/dist/colorExpressions.d.ts +131 -0
  34. package/dist/colorExpressions.js +148 -0
  35. package/dist/defineAssetGroup.d.ts +166 -0
  36. package/dist/defineAssetGroup.js +264 -0
  37. package/dist/defineProvider.d.ts +29 -0
  38. package/dist/defineProvider.js +60 -0
  39. package/dist/element-marker.d.ts +54 -0
  40. package/dist/element-marker.js +113 -0
  41. package/dist/entity-utils.d.ts +56 -0
  42. package/dist/entity-utils.js +105 -0
  43. package/dist/factories.d.ts +707 -0
  44. package/dist/factories.js +393 -0
  45. package/dist/foreign-component-name.d.ts +21 -0
  46. package/dist/foreign-component-name.js +42 -0
  47. package/dist/index.d.ts +32 -0
  48. package/dist/index.js +28 -0
  49. package/dist/interpolate.d.ts +20 -0
  50. package/dist/interpolate.js +10 -0
  51. package/dist/jsx/__fixtures__/cross-component-preview.d.ts +3 -0
  52. package/dist/jsx/__fixtures__/cross-component-preview.js +15 -0
  53. package/dist/jsx/jsx-dev-runtime.d.ts +15 -0
  54. package/dist/jsx/jsx-dev-runtime.js +11 -0
  55. package/dist/jsx/jsx-runtime.d.ts +48 -0
  56. package/dist/jsx/jsx-runtime.js +305 -0
  57. package/dist/markers.d.ts +217 -0
  58. package/dist/markers.js +67 -0
  59. package/dist/refs.d.ts +158 -0
  60. package/dist/refs.js +104 -0
  61. package/dist/renderer/RendererErrorBoundary.d.ts +26 -0
  62. package/dist/renderer/RendererErrorBoundary.js +30 -0
  63. package/dist/renderer/UdsRenderer.d.ts +80 -0
  64. package/dist/renderer/UdsRenderer.js +33 -0
  65. package/dist/renderer/assetRenderable.d.ts +13 -0
  66. package/dist/renderer/assetRenderable.js +13 -0
  67. package/dist/renderer/index.d.ts +14 -0
  68. package/dist/renderer/index.js +14 -0
  69. package/dist/renderer/makeRegistry.d.ts +34 -0
  70. package/dist/renderer/makeRegistry.js +52 -0
  71. package/dist/renderer/makeUdsRenderer.d.ts +29 -0
  72. package/dist/renderer/makeUdsRenderer.js +35 -0
  73. package/dist/renderer/primitives/FragmentRenderer.d.ts +12 -0
  74. package/dist/renderer/primitives/FragmentRenderer.js +11 -0
  75. package/dist/renderer/primitives/SlotRenderer.d.ts +21 -0
  76. package/dist/renderer/primitives/SlotRenderer.js +20 -0
  77. package/dist/renderer/wrapRegistry.d.ts +64 -0
  78. package/dist/renderer/wrapRegistry.js +39 -0
  79. package/dist/renderer/wrappers/component-slots.d.ts +41 -0
  80. package/dist/renderer/wrappers/component-slots.js +66 -0
  81. package/dist/renderer/wrappers/event-bridge.d.ts +20 -0
  82. package/dist/renderer/wrappers/event-bridge.js +78 -0
  83. package/dist/renderer/wrappers/hex-normalize.d.ts +14 -0
  84. package/dist/renderer/wrappers/hex-normalize.js +35 -0
  85. package/dist/renderer/wrappers/html-aliases.d.ts +24 -0
  86. package/dist/renderer/wrappers/html-aliases.js +62 -0
  87. package/dist/renderer/wrappers/inline-styles.d.ts +16 -0
  88. package/dist/renderer/wrappers/inline-styles.js +104 -0
  89. package/dist/renderer/wrappers/slot-resolution.d.ts +25 -0
  90. package/dist/renderer/wrappers/slot-resolution.js +68 -0
  91. package/dist/renderer/wrappers/void-elements.d.ts +23 -0
  92. package/dist/renderer/wrappers/void-elements.js +28 -0
  93. package/dist/spec/apply-forced-modifiers.d.ts +19 -0
  94. package/dist/spec/apply-forced-modifiers.js +49 -0
  95. package/dist/spec/asset-jsx.d.ts +48 -0
  96. package/dist/spec/asset-jsx.js +48 -0
  97. package/dist/spec/collapse-text-labels.d.ts +44 -0
  98. package/dist/spec/collapse-text-labels.js +107 -0
  99. package/dist/spec/empty-node-slots.d.ts +51 -0
  100. package/dist/spec/empty-node-slots.js +141 -0
  101. package/dist/spec/index.d.ts +10 -0
  102. package/dist/spec/index.js +10 -0
  103. package/dist/spec/jsxToSpec.d.ts +48 -0
  104. package/dist/spec/jsxToSpec.js +506 -0
  105. package/dist/spec/layer-props.d.ts +52 -0
  106. package/dist/spec/layer-props.js +149 -0
  107. package/dist/spec/preview-controls.d.ts +44 -0
  108. package/dist/spec/preview-controls.js +139 -0
  109. package/dist/spec/slot-refs.d.ts +39 -0
  110. package/dist/spec/slot-refs.js +56 -0
  111. package/dist/spec/specToJsx.d.ts +35 -0
  112. package/dist/spec/specToJsx.js +127 -0
  113. package/dist/token-override-rows.d.ts +66 -0
  114. package/dist/token-override-rows.js +223 -0
  115. package/dist/tokenValueType.d.ts +34 -0
  116. package/dist/tokenValueType.js +138 -0
  117. package/dist/tsconfig.tsbuildinfo +1 -0
  118. package/dist/types/css-properties.d.ts +232 -0
  119. package/dist/types/css-properties.js +14 -0
  120. package/dist/types/css-property-keywords.d.ts +156 -0
  121. package/dist/types/css-property-keywords.js +616 -0
  122. package/dist/types/css-values.d.ts +63 -0
  123. package/dist/types/css-values.js +16 -0
  124. package/dist/types.d.ts +708 -0
  125. package/dist/types.js +12 -0
  126. package/dist/units.d.ts +14 -0
  127. package/dist/units.js +16 -0
  128. package/dist/utils/index.d.ts +4 -0
  129. package/dist/utils/index.js +4 -0
  130. package/package.json +81 -0
@@ -0,0 +1,48 @@
1
+ import { AssetNodeResolver } from "./asset-jsx.js";
2
+ import { Spec } from "@json-render/core";
3
+
4
+ //#region src/spec/jsxToSpec.d.ts
5
+ /**
6
+ * Sentinel value used when a prop expression couldn't be statically resolved.
7
+ * Callers can check `hasUnresolvedProps(spec)` to detect this.
8
+ */
9
+ declare const UNRESOLVED: unique symbol;
10
+ /** Check if any element in the spec has prop values that couldn't be statically resolved. */
11
+ declare function hasUnresolvedProps(spec: Spec): boolean;
12
+ /** Return a copy of the spec with all UNRESOLVED and STATE_SETTER prop values removed. */
13
+ declare function stripUnresolvedProps(spec: Spec): Spec;
14
+ interface JsxToSpecOptions {
15
+ /**
16
+ * Full module source for scope resolution.
17
+ * When provided, top-level const declarations are resolved
18
+ * and local component functions are inlined.
19
+ */
20
+ moduleSource?: string;
21
+ /**
22
+ * Set of known component names in the registry. When provided, any
23
+ * PascalCase JSX element whose tag is NOT in this set (e.g. providers,
24
+ * wrappers) is treated as a transparent fragment — its children are
25
+ * flattened into the parent.
26
+ */
27
+ knownComponents?: Set<string>;
28
+ /**
29
+ * Reconstructs placed asset nodes from authoring-component tags —
30
+ * `<Icon name="Trophy" …/>` → type `yahoo-os:asset:icons/Trophy`. The
31
+ * exact inverse of `specToJsx`'s `assetComponents` mapping; without it an
32
+ * `<Icon name=…/>` round-trips as a literal `Icon` component node.
33
+ */
34
+ resolveAssetNode?: AssetNodeResolver;
35
+ }
36
+ /**
37
+ * Convert JSX source code into a json-render Spec.
38
+ *
39
+ * Accepts either a full JSX module or a JSX expression snippet.
40
+ * When `moduleSource` is provided, identifier references are resolved
41
+ * against the module's top-level const declarations, and local component
42
+ * functions are inlined.
43
+ *
44
+ * Returns `null` if no JSX element is found in the source.
45
+ */
46
+ declare function jsxToSpec(source: string, options?: JsxToSpecOptions): Spec | null;
47
+ //#endregion
48
+ export { JsxToSpecOptions, UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps };
@@ -0,0 +1,506 @@
1
+ import { parse } from "@babel/parser";
2
+ //#region src/spec/jsxToSpec.ts
3
+ /**
4
+ * Sentinel value for useState setter functions.
5
+ * When a prop value resolves to this, the prop is a state setter (e.g. onChange={setValue})
6
+ * and should be stripped — $bindState handles write-back automatically.
7
+ */
8
+ const STATE_SETTER = Symbol.for("jsxToSpec.stateSetter");
9
+ function buildModuleScope(ast) {
10
+ const scope = {
11
+ values: /* @__PURE__ */ new Map(),
12
+ valueNodes: /* @__PURE__ */ new Map(),
13
+ components: /* @__PURE__ */ new Map(),
14
+ stateBindings: /* @__PURE__ */ new Map(),
15
+ stateSetters: /* @__PURE__ */ new Map()
16
+ };
17
+ const body = getModuleBody(ast);
18
+ if (!body) return scope;
19
+ collectUseStateBindings(body, scope);
20
+ for (const stmt of body) {
21
+ if (stmt.type === "VariableDeclaration") {
22
+ const decl = stmt;
23
+ if (decl.kind !== "const") continue;
24
+ for (const declarator of decl.declarations) {
25
+ const d = declarator;
26
+ if (d.id.type !== "Identifier" || !d.init) continue;
27
+ const name = d.id.name;
28
+ const value = evaluateExpression(d.init, scope);
29
+ if (value !== UNRESOLVED) scope.values.set(name, value);
30
+ scope.valueNodes.set(name, d.init);
31
+ if (name[0] === name[0].toUpperCase()) {
32
+ const jsx = findJsxInFunctionBody(d.init);
33
+ if (jsx) scope.components.set(name, jsx);
34
+ }
35
+ }
36
+ }
37
+ if (stmt.type === "FunctionDeclaration") {
38
+ const fn = stmt;
39
+ if (!fn.id || fn.id.type !== "Identifier") continue;
40
+ const name = fn.id.name;
41
+ if (name[0] === name[0].toUpperCase()) {
42
+ const jsx = findJsxInFunctionBody(fn);
43
+ if (jsx) scope.components.set(name, jsx);
44
+ }
45
+ }
46
+ }
47
+ return scope;
48
+ }
49
+ /**
50
+ * Detect `const [x, setX] = useState(initialValue)` patterns in function
51
+ * bodies and register them in the scope's stateBindings / stateSetters maps.
52
+ *
53
+ * Scans all function declarations and arrow function expressions at any
54
+ * nesting level (top-level functions, component functions, etc.).
55
+ */
56
+ function collectUseStateBindings(stmts, scope) {
57
+ for (const stmt of stmts) {
58
+ if (stmt.type === "FunctionDeclaration") {
59
+ const body = stmt.body;
60
+ if (body.type === "BlockStatement") collectUseStateFromBlock(body.body, scope);
61
+ }
62
+ if (stmt.type === "VariableDeclaration") {
63
+ const decl = stmt;
64
+ for (const declarator of decl.declarations) {
65
+ const d = declarator;
66
+ if (!d.init) continue;
67
+ if (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression") {
68
+ const body = d.init.body;
69
+ if (body.type === "BlockStatement") collectUseStateFromBlock(body.body, scope);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Scan statements in a block for `const [x, setX] = useState(init)` patterns.
77
+ */
78
+ function collectUseStateFromBlock(stmts, scope) {
79
+ for (const stmt of stmts) {
80
+ if (stmt.type !== "VariableDeclaration") continue;
81
+ const decl = stmt;
82
+ if (decl.kind !== "const") continue;
83
+ for (const declarator of decl.declarations) {
84
+ const d = declarator;
85
+ if (d.id.type !== "ArrayPattern" || !d.init) continue;
86
+ if (d.init.type !== "CallExpression") continue;
87
+ const call = d.init;
88
+ const callee = call.callee;
89
+ if (callee.type !== "Identifier") continue;
90
+ if (callee.name !== "useState") continue;
91
+ const elements = d.id.elements;
92
+ if (elements.length < 2) continue;
93
+ if (elements[0].type !== "Identifier" || elements[1].type !== "Identifier") continue;
94
+ const stateVarName = elements[0].name;
95
+ const setterName = elements[1].name;
96
+ const initArg = call.arguments[0];
97
+ const initialValue = initArg ? evaluateExpression(initArg, scope) : void 0;
98
+ scope.stateBindings.set(stateVarName, initialValue !== UNRESOLVED ? initialValue : null);
99
+ scope.stateSetters.set(setterName, stateVarName);
100
+ scope.values.set(stateVarName, { $bindState: `/${stateVarName}` });
101
+ scope.values.set(setterName, STATE_SETTER);
102
+ }
103
+ }
104
+ }
105
+ function getModuleBody(ast) {
106
+ if (ast.type === "File") return ast.program.body;
107
+ if (ast.type === "Program") return ast.body;
108
+ return null;
109
+ }
110
+ /**
111
+ * Extract JSX from a function body (arrow function or function declaration).
112
+ */
113
+ function findJsxInFunctionBody(node) {
114
+ if (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") {
115
+ const body = node.body;
116
+ return extractJsxFromBody(body);
117
+ }
118
+ if (node.type === "FunctionDeclaration") {
119
+ const body = node.body;
120
+ return extractJsxFromBody(body);
121
+ }
122
+ return null;
123
+ }
124
+ function extractJsxFromBody(body) {
125
+ if (body.type === "JSXElement") return body;
126
+ if (body.type === "JSXFragment") return body;
127
+ if (body.type === "ParenthesizedExpression") return extractJsxFromBody(body.expression);
128
+ if (body.type === "BlockStatement") {
129
+ const stmts = body.body;
130
+ for (const stmt of stmts) if (stmt.type === "ReturnStatement") {
131
+ const arg = stmt.argument;
132
+ if (arg) return extractJsxFromBody(arg);
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+ /**
138
+ * Sentinel value used when a prop expression couldn't be statically resolved.
139
+ * Callers can check `hasUnresolvedProps(spec)` to detect this.
140
+ */
141
+ const UNRESOLVED = Symbol.for("jsxToSpec.unresolved");
142
+ /** Check if any element in the spec has prop values that couldn't be statically resolved. */
143
+ function hasUnresolvedProps(spec) {
144
+ for (const el of Object.values(spec.elements)) if (el.props) {
145
+ for (const value of Object.values(el.props)) if (value === UNRESOLVED || value === STATE_SETTER) return true;
146
+ }
147
+ return false;
148
+ }
149
+ /** Return a copy of the spec with all UNRESOLVED and STATE_SETTER prop values removed. */
150
+ function stripUnresolvedProps(spec) {
151
+ const elements = {};
152
+ for (const [key, el] of Object.entries(spec.elements)) {
153
+ if (!el.props) {
154
+ elements[key] = { ...el };
155
+ continue;
156
+ }
157
+ const cleanProps = {};
158
+ for (const [k, v] of Object.entries(el.props)) if (v !== UNRESOLVED && v !== STATE_SETTER) cleanProps[k] = v;
159
+ elements[key] = {
160
+ ...el,
161
+ props: cleanProps
162
+ };
163
+ }
164
+ return {
165
+ ...spec,
166
+ elements
167
+ };
168
+ }
169
+ function evaluateExpression(node, scope) {
170
+ switch (node.type) {
171
+ case "StringLiteral": return node.value;
172
+ case "NumericLiteral": return node.value;
173
+ case "BooleanLiteral": return node.value;
174
+ case "NullLiteral": return null;
175
+ case "Identifier": {
176
+ const name = node.name;
177
+ if (name === "undefined") return UNRESOLVED;
178
+ if (scope.values.has(name)) return scope.values.get(name);
179
+ const initNode = scope.valueNodes.get(name);
180
+ if (initNode) {
181
+ const value = evaluateExpression(initNode, scope);
182
+ if (value !== UNRESOLVED) {
183
+ scope.values.set(name, value);
184
+ return value;
185
+ }
186
+ }
187
+ return UNRESOLVED;
188
+ }
189
+ case "TemplateLiteral": {
190
+ const quasis = node.quasis;
191
+ const expressions = node.expressions;
192
+ if (expressions.length === 0) return quasis[0].value.cooked;
193
+ let result = "";
194
+ for (let i = 0; i < quasis.length; i++) {
195
+ result += quasis[i].value.cooked;
196
+ if (i < expressions.length) {
197
+ const val = evaluateExpression(expressions[i], scope);
198
+ if (val === UNRESOLVED) return UNRESOLVED;
199
+ result += String(val);
200
+ }
201
+ }
202
+ return result;
203
+ }
204
+ case "ObjectExpression": return evaluateObjectExpression(node, scope);
205
+ case "ArrayExpression": return evaluateArrayExpression(node, scope);
206
+ case "UnaryExpression": {
207
+ const unary = node;
208
+ if (unary.operator === "-") {
209
+ const arg = evaluateExpression(unary.argument, scope);
210
+ if (typeof arg === "number") return -arg;
211
+ }
212
+ if (unary.operator === "!") {
213
+ const arg = evaluateExpression(unary.argument, scope);
214
+ if (arg !== UNRESOLVED) return !arg;
215
+ }
216
+ return UNRESOLVED;
217
+ }
218
+ default: return UNRESOLVED;
219
+ }
220
+ }
221
+ function evaluateObjectExpression(node, scope) {
222
+ const result = {};
223
+ for (const prop of node.properties) {
224
+ if (prop.type === "SpreadElement") {
225
+ const arg = prop.argument;
226
+ const val = evaluateExpression(arg, scope);
227
+ if (val === UNRESOLVED || typeof val !== "object" || val === null) return UNRESOLVED;
228
+ Object.assign(result, val);
229
+ continue;
230
+ }
231
+ if (prop.type !== "ObjectProperty") return UNRESOLVED;
232
+ const objProp = prop;
233
+ if (objProp.computed) return UNRESOLVED;
234
+ let key;
235
+ if (objProp.key.type === "Identifier") key = objProp.key.name;
236
+ else if (objProp.key.type === "StringLiteral") key = objProp.key.value;
237
+ else return UNRESOLVED;
238
+ const value = evaluateExpression(objProp.value, scope);
239
+ if (value !== UNRESOLVED) result[key] = value;
240
+ }
241
+ return result;
242
+ }
243
+ function evaluateArrayExpression(node, scope) {
244
+ const result = [];
245
+ for (const element of node.elements) {
246
+ if (!element) return UNRESOLVED;
247
+ if (element.type === "SpreadElement") {
248
+ const arg = element.argument;
249
+ const val = evaluateExpression(arg, scope);
250
+ if (val === UNRESOLVED || !Array.isArray(val)) return UNRESOLVED;
251
+ result.push(...val);
252
+ continue;
253
+ }
254
+ const value = evaluateExpression(element, scope);
255
+ if (value === UNRESOLVED) return UNRESOLVED;
256
+ result.push(value);
257
+ }
258
+ return result;
259
+ }
260
+ function getTagName(element) {
261
+ const { name } = element.openingElement;
262
+ if (name.type === "JSXIdentifier") return name.name;
263
+ return null;
264
+ }
265
+ function getAttributeValue(valueNode, scope, ctx) {
266
+ if (valueNode === null) return true;
267
+ switch (valueNode.type) {
268
+ case "StringLiteral": return valueNode.value;
269
+ case "JSXExpressionContainer": {
270
+ const expr = valueNode.expression;
271
+ if (ctx && (expr.type === "JSXElement" || expr.type === "JSXFragment")) {
272
+ const slotKey = convertJsxNode(expr, ctx);
273
+ if (slotKey) return { $slot: slotKey };
274
+ return UNRESOLVED;
275
+ }
276
+ return evaluateExpression(expr, scope);
277
+ }
278
+ default: return UNRESOLVED;
279
+ }
280
+ }
281
+ function collectTextChildren(children) {
282
+ const textParts = [];
283
+ for (const child of children) if (child.type === "JSXText") {
284
+ const trimmed = child.value.replace(/\n\s*/g, " ").trim();
285
+ if (trimmed) textParts.push(trimmed);
286
+ } else if (child.type === "JSXExpressionContainer") {
287
+ const expr = child.expression;
288
+ if (expr.type === "StringLiteral") textParts.push(expr.value);
289
+ else return null;
290
+ } else if (child.type === "JSXElement" || child.type === "JSXFragment") return null;
291
+ return textParts.length > 0 ? textParts.join(" ") : null;
292
+ }
293
+ function hasElementChildren(children) {
294
+ return children.some((c) => c.type === "JSXElement" || c.type === "JSXFragment");
295
+ }
296
+ function nextKey(ctx) {
297
+ return `el${ctx.counter++}`;
298
+ }
299
+ /** Map React event prop names to json-render event names */
300
+ const EVENT_PROP_MAP = {
301
+ onClick: "press",
302
+ onPress: "press",
303
+ onSubmit: "submit"
304
+ };
305
+ /**
306
+ * Try to extract a json-render `on` binding from an event handler prop.
307
+ *
308
+ * Detects patterns like:
309
+ * onClick={() => setSetter(value)} → { action: "setState", params: { statePath, value } }
310
+ * onClick={() => setter(value)} → same (setter is a known state setter)
311
+ *
312
+ * Returns null if the prop is not a recognized event handler pattern.
313
+ */
314
+ function tryExtractOnBinding(propName, valueNode, scope) {
315
+ const eventName = EVENT_PROP_MAP[propName];
316
+ if (!eventName || !valueNode) return null;
317
+ if (valueNode.type !== "JSXExpressionContainer") return null;
318
+ const expr = valueNode.expression;
319
+ if (expr.type !== "ArrowFunctionExpression") return null;
320
+ const arrow = expr;
321
+ let callExpr = null;
322
+ if (arrow.body.type === "CallExpression") callExpr = arrow.body;
323
+ else if (arrow.body.type === "BlockStatement") {
324
+ const stmts = arrow.body.body;
325
+ if (stmts.length === 1 && stmts[0].type === "ExpressionStatement") {
326
+ const innerExpr = stmts[0].expression;
327
+ if (innerExpr.type === "CallExpression") callExpr = innerExpr;
328
+ }
329
+ }
330
+ if (!callExpr) return null;
331
+ const call = callExpr;
332
+ if (call.callee.type !== "Identifier") return null;
333
+ const calleeName = call.callee.name;
334
+ const stateVarName = scope.stateSetters.get(calleeName);
335
+ if (!stateVarName) return null;
336
+ const arg = call.arguments[0];
337
+ const value = arg ? evaluateExpression(arg, scope) : null;
338
+ if (value === UNRESOLVED) return null;
339
+ return {
340
+ event: eventName,
341
+ action: {
342
+ action: "setState",
343
+ params: {
344
+ statePath: `/${stateVarName}`,
345
+ value
346
+ }
347
+ }
348
+ };
349
+ }
350
+ function convertElement(node, ctx) {
351
+ const tagName = getTagName(node);
352
+ if (!tagName) return null;
353
+ if (ctx.scope.components.has(tagName) && !ctx.inlining.has(tagName)) {
354
+ const componentJsx = ctx.scope.components.get(tagName);
355
+ ctx.inlining.add(tagName);
356
+ const result = convertJsxNode(componentJsx, ctx);
357
+ ctx.inlining.delete(tagName);
358
+ return result;
359
+ }
360
+ if (ctx.knownComponents && tagName[0] === tagName[0].toUpperCase() && !ctx.knownComponents.has(tagName)) return flattenChildrenAsFragment(node.children, ctx);
361
+ const key = nextKey(ctx);
362
+ const props = {};
363
+ const onBindings = {};
364
+ for (const attr of node.openingElement.attributes) if (attr.type === "JSXAttribute") {
365
+ const jsxAttr = attr;
366
+ const propName = jsxAttr.name.name;
367
+ const binding = tryExtractOnBinding(propName, jsxAttr.value, ctx.scope);
368
+ if (binding) {
369
+ onBindings[binding.event] = binding.action;
370
+ continue;
371
+ }
372
+ props[propName] = getAttributeValue(jsxAttr.value, ctx.scope, ctx);
373
+ } else if (attr.type === "JSXSpreadAttribute") props.__spread__ = UNRESOLVED;
374
+ const childKeys = [];
375
+ const textContent = collectTextChildren(node.children);
376
+ if (textContent !== null && !hasElementChildren(node.children)) props.children = textContent;
377
+ else for (const child of node.children) {
378
+ const childKey = convertJsxNode(child, ctx);
379
+ if (childKey) childKeys.push(childKey);
380
+ }
381
+ const assetType = ctx.resolveAssetNode?.(tagName, props) ?? null;
382
+ if (assetType) delete props.name;
383
+ const element = {
384
+ type: assetType ?? tagName,
385
+ props
386
+ };
387
+ if (childKeys.length > 0) element.children = childKeys;
388
+ if (Object.keys(onBindings).length > 0) element.on = onBindings;
389
+ ctx.elements[key] = element;
390
+ return key;
391
+ }
392
+ /**
393
+ * Flatten a list of JSX children as if they were inside a fragment.
394
+ * Returns a single key if there's one child, a Fragment element for
395
+ * multiple, or null for none.
396
+ */
397
+ function flattenChildrenAsFragment(children, ctx) {
398
+ const childKeys = [];
399
+ for (const child of children) {
400
+ const childKey = convertJsxNode(child, ctx);
401
+ if (childKey) childKeys.push(childKey);
402
+ }
403
+ if (childKeys.length === 1) return childKeys[0];
404
+ if (childKeys.length > 1) {
405
+ const fragKey = nextKey(ctx);
406
+ ctx.elements[fragKey] = {
407
+ type: "Fragment",
408
+ props: {},
409
+ children: childKeys
410
+ };
411
+ return fragKey;
412
+ }
413
+ return null;
414
+ }
415
+ function convertJsxNode(node, ctx) {
416
+ if (node.type === "JSXElement") return convertElement(node, ctx);
417
+ if (node.type === "JSXFragment") return flattenChildrenAsFragment(node.children, ctx);
418
+ return null;
419
+ }
420
+ function findJsxRoot(node) {
421
+ if (node.type === "JSXElement") return node;
422
+ if (node.type === "JSXFragment") return node;
423
+ if (node.type === "ParenthesizedExpression") return findJsxRoot(node.expression);
424
+ if (node.type === "ReturnStatement") {
425
+ const arg = node.argument;
426
+ return arg ? findJsxRoot(arg) : null;
427
+ }
428
+ if (node.type === "ArrowFunctionExpression" || node.type === "FunctionExpression") {
429
+ const body = node.body;
430
+ return extractJsxFromBody(body);
431
+ }
432
+ if (node.type === "ExpressionStatement") return findJsxRoot(node.expression);
433
+ if (node.type === "VariableDeclaration") {
434
+ const declarations = node.declarations;
435
+ for (const decl of declarations) if (decl.type === "VariableDeclarator") {
436
+ const init = decl.init;
437
+ if (init) {
438
+ const found = findJsxRoot(init);
439
+ if (found) return found;
440
+ }
441
+ }
442
+ return null;
443
+ }
444
+ if (node.type === "FunctionDeclaration") {
445
+ const body = node.body;
446
+ if (body.type === "BlockStatement") {
447
+ const stmts = body.body;
448
+ for (const stmt of stmts) if (stmt.type === "ReturnStatement") return findJsxRoot(stmt);
449
+ }
450
+ return null;
451
+ }
452
+ if (node.type === "Program" || node.type === "File") {
453
+ const body = node.type === "File" ? node.program.body : node.body;
454
+ for (const stmt of body) {
455
+ const found = findJsxRoot(stmt);
456
+ if (found) return found;
457
+ }
458
+ }
459
+ return null;
460
+ }
461
+ /**
462
+ * Convert JSX source code into a json-render Spec.
463
+ *
464
+ * Accepts either a full JSX module or a JSX expression snippet.
465
+ * When `moduleSource` is provided, identifier references are resolved
466
+ * against the module's top-level const declarations, and local component
467
+ * functions are inlined.
468
+ *
469
+ * Returns `null` if no JSX element is found in the source.
470
+ */
471
+ function jsxToSpec(source, options) {
472
+ const ast = parse(source, {
473
+ sourceType: "module",
474
+ plugins: ["jsx", "typescript"],
475
+ errorRecovery: true
476
+ });
477
+ const scope = buildModuleScope(options?.moduleSource ? parse(options.moduleSource, {
478
+ sourceType: "module",
479
+ plugins: ["jsx", "typescript"],
480
+ errorRecovery: true
481
+ }) : ast);
482
+ const jsxRoot = findJsxRoot(ast);
483
+ if (!jsxRoot) return null;
484
+ const ctx = {
485
+ elements: {},
486
+ counter: 0,
487
+ scope,
488
+ inlining: /* @__PURE__ */ new Set(),
489
+ knownComponents: options?.knownComponents ?? null,
490
+ resolveAssetNode: options?.resolveAssetNode ?? null
491
+ };
492
+ const rootKey = convertJsxNode(jsxRoot, ctx);
493
+ if (!rootKey) return null;
494
+ const spec = {
495
+ root: rootKey,
496
+ elements: ctx.elements
497
+ };
498
+ if (scope.stateBindings.size > 0) {
499
+ const state = {};
500
+ for (const [name, initialValue] of scope.stateBindings) state[name] = initialValue;
501
+ spec.state = state;
502
+ }
503
+ return spec;
504
+ }
505
+ //#endregion
506
+ export { UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps };
@@ -0,0 +1,52 @@
1
+ import { BaseStyles, CompoundPropsEntry } from "../types.js";
2
+
3
+ //#region src/spec/layer-props.d.ts
4
+ type RenderedLayerProps = Record<string, Record<string, unknown>>;
5
+ /**
6
+ * Structural view of the component fields style resolution reads. Satisfied by
7
+ * a real `@yahoo/uds-create-config` `Component` (Studio, playground) AND by codegen's
8
+ * capture-time `ProbeComponent` (`extractPreviewSpecs.buildRenderSpec`), so the
9
+ * same resolver bakes styles into the render spec at build time and resolves
10
+ * derived (non-render) values like the layers-panel `display` at render time.
11
+ */
12
+ interface ResolvableComponent {
13
+ layers: ReadonlyMap<string, unknown>;
14
+ base?: BaseStyles;
15
+ props?: Record<string, unknown>;
16
+ compoundProps?: readonly CompoundPropsEntry[];
17
+ }
18
+ /**
19
+ * Resolve the styles a layer effectively has for a set of prop-axis values and
20
+ * (optionally) one forced interaction state, walking the authoring surfaces
21
+ * codegen reads:
22
+ *
23
+ * 1. `component.base[layer]` — the always-on baseline.
24
+ * 2. `component.props[axis].values[value][layer]` — per axis key in `propValues`.
25
+ * 3. `component.compoundProps[].layers[layer]` — for entries whose `when`
26
+ * is a subset of `propValues` (multi-axis overrides).
27
+ * 4. State overlay — when `state` names a modifier sub-object (`_hover`) on
28
+ * the merged surface, its props overlay the base so a static preview
29
+ * shows that state.
30
+ *
31
+ * `propValues` are plain axis names → values (no reserved keys). `state` is a
32
+ * single forced interaction modifier (`'_hover'`); pass it directly rather than
33
+ * smuggling it into `propValues`. **Modes are intentionally not a parameter** —
34
+ * mode visuals ride a scoped wrapper class (`.dark &`) and flip live, so they
35
+ * are never folded into the static base here.
36
+ */
37
+ declare function resolveAuthoredLayerProps(component: ResolvableComponent | undefined | null, layer: string, propValues: Record<string, unknown>, state?: string | null): Record<string, unknown>;
38
+ /**
39
+ * Resolve per-layer style bags for a set of prop values, mirroring the config's
40
+ * variant resolution. `buildRenderSpec` calls this once per variant combo to
41
+ * bake the bags onto the render spec.
42
+ *
43
+ * `state` is left `null` by the bake path — modifier blocks ride through as
44
+ * nested style props and forced state is applied per cell (the render-spec
45
+ * consumers fold the active modifier into props), so folding it into the base
46
+ * here would be redundant. (Derived callers like the layers panel also pass no
47
+ * state.) `cssVarPrefix` resolves color expressions to a `var(...)`-referencing
48
+ * arbitrary value.
49
+ */
50
+ declare function resolveRenderedLayerProps(component: ResolvableComponent | undefined, propValues: Record<string, unknown>, state?: string | null, cssVarPrefix?: string): RenderedLayerProps;
51
+ //#endregion
52
+ export { ResolvableComponent, resolveAuthoredLayerProps, resolveRenderedLayerProps };