@maxhealth.tech/prefab 0.3.9 → 0.3.11

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 (95) hide show
  1. package/CHANGELOG.md +723 -671
  2. package/README.md +76 -10
  3. package/dist/a2ui/browser.d.ts +46 -0
  4. package/dist/a2ui/browser.d.ts.map +1 -0
  5. package/dist/a2ui/browser.js +58 -0
  6. package/dist/a2ui/browser.js.map +1 -0
  7. package/dist/a2ui/catalog.d.ts +72 -0
  8. package/dist/a2ui/catalog.d.ts.map +1 -0
  9. package/dist/a2ui/catalog.js +521 -0
  10. package/dist/a2ui/catalog.js.map +1 -0
  11. package/dist/a2ui/control.d.ts +20 -0
  12. package/dist/a2ui/control.d.ts.map +1 -0
  13. package/dist/a2ui/control.js +107 -0
  14. package/dist/a2ui/control.js.map +1 -0
  15. package/dist/a2ui/emit.d.ts +59 -0
  16. package/dist/a2ui/emit.d.ts.map +1 -0
  17. package/dist/a2ui/emit.js +373 -0
  18. package/dist/a2ui/emit.js.map +1 -0
  19. package/dist/a2ui/expr.d.ts +91 -0
  20. package/dist/a2ui/expr.d.ts.map +1 -0
  21. package/dist/a2ui/expr.js +201 -0
  22. package/dist/a2ui/expr.js.map +1 -0
  23. package/dist/a2ui/icons.d.ts +30 -0
  24. package/dist/a2ui/icons.d.ts.map +1 -0
  25. package/dist/a2ui/icons.js +87 -0
  26. package/dist/a2ui/icons.js.map +1 -0
  27. package/dist/a2ui/index.d.ts +29 -0
  28. package/dist/a2ui/index.d.ts.map +1 -0
  29. package/dist/a2ui/index.js +24 -0
  30. package/dist/a2ui/index.js.map +1 -0
  31. package/dist/a2ui/pipes.d.ts +49 -0
  32. package/dist/a2ui/pipes.d.ts.map +1 -0
  33. package/dist/a2ui/pipes.js +106 -0
  34. package/dist/a2ui/pipes.js.map +1 -0
  35. package/dist/a2ui/table.d.ts +31 -0
  36. package/dist/a2ui/table.d.ts.map +1 -0
  37. package/dist/a2ui/table.js +155 -0
  38. package/dist/a2ui/table.js.map +1 -0
  39. package/dist/a2ui/types.d.ts +174 -0
  40. package/dist/a2ui/types.d.ts.map +1 -0
  41. package/dist/a2ui/types.js +35 -0
  42. package/dist/a2ui/types.js.map +1 -0
  43. package/dist/a2ui.min.js +1 -0
  44. package/dist/app.d.ts +17 -0
  45. package/dist/app.d.ts.map +1 -1
  46. package/dist/app.js +19 -0
  47. package/dist/app.js.map +1 -1
  48. package/dist/auto/form.d.ts +25 -0
  49. package/dist/auto/form.d.ts.map +1 -1
  50. package/dist/auto/form.js +21 -8
  51. package/dist/auto/form.js.map +1 -1
  52. package/dist/core/version.d.ts +1 -1
  53. package/dist/core/version.d.ts.map +1 -1
  54. package/dist/core/version.js +1 -1
  55. package/dist/core/version.js.map +1 -1
  56. package/dist/index.d.ts +9 -2
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +4 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/mcp/a2ui.d.ts +91 -0
  61. package/dist/mcp/a2ui.d.ts.map +1 -0
  62. package/dist/mcp/a2ui.js +134 -0
  63. package/dist/mcp/a2ui.js.map +1 -0
  64. package/dist/mcp/display.d.ts +28 -6
  65. package/dist/mcp/display.d.ts.map +1 -1
  66. package/dist/mcp/display.js +10 -9
  67. package/dist/mcp/display.js.map +1 -1
  68. package/dist/mcp/index.d.ts +7 -2
  69. package/dist/mcp/index.d.ts.map +1 -1
  70. package/dist/mcp/index.js +3 -1
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/mcp/input-required.d.ts +79 -0
  73. package/dist/mcp/input-required.d.ts.map +1 -0
  74. package/dist/mcp/input-required.js +231 -0
  75. package/dist/mcp/input-required.js.map +1 -0
  76. package/dist/mcp/resource.d.ts +10 -0
  77. package/dist/mcp/resource.d.ts.map +1 -1
  78. package/dist/mcp/resource.js +12 -4
  79. package/dist/mcp/resource.js.map +1 -1
  80. package/dist/mcp/result.d.ts +7 -5
  81. package/dist/mcp/result.d.ts.map +1 -1
  82. package/dist/mcp/result.js +5 -3
  83. package/dist/mcp/result.js.map +1 -1
  84. package/dist/mcp/types.d.ts +117 -0
  85. package/dist/mcp/types.d.ts.map +1 -1
  86. package/dist/renderer/components/index.d.ts.map +1 -1
  87. package/dist/renderer/components/index.js +6 -0
  88. package/dist/renderer/components/index.js.map +1 -1
  89. package/dist/renderer/engine.d.ts +4 -0
  90. package/dist/renderer/engine.d.ts.map +1 -1
  91. package/dist/renderer/engine.js +24 -0
  92. package/dist/renderer/engine.js.map +1 -1
  93. package/dist/renderer.auto.min.js +13 -13
  94. package/dist/renderer.min.js +13 -13
  95. package/package.json +14 -3
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Control-flow mappers — `ForEach`, `Define`/`Use`/`Slot`, and the conditionals.
3
+ *
4
+ * These are the prefab components with no A2UI component of their own, and they
5
+ * split three ways. `ForEach` has an A2UI *mechanism* rather than a component:
6
+ * the child template, the same construct `./table.ts` uses for `DataTable`.
7
+ * `Define`/`Use`/`Slot` need no A2UI concept at all, because a definition can be
8
+ * expanded before the payload is sent.
9
+ *
10
+ * Conditionals are the exception, and the one genuine capability gap between the
11
+ * two protocols. A2UI has no declarative `if`: the renderer draws what the
12
+ * adjacency list says, and the agent sends a fresh `updateComponents` when the
13
+ * shape should change. prefab runs a reactive client that re-shapes itself
14
+ * without a round trip. Faking it — emitting a one-item list template as a
15
+ * pretend conditional — would produce a UI that is wrong in a way nothing
16
+ * reports, so it is diagnosed instead.
17
+ */
18
+ import { escapePointerToken } from './expr.js';
19
+ /** Read the first present scalar prop from a node. */
20
+ function textOf(node, ...keys) {
21
+ for (const k of keys) {
22
+ const v = node[k];
23
+ if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
24
+ return String(v);
25
+ }
26
+ return undefined;
27
+ }
28
+ /** Narrow an unknown `slots` prop to the shape the renderer expects. */
29
+ function isNodeMap(value) {
30
+ return value != null && typeof value === 'object' && !Array.isArray(value);
31
+ }
32
+ export const CONTROL_MAPPERS = {
33
+ ForEach: (node, ctx) => {
34
+ const expression = textOf(node, 'expression');
35
+ if (expression == null) {
36
+ ctx.note('unsupported', 'ForEach', 'no expression to iterate');
37
+ return undefined;
38
+ }
39
+ const bound = ctx.bind(expression);
40
+ if (bound.kind !== 'binding') {
41
+ ctx.note('expression', 'ForEach', `"${expression}" is not a plain path, so there is no list to bind`);
42
+ return undefined;
43
+ }
44
+ // Inside the template, `$item` is the current row and paths are relative to
45
+ // it, which is exactly how A2UI resolves a template's bindings.
46
+ const template = ctx.inScope({ $item: '', $index: '' }, () => ctx.single(node.children));
47
+ if (template == null) {
48
+ ctx.note('unsupported', 'ForEach', 'the loop body had nothing to render');
49
+ return undefined;
50
+ }
51
+ return { component: 'Column', children: { path: bound.value.path, componentId: template } };
52
+ },
53
+ // A definition is a template, not content. The renderer draws nothing at the
54
+ // point of definition, and neither does this.
55
+ Define: () => undefined,
56
+ Use: (node, ctx) => {
57
+ const name = textOf(node, 'def', 'name');
58
+ if (name == null) {
59
+ ctx.note('unsupported', 'Use', 'no definition name');
60
+ return undefined;
61
+ }
62
+ const body = ctx.definition(name);
63
+ if (body == null) {
64
+ ctx.note('unsupported', 'Use', `no definition named "${name}" was declared`);
65
+ return undefined;
66
+ }
67
+ // Overrides are the definition's parameters. They are seeded into the data
68
+ // model and brought into scope by name, so a `{{ title }}` inside the body
69
+ // reads this call's value rather than whatever sits at the model root.
70
+ const overrides = node.overrides;
71
+ const scope = {};
72
+ if (overrides != null && typeof overrides === 'object' && !Array.isArray(overrides)) {
73
+ const root = ctx.bindData(`use_${name}`, overrides);
74
+ for (const key of Object.keys(overrides)) {
75
+ scope[key] = `${root}/${escapePointerToken(key)}`;
76
+ }
77
+ }
78
+ const slots = {
79
+ ...(isNodeMap(node.slots) ? node.slots : {}),
80
+ ...(Array.isArray(node.children) && node.children.length > 0 ? { default: node.children } : {}),
81
+ };
82
+ const inlined = ctx.expand(name, () => ctx.inScope(scope, () => ctx.withSlots(slots, () => ctx.single(body))));
83
+ if (inlined == null) {
84
+ ctx.note('unsupported', 'Use', `definition "${name}" rendered nothing`);
85
+ return undefined;
86
+ }
87
+ return { component: 'Column', children: [inlined] };
88
+ },
89
+ Slot: (node, ctx) => {
90
+ const name = textOf(node, 'name') ?? 'default';
91
+ // Slot content from the enclosing Use, or the slot's own fallback children.
92
+ const content = ctx.slotContent(name) ?? (Array.isArray(node.children) ? node.children : undefined);
93
+ const inlined = content != null ? ctx.single(content) : undefined;
94
+ if (inlined == null) {
95
+ ctx.note('unsupported', 'Slot', `slot "${name}" had neither content nor a fallback`);
96
+ return undefined;
97
+ }
98
+ return { component: 'Column', children: [inlined] };
99
+ },
100
+ };
101
+ for (const type of ['If', 'Elif', 'Else', 'Condition', 'Match', 'Case']) {
102
+ CONTROL_MAPPERS[type] = (node, ctx) => {
103
+ ctx.note('unsupported', node.type, 'A2UI has no declarative conditional; the agent re-sends updateComponents when the shape changes');
104
+ return undefined;
105
+ };
106
+ }
107
+ //# sourceMappingURL=control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../../src/a2ui/control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `$prefab` → A2UI emitter.
3
+ *
4
+ * Walks the nested `$prefab` component tree and produces A2UI's flat adjacency
5
+ * list, plus the surface data model. Three invariants drive the implementation:
6
+ *
7
+ * - **The root is named `root`.** A2UI requires exactly that id on the entry
8
+ * component, so it is reserved before traversal begins rather than renamed
9
+ * afterwards.
10
+ * - **Ids are allocated before children are emitted.** A mapper calls back
11
+ * into the context to emit its children, so the parent's slot is reserved
12
+ * first and filled in once the mapper returns. Nodes that turn out to be
13
+ * unmappable release their slot, which is why the components map is keyed
14
+ * by id rather than being a positional array.
15
+ * - **Emission is deterministic.** Ids are drawn from a counter in traversal
16
+ * order, so the same tree always produces byte-identical output and can be
17
+ * asserted on in tests and cached by hosts.
18
+ */
19
+ import type { PrefabWireFormat } from '../app.js';
20
+ import { type A2uiDiagnostic, type A2uiMessage } from './types.js';
21
+ export interface A2uiEmitOptions {
22
+ /**
23
+ * Surface id. Must be unique for the renderer's lifetime.
24
+ * @default 'prefab'
25
+ */
26
+ surfaceId?: string;
27
+ /**
28
+ * Catalog the surface's components are drawn from.
29
+ * @default the A2UI Basic catalog
30
+ */
31
+ catalogId?: string;
32
+ /**
33
+ * Split the output into `createSurface` + `updateComponents` +
34
+ * `updateDataModel` instead of inlining everything into `createSurface`.
35
+ * Streaming transports want the split so the renderer can paint early; a
36
+ * single stored payload does not. @default false
37
+ */
38
+ stream?: boolean;
39
+ /** Ask the renderer to echo the data model back on every event. @default false */
40
+ sendDataModel?: boolean;
41
+ /** Log degradations and dropped nodes at warn level. @default false */
42
+ warn?: boolean;
43
+ }
44
+ /** Emitted messages plus what the translation cost. */
45
+ export interface A2uiEmitResult {
46
+ messages: A2uiMessage[];
47
+ diagnostics: A2uiDiagnostic[];
48
+ }
49
+ /**
50
+ * Translate a `$prefab` wire payload into A2UI messages.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * const { messages, diagnostics } = emitA2UI(app.toJSON())
55
+ * if (diagnostics.length > 0) console.warn(diagnostics)
56
+ * ```
57
+ */
58
+ export declare function emitA2UI(wire: PrefabWireFormat, options?: A2uiEmitOptions): A2uiEmitResult;
59
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../src/a2ui/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAIjD,OAAO,EAML,KAAK,cAAc,EAInB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAA;AAInB,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,uEAAuE;IACvE,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB,WAAW,EAAE,cAAc,EAAE,CAAA;CAC9B;AAiWD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAG1F"}
@@ -0,0 +1,373 @@
1
+ /**
2
+ * `$prefab` → A2UI emitter.
3
+ *
4
+ * Walks the nested `$prefab` component tree and produces A2UI's flat adjacency
5
+ * list, plus the surface data model. Three invariants drive the implementation:
6
+ *
7
+ * - **The root is named `root`.** A2UI requires exactly that id on the entry
8
+ * component, so it is reserved before traversal begins rather than renamed
9
+ * afterwards.
10
+ * - **Ids are allocated before children are emitted.** A mapper calls back
11
+ * into the context to emit its children, so the parent's slot is reserved
12
+ * first and filled in once the mapper returns. Nodes that turn out to be
13
+ * unmappable release their slot, which is why the components map is keyed
14
+ * by id rather than being a positional array.
15
+ * - **Emission is deterministic.** Ids are drawn from a counter in traversal
16
+ * order, so the same tree always produces byte-identical output and can be
17
+ * asserted on in tests and cached by hosts.
18
+ */
19
+ import { createLogger } from '../core/logger.js';
20
+ import { dynamicString, escapePointerToken, toBinding } from './expr.js';
21
+ import { fallbackMapper, isConsumedByParent, mapperFor } from './catalog.js';
22
+ import { A2UI_BASIC_CATALOG, A2UI_ROOT_ID, A2UI_VERSION, } from './types.js';
23
+ const log = createLogger('a2ui');
24
+ /**
25
+ * The wrapper `toJSON()` puts around every view. It carries a CSS class and
26
+ * nothing else, so it is unwrapped rather than emitted as a pointless Column.
27
+ */
28
+ function unwrapAppRoot(view) {
29
+ const children = view.children;
30
+ if (view.type === 'Div'
31
+ && typeof view.cssClass === 'string'
32
+ && view.cssClass.startsWith('pf-app-root')
33
+ && Array.isArray(children)
34
+ && children.length === 1) {
35
+ return children[0];
36
+ }
37
+ return view;
38
+ }
39
+ /**
40
+ * Collect every `Define` in the tree.
41
+ *
42
+ * A pre-pass rather than collection during the walk, because prefab resolves a
43
+ * definition by name at render time and imposes no ordering: a `Use` may appear
44
+ * before the `Define` it refers to, and inside a different branch of the tree.
45
+ */
46
+ function collectDefinitions(node, into) {
47
+ if (node.type === 'Define') {
48
+ const name = typeof node.name === 'string' ? node.name : undefined;
49
+ if (name != null && Array.isArray(node.children))
50
+ into.set(name, node.children);
51
+ }
52
+ if (Array.isArray(node.children))
53
+ for (const child of node.children)
54
+ collectDefinitions(child, into);
55
+ }
56
+ class Emitter {
57
+ warn;
58
+ /** Insertion-ordered; `undefined` marks a reserved slot that was released. */
59
+ components = new Map();
60
+ // A Map rather than an object literal so a rolled-back subtree's seeded keys
61
+ // can be removed without a dynamic delete.
62
+ dataModel = new Map();
63
+ used = new Set([A2UI_ROOT_ID]);
64
+ diagnostics = [];
65
+ definitions = new Map();
66
+ counter = 0;
67
+ /** Names in force for binding, extended while inlining a template or a definition. */
68
+ scope = {};
69
+ /** Slot content from the nearest enclosing `Use`. */
70
+ slots = {};
71
+ /**
72
+ * Definitions currently being expanded, so a `Use` inside its own `Define`
73
+ * reports a cycle instead of recursing until the stack gives out.
74
+ */
75
+ expanding = new Set();
76
+ constructor(warn) {
77
+ this.warn = warn;
78
+ }
79
+ bind(value) {
80
+ return toBinding(value, this.scope);
81
+ }
82
+ dyn(value) {
83
+ return dynamicString(value, this.scope);
84
+ }
85
+ inScope(names, fn) {
86
+ const previous = this.scope;
87
+ this.scope = { ...previous, ...names };
88
+ try {
89
+ return fn();
90
+ }
91
+ finally {
92
+ this.scope = previous;
93
+ }
94
+ }
95
+ withSlots(slots, fn) {
96
+ const previous = this.slots;
97
+ this.slots = { ...previous, ...slots };
98
+ try {
99
+ return fn();
100
+ }
101
+ finally {
102
+ this.slots = previous;
103
+ }
104
+ }
105
+ slotContent(name) {
106
+ return this.slots[name];
107
+ }
108
+ definition(name) {
109
+ if (this.expanding.has(name)) {
110
+ this.note('unsupported', 'Use', `definition "${name}" uses itself; A2UI has no recursive template`);
111
+ return undefined;
112
+ }
113
+ return this.definitions.get(name);
114
+ }
115
+ /** Track expansion depth so `definition()` can detect a cycle. */
116
+ expand(name, fn) {
117
+ this.expanding.add(name);
118
+ try {
119
+ return fn();
120
+ }
121
+ finally {
122
+ this.expanding.delete(name);
123
+ }
124
+ }
125
+ note(kind, subject, detail) {
126
+ this.diagnostics.push({ kind, subject, detail });
127
+ if (this.warn)
128
+ log.warn(`${kind}: ${subject} — ${detail}`);
129
+ }
130
+ /** Allocate an id, honouring an author-supplied one when it is still free. */
131
+ allocate(node) {
132
+ const preferred = typeof node?.id === 'string' && node.id.length > 0 ? node.id : undefined;
133
+ if (preferred != null && !this.used.has(preferred)) {
134
+ this.used.add(preferred);
135
+ return preferred;
136
+ }
137
+ let id;
138
+ do {
139
+ this.counter += 1;
140
+ id = `c${this.counter}`;
141
+ } while (this.used.has(id));
142
+ this.used.add(id);
143
+ return id;
144
+ }
145
+ push(props) {
146
+ const id = this.allocate();
147
+ this.components.set(id, { id, ...props });
148
+ return id;
149
+ }
150
+ bindData(key, value) {
151
+ let name = key;
152
+ let n = 0;
153
+ while (this.dataModel.has(name)) {
154
+ n += 1;
155
+ name = `${key}${n}`;
156
+ }
157
+ this.dataModel.set(name, value);
158
+ return `/${escapePointerToken(name)}`;
159
+ }
160
+ child(node) {
161
+ return this.emit(node, false);
162
+ }
163
+ children(nodes) {
164
+ if (!Array.isArray(nodes))
165
+ return [];
166
+ const ids = [];
167
+ for (const node of nodes) {
168
+ if (node == null || typeof node !== 'object')
169
+ continue;
170
+ const id = this.emit(node, false);
171
+ if (id != null)
172
+ ids.push(id);
173
+ }
174
+ return ids;
175
+ }
176
+ single(nodes) {
177
+ const ids = this.children(nodes);
178
+ if (ids.length === 0)
179
+ return undefined;
180
+ if (ids.length === 1)
181
+ return ids[0];
182
+ // A2UI's single-child slots take one id, so several children need a wrapper.
183
+ return this.push({ component: 'Column', children: ids });
184
+ }
185
+ action(value, subject) {
186
+ if (value == null)
187
+ return undefined;
188
+ if (Array.isArray(value)) {
189
+ if (value.length === 0)
190
+ return undefined;
191
+ if (value.length > 1) {
192
+ this.note('action', subject, `${value.length} actions were bound; A2UI carries one, so the rest were dropped`);
193
+ }
194
+ return this.action(value[0], subject);
195
+ }
196
+ if (typeof value !== 'object')
197
+ return undefined;
198
+ const json = value;
199
+ const kind = typeof json.action === 'string' ? json.action : undefined;
200
+ if (kind == null)
201
+ return undefined;
202
+ switch (kind) {
203
+ // `callTool` is the spelling the shipped examples use and the renderer
204
+ // accepts both, so an emitter that knew only one silently downgraded every
205
+ // hand-written tool call into a generic agent event.
206
+ case 'toolCall':
207
+ case 'callTool': {
208
+ const tool = typeof json.tool === 'string' ? json.tool : undefined;
209
+ if (tool == null)
210
+ return undefined;
211
+ const context = this.eventContext(json.arguments, subject);
212
+ return { event: { name: tool, ...(context != null && { context }) } };
213
+ }
214
+ case 'sendMessage': {
215
+ const message = typeof json.message === 'string' ? json.message : '';
216
+ return { event: { name: 'sendMessage', context: { message } } };
217
+ }
218
+ case 'openLink': {
219
+ const url = typeof json.url === 'string' ? json.url : typeof json.href === 'string' ? json.href : undefined;
220
+ if (url == null)
221
+ return undefined;
222
+ return { functionCall: { call: 'openUrl', args: { url } } };
223
+ }
224
+ default: {
225
+ // Everything else mutates renderer state, which the Basic catalog has no
226
+ // function for. Reporting the intent to the agent keeps the control
227
+ // interactive instead of dropping it for want of an action.
228
+ this.note('action', subject, `"${kind}" has no renderer-side equivalent; emitted as an agent event`);
229
+ const { action: _kind, ...rest } = json;
230
+ const context = this.eventContext(rest, subject);
231
+ return { event: { name: kind, ...(context != null && { context }) } };
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * Convert a prefab action's argument bag into an A2UI event context.
237
+ *
238
+ * Values go through the same `{{ }}` conversion as component props, so a
239
+ * `CallTool('search', { arguments: { q: '{{ query }}' } })` sends the bound
240
+ * value rather than shipping the uninterpolated template to the agent.
241
+ */
242
+ eventContext(value, subject) {
243
+ if (value == null || typeof value !== 'object' || Array.isArray(value))
244
+ return undefined;
245
+ const context = {};
246
+ for (const [key, raw] of Object.entries(value)) {
247
+ if (typeof raw === 'number' || typeof raw === 'boolean' || raw === null) {
248
+ context[key] = raw;
249
+ continue;
250
+ }
251
+ if (typeof raw !== 'string') {
252
+ this.note('action', subject, `argument "${key}" is not a scalar and was dropped from the event context`);
253
+ continue;
254
+ }
255
+ const bound = toBinding(raw);
256
+ if (bound.kind === 'unbindable') {
257
+ this.note('action', subject, `argument "${key}" uses "${bound.expression}", which A2UI cannot bind; it was dropped`);
258
+ continue;
259
+ }
260
+ context[key] = bound.kind === 'binding' ? bound.value : bound.value;
261
+ }
262
+ return Object.keys(context).length > 0 ? context : undefined;
263
+ }
264
+ /**
265
+ * Undo everything emitted since a watermark.
266
+ *
267
+ * A mapper reads its children before deciding whether it can map at all — a
268
+ * `Dialog` emits its body, then finds it cannot build a trigger. Without this,
269
+ * those children stay in the adjacency list with nothing pointing at them,
270
+ * which is a payload the renderer rejects for unreachability. Dropping a node
271
+ * has to drop its whole subtree.
272
+ */
273
+ rollback(components, dataKeys) {
274
+ const keys = [...this.components.keys()];
275
+ for (let i = components; i < keys.length; i++) {
276
+ this.components.delete(keys[i]);
277
+ if (keys[i] !== A2UI_ROOT_ID)
278
+ this.used.delete(keys[i]);
279
+ }
280
+ const seeded = [...this.dataModel.keys()];
281
+ for (let i = dataKeys; i < seeded.length; i++)
282
+ this.dataModel.delete(seeded[i]);
283
+ }
284
+ /** Emit one subtree. Returns the allocated id, or `undefined` if it was dropped. */
285
+ emit(node, isRoot) {
286
+ if (typeof node.type !== 'string')
287
+ return undefined;
288
+ if (isConsumedByParent(node.type)) {
289
+ this.note('unsupported', node.type, 'only meaningful inside its parent; emitted standalone it has no meaning');
290
+ return undefined;
291
+ }
292
+ const componentMark = this.components.size;
293
+ const dataMark = this.dataModel.size;
294
+ const id = isRoot ? A2UI_ROOT_ID : this.allocate(node);
295
+ // Reserve the slot before the mapper runs, so children emitted during
296
+ // mapping cannot claim this id.
297
+ this.components.set(id, undefined);
298
+ const mapper = mapperFor(node.type) ?? fallbackMapper;
299
+ const props = mapper(node, this);
300
+ if (props == null) {
301
+ this.rollback(componentMark, dataMark);
302
+ return undefined;
303
+ }
304
+ this.components.set(id, { id, ...props });
305
+ return id;
306
+ }
307
+ finish(wire, options) {
308
+ const surfaceId = options.surfaceId ?? 'prefab';
309
+ // Envelope-level defs first, then any `Define` in the tree, which wins on a
310
+ // name clash for the same reason it does in the renderer: it is nearer.
311
+ for (const [name, body] of Object.entries(wire.defs ?? {}))
312
+ this.definitions.set(name, [body]);
313
+ collectDefinitions(wire.view, this.definitions);
314
+ const rootId = this.emit(unwrapAppRoot(wire.view), true);
315
+ if (rootId == null) {
316
+ this.note('unsupported', 'view', 'nothing in the view could be expressed in A2UI; the surface is empty');
317
+ }
318
+ const components = [];
319
+ for (const c of this.components.values())
320
+ if (c != null)
321
+ components.push(c);
322
+ // prefab state and any literals seeded during mapping share one data model.
323
+ // State wins on a collision, since seeded keys are generated and state keys
324
+ // are author-chosen.
325
+ const dataModel = { ...Object.fromEntries(this.dataModel), ...(wire.state ?? {}) };
326
+ const hasData = Object.keys(dataModel).length > 0;
327
+ const messages = [];
328
+ const catalogId = options.catalogId ?? A2UI_BASIC_CATALOG;
329
+ if (options.stream === true) {
330
+ messages.push({
331
+ version: A2UI_VERSION,
332
+ createSurface: {
333
+ surfaceId,
334
+ catalogId,
335
+ ...(options.sendDataModel === true && { sendDataModel: true }),
336
+ },
337
+ });
338
+ if (components.length > 0) {
339
+ messages.push({ version: A2UI_VERSION, updateComponents: { surfaceId, components } });
340
+ }
341
+ if (hasData) {
342
+ messages.push({ version: A2UI_VERSION, updateDataModel: { surfaceId, value: dataModel } });
343
+ }
344
+ }
345
+ else {
346
+ messages.push({
347
+ version: A2UI_VERSION,
348
+ createSurface: {
349
+ surfaceId,
350
+ catalogId,
351
+ ...(options.sendDataModel === true && { sendDataModel: true }),
352
+ ...(components.length > 0 && { components }),
353
+ ...(hasData && { dataModel }),
354
+ },
355
+ });
356
+ }
357
+ return { messages, diagnostics: this.diagnostics };
358
+ }
359
+ }
360
+ /**
361
+ * Translate a `$prefab` wire payload into A2UI messages.
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * const { messages, diagnostics } = emitA2UI(app.toJSON())
366
+ * if (diagnostics.length > 0) console.warn(diagnostics)
367
+ * ```
368
+ */
369
+ export function emitA2UI(wire, options) {
370
+ const opts = options ?? {};
371
+ return new Emitter(opts.warn === true).finish(wire, opts);
372
+ }
373
+ //# sourceMappingURL=emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/a2ui/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,SAAS,EAAsC,MAAM,WAAW,CAAA;AAC5G,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAoC,MAAM,cAAc,CAAA;AAC9G,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,YAAY,GAQb,MAAM,YAAY,CAAA;AAEnB,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;AAgChC;;;GAGG;AACH,SAAS,aAAa,CAAC,IAAmB;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;IAC9B,IACE,IAAI,CAAC,IAAI,KAAK,KAAK;WAChB,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ;WACjC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC;WACvC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;WACvB,QAAQ,CAAC,MAAM,KAAK,CAAC,EACxB,CAAC;QACD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,IAAmB,EAAE,IAAkC;IACjF,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;QAClE,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IACjF,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;AACtG,CAAC;AAED,MAAM,OAAO;IAuBkB;IAtB7B,8EAA8E;IAC7D,UAAU,GAAG,IAAI,GAAG,EAAqC,CAAA;IAC1E,6EAA6E;IAC7E,2CAA2C;IAC1B,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAA;IACtC,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,YAAY,CAAC,CAAC,CAAA;IACtC,WAAW,GAAqB,EAAE,CAAA;IAClC,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAA;IACzD,OAAO,GAAG,CAAC,CAAA;IAEnB,sFAAsF;IAC9E,KAAK,GAAc,EAAE,CAAA;IAE7B,qDAAqD;IAC7C,KAAK,GAAoC,EAAE,CAAA;IAEnD;;;OAGG;IACc,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IAE9C,YAA6B,IAAa;QAAb,SAAI,GAAJ,IAAI,CAAS;IAAG,CAAC;IAE9C,IAAI,CAAC,KAAa;QAChB,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;IACrC,CAAC;IAED,GAAG,CAAC,KAAyB;QAC3B,OAAO,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC;IAED,OAAO,CAAI,KAAgB,EAAE,EAAW;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAA;QAC3B,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAA;QACtC,IAAI,CAAC;YACH,OAAO,EAAE,EAAE,CAAA;QACb,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;QACvB,CAAC;IACH,CAAC;IAED,SAAS,CAAI,KAAsC,EAAE,EAAW;QAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAA;QAC3B,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAA;QACtC,IAAI,CAAC;YACH,OAAO,EAAE,EAAE,CAAA;QACb,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAA;QACvB,CAAC;IACH,CAAC;IAED,WAAW,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,eAAe,IAAI,+CAA+C,CAAC,CAAA;YACnG,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC;IAED,kEAAkE;IAClE,MAAM,CAAI,IAAY,EAAE,EAAW;QACjC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACxB,IAAI,CAAC;YACH,OAAO,EAAE,EAAE,CAAA;QACb,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAwB,EAAE,OAAe,EAAE,MAAc;QAC5D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;QAChD,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,OAAO,MAAM,MAAM,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,8EAA8E;IACtE,QAAQ,CAAC,IAAoB;QACnC,MAAM,SAAS,GAAG,OAAO,IAAI,EAAE,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAC1F,IAAI,SAAS,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;YACxB,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,IAAI,EAAU,CAAA;QACd,GAAG,CAAC;YACF,IAAI,CAAC,OAAO,IAAI,CAAC,CAAA;YACjB,EAAE,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAA;QACzB,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,CAAC,KAAgB;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAA;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;QACzC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,QAAQ,CAAC,GAAW,EAAE,KAAc;QAClC,IAAI,IAAI,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,GAAG,CAAC,CAAA;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,CAAC,IAAI,CAAC,CAAA;YACN,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,CAAA;QACrB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC/B,OAAO,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,IAAmB;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC/B,CAAC;IAED,QAAQ,CAAC,KAAc;QACrB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QACpC,MAAM,GAAG,GAAa,EAAE,CAAA;QACxB,KAAK,MAAM,IAAI,IAAI,KAAkB,EAAE,CAAC;YACtC,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;gBAAE,SAAQ;YACtD,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAqB,EAAE,KAAK,CAAC,CAAA;YAClD,IAAI,EAAE,IAAI,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC9B,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,MAAM,CAAC,KAAc;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAChC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACtC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAA;QACnC,6EAA6E;QAC7E,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,MAAM,CAAC,KAAc,EAAE,OAAe;QACpC,IAAI,KAAK,IAAI,IAAI;YAAE,OAAO,SAAS,CAAA;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAA;YACxC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,MAAM,iEAAiE,CAAC,CAAA;YAChH,CAAC;YACD,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;QACvC,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAA;QAE/C,MAAM,IAAI,GAAG,KAAgC,CAAA;QAC7C,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;QACtE,IAAI,IAAI,IAAI,IAAI;YAAE,OAAO,SAAS,CAAA;QAElC,QAAQ,IAAI,EAAE,CAAC;YACb,uEAAuE;YACvE,2EAA2E;YAC3E,qDAAqD;YACrD,KAAK,UAAU,CAAC;YAChB,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;gBAClE,IAAI,IAAI,IAAI,IAAI;oBAAE,OAAO,SAAS,CAAA;gBAClC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;gBAC1D,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAA;YACvE,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;gBACpE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;YACjE,CAAC;YACD,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;gBAC3G,IAAI,GAAG,IAAI,IAAI;oBAAE,OAAO,SAAS,CAAA;gBACjC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;YAC7D,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACR,yEAAyE;gBACzE,oEAAoE;gBACpE,4DAA4D;gBAC5D,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,IAAI,8DAA8D,CAAC,CAAA;gBACpG,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;gBACvC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;gBAChD,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,IAAI,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAA;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACK,YAAY,CAAC,KAAc,EAAE,OAAe;QAClD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACxF,MAAM,OAAO,GAAqC,EAAE,CAAA;QACpD,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YAC1E,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACxE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;gBAClB,SAAQ;YACV,CAAC;YACD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,GAAG,0DAA0D,CAAC,CAAA;gBACxG,SAAQ;YACV,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAA;YAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,GAAG,WAAW,KAAK,CAAC,UAAU,2CAA2C,CAAC,CAAA;gBACpH,SAAQ;YACV,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;QACrE,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,CAAC;IAED;;;;;;;;OAQG;IACK,QAAQ,CAAC,UAAkB,EAAE,QAAgB;QACnD,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAA;QACxC,KAAK,IAAI,CAAC,GAAG,UAAU,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,YAAY;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAA;QACzC,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACjF,CAAC;IAED,oFAAoF;IACpF,IAAI,CAAC,IAAmB,EAAE,MAAe;QACvC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAA;QAEnD,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,EAAE,yEAAyE,CAAC,CAAA;YAC9G,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAA;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAA;QAEpC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACtD,sEAAsE;QACtE,gCAAgC;QAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAA;QAElC,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAA;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;QAEhC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAA;YACtC,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;QACzC,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,CAAC,IAAsB,EAAE,OAAwB;QACrD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAA;QAE/C,4EAA4E;QAC5E,wEAAwE;QACxE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;YAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9F,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAE/C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA;QAExD,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,sEAAsE,CAAC,CAAA;QAC1G,CAAC;QAED,MAAM,UAAU,GAAoB,EAAE,CAAA;QACtC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE;YAAE,IAAI,CAAC,IAAI,IAAI;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAE3E,4EAA4E;QAC5E,4EAA4E;QAC5E,qBAAqB;QACrB,MAAM,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAA;QAClF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA;QAEjD,MAAM,QAAQ,GAAkB,EAAE,CAAA;QAClC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAA;QAEzD,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,YAAY;gBACrB,aAAa,EAAE;oBACb,SAAS;oBACT,SAAS;oBACT,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;iBAC/D;aACF,CAAC,CAAA;YACF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;YACvF,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAA;YAC5F,CAAC;QACH,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,YAAY;gBACrB,aAAa,EAAE;oBACb,SAAS;oBACT,SAAS;oBACT,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,IAAI,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;oBAC9D,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC;oBAC5C,GAAG,CAAC,OAAO,IAAI,EAAE,SAAS,EAAE,CAAC;iBAC9B;aACF,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAA;IACpD,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAsB,EAAE,OAAyB;IACxE,MAAM,IAAI,GAAG,OAAO,IAAI,EAAE,CAAA;IAC1B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * `{{ }}` template → A2UI data binding.
3
+ *
4
+ * `$prefab` interpolates arbitrary expressions client-side. A2UI binds values
5
+ * through JSON Pointers and, for text that mixes literals with values, through
6
+ * the `formatString` catalog function. Between them those cover more than a
7
+ * plain-path conversion would suggest:
8
+ *
9
+ * - `{{ user.name }}` → `{ path: '/user/name' }`
10
+ * - `Hi {{ name }}!` → `{ call: 'formatString', args: { value: 'Hi ${/name}!' } }`
11
+ * - `{{ p | currency:'EUR' }}` → `{ call: 'formatCurrency', args: { … } }`
12
+ * - `{{ count + 1 }}` → nothing; A2UI has no expression language
13
+ *
14
+ * What does not survive is arithmetic, conditionals, and the pipes that
15
+ * transform data rather than format it (see `./pipes.ts`). Those are reported as
16
+ * `expression` diagnostics rather than emitted as a binding that would render an
17
+ * empty string in someone's renderer.
18
+ *
19
+ * ## Scopes
20
+ *
21
+ * A binding is resolved against a {@link BindScope}, which is how names local to
22
+ * a region become pointers. Inside a list template A2UI resolves relative paths
23
+ * against the current item, so prefab's `$item` maps to the empty prefix; inside
24
+ * an inlined definition, a `Use`'s overrides map to wherever the emitter seeded
25
+ * them. Without this, a name that means something local would silently bind to
26
+ * the root of the data model and read whatever happened to be there.
27
+ */
28
+ import type { A2uiDataBinding, A2uiDynamicString, A2uiFunctionCall } from './types.js';
29
+ /**
30
+ * Names local to a region, mapped to the pointer they resolve to.
31
+ *
32
+ * An empty-string value means "relative to the current template item", which is
33
+ * how A2UI addresses fields inside a list template.
34
+ */
35
+ export type BindScope = Record<string, string>;
36
+ /**
37
+ * Escape one JSON Pointer reference token (RFC 6901 §3).
38
+ *
39
+ * `~` must be escaped before `/`, otherwise the `~1` produced for a slash gets
40
+ * re-escaped into `~01` on the second pass.
41
+ */
42
+ export declare function escapePointerToken(token: string): string;
43
+ /** Build a JSON Pointer from already-split path segments. */
44
+ export declare function toJsonPointer(segments: string[]): string;
45
+ /** The outcome of converting one prefab value into an A2UI dynamic value. */
46
+ export type BindingResult =
47
+ /** A literal with no template in it. */
48
+ {
49
+ kind: 'literal';
50
+ value: string;
51
+ }
52
+ /** A `{{ path }}` that mapped cleanly onto a JSON Pointer. */
53
+ | {
54
+ kind: 'binding';
55
+ value: A2uiDataBinding;
56
+ }
57
+ /**
58
+ * A value produced by a catalog function: interpolated text, or a pipe that
59
+ * maps onto one of A2UI's formatters. `note` carries anything the mapping
60
+ * cost, for the caller to report.
61
+ */
62
+ | {
63
+ kind: 'format';
64
+ value: A2uiFunctionCall;
65
+ note?: string;
66
+ }
67
+ /** The loop index, which A2UI exposes as a system function. */
68
+ | {
69
+ kind: 'index';
70
+ value: A2uiFunctionCall;
71
+ }
72
+ /** A template too rich for A2UI. `expression` is the source, for diagnostics. */
73
+ | {
74
+ kind: 'unbindable';
75
+ expression: string;
76
+ };
77
+ /**
78
+ * Convert a prefab string value into an A2UI dynamic value.
79
+ *
80
+ * A whole-string template over a plain path becomes a binding, one over a
81
+ * formatting pipe becomes a catalog-function call, mixed text becomes a
82
+ * `formatString` call, a string with no template passes through, and anything
83
+ * else is unbindable.
84
+ */
85
+ export declare function toBinding(value: string, scope?: BindScope): BindingResult;
86
+ /**
87
+ * Resolve a value to an `A2uiDynamicString`, or `undefined` when it cannot be
88
+ * expressed. Callers pair this with a diagnostic when it returns `undefined`.
89
+ */
90
+ export declare function dynamicString(value: string | undefined, scope?: BindScope): A2uiDynamicString | undefined;
91
+ //# sourceMappingURL=expr.d.ts.map