@assistant-ui/react-generative-ui 0.0.23 → 0.1.0

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 (338) hide show
  1. package/README.md +2 -0
  2. package/dist/a2ui.d.ts +1 -4
  3. package/dist/a2ui.d.ts.map +1 -1
  4. package/dist/a2ui.js +1 -4
  5. package/dist/index.d.ts +1 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -10
  8. package/dist/index.server.d.ts +1 -2
  9. package/dist/index.server.d.ts.map +1 -1
  10. package/dist/index.server.js +1 -10
  11. package/dist/ir.d.ts +1 -111
  12. package/dist/ir.d.ts.map +1 -1
  13. package/dist/ir.js +1 -175
  14. package/dist/slack.d.ts +1 -4
  15. package/dist/slack.d.ts.map +1 -1
  16. package/dist/slack.js +1 -4
  17. package/dist/teams.d.ts +1 -4
  18. package/dist/teams.d.ts.map +1 -1
  19. package/dist/teams.js +1 -4
  20. package/package.json +5 -5
  21. package/src/a2ui.ts +1 -22
  22. package/src/index.server.ts +1 -2
  23. package/src/index.test.ts +75 -0
  24. package/src/index.ts +1 -2
  25. package/src/ir.ts +1 -279
  26. package/src/slack.ts +1 -39
  27. package/src/teams.ts +1 -35
  28. package/dist/JSONGenerativeUI.client.d.ts +0 -28
  29. package/dist/JSONGenerativeUI.client.d.ts.map +0 -1
  30. package/dist/JSONGenerativeUI.client.js +0 -101
  31. package/dist/JSONGenerativeUI.client.js.map +0 -1
  32. package/dist/JSONGenerativeUI.server.d.ts +0 -21
  33. package/dist/JSONGenerativeUI.server.d.ts.map +0 -1
  34. package/dist/JSONGenerativeUI.server.js +0 -32
  35. package/dist/JSONGenerativeUI.server.js.map +0 -1
  36. package/dist/JSONGenerativeUI.shared.d.ts +0 -63
  37. package/dist/JSONGenerativeUI.shared.d.ts.map +0 -1
  38. package/dist/JSONGenerativeUI.shared.js +0 -31
  39. package/dist/JSONGenerativeUI.shared.js.map +0 -1
  40. package/dist/RadioGroupScope.d.ts +0 -6
  41. package/dist/RadioGroupScope.d.ts.map +0 -1
  42. package/dist/RadioGroupScope.js +0 -25
  43. package/dist/RadioGroupScope.js.map +0 -1
  44. package/dist/a2ui/BindingContext.d.ts +0 -11
  45. package/dist/a2ui/BindingContext.d.ts.map +0 -1
  46. package/dist/a2ui/BindingContext.js +0 -12
  47. package/dist/a2ui/BindingContext.js.map +0 -1
  48. package/dist/a2ui/PresentRenderer.d.ts +0 -11
  49. package/dist/a2ui/PresentRenderer.d.ts.map +0 -1
  50. package/dist/a2ui/PresentRenderer.js +0 -39
  51. package/dist/a2ui/PresentRenderer.js.map +0 -1
  52. package/dist/a2ui/convert.d.ts +0 -15
  53. package/dist/a2ui/convert.d.ts.map +0 -1
  54. package/dist/a2ui/convert.js +0 -728
  55. package/dist/a2ui/convert.js.map +0 -1
  56. package/dist/a2ui/dataModel.d.ts +0 -9
  57. package/dist/a2ui/dataModel.d.ts.map +0 -1
  58. package/dist/a2ui/dataModel.js +0 -44
  59. package/dist/a2ui/dataModel.js.map +0 -1
  60. package/dist/a2ui/reducer.d.ts +0 -8
  61. package/dist/a2ui/reducer.d.ts.map +0 -1
  62. package/dist/a2ui/reducer.js +0 -242
  63. package/dist/a2ui/reducer.js.map +0 -1
  64. package/dist/a2ui/snapshot.d.ts +0 -3
  65. package/dist/a2ui/snapshot.d.ts.map +0 -1
  66. package/dist/a2ui/snapshot.js +0 -33
  67. package/dist/a2ui/snapshot.js.map +0 -1
  68. package/dist/a2ui/types.d.ts +0 -88
  69. package/dist/a2ui/types.d.ts.map +0 -1
  70. package/dist/a2ui/types.js +0 -6
  71. package/dist/a2ui/types.js.map +0 -1
  72. package/dist/a2ui/valueFunctions.d.ts +0 -16
  73. package/dist/a2ui/valueFunctions.d.ts.map +0 -1
  74. package/dist/a2ui/valueFunctions.js +0 -332
  75. package/dist/a2ui/valueFunctions.js.map +0 -1
  76. package/dist/actionRegistry.d.ts +0 -29
  77. package/dist/actionRegistry.d.ts.map +0 -1
  78. package/dist/actionRegistry.js +0 -41
  79. package/dist/actionRegistry.js.map +0 -1
  80. package/dist/answeredValues.d.ts +0 -16
  81. package/dist/answeredValues.d.ts.map +0 -1
  82. package/dist/answeredValues.js +0 -37
  83. package/dist/answeredValues.js.map +0 -1
  84. package/dist/buildPresentParameters.d.ts +0 -21
  85. package/dist/buildPresentParameters.d.ts.map +0 -1
  86. package/dist/buildPresentParameters.js +0 -95
  87. package/dist/buildPresentParameters.js.map +0 -1
  88. package/dist/constants.d.ts +0 -15
  89. package/dist/constants.d.ts.map +0 -1
  90. package/dist/constants.js +0 -19
  91. package/dist/constants.js.map +0 -1
  92. package/dist/convert/boundSpec.d.ts +0 -48
  93. package/dist/convert/boundSpec.d.ts.map +0 -1
  94. package/dist/convert/boundSpec.js +0 -108
  95. package/dist/convert/boundSpec.js.map +0 -1
  96. package/dist/convert/copyBounded.d.ts +0 -25
  97. package/dist/convert/copyBounded.d.ts.map +0 -1
  98. package/dist/convert/copyBounded.js +0 -38
  99. package/dist/convert/copyBounded.js.map +0 -1
  100. package/dist/convert/isElement.d.ts +0 -3
  101. package/dist/convert/isElement.d.ts.map +0 -1
  102. package/dist/convert/isElement.js +0 -6
  103. package/dist/convert/isElement.js.map +0 -1
  104. package/dist/convert/takeRun.d.ts +0 -6
  105. package/dist/convert/takeRun.d.ts.map +0 -1
  106. package/dist/convert/takeRun.js +0 -20
  107. package/dist/convert/takeRun.js.map +0 -1
  108. package/dist/defineGenerativeComponents.d.ts +0 -29
  109. package/dist/defineGenerativeComponents.d.ts.map +0 -1
  110. package/dist/defineGenerativeComponents.js +0 -34
  111. package/dist/defineGenerativeComponents.js.map +0 -1
  112. package/dist/fieldReferences.d.ts +0 -9
  113. package/dist/fieldReferences.d.ts.map +0 -1
  114. package/dist/fieldReferences.js +0 -53
  115. package/dist/fieldReferences.js.map +0 -1
  116. package/dist/generativeUIToJSX.d.ts +0 -18
  117. package/dist/generativeUIToJSX.d.ts.map +0 -1
  118. package/dist/generativeUIToJSX.js +0 -76
  119. package/dist/generativeUIToJSX.js.map +0 -1
  120. package/dist/index.shared.d.ts +0 -15
  121. package/dist/index.shared.d.ts.map +0 -1
  122. package/dist/index.shared.js +0 -9
  123. package/dist/ir.js.map +0 -1
  124. package/dist/renderGenerativeUI.d.ts +0 -14
  125. package/dist/renderGenerativeUI.d.ts.map +0 -1
  126. package/dist/renderGenerativeUI.js +0 -83
  127. package/dist/renderGenerativeUI.js.map +0 -1
  128. package/dist/scopeSchema.d.ts +0 -6
  129. package/dist/scopeSchema.d.ts.map +0 -1
  130. package/dist/scopeSchema.js +0 -56
  131. package/dist/scopeSchema.js.map +0 -1
  132. package/dist/slack/constants.d.ts +0 -93
  133. package/dist/slack/constants.d.ts.map +0 -1
  134. package/dist/slack/constants.js +0 -146
  135. package/dist/slack/constants.js.map +0 -1
  136. package/dist/slack/decodeBlockAction.d.ts +0 -10
  137. package/dist/slack/decodeBlockAction.d.ts.map +0 -1
  138. package/dist/slack/decodeBlockAction.js +0 -129
  139. package/dist/slack/decodeBlockAction.js.map +0 -1
  140. package/dist/slack/fromSlackBlocks.d.ts +0 -27
  141. package/dist/slack/fromSlackBlocks.d.ts.map +0 -1
  142. package/dist/slack/fromSlackBlocks.js +0 -483
  143. package/dist/slack/fromSlackBlocks.js.map +0 -1
  144. package/dist/slack/toSlackBlocks.d.ts +0 -4
  145. package/dist/slack/toSlackBlocks.d.ts.map +0 -1
  146. package/dist/slack/toSlackBlocks.js +0 -901
  147. package/dist/slack/toSlackBlocks.js.map +0 -1
  148. package/dist/slack/types.d.ts +0 -204
  149. package/dist/slack/types.d.ts.map +0 -1
  150. package/dist/slack/types.js +0 -0
  151. package/dist/teams/constants.d.ts +0 -34
  152. package/dist/teams/constants.d.ts.map +0 -1
  153. package/dist/teams/constants.js +0 -68
  154. package/dist/teams/constants.js.map +0 -1
  155. package/dist/teams/decodeSubmitData.d.ts +0 -26
  156. package/dist/teams/decodeSubmitData.d.ts.map +0 -1
  157. package/dist/teams/decodeSubmitData.js +0 -70
  158. package/dist/teams/decodeSubmitData.js.map +0 -1
  159. package/dist/teams/temporalId.d.ts +0 -5
  160. package/dist/teams/temporalId.d.ts.map +0 -1
  161. package/dist/teams/temporalId.js +0 -28
  162. package/dist/teams/temporalId.js.map +0 -1
  163. package/dist/teams/toAdaptiveCard.d.ts +0 -45
  164. package/dist/teams/toAdaptiveCard.d.ts.map +0 -1
  165. package/dist/teams/toAdaptiveCard.js +0 -642
  166. package/dist/teams/toAdaptiveCard.js.map +0 -1
  167. package/dist/teams/toTeamsAttachments.d.ts +0 -10
  168. package/dist/teams/toTeamsAttachments.d.ts.map +0 -1
  169. package/dist/teams/toTeamsAttachments.js +0 -99
  170. package/dist/teams/toTeamsAttachments.js.map +0 -1
  171. package/dist/teams/types.d.ts +0 -224
  172. package/dist/teams/types.d.ts.map +0 -1
  173. package/dist/teams/types.js +0 -0
  174. package/dist/temporal.d.ts +0 -33
  175. package/dist/temporal.d.ts.map +0 -1
  176. package/dist/temporal.js +0 -152
  177. package/dist/temporal.js.map +0 -1
  178. package/dist/types.d.ts +0 -99
  179. package/dist/types.d.ts.map +0 -1
  180. package/dist/types.js +0 -0
  181. package/dist/vocabulary/alert.d.ts +0 -32
  182. package/dist/vocabulary/alert.d.ts.map +0 -1
  183. package/dist/vocabulary/alert.js +0 -160
  184. package/dist/vocabulary/alert.js.map +0 -1
  185. package/dist/vocabulary/collectFormValues.d.ts +0 -23
  186. package/dist/vocabulary/collectFormValues.d.ts.map +0 -1
  187. package/dist/vocabulary/collectFormValues.js +0 -44
  188. package/dist/vocabulary/collectFormValues.js.map +0 -1
  189. package/dist/vocabulary/data.d.ts +0 -66
  190. package/dist/vocabulary/data.d.ts.map +0 -1
  191. package/dist/vocabulary/data.js +0 -503
  192. package/dist/vocabulary/data.js.map +0 -1
  193. package/dist/vocabulary/dispatch.d.ts +0 -9
  194. package/dist/vocabulary/dispatch.d.ts.map +0 -1
  195. package/dist/vocabulary/dispatch.js +0 -50
  196. package/dist/vocabulary/dispatch.js.map +0 -1
  197. package/dist/vocabulary/fact.d.ts +0 -19
  198. package/dist/vocabulary/fact.d.ts.map +0 -1
  199. package/dist/vocabulary/fact.js +0 -51
  200. package/dist/vocabulary/fact.js.map +0 -1
  201. package/dist/vocabulary/form.d.ts +0 -11
  202. package/dist/vocabulary/form.d.ts.map +0 -1
  203. package/dist/vocabulary/form.js +0 -23
  204. package/dist/vocabulary/form.js.map +0 -1
  205. package/dist/vocabulary/formatValue.d.ts +0 -7
  206. package/dist/vocabulary/formatValue.d.ts.map +0 -1
  207. package/dist/vocabulary/formatValue.js +0 -76
  208. package/dist/vocabulary/formatValue.js.map +0 -1
  209. package/dist/vocabulary/icon.d.ts +0 -41
  210. package/dist/vocabulary/icon.d.ts.map +0 -1
  211. package/dist/vocabulary/icon.js +0 -272
  212. package/dist/vocabulary/icon.js.map +0 -1
  213. package/dist/vocabulary/index.d.ts +0 -12
  214. package/dist/vocabulary/index.d.ts.map +0 -1
  215. package/dist/vocabulary/index.js +0 -36
  216. package/dist/vocabulary/index.js.map +0 -1
  217. package/dist/vocabulary/interactive.d.ts +0 -230
  218. package/dist/vocabulary/interactive.d.ts.map +0 -1
  219. package/dist/vocabulary/interactive.js +0 -530
  220. package/dist/vocabulary/interactive.js.map +0 -1
  221. package/dist/vocabulary/layout.d.ts +0 -79
  222. package/dist/vocabulary/layout.d.ts.map +0 -1
  223. package/dist/vocabulary/layout.js +0 -139
  224. package/dist/vocabulary/layout.js.map +0 -1
  225. package/dist/vocabulary/list.d.ts +0 -14
  226. package/dist/vocabulary/list.d.ts.map +0 -1
  227. package/dist/vocabulary/list.js +0 -50
  228. package/dist/vocabulary/list.js.map +0 -1
  229. package/dist/vocabulary/media.d.ts +0 -25
  230. package/dist/vocabulary/media.d.ts.map +0 -1
  231. package/dist/vocabulary/media.js +0 -42
  232. package/dist/vocabulary/media.js.map +0 -1
  233. package/dist/vocabulary/text.d.ts +0 -57
  234. package/dist/vocabulary/text.d.ts.map +0 -1
  235. package/dist/vocabulary/text.js +0 -49
  236. package/dist/vocabulary/text.js.map +0 -1
  237. package/dist/vocabulary/toTextContent.d.ts +0 -2
  238. package/dist/vocabulary/toTextContent.d.ts.map +0 -1
  239. package/dist/vocabulary/toTextContent.js +0 -6
  240. package/dist/vocabulary/toTextContent.js.map +0 -1
  241. package/src/JSONGenerativeUI.client.tsx +0 -168
  242. package/src/JSONGenerativeUI.server.tsx +0 -39
  243. package/src/JSONGenerativeUI.shared.ts +0 -90
  244. package/src/JSONGenerativeUI.test.tsx +0 -1298
  245. package/src/RadioGroupScope.server.test.tsx +0 -24
  246. package/src/RadioGroupScope.tsx +0 -34
  247. package/src/a2ui/BindingContext.ts +0 -26
  248. package/src/a2ui/PresentRenderer.tsx +0 -83
  249. package/src/a2ui/convert.test.ts +0 -2923
  250. package/src/a2ui/convert.ts +0 -1207
  251. package/src/a2ui/dataModel.ts +0 -69
  252. package/src/a2ui/reducer.test.ts +0 -422
  253. package/src/a2ui/reducer.ts +0 -363
  254. package/src/a2ui/snapshot.test.ts +0 -52
  255. package/src/a2ui/snapshot.ts +0 -52
  256. package/src/a2ui/types.ts +0 -114
  257. package/src/a2ui/valueFunctions.test.ts +0 -271
  258. package/src/a2ui/valueFunctions.ts +0 -523
  259. package/src/actionRegistry.test.ts +0 -90
  260. package/src/actionRegistry.ts +0 -88
  261. package/src/answeredValues.test.ts +0 -33
  262. package/src/answeredValues.tsx +0 -70
  263. package/src/buildPresentParameters.test.ts +0 -246
  264. package/src/buildPresentParameters.ts +0 -130
  265. package/src/constants.ts +0 -17
  266. package/src/convert/boundSpec.test.ts +0 -192
  267. package/src/convert/boundSpec.ts +0 -134
  268. package/src/convert/copyBounded.test.ts +0 -131
  269. package/src/convert/copyBounded.ts +0 -38
  270. package/src/convert/isElement.ts +0 -6
  271. package/src/convert/takeRun.test.ts +0 -64
  272. package/src/convert/takeRun.ts +0 -19
  273. package/src/defineGenerativeComponents.ts +0 -38
  274. package/src/fieldReferences.test.ts +0 -66
  275. package/src/fieldReferences.ts +0 -83
  276. package/src/generativeUIToJSX.test.ts +0 -268
  277. package/src/generativeUIToJSX.ts +0 -152
  278. package/src/index.server.test.ts +0 -106
  279. package/src/index.shared.ts +0 -61
  280. package/src/ir.test.ts +0 -203
  281. package/src/renderGenerativeUI.test.tsx +0 -373
  282. package/src/renderGenerativeUI.tsx +0 -165
  283. package/src/scopeSchema.test.ts +0 -72
  284. package/src/scopeSchema.ts +0 -71
  285. package/src/slack/a2uiSlack.test.ts +0 -198
  286. package/src/slack/constants.ts +0 -194
  287. package/src/slack/datePicker.test.ts +0 -612
  288. package/src/slack/decodeBlockAction.test.ts +0 -233
  289. package/src/slack/decodeBlockAction.ts +0 -232
  290. package/src/slack/fromSlackBlocks.test.ts +0 -1465
  291. package/src/slack/fromSlackBlocks.ts +0 -789
  292. package/src/slack/toSlackBlocks.test.ts +0 -3065
  293. package/src/slack/toSlackBlocks.ts +0 -1818
  294. package/src/slack/types.ts +0 -264
  295. package/src/teams/constants.ts +0 -93
  296. package/src/teams/decodeSubmitData.test.ts +0 -397
  297. package/src/teams/decodeSubmitData.ts +0 -110
  298. package/src/teams/temporal.test.ts +0 -766
  299. package/src/teams/temporalId.ts +0 -56
  300. package/src/teams/toAdaptiveCard.test.ts +0 -1897
  301. package/src/teams/toAdaptiveCard.ts +0 -1057
  302. package/src/teams/toTeamsAttachments.test.ts +0 -74
  303. package/src/teams/toTeamsAttachments.ts +0 -133
  304. package/src/teams/types.ts +0 -266
  305. package/src/temporal.test.ts +0 -319
  306. package/src/temporal.ts +0 -259
  307. package/src/types.ts +0 -119
  308. package/src/vocabulary/alert.test.tsx +0 -427
  309. package/src/vocabulary/alert.tsx +0 -217
  310. package/src/vocabulary/collectFormValues.test.ts +0 -389
  311. package/src/vocabulary/collectFormValues.ts +0 -116
  312. package/src/vocabulary/data.test.tsx +0 -858
  313. package/src/vocabulary/data.tsx +0 -819
  314. package/src/vocabulary/datepicker.dom.test.tsx +0 -1148
  315. package/src/vocabulary/dispatch.ts +0 -83
  316. package/src/vocabulary/fact.test.tsx +0 -94
  317. package/src/vocabulary/fact.tsx +0 -54
  318. package/src/vocabulary/form.test.tsx +0 -113
  319. package/src/vocabulary/form.tsx +0 -39
  320. package/src/vocabulary/formatValue.test.ts +0 -72
  321. package/src/vocabulary/formatValue.ts +0 -127
  322. package/src/vocabulary/icon.test.tsx +0 -64
  323. package/src/vocabulary/icon.tsx +0 -174
  324. package/src/vocabulary/index.test.ts +0 -65
  325. package/src/vocabulary/index.ts +0 -33
  326. package/src/vocabulary/interactive.dispatch.test.tsx +0 -454
  327. package/src/vocabulary/interactive.dom.test.tsx +0 -1747
  328. package/src/vocabulary/interactive.test.tsx +0 -377
  329. package/src/vocabulary/interactive.tsx +0 -1048
  330. package/src/vocabulary/layout.test.tsx +0 -323
  331. package/src/vocabulary/layout.tsx +0 -247
  332. package/src/vocabulary/list.test.tsx +0 -222
  333. package/src/vocabulary/list.tsx +0 -50
  334. package/src/vocabulary/media.test.tsx +0 -85
  335. package/src/vocabulary/media.tsx +0 -56
  336. package/src/vocabulary/text.test.tsx +0 -102
  337. package/src/vocabulary/text.tsx +0 -60
  338. package/src/vocabulary/toTextContent.ts +0 -2
