@a2ui/web_core 0.9.2 → 0.10.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 (154) hide show
  1. package/.tsbuildinfo +1 -1
  2. package/LICENSE +25 -1
  3. package/README.md +1 -1
  4. package/package.json +1 -1
  5. package/src/v0_8/data/guards.d.ts +1 -1
  6. package/src/v0_8/data/guards.d.ts.map +1 -1
  7. package/src/v0_8/data/guards.js +37 -41
  8. package/src/v0_8/data/guards.js.map +1 -1
  9. package/src/v0_8/data/guards.test.js +51 -51
  10. package/src/v0_8/data/guards.test.js.map +1 -1
  11. package/src/v0_8/data/model-processor.d.ts +1 -1
  12. package/src/v0_8/data/model-processor.d.ts.map +1 -1
  13. package/src/v0_8/data/model-processor.js +85 -88
  14. package/src/v0_8/data/model-processor.js.map +1 -1
  15. package/src/v0_8/data/model-processor.test.js +288 -323
  16. package/src/v0_8/data/model-processor.test.js.map +1 -1
  17. package/src/v0_8/errors.js +5 -5
  18. package/src/v0_8/events/index.d.ts +2 -2
  19. package/src/v0_8/events/index.js +2 -2
  20. package/src/v0_8/events/validation-event.d.ts +4 -4
  21. package/src/v0_8/events/validation-event.d.ts.map +1 -1
  22. package/src/v0_8/events/validation-event.js +1 -1
  23. package/src/v0_8/events/validation-event.js.map +1 -1
  24. package/src/v0_8/index.d.ts +8 -8
  25. package/src/v0_8/index.js +9 -9
  26. package/src/v0_8/index.js.map +1 -1
  27. package/src/v0_8/schema/common-types.d.ts +4 -4
  28. package/src/v0_8/schema/common-types.d.ts.map +1 -1
  29. package/src/v0_8/schema/common-types.js +36 -84
  30. package/src/v0_8/schema/common-types.js.map +1 -1
  31. package/src/v0_8/schema/server-to-client.d.ts +562 -562
  32. package/src/v0_8/schema/server-to-client.d.ts.map +1 -1
  33. package/src/v0_8/schema/server-to-client.js +28 -38
  34. package/src/v0_8/schema/server-to-client.js.map +1 -1
  35. package/src/v0_8/schema/verify-schema.test.js +31 -43
  36. package/src/v0_8/schema/verify-schema.test.js.map +1 -1
  37. package/src/v0_8/schemas/catalog_description_schema.json +1 -5
  38. package/src/v0_8/schemas/client_to_server.json +2 -11
  39. package/src/v0_8/schemas/server_to_client_with_standard_catalog.json +3 -23
  40. package/src/v0_8/schemas/standard_catalog_definition.json +36 -159
  41. package/src/v0_8/styles/behavior.js +1 -1
  42. package/src/v0_8/styles/border.js +2 -2
  43. package/src/v0_8/styles/border.js.map +1 -1
  44. package/src/v0_8/styles/colors.js +13 -13
  45. package/src/v0_8/styles/colors.js.map +1 -1
  46. package/src/v0_8/styles/index.d.ts +1 -1
  47. package/src/v0_8/styles/index.d.ts.map +1 -1
  48. package/src/v0_8/styles/index.js +10 -18
  49. package/src/v0_8/styles/index.js.map +1 -1
  50. package/src/v0_8/styles/layout.d.ts.map +1 -1
  51. package/src/v0_8/styles/layout.js +10 -12
  52. package/src/v0_8/styles/layout.js.map +1 -1
  53. package/src/v0_8/styles/opacity.js +1 -1
  54. package/src/v0_8/styles/styles.test.js +43 -43
  55. package/src/v0_8/styles/styles.test.js.map +1 -1
  56. package/src/v0_8/styles/type.js +1 -1
  57. package/src/v0_8/styles/utils.d.ts +1 -1
  58. package/src/v0_8/styles/utils.d.ts.map +1 -1
  59. package/src/v0_8/styles/utils.js +4 -4
  60. package/src/v0_8/styles/utils.js.map +1 -1
  61. package/src/v0_8/types/client-event.d.ts.map +1 -1
  62. package/src/v0_8/types/colors.d.ts +13 -13
  63. package/src/v0_8/types/colors.d.ts.map +1 -1
  64. package/src/v0_8/types/components.d.ts +2 -2
  65. package/src/v0_8/types/components.d.ts.map +1 -1
  66. package/src/v0_8/types/primitives.d.ts +2 -2
  67. package/src/v0_8/types/primitives.d.ts.map +1 -1
  68. package/src/v0_8/types/types.d.ts +32 -32
  69. package/src/v0_8/types/types.d.ts.map +1 -1
  70. package/src/v0_9/basic_catalog/components/basic_components.d.ts +84 -68
  71. package/src/v0_9/basic_catalog/components/basic_components.d.ts.map +1 -1
  72. package/src/v0_9/basic_catalog/components/basic_components.js +17 -46
  73. package/src/v0_9/basic_catalog/components/basic_components.js.map +1 -1
  74. package/src/v0_9/basic_catalog/expressions/expression_parser.d.ts.map +1 -1
  75. package/src/v0_9/basic_catalog/expressions/expression_parser.js +5 -11
  76. package/src/v0_9/basic_catalog/expressions/expression_parser.js.map +1 -1
  77. package/src/v0_9/basic_catalog/expressions/expression_parser.test.js +6 -26
  78. package/src/v0_9/basic_catalog/expressions/expression_parser.test.js.map +1 -1
  79. package/src/v0_9/basic_catalog/functions/basic_functions.d.ts.map +1 -1
  80. package/src/v0_9/basic_catalog/functions/basic_functions.js.map +1 -1
  81. package/src/v0_9/basic_catalog/functions/basic_functions.test.js +1 -3
  82. package/src/v0_9/basic_catalog/functions/basic_functions.test.js.map +1 -1
  83. package/src/v0_9/basic_catalog/functions/basic_functions_api.d.ts.map +1 -1
  84. package/src/v0_9/basic_catalog/functions/basic_functions_api.js.map +1 -1
  85. package/src/v0_9/basic_catalog/index.d.ts +2 -1
  86. package/src/v0_9/basic_catalog/index.d.ts.map +1 -1
  87. package/src/v0_9/basic_catalog/index.js +1 -1
  88. package/src/v0_9/basic_catalog/index.js.map +1 -1
  89. package/src/v0_9/basic_catalog/styles/default.d.ts +34 -0
  90. package/src/v0_9/basic_catalog/styles/default.d.ts.map +1 -1
  91. package/src/v0_9/basic_catalog/styles/default.js +29 -6
  92. package/src/v0_9/basic_catalog/styles/default.js.map +1 -1
  93. package/src/v0_9/catalog/types.d.ts.map +1 -1
  94. package/src/v0_9/catalog/types.js.map +1 -1
  95. package/src/v0_9/catalog/types.test.js.map +1 -1
  96. package/src/v0_9/processing/message-processor.d.ts.map +1 -1
  97. package/src/v0_9/processing/message-processor.js +1 -2
  98. package/src/v0_9/processing/message-processor.js.map +1 -1
  99. package/src/v0_9/processing/message-processor.test.js +7 -19
  100. package/src/v0_9/processing/message-processor.test.js.map +1 -1
  101. package/src/v0_9/reactivity/signals.test.d.ts.map +1 -1
  102. package/src/v0_9/reactivity/signals.test.js +1 -1
  103. package/src/v0_9/reactivity/signals.test.js.map +1 -1
  104. package/src/v0_9/rendering/component-context.d.ts.map +1 -1
  105. package/src/v0_9/rendering/component-context.js.map +1 -1
  106. package/src/v0_9/rendering/data-context.d.ts.map +1 -1
  107. package/src/v0_9/rendering/data-context.js.map +1 -1
  108. package/src/v0_9/rendering/data-context.test.js +1 -4
  109. package/src/v0_9/rendering/data-context.test.js.map +1 -1
  110. package/src/v0_9/rendering/generic-binder.d.ts.map +1 -1
  111. package/src/v0_9/rendering/generic-binder.js +9 -17
  112. package/src/v0_9/rendering/generic-binder.js.map +1 -1
  113. package/src/v0_9/rendering/generic-binder.test.js +3 -9
  114. package/src/v0_9/rendering/generic-binder.test.js.map +1 -1
  115. package/src/v0_9/schema/client-capabilities.d.ts.map +1 -1
  116. package/src/v0_9/schema/client-to-server.d.ts +52 -52
  117. package/src/v0_9/schema/client-to-server.d.ts.map +1 -1
  118. package/src/v0_9/schema/client-to-server.js +7 -24
  119. package/src/v0_9/schema/client-to-server.js.map +1 -1
  120. package/src/v0_9/schema/client-to-server.test.js +1 -1
  121. package/src/v0_9/schema/client-to-server.test.js.map +1 -1
  122. package/src/v0_9/schema/common-types.d.ts +2 -0
  123. package/src/v0_9/schema/common-types.d.ts.map +1 -1
  124. package/src/v0_9/schema/common-types.js +4 -13
  125. package/src/v0_9/schema/common-types.js.map +1 -1
  126. package/src/v0_9/schema/server-to-client.d.ts +28 -28
  127. package/src/v0_9/schema/server-to-client.d.ts.map +1 -1
  128. package/src/v0_9/schema/server-to-client.js +6 -19
  129. package/src/v0_9/schema/server-to-client.js.map +1 -1
  130. package/src/v0_9/schema/verify-schema.test.js +4 -16
  131. package/src/v0_9/schema/verify-schema.test.js.map +1 -1
  132. package/src/v0_9/schemas/basic_catalog.json +6 -10
  133. package/src/v0_9/schemas/client_capabilities.json +1 -9
  134. package/src/v0_9/schemas/client_to_server.json +1 -7
  135. package/src/v0_9/schemas/client_to_server_list_wrapper.json +1 -3
  136. package/src/v0_9/schemas/common_types.json +2 -12
  137. package/src/v0_9/schemas/server_to_client.json +1 -1
  138. package/src/v0_9/schemas/server_to_client_list_wrapper.json +1 -3
  139. package/src/v0_9/state/data-model.d.ts.map +1 -1
  140. package/src/v0_9/state/data-model.js +1 -2
  141. package/src/v0_9/state/data-model.js.map +1 -1
  142. package/src/v0_9/state/data-model.test.js.map +1 -1
  143. package/src/v0_9/state/surface-components-model.d.ts.map +1 -1
  144. package/src/v0_9/state/surface-components-model.js.map +1 -1
  145. package/src/v0_9/state/surface-group-model.d.ts.map +1 -1
  146. package/src/v0_9/state/surface-group-model.js.map +1 -1
  147. package/src/v0_9/state/surface-model.d.ts +1 -1
  148. package/src/v0_9/state/surface-model.d.ts.map +1 -1
  149. package/src/v0_9/state/surface-model.js +2 -5
  150. package/src/v0_9/state/surface-model.js.map +1 -1
  151. package/src/v0_9/state/surface-model.test.js.map +1 -1
  152. package/src/v0_9/test/function_execution.spec.js.map +1 -1
  153. package/src/v0_9/test/test-utils.d.ts.map +1 -1
  154. package/src/v0_9/test/test-utils.js.map +1 -1
