MCPcopy
hub / github.com/thesysdev/openui / substituteRef

Function substituteRef

packages/lang-core/src/runtime/evaluator.ts:371–437  ·  view source on GitHub ↗

* Substitute all Ref(varName) nodes in an AST tree with a literal value. * This pre-resolves loop variables so deferred expressions (like Action steps) * don't lose scope when evaluated later at click time.

(node: ASTNode, varName: string, value: unknown)

Source from the content-addressed store, hash-verified

369 * don't lose scope when evaluated later at click time.
370 */
371function substituteRef(node: ASTNode, varName: string, value: unknown): ASTNode {
372 switch (node.k) {
373 case "Ref":
374 return node.n === varName ? toLiteralAST(value) : node;
375 case "Member": {
376 // Member access on the loop var: t.id → resolve t, then access .id
377 if (isASTNode(node.obj)) {
378 const subObj = substituteRef(node.obj as ASTNode, varName, value);
379 // If obj resolved to a literal, we can inline the member access result
380 if (subObj.k === "Obj") {
381 const entry = subObj.entries.find(([k]) => k === node.field);
382 if (entry) return entry[1];
383 }
384 return { ...node, obj: subObj };
385 }
386 return node;
387 }
388 case "Index":
389 return {
390 ...node,
391 obj: isASTNode(node.obj) ? substituteRef(node.obj as ASTNode, varName, value) : node.obj,
392 index: isASTNode(node.index)
393 ? substituteRef(node.index as ASTNode, varName, value)
394 : node.index,
395 };
396 case "BinOp":
397 return {
398 ...node,
399 left: substituteRef(node.left, varName, value),
400 right: substituteRef(node.right, varName, value),
401 };
402 case "UnaryOp":
403 return { ...node, operand: substituteRef(node.operand, varName, value) };
404 case "Ternary":
405 return {
406 ...node,
407 cond: substituteRef(node.cond, varName, value),
408 then: substituteRef(node.then, varName, value),
409 else: substituteRef(node.else, varName, value),
410 };
411 case "Arr":
412 return { ...node, els: node.els.map((e) => substituteRef(e, varName, value)) };
413 case "Obj":
414 return {
415 ...node,
416 entries: node.entries.map(
417 ([k, v]) => [k, substituteRef(v, varName, value)] as [string, ASTNode],
418 ),
419 };
420 case "Comp": {
421 const result = { ...node, args: node.args.map((a) => substituteRef(a, varName, value)) };
422 // Also substitute in mappedProps (added by materializer for catalog components)
423 if (node.mappedProps) {
424 const subProps: Record<string, ASTNode> = {};
425 for (const [k, v] of Object.entries(node.mappedProps)) {
426 subProps[k] = substituteRef(v, varName, value);
427 }
428 (result as any).mappedProps = subProps;

Callers 1

evaluateLazyBuiltinFunction · 0.85

Calls 2

isASTNodeFunction · 0.90
toLiteralASTFunction · 0.85

Tested by

no test coverage detected