@assistant-ui/react-generative-ui 0.0.20 → 0.0.22
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/LICENSE +1 -1
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.client.js +30 -13
- package/dist/JSONGenerativeUI.client.js.map +1 -1
- package/dist/RadioGroupScope.d.ts +6 -0
- package/dist/RadioGroupScope.d.ts.map +1 -0
- package/dist/RadioGroupScope.js +25 -0
- package/dist/RadioGroupScope.js.map +1 -0
- package/dist/a2ui/BindingContext.d.ts +11 -0
- package/dist/a2ui/BindingContext.d.ts.map +1 -0
- package/dist/a2ui/BindingContext.js +12 -0
- package/dist/a2ui/BindingContext.js.map +1 -0
- package/dist/a2ui/PresentRenderer.d.ts +11 -0
- package/dist/a2ui/PresentRenderer.d.ts.map +1 -0
- package/dist/a2ui/PresentRenderer.js +39 -0
- package/dist/a2ui/PresentRenderer.js.map +1 -0
- package/dist/a2ui/convert.d.ts +6 -0
- package/dist/a2ui/convert.d.ts.map +1 -1
- package/dist/a2ui/convert.js +369 -87
- package/dist/a2ui/convert.js.map +1 -1
- package/dist/a2ui/dataModel.d.ts +9 -0
- package/dist/a2ui/dataModel.d.ts.map +1 -0
- package/dist/a2ui/dataModel.js +44 -0
- package/dist/a2ui/dataModel.js.map +1 -0
- package/dist/a2ui/reducer.d.ts +5 -0
- package/dist/a2ui/reducer.d.ts.map +1 -1
- package/dist/a2ui/reducer.js +3 -3
- package/dist/a2ui/reducer.js.map +1 -1
- package/dist/a2ui/types.d.ts +8 -2
- package/dist/a2ui/types.d.ts.map +1 -1
- package/dist/a2ui/types.js.map +1 -1
- package/dist/a2ui/valueFunctions.d.ts +16 -0
- package/dist/a2ui/valueFunctions.d.ts.map +1 -0
- package/dist/a2ui/valueFunctions.js +332 -0
- package/dist/a2ui/valueFunctions.js.map +1 -0
- package/dist/actionRegistry.d.ts +1 -1
- package/dist/actionRegistry.js.map +1 -1
- package/dist/answeredValues.d.ts +16 -0
- package/dist/answeredValues.d.ts.map +1 -0
- package/dist/answeredValues.js +37 -0
- package/dist/answeredValues.js.map +1 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/fieldReferences.d.ts +9 -0
- package/dist/fieldReferences.d.ts.map +1 -0
- package/dist/fieldReferences.js +53 -0
- package/dist/fieldReferences.js.map +1 -0
- package/dist/generativeUIToJSX.js +3 -3
- package/dist/generativeUIToJSX.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.server.js +2 -2
- package/dist/index.shared.js +2 -2
- package/dist/ir.d.ts +1 -1
- package/dist/ir.js.map +1 -1
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/renderGenerativeUI.js +12 -1
- package/dist/renderGenerativeUI.js.map +1 -1
- package/dist/slack/constants.d.ts +2 -0
- package/dist/slack/constants.d.ts.map +1 -1
- package/dist/slack/constants.js +3 -1
- package/dist/slack/constants.js.map +1 -1
- package/dist/slack/decodeBlockAction.d.ts +3 -1
- package/dist/slack/decodeBlockAction.d.ts.map +1 -1
- package/dist/slack/decodeBlockAction.js +58 -7
- package/dist/slack/decodeBlockAction.js.map +1 -1
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
- package/dist/slack/fromSlackBlocks.js +20 -3
- package/dist/slack/fromSlackBlocks.js.map +1 -1
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.js +187 -19
- package/dist/slack/toSlackBlocks.js.map +1 -1
- package/dist/slack/types.d.ts +4 -0
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/teams/constants.d.ts +1 -1
- package/dist/teams/constants.d.ts.map +1 -1
- package/dist/teams/constants.js +1 -1
- package/dist/teams/constants.js.map +1 -1
- package/dist/teams/decodeSubmitData.d.ts +4 -0
- package/dist/teams/decodeSubmitData.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.js +6 -1
- package/dist/teams/decodeSubmitData.js.map +1 -1
- package/dist/teams/toAdaptiveCard.d.ts +5 -4
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.js +56 -17
- package/dist/teams/toAdaptiveCard.js.map +1 -1
- package/dist/teams/types.d.ts +4 -1
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +9 -2
- package/dist/vocabulary/alert.d.ts.map +1 -1
- package/dist/vocabulary/alert.js +116 -19
- package/dist/vocabulary/alert.js.map +1 -1
- package/dist/vocabulary/collectFormValues.d.ts +2 -1
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
- package/dist/vocabulary/collectFormValues.js +10 -3
- package/dist/vocabulary/collectFormValues.js.map +1 -1
- package/dist/vocabulary/data.d.ts +22 -5
- package/dist/vocabulary/data.d.ts.map +1 -1
- package/dist/vocabulary/data.js +278 -83
- package/dist/vocabulary/data.js.map +1 -1
- package/dist/vocabulary/dispatch.d.ts +3 -2
- package/dist/vocabulary/dispatch.d.ts.map +1 -1
- package/dist/vocabulary/dispatch.js +33 -4
- package/dist/vocabulary/dispatch.js.map +1 -1
- package/dist/vocabulary/fact.d.ts +8 -1
- package/dist/vocabulary/fact.d.ts.map +1 -1
- package/dist/vocabulary/fact.js +37 -11
- package/dist/vocabulary/fact.js.map +1 -1
- package/dist/vocabulary/form.d.ts.map +1 -1
- package/dist/vocabulary/form.js +3 -3
- package/dist/vocabulary/form.js.map +1 -1
- package/dist/vocabulary/formatValue.d.ts +7 -0
- package/dist/vocabulary/formatValue.d.ts.map +1 -0
- package/dist/vocabulary/formatValue.js +76 -0
- package/dist/vocabulary/formatValue.js.map +1 -0
- package/dist/vocabulary/icon.d.ts +1 -1
- package/dist/vocabulary/interactive.d.ts +137 -8
- package/dist/vocabulary/interactive.d.ts.map +1 -1
- package/dist/vocabulary/interactive.js +404 -103
- package/dist/vocabulary/interactive.js.map +1 -1
- package/dist/vocabulary/layout.d.ts.map +1 -1
- package/dist/vocabulary/layout.js +4 -4
- package/dist/vocabulary/layout.js.map +1 -1
- package/dist/vocabulary/list.js +2 -2
- package/dist/vocabulary/list.js.map +1 -1
- package/dist/vocabulary/text.d.ts +1 -1
- package/package.json +6 -3
- package/src/JSONGenerativeUI.client.tsx +84 -40
- package/src/JSONGenerativeUI.test.tsx +964 -68
- package/src/RadioGroupScope.server.test.tsx +24 -0
- package/src/RadioGroupScope.tsx +34 -0
- package/src/a2ui/BindingContext.ts +26 -0
- package/src/a2ui/PresentRenderer.tsx +83 -0
- package/src/a2ui/convert.test.ts +1982 -145
- package/src/a2ui/convert.ts +677 -137
- package/src/a2ui/dataModel.ts +69 -0
- package/src/a2ui/reducer.test.ts +35 -0
- package/src/a2ui/reducer.ts +5 -4
- package/src/a2ui/types.ts +9 -2
- package/src/a2ui/valueFunctions.test.ts +271 -0
- package/src/a2ui/valueFunctions.ts +523 -0
- package/src/actionRegistry.ts +1 -1
- package/src/answeredValues.test.ts +33 -0
- package/src/answeredValues.tsx +70 -0
- package/src/constants.ts +4 -0
- package/src/fieldReferences.test.ts +66 -0
- package/src/fieldReferences.ts +83 -0
- package/src/generativeUIToJSX.test.ts +18 -0
- package/src/generativeUIToJSX.ts +4 -6
- package/src/index.server.test.ts +106 -0
- package/src/ir.ts +1 -1
- package/src/renderGenerativeUI.test.tsx +14 -5
- package/src/renderGenerativeUI.tsx +30 -1
- package/src/slack/a2uiSlack.test.ts +198 -0
- package/src/slack/constants.ts +3 -0
- package/src/slack/decodeBlockAction.test.ts +98 -0
- package/src/slack/decodeBlockAction.ts +110 -17
- package/src/slack/fromSlackBlocks.test.ts +222 -3
- package/src/slack/fromSlackBlocks.ts +53 -2
- package/src/slack/toSlackBlocks.test.ts +682 -3
- package/src/slack/toSlackBlocks.ts +374 -23
- package/src/slack/types.ts +4 -0
- package/src/teams/constants.ts +1 -1
- package/src/teams/decodeSubmitData.test.ts +33 -0
- package/src/teams/decodeSubmitData.ts +9 -1
- package/src/teams/toAdaptiveCard.test.ts +219 -0
- package/src/teams/toAdaptiveCard.ts +93 -19
- package/src/teams/types.ts +4 -1
- package/src/vocabulary/alert.test.tsx +288 -7
- package/src/vocabulary/alert.tsx +168 -26
- package/src/vocabulary/collectFormValues.test.ts +28 -1
- package/src/vocabulary/collectFormValues.ts +25 -5
- package/src/vocabulary/data.test.tsx +248 -6
- package/src/vocabulary/data.tsx +398 -100
- package/src/vocabulary/dispatch.ts +63 -2
- package/src/vocabulary/fact.test.tsx +67 -0
- package/src/vocabulary/fact.tsx +40 -9
- package/src/vocabulary/form.tsx +7 -2
- package/src/vocabulary/formatValue.test.ts +72 -0
- package/src/vocabulary/formatValue.ts +127 -0
- package/src/vocabulary/index.test.ts +2 -0
- package/src/vocabulary/interactive.dispatch.test.tsx +167 -79
- package/src/vocabulary/interactive.dom.test.tsx +1699 -0
- package/src/vocabulary/interactive.test.tsx +60 -4
- package/src/vocabulary/interactive.tsx +770 -151
- package/src/vocabulary/layout.test.tsx +6 -4
- package/src/vocabulary/layout.tsx +13 -2
- package/src/vocabulary/list.tsx +2 -2
package/dist/a2ui/convert.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { ICON_NAMES } from "../ir.js";
|
|
2
2
|
import { A2UI_SURFACE_ID } from "./types.js";
|
|
3
|
+
import "./reducer.js";
|
|
4
|
+
import { decodePointer, resolvePointer } from "./dataModel.js";
|
|
5
|
+
import { evaluateA2uiValueFunction } from "./valueFunctions.js";
|
|
3
6
|
//#region src/a2ui/convert.ts
|
|
4
7
|
const DEPTH_CAP = 32;
|
|
5
8
|
const TEMPLATE_ITEM_CAP = 100;
|
|
6
9
|
const NODE_BUDGET = 5e3;
|
|
10
|
+
const EVALUATION_BUDGET = 2e4;
|
|
7
11
|
const SUPPORTED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
8
12
|
"Text",
|
|
9
13
|
"Image",
|
|
@@ -17,7 +21,13 @@ const SUPPORTED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
17
21
|
"TextField",
|
|
18
22
|
"CheckBox",
|
|
19
23
|
"ChoicePicker",
|
|
20
|
-
"DateTimeInput"
|
|
24
|
+
"DateTimeInput",
|
|
25
|
+
"Slider"
|
|
26
|
+
]);
|
|
27
|
+
const CHILD_LIST_COMPONENTS = /* @__PURE__ */ new Set([
|
|
28
|
+
"Row",
|
|
29
|
+
"Column",
|
|
30
|
+
"List"
|
|
21
31
|
]);
|
|
22
32
|
const ICON_NAME_SET = new Set(ICON_NAMES);
|
|
23
33
|
const ICON_SIZE_SET = /* @__PURE__ */ new Set([
|
|
@@ -40,44 +50,85 @@ const setOwnProperty = (target, key, value) => {
|
|
|
40
50
|
});
|
|
41
51
|
else target[key] = value;
|
|
42
52
|
};
|
|
53
|
+
const FUNCTION_CALL_KEYS = /* @__PURE__ */ new Set([
|
|
54
|
+
"call",
|
|
55
|
+
"args",
|
|
56
|
+
"returnType",
|
|
57
|
+
"catalogId"
|
|
58
|
+
]);
|
|
59
|
+
const isFunctionCall = (value) => isPlainObject(value) && typeof value["call"] === "string" && (value["args"] === void 0 || isPlainObject(value["args"])) && Object.keys(value).every((key) => FUNCTION_CALL_KEYS.has(key));
|
|
43
60
|
const isBinding = (value) => isPlainObject(value) && Object.keys(value).length === 1 && typeof value["path"] === "string";
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
61
|
+
const childTemplateOf = (children) => {
|
|
62
|
+
const template = isPlainObject(children) && Object.keys(children).length === 1 && isPlainObject(children["template"]) ? children["template"] : children;
|
|
63
|
+
return isPlainObject(template) && Object.keys(template).length === 2 && typeof template["componentId"] === "string" && typeof template["path"] === "string" ? {
|
|
64
|
+
componentId: template["componentId"],
|
|
65
|
+
path: template["path"]
|
|
66
|
+
} : void 0;
|
|
49
67
|
};
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
const bindingPath = (value) => isBinding(value) ? value.path : void 0;
|
|
69
|
+
const pointerIn = (scope, path) => (path.startsWith("/") ? "" : scope.path) + decodePointer(path).map((segment) => `/${segment.replaceAll("~", "~0").replaceAll("/", "~1")}`).join("");
|
|
70
|
+
const setIn = (value, segments, leaf) => {
|
|
71
|
+
const [head, ...rest] = segments;
|
|
72
|
+
if (head === void 0) return leaf;
|
|
73
|
+
if (/^(0|[1-9]\d*)$/.test(head) && (Array.isArray(value) || value === void 0 || value === null)) {
|
|
74
|
+
const list = Array.isArray(value) ? value : [];
|
|
75
|
+
const index = Number(head);
|
|
76
|
+
if (index >= list.length && index > 1e4) return value;
|
|
77
|
+
const copy = [...list];
|
|
78
|
+
copy[index] = setIn(copy[index], rest, leaf);
|
|
79
|
+
return copy;
|
|
62
80
|
}
|
|
63
|
-
|
|
81
|
+
const copy = isRecord(value) ? { ...value } : {};
|
|
82
|
+
setOwnProperty(copy, head, setIn(Object.hasOwn(copy, head) ? copy[head] : void 0, rest, leaf));
|
|
83
|
+
return copy;
|
|
64
84
|
};
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
const withFieldReferences = (value, pointer, fields) => {
|
|
86
|
+
if (fields.has(pointer)) return fields.get(pointer);
|
|
87
|
+
let result = value;
|
|
88
|
+
for (const [name, field] of fields) if (name.startsWith(`${pointer}/`)) result = setIn(result, decodePointer(name.slice(pointer.length)), field);
|
|
89
|
+
return result;
|
|
69
90
|
};
|
|
70
|
-
const
|
|
71
|
-
if (isBinding(value)) return resolvePointer(source, value.path);
|
|
72
|
-
if (Array.isArray(value)) return value.map((entry) => materialize(entry, source)).filter((entry) => entry !== void 0);
|
|
73
|
-
if (!isPlainObject(value)) return value;
|
|
91
|
+
const materializeEntries = (value, source, context, evaluate, depth, positional = false) => {
|
|
74
92
|
const result = {};
|
|
75
93
|
for (const [key, entry] of Object.entries(value)) {
|
|
76
|
-
const resolved =
|
|
94
|
+
const resolved = key === "functionCall" && isFunctionCall(entry) ? {
|
|
95
|
+
...entry,
|
|
96
|
+
...entry.args !== void 0 ? { args: materializeEntries(entry.args, source, context, evaluate, depth, true) } : {}
|
|
97
|
+
} : materialize(entry, source, context, evaluate, depth, positional);
|
|
77
98
|
if (resolved !== void 0) setOwnProperty(result, key, resolved);
|
|
78
99
|
}
|
|
79
100
|
return result;
|
|
80
101
|
};
|
|
102
|
+
function materialize(value, source, context, evaluate = true, depth = 0, positional = false) {
|
|
103
|
+
if (isBinding(value)) {
|
|
104
|
+
const pointer = pointerIn({
|
|
105
|
+
data: source,
|
|
106
|
+
path: context.scopePath
|
|
107
|
+
}, value.path);
|
|
108
|
+
const resolved = resolvePointer(context.surface.dataModel, pointer);
|
|
109
|
+
context.dependencies?.set(pointer, resolved);
|
|
110
|
+
return resolved;
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(value)) {
|
|
113
|
+
const entries = value.map((entry) => materialize(entry, source, context, evaluate, depth, positional));
|
|
114
|
+
return positional ? entries : entries.filter((entry) => entry !== void 0);
|
|
115
|
+
}
|
|
116
|
+
if (!isPlainObject(value)) return value;
|
|
117
|
+
if (!evaluate || !isFunctionCall(value)) return materializeEntries(value, source, context, evaluate, depth, positional);
|
|
118
|
+
if (!spendEvaluation(context)) return void 0;
|
|
119
|
+
if (depth >= DEPTH_CAP) {
|
|
120
|
+
if (!context.functionDepthWarned) {
|
|
121
|
+
context.warnings.push(`A2UI function nesting cap of ${DEPTH_CAP} was reached.`);
|
|
122
|
+
context.functionDepthWarned = true;
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
return evaluateA2uiValueFunction(value.call, materializeEntries(value.args ?? {}, source, context, true, depth + 1, true), {
|
|
127
|
+
resolve: (part) => spendEvaluation(context) ? materialize(part, source, context, true, depth + 1) : void 0,
|
|
128
|
+
warn: (message) => context.warnings.push(message),
|
|
129
|
+
templates: context.templates
|
|
130
|
+
});
|
|
131
|
+
}
|
|
81
132
|
const firstDefined = (props, keys) => {
|
|
82
133
|
for (const key of keys) if (props[key] !== void 0) return props[key];
|
|
83
134
|
};
|
|
@@ -86,6 +137,74 @@ const stringProp = (props, keys) => {
|
|
|
86
137
|
return typeof value === "string" ? value : void 0;
|
|
87
138
|
};
|
|
88
139
|
const sourceSurfaceId = (surface) => surface[A2UI_SURFACE_ID] ?? "";
|
|
140
|
+
const BOUND_KEYS = [
|
|
141
|
+
"text",
|
|
142
|
+
"value",
|
|
143
|
+
"binding"
|
|
144
|
+
];
|
|
145
|
+
const INPUT_COMPONENTS = /* @__PURE__ */ new Set([
|
|
146
|
+
"TextField",
|
|
147
|
+
"CheckBox",
|
|
148
|
+
"ChoicePicker",
|
|
149
|
+
"DateTimeInput",
|
|
150
|
+
"Slider"
|
|
151
|
+
]);
|
|
152
|
+
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
153
|
+
const finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
154
|
+
const decimalPlaces = (value) => {
|
|
155
|
+
const [mantissa = "", exponent = "0"] = String(value).split("e");
|
|
156
|
+
return Math.max(0, (mantissa.split(".")[1]?.length ?? 0) - Number(exponent));
|
|
157
|
+
};
|
|
158
|
+
const sliderStep = (min, max, value, steps) => {
|
|
159
|
+
if (max <= min) return void 0;
|
|
160
|
+
if (typeof steps === "number" && Number.isInteger(steps) && steps >= 1) return (max - min) / steps;
|
|
161
|
+
const precision = Math.max(decimalPlaces(min), value === void 0 ? 0 : decimalPlaces(value));
|
|
162
|
+
return Math.min(10 ** Math.floor(Math.log10((max - min) / 100)), 10 ** -precision);
|
|
163
|
+
};
|
|
164
|
+
const recordBindings = (node, props, mapped, scope, context) => {
|
|
165
|
+
const component = node["component"];
|
|
166
|
+
const name = mapped["name"];
|
|
167
|
+
const boundKey = BOUND_KEYS.find((key) => node[key] !== void 0);
|
|
168
|
+
const value = boundKey === void 0 ? void 0 : props[boundKey];
|
|
169
|
+
if (INPUT_COMPONENTS.has(String(component)) && typeof name === "string") {
|
|
170
|
+
context.textFields.set(name, (!context.textFields.has(name) || context.bindings !== void 0) && (component === "TextField" || component === "DateTimeInput"));
|
|
171
|
+
const field = (fallback) => fallback === void 0 ? { $field: name } : {
|
|
172
|
+
$field: name,
|
|
173
|
+
fallback
|
|
174
|
+
};
|
|
175
|
+
const listValued = component === "ChoicePicker" && mapped.$type !== "CheckboxGroup" && typeof value !== "string";
|
|
176
|
+
context.inputFields.set(name, listValued ? [field(Array.isArray(value) ? value[0] : void 0)] : field(value));
|
|
177
|
+
}
|
|
178
|
+
const action = mapped.$action;
|
|
179
|
+
const raw = node["action"];
|
|
180
|
+
if (!action || !isRecord(raw)) return;
|
|
181
|
+
const functionCall = action.type === "a2ui:functionCall";
|
|
182
|
+
const event = isRecord(raw["event"]) ? raw["event"] : raw;
|
|
183
|
+
const userMessage = event["userMessage"];
|
|
184
|
+
if (!functionCall && isBinding(userMessage)) context.boundUserMessages.push({
|
|
185
|
+
action,
|
|
186
|
+
pointer: pointerIn(scope, userMessage.path)
|
|
187
|
+
});
|
|
188
|
+
const rawEntries = functionCall ? isRecord(raw["functionCall"]) ? raw["functionCall"]["args"] : void 0 : event["context"];
|
|
189
|
+
const target = functionCall ? action["args"] : action["context"];
|
|
190
|
+
if (!isRecord(rawEntries) || !isRecord(target)) return;
|
|
191
|
+
for (const [key, entry] of Object.entries(rawEntries)) if (isBinding(entry)) context.boundActionEntries.push({
|
|
192
|
+
target,
|
|
193
|
+
key,
|
|
194
|
+
pointer: pointerIn(scope, entry.path)
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
const spendEvaluation = (context) => {
|
|
198
|
+
if (context.evaluations < EVALUATION_BUDGET) {
|
|
199
|
+
context.evaluations++;
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (!context.evaluationBudgetWarned) {
|
|
203
|
+
context.warnings.push(`A2UI function evaluation budget of ${EVALUATION_BUDGET} was reached.`);
|
|
204
|
+
context.evaluationBudgetWarned = true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
};
|
|
89
208
|
const reserveNode = (context) => {
|
|
90
209
|
if (context.emittedNodes >= NODE_BUDGET) {
|
|
91
210
|
if (!context.budgetWarned) {
|
|
@@ -97,33 +216,65 @@ const reserveNode = (context) => {
|
|
|
97
216
|
context.emittedNodes++;
|
|
98
217
|
return true;
|
|
99
218
|
};
|
|
100
|
-
const
|
|
219
|
+
const childReferences = (node) => {
|
|
101
220
|
const children = node["children"];
|
|
102
|
-
|
|
221
|
+
const references = Array.isArray(children) ? [...children] : [];
|
|
222
|
+
if (node["child"] !== void 0) references.push(node["child"]);
|
|
223
|
+
if (node["component"] === "Modal") references.push(node["trigger"], node["content"]);
|
|
224
|
+
if (node["component"] === "Tabs" && Array.isArray(node["tabs"])) for (const tab of node["tabs"]) references.push(isRecord(tab) ? tab["child"] : void 0);
|
|
225
|
+
return references;
|
|
226
|
+
};
|
|
227
|
+
const childrenOf = (node, scope, context, depth, visited) => {
|
|
103
228
|
const result = [];
|
|
104
|
-
for (const childId of
|
|
229
|
+
for (const childId of childReferences(node)) {
|
|
105
230
|
if (typeof childId !== "string") {
|
|
106
231
|
context.warnings.push(`Component "${String(node["id"] ?? "")}" has a malformed child reference.`);
|
|
107
232
|
continue;
|
|
108
233
|
}
|
|
109
|
-
const child = convertComponent(childId,
|
|
234
|
+
const child = convertComponent(childId, scope, context, depth + 1, visited);
|
|
110
235
|
if (child) result.push(child);
|
|
111
236
|
}
|
|
112
237
|
return result;
|
|
113
238
|
};
|
|
114
|
-
const
|
|
239
|
+
const textLabel = (node, children, context) => {
|
|
240
|
+
const references = childReferences(node);
|
|
241
|
+
const [reference] = references;
|
|
242
|
+
const [child] = children;
|
|
243
|
+
if (references.length !== 1 || children.length !== 1 || typeof reference !== "string" || !child || context.surface.components.get(reference)?.["component"] !== "Text") return;
|
|
244
|
+
const text = child.$type === "Header" ? child["text"] : child["value"];
|
|
245
|
+
return typeof text === "string" ? text : void 0;
|
|
246
|
+
};
|
|
247
|
+
const mappedAction = (node, props, context) => {
|
|
115
248
|
const action = props["action"];
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const rawContext = isRecord(action) ? action["context"] : void 0;
|
|
119
|
-
const resolvedContext = rawContext === void 0 ? void 0 : materialize(rawContext, dataSource);
|
|
120
|
-
return {
|
|
121
|
-
type: "a2ui:action",
|
|
122
|
-
name: actionName,
|
|
249
|
+
if (action === void 0) return void 0;
|
|
250
|
+
const source = {
|
|
123
251
|
surfaceId: context.surfaceId,
|
|
124
|
-
sourceComponentId: typeof node["id"] === "string" ? node["id"] : ""
|
|
125
|
-
...resolvedContext !== void 0 ? { context: resolvedContext } : {}
|
|
252
|
+
sourceComponentId: typeof node["id"] === "string" ? node["id"] : ""
|
|
126
253
|
};
|
|
254
|
+
const event = isRecord(action) && isRecord(action["event"]) ? action["event"] : action;
|
|
255
|
+
const actionName = typeof event === "string" ? event : isRecord(event) && typeof event["name"] === "string" ? event["name"] : void 0;
|
|
256
|
+
if (actionName) {
|
|
257
|
+
const actionContext = isRecord(event) ? event["context"] : void 0;
|
|
258
|
+
const userMessage = isRecord(event) ? event["userMessage"] : void 0;
|
|
259
|
+
return {
|
|
260
|
+
type: "a2ui:action",
|
|
261
|
+
name: actionName,
|
|
262
|
+
...source,
|
|
263
|
+
...typeof userMessage === "string" ? { userMessage } : {},
|
|
264
|
+
...actionContext !== void 0 ? { context: actionContext } : {}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const functionCall = isRecord(action) ? action["functionCall"] : void 0;
|
|
268
|
+
if (isRecord(functionCall) && typeof functionCall["call"] === "string") {
|
|
269
|
+
const args = functionCall["args"];
|
|
270
|
+
return {
|
|
271
|
+
type: "a2ui:functionCall",
|
|
272
|
+
call: functionCall["call"],
|
|
273
|
+
...source,
|
|
274
|
+
...isRecord(args) ? { args } : {}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
context.warnings.push(`Component "${String(node["id"] ?? "")}" has a malformed action.`);
|
|
127
278
|
};
|
|
128
279
|
const choiceOptions = (value) => {
|
|
129
280
|
if (!Array.isArray(value)) return [];
|
|
@@ -134,7 +285,7 @@ const choiceOptions = (value) => {
|
|
|
134
285
|
});
|
|
135
286
|
return options;
|
|
136
287
|
};
|
|
137
|
-
const mappedProps = (node, props,
|
|
288
|
+
const mappedProps = (node, props, context, scope) => {
|
|
138
289
|
const component = node["component"];
|
|
139
290
|
if (component === "Text") {
|
|
140
291
|
const text = stringProp(props, ["text", "value"]);
|
|
@@ -225,35 +376,37 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
225
376
|
};
|
|
226
377
|
if (component === "Button") {
|
|
227
378
|
const label = stringProp(props, ["label", "text"]);
|
|
228
|
-
const
|
|
379
|
+
const variantStyle = props["variant"] === "primary" ? "primary" : props["variant"] === "borderless" ? "ghost" : void 0;
|
|
380
|
+
const buttonStyle = typeof props["buttonStyle"] === "string" ? props["buttonStyle"] : variantStyle;
|
|
229
381
|
const block = props["block"];
|
|
230
382
|
const submit = props["submit"];
|
|
231
|
-
const action = mappedAction(node, props,
|
|
383
|
+
const action = mappedAction(node, props, context);
|
|
232
384
|
return {
|
|
233
385
|
$type: "Button",
|
|
234
386
|
...label !== void 0 ? { label } : {},
|
|
235
|
-
...
|
|
387
|
+
...buttonStyle !== void 0 ? { buttonStyle } : {},
|
|
236
388
|
...typeof block === "boolean" ? { block } : {},
|
|
237
389
|
...typeof submit === "boolean" ? { submit } : {},
|
|
238
390
|
...action ? { $action: action } : {}
|
|
239
391
|
};
|
|
240
392
|
}
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
"value",
|
|
244
|
-
"binding"
|
|
245
|
-
]);
|
|
246
|
-
const name = lastPointerSegment(bindingPath(binding));
|
|
393
|
+
const bound = bindingPath(firstDefined(node, BOUND_KEYS));
|
|
394
|
+
const name = bound === void 0 ? void 0 : pointerIn(scope, bound);
|
|
247
395
|
const label = stringProp(props, ["label"]);
|
|
248
396
|
if (component === "TextField") {
|
|
249
397
|
const placeholder = stringProp(props, ["placeholder"]);
|
|
250
|
-
const
|
|
398
|
+
const inputType = props["variant"] === "obscured" ? "password" : props["variant"] === "number" ? "number" : void 0;
|
|
399
|
+
const multiline = typeof props["multiline"] === "boolean" ? props["multiline"] : props["variant"] === "longText" || props["textFieldType"] === "longText" ? true : void 0;
|
|
400
|
+
const initial = firstDefined(props, ["value", "text"]);
|
|
401
|
+
const defaultValue = typeof initial === "string" ? initial : typeof initial === "number" && Number.isFinite(initial) ? String(initial) : void 0;
|
|
251
402
|
return {
|
|
252
403
|
$type: "Input",
|
|
404
|
+
...inputType !== void 0 ? { inputType } : {},
|
|
253
405
|
...placeholder !== void 0 ? { placeholder } : {},
|
|
254
406
|
...multiline !== void 0 ? { multiline } : {},
|
|
255
407
|
...label !== void 0 ? { label } : {},
|
|
256
|
-
...name !== void 0 ? { name } : {}
|
|
408
|
+
...name !== void 0 ? { name } : {},
|
|
409
|
+
...defaultValue !== void 0 ? { defaultValue } : {}
|
|
257
410
|
};
|
|
258
411
|
}
|
|
259
412
|
if (component === "CheckBox") {
|
|
@@ -265,28 +418,51 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
265
418
|
...typeof defaultChecked === "boolean" ? { defaultChecked } : {}
|
|
266
419
|
};
|
|
267
420
|
}
|
|
421
|
+
if (component === "Slider") {
|
|
422
|
+
const min = finiteNumber(props["min"]) ?? 0;
|
|
423
|
+
const max = finiteNumber(props["max"]);
|
|
424
|
+
if (max === void 0 || max < min) return void 0;
|
|
425
|
+
const value = finiteNumber(props["value"]);
|
|
426
|
+
const step = sliderStep(min, max, name === void 0 ? value : finiteNumber(resolvePointer(context.stepModel, name)), props["steps"]);
|
|
427
|
+
return {
|
|
428
|
+
$type: "Slider",
|
|
429
|
+
min,
|
|
430
|
+
max,
|
|
431
|
+
...step !== void 0 ? { step } : {},
|
|
432
|
+
...value !== void 0 ? { defaultValue: value } : {},
|
|
433
|
+
...label !== void 0 ? { label } : {},
|
|
434
|
+
...name !== void 0 ? { name } : {}
|
|
435
|
+
};
|
|
436
|
+
}
|
|
268
437
|
if (component === "ChoicePicker") {
|
|
269
438
|
const options = choiceOptions(props["options"]);
|
|
270
439
|
const value = props["value"];
|
|
271
|
-
const
|
|
272
|
-
if (props["variant"] === "
|
|
273
|
-
$type: "
|
|
440
|
+
const selected = typeof value === "string" ? [value] : Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
441
|
+
if (props["variant"] === "multipleSelection") return {
|
|
442
|
+
$type: "CheckboxGroup",
|
|
274
443
|
options,
|
|
275
444
|
...label !== void 0 ? { label } : {},
|
|
276
445
|
...name !== void 0 ? { name } : {},
|
|
277
|
-
...
|
|
446
|
+
...selected.length > 0 ? { defaultValue: selected } : {}
|
|
278
447
|
};
|
|
279
|
-
const
|
|
448
|
+
const [defaultValue] = selected;
|
|
280
449
|
return {
|
|
281
|
-
$type: "
|
|
450
|
+
$type: "RadioGroup",
|
|
282
451
|
options,
|
|
283
|
-
...placeholder !== void 0 ? { placeholder } : {},
|
|
284
452
|
...label !== void 0 ? { label } : {},
|
|
285
|
-
...name !== void 0 ? { name } : {}
|
|
453
|
+
...name !== void 0 ? { name } : {},
|
|
454
|
+
...defaultValue !== void 0 ? { defaultValue } : {}
|
|
286
455
|
};
|
|
287
456
|
}
|
|
288
457
|
if (component === "DateTimeInput") {
|
|
289
458
|
const value = stringProp(props, ["value"]);
|
|
459
|
+
const shapeValue = name === void 0 ? value : resolvePointer(context.stepModel, name);
|
|
460
|
+
if (props["enableTime"] === true || typeof shapeValue === "string" && shapeValue !== "" && !DATE_PATTERN.test(shapeValue)) return {
|
|
461
|
+
$type: "Input",
|
|
462
|
+
...value !== void 0 ? { defaultValue: value } : {},
|
|
463
|
+
...label !== void 0 ? { label } : {},
|
|
464
|
+
...name !== void 0 ? { name } : {}
|
|
465
|
+
};
|
|
290
466
|
const min = stringProp(props, ["min"]);
|
|
291
467
|
const max = stringProp(props, ["max"]);
|
|
292
468
|
return {
|
|
@@ -299,11 +475,12 @@ const mappedProps = (node, props, dataSource, context) => {
|
|
|
299
475
|
};
|
|
300
476
|
}
|
|
301
477
|
};
|
|
302
|
-
const convertTemplate = (node,
|
|
478
|
+
const convertTemplate = (node, template, scope, context, depth, visited, converted) => {
|
|
303
479
|
if (!reserveNode(context)) return null;
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
const list = resolvePointer(
|
|
480
|
+
const container = converted ?? { $type: "ListView" };
|
|
481
|
+
const itemized = container.$type === "ListView";
|
|
482
|
+
const list = resolvePointer(context.surface.dataModel, pointerIn(scope, template.path));
|
|
483
|
+
const listPointer = pointerIn(scope, template.path);
|
|
307
484
|
if (!Array.isArray(list)) {
|
|
308
485
|
context.warnings.push(`Template on component "${String(node["id"] ?? "")}" did not resolve to a list.`);
|
|
309
486
|
return {
|
|
@@ -318,21 +495,23 @@ const convertTemplate = (node, templateChildren, dataSource, context, depth, vis
|
|
|
318
495
|
}
|
|
319
496
|
const children = [];
|
|
320
497
|
for (let index = 0; index < itemCount; index++) {
|
|
321
|
-
if (
|
|
322
|
-
const child = convertComponent(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
498
|
+
if (itemized && !reserveNode(context)) break;
|
|
499
|
+
const child = convertComponent(template.componentId, {
|
|
500
|
+
data: list[index],
|
|
501
|
+
path: `${listPointer}/${index}`
|
|
502
|
+
}, context, depth + 1, visited);
|
|
503
|
+
if (itemized) children.push({
|
|
326
504
|
$type: "ListViewItem",
|
|
327
505
|
...child ? { children: child } : {}
|
|
328
506
|
});
|
|
507
|
+
else if (child) children.push(child);
|
|
329
508
|
}
|
|
330
509
|
return {
|
|
331
510
|
...container,
|
|
332
511
|
children
|
|
333
512
|
};
|
|
334
513
|
};
|
|
335
|
-
function convertComponent(componentId,
|
|
514
|
+
function convertComponent(componentId, scope, context, depth, visited) {
|
|
336
515
|
if (depth >= DEPTH_CAP) {
|
|
337
516
|
if (!context.depthWarned) {
|
|
338
517
|
context.warnings.push(`A2UI depth cap of ${DEPTH_CAP} was reached.`);
|
|
@@ -356,19 +535,61 @@ function convertComponent(componentId, dataSource, context, depth, visited) {
|
|
|
356
535
|
context.warnings.push(`Unknown A2UI component "${String(component ?? "")}" was skipped.`);
|
|
357
536
|
return null;
|
|
358
537
|
}
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
if (!SUPPORTED_COMPONENTS.has(component) && !context.keepUnknownComponents && !hasTemplate) {
|
|
538
|
+
const template = childTemplateOf(node["children"]);
|
|
539
|
+
if (!SUPPORTED_COMPONENTS.has(component) && !context.keepUnknownComponents && !template) {
|
|
362
540
|
context.warnings.push(`Unknown A2UI component "${component}" was skipped.`);
|
|
363
541
|
return null;
|
|
364
542
|
}
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
543
|
+
const cacheKey = context.cache ? JSON.stringify([
|
|
544
|
+
componentId,
|
|
545
|
+
scope.path,
|
|
546
|
+
depth
|
|
547
|
+
]) : "";
|
|
548
|
+
let cached = context.cache?.get(cacheKey);
|
|
549
|
+
if (cached && (context.evaluations + cached.evaluations > EVALUATION_BUDGET || [...cached.dependencies].some(([path, value]) => !Object.is(resolvePointer(context.surface.dataModel, path), value)))) cached = void 0;
|
|
550
|
+
let props;
|
|
551
|
+
let mapped;
|
|
552
|
+
if (cached) {
|
|
553
|
+
props = cached.props;
|
|
554
|
+
mapped = cached.mapped;
|
|
555
|
+
context.evaluations += cached.evaluations;
|
|
556
|
+
} else {
|
|
557
|
+
props = {};
|
|
558
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
559
|
+
const evaluations = context.evaluations;
|
|
560
|
+
context.dependencies = dependencies;
|
|
561
|
+
context.scopePath = scope.path;
|
|
562
|
+
for (const [key, value] of Object.entries(node)) {
|
|
563
|
+
if (key === "id" || key === "component" || key === "children" || key === "child") continue;
|
|
564
|
+
const resolved = materialize(value, scope.data, context, key !== "checks");
|
|
565
|
+
if (resolved !== void 0) setOwnProperty(props, key, resolved);
|
|
566
|
+
}
|
|
567
|
+
context.dependencies = void 0;
|
|
568
|
+
mapped = mappedProps(node, props, context, scope);
|
|
569
|
+
if (context.cache && context.warnings.length === 0 && !mapped?.$action) {
|
|
570
|
+
cached = {
|
|
571
|
+
props,
|
|
572
|
+
mapped,
|
|
573
|
+
dependencies,
|
|
574
|
+
evaluations: context.evaluations - evaluations
|
|
575
|
+
};
|
|
576
|
+
context.cache.set(cacheKey, cached);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
if (mapped && context.bindings && typeof mapped["name"] === "string" && INPUT_COMPONENTS.has(component)) {
|
|
580
|
+
const field = mapped.$type === "Checkbox" ? "checked" : "value";
|
|
581
|
+
const defaultField = mapped.$type === "Checkbox" ? "defaultChecked" : "defaultValue";
|
|
582
|
+
const fallback = mapped.$type === "Checkbox" ? false : mapped.$type === "CheckboxGroup" ? [] : mapped.$type === "Slider" ? mapped["min"] : "";
|
|
583
|
+
const { [defaultField]: initialValue, ...rest } = mapped;
|
|
584
|
+
mapped = {
|
|
585
|
+
...rest,
|
|
586
|
+
[field]: initialValue ?? mapped[field] ?? fallback
|
|
587
|
+
};
|
|
588
|
+
context.bindings.set(mapped["name"], {
|
|
589
|
+
value: mapped[field],
|
|
590
|
+
arrayValue: component === "ChoicePicker" && mapped.$type !== "CheckboxGroup" && typeof props["value"] !== "string"
|
|
591
|
+
});
|
|
370
592
|
}
|
|
371
|
-
const mapped = mappedProps(node, props, dataSource, context);
|
|
372
593
|
if (!mapped && SUPPORTED_COMPONENTS.has(component)) {
|
|
373
594
|
context.warnings.push(`A2UI component "${component}" could not be mapped and was skipped.`);
|
|
374
595
|
return null;
|
|
@@ -377,24 +598,56 @@ function convertComponent(componentId, dataSource, context, depth, visited) {
|
|
|
377
598
|
$type: component,
|
|
378
599
|
...Object.fromEntries(Object.entries(props).filter(([key]) => !key.startsWith("$")))
|
|
379
600
|
} : void 0;
|
|
380
|
-
if (
|
|
601
|
+
if (template) return convertTemplate(node, template, scope, context, depth, visited, CHILD_LIST_COMPONENTS.has(component) ? mapped : retained);
|
|
381
602
|
if (!reserveNode(context)) return null;
|
|
382
603
|
const converted = mapped ?? retained;
|
|
383
604
|
if (!converted) return null;
|
|
384
|
-
|
|
605
|
+
recordBindings(node, props, converted, scope, context);
|
|
606
|
+
const children = childrenOf(node, scope, context, depth, visited);
|
|
607
|
+
if (mapped?.$type === "Button" && mapped["label"] === void 0) {
|
|
608
|
+
const label = textLabel(node, children, context);
|
|
609
|
+
if (label !== void 0) return {
|
|
610
|
+
...mapped,
|
|
611
|
+
label
|
|
612
|
+
};
|
|
613
|
+
}
|
|
385
614
|
const listChildren = component === "List" && mapped?.$type === "ListView" ? children.map((child) => ({
|
|
386
615
|
$type: "ListViewItem",
|
|
387
616
|
children: child
|
|
388
617
|
})) : children;
|
|
389
|
-
return
|
|
618
|
+
if (cached?.result && cached.children?.length === listChildren.length && cached.children.every((child, index) => child === listChildren[index])) return cached.result;
|
|
619
|
+
const result = {
|
|
390
620
|
...converted,
|
|
391
621
|
...listChildren.length > 0 ? { children: listChildren } : {}
|
|
392
622
|
};
|
|
623
|
+
if (cached) {
|
|
624
|
+
cached.children = listChildren;
|
|
625
|
+
cached.result = result;
|
|
626
|
+
}
|
|
627
|
+
return result;
|
|
393
628
|
} finally {
|
|
394
629
|
visited.delete(componentId);
|
|
395
630
|
}
|
|
396
631
|
}
|
|
397
632
|
function convertSurfaceToUISpec(surface, options = {}) {
|
|
633
|
+
return convertSurface(surface, options.keepUnknownComponents === true);
|
|
634
|
+
}
|
|
635
|
+
const createLiveSurfaceConverter = (surface) => {
|
|
636
|
+
const cache = /* @__PURE__ */ new Map();
|
|
637
|
+
const templates = /* @__PURE__ */ new Map();
|
|
638
|
+
return (dataModel) => {
|
|
639
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
640
|
+
return {
|
|
641
|
+
...convertSurface({
|
|
642
|
+
...surface,
|
|
643
|
+
dataModel,
|
|
644
|
+
[A2UI_SURFACE_ID]: sourceSurfaceId(surface)
|
|
645
|
+
}, false, bindings, cache, templates, surface.dataModel),
|
|
646
|
+
bindings
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
};
|
|
650
|
+
function convertSurface(surface, keepUnknownComponents, bindings, cache, templates = /* @__PURE__ */ new Map(), stepModel = surface.dataModel) {
|
|
398
651
|
const warnings = [];
|
|
399
652
|
if (!surface.components.has("root")) return {
|
|
400
653
|
spec: null,
|
|
@@ -402,17 +655,46 @@ function convertSurfaceToUISpec(surface, options = {}) {
|
|
|
402
655
|
};
|
|
403
656
|
const context = {
|
|
404
657
|
surface,
|
|
658
|
+
stepModel,
|
|
405
659
|
surfaceId: sourceSurfaceId(surface),
|
|
406
660
|
warnings,
|
|
407
661
|
emittedNodes: 0,
|
|
408
662
|
depthWarned: false,
|
|
409
663
|
budgetWarned: false,
|
|
410
664
|
templateCapWarned: false,
|
|
411
|
-
|
|
665
|
+
evaluations: 0,
|
|
666
|
+
evaluationBudgetWarned: false,
|
|
667
|
+
functionDepthWarned: false,
|
|
668
|
+
templates,
|
|
669
|
+
inputFields: /* @__PURE__ */ new Map(),
|
|
670
|
+
textFields: /* @__PURE__ */ new Map(),
|
|
671
|
+
boundActionEntries: [],
|
|
672
|
+
boundUserMessages: [],
|
|
673
|
+
keepUnknownComponents,
|
|
674
|
+
bindings,
|
|
675
|
+
cache,
|
|
676
|
+
dependencies: void 0,
|
|
677
|
+
scopePath: ""
|
|
412
678
|
};
|
|
413
679
|
try {
|
|
680
|
+
const spec = convertComponent("root", {
|
|
681
|
+
data: surface.dataModel,
|
|
682
|
+
path: ""
|
|
683
|
+
}, context, 0, /* @__PURE__ */ new Set());
|
|
684
|
+
for (const { target, key, pointer } of context.boundActionEntries) {
|
|
685
|
+
const value = withFieldReferences(target[key], pointer, context.inputFields);
|
|
686
|
+
if (value !== void 0) setOwnProperty(target, key, value);
|
|
687
|
+
}
|
|
688
|
+
for (const { action, pointer } of context.boundUserMessages) {
|
|
689
|
+
if (!context.textFields.get(pointer)) continue;
|
|
690
|
+
const fallback = action["userMessage"];
|
|
691
|
+
setOwnProperty(action, "userMessage", typeof fallback === "string" ? {
|
|
692
|
+
$field: pointer,
|
|
693
|
+
fallback
|
|
694
|
+
} : { $field: pointer });
|
|
695
|
+
}
|
|
414
696
|
return {
|
|
415
|
-
spec
|
|
697
|
+
spec,
|
|
416
698
|
warnings
|
|
417
699
|
};
|
|
418
700
|
} catch {
|
|
@@ -424,6 +706,6 @@ function convertSurfaceToUISpec(surface, options = {}) {
|
|
|
424
706
|
}
|
|
425
707
|
}
|
|
426
708
|
//#endregion
|
|
427
|
-
export { convertSurfaceToUISpec };
|
|
709
|
+
export { convertSurfaceToUISpec, createLiveSurfaceConverter };
|
|
428
710
|
|
|
429
711
|
//# sourceMappingURL=convert.js.map
|