@@ -1,69 +0,0 @@
1
- import { setAtPointer } from "./reducer";
2
-
3
- const isRecord = (value: unknown): value is Record<string, unknown> =>
4
- typeof value === "object" && value !== null && !Array.isArray(value);
5
-
6
- export const equalData = (left: unknown, right: unknown): boolean => {
7
- if (Object.is(left, right)) return true;
8
- if (Array.isArray(left) && Array.isArray(right)) {
9
- return (
10
- left.length === right.length &&
11
- left.every((value, index) => equalData(value, right[index]))
12
- );
13
- }
14
- if (!isRecord(left) || !isRecord(right)) return false;
15
- const keys = Object.keys(left);
16
- return (
17
- keys.length === Object.keys(right).length &&
18
- keys.every(
19
- (key) => Object.hasOwn(right, key) && equalData(left[key], right[key]),
20
- )
21
- );
22
- };
23
-
24
- export const decodePointer = (path: string): string[] => {
25
- if (path === "" || path === "/") return [];
26
- return (path.startsWith("/") ? path.slice(1) : path)
27
- .split("/")
28
- .map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"));
29
- };
30
-
31
- export const resolvePointer = (source: unknown, path: string): unknown => {
32
- let current = source;
33
- for (const segment of decodePointer(path)) {
34
- if (Array.isArray(current)) {
35
- if (!/^(0|[1-9]\d*)$/.test(segment)) return undefined;
36
- current = current[Number(segment)];
37
- continue;
38
- }
39
- if (!isRecord(current) || !Object.hasOwn(current, segment)) {
40
- return undefined;
41
- }
42
- current = current[segment];
43
- }
44
- return current;
45
- };
46
-
47
- export const reconcileDataModel = (
48
- previous: unknown,
49
- incoming: unknown,
50
- local: unknown,
51
- editedPaths: ReadonlySet<string>,
52
- ) => {
53
- let value = incoming;
54
- const retained = new Set<string>();
55
- for (const path of editedPaths) {
56
- if (
57
- equalData(resolvePointer(previous, path), resolvePointer(incoming, path))
58
- ) {
59
- value = setAtPointer(
60
- value,
61
- path,
62
- resolvePointer(local, path),
63
- false,
64
- ).value;
65
- retained.add(path);
66
- }
67
- }
68
- return { incoming, value, editedPaths: retained };
69
- };
@@ -1,422 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { applyA2uiOperations } from "./reducer";
3
- import type { A2uiState, A2uiSurfaceState } from "./types";
4
-
5
- describe("applyA2uiOperations", () => {
6
- it("applies create, component upsert, data model update, and delete operations without mutating prior state", () => {
7
- const initial: A2uiState = new Map();
8
- const created = applyA2uiOperations(initial, [
9
- {
10
- version: "v0.9",
11
- createSurface: { surfaceId: "main", catalogId: "default" },
12
- },
13
- {
14
- version: "v0.9",
15
- updateComponents: {
16
- surfaceId: "main",
17
- components: [
18
- { id: "root", component: "Text", text: "first" },
19
- { id: "root", component: "Text", text: "second" },
20
- ],
21
- },
22
- },
23
- {
24
- version: "v0.9",
25
- updateDataModel: {
26
- surfaceId: "main",
27
- path: "/profile/name",
28
- contents: "Ada",
29
- value: "ignored",
30
- data: "ignored",
31
- },
32
- },
33
- ]);
34
-
35
- expect(initial.size).toBe(0);
36
- expect(created.warnings).toEqual([]);
37
- expect(created.state.get("main")).toMatchObject({
38
- catalogId: "default",
39
- dataModel: { profile: { name: "Ada" } },
40
- });
41
- expect(created.state.get("main")?.components.get("root")).toEqual({
42
- id: "root",
43
- component: "Text",
44
- text: "second",
45
- });
46
-
47
- const removed = applyA2uiOperations(created.state, [
48
- {
49
- version: "v1.0",
50
- deleteSurface: { surfaceId: "main" },
51
- },
52
- ]);
53
-
54
- expect(removed.warnings).toEqual([]);
55
- expect(removed.state.has("main")).toBe(false);
56
- expect(created.state.has("main")).toBe(true);
57
- });
58
-
59
- it("accepts v1.0 inline components and data model as initial state", () => {
60
- const result = applyA2uiOperations(new Map(), [
61
- {
62
- version: "v1.0",
63
- createSurface: {
64
- surfaceId: "inline",
65
- catalogId: "basic",
66
- surfaceProperties: { ignored: true },
67
- sendDataModel: true,
68
- components: [
69
- { id: "root", component: "Text", text: { path: "/message" } },
70
- ],
71
- dataModel: { message: "hello" },
72
- },
73
- },
74
- ]);
75
-
76
- expect(result.warnings).toEqual([]);
77
- expect(result.state.get("inline")).toMatchObject({
78
- catalogId: "basic",
79
- dataModel: { message: "hello" },
80
- });
81
- expect(result.state.get("inline")?.components.get("root")).toEqual({
82
- id: "root",
83
- component: "Text",
84
- text: { path: "/message" },
85
- });
86
- });
87
-
88
- it("keeps a v1.0 catalog id from surface properties", () => {
89
- const result = applyA2uiOperations(new Map(), [
90
- {
91
- version: "v1.0",
92
- createSurface: {
93
- surfaceId: "properties",
94
- surfaceProperties: { catalogId: "basic" },
95
- },
96
- },
97
- ]);
98
-
99
- expect(result.warnings).toEqual([]);
100
- expect(result.state.get("properties")?.catalogId).toBe("basic");
101
- });
102
-
103
- it("applies v0.9.1 operations the way v0.9 does", () => {
104
- const result = applyA2uiOperations(new Map(), [
105
- {
106
- version: "v0.9.1",
107
- createSurface: { surfaceId: "main", catalogId: "basic" },
108
- },
109
- {
110
- version: "v0.9.1",
111
- updateComponents: {
112
- surfaceId: "main",
113
- components: [{ id: "root", component: "Text", text: "hello" }],
114
- },
115
- },
116
- {
117
- version: "v0.9.1",
118
- updateDataModel: {
119
- surfaceId: "main",
120
- path: "/profile/name",
121
- value: "Ada",
122
- },
123
- },
124
- ]);
125
-
126
- expect(result.warnings).toEqual([]);
127
- expect(result.state.get("main")).toMatchObject({
128
- catalogId: "basic",
129
- dataModel: { profile: { name: "Ada" } },
130
- });
131
- expect(result.state.get("main")?.components.get("root")).toEqual({
132
- id: "root",
133
- component: "Text",
134
- text: "hello",
135
- });
136
- });
137
-
138
- it.each(["10001", "4294967294"])(
139
- "rejects array pointer index %s beyond the auto-vivification limit",
140
- (index) => {
141
- const dataModel = { items: [] };
142
- const state: A2uiState = new Map([
143
- ["main", { components: new Map(), dataModel }],
144
- ]);
145
-
146
- const result = applyA2uiOperations(state, [
147
- {
148
- version: "v1.0",
149
- updateDataModel: {
150
- surfaceId: "main",
151
- path: `/items/${index}`,
152
- value: "unsafe",
153
- },
154
- },
155
- ]);
156
-
157
- expect(result.warnings).toEqual([
158
- "Operation at index 0 has an invalid JSON Pointer path.",
159
- ]);
160
- expect(result.state.get("main")?.dataModel).toBe(dataModel);
161
- expect(dataModel.items).toHaveLength(0);
162
- },
163
- );
164
-
165
- it("allows bounded expansion, existing large indices, and appends", () => {
166
- const items = new Array<string | undefined>(10_002);
167
- items[10_001] = "existing";
168
- const state: A2uiState = new Map([
169
- ["main", { components: new Map(), dataModel: { bounded: [], items } }],
170
- ]);
171
-
172
- const result = applyA2uiOperations(state, [
173
- {
174
- version: "v1.0",
175
- updateDataModel: {
176
- surfaceId: "main",
177
- path: "/bounded/10000",
178
- value: "limit",
179
- },
180
- },
181
- {
182
- version: "v1.0",
183
- updateDataModel: {
184
- surfaceId: "main",
185
- path: "/items/10001",
186
- value: "updated",
187
- },
188
- },
189
- {
190
- version: "v1.0",
191
- updateDataModel: {
192
- surfaceId: "main",
193
- path: "/items/-",
194
- value: "appended",
195
- },
196
- },
197
- ]);
198
-
199
- const resultModel = result.state.get("main")!.dataModel as {
200
- bounded: string[];
201
- items: string[];
202
- };
203
- expect(result.warnings).toEqual([]);
204
- expect(resultModel.bounded).toHaveLength(10_001);
205
- expect(resultModel.bounded[10_000]).toBe("limit");
206
- expect(resultModel.items).toHaveLength(10_003);
207
- expect(resultModel.items[10_001]).toBe("updated");
208
- expect(resultModel.items[10_002]).toBe("appended");
209
- });
210
-
211
- it("stores prototype-named JSON Pointer segments as own properties", () => {
212
- const state: A2uiState = new Map([
213
- ["main", { components: new Map(), dataModel: {} }],
214
- ]);
215
-
216
- const result = applyA2uiOperations(state, [
217
- {
218
- version: "v1.0",
219
- updateDataModel: {
220
- surfaceId: "main",
221
- path: "/__proto__/admin",
222
- value: true,
223
- },
224
- },
225
- ]);
226
-
227
- const resultModel = result.state.get("main")?.dataModel as Record<
228
- string,
229
- unknown
230
- >;
231
- expect(result.warnings).toEqual([]);
232
- expect(Object.getPrototypeOf(resultModel)).toBe(Object.prototype);
233
- expect(Object.hasOwn(resultModel, "__proto__")).toBe(true);
234
- expect(resultModel["__proto__"]).toEqual({ admin: true });
235
- expect(JSON.stringify(resultModel)).toBe('{"__proto__":{"admin":true}}');
236
- });
237
-
238
- it("deletes object properties updated to null", () => {
239
- const dataModel = {
240
- profile: { name: "Ada", role: "admin" },
241
- tags: ["first", "second"],
242
- };
243
- const state: A2uiState = new Map([
244
- ["main", { components: new Map(), dataModel }],
245
- ]);
246
-
247
- const result = applyA2uiOperations(state, [
248
- {
249
- version: "v1.0",
250
- updateDataModel: {
251
- surfaceId: "main",
252
- path: "/profile/name",
253
- value: null,
254
- },
255
- },
256
- {
257
- version: "v1.0",
258
- updateDataModel: {
259
- surfaceId: "main",
260
- path: "/tags/1",
261
- value: null,
262
- },
263
- },
264
- ]);
265
-
266
- expect(result.warnings).toEqual([]);
267
- const resultModel = result.state.get("main")?.dataModel as typeof dataModel;
268
- expect(resultModel.profile).toEqual({ role: "admin" });
269
- expect(resultModel.tags).toHaveLength(2);
270
- expect(resultModel.tags[0]).toBe("first");
271
- expect(Object.prototype.hasOwnProperty.call(resultModel.tags, 1)).toBe(
272
- false,
273
- );
274
- expect(dataModel).toEqual({
275
- profile: { name: "Ada", role: "admin" },
276
- tags: ["first", "second"],
277
- });
278
- });
279
-
280
- it("preserves null values in v0.9 data model updates", () => {
281
- const state: A2uiState = new Map([
282
- [
283
- "main",
284
- { components: new Map(), dataModel: { profile: { name: "Ada" } } },
285
- ],
286
- ]);
287
-
288
- const result = applyA2uiOperations(state, [
289
- {
290
- version: "v0.9",
291
- updateDataModel: {
292
- surfaceId: "main",
293
- path: "/profile/name",
294
- value: null,
295
- },
296
- },
297
- ]);
298
-
299
- expect(result.warnings).toEqual([]);
300
- expect(result.state.get("main")?.dataModel).toEqual({
301
- profile: { name: null },
302
- });
303
- });
304
-
305
- it("does not create missing paths for null updates", () => {
306
- const dataModel = { profile: { name: "Ada" }, tags: ["first", "second"] };
307
- const state: A2uiState = new Map([
308
- ["main", { components: new Map(), dataModel }],
309
- ]);
310
-
311
- const result = applyA2uiOperations(state, [
312
- {
313
- version: "v1.0",
314
- updateDataModel: {
315
- surfaceId: "main",
316
- path: "/missing/value",
317
- value: null,
318
- },
319
- },
320
- {
321
- version: "v1.0",
322
- updateDataModel: {
323
- surfaceId: "main",
324
- path: "/tags/-",
325
- value: null,
326
- },
327
- },
328
- {
329
- version: "v1.0",
330
- updateDataModel: {
331
- surfaceId: "main",
332
- path: "/tags/7",
333
- value: null,
334
- },
335
- },
336
- ]);
337
-
338
- expect(result.warnings).toEqual([]);
339
- expect(result.state.get("main")?.dataModel).toBe(dataModel);
340
- });
341
-
342
- it("allows null to replace the data model root", () => {
343
- const state: A2uiState = new Map([
344
- [
345
- "main",
346
- { components: new Map(), dataModel: { profile: { name: "Ada" } } },
347
- ],
348
- ]);
349
-
350
- const result = applyA2uiOperations(state, [
351
- {
352
- version: "v1.0",
353
- updateDataModel: { surfaceId: "main", value: null },
354
- },
355
- ]);
356
-
357
- expect(result.warnings).toEqual([]);
358
- expect(result.state.get("main")?.dataModel).toBeNull();
359
- });
360
-
361
- it("clones the touched surface and component map", () => {
362
- const components = new Map<string, Record<string, unknown>>([
363
- ["root", { id: "root", component: "Divider" }],
364
- ]);
365
- const surface: A2uiSurfaceState = {
366
- components,
367
- dataModel: { value: 1 },
368
- };
369
- const state: A2uiState = new Map([["main", surface]]);
370
-
371
- const result = applyA2uiOperations(state, [
372
- {
373
- version: "v1.0",
374
- updateComponents: {
375
- surfaceId: "main",
376
- components: [{ id: "next", component: "Divider" }],
377
- },
378
- },
379
- ]);
380
-
381
- expect(result.state.get("main")).not.toBe(surface);
382
- expect(result.state.get("main")?.components).not.toBe(components);
383
- expect(components.has("next")).toBe(false);
384
- expect(result.state.get("main")?.components.has("next")).toBe(true);
385
- });
386
-
387
- it("skips unknown operations with a warning naming the key", () => {
388
- const result = applyA2uiOperations(new Map(), [
389
- {
390
- version: "v1.0",
391
- animateSurface: { surfaceId: "main" },
392
- },
393
- ]);
394
-
395
- expect(result.state.size).toBe(0);
396
- expect(result.warnings).toHaveLength(1);
397
- expect(result.warnings[0]).toContain("animateSurface");
398
- });
399
-
400
- it("tolerates non-array input and malformed entries", () => {
401
- const nonArray = applyA2uiOperations(new Map(), { version: "v1.0" });
402
- expect(nonArray.state.size).toBe(0);
403
- expect(nonArray.warnings).toHaveLength(1);
404
-
405
- const malformed = applyA2uiOperations(new Map(), [
406
- null,
407
- 42,
408
- {},
409
- { version: "v2.0", deleteSurface: { surfaceId: "main" } },
410
- {
411
- version: "v1.0",
412
- createSurface: { surfaceId: "main" },
413
- deleteSurface: { surfaceId: "main" },
414
- },
415
- { version: "v1.0", updateComponents: null },
416
- { version: "v1.0", deleteSurface: {} },
417
- ]);
418
-
419
- expect(malformed.state.size).toBe(0);
420
- expect(malformed.warnings).toHaveLength(7);
421
- });
422
- });