@antglobal/copilot-cards-core 1.0.5 → 1.0.7
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/README.md +57 -0
- package/dist/index.cjs +349 -128
- package/dist/index.d.ts +33 -7
- package/dist/index.js +349 -129
- package/dist/validation-text.cjs +1298 -0
- package/dist/validation-text.d.ts +215 -0
- package/dist/validation-text.js +1293 -0
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -201,87 +201,106 @@ function evaluateExpression(expr, context) {
|
|
|
201
201
|
return t;
|
|
202
202
|
}
|
|
203
203
|
// Precedence (low → high): ternary → || → && → equality → relational → unary → atom
|
|
204
|
-
function parseTernary() {
|
|
205
|
-
const
|
|
204
|
+
function parseTernary(mode) {
|
|
205
|
+
const condition = parseOr(mode);
|
|
206
206
|
if (peek()?.type === 'question') {
|
|
207
207
|
consume(); // ?
|
|
208
|
-
const
|
|
208
|
+
const truthyMode = mode === 'evaluate' && Boolean(condition)
|
|
209
|
+
? 'evaluate'
|
|
210
|
+
: 'consume';
|
|
211
|
+
const truthy = parseTernary(truthyMode);
|
|
209
212
|
expect('colon');
|
|
210
|
-
const
|
|
211
|
-
|
|
213
|
+
const falsyMode = mode === 'evaluate' && !condition
|
|
214
|
+
? 'evaluate'
|
|
215
|
+
: 'consume';
|
|
216
|
+
const falsy = parseTernary(falsyMode);
|
|
217
|
+
if (mode === 'consume')
|
|
218
|
+
return undefined;
|
|
219
|
+
return condition ? truthy : falsy;
|
|
212
220
|
}
|
|
213
|
-
return
|
|
221
|
+
return condition;
|
|
214
222
|
}
|
|
215
|
-
function parseOr() {
|
|
216
|
-
let left = parseAnd();
|
|
223
|
+
function parseOr(mode) {
|
|
224
|
+
let left = parseAnd(mode);
|
|
217
225
|
while (peek()?.value === '||') {
|
|
218
226
|
consume();
|
|
219
|
-
|
|
227
|
+
const rightMode = mode === 'evaluate' && !left ? 'evaluate' : 'consume';
|
|
228
|
+
const right = parseAnd(rightMode);
|
|
229
|
+
if (rightMode === 'evaluate')
|
|
230
|
+
left = right;
|
|
220
231
|
}
|
|
221
232
|
return left;
|
|
222
233
|
}
|
|
223
|
-
function parseAnd() {
|
|
224
|
-
let left = parseEquality();
|
|
234
|
+
function parseAnd(mode) {
|
|
235
|
+
let left = parseEquality(mode);
|
|
225
236
|
while (peek()?.value === '&&') {
|
|
226
237
|
consume();
|
|
227
|
-
|
|
238
|
+
const rightMode = mode === 'evaluate' && Boolean(left) ? 'evaluate' : 'consume';
|
|
239
|
+
const right = parseEquality(rightMode);
|
|
240
|
+
if (rightMode === 'evaluate')
|
|
241
|
+
left = right;
|
|
228
242
|
}
|
|
229
243
|
return left;
|
|
230
244
|
}
|
|
231
|
-
function parseEquality() {
|
|
232
|
-
let left = parseRelational();
|
|
245
|
+
function parseEquality(mode) {
|
|
246
|
+
let left = parseRelational(mode);
|
|
233
247
|
while (peek()?.value === '===' || peek()?.value === '!==' || peek()?.value === '==' || peek()?.value === '!=') {
|
|
234
248
|
const op = consume().value;
|
|
235
|
-
const right = parseRelational();
|
|
236
|
-
if (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
249
|
+
const right = parseRelational(mode);
|
|
250
|
+
if (mode === 'evaluate') {
|
|
251
|
+
if (op === '===' || op === '==')
|
|
252
|
+
left = left === right;
|
|
253
|
+
else
|
|
254
|
+
left = left !== right;
|
|
255
|
+
}
|
|
240
256
|
}
|
|
241
257
|
return left;
|
|
242
258
|
}
|
|
243
|
-
function parseRelational() {
|
|
244
|
-
let left = parseUnary();
|
|
259
|
+
function parseRelational(mode) {
|
|
260
|
+
let left = parseUnary(mode);
|
|
245
261
|
while (peek()?.value === '>' || peek()?.value === '<' || peek()?.value === '>=' || peek()?.value === '<=') {
|
|
246
262
|
const op = consume().value;
|
|
247
|
-
const right = parseUnary();
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
263
|
+
const right = parseUnary(mode);
|
|
264
|
+
if (mode === 'evaluate') {
|
|
265
|
+
if (op === '>')
|
|
266
|
+
left = left > right;
|
|
267
|
+
else if (op === '<')
|
|
268
|
+
left = left < right;
|
|
269
|
+
else if (op === '>=')
|
|
270
|
+
left = left >= right;
|
|
271
|
+
else
|
|
272
|
+
left = left <= right;
|
|
273
|
+
}
|
|
256
274
|
}
|
|
257
275
|
return left;
|
|
258
276
|
}
|
|
259
|
-
function parseUnary() {
|
|
277
|
+
function parseUnary(mode) {
|
|
260
278
|
if (peek()?.value === '!') {
|
|
261
279
|
consume();
|
|
262
|
-
|
|
280
|
+
const value = parseUnary(mode);
|
|
281
|
+
return mode === 'evaluate' ? !value : undefined;
|
|
263
282
|
}
|
|
264
|
-
return parseAtom();
|
|
283
|
+
return parseAtom(mode);
|
|
265
284
|
}
|
|
266
|
-
function parseAtom() {
|
|
285
|
+
function parseAtom(mode) {
|
|
267
286
|
const t = peek();
|
|
268
287
|
if (!t)
|
|
269
288
|
return undefined;
|
|
270
289
|
if (t.type === 'string') {
|
|
271
290
|
consume();
|
|
272
|
-
return t.value;
|
|
291
|
+
return mode === 'evaluate' ? t.value : undefined;
|
|
273
292
|
}
|
|
274
293
|
if (t.type === 'number') {
|
|
275
294
|
consume();
|
|
276
|
-
return Number(t.value);
|
|
295
|
+
return mode === 'evaluate' ? Number(t.value) : undefined;
|
|
277
296
|
}
|
|
278
297
|
if (t.type === 'boolean') {
|
|
279
298
|
consume();
|
|
280
|
-
return t.value === 'true';
|
|
299
|
+
return mode === 'evaluate' ? t.value === 'true' : undefined;
|
|
281
300
|
}
|
|
282
301
|
if (t.type === 'null') {
|
|
283
302
|
consume();
|
|
284
|
-
return null;
|
|
303
|
+
return mode === 'evaluate' ? null : undefined;
|
|
285
304
|
}
|
|
286
305
|
if (t.type === 'undefined') {
|
|
287
306
|
consume();
|
|
@@ -289,19 +308,19 @@ function evaluateExpression(expr, context) {
|
|
|
289
308
|
}
|
|
290
309
|
if (t.type === 'ident') {
|
|
291
310
|
consume();
|
|
292
|
-
return getByPath$1(context, t.value);
|
|
311
|
+
return mode === 'evaluate' ? getByPath$1(context, t.value) : undefined;
|
|
293
312
|
}
|
|
294
313
|
if (t.type === 'paren' && t.value === '(') {
|
|
295
314
|
consume();
|
|
296
|
-
const
|
|
315
|
+
const value = parseTernary(mode);
|
|
297
316
|
expect('paren', ')');
|
|
298
|
-
return
|
|
317
|
+
return value;
|
|
299
318
|
}
|
|
300
319
|
// Fallback
|
|
301
320
|
consume();
|
|
302
321
|
return undefined;
|
|
303
322
|
}
|
|
304
|
-
const result = parseTernary();
|
|
323
|
+
const result = parseTernary('evaluate');
|
|
305
324
|
return result;
|
|
306
325
|
}
|
|
307
326
|
/**
|
|
@@ -386,7 +405,7 @@ async function parseResponseBody(response) {
|
|
|
386
405
|
* @param silent - If true, only write to ctx.variables without calling
|
|
387
406
|
* setVariable (avoids triggering re-render during polling iterations).
|
|
388
407
|
* When variableWriter is present it owns the write and must synchronously
|
|
389
|
-
* update the
|
|
408
|
+
* update the renderer-owned variable view while honoring this flag.
|
|
390
409
|
*/
|
|
391
410
|
function writeResponseVariable(ctx, responseKey, data, silent = false) {
|
|
392
411
|
if (ctx.variableWriter) {
|
|
@@ -1844,97 +1863,215 @@ function parseSchema(input) {
|
|
|
1844
1863
|
}
|
|
1845
1864
|
return buildNode(rootID);
|
|
1846
1865
|
}
|
|
1847
|
-
|
|
1866
|
+
function encodePointerSegment(segment) {
|
|
1867
|
+
return String(segment).replace(/~/g, '~0').replace(/\//g, '~1');
|
|
1868
|
+
}
|
|
1869
|
+
function schemaPath(...segments) {
|
|
1870
|
+
return segments.length > 0
|
|
1871
|
+
? `/${segments.map(encodePointerSegment).join('/')}`
|
|
1872
|
+
: '';
|
|
1873
|
+
}
|
|
1874
|
+
function elementPath(id, ...segments) {
|
|
1875
|
+
return schemaPath('elements', id, ...segments);
|
|
1876
|
+
}
|
|
1877
|
+
function slotPath(id, slotName, ...segments) {
|
|
1878
|
+
return elementPath(id, 'props', 'slots', slotName, ...segments);
|
|
1879
|
+
}
|
|
1880
|
+
function addIssue(issues, code, path, message, params, anchorPath) {
|
|
1881
|
+
issues.push({
|
|
1882
|
+
code,
|
|
1883
|
+
path,
|
|
1884
|
+
...(anchorPath === undefined ? {} : { anchorPath }),
|
|
1885
|
+
message,
|
|
1886
|
+
...(params === undefined ? {} : { params }),
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
function displayValue(value) {
|
|
1890
|
+
try {
|
|
1891
|
+
return String(value);
|
|
1892
|
+
}
|
|
1893
|
+
catch {
|
|
1894
|
+
return '<unprintable>';
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
function displayError(error) {
|
|
1898
|
+
const message = readOwnData(error, 'message');
|
|
1899
|
+
return displayValue(message.kind === 'value' ? message.value : error);
|
|
1900
|
+
}
|
|
1848
1901
|
/**
|
|
1849
|
-
* Validate
|
|
1902
|
+
* Validate an unknown schema input and return structured diagnostics.
|
|
1903
|
+
*
|
|
1904
|
+
* Component names and component-specific props are deliberately not checked;
|
|
1905
|
+
* this validator only owns the shared card graph and binding protocol.
|
|
1850
1906
|
*/
|
|
1851
|
-
function
|
|
1852
|
-
const
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1907
|
+
function validateSchemaDetailed(input) {
|
|
1908
|
+
const issues = [];
|
|
1909
|
+
if (!isPlainObject(input)) {
|
|
1910
|
+
addIssue(issues, 'SCHEMA_TYPE_MISMATCH', '', 'Schema must be a non-null plain object');
|
|
1911
|
+
return issues;
|
|
1912
|
+
}
|
|
1913
|
+
let schema;
|
|
1914
|
+
try {
|
|
1915
|
+
schema = normalizeSchema(input);
|
|
1856
1916
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1917
|
+
catch (error) {
|
|
1918
|
+
addIssue(issues, 'LEGACY_CONVERSION_FAILED', '', `Legacy schema conversion failed: ${displayError(error)}`);
|
|
1919
|
+
return issues;
|
|
1859
1920
|
}
|
|
1860
|
-
|
|
1861
|
-
|
|
1921
|
+
const version = readOwnData(schema, 'version');
|
|
1922
|
+
if (version.kind !== 'value' || !version.value) {
|
|
1923
|
+
addIssue(issues, 'SCHEMA_REQUIRED_FIELD', schemaPath('version'), 'Missing "version" field', undefined, '');
|
|
1862
1924
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1925
|
+
const rootID = readOwnData(schema, 'rootID');
|
|
1926
|
+
if (rootID.kind !== 'value' || typeof rootID.value !== 'string') {
|
|
1927
|
+
addIssue(issues, 'ROOT_TYPE_MISMATCH', schemaPath('rootID'), '"rootID" field must be a string', undefined, rootID.kind === 'missing' ? '' : undefined);
|
|
1865
1928
|
}
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1929
|
+
else if (!rootID.value) {
|
|
1930
|
+
addIssue(issues, 'SCHEMA_REQUIRED_FIELD', schemaPath('rootID'), 'Missing "rootID" field');
|
|
1931
|
+
}
|
|
1932
|
+
const elementsRead = readOwnData(schema, 'elements');
|
|
1933
|
+
if (elementsRead.kind === 'missing') {
|
|
1934
|
+
addIssue(issues, 'SCHEMA_REQUIRED_FIELD', schemaPath('elements'), 'Missing "elements" field', undefined, '');
|
|
1935
|
+
return issues;
|
|
1936
|
+
}
|
|
1937
|
+
const rawElements = elementsRead.kind === 'value'
|
|
1938
|
+
? elementsRead.value
|
|
1939
|
+
: undefined;
|
|
1940
|
+
if (!isPlainObject(rawElements)) {
|
|
1941
|
+
addIssue(issues, 'SCHEMA_TYPE_MISMATCH', schemaPath('elements'), '"elements" field must be an object');
|
|
1942
|
+
return issues;
|
|
1943
|
+
}
|
|
1944
|
+
const elements = rawElements;
|
|
1945
|
+
const elementEntries = ownStringDataEntries(elements);
|
|
1946
|
+
for (const id of elementEntries.accessors) {
|
|
1947
|
+
addIssue(issues, 'ELEMENT_ACCESSOR_NOT_ALLOWED', elementPath(id), `Element "${id}" must be an own data property`, { elementId: id });
|
|
1948
|
+
}
|
|
1949
|
+
if (elementEntries.opaque) {
|
|
1950
|
+
addIssue(issues, 'ELEMENTS_UNINSPECTABLE', schemaPath('elements'), 'The "elements" field could not be inspected safely');
|
|
1951
|
+
return issues;
|
|
1952
|
+
}
|
|
1953
|
+
const allIds = new Set([
|
|
1954
|
+
...elementEntries.entries.map(([id]) => id),
|
|
1955
|
+
...elementEntries.accessors,
|
|
1956
|
+
]);
|
|
1957
|
+
const validationElements = Object.create(null);
|
|
1958
|
+
for (const [id, element] of elementEntries.entries) {
|
|
1959
|
+
Object.defineProperty(validationElements, id, {
|
|
1960
|
+
configurable: true,
|
|
1961
|
+
enumerable: true,
|
|
1962
|
+
value: element,
|
|
1963
|
+
writable: true,
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
const validationSchema = {
|
|
1967
|
+
rootID: rootID.kind === 'value' && typeof rootID.value === 'string'
|
|
1968
|
+
? rootID.value
|
|
1969
|
+
: '',
|
|
1970
|
+
elements: validationElements};
|
|
1971
|
+
if (rootID.kind === 'value'
|
|
1972
|
+
&& typeof rootID.value === 'string'
|
|
1973
|
+
&& rootID.value
|
|
1974
|
+
&& !allIds.has(rootID.value)) {
|
|
1975
|
+
addIssue(issues, 'ROOT_REFERENCE_NOT_FOUND', schemaPath('rootID'), `Root element "${rootID.value}" not found in elements`, { rootID: rootID.value });
|
|
1976
|
+
}
|
|
1977
|
+
for (const [id, rawElement] of elementEntries.entries) {
|
|
1978
|
+
if (!isPlainObject(rawElement)) {
|
|
1979
|
+
addIssue(issues, 'ELEMENT_TYPE_MISMATCH', elementPath(id), `Element "${id}" must be an object`, { elementId: id });
|
|
1980
|
+
continue;
|
|
1981
|
+
}
|
|
1982
|
+
const element = rawElement;
|
|
1983
|
+
const type = readOwnData(element, 'type');
|
|
1984
|
+
if (type.kind !== 'value' || !type.value) {
|
|
1985
|
+
addIssue(issues, 'ELEMENT_TYPE_MISSING', elementPath(id, 'type'), `Element "${id}" is missing a "type" field`, { elementId: id }, type.kind === 'missing' ? elementPath(id) : undefined);
|
|
1986
|
+
}
|
|
1987
|
+
const props = readOwnData(element, 'props');
|
|
1988
|
+
if (props.kind !== 'value' || !isPlainObject(props.value)) {
|
|
1989
|
+
addIssue(issues, 'ELEMENT_PROPS_TYPE_MISMATCH', elementPath(id, 'props'), `Element "${id}" "props" field must be an object`, { elementId: id }, props.kind === 'missing' ? elementPath(id) : undefined);
|
|
1990
|
+
continue;
|
|
1870
1991
|
}
|
|
1871
1992
|
// Validate slot children and groups references without invoking accessors.
|
|
1872
|
-
const
|
|
1993
|
+
const rawSlots = readOwnData(props.value, 'slots');
|
|
1994
|
+
if (rawSlots.kind === 'accessor' || rawSlots.kind === 'opaque') {
|
|
1995
|
+
addIssue(issues, 'SLOTS_UNINSPECTABLE', elementPath(id, 'props', 'slots'), `Element "${id}" slots could not be inspected safely`, { elementId: id });
|
|
1996
|
+
continue;
|
|
1997
|
+
}
|
|
1998
|
+
if (rawSlots.kind === 'value' && !isPlainObject(rawSlots.value)) {
|
|
1999
|
+
addIssue(issues, 'SLOTS_TYPE_MISMATCH', elementPath(id, 'props', 'slots'), `Element "${id}" "slots" field must be an object`, { elementId: id });
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
const slots = rawSlots.kind === 'value'
|
|
2003
|
+
? ownStringDataEntries(rawSlots.value)
|
|
2004
|
+
: ownStringDataEntries(undefined);
|
|
1873
2005
|
for (const slotName of slots.accessors) {
|
|
1874
|
-
|
|
2006
|
+
addIssue(issues, 'SLOT_ACCESSOR_NOT_ALLOWED', slotPath(id, slotName), `Element "${id}" slot "${slotName}" must be an own data property`, { elementId: id, slotName });
|
|
1875
2007
|
}
|
|
1876
2008
|
if (slots.opaque) {
|
|
1877
|
-
|
|
2009
|
+
addIssue(issues, 'SLOTS_UNINSPECTABLE', elementPath(id, 'props', 'slots'), `Element "${id}" slots could not be inspected safely`, { elementId: id });
|
|
1878
2010
|
}
|
|
1879
2011
|
for (const [slotName, slot] of slots.entries) {
|
|
1880
|
-
if (!slot
|
|
1881
|
-
|
|
2012
|
+
if (!isPlainObject(slot)) {
|
|
2013
|
+
addIssue(issues, 'SLOT_TYPE_MISMATCH', slotPath(id, slotName), `Element "${id}" slot "${slotName}" must be an object`, { elementId: id, slotName });
|
|
1882
2014
|
continue;
|
|
1883
2015
|
}
|
|
1884
2016
|
const children = readOwnData(slot, 'children');
|
|
1885
2017
|
if (children.kind === 'value') {
|
|
1886
2018
|
const values = ownArrayDataValues(children.value);
|
|
1887
2019
|
if (!values) {
|
|
1888
|
-
|
|
2020
|
+
addIssue(issues, 'SLOT_CHILDREN_TYPE_MISMATCH', slotPath(id, slotName, 'children'), `Element "${id}" slot "${slotName}" children must be an array`, { elementId: id, slotName });
|
|
1889
2021
|
}
|
|
1890
2022
|
else {
|
|
1891
|
-
for (const childId of values) {
|
|
2023
|
+
for (const [index, childId] of values.entries()) {
|
|
1892
2024
|
if (typeof childId !== 'string' || childId.length === 0) {
|
|
1893
|
-
|
|
2025
|
+
addIssue(issues, 'SLOT_CHILD_ID_INVALID', slotPath(id, slotName, 'children', index), `Element "${id}" slot "${slotName}" child IDs must be non-empty strings; received "${displayValue(childId)}"`, { elementId: id, slotName, value: childId });
|
|
1894
2026
|
}
|
|
1895
2027
|
else if (!allIds.has(childId)) {
|
|
1896
|
-
|
|
2028
|
+
addIssue(issues, 'ELEMENT_REFERENCE_NOT_FOUND', slotPath(id, slotName, 'children', index), `Element "${id}" slot "${slotName}" references unknown child "${displayValue(childId)}"`, { elementId: id, slotName, reference: childId });
|
|
1897
2029
|
}
|
|
1898
2030
|
}
|
|
1899
2031
|
}
|
|
1900
2032
|
}
|
|
1901
2033
|
else if (children.kind === 'accessor' || children.kind === 'opaque') {
|
|
1902
|
-
|
|
2034
|
+
addIssue(issues, 'SLOT_ACCESSOR_NOT_ALLOWED', slotPath(id, slotName, 'children'), `Element "${id}" slot "${slotName}" children must be an own data property`, { elementId: id, slotName, field: 'children' });
|
|
1903
2035
|
}
|
|
1904
2036
|
const groups = readOwnData(slot, 'groups');
|
|
1905
2037
|
if (groups.kind === 'value') {
|
|
1906
2038
|
const groupValues = ownArrayDataValues(groups.value);
|
|
1907
2039
|
if (!groupValues) {
|
|
1908
|
-
|
|
2040
|
+
addIssue(issues, 'SLOT_GROUPS_TYPE_MISMATCH', slotPath(id, slotName, 'groups'), `Element "${id}" slot "${slotName}" groups must be an array`, { elementId: id, slotName });
|
|
1909
2041
|
}
|
|
1910
2042
|
else {
|
|
1911
|
-
for (const group of groupValues) {
|
|
2043
|
+
for (const [groupIndex, group] of groupValues.entries()) {
|
|
1912
2044
|
const childrenInGroup = ownArrayDataValues(group);
|
|
1913
2045
|
if (!childrenInGroup) {
|
|
1914
|
-
|
|
2046
|
+
addIssue(issues, 'SLOT_GROUP_TYPE_MISMATCH', slotPath(id, slotName, 'groups', groupIndex), `Element "${id}" slot "${slotName}" groups must contain arrays`, { elementId: id, slotName });
|
|
1915
2047
|
continue;
|
|
1916
2048
|
}
|
|
1917
|
-
for (const childId of childrenInGroup) {
|
|
2049
|
+
for (const [childIndex, childId] of childrenInGroup.entries()) {
|
|
1918
2050
|
if (typeof childId !== 'string' || childId.length === 0) {
|
|
1919
|
-
|
|
2051
|
+
addIssue(issues, 'SLOT_GROUP_CHILD_ID_INVALID', slotPath(id, slotName, 'groups', groupIndex, childIndex), `Element "${id}" slot "${slotName}" group child IDs must be non-empty strings; received "${displayValue(childId)}"`, { elementId: id, slotName, value: childId });
|
|
1920
2052
|
}
|
|
1921
2053
|
else if (!allIds.has(childId)) {
|
|
1922
|
-
|
|
2054
|
+
addIssue(issues, 'ELEMENT_REFERENCE_NOT_FOUND', slotPath(id, slotName, 'groups', groupIndex, childIndex), `Element "${id}" slot "${slotName}" group references unknown child "${displayValue(childId)}"`, { elementId: id, slotName, reference: childId });
|
|
1923
2055
|
}
|
|
1924
2056
|
}
|
|
1925
2057
|
}
|
|
1926
2058
|
}
|
|
1927
2059
|
}
|
|
1928
2060
|
else if (groups.kind === 'accessor' || groups.kind === 'opaque') {
|
|
1929
|
-
|
|
2061
|
+
addIssue(issues, 'SLOT_ACCESSOR_NOT_ALLOWED', slotPath(id, slotName, 'groups'), `Element "${id}" slot "${slotName}" groups must be an own data property`, { elementId: id, slotName, field: 'groups' });
|
|
1930
2062
|
}
|
|
1931
2063
|
}
|
|
1932
2064
|
}
|
|
1933
|
-
validateRepeatBindings(
|
|
1934
|
-
return
|
|
2065
|
+
validateRepeatBindings(validationSchema, issues);
|
|
2066
|
+
return issues;
|
|
2067
|
+
}
|
|
2068
|
+
/** Validate a CardSchema and return backwards-compatible error messages. */
|
|
2069
|
+
function validateSchema(input) {
|
|
2070
|
+
return validateSchemaDetailed(input).map(issue => issue.message);
|
|
1935
2071
|
}
|
|
1936
2072
|
const REPEAT_SLOT_LAYOUTS = new Set([
|
|
1937
2073
|
'default',
|
|
2074
|
+
'flex',
|
|
1938
2075
|
'list',
|
|
1939
2076
|
'grid',
|
|
1940
2077
|
'horizontalScroll',
|
|
@@ -2032,7 +2169,10 @@ function ownArrayDataValues(value) {
|
|
|
2032
2169
|
}
|
|
2033
2170
|
}
|
|
2034
2171
|
function elementSlotEntries(element) {
|
|
2035
|
-
const
|
|
2172
|
+
const props = readOwnData(element, 'props');
|
|
2173
|
+
const slots = props.kind === 'value'
|
|
2174
|
+
? readOwnData(props.value, 'slots')
|
|
2175
|
+
: props;
|
|
2036
2176
|
return slots.kind === 'value'
|
|
2037
2177
|
? ownStringDataEntries(slots.value)
|
|
2038
2178
|
: {
|
|
@@ -2048,11 +2188,15 @@ function readRepeatBindingFields(value) {
|
|
|
2048
2188
|
const template = readOwnData(value, 'template');
|
|
2049
2189
|
const item = readOwnData(value, 'item');
|
|
2050
2190
|
const index = readOwnData(value, 'index');
|
|
2191
|
+
const emptyTemplate = readOwnData(value, 'emptyTemplate');
|
|
2051
2192
|
return {
|
|
2052
2193
|
source: source.kind === 'value' ? source.value : undefined,
|
|
2053
2194
|
template: template.kind === 'value' ? template.value : undefined,
|
|
2054
|
-
item
|
|
2195
|
+
...(item.kind === 'value' ? { item: item.value } : {}),
|
|
2055
2196
|
...(index.kind === 'value' ? { index: index.value } : {}),
|
|
2197
|
+
...(emptyTemplate.kind === 'value'
|
|
2198
|
+
? { emptyTemplate: emptyTemplate.value }
|
|
2199
|
+
: {}),
|
|
2056
2200
|
};
|
|
2057
2201
|
}
|
|
2058
2202
|
function slotStaticReferences(slot) {
|
|
@@ -2177,6 +2321,10 @@ function elementReferences(element) {
|
|
|
2177
2321
|
if (typeof binding?.template === 'string' && binding.template) {
|
|
2178
2322
|
references.push(binding.template);
|
|
2179
2323
|
}
|
|
2324
|
+
if (typeof binding?.emptyTemplate === 'string'
|
|
2325
|
+
&& binding.emptyTemplate) {
|
|
2326
|
+
references.push(binding.emptyTemplate);
|
|
2327
|
+
}
|
|
2180
2328
|
const a2ui = getA2UIChildBinding(slot);
|
|
2181
2329
|
if (typeof a2ui?.templateId === 'string' && a2ui.templateId) {
|
|
2182
2330
|
references.push(a2ui.templateId);
|
|
@@ -2184,14 +2332,14 @@ function elementReferences(element) {
|
|
|
2184
2332
|
}
|
|
2185
2333
|
return references;
|
|
2186
2334
|
}
|
|
2187
|
-
function validateRepeatBindings(schema,
|
|
2335
|
+
function validateRepeatBindings(schema, issues) {
|
|
2188
2336
|
const dynamicBindings = [];
|
|
2189
2337
|
for (const [id, element] of Object.entries(schema.elements)) {
|
|
2190
2338
|
const elementRepeats = elementSlotEntries(element).entries
|
|
2191
2339
|
.filter((entry) => hasOwn(entry[1], 'repeat')
|
|
2192
2340
|
|| getA2UIChildBinding(entry[1]) !== undefined);
|
|
2193
2341
|
if (elementRepeats.length > 1) {
|
|
2194
|
-
|
|
2342
|
+
addIssue(issues, 'DYNAMIC_SLOT_MULTIPLE', elementPath(id, 'props', 'slots'), `Element "${id}" has more than one dynamic slot`, { elementId: id });
|
|
2195
2343
|
}
|
|
2196
2344
|
for (const [slotName, slot] of elementRepeats) {
|
|
2197
2345
|
const a2ui = getA2UIChildBinding(slot);
|
|
@@ -2205,10 +2353,10 @@ function validateRepeatBindings(schema, errors) {
|
|
|
2205
2353
|
});
|
|
2206
2354
|
if (typeof a2ui.templateId !== 'string'
|
|
2207
2355
|
|| a2ui.templateId.length === 0) {
|
|
2208
|
-
|
|
2356
|
+
addIssue(issues, 'DYNAMIC_TEMPLATE_INVALID', slotPath(id, slotName), `Element "${id}" slot "${slotName}" dynamic children template must be a non-empty string`, { elementId: id, slotName });
|
|
2209
2357
|
}
|
|
2210
2358
|
else if (!getOwnElement(schema, a2ui.templateId)) {
|
|
2211
|
-
|
|
2359
|
+
addIssue(issues, 'DYNAMIC_TEMPLATE_NOT_FOUND', slotPath(id, slotName), `Element "${id}" slot "${slotName}" dynamic children reference unknown template "${a2ui.templateId}"`, { elementId: id, slotName, reference: a2ui.templateId });
|
|
2212
2360
|
}
|
|
2213
2361
|
continue;
|
|
2214
2362
|
}
|
|
@@ -2216,7 +2364,7 @@ function validateRepeatBindings(schema, errors) {
|
|
|
2216
2364
|
? repeat.value
|
|
2217
2365
|
: undefined;
|
|
2218
2366
|
if (!isPlainObject(rawBinding)) {
|
|
2219
|
-
|
|
2367
|
+
addIssue(issues, 'REPEAT_TYPE_MISMATCH', slotPath(id, slotName, 'repeat'), `Element "${id}" slot "${slotName}" repeat must be a non-null plain object`, { elementId: id, slotName });
|
|
2220
2368
|
continue;
|
|
2221
2369
|
}
|
|
2222
2370
|
const binding = readRepeatBindingFields(rawBinding);
|
|
@@ -2228,7 +2376,7 @@ function validateRepeatBindings(schema, errors) {
|
|
|
2228
2376
|
binding,
|
|
2229
2377
|
});
|
|
2230
2378
|
if (!REPEAT_SLOT_LAYOUTS.has(slotName)) {
|
|
2231
|
-
|
|
2379
|
+
addIssue(issues, 'REPEAT_SLOT_UNSUPPORTED', slotPath(id, slotName, 'repeat'), `Element "${id}" slot "${slotName}" does not support repeat`, { elementId: id, slotName });
|
|
2232
2380
|
}
|
|
2233
2381
|
const children = readOwnData(slot, 'children');
|
|
2234
2382
|
const groups = readOwnData(slot, 'groups');
|
|
@@ -2238,49 +2386,78 @@ function validateRepeatBindings(schema, errors) {
|
|
|
2238
2386
|
|| (groups.kind === 'value' && !!groups.value)
|
|
2239
2387
|
|| groups.kind === 'accessor'
|
|
2240
2388
|
|| groups.kind === 'opaque') {
|
|
2241
|
-
|
|
2389
|
+
addIssue(issues, 'REPEAT_CONTENT_CONFLICT', slotPath(id, slotName, 'repeat'), `Element "${id}" slot "${slotName}" cannot combine repeat with children or groups`, { elementId: id, slotName });
|
|
2242
2390
|
}
|
|
2243
2391
|
if (typeof binding.source !== 'string') {
|
|
2244
|
-
|
|
2392
|
+
addIssue(issues, 'REPEAT_SOURCE_TYPE_MISMATCH', slotPath(id, slotName, 'repeat', 'source'), `Element "${id}" slot "${slotName}" repeat source must be a string`, { elementId: id, slotName }, hasOwn(rawBinding, 'source')
|
|
2393
|
+
? undefined
|
|
2394
|
+
: slotPath(id, slotName, 'repeat'));
|
|
2245
2395
|
}
|
|
2246
2396
|
else if (!isCompleteExpression(binding.source)) {
|
|
2247
|
-
|
|
2397
|
+
addIssue(issues, 'REPEAT_SOURCE_INVALID', slotPath(id, slotName, 'repeat', 'source'), `Element "${id}" slot "${slotName}" repeat source must be one complete non-empty \${...} expression`, { elementId: id, slotName });
|
|
2248
2398
|
}
|
|
2249
2399
|
if (typeof binding.template !== 'string') {
|
|
2250
|
-
|
|
2400
|
+
addIssue(issues, 'REPEAT_TEMPLATE_TYPE_MISMATCH', slotPath(id, slotName, 'repeat', 'template'), `Element "${id}" slot "${slotName}" repeat template must be a string`, { elementId: id, slotName }, hasOwn(rawBinding, 'template')
|
|
2401
|
+
? undefined
|
|
2402
|
+
: slotPath(id, slotName, 'repeat'));
|
|
2251
2403
|
}
|
|
2252
2404
|
else if (!binding.template) {
|
|
2253
|
-
|
|
2405
|
+
addIssue(issues, 'REPEAT_TEMPLATE_INVALID', slotPath(id, slotName, 'repeat', 'template'), `Element "${id}" slot "${slotName}" repeat template must be a non-empty string`, { elementId: id, slotName });
|
|
2254
2406
|
}
|
|
2255
2407
|
else if (!getOwnElement(schema, binding.template)) {
|
|
2256
|
-
|
|
2408
|
+
addIssue(issues, 'REPEAT_TEMPLATE_NOT_FOUND', slotPath(id, slotName, 'repeat', 'template'), `Element "${id}" slot "${slotName}" repeat references unknown template "${binding.template}"`, { elementId: id, slotName, reference: binding.template });
|
|
2409
|
+
}
|
|
2410
|
+
if (binding.item !== undefined) {
|
|
2411
|
+
validateAlias(id, slotName, 'item', binding.item, issues);
|
|
2257
2412
|
}
|
|
2258
|
-
validateAlias(id, slotName, 'item', binding.item, errors);
|
|
2259
2413
|
if (binding.index !== undefined) {
|
|
2260
|
-
validateAlias(id, slotName, 'index', binding.index,
|
|
2414
|
+
validateAlias(id, slotName, 'index', binding.index, issues);
|
|
2261
2415
|
}
|
|
2262
|
-
if (binding.index !== undefined
|
|
2263
|
-
|
|
2416
|
+
if (binding.index !== undefined
|
|
2417
|
+
&& (binding.item ?? '$item') === binding.index) {
|
|
2418
|
+
addIssue(issues, 'REPEAT_ALIAS_COLLISION', slotPath(id, slotName, 'repeat', 'index'), `Element "${id}" slot "${slotName}" repeat item and index aliases must be different`, { elementId: id, slotName, alias: binding.index });
|
|
2419
|
+
}
|
|
2420
|
+
if (binding.emptyTemplate !== undefined) {
|
|
2421
|
+
if (typeof binding.emptyTemplate !== 'string') {
|
|
2422
|
+
addIssue(issues, 'REPEAT_EMPTY_TEMPLATE_TYPE_MISMATCH', slotPath(id, slotName, 'repeat', 'emptyTemplate'), `Element "${id}" slot "${slotName}" repeat emptyTemplate must be a string`, { elementId: id, slotName });
|
|
2423
|
+
}
|
|
2424
|
+
else if (!binding.emptyTemplate) {
|
|
2425
|
+
addIssue(issues, 'REPEAT_EMPTY_TEMPLATE_INVALID', slotPath(id, slotName, 'repeat', 'emptyTemplate'), `Element "${id}" slot "${slotName}" repeat emptyTemplate must be a non-empty string`, { elementId: id, slotName });
|
|
2426
|
+
}
|
|
2427
|
+
else if (!getOwnElement(schema, binding.emptyTemplate)) {
|
|
2428
|
+
addIssue(issues, 'REPEAT_EMPTY_TEMPLATE_NOT_FOUND', slotPath(id, slotName, 'repeat', 'emptyTemplate'), `Element "${id}" slot "${slotName}" repeat references unknown empty template "${binding.emptyTemplate}"`, { elementId: id, slotName, reference: binding.emptyTemplate });
|
|
2429
|
+
}
|
|
2264
2430
|
}
|
|
2265
2431
|
}
|
|
2266
2432
|
}
|
|
2267
|
-
validateRepeatNesting(schema, dynamicBindings,
|
|
2268
|
-
validateDynamicClosures(schema, dynamicBindings,
|
|
2433
|
+
validateRepeatNesting(schema, dynamicBindings, issues);
|
|
2434
|
+
validateDynamicClosures(schema, dynamicBindings, issues);
|
|
2269
2435
|
}
|
|
2270
|
-
function validateAlias(owner, slotName, kind, alias,
|
|
2436
|
+
function validateAlias(owner, slotName, kind, alias, issues) {
|
|
2271
2437
|
if (typeof alias !== 'string') {
|
|
2272
|
-
|
|
2438
|
+
addIssue(issues, 'REPEAT_ALIAS_TYPE_MISMATCH', slotPath(owner, slotName, 'repeat', kind), `Element "${owner}" slot "${slotName}" repeat ${kind} must be a string`, { elementId: owner, slotName, field: kind });
|
|
2273
2439
|
}
|
|
2274
2440
|
else if (!ALIAS_PATTERN.test(alias)) {
|
|
2275
|
-
|
|
2441
|
+
addIssue(issues, 'REPEAT_ALIAS_INVALID', slotPath(owner, slotName, 'repeat', kind), `Element "${owner}" slot "${slotName}" repeat ${kind} alias "${alias}" is invalid`, { elementId: owner, slotName, field: kind, alias });
|
|
2276
2442
|
}
|
|
2277
2443
|
else if (RESERVED_ALIASES.has(alias)) {
|
|
2278
|
-
|
|
2444
|
+
addIssue(issues, 'REPEAT_ALIAS_RESERVED', slotPath(owner, slotName, 'repeat', kind), `Element "${owner}" slot "${slotName}" repeat ${kind} alias "${alias}" is reserved`, { elementId: owner, slotName, field: kind, alias });
|
|
2279
2445
|
}
|
|
2280
2446
|
}
|
|
2281
|
-
function validateRepeatNesting(schema, bindings,
|
|
2447
|
+
function validateRepeatNesting(schema, bindings, issues) {
|
|
2282
2448
|
const reportedCycles = new Set();
|
|
2283
2449
|
const reportedCollisions = new Set();
|
|
2450
|
+
function effectiveAliases(binding) {
|
|
2451
|
+
if (!binding)
|
|
2452
|
+
return [];
|
|
2453
|
+
if (binding.item !== undefined) {
|
|
2454
|
+
return [binding.item, binding.index].filter((alias) => typeof alias === 'string');
|
|
2455
|
+
}
|
|
2456
|
+
return [
|
|
2457
|
+
'$item',
|
|
2458
|
+
binding.index === undefined ? '$index' : binding.index,
|
|
2459
|
+
].filter((alias) => typeof alias === 'string');
|
|
2460
|
+
}
|
|
2284
2461
|
function visitElement(id, activeAliases, repeatPath, visitedStatic) {
|
|
2285
2462
|
const element = getOwnElement(schema, id);
|
|
2286
2463
|
if (!element || visitedStatic.has(id))
|
|
@@ -2295,26 +2472,31 @@ function validateRepeatNesting(schema, bindings, errors) {
|
|
|
2295
2472
|
? readRepeatBindingFields(repeat.value)
|
|
2296
2473
|
: undefined;
|
|
2297
2474
|
const a2uiBinding = getA2UIChildBinding(slot);
|
|
2298
|
-
const
|
|
2299
|
-
|
|
2475
|
+
const itemTemplate = nativeBinding?.template ?? a2uiBinding?.templateId;
|
|
2476
|
+
const visitDynamicTemplate = (template, aliases) => {
|
|
2477
|
+
if (!template)
|
|
2478
|
+
return;
|
|
2300
2479
|
const cycleAt = repeatPath.indexOf(template);
|
|
2301
2480
|
if (cycleAt >= 0) {
|
|
2302
2481
|
const cycle = [...repeatPath.slice(cycleAt), template].join(' -> ');
|
|
2303
2482
|
if (!reportedCycles.has(cycle)) {
|
|
2304
2483
|
reportedCycles.add(cycle);
|
|
2305
|
-
|
|
2484
|
+
addIssue(issues, nativeBinding
|
|
2485
|
+
? 'REPEAT_TEMPLATE_CYCLE'
|
|
2486
|
+
: 'DYNAMIC_TEMPLATE_CYCLE', nativeBinding
|
|
2487
|
+
? slotPath(id, slotName, 'repeat', 'template')
|
|
2488
|
+
: slotPath(id, slotName), nativeBinding
|
|
2306
2489
|
? `Element "${id}" slot "${slotName}" has repeat template cycle: ${cycle}`
|
|
2307
|
-
: `Element "${id}" slot "${slotName}" has dynamic template cycle: ${cycle}
|
|
2490
|
+
: `Element "${id}" slot "${slotName}" has dynamic template cycle: ${cycle}`, { elementId: id, slotName, cycle });
|
|
2308
2491
|
}
|
|
2309
|
-
|
|
2492
|
+
return;
|
|
2310
2493
|
}
|
|
2311
|
-
const aliases = [nativeBinding?.item, nativeBinding?.index].filter((alias) => typeof alias === 'string');
|
|
2312
2494
|
for (const alias of aliases) {
|
|
2313
2495
|
if (activeAliases.has(alias)) {
|
|
2314
2496
|
const key = `${id}:${slotName}:${alias}`;
|
|
2315
2497
|
if (!reportedCollisions.has(key)) {
|
|
2316
2498
|
reportedCollisions.add(key);
|
|
2317
|
-
|
|
2499
|
+
addIssue(issues, 'REPEAT_ALIAS_COLLISION', slotPath(id, slotName, 'repeat'), `Element "${id}" slot "${slotName}" repeat alias "${alias}" conflicts with an active repeat alias`, { elementId: id, slotName, alias });
|
|
2318
2500
|
}
|
|
2319
2501
|
}
|
|
2320
2502
|
}
|
|
@@ -2322,7 +2504,9 @@ function validateRepeatNesting(schema, bindings, errors) {
|
|
|
2322
2504
|
for (const alias of aliases)
|
|
2323
2505
|
nestedAliases.add(alias);
|
|
2324
2506
|
visitElement(template, nestedAliases, [...repeatPath, template], new Set());
|
|
2325
|
-
}
|
|
2507
|
+
};
|
|
2508
|
+
visitDynamicTemplate(itemTemplate, effectiveAliases(nativeBinding));
|
|
2509
|
+
visitDynamicTemplate(nativeBinding?.emptyTemplate, []);
|
|
2326
2510
|
for (const child of slotStaticReferences(slot)) {
|
|
2327
2511
|
visitElement(child, activeAliases, repeatPath, nextVisitedStatic);
|
|
2328
2512
|
}
|
|
@@ -2330,13 +2514,17 @@ function validateRepeatNesting(schema, bindings, errors) {
|
|
|
2330
2514
|
}
|
|
2331
2515
|
for (const dynamic of bindings) {
|
|
2332
2516
|
const { owner, binding, template } = dynamic;
|
|
2333
|
-
const aliases = new Set(
|
|
2517
|
+
const aliases = new Set(effectiveAliases(binding));
|
|
2334
2518
|
if (typeof template === 'string' && template) {
|
|
2335
2519
|
visitElement(template, aliases, [owner, template], new Set());
|
|
2336
2520
|
}
|
|
2521
|
+
if (typeof binding?.emptyTemplate === 'string'
|
|
2522
|
+
&& binding.emptyTemplate) {
|
|
2523
|
+
visitElement(binding.emptyTemplate, new Set(), [owner, binding.emptyTemplate], new Set());
|
|
2524
|
+
}
|
|
2337
2525
|
}
|
|
2338
2526
|
}
|
|
2339
|
-
function validateDynamicClosures(schema, repeats,
|
|
2527
|
+
function validateDynamicClosures(schema, repeats, issues) {
|
|
2340
2528
|
for (const { owner } of repeats) {
|
|
2341
2529
|
const visited = new Set();
|
|
2342
2530
|
function visit(id) {
|
|
@@ -2350,10 +2538,11 @@ function validateDynamicClosures(schema, repeats, errors) {
|
|
|
2350
2538
|
if ((lifecycle.kind === 'value' && !!lifecycle.value)
|
|
2351
2539
|
|| lifecycle.kind === 'accessor'
|
|
2352
2540
|
|| lifecycle.kind === 'opaque') {
|
|
2353
|
-
|
|
2541
|
+
addIssue(issues, 'DYNAMIC_LIFECYCLE_UNSUPPORTED', elementPath(id, 'lifecycle'), `Element "${id}" in dynamic patch closure owned by "${owner}" cannot use lifecycle`, { elementId: id, owner });
|
|
2354
2542
|
}
|
|
2355
|
-
|
|
2356
|
-
|
|
2543
|
+
const props = readOwnData(element, 'props');
|
|
2544
|
+
if (props.kind === 'value' && hasOwn(props.value, 'variableKey')) {
|
|
2545
|
+
addIssue(issues, 'DYNAMIC_VARIABLE_KEY_UNSUPPORTED', elementPath(id, 'props', 'variableKey'), `Element "${id}" in dynamic patch closure owned by "${owner}" cannot use props.variableKey`, { elementId: id, owner });
|
|
2357
2546
|
}
|
|
2358
2547
|
for (const reference of elementReferences(element))
|
|
2359
2548
|
visit(reference);
|
|
@@ -2880,6 +3069,7 @@ function materializeCard(input, variables, options = {}) {
|
|
|
2880
3069
|
template: native.template,
|
|
2881
3070
|
item: native.item,
|
|
2882
3071
|
index: native.index,
|
|
3072
|
+
emptyTemplate: native.emptyTemplate,
|
|
2883
3073
|
};
|
|
2884
3074
|
}
|
|
2885
3075
|
else {
|
|
@@ -2907,6 +3097,9 @@ function materializeCard(input, variables, options = {}) {
|
|
|
2907
3097
|
sourceOwnerId: sourceId,
|
|
2908
3098
|
slot: slotName,
|
|
2909
3099
|
templateId: binding.template,
|
|
3100
|
+
...(binding.emptyTemplate
|
|
3101
|
+
? { emptyTemplateId: binding.emptyTemplate }
|
|
3102
|
+
: {}),
|
|
2910
3103
|
...(sourcePath === undefined ? {} : { sourcePath }),
|
|
2911
3104
|
dataPath: activeScope.dataPath,
|
|
2912
3105
|
instancePath,
|
|
@@ -2918,6 +3111,9 @@ function materializeCard(input, variables, options = {}) {
|
|
|
2918
3111
|
repeatOwners.set(ownerKey, owner);
|
|
2919
3112
|
slotOwners.set(slotName, { owner, binding, sourcePath, depth });
|
|
2920
3113
|
addDependency('component', binding.template, ownerKey);
|
|
3114
|
+
if (binding.emptyTemplate) {
|
|
3115
|
+
addDependency('component', binding.emptyTemplate, ownerKey);
|
|
3116
|
+
}
|
|
2921
3117
|
const runtimeKeys = runtimeOwnerKeys.get(id) ?? [];
|
|
2922
3118
|
if (runtimeKeys.length > 0) {
|
|
2923
3119
|
for (const key of runtimeKeys)
|
|
@@ -2998,15 +3194,30 @@ function materializeCard(input, variables, options = {}) {
|
|
|
2998
3194
|
Reflect.deleteProperty(slot, 'repeat');
|
|
2999
3195
|
Reflect.deleteProperty(slot, A2UI_CHILD_BINDING);
|
|
3000
3196
|
slot.children = [];
|
|
3197
|
+
if (items.length === 0
|
|
3198
|
+
&& binding.dialect === 'native'
|
|
3199
|
+
&& binding.emptyTemplate) {
|
|
3200
|
+
const emptyPath = appendOccurrence(structuralPath, 'item', sourceId, slotName, `${binding.emptyTemplate}:empty`);
|
|
3201
|
+
const empty = buildNode(binding.emptyTemplate, activeScope, emptyPath, emptyPath, true, id, depth, owner.key, nextActiveDefinitions);
|
|
3202
|
+
slot.children.push(empty.id);
|
|
3203
|
+
node.children.push(empty);
|
|
3204
|
+
}
|
|
3001
3205
|
items.forEach((item, index) => {
|
|
3002
3206
|
const dataPath = sourcePath === undefined
|
|
3003
3207
|
? activeScope.dataPath
|
|
3004
3208
|
: joinPointer(sourcePath, [String(index)]);
|
|
3005
|
-
const locals = binding.dialect === 'native'
|
|
3006
|
-
?
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3209
|
+
const locals = binding.dialect === 'native'
|
|
3210
|
+
? binding.item !== undefined
|
|
3211
|
+
? {
|
|
3212
|
+
[binding.item]: item,
|
|
3213
|
+
...(binding.index === undefined
|
|
3214
|
+
? {}
|
|
3215
|
+
: { [binding.index]: index }),
|
|
3216
|
+
}
|
|
3217
|
+
: {
|
|
3218
|
+
$item: item,
|
|
3219
|
+
[binding.index ?? '$index']: index,
|
|
3220
|
+
}
|
|
3010
3221
|
: {};
|
|
3011
3222
|
const childScope = {
|
|
3012
3223
|
root: rootVariables,
|
|
@@ -3016,14 +3227,23 @@ function materializeCard(input, variables, options = {}) {
|
|
|
3016
3227
|
bindingDialect: binding.dialect,
|
|
3017
3228
|
};
|
|
3018
3229
|
const aliases = new Map();
|
|
3019
|
-
if (binding.dialect === 'native'
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3230
|
+
if (binding.dialect === 'native') {
|
|
3231
|
+
const itemAlias = binding.item ?? '$item';
|
|
3232
|
+
const indexAlias = binding.item === undefined
|
|
3233
|
+
? binding.index ?? '$index'
|
|
3234
|
+
: binding.index;
|
|
3235
|
+
aliases.set(itemAlias, sourcePath === undefined ? undefined : dataPath);
|
|
3236
|
+
if (indexAlias !== undefined) {
|
|
3237
|
+
aliases.set(indexAlias, sourcePath);
|
|
3238
|
+
}
|
|
3023
3239
|
}
|
|
3024
3240
|
scopeAliasPaths.set(childScope, aliases);
|
|
3025
|
-
scopeIndexAliases.set(childScope, new Set(binding.dialect === 'native'
|
|
3026
|
-
?
|
|
3241
|
+
scopeIndexAliases.set(childScope, new Set(binding.dialect === 'native'
|
|
3242
|
+
? binding.item === undefined
|
|
3243
|
+
? [binding.index ?? '$index']
|
|
3244
|
+
: binding.index === undefined
|
|
3245
|
+
? []
|
|
3246
|
+
: [binding.index]
|
|
3027
3247
|
: []));
|
|
3028
3248
|
const itemPath = appendOccurrence(structuralPath, 'item', sourceId, slotName, `${binding.template}:${index}`);
|
|
3029
3249
|
const child = buildNode(binding.template, childScope, itemPath, itemPath, true, id, depth, owner.key, nextActiveDefinitions);
|
|
@@ -4749,4 +4969,4 @@ function getBuiltinIcon(name) {
|
|
|
4749
4969
|
return BUILTIN_ICONS[name];
|
|
4750
4970
|
}
|
|
4751
4971
|
|
|
4752
|
-
export { ActionRegistry, BUILTIN_ICONS, BUILTIN_ICON_NAMES, JsonPointerPathError, LifecycleManager, StreamingEngine, StreamingParser, a2uiComponentToElement, a2uiToCommand, bindingTopologyFingerprint, cloneJsonData, convertLegacySchema, createA2UIParameterResolver, createExpressionContext, createLifecycleManager, decodeJsonPointerSegment, extractPartialSchema, findAffectedRepeatOwners, findTemplateRepeatOwners, getBuiltinIcon, getByJsonPointer, getByPath$1 as getByPath, hasDynamicChildren, hasExpression, interpolate, isA2UIChildList, isA2UIDynamicChildList, isA2UIEnvelope, isA2UIPathBinding, isBoundRenderTreeNode, isLegacySchema, materializeCard, normalizeSchema, parseJsonPointer, parseSchema, registerActionHandler, registry, replaceRootContents, requiresBindingMaterialization, resetIdCounter, resolveA2UIDeep, resolveA2UIPath, resolveActionRef, resolveDeep, resolveExpression, resolveExpressionValue, runActionStep, runActionSteps, setByJsonPointer, setByPath, validateSchema };
|
|
4972
|
+
export { ActionRegistry, BUILTIN_ICONS, BUILTIN_ICON_NAMES, JsonPointerPathError, LifecycleManager, StreamingEngine, StreamingParser, a2uiComponentToElement, a2uiToCommand, bindingTopologyFingerprint, cloneJsonData, convertLegacySchema, createA2UIParameterResolver, createExpressionContext, createLifecycleManager, decodeJsonPointerSegment, extractPartialSchema, findAffectedRepeatOwners, findTemplateRepeatOwners, getBuiltinIcon, getByJsonPointer, getByPath$1 as getByPath, hasDynamicChildren, hasExpression, interpolate, isA2UIChildList, isA2UIDynamicChildList, isA2UIEnvelope, isA2UIPathBinding, isBoundRenderTreeNode, isLegacySchema, materializeCard, normalizeSchema, parseJsonPointer, parseSchema, registerActionHandler, registry, replaceRootContents, requiresBindingMaterialization, resetIdCounter, resolveA2UIDeep, resolveA2UIPath, resolveActionRef, resolveDeep, resolveExpression, resolveExpressionValue, runActionStep, runActionSteps, setByJsonPointer, setByPath, validateSchema, validateSchemaDetailed };
|