@@ -13,139 +13,143 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import assert from "node:assert";
17
- import { describe, it, beforeEach } from "node:test";
18
- import { A2uiMessageProcessor } from "./model-processor.js";
19
- describe("A2uiMessageProcessor", () => {
16
+ import assert from 'node:assert';
17
+ import { describe, it, beforeEach } from 'node:test';
18
+ import { A2uiMessageProcessor } from './model-processor.js';
19
+ describe('A2uiMessageProcessor', () => {
20
20
  let processor;
21
21
  beforeEach(() => {
22
22
  processor = new A2uiMessageProcessor();
23
23
  });
24
- it("handles beginRendering", () => {
24
+ it('handles beginRendering', () => {
25
25
  processor.processMessages([
26
26
  {
27
27
  beginRendering: {
28
- surfaceId: "s1",
29
- root: "root",
30
- styles: { font: "Arial" },
28
+ surfaceId: 's1',
29
+ root: 'root',
30
+ styles: { font: 'Arial' },
31
31
  },
32
32
  },
33
33
  ]);
34
34
  const surfaces = processor.getSurfaces();
35
- const surface = surfaces.get("s1");
35
+ const surface = surfaces.get('s1');
36
36
  assert.ok(surface);
37
- assert.strictEqual(surface.rootComponentId, "root");
38
- assert.deepStrictEqual(surface.styles, { font: "Arial" });
37
+ assert.strictEqual(surface.rootComponentId, 'root');
38
+ assert.deepStrictEqual(surface.styles, { font: 'Arial' });
39
39
  // The component tree remains null until components are added via surfaceUpdate.
40
40
  assert.strictEqual(surface.componentTree, null);
41
41
  });
42
- it("handles surfaceUpdate", () => {
42
+ it('handles surfaceUpdate', () => {
43
43
  processor.processMessages([
44
44
  {
45
- beginRendering: { surfaceId: "s1", root: "root" },
45
+ beginRendering: { surfaceId: 's1', root: 'root' },
46
46
  },
47
47
  ]);
48
48
  processor.processMessages([
49
49
  {
50
50
  surfaceUpdate: {
51
- surfaceId: "s1",
51
+ surfaceId: 's1',
52
52
  components: [
53
53
  {
54
- id: "root",
54
+ id: 'root',
55
55
  component: {
56
- Text: { text: { literal: "Hello" }, usageHint: "body" },
56
+ Text: { text: { literal: 'Hello' }, usageHint: 'body' },
57
57
  },
58
58
  },
59
59
  ],
60
60
  },
61
61
  },
62
62
  ]);
63
- const surface = processor.getSurfaces().get("s1");
63
+ const surface = processor.getSurfaces().get('s1');
64
64
  assert.ok(surface);
65
65
  assert.ok(surface.componentTree);
66
66
  const root = surface.componentTree;
67
- assert.strictEqual(root.id, "root");
68
- assert.strictEqual(root.type, "Text");
67
+ assert.strictEqual(root.id, 'root');
68
+ assert.strictEqual(root.type, 'Text');
69
69
  // The property preserves the literal wrapper
70
- assert.deepStrictEqual(root.properties.text, { literal: "Hello" });
70
+ assert.deepStrictEqual(root.properties.text, { literal: 'Hello' });
71
71
  });
72
- it("handles dataModelUpdate", () => {
72
+ it('handles dataModelUpdate', () => {
73
73
  processor.processMessages([
74
74
  {
75
- beginRendering: { surfaceId: "s1", root: "root" },
75
+ beginRendering: { surfaceId: 's1', root: 'root' },
76
76
  },
77
77
  {
78
78
  dataModelUpdate: {
79
- surfaceId: "s1",
80
- contents: [{ key: "message", valueString: "World" }],
79
+ surfaceId: 's1',
80
+ contents: [{ key: 'message', valueString: 'World' }],
81
81
  },
82
82
  },
83
83
  ]);
84
- const surface = processor.getSurfaces().get("s1");
85
- assert.strictEqual(surface?.dataModel.get("message"), "World");
84
+ const surface = processor.getSurfaces().get('s1');
85
+ assert.strictEqual(surface?.dataModel.get('message'), 'World');
86
86
  });
87
- it("handles deleteSurface", () => {
87
+ it('handles deleteSurface', () => {
88
88
  processor.processMessages([
89
89
  {
90
- beginRendering: { surfaceId: "s1", root: "root" },
90
+ beginRendering: { surfaceId: 's1', root: 'root' },
91
91
  },
92
92
  ]);
93
- assert.ok(processor.getSurfaces().has("s1"));
93
+ assert.ok(processor.getSurfaces().has('s1'));
94
94
  processor.processMessages([
95
95
  {
96
- deleteSurface: { surfaceId: "s1" },
96
+ deleteSurface: { surfaceId: 's1' },
97
97
  },
98
98
  ]);
99
- assert.ok(!processor.getSurfaces().has("s1"));
99
+ assert.ok(!processor.getSurfaces().has('s1'));
100
100
  });
101
- it("resolves component references (children)", () => {
101
+ it('resolves component references (children)', () => {
102
102
  processor.processMessages([
103
- { beginRendering: { surfaceId: "s1", root: "row" } },
103
+ { beginRendering: { surfaceId: 's1', root: 'row' } },
104
104
  {
105
105
  surfaceUpdate: {
106
- surfaceId: "s1",
106
+ surfaceId: 's1',
107
107
  components: [
108
108
  {
109
- id: "row",
109
+ id: 'row',
110
110
  component: {
111
- Row: { children: { explicitList: ["t1", "t2"] } },
111
+ Row: { children: { explicitList: ['t1', 't2'] } },
112
112
  },
113
113
  },
114
114
  {
115
- id: "t1",
115
+ id: 't1',
116
116
  component: {
117
- Text: { text: { literal: "One" }, usageHint: "body" },
117
+ Text: { text: { literal: 'One' }, usageHint: 'body' },
118
118
  },
119
119
  },
120
120
  {
121
- id: "t2",
121
+ id: 't2',
122
122
  component: {
123
- Text: { text: { literal: "Two" }, usageHint: "body" },
123
+ Text: { text: { literal: 'Two' }, usageHint: 'body' },
124
124
  },
125
125
  },
126
126
  ],
127
127
  },
128
128
  },
129
129
  ]);
130
- const surface = processor.getSurfaces().get("s1");
130
+ const surface = processor.getSurfaces().get('s1');
131
131
  const root = surface?.componentTree;
132
- assert.strictEqual(root.type, "Row");
132
+ assert.strictEqual(root.type, 'Row');
133
133
  assert.strictEqual(root.properties.children.length, 2);
134
- assert.deepStrictEqual(root.properties.children[0].properties.text, { literal: "One" });
135
- assert.deepStrictEqual(root.properties.children[1].properties.text, { literal: "Two" });
134
+ assert.deepStrictEqual(root.properties.children[0].properties.text, {
135
+ literal: 'One',
136
+ });
137
+ assert.deepStrictEqual(root.properties.children[1].properties.text, {
138
+ literal: 'Two',
139
+ });
136
140
  });
137
- it("resolves templates", () => {
141
+ it('resolves templates', () => {
138
142
  processor.processMessages([
139
- { beginRendering: { surfaceId: "s1", root: "row" } },
143
+ { beginRendering: { surfaceId: 's1', root: 'row' } },
140
144
  {
141
145
  dataModelUpdate: {
142
- surfaceId: "s1",
146
+ surfaceId: 's1',
143
147
  contents: [
144
148
  {
145
- key: "items",
149
+ key: 'items',
146
150
  valueMap: [
147
- { key: "0", valueString: "Item A" },
148
- { key: "1", valueString: "Item B" },
151
+ { key: '0', valueString: 'Item A' },
152
+ { key: '1', valueString: 'Item B' },
149
153
  ],
150
154
  },
151
155
  ],
@@ -153,40 +157,40 @@ describe("A2uiMessageProcessor", () => {
153
157
  },
154
158
  {
155
159
  surfaceUpdate: {
156
- surfaceId: "s1",
160
+ surfaceId: 's1',
157
161
  components: [
158
162
  {
159
- id: "row",
163
+ id: 'row',
160
164
  component: {
161
165
  Row: {
162
166
  children: {
163
167
  template: {
164
- componentId: "item",
165
- dataBinding: "/items",
168
+ componentId: 'item',
169
+ dataBinding: '/items',
166
170
  },
167
171
  },
168
172
  },
169
173
  },
170
174
  },
171
175
  {
172
- id: "item",
176
+ id: 'item',
173
177
  component: {
174
- Text: { text: { path: "." }, usageHint: "body" },
178
+ Text: { text: { path: '.' }, usageHint: 'body' },
175
179
  },
176
180
  },
177
181
  ],
178
182
  },
179
183
  },
180
184
  ]);
181
- const surface = processor.getSurfaces().get("s1");
185
+ const surface = processor.getSurfaces().get('s1');
182
186
  const root = surface?.componentTree;
183
- assert.strictEqual(root.type, "Row");
187
+ assert.strictEqual(root.type, 'Row');
184
188
  assert.strictEqual(root.properties.children.length, 2);
185
189
  // Verify template expansion
186
190
  const child0 = root.properties.children[0];
187
191
  const child1 = root.properties.children[1];
188
192
  // Check that binding paths are correct (processor does NOT resolve the value, just the binding path context)
189
- assert.deepStrictEqual(child0.properties.text, { path: "." });
193
+ assert.deepStrictEqual(child0.properties.text, { path: '.' });
190
194
  // Now verify we can resolve the data using the node's context
191
195
  const textProp0 = child0.properties.text;
192
196
  const resolvedValue0 = processor.getData(child0, textProp0.path, 's1');
@@ -195,178 +199,162 @@ describe("A2uiMessageProcessor", () => {
195
199
  const resolvedValue1 = processor.getData(child1, textProp1.path, 's1');
196
200
  assert.strictEqual(resolvedValue1, 'Item B');
197
201
  });
198
- it("getData resolves paths relative to node context", () => {
202
+ it('getData resolves paths relative to node context', () => {
199
203
  processor.processMessages([
200
- { beginRendering: { surfaceId: "s1", root: "root" } },
204
+ { beginRendering: { surfaceId: 's1', root: 'root' } },
201
205
  {
202
206
  dataModelUpdate: {
203
- surfaceId: "s1",
204
- contents: [
205
- { key: "user", valueMap: [{ key: "name", valueString: "Alice" }] },
206
- ],
207
+ surfaceId: 's1',
208
+ contents: [{ key: 'user', valueMap: [{ key: 'name', valueString: 'Alice' }] }],
207
209
  },
208
210
  },
209
211
  ]);
210
- processor.getSurfaces().get("s1");
211
- const node = { id: "test", dataContextPath: "/user" };
212
- const name = processor.getData(node, "name", "s1");
213
- assert.strictEqual(name, "Alice");
214
- const self = processor.getData(node, ".", "s1");
212
+ processor.getSurfaces().get('s1');
213
+ const node = { id: 'test', dataContextPath: '/user' };
214
+ const name = processor.getData(node, 'name', 's1');
215
+ assert.strictEqual(name, 'Alice');
216
+ const self = processor.getData(node, '.', 's1');
215
217
  assert.ok(self instanceof Map);
216
- assert.strictEqual(self.get("name"), "Alice");
217
- const rootData = processor.getData(node, "/user/name", "s1");
218
- assert.strictEqual(rootData, "Alice");
218
+ assert.strictEqual(self.get('name'), 'Alice');
219
+ const rootData = processor.getData(node, '/user/name', 's1');
220
+ assert.strictEqual(rootData, 'Alice');
219
221
  });
220
- it("setData updates data model", () => {
221
- processor.processMessages([
222
- { beginRendering: { surfaceId: "s1", root: "root" } },
223
- ]);
224
- const surface = processor.getSurfaces().get("s1");
225
- const node = { id: "test", dataContextPath: "/" };
226
- processor.setData(node, "count", 42, "s1");
227
- assert.strictEqual(surface?.dataModel.get("count"), 42);
228
- processor.setData(node, "/nested/value", "foo", "s1");
229
- const nested = surface?.dataModel.get("nested");
230
- assert.strictEqual(nested.get("value"), "foo");
222
+ it('setData updates data model', () => {
223
+ processor.processMessages([{ beginRendering: { surfaceId: 's1', root: 'root' } }]);
224
+ const surface = processor.getSurfaces().get('s1');
225
+ const node = { id: 'test', dataContextPath: '/' };
226
+ processor.setData(node, 'count', 42, 's1');
227
+ assert.strictEqual(surface?.dataModel.get('count'), 42);
228
+ processor.setData(node, '/nested/value', 'foo', 's1');
229
+ const nested = surface?.dataModel.get('nested');
230
+ assert.strictEqual(nested.get('value'), 'foo');
231
231
  });
232
- it("normalizes paths correctly", () => {
233
- const p = processor.normalizePath("users[0].name");
234
- assert.strictEqual(p, "/users/0/name");
232
+ it('normalizes paths correctly', () => {
233
+ const p = processor.normalizePath('users[0].name');
234
+ assert.strictEqual(p, '/users/0/name');
235
235
  });
236
- it("parses JSON strings in data", () => {
237
- processor.processMessages([
238
- { beginRendering: { surfaceId: "s1", root: "root" } },
239
- ]);
236
+ it('parses JSON strings in data', () => {
237
+ processor.processMessages([{ beginRendering: { surfaceId: 's1', root: 'root' } }]);
240
238
  // Explicitly testing private/internal parsing logic via public update
241
239
  processor.processMessages([
242
240
  {
243
241
  dataModelUpdate: {
244
- surfaceId: "s1",
245
- contents: [{ key: "config", valueString: '{"theme":"dark"}' }],
242
+ surfaceId: 's1',
243
+ contents: [{ key: 'config', valueString: '{"theme":"dark"}' }],
246
244
  },
247
245
  },
248
246
  ]);
249
- const surface = processor.getSurfaces().get("s1");
250
- const config = surface?.dataModel.get("config");
251
- assert.deepStrictEqual(config, { theme: "dark" });
247
+ const surface = processor.getSurfaces().get('s1');
248
+ const config = surface?.dataModel.get('config');
249
+ assert.deepStrictEqual(config, { theme: 'dark' });
252
250
  });
253
- it("test basic edge cases and internal fallbacks", () => {
251
+ it('test basic edge cases and internal fallbacks', () => {
254
252
  // 1. clearSurfaces
255
- processor.processMessages([
256
- { beginRendering: { surfaceId: "s1", root: "root" } },
257
- ]);
253
+ processor.processMessages([{ beginRendering: { surfaceId: 's1', root: 'root' } }]);
258
254
  assert.strictEqual(processor.getSurfaces().size, 1);
259
255
  processor.clearSurfaces();
260
256
  assert.strictEqual(processor.getSurfaces().size, 0);
261
257
  // 2. setData with null node
262
- processor.processMessages([
263
- { beginRendering: { surfaceId: "s1", root: "root" } },
264
- ]);
258
+ processor.processMessages([{ beginRendering: { surfaceId: 's1', root: 'root' } }]);
265
259
  // Shouldn't throw
266
- processor.setData(null, "foo", "bar");
260
+ processor.setData(null, 'foo', 'bar');
267
261
  // 3. setData with default data context (default to /)
268
- const node = { id: "test", dataContextPath: undefined };
269
- processor.setData(node, ".", "value");
270
- const surface = processor.getSurfaces().get("s1");
271
- assert.strictEqual(surface.dataModel.get("."), undefined); // Normal setDataByPath logic when root=/
262
+ const node = { id: 'test', dataContextPath: undefined };
263
+ processor.setData(node, '.', 'value');
264
+ const surface = processor.getSurfaces().get('s1');
265
+ assert.strictEqual(surface.dataModel.get('.'), undefined); // Normal setDataByPath logic when root=/
272
266
  // 4. parseIfJsonString with invalid JSON layout
273
267
  processor.processMessages([
274
268
  {
275
269
  dataModelUpdate: {
276
- surfaceId: "s1",
277
- contents: [{ key: "badJson", valueString: '{bad" }' }],
270
+ surfaceId: 's1',
271
+ contents: [{ key: 'badJson', valueString: '{bad" }' }],
278
272
  },
279
273
  },
280
274
  ]);
281
- assert.strictEqual(surface.dataModel.get("badJson"), '{bad" }'); // Returns original
275
+ assert.strictEqual(surface.dataModel.get('badJson'), '{bad" }'); // Returns original
282
276
  // 5. convertKeyValueArrayToMap with missing valueKey
283
277
  // Explicit array pass directly to internal mapping simulation
284
- processor.setDataByPath(surface.dataModel, "malformed", [
285
- { key: "foo", unknownKey: "bar" }, // missing value map/string etc
278
+ processor.setDataByPath(surface.dataModel, 'malformed', [
279
+ { key: 'foo', unknownKey: 'bar' }, // missing value map/string etc
286
280
  ]);
287
- const malformed = surface.dataModel.get("malformed");
288
- assert.strictEqual(malformed.has("foo"), false); // Skips processing
281
+ const malformed = surface.dataModel.get('malformed');
282
+ assert.strictEqual(malformed.has('foo'), false); // Skips processing
289
283
  // 6. object normalization at root
290
- processor.setDataByPath(surface.dataModel, "/", {
291
- plain: "object",
284
+ processor.setDataByPath(surface.dataModel, '/', {
285
+ plain: 'object',
292
286
  });
293
- assert.strictEqual(surface.dataModel.get("plain"), "object");
287
+ assert.strictEqual(surface.dataModel.get('plain'), 'object');
294
288
  // 7. non-map/object root fails gracefully
295
- processor.setDataByPath(surface.dataModel, "/", "stringroot");
289
+ processor.setDataByPath(surface.dataModel, '/', 'stringroot');
296
290
  // Doesn't explode, just prints error internally
297
291
  });
298
- it("test array set operations and invalid primitive traversal", () => {
299
- processor.processMessages([
300
- { beginRendering: { surfaceId: "s1", root: "root" } },
301
- ]);
302
- const surface = processor.getSurfaces().get("s1");
292
+ it('test array set operations and invalid primitive traversal', () => {
293
+ processor.processMessages([{ beginRendering: { surfaceId: 's1', root: 'root' } }]);
294
+ const surface = processor.getSurfaces().get('s1');
303
295
  // Manually set an array to avoid empty array being converted to Map
304
- surface.dataModel.set("list", ["dummy"]);
296
+ surface.dataModel.set('list', ['dummy']);
305
297
  // Now it's an array at /list, set something deep inside it
306
- processor.setDataByPath(surface.dataModel, "/list/0/name", "Alice");
298
+ processor.setDataByPath(surface.dataModel, '/list/0/name', 'Alice');
307
299
  // Also test setting a value directly on an array index
308
- processor.setDataByPath(surface.dataModel, "/list/1", "Bob");
309
- const list = surface.dataModel.get("list");
310
- assert.strictEqual(list[0].get("name"), "Alice"); // It creates a Map for `name`
311
- assert.strictEqual(list[1], "Bob");
300
+ processor.setDataByPath(surface.dataModel, '/list/1', 'Bob');
301
+ const list = surface.dataModel.get('list');
302
+ assert.strictEqual(list[0].get('name'), 'Alice'); // It creates a Map for `name`
303
+ assert.strictEqual(list[1], 'Bob');
312
304
  // Test getDataByPath failing traversal over a primitive
313
- processor.setDataByPath(surface.dataModel, "/primitive", "hello");
314
- const result = processor.getDataByPath(surface.dataModel, "/primitive/invalid");
305
+ processor.setDataByPath(surface.dataModel, '/primitive', 'hello');
306
+ const result = processor.getDataByPath(surface.dataModel, '/primitive/invalid');
315
307
  assert.strictEqual(result, null);
316
308
  });
317
- it("test tree rebuilding edge cases", () => {
318
- processor.processMessages([
319
- { beginRendering: { surfaceId: "s_tree", root: "root" } },
320
- ]);
321
- const surface = processor.getSurfaces().get("s_tree");
309
+ it('test tree rebuilding edge cases', () => {
310
+ processor.processMessages([{ beginRendering: { surfaceId: 's_tree', root: 'root' } }]);
311
+ const surface = processor.getSurfaces().get('s_tree');
322
312
  // 1. rebuildComponentTree without rootComponentId
323
313
  surface.rootComponentId = null;
324
314
  processor.rebuildComponentTree(surface);
325
315
  assert.strictEqual(surface.componentTree, null);
326
316
  // 2. Circular dependency
327
- surface.rootComponentId = "circleA";
328
- surface.components.set("circleA", {
329
- id: "circleA",
330
- component: { Row: { children: ["circleB"] } },
317
+ surface.rootComponentId = 'circleA';
318
+ surface.components.set('circleA', {
319
+ id: 'circleA',
320
+ component: { Row: { children: ['circleB'] } },
331
321
  });
332
- surface.components.set("circleB", {
333
- id: "circleB",
334
- component: { Row: { children: ["circleA"] } },
322
+ surface.components.set('circleB', {
323
+ id: 'circleB',
324
+ component: { Row: { children: ['circleA'] } },
335
325
  });
336
326
  assert.throws(() => {
337
327
  processor.rebuildComponentTree(surface);
338
328
  }, /Circular dependency/);
339
329
  });
340
- it("throws A2uiValidationError for malformed components", () => {
341
- processor.processMessages([
342
- { beginRendering: { surfaceId: `s_bad_comp`, root: "bad" } },
343
- ]);
344
- const surface = processor.getSurfaces().get("s_bad_comp");
345
- surface.rootComponentId = "bad";
330
+ it('throws A2uiValidationError for malformed components', () => {
331
+ processor.processMessages([{ beginRendering: { surfaceId: `s_bad_comp`, root: 'bad' } }]);
332
+ const surface = processor.getSurfaces().get('s_bad_comp');
333
+ surface.rootComponentId = 'bad';
346
334
  // Divider is omitted here because it has no required fields, so `{}` is valid.
347
335
  const types = [
348
- "Text",
349
- "Image",
350
- "Icon",
351
- "Video",
352
- "AudioPlayer",
353
- "Row",
354
- "Column",
355
- "List",
356
- "Card",
357
- "Tabs",
358
- "Modal",
359
- "Button",
360
- "CheckBox",
361
- "TextField",
362
- "DateTimeInput",
363
- "MultipleChoice",
364
- "Slider",
336
+ 'Text',
337
+ 'Image',
338
+ 'Icon',
339
+ 'Video',
340
+ 'AudioPlayer',
341
+ 'Row',
342
+ 'Column',
343
+ 'List',
344
+ 'Card',
345
+ 'Tabs',
346
+ 'Modal',
347
+ 'Button',
348
+ 'CheckBox',
349
+ 'TextField',
350
+ 'DateTimeInput',
351
+ 'MultipleChoice',
352
+ 'Slider',
365
353
  ];
366
354
  for (const type of types) {
367
355
  assert.throws(() => {
368
- surface.components.set("bad", {
369
- id: "bad",
356
+ surface.components.set('bad', {
357
+ id: 'bad',
370
358
  component: {
371
359
  [type]: {
372
360
  /* missing required fields */
@@ -377,334 +365,311 @@ describe("A2uiMessageProcessor", () => {
377
365
  }, /Invalid data; expected/);
378
366
  }
379
367
  // Default catch-all (doesn't throw, just passes it through)
380
- surface.components.set("bad", {
381
- id: "bad",
382
- component: { CustomWidget: { foo: "bar" } },
368
+ surface.components.set('bad', {
369
+ id: 'bad',
370
+ component: { CustomWidget: { foo: 'bar' } },
383
371
  });
384
372
  processor.rebuildComponentTree(surface);
385
- assert.strictEqual(surface.componentTree.type, "CustomWidget");
373
+ assert.strictEqual(surface.componentTree.type, 'CustomWidget');
386
374
  });
387
- it("resolves Template with Array data", () => {
375
+ it('resolves Template with Array data', () => {
388
376
  processor.processMessages([
389
- { beginRendering: { surfaceId: "s3_arr", root: "list" } },
377
+ { beginRendering: { surfaceId: 's3_arr', root: 'list' } },
390
378
  {
391
379
  dataModelUpdate: {
392
- surfaceId: "s3_arr",
393
- path: "/items",
380
+ surfaceId: 's3_arr',
381
+ path: '/items',
394
382
  contents: [
395
- { key: "0", valueString: "a" },
396
- { key: "1", valueString: "b" },
383
+ { key: '0', valueString: 'a' },
384
+ { key: '1', valueString: 'b' },
397
385
  ],
398
386
  },
399
387
  },
400
388
  ]);
401
- const surface = processor.getSurfaces().get("s3_arr");
402
- surface.components.set("list", {
403
- id: "list",
389
+ const surface = processor.getSurfaces().get('s3_arr');
390
+ surface.components.set('list', {
391
+ id: 'list',
404
392
  component: {
405
393
  List: {
406
394
  children: {
407
- template: { dataBinding: "/items", componentId: "item" },
395
+ template: { dataBinding: '/items', componentId: 'item' },
408
396
  },
409
397
  },
410
398
  },
411
399
  });
412
- surface.components.set("item", {
413
- id: "item",
400
+ surface.components.set('item', {
401
+ id: 'item',
414
402
  component: {
415
- Text: { text: { literalString: "hello" }, usageHint: "body" },
403
+ Text: { text: { literalString: 'hello' }, usageHint: 'body' },
416
404
  },
417
405
  });
418
406
  processor.rebuildComponentTree(surface);
419
407
  const root = surface.componentTree;
420
408
  assert.strictEqual(root.properties.children.length, 2);
421
- assert.strictEqual(root.properties.children[0].id, "item:0");
422
- assert.strictEqual(root.properties.children[0].dataContextPath, "/items/0");
423
- assert.strictEqual(root.properties.children[1].id, "item:1");
424
- assert.strictEqual(root.properties.children[1].dataContextPath, "/items/1");
409
+ assert.strictEqual(root.properties.children[0].id, 'item:0');
410
+ assert.strictEqual(root.properties.children[0].dataContextPath, '/items/0');
411
+ assert.strictEqual(root.properties.children[1].id, 'item:1');
412
+ assert.strictEqual(root.properties.children[1].dataContextPath, '/items/1');
425
413
  });
426
- it("resolves Template with undefined/null data as empty array", () => {
427
- processor.processMessages([
428
- { beginRendering: { surfaceId: "s3_null", root: "list" } },
429
- ]);
430
- const surface = processor.getSurfaces().get("s3_null");
431
- surface.components.set("list", {
432
- id: "list",
414
+ it('resolves Template with undefined/null data as empty array', () => {
415
+ processor.processMessages([{ beginRendering: { surfaceId: 's3_null', root: 'list' } }]);
416
+ const surface = processor.getSurfaces().get('s3_null');
417
+ surface.components.set('list', {
418
+ id: 'list',
433
419
  component: {
434
420
  List: {
435
421
  children: {
436
- template: { dataBinding: "/missingItems", componentId: "item" },
422
+ template: { dataBinding: '/missingItems', componentId: 'item' },
437
423
  },
438
424
  },
439
425
  },
440
426
  });
441
- surface.components.set("item", {
442
- id: "item",
427
+ surface.components.set('item', {
428
+ id: 'item',
443
429
  component: {
444
- Text: { text: { literalString: "hello" }, usageHint: "body" },
430
+ Text: { text: { literalString: 'hello' }, usageHint: 'body' },
445
431
  },
446
432
  });
447
433
  processor.rebuildComponentTree(surface);
448
434
  const root = surface.componentTree;
449
435
  assert.deepStrictEqual(root.properties.children, []);
450
436
  });
451
- it("sets primitive at path via single array element with dot key", () => {
437
+ it('sets primitive at path via single array element with dot key', () => {
452
438
  processor.processMessages([
453
- { beginRendering: { surfaceId: "s1_prim", root: "list" } },
439
+ { beginRendering: { surfaceId: 's1_prim', root: 'list' } },
454
440
  {
455
441
  dataModelUpdate: {
456
- surfaceId: "s1_prim",
457
- path: "/nested/item",
458
- contents: [{ key: ".", valueString: "hello" }],
442
+ surfaceId: 's1_prim',
443
+ path: '/nested/item',
444
+ contents: [{ key: '.', valueString: 'hello' }],
459
445
  },
460
446
  },
461
447
  ]);
462
- const surface = processor.getSurfaces().get("s1_prim");
463
- surface.components.set("list", {
464
- id: "list",
448
+ const surface = processor.getSurfaces().get('s1_prim');
449
+ surface.components.set('list', {
450
+ id: 'list',
465
451
  component: { Row: { children: { explicitList: [] } } },
466
452
  });
467
453
  processor.rebuildComponentTree(surface);
468
454
  const root = surface.componentTree;
469
- assert.strictEqual(processor.getData(root, "/nested/item", "s1_prim"), "hello");
455
+ assert.strictEqual(processor.getData(root, '/nested/item', 's1_prim'), 'hello');
470
456
  // Test the fallback where valueString is absent but we pass something anyway
471
457
  assert.throws(() => {
472
458
  processor.processMessages([
473
459
  {
474
460
  dataModelUpdate: {
475
- surfaceId: "s1_prim",
476
- path: "/nested/malformed",
477
- contents: [{ key: "." }],
461
+ surfaceId: 's1_prim',
462
+ path: '/nested/malformed',
463
+ contents: [{ key: '.' }],
478
464
  },
479
465
  },
480
466
  ]);
481
467
  }, /Value must have exactly one value property/);
482
468
  });
483
- it("path resolves through primitive objects and arrays", () => {
484
- processor.processMessages([
485
- { beginRendering: { surfaceId: "s1_path", root: "list" } },
486
- ]);
487
- const surface = processor.getSurfaces().get("s1_path");
488
- surface.dataModel.set("obj", {
489
- nestedMap: new Map([["index", [1, 2, { val: "hi" }]]]),
469
+ it('path resolves through primitive objects and arrays', () => {
470
+ processor.processMessages([{ beginRendering: { surfaceId: 's1_path', root: 'list' } }]);
471
+ const surface = processor.getSurfaces().get('s1_path');
472
+ surface.dataModel.set('obj', {
473
+ nestedMap: new Map([['index', [1, 2, { val: 'hi' }]]]),
490
474
  });
491
- surface.components.set("list", {
492
- id: "list",
475
+ surface.components.set('list', {
476
+ id: 'list',
493
477
  component: { Row: { children: { explicitList: [] } } },
494
478
  });
495
479
  processor.rebuildComponentTree(surface);
496
480
  const root = surface.componentTree;
497
- assert.strictEqual(processor.getData(root, "/obj/nestedMap/index/2/val", "s1_path"), "hi");
498
- assert.strictEqual(processor.getData(root, "/obj/nestedMap/index/2/val/deeper", "s1_path"), null);
481
+ assert.strictEqual(processor.getData(root, '/obj/nestedMap/index/2/val', 's1_path'), 'hi');
482
+ assert.strictEqual(processor.getData(root, '/obj/nestedMap/index/2/val/deeper', 's1_path'), null);
499
483
  });
500
- it("builds all component types correctly", () => {
501
- const surfaceId = "s_all";
502
- processor.processMessages([{ beginRendering: { surfaceId, root: "col" } }]);
484
+ it('builds all component types correctly', () => {
485
+ const surfaceId = 's_all';
486
+ processor.processMessages([{ beginRendering: { surfaceId, root: 'col' } }]);
503
487
  const surface = processor.getSurfaces().get(surfaceId);
504
488
  const components = {
505
- col: { Column: { children: ["row"] } },
506
- row: { Row: { children: ["card"] } },
507
- card: { Card: { child: "tabs" } },
489
+ col: { Column: { children: ['row'] } },
490
+ row: { Row: { children: ['card'] } },
491
+ card: { Card: { child: 'tabs' } },
508
492
  tabs: {
509
493
  Tabs: {
510
- tabItems: [{ title: { literalString: "T1" }, child: "modal" }],
494
+ tabItems: [{ title: { literalString: 'T1' }, child: 'modal' }],
511
495
  },
512
496
  },
513
- modal: { Modal: { entryPointChild: "list", contentChild: "div" } },
514
- list: { List: { children: ["btn"] } },
515
- btn: { Button: { child: "btn_txt", action: "act" } },
516
- btn_txt: { Text: { text: { literalString: "Click" } } },
497
+ modal: { Modal: { entryPointChild: 'list', contentChild: 'div' } },
498
+ list: { List: { children: ['btn'] } },
499
+ btn: { Button: { child: 'btn_txt', action: 'act' } },
500
+ btn_txt: { Text: { text: { literalString: 'Click' } } },
517
501
  div: { Divider: {} },
518
502
  chk: {
519
503
  CheckBox: {
520
- label: { literalString: "Chk" },
504
+ label: { literalString: 'Chk' },
521
505
  value: { literalBoolean: true },
522
506
  },
523
507
  },
524
- txt: { TextField: { label: { literalString: "Txt" } } },
525
- dt: { DateTimeInput: { value: { literalString: "2022-01-01" } } },
526
- mc: { MultipleChoice: { selections: { literal: ["a"] } } },
508
+ txt: { TextField: { label: { literalString: 'Txt' } } },
509
+ dt: { DateTimeInput: { value: { literalString: '2022-01-01' } } },
510
+ mc: { MultipleChoice: { selections: { literal: ['a'] } } },
527
511
  sl: { Slider: { value: { literalNumber: 50 } } },
528
- img: { Image: { url: { literalString: "http://img" } } },
529
- icon: { Icon: { name: { literalString: "home" } } },
530
- vid: { Video: { url: { literalString: "http://vid" } } },
531
- aud: { AudioPlayer: { url: { literalString: "http://aud" } } },
512
+ img: { Image: { url: { literalString: 'http://img' } } },
513
+ icon: { Icon: { name: { literalString: 'home' } } },
514
+ vid: { Video: { url: { literalString: 'http://vid' } } },
515
+ aud: { AudioPlayer: { url: { literalString: 'http://aud' } } },
532
516
  };
533
517
  for (const [id, comp] of Object.entries(components)) {
534
518
  surface.components.set(id, { id, component: comp });
535
519
  }
536
- surface.components.set("root_all", {
537
- id: "root_all",
520
+ surface.components.set('root_all', {
521
+ id: 'root_all',
538
522
  component: {
539
523
  Column: {
540
- children: [
541
- "col",
542
- "chk",
543
- "txt",
544
- "dt",
545
- "mc",
546
- "sl",
547
- "img",
548
- "icon",
549
- "vid",
550
- "aud",
551
- ],
524
+ children: ['col', 'chk', 'txt', 'dt', 'mc', 'sl', 'img', 'icon', 'vid', 'aud'],
552
525
  },
553
526
  },
554
527
  });
555
- surface.rootComponentId = "root_all";
528
+ surface.rootComponentId = 'root_all';
556
529
  processor.rebuildComponentTree(surface);
557
530
  const root = surface.componentTree;
558
- assert.strictEqual(root.type, "Column");
531
+ assert.strictEqual(root.type, 'Column');
559
532
  assert.strictEqual(root.properties.children.length, 10);
560
533
  });
561
- it("handles recursive valueMap in convertKeyValueArrayToMap", () => {
534
+ it('handles recursive valueMap in convertKeyValueArrayToMap', () => {
562
535
  // We need to bypass private check or use a method that calls it.
563
536
  // setData calls setDataByPath which calls convertKeyValueArrayToMap.
564
537
  const update = {
565
- surfaceId: "s_rec",
538
+ surfaceId: 's_rec',
566
539
  contents: [
567
540
  {
568
- key: "nested",
569
- valueMap: [{ key: "inner", valueString: "val" }],
541
+ key: 'nested',
542
+ valueMap: [{ key: 'inner', valueString: 'val' }],
570
543
  },
571
544
  ], // Recursive generic type difficult to construct in TS literal
572
545
  };
573
546
  // We can use processMessages with dataModelUpdate.
574
- processor.processMessages([
575
- { beginRendering: { surfaceId: "s_rec", root: "root" } },
576
- ]);
547
+ processor.processMessages([{ beginRendering: { surfaceId: 's_rec', root: 'root' } }]);
577
548
  // Set root to Map first
578
- const surface = processor.getSurfaces().get("s_rec");
579
- surface.dataModel.set("junk", "ignored");
549
+ const surface = processor.getSurfaces().get('s_rec');
550
+ surface.dataModel.set('junk', 'ignored');
580
551
  processor.processMessages([{ dataModelUpdate: update }]);
581
552
  // Verify data
582
- const nested = surface.dataModel.get("nested");
553
+ const nested = surface.dataModel.get('nested');
583
554
  assert.strictEqual(nested instanceof Map, true);
584
- assert.strictEqual(nested.get("inner"), "val");
555
+ assert.strictEqual(nested.get('inner'), 'val');
585
556
  });
586
- it("resolves Template with Map data", () => {
557
+ it('resolves Template with Map data', () => {
587
558
  processor.processMessages([
588
- { beginRendering: { surfaceId: "s3_map", root: "list" } },
559
+ { beginRendering: { surfaceId: 's3_map', root: 'list' } },
589
560
  {
590
561
  dataModelUpdate: {
591
- surfaceId: "s3_map",
562
+ surfaceId: 's3_map',
592
563
  contents: [
593
564
  {
594
- key: "items",
565
+ key: 'items',
595
566
  valueMap: [
596
- { key: "a", valueString: "valA" },
597
- { key: "b", valueString: "valB" },
567
+ { key: 'a', valueString: 'valA' },
568
+ { key: 'b', valueString: 'valB' },
598
569
  ],
599
570
  },
600
571
  ],
601
572
  },
602
573
  },
603
574
  ]);
604
- const surface = processor.getSurfaces().get("s3_map");
575
+ const surface = processor.getSurfaces().get('s3_map');
605
576
  // Define components
606
- surface.components.set("list", {
607
- id: "list",
577
+ surface.components.set('list', {
578
+ id: 'list',
608
579
  component: {
609
580
  List: {
610
581
  children: {
611
582
  template: {
612
- dataBinding: "/items",
613
- componentId: "item",
583
+ dataBinding: '/items',
584
+ componentId: 'item',
614
585
  },
615
586
  },
616
587
  },
617
588
  },
618
589
  });
619
- surface.components.set("item", {
620
- id: "item",
590
+ surface.components.set('item', {
591
+ id: 'item',
621
592
  component: {
622
- Text: { text: { path: "." } },
593
+ Text: { text: { path: '.' } },
623
594
  },
624
595
  });
625
596
  processor.rebuildComponentTree(surface);
626
597
  const root = surface.componentTree;
627
- assert.strictEqual(root.type, "List");
598
+ assert.strictEqual(root.type, 'List');
628
599
  // Map entries should be processed.
629
600
  assert.strictEqual(root.properties.children.length, 2);
630
601
  });
631
- it("handles Object-to-Map normalization in handleDataModelUpdate (direct call)", () => {
632
- const surfaceId = "s_norm";
633
- processor.processMessages([
634
- { beginRendering: { surfaceId, root: "root" } },
635
- ]);
602
+ it('handles Object-to-Map normalization in handleDataModelUpdate (direct call)', () => {
603
+ const surfaceId = 's_norm';
604
+ processor.processMessages([{ beginRendering: { surfaceId, root: 'root' } }]);
636
605
  const surface = processor.getSurfaces().get(surfaceId);
637
606
  // Direct call to bypass Zod validation in processMessages
638
607
  processor.handleDataModelUpdate({
639
608
  surfaceId,
640
- contents: { normalized: "value" },
609
+ contents: { normalized: 'value' },
641
610
  }, surfaceId);
642
- assert.strictEqual(surface.dataModel.get("normalized"), "value");
611
+ assert.strictEqual(surface.dataModel.get('normalized'), 'value');
643
612
  });
644
- it("throws validation error for invalid List", () => {
645
- const surfaceId = "s_bad_list";
646
- processor.processMessages([
647
- { beginRendering: { surfaceId, root: "badList" } },
648
- ]);
613
+ it('throws validation error for invalid List', () => {
614
+ const surfaceId = 's_bad_list';
615
+ processor.processMessages([{ beginRendering: { surfaceId, root: 'badList' } }]);
649
616
  const surface = processor.getSurfaces().get(surfaceId);
650
- surface.components.set("badList", {
651
- id: "badList",
652
- component: { List: { children: "not-array" } },
617
+ surface.components.set('badList', {
618
+ id: 'badList',
619
+ component: { List: { children: 'not-array' } },
653
620
  });
654
621
  assert.throws(() => {
655
622
  processor.rebuildComponentTree(surface);
656
623
  }, /Invalid data; expected List/);
657
624
  });
658
- it("handles recursive valueMap in convertKeyValueArrayToMap with dot key", () => {
659
- const surfaceId = "s_dot_rec";
625
+ it('handles recursive valueMap in convertKeyValueArrayToMap with dot key', () => {
626
+ const surfaceId = 's_dot_rec';
660
627
  const surface = processor.getOrCreateSurface(surfaceId);
661
628
  const value = [
662
629
  {
663
- key: ".",
664
- valueMap: [{ key: "inner", valueString: "val" }],
630
+ key: '.',
631
+ valueMap: [{ key: 'inner', valueString: 'val' }],
665
632
  },
666
633
  ];
667
634
  // Calling setDataByPath directly (private)
668
- processor.setDataByPath(surface.dataModel, "/target", value);
669
- const target = surface.dataModel.get("target");
635
+ processor.setDataByPath(surface.dataModel, '/target', value);
636
+ const target = surface.dataModel.get('target');
670
637
  assert.strictEqual(target instanceof Map, true);
671
- assert.strictEqual(target.get("inner"), "val");
638
+ assert.strictEqual(target.get('inner'), 'val');
672
639
  });
673
- it("resolves Template with Array data (via direct setData)", () => {
674
- const surfaceId = "s_direct_arr";
675
- processor.processMessages([
676
- { beginRendering: { surfaceId, root: "list" } },
677
- ]);
640
+ it('resolves Template with Array data (via direct setData)', () => {
641
+ const surfaceId = 's_direct_arr';
642
+ processor.processMessages([{ beginRendering: { surfaceId, root: 'list' } }]);
678
643
  const surface = processor.getSurfaces().get(surfaceId);
679
644
  // Setup components
680
- surface.components.set("list", {
681
- id: "list",
645
+ surface.components.set('list', {
646
+ id: 'list',
682
647
  component: {
683
648
  List: {
684
649
  children: {
685
650
  template: {
686
- dataBinding: "/items",
687
- componentId: "item",
651
+ dataBinding: '/items',
652
+ componentId: 'item',
688
653
  },
689
654
  },
690
655
  },
691
656
  },
692
657
  });
693
- surface.components.set("item", {
694
- id: "item",
658
+ surface.components.set('item', {
659
+ id: 'item',
695
660
  component: {
696
- Text: { text: { path: "." } },
661
+ Text: { text: { path: '.' } },
697
662
  },
698
663
  });
699
664
  // Direct set array to bypass normalization/schema
700
- const itemsArray = ["A", "B"];
701
- surface.dataModel.set("items", itemsArray);
665
+ const itemsArray = ['A', 'B'];
666
+ surface.dataModel.set('items', itemsArray);
702
667
  processor.rebuildComponentTree(surface);
703
668
  const root = surface.componentTree;
704
- assert.strictEqual(root.type, "List");
669
+ assert.strictEqual(root.type, 'List');
705
670
  assert.strictEqual(root.properties.children.length, 2);
706
671
  });
707
- it("ignores non-strings when trying to parse JSON", () => {
672
+ it('ignores non-strings when trying to parse JSON', () => {
708
673
  const result = processor.parseIfJsonString(123);
709
674
  assert.strictEqual(result, 123);
710
675
  });