@makehq/forman-schema 1.9.6 → 1.11.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.
- package/dist/index.cjs +157 -46
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +157 -46
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1066,6 +1066,47 @@ function extractNestedFromField(field) {
|
|
|
1066
1066
|
if (isObject(field.options) && field.options.nested) return field.options.nested;
|
|
1067
1067
|
return void 0;
|
|
1068
1068
|
}
|
|
1069
|
+
var SCHEMA_STRIP_KEYS = [
|
|
1070
|
+
"nested",
|
|
1071
|
+
"options",
|
|
1072
|
+
"help",
|
|
1073
|
+
"rpc",
|
|
1074
|
+
"sort",
|
|
1075
|
+
"disabled",
|
|
1076
|
+
"multiline",
|
|
1077
|
+
"tags",
|
|
1078
|
+
"extension",
|
|
1079
|
+
"codepage",
|
|
1080
|
+
"logic"
|
|
1081
|
+
];
|
|
1082
|
+
function clampFieldForSchema(field) {
|
|
1083
|
+
const clamped = { ...field };
|
|
1084
|
+
for (const key of SCHEMA_STRIP_KEYS) {
|
|
1085
|
+
delete clamped[key];
|
|
1086
|
+
}
|
|
1087
|
+
if (field.spec != null) {
|
|
1088
|
+
clamped.spec = Array.isArray(field.spec) ? field.spec.map(clampFieldForSchema) : clampFieldForSchema(field.spec);
|
|
1089
|
+
}
|
|
1090
|
+
if (field.type === "select" && !field.validate?.enum) {
|
|
1091
|
+
const rawOptions = isObject(field.options) ? field.options.store : field.options;
|
|
1092
|
+
if (Array.isArray(rawOptions)) {
|
|
1093
|
+
const values = [];
|
|
1094
|
+
for (const item of rawOptions) {
|
|
1095
|
+
if ("options" in item) {
|
|
1096
|
+
for (const opt of item.options) {
|
|
1097
|
+
values.push(opt.value);
|
|
1098
|
+
}
|
|
1099
|
+
} else if ("value" in item) {
|
|
1100
|
+
values.push(item.value);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
if (values.length > 0) {
|
|
1104
|
+
clamped.validate = { ...clamped.validate, enum: values.map(String) };
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return clamped;
|
|
1109
|
+
}
|
|
1069
1110
|
var FORMAN_TYPE_MAP2 = {
|
|
1070
1111
|
account: "number",
|
|
1071
1112
|
hook: "number",
|
|
@@ -1110,11 +1151,13 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
1110
1151
|
};
|
|
1111
1152
|
async function validateFormanWithDomainsInternal(domains, options) {
|
|
1112
1153
|
const errors = [];
|
|
1154
|
+
const warnings = [];
|
|
1113
1155
|
const roots = Object.keys(domains).reduce(
|
|
1114
1156
|
(acc, domain) => {
|
|
1115
1157
|
acc[domain] = {
|
|
1116
1158
|
seenFields: /* @__PURE__ */ new Set(),
|
|
1117
1159
|
fieldStates: [],
|
|
1160
|
+
schemaFields: [],
|
|
1118
1161
|
validateFields: (fields, context) => {
|
|
1119
1162
|
return validateFormanValue(
|
|
1120
1163
|
domains[domain].values,
|
|
@@ -1173,6 +1216,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1173
1216
|
}
|
|
1174
1217
|
);
|
|
1175
1218
|
errors.push(...result.errors);
|
|
1219
|
+
warnings.push(...result.warnings);
|
|
1176
1220
|
const restoreExtras = options?.states && domains[domain]?.restoreExtras;
|
|
1177
1221
|
if (restoreExtras) {
|
|
1178
1222
|
const fieldStateMap = new Map(
|
|
@@ -1208,16 +1252,19 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1208
1252
|
return {
|
|
1209
1253
|
valid: errors.length === 0,
|
|
1210
1254
|
errors,
|
|
1255
|
+
warnings,
|
|
1211
1256
|
states: errors.length === 0 && options?.states ? buildRestoreStructure(
|
|
1212
1257
|
Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
|
|
1213
|
-
) : void 0
|
|
1258
|
+
) : void 0,
|
|
1259
|
+
schemas: errors.length === 0 && options?.schemas ? Object.fromEntries(Object.keys(domains).map((domain) => [domain, roots[domain].schemaFields])) : void 0
|
|
1214
1260
|
};
|
|
1215
1261
|
}
|
|
1216
1262
|
async function validateFormanValue(value, field, context) {
|
|
1217
1263
|
if (isVisualType(field.type)) {
|
|
1218
1264
|
return {
|
|
1219
1265
|
valid: true,
|
|
1220
|
-
errors: []
|
|
1266
|
+
errors: [],
|
|
1267
|
+
warnings: []
|
|
1221
1268
|
};
|
|
1222
1269
|
}
|
|
1223
1270
|
const normalizedField = normalizeFormanFieldType(field);
|
|
@@ -1230,7 +1277,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1230
1277
|
path: context.path.join("."),
|
|
1231
1278
|
message: "Field is mandatory."
|
|
1232
1279
|
}
|
|
1233
|
-
]
|
|
1280
|
+
],
|
|
1281
|
+
warnings: []
|
|
1234
1282
|
};
|
|
1235
1283
|
}
|
|
1236
1284
|
if (value == null || value === "") {
|
|
@@ -1239,7 +1287,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1239
1287
|
}
|
|
1240
1288
|
return {
|
|
1241
1289
|
valid: true,
|
|
1242
|
-
errors: []
|
|
1290
|
+
errors: [],
|
|
1291
|
+
warnings: []
|
|
1243
1292
|
};
|
|
1244
1293
|
}
|
|
1245
1294
|
const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
|
|
@@ -1254,7 +1303,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1254
1303
|
path: context.path.join("."),
|
|
1255
1304
|
message: `Expected type '${expectedType}', got type '${actualType}'.`
|
|
1256
1305
|
}
|
|
1257
|
-
]
|
|
1306
|
+
],
|
|
1307
|
+
warnings: []
|
|
1258
1308
|
};
|
|
1259
1309
|
}
|
|
1260
1310
|
if (containsIMLExpression(value)) {
|
|
@@ -1267,7 +1317,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1267
1317
|
path: context.path.join("."),
|
|
1268
1318
|
message: "Value contains prohibited IML expression."
|
|
1269
1319
|
}
|
|
1270
|
-
]
|
|
1320
|
+
],
|
|
1321
|
+
warnings: []
|
|
1271
1322
|
};
|
|
1272
1323
|
}
|
|
1273
1324
|
if (isEditableType(normalizedField.type)) {
|
|
@@ -1282,7 +1333,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1282
1333
|
}
|
|
1283
1334
|
return {
|
|
1284
1335
|
valid: true,
|
|
1285
|
-
errors: []
|
|
1336
|
+
errors: [],
|
|
1337
|
+
warnings: []
|
|
1286
1338
|
};
|
|
1287
1339
|
}
|
|
1288
1340
|
if (normalizedField.type === "udttype") {
|
|
@@ -1317,6 +1369,7 @@ async function validateFormanValue(value, field, context) {
|
|
|
1317
1369
|
}
|
|
1318
1370
|
async function handleCollectionType2(value, field, context) {
|
|
1319
1371
|
const errors = [];
|
|
1372
|
+
const warnings = [];
|
|
1320
1373
|
const seen = context.path.length === 0 ? context.roots[context.domain].seenFields : /* @__PURE__ */ new Set();
|
|
1321
1374
|
const path = context.path;
|
|
1322
1375
|
if (Array.isArray(field.spec)) {
|
|
@@ -1343,7 +1396,8 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1343
1396
|
path: context.path.join("."),
|
|
1344
1397
|
message: `Failed to resolve remote resource ${subField}: ${error}`
|
|
1345
1398
|
}
|
|
1346
|
-
]
|
|
1399
|
+
],
|
|
1400
|
+
warnings
|
|
1347
1401
|
};
|
|
1348
1402
|
}
|
|
1349
1403
|
}
|
|
@@ -1359,6 +1413,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1359
1413
|
continue;
|
|
1360
1414
|
}
|
|
1361
1415
|
if (context.strict && !seen.has(subField.name)) seen.add(subField.name);
|
|
1416
|
+
if (path.length === 0) {
|
|
1417
|
+
context.roots[context.domain].schemaFields.push(clampFieldForSchema(subField));
|
|
1418
|
+
}
|
|
1362
1419
|
const result = await validateFormanValue(value[subField.name], subField, {
|
|
1363
1420
|
...context,
|
|
1364
1421
|
path: [...path, subField.name],
|
|
@@ -1376,15 +1433,20 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1376
1433
|
continue;
|
|
1377
1434
|
}
|
|
1378
1435
|
if (context2.strict && !seen.has(subField2.name)) seen.add(subField2.name);
|
|
1436
|
+
if (path.length === 0) {
|
|
1437
|
+
context2.roots[context2.domain].schemaFields.push(clampFieldForSchema(subField2));
|
|
1438
|
+
}
|
|
1379
1439
|
const result2 = await validateFormanValue(value[subField2.name], subField2, {
|
|
1380
1440
|
...context2,
|
|
1381
1441
|
path: [...path, subField2.name]
|
|
1382
1442
|
});
|
|
1383
1443
|
errors.push(...result2.errors);
|
|
1444
|
+
warnings.push(...result2.warnings);
|
|
1384
1445
|
}
|
|
1385
1446
|
}
|
|
1386
1447
|
});
|
|
1387
1448
|
errors.push(...result.errors);
|
|
1449
|
+
warnings.push(...result.warnings);
|
|
1388
1450
|
}
|
|
1389
1451
|
}
|
|
1390
1452
|
if (context.strict && context.path.length > 0) {
|
|
@@ -1401,11 +1463,13 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1401
1463
|
}
|
|
1402
1464
|
return {
|
|
1403
1465
|
valid: errors.length === 0,
|
|
1404
|
-
errors
|
|
1466
|
+
errors,
|
|
1467
|
+
warnings
|
|
1405
1468
|
};
|
|
1406
1469
|
}
|
|
1407
1470
|
async function handleArrayType2(value, field, context) {
|
|
1408
1471
|
const errors = [];
|
|
1472
|
+
const warnings = [];
|
|
1409
1473
|
if (field.spec) {
|
|
1410
1474
|
for (const [index, item] of value.entries()) {
|
|
1411
1475
|
const result = await validateFormanValue(
|
|
@@ -1414,6 +1478,7 @@ async function handleArrayType2(value, field, context) {
|
|
|
1414
1478
|
{ ...context, path: [...context.path, index] }
|
|
1415
1479
|
);
|
|
1416
1480
|
errors.push(...result.errors);
|
|
1481
|
+
warnings.push(...result.warnings);
|
|
1417
1482
|
}
|
|
1418
1483
|
}
|
|
1419
1484
|
if (field.validate) {
|
|
@@ -1434,7 +1499,8 @@ async function handleArrayType2(value, field, context) {
|
|
|
1434
1499
|
}
|
|
1435
1500
|
return {
|
|
1436
1501
|
valid: errors.length === 0,
|
|
1437
|
-
errors
|
|
1502
|
+
errors,
|
|
1503
|
+
warnings
|
|
1438
1504
|
};
|
|
1439
1505
|
}
|
|
1440
1506
|
async function handleFilterType2(value, field, context) {
|
|
@@ -1491,6 +1557,7 @@ async function handleFilterType2(value, field, context) {
|
|
|
1491
1557
|
}
|
|
1492
1558
|
async function handlePathType(value, field, context) {
|
|
1493
1559
|
const errors = [];
|
|
1560
|
+
const warnings = [];
|
|
1494
1561
|
if (typeof value !== "string") {
|
|
1495
1562
|
return {
|
|
1496
1563
|
valid: false,
|
|
@@ -1501,7 +1568,8 @@ async function handlePathType(value, field, context) {
|
|
|
1501
1568
|
path: context.path.join("."),
|
|
1502
1569
|
message: `Expected type 'string' for path, got type '${typeof value}'.`
|
|
1503
1570
|
}
|
|
1504
|
-
]
|
|
1571
|
+
],
|
|
1572
|
+
warnings
|
|
1505
1573
|
};
|
|
1506
1574
|
}
|
|
1507
1575
|
let showRoot = true;
|
|
@@ -1526,7 +1594,8 @@ async function handlePathType(value, field, context) {
|
|
|
1526
1594
|
path: context.path.join("."),
|
|
1527
1595
|
message: `Single level path cannot contain slashes.`
|
|
1528
1596
|
}
|
|
1529
|
-
]
|
|
1597
|
+
],
|
|
1598
|
+
warnings
|
|
1530
1599
|
};
|
|
1531
1600
|
}
|
|
1532
1601
|
let nested = field.nested ? field.nested : isObject(field.options) ? field.options.nested : void 0;
|
|
@@ -1535,7 +1604,8 @@ async function handlePathType(value, field, context) {
|
|
|
1535
1604
|
if (showRoot && value === "/" && field.type === "folder") {
|
|
1536
1605
|
return {
|
|
1537
1606
|
valid: true,
|
|
1538
|
-
errors: []
|
|
1607
|
+
errors: [],
|
|
1608
|
+
warnings
|
|
1539
1609
|
};
|
|
1540
1610
|
}
|
|
1541
1611
|
if (levels.length < 2) {
|
|
@@ -1548,11 +1618,13 @@ async function handlePathType(value, field, context) {
|
|
|
1548
1618
|
path: context.path.join("."),
|
|
1549
1619
|
message: `Invalid path "${value}" encountered.`
|
|
1550
1620
|
}
|
|
1551
|
-
]
|
|
1621
|
+
],
|
|
1622
|
+
warnings
|
|
1552
1623
|
};
|
|
1553
1624
|
}
|
|
1554
1625
|
const selectedPath = [];
|
|
1555
1626
|
let levelOptions = [];
|
|
1627
|
+
let optionsFromRPC = false;
|
|
1556
1628
|
for (let levelIndex = 0; levelIndex < levels.length - 1; ++levelIndex) {
|
|
1557
1629
|
const isLastLevel = levelIndex === levels.length - 2;
|
|
1558
1630
|
const levelSelectedValue = levels[levelIndex + 1];
|
|
@@ -1567,7 +1639,8 @@ async function handlePathType(value, field, context) {
|
|
|
1567
1639
|
path: context.path.join("."),
|
|
1568
1640
|
message: `Invalid selected value of "${value}" encountered.`
|
|
1569
1641
|
}
|
|
1570
|
-
]
|
|
1642
|
+
],
|
|
1643
|
+
warnings
|
|
1571
1644
|
};
|
|
1572
1645
|
}
|
|
1573
1646
|
if (typeof options === "string") {
|
|
@@ -1575,6 +1648,7 @@ async function handlePathType(value, field, context) {
|
|
|
1575
1648
|
levelOptions = await context.resolveRemote(options, context, {
|
|
1576
1649
|
[field.name]: (showRoot && !selectedPathValue.startsWith("/") ? "/" : "") + selectedPathValue
|
|
1577
1650
|
});
|
|
1651
|
+
optionsFromRPC = true;
|
|
1578
1652
|
} catch (error) {
|
|
1579
1653
|
return {
|
|
1580
1654
|
valid: false,
|
|
@@ -1585,7 +1659,8 @@ async function handlePathType(value, field, context) {
|
|
|
1585
1659
|
path: context.path.join("."),
|
|
1586
1660
|
message: `Failed to resolve remote resource ${options}: ${error}`
|
|
1587
1661
|
}
|
|
1588
|
-
]
|
|
1662
|
+
],
|
|
1663
|
+
warnings
|
|
1589
1664
|
};
|
|
1590
1665
|
}
|
|
1591
1666
|
} else if (isLastLevel) {
|
|
@@ -1602,6 +1677,14 @@ async function handlePathType(value, field, context) {
|
|
|
1602
1677
|
});
|
|
1603
1678
|
const selectedOption = selectableOptions.find((candidate) => candidate.value === levelSelectedValue);
|
|
1604
1679
|
if (!selectedOption) {
|
|
1680
|
+
if (optionsFromRPC) {
|
|
1681
|
+
warnings.push({
|
|
1682
|
+
domain: context.domain,
|
|
1683
|
+
path: context.path.join("."),
|
|
1684
|
+
message: `Path '${levelSelectedValue}' not found in options.`
|
|
1685
|
+
});
|
|
1686
|
+
break;
|
|
1687
|
+
}
|
|
1605
1688
|
return {
|
|
1606
1689
|
valid: false,
|
|
1607
1690
|
errors: [
|
|
@@ -1611,7 +1694,8 @@ async function handlePathType(value, field, context) {
|
|
|
1611
1694
|
path: context.path.join("."),
|
|
1612
1695
|
message: `Path '${levelSelectedValue}' not found in options.`
|
|
1613
1696
|
}
|
|
1614
|
-
]
|
|
1697
|
+
],
|
|
1698
|
+
warnings
|
|
1615
1699
|
};
|
|
1616
1700
|
}
|
|
1617
1701
|
selectedPath.push(selectedOption);
|
|
@@ -1628,16 +1712,20 @@ async function handlePathType(value, field, context) {
|
|
|
1628
1712
|
if (nested) {
|
|
1629
1713
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1630
1714
|
errors.push(...result.errors);
|
|
1715
|
+
warnings.push(...result.warnings);
|
|
1631
1716
|
}
|
|
1632
1717
|
return {
|
|
1633
1718
|
valid: errors.length === 0,
|
|
1634
|
-
errors
|
|
1719
|
+
errors,
|
|
1720
|
+
warnings
|
|
1635
1721
|
};
|
|
1636
1722
|
}
|
|
1637
1723
|
async function handleSelectType(value, field, context) {
|
|
1638
1724
|
const errors = [];
|
|
1725
|
+
const warnings = [];
|
|
1639
1726
|
let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
1640
1727
|
let nested = extractNestedFromField(field);
|
|
1728
|
+
let optionsFromRPC = false;
|
|
1641
1729
|
if (typeof optionsOrGroups === "string") {
|
|
1642
1730
|
try {
|
|
1643
1731
|
const resolved = await context.resolveRemote(optionsOrGroups, context);
|
|
@@ -1651,10 +1739,12 @@ async function handleSelectType(value, field, context) {
|
|
|
1651
1739
|
path: context.path.join("."),
|
|
1652
1740
|
message: `Remote resource ${optionsOrGroups} returned no data.`
|
|
1653
1741
|
}
|
|
1654
|
-
]
|
|
1742
|
+
],
|
|
1743
|
+
warnings
|
|
1655
1744
|
};
|
|
1656
1745
|
}
|
|
1657
1746
|
optionsOrGroups = Array.isArray(resolved) ? resolved : [resolved];
|
|
1747
|
+
optionsFromRPC = true;
|
|
1658
1748
|
} catch (error) {
|
|
1659
1749
|
return {
|
|
1660
1750
|
valid: false,
|
|
@@ -1665,7 +1755,8 @@ async function handleSelectType(value, field, context) {
|
|
|
1665
1755
|
path: context.path.join("."),
|
|
1666
1756
|
message: `Failed to resolve remote resource ${optionsOrGroups}: ${error}`
|
|
1667
1757
|
}
|
|
1668
|
-
]
|
|
1758
|
+
],
|
|
1759
|
+
warnings
|
|
1669
1760
|
};
|
|
1670
1761
|
}
|
|
1671
1762
|
}
|
|
@@ -1680,7 +1771,8 @@ async function handleSelectType(value, field, context) {
|
|
|
1680
1771
|
path: context.path.join("."),
|
|
1681
1772
|
message: `Value is not an array.`
|
|
1682
1773
|
}
|
|
1683
|
-
]
|
|
1774
|
+
],
|
|
1775
|
+
warnings
|
|
1684
1776
|
};
|
|
1685
1777
|
}
|
|
1686
1778
|
for (const singleValue of value) {
|
|
@@ -1690,7 +1782,7 @@ async function handleSelectType(value, field, context) {
|
|
|
1690
1782
|
optionsOrGroups
|
|
1691
1783
|
);
|
|
1692
1784
|
if (!found) {
|
|
1693
|
-
errors.push({
|
|
1785
|
+
(optionsFromRPC ? warnings : errors).push({
|
|
1694
1786
|
domain: context.domain,
|
|
1695
1787
|
path: context.path.join("."),
|
|
1696
1788
|
message: `Value '${singleValue}' not found in options.`
|
|
@@ -1728,40 +1820,53 @@ async function handleSelectType(value, field, context) {
|
|
|
1728
1820
|
} else {
|
|
1729
1821
|
const item = findValueInSelectOptions(field, value, optionsOrGroups);
|
|
1730
1822
|
if (!item) {
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
{
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1823
|
+
if (optionsFromRPC) {
|
|
1824
|
+
warnings.push({
|
|
1825
|
+
domain: context.domain,
|
|
1826
|
+
path: context.path.join("."),
|
|
1827
|
+
message: `Value '${value}' not found in options.`
|
|
1828
|
+
});
|
|
1829
|
+
} else {
|
|
1830
|
+
return {
|
|
1831
|
+
valid: false,
|
|
1832
|
+
errors: [
|
|
1833
|
+
...errors,
|
|
1834
|
+
{
|
|
1835
|
+
domain: context.domain,
|
|
1836
|
+
path: context.path.join("."),
|
|
1837
|
+
message: `Value '${value}' not found in options.`
|
|
1838
|
+
}
|
|
1839
|
+
],
|
|
1840
|
+
warnings
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
} else {
|
|
1844
|
+
if (item.label) {
|
|
1845
|
+
context.roots[context.domain].fieldStates.push({
|
|
1846
|
+
path: context.path,
|
|
1847
|
+
state: {
|
|
1848
|
+
mode: isReferenceType(field.type) ? void 0 : "chose",
|
|
1849
|
+
label: item.label
|
|
1739
1850
|
}
|
|
1740
|
-
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
if (item.label) {
|
|
1744
|
-
context.roots[context.domain].fieldStates.push({
|
|
1745
|
-
path: context.path,
|
|
1746
|
-
state: {
|
|
1747
|
-
mode: isReferenceType(field.type) ? void 0 : "chose",
|
|
1748
|
-
label: item.label
|
|
1749
|
-
}
|
|
1750
|
-
});
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
if (item.nested) nested = item.nested;
|
|
1751
1854
|
}
|
|
1752
|
-
if (item.nested) nested = item.nested;
|
|
1753
1855
|
}
|
|
1754
1856
|
if (nested) {
|
|
1755
1857
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1756
1858
|
errors.push(...result.errors);
|
|
1859
|
+
warnings.push(...result.warnings);
|
|
1757
1860
|
}
|
|
1758
1861
|
return {
|
|
1759
1862
|
valid: errors.length === 0,
|
|
1760
|
-
errors
|
|
1863
|
+
errors,
|
|
1864
|
+
warnings
|
|
1761
1865
|
};
|
|
1762
1866
|
}
|
|
1763
1867
|
async function handleNestedFields(nested, value, field, context) {
|
|
1764
1868
|
const errors = [];
|
|
1869
|
+
const warnings = [];
|
|
1765
1870
|
let store = isObject(nested) ? nested.store : nested;
|
|
1766
1871
|
const domain = isObject(nested) && nested.domain ? nested.domain : void 0;
|
|
1767
1872
|
context = {
|
|
@@ -1792,7 +1897,8 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1792
1897
|
path: context.path.join("."),
|
|
1793
1898
|
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
1794
1899
|
}
|
|
1795
|
-
]
|
|
1900
|
+
],
|
|
1901
|
+
warnings
|
|
1796
1902
|
};
|
|
1797
1903
|
}
|
|
1798
1904
|
} else {
|
|
@@ -1812,17 +1918,20 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1812
1918
|
} else {
|
|
1813
1919
|
const result = await context.roots[resolvedDomain].validateFields(store, context);
|
|
1814
1920
|
errors.push(...result.errors);
|
|
1921
|
+
warnings.push(...result.warnings);
|
|
1815
1922
|
}
|
|
1816
1923
|
} else if (store) {
|
|
1817
1924
|
await context.validateNestedFields(store, context);
|
|
1818
1925
|
}
|
|
1819
1926
|
return {
|
|
1820
1927
|
valid: errors.length === 0,
|
|
1821
|
-
errors
|
|
1928
|
+
errors,
|
|
1929
|
+
warnings
|
|
1822
1930
|
};
|
|
1823
1931
|
}
|
|
1824
1932
|
async function handlePrimitiveType2(value, field, context) {
|
|
1825
1933
|
const errors = [];
|
|
1934
|
+
const warnings = [];
|
|
1826
1935
|
if (field.validate) {
|
|
1827
1936
|
if (typeof value === "string") {
|
|
1828
1937
|
if (field.validate.pattern && !new RegExp(
|
|
@@ -1876,10 +1985,12 @@ async function handlePrimitiveType2(value, field, context) {
|
|
|
1876
1985
|
if (nested) {
|
|
1877
1986
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1878
1987
|
errors.push(...result.errors);
|
|
1988
|
+
warnings.push(...result.warnings);
|
|
1879
1989
|
}
|
|
1880
1990
|
return {
|
|
1881
1991
|
valid: errors.length === 0,
|
|
1882
|
-
errors
|
|
1992
|
+
errors,
|
|
1993
|
+
warnings
|
|
1883
1994
|
};
|
|
1884
1995
|
}
|
|
1885
1996
|
|
package/dist/index.d.cts
CHANGED
|
@@ -197,8 +197,19 @@ type FormanValidationResult = {
|
|
|
197
197
|
/** Error message */
|
|
198
198
|
message: string;
|
|
199
199
|
}[];
|
|
200
|
+
/** Warnings (do not affect validity) */
|
|
201
|
+
warnings: {
|
|
202
|
+
/** Field domain */
|
|
203
|
+
domain: string;
|
|
204
|
+
/** Field path */
|
|
205
|
+
path: string;
|
|
206
|
+
/** Warning message */
|
|
207
|
+
message: string;
|
|
208
|
+
}[];
|
|
200
209
|
/** States of fields grouped by domain */
|
|
201
210
|
states?: Record<string, FormanSchemaFieldState>;
|
|
211
|
+
/** Resolved schema fields per domain */
|
|
212
|
+
schemas?: Record<string, FormanSchemaField[]>;
|
|
202
213
|
};
|
|
203
214
|
type FormanSchemaFieldState = {
|
|
204
215
|
mode?: 'chose' | 'edit';
|
|
@@ -214,6 +225,8 @@ type FormanValidationOptions = {
|
|
|
214
225
|
strict?: boolean;
|
|
215
226
|
/** Whether to generate states for fields */
|
|
216
227
|
states?: boolean;
|
|
228
|
+
/** Whether to collect resolved schema fields per domain */
|
|
229
|
+
schemas?: boolean;
|
|
217
230
|
/** Remote resource resolver */
|
|
218
231
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
219
232
|
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
package/dist/index.d.ts
CHANGED
|
@@ -197,8 +197,19 @@ type FormanValidationResult = {
|
|
|
197
197
|
/** Error message */
|
|
198
198
|
message: string;
|
|
199
199
|
}[];
|
|
200
|
+
/** Warnings (do not affect validity) */
|
|
201
|
+
warnings: {
|
|
202
|
+
/** Field domain */
|
|
203
|
+
domain: string;
|
|
204
|
+
/** Field path */
|
|
205
|
+
path: string;
|
|
206
|
+
/** Warning message */
|
|
207
|
+
message: string;
|
|
208
|
+
}[];
|
|
200
209
|
/** States of fields grouped by domain */
|
|
201
210
|
states?: Record<string, FormanSchemaFieldState>;
|
|
211
|
+
/** Resolved schema fields per domain */
|
|
212
|
+
schemas?: Record<string, FormanSchemaField[]>;
|
|
202
213
|
};
|
|
203
214
|
type FormanSchemaFieldState = {
|
|
204
215
|
mode?: 'chose' | 'edit';
|
|
@@ -214,6 +225,8 @@ type FormanValidationOptions = {
|
|
|
214
225
|
strict?: boolean;
|
|
215
226
|
/** Whether to generate states for fields */
|
|
216
227
|
states?: boolean;
|
|
228
|
+
/** Whether to collect resolved schema fields per domain */
|
|
229
|
+
schemas?: boolean;
|
|
217
230
|
/** Remote resource resolver */
|
|
218
231
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
219
232
|
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
package/dist/index.js
CHANGED
|
@@ -1037,6 +1037,47 @@ function extractNestedFromField(field) {
|
|
|
1037
1037
|
if (isObject(field.options) && field.options.nested) return field.options.nested;
|
|
1038
1038
|
return void 0;
|
|
1039
1039
|
}
|
|
1040
|
+
var SCHEMA_STRIP_KEYS = [
|
|
1041
|
+
"nested",
|
|
1042
|
+
"options",
|
|
1043
|
+
"help",
|
|
1044
|
+
"rpc",
|
|
1045
|
+
"sort",
|
|
1046
|
+
"disabled",
|
|
1047
|
+
"multiline",
|
|
1048
|
+
"tags",
|
|
1049
|
+
"extension",
|
|
1050
|
+
"codepage",
|
|
1051
|
+
"logic"
|
|
1052
|
+
];
|
|
1053
|
+
function clampFieldForSchema(field) {
|
|
1054
|
+
const clamped = { ...field };
|
|
1055
|
+
for (const key of SCHEMA_STRIP_KEYS) {
|
|
1056
|
+
delete clamped[key];
|
|
1057
|
+
}
|
|
1058
|
+
if (field.spec != null) {
|
|
1059
|
+
clamped.spec = Array.isArray(field.spec) ? field.spec.map(clampFieldForSchema) : clampFieldForSchema(field.spec);
|
|
1060
|
+
}
|
|
1061
|
+
if (field.type === "select" && !field.validate?.enum) {
|
|
1062
|
+
const rawOptions = isObject(field.options) ? field.options.store : field.options;
|
|
1063
|
+
if (Array.isArray(rawOptions)) {
|
|
1064
|
+
const values = [];
|
|
1065
|
+
for (const item of rawOptions) {
|
|
1066
|
+
if ("options" in item) {
|
|
1067
|
+
for (const opt of item.options) {
|
|
1068
|
+
values.push(opt.value);
|
|
1069
|
+
}
|
|
1070
|
+
} else if ("value" in item) {
|
|
1071
|
+
values.push(item.value);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
if (values.length > 0) {
|
|
1075
|
+
clamped.validate = { ...clamped.validate, enum: values.map(String) };
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
return clamped;
|
|
1080
|
+
}
|
|
1040
1081
|
var FORMAN_TYPE_MAP2 = {
|
|
1041
1082
|
account: "number",
|
|
1042
1083
|
hook: "number",
|
|
@@ -1081,11 +1122,13 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
1081
1122
|
};
|
|
1082
1123
|
async function validateFormanWithDomainsInternal(domains, options) {
|
|
1083
1124
|
const errors = [];
|
|
1125
|
+
const warnings = [];
|
|
1084
1126
|
const roots = Object.keys(domains).reduce(
|
|
1085
1127
|
(acc, domain) => {
|
|
1086
1128
|
acc[domain] = {
|
|
1087
1129
|
seenFields: /* @__PURE__ */ new Set(),
|
|
1088
1130
|
fieldStates: [],
|
|
1131
|
+
schemaFields: [],
|
|
1089
1132
|
validateFields: (fields, context) => {
|
|
1090
1133
|
return validateFormanValue(
|
|
1091
1134
|
domains[domain].values,
|
|
@@ -1144,6 +1187,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1144
1187
|
}
|
|
1145
1188
|
);
|
|
1146
1189
|
errors.push(...result.errors);
|
|
1190
|
+
warnings.push(...result.warnings);
|
|
1147
1191
|
const restoreExtras = options?.states && domains[domain]?.restoreExtras;
|
|
1148
1192
|
if (restoreExtras) {
|
|
1149
1193
|
const fieldStateMap = new Map(
|
|
@@ -1179,16 +1223,19 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1179
1223
|
return {
|
|
1180
1224
|
valid: errors.length === 0,
|
|
1181
1225
|
errors,
|
|
1226
|
+
warnings,
|
|
1182
1227
|
states: errors.length === 0 && options?.states ? buildRestoreStructure(
|
|
1183
1228
|
Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
|
|
1184
|
-
) : void 0
|
|
1229
|
+
) : void 0,
|
|
1230
|
+
schemas: errors.length === 0 && options?.schemas ? Object.fromEntries(Object.keys(domains).map((domain) => [domain, roots[domain].schemaFields])) : void 0
|
|
1185
1231
|
};
|
|
1186
1232
|
}
|
|
1187
1233
|
async function validateFormanValue(value, field, context) {
|
|
1188
1234
|
if (isVisualType(field.type)) {
|
|
1189
1235
|
return {
|
|
1190
1236
|
valid: true,
|
|
1191
|
-
errors: []
|
|
1237
|
+
errors: [],
|
|
1238
|
+
warnings: []
|
|
1192
1239
|
};
|
|
1193
1240
|
}
|
|
1194
1241
|
const normalizedField = normalizeFormanFieldType(field);
|
|
@@ -1201,7 +1248,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1201
1248
|
path: context.path.join("."),
|
|
1202
1249
|
message: "Field is mandatory."
|
|
1203
1250
|
}
|
|
1204
|
-
]
|
|
1251
|
+
],
|
|
1252
|
+
warnings: []
|
|
1205
1253
|
};
|
|
1206
1254
|
}
|
|
1207
1255
|
if (value == null || value === "") {
|
|
@@ -1210,7 +1258,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1210
1258
|
}
|
|
1211
1259
|
return {
|
|
1212
1260
|
valid: true,
|
|
1213
|
-
errors: []
|
|
1261
|
+
errors: [],
|
|
1262
|
+
warnings: []
|
|
1214
1263
|
};
|
|
1215
1264
|
}
|
|
1216
1265
|
const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
|
|
@@ -1225,7 +1274,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1225
1274
|
path: context.path.join("."),
|
|
1226
1275
|
message: `Expected type '${expectedType}', got type '${actualType}'.`
|
|
1227
1276
|
}
|
|
1228
|
-
]
|
|
1277
|
+
],
|
|
1278
|
+
warnings: []
|
|
1229
1279
|
};
|
|
1230
1280
|
}
|
|
1231
1281
|
if (containsIMLExpression(value)) {
|
|
@@ -1238,7 +1288,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1238
1288
|
path: context.path.join("."),
|
|
1239
1289
|
message: "Value contains prohibited IML expression."
|
|
1240
1290
|
}
|
|
1241
|
-
]
|
|
1291
|
+
],
|
|
1292
|
+
warnings: []
|
|
1242
1293
|
};
|
|
1243
1294
|
}
|
|
1244
1295
|
if (isEditableType(normalizedField.type)) {
|
|
@@ -1253,7 +1304,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1253
1304
|
}
|
|
1254
1305
|
return {
|
|
1255
1306
|
valid: true,
|
|
1256
|
-
errors: []
|
|
1307
|
+
errors: [],
|
|
1308
|
+
warnings: []
|
|
1257
1309
|
};
|
|
1258
1310
|
}
|
|
1259
1311
|
if (normalizedField.type === "udttype") {
|
|
@@ -1288,6 +1340,7 @@ async function validateFormanValue(value, field, context) {
|
|
|
1288
1340
|
}
|
|
1289
1341
|
async function handleCollectionType2(value, field, context) {
|
|
1290
1342
|
const errors = [];
|
|
1343
|
+
const warnings = [];
|
|
1291
1344
|
const seen = context.path.length === 0 ? context.roots[context.domain].seenFields : /* @__PURE__ */ new Set();
|
|
1292
1345
|
const path = context.path;
|
|
1293
1346
|
if (Array.isArray(field.spec)) {
|
|
@@ -1314,7 +1367,8 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1314
1367
|
path: context.path.join("."),
|
|
1315
1368
|
message: `Failed to resolve remote resource ${subField}: ${error}`
|
|
1316
1369
|
}
|
|
1317
|
-
]
|
|
1370
|
+
],
|
|
1371
|
+
warnings
|
|
1318
1372
|
};
|
|
1319
1373
|
}
|
|
1320
1374
|
}
|
|
@@ -1330,6 +1384,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1330
1384
|
continue;
|
|
1331
1385
|
}
|
|
1332
1386
|
if (context.strict && !seen.has(subField.name)) seen.add(subField.name);
|
|
1387
|
+
if (path.length === 0) {
|
|
1388
|
+
context.roots[context.domain].schemaFields.push(clampFieldForSchema(subField));
|
|
1389
|
+
}
|
|
1333
1390
|
const result = await validateFormanValue(value[subField.name], subField, {
|
|
1334
1391
|
...context,
|
|
1335
1392
|
path: [...path, subField.name],
|
|
@@ -1347,15 +1404,20 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1347
1404
|
continue;
|
|
1348
1405
|
}
|
|
1349
1406
|
if (context2.strict && !seen.has(subField2.name)) seen.add(subField2.name);
|
|
1407
|
+
if (path.length === 0) {
|
|
1408
|
+
context2.roots[context2.domain].schemaFields.push(clampFieldForSchema(subField2));
|
|
1409
|
+
}
|
|
1350
1410
|
const result2 = await validateFormanValue(value[subField2.name], subField2, {
|
|
1351
1411
|
...context2,
|
|
1352
1412
|
path: [...path, subField2.name]
|
|
1353
1413
|
});
|
|
1354
1414
|
errors.push(...result2.errors);
|
|
1415
|
+
warnings.push(...result2.warnings);
|
|
1355
1416
|
}
|
|
1356
1417
|
}
|
|
1357
1418
|
});
|
|
1358
1419
|
errors.push(...result.errors);
|
|
1420
|
+
warnings.push(...result.warnings);
|
|
1359
1421
|
}
|
|
1360
1422
|
}
|
|
1361
1423
|
if (context.strict && context.path.length > 0) {
|
|
@@ -1372,11 +1434,13 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1372
1434
|
}
|
|
1373
1435
|
return {
|
|
1374
1436
|
valid: errors.length === 0,
|
|
1375
|
-
errors
|
|
1437
|
+
errors,
|
|
1438
|
+
warnings
|
|
1376
1439
|
};
|
|
1377
1440
|
}
|
|
1378
1441
|
async function handleArrayType2(value, field, context) {
|
|
1379
1442
|
const errors = [];
|
|
1443
|
+
const warnings = [];
|
|
1380
1444
|
if (field.spec) {
|
|
1381
1445
|
for (const [index, item] of value.entries()) {
|
|
1382
1446
|
const result = await validateFormanValue(
|
|
@@ -1385,6 +1449,7 @@ async function handleArrayType2(value, field, context) {
|
|
|
1385
1449
|
{ ...context, path: [...context.path, index] }
|
|
1386
1450
|
);
|
|
1387
1451
|
errors.push(...result.errors);
|
|
1452
|
+
warnings.push(...result.warnings);
|
|
1388
1453
|
}
|
|
1389
1454
|
}
|
|
1390
1455
|
if (field.validate) {
|
|
@@ -1405,7 +1470,8 @@ async function handleArrayType2(value, field, context) {
|
|
|
1405
1470
|
}
|
|
1406
1471
|
return {
|
|
1407
1472
|
valid: errors.length === 0,
|
|
1408
|
-
errors
|
|
1473
|
+
errors,
|
|
1474
|
+
warnings
|
|
1409
1475
|
};
|
|
1410
1476
|
}
|
|
1411
1477
|
async function handleFilterType2(value, field, context) {
|
|
@@ -1462,6 +1528,7 @@ async function handleFilterType2(value, field, context) {
|
|
|
1462
1528
|
}
|
|
1463
1529
|
async function handlePathType(value, field, context) {
|
|
1464
1530
|
const errors = [];
|
|
1531
|
+
const warnings = [];
|
|
1465
1532
|
if (typeof value !== "string") {
|
|
1466
1533
|
return {
|
|
1467
1534
|
valid: false,
|
|
@@ -1472,7 +1539,8 @@ async function handlePathType(value, field, context) {
|
|
|
1472
1539
|
path: context.path.join("."),
|
|
1473
1540
|
message: `Expected type 'string' for path, got type '${typeof value}'.`
|
|
1474
1541
|
}
|
|
1475
|
-
]
|
|
1542
|
+
],
|
|
1543
|
+
warnings
|
|
1476
1544
|
};
|
|
1477
1545
|
}
|
|
1478
1546
|
let showRoot = true;
|
|
@@ -1497,7 +1565,8 @@ async function handlePathType(value, field, context) {
|
|
|
1497
1565
|
path: context.path.join("."),
|
|
1498
1566
|
message: `Single level path cannot contain slashes.`
|
|
1499
1567
|
}
|
|
1500
|
-
]
|
|
1568
|
+
],
|
|
1569
|
+
warnings
|
|
1501
1570
|
};
|
|
1502
1571
|
}
|
|
1503
1572
|
let nested = field.nested ? field.nested : isObject(field.options) ? field.options.nested : void 0;
|
|
@@ -1506,7 +1575,8 @@ async function handlePathType(value, field, context) {
|
|
|
1506
1575
|
if (showRoot && value === "/" && field.type === "folder") {
|
|
1507
1576
|
return {
|
|
1508
1577
|
valid: true,
|
|
1509
|
-
errors: []
|
|
1578
|
+
errors: [],
|
|
1579
|
+
warnings
|
|
1510
1580
|
};
|
|
1511
1581
|
}
|
|
1512
1582
|
if (levels.length < 2) {
|
|
@@ -1519,11 +1589,13 @@ async function handlePathType(value, field, context) {
|
|
|
1519
1589
|
path: context.path.join("."),
|
|
1520
1590
|
message: `Invalid path "${value}" encountered.`
|
|
1521
1591
|
}
|
|
1522
|
-
]
|
|
1592
|
+
],
|
|
1593
|
+
warnings
|
|
1523
1594
|
};
|
|
1524
1595
|
}
|
|
1525
1596
|
const selectedPath = [];
|
|
1526
1597
|
let levelOptions = [];
|
|
1598
|
+
let optionsFromRPC = false;
|
|
1527
1599
|
for (let levelIndex = 0; levelIndex < levels.length - 1; ++levelIndex) {
|
|
1528
1600
|
const isLastLevel = levelIndex === levels.length - 2;
|
|
1529
1601
|
const levelSelectedValue = levels[levelIndex + 1];
|
|
@@ -1538,7 +1610,8 @@ async function handlePathType(value, field, context) {
|
|
|
1538
1610
|
path: context.path.join("."),
|
|
1539
1611
|
message: `Invalid selected value of "${value}" encountered.`
|
|
1540
1612
|
}
|
|
1541
|
-
]
|
|
1613
|
+
],
|
|
1614
|
+
warnings
|
|
1542
1615
|
};
|
|
1543
1616
|
}
|
|
1544
1617
|
if (typeof options === "string") {
|
|
@@ -1546,6 +1619,7 @@ async function handlePathType(value, field, context) {
|
|
|
1546
1619
|
levelOptions = await context.resolveRemote(options, context, {
|
|
1547
1620
|
[field.name]: (showRoot && !selectedPathValue.startsWith("/") ? "/" : "") + selectedPathValue
|
|
1548
1621
|
});
|
|
1622
|
+
optionsFromRPC = true;
|
|
1549
1623
|
} catch (error) {
|
|
1550
1624
|
return {
|
|
1551
1625
|
valid: false,
|
|
@@ -1556,7 +1630,8 @@ async function handlePathType(value, field, context) {
|
|
|
1556
1630
|
path: context.path.join("."),
|
|
1557
1631
|
message: `Failed to resolve remote resource ${options}: ${error}`
|
|
1558
1632
|
}
|
|
1559
|
-
]
|
|
1633
|
+
],
|
|
1634
|
+
warnings
|
|
1560
1635
|
};
|
|
1561
1636
|
}
|
|
1562
1637
|
} else if (isLastLevel) {
|
|
@@ -1573,6 +1648,14 @@ async function handlePathType(value, field, context) {
|
|
|
1573
1648
|
});
|
|
1574
1649
|
const selectedOption = selectableOptions.find((candidate) => candidate.value === levelSelectedValue);
|
|
1575
1650
|
if (!selectedOption) {
|
|
1651
|
+
if (optionsFromRPC) {
|
|
1652
|
+
warnings.push({
|
|
1653
|
+
domain: context.domain,
|
|
1654
|
+
path: context.path.join("."),
|
|
1655
|
+
message: `Path '${levelSelectedValue}' not found in options.`
|
|
1656
|
+
});
|
|
1657
|
+
break;
|
|
1658
|
+
}
|
|
1576
1659
|
return {
|
|
1577
1660
|
valid: false,
|
|
1578
1661
|
errors: [
|
|
@@ -1582,7 +1665,8 @@ async function handlePathType(value, field, context) {
|
|
|
1582
1665
|
path: context.path.join("."),
|
|
1583
1666
|
message: `Path '${levelSelectedValue}' not found in options.`
|
|
1584
1667
|
}
|
|
1585
|
-
]
|
|
1668
|
+
],
|
|
1669
|
+
warnings
|
|
1586
1670
|
};
|
|
1587
1671
|
}
|
|
1588
1672
|
selectedPath.push(selectedOption);
|
|
@@ -1599,16 +1683,20 @@ async function handlePathType(value, field, context) {
|
|
|
1599
1683
|
if (nested) {
|
|
1600
1684
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1601
1685
|
errors.push(...result.errors);
|
|
1686
|
+
warnings.push(...result.warnings);
|
|
1602
1687
|
}
|
|
1603
1688
|
return {
|
|
1604
1689
|
valid: errors.length === 0,
|
|
1605
|
-
errors
|
|
1690
|
+
errors,
|
|
1691
|
+
warnings
|
|
1606
1692
|
};
|
|
1607
1693
|
}
|
|
1608
1694
|
async function handleSelectType(value, field, context) {
|
|
1609
1695
|
const errors = [];
|
|
1696
|
+
const warnings = [];
|
|
1610
1697
|
let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
1611
1698
|
let nested = extractNestedFromField(field);
|
|
1699
|
+
let optionsFromRPC = false;
|
|
1612
1700
|
if (typeof optionsOrGroups === "string") {
|
|
1613
1701
|
try {
|
|
1614
1702
|
const resolved = await context.resolveRemote(optionsOrGroups, context);
|
|
@@ -1622,10 +1710,12 @@ async function handleSelectType(value, field, context) {
|
|
|
1622
1710
|
path: context.path.join("."),
|
|
1623
1711
|
message: `Remote resource ${optionsOrGroups} returned no data.`
|
|
1624
1712
|
}
|
|
1625
|
-
]
|
|
1713
|
+
],
|
|
1714
|
+
warnings
|
|
1626
1715
|
};
|
|
1627
1716
|
}
|
|
1628
1717
|
optionsOrGroups = Array.isArray(resolved) ? resolved : [resolved];
|
|
1718
|
+
optionsFromRPC = true;
|
|
1629
1719
|
} catch (error) {
|
|
1630
1720
|
return {
|
|
1631
1721
|
valid: false,
|
|
@@ -1636,7 +1726,8 @@ async function handleSelectType(value, field, context) {
|
|
|
1636
1726
|
path: context.path.join("."),
|
|
1637
1727
|
message: `Failed to resolve remote resource ${optionsOrGroups}: ${error}`
|
|
1638
1728
|
}
|
|
1639
|
-
]
|
|
1729
|
+
],
|
|
1730
|
+
warnings
|
|
1640
1731
|
};
|
|
1641
1732
|
}
|
|
1642
1733
|
}
|
|
@@ -1651,7 +1742,8 @@ async function handleSelectType(value, field, context) {
|
|
|
1651
1742
|
path: context.path.join("."),
|
|
1652
1743
|
message: `Value is not an array.`
|
|
1653
1744
|
}
|
|
1654
|
-
]
|
|
1745
|
+
],
|
|
1746
|
+
warnings
|
|
1655
1747
|
};
|
|
1656
1748
|
}
|
|
1657
1749
|
for (const singleValue of value) {
|
|
@@ -1661,7 +1753,7 @@ async function handleSelectType(value, field, context) {
|
|
|
1661
1753
|
optionsOrGroups
|
|
1662
1754
|
);
|
|
1663
1755
|
if (!found) {
|
|
1664
|
-
errors.push({
|
|
1756
|
+
(optionsFromRPC ? warnings : errors).push({
|
|
1665
1757
|
domain: context.domain,
|
|
1666
1758
|
path: context.path.join("."),
|
|
1667
1759
|
message: `Value '${singleValue}' not found in options.`
|
|
@@ -1699,40 +1791,53 @@ async function handleSelectType(value, field, context) {
|
|
|
1699
1791
|
} else {
|
|
1700
1792
|
const item = findValueInSelectOptions(field, value, optionsOrGroups);
|
|
1701
1793
|
if (!item) {
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
{
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1794
|
+
if (optionsFromRPC) {
|
|
1795
|
+
warnings.push({
|
|
1796
|
+
domain: context.domain,
|
|
1797
|
+
path: context.path.join("."),
|
|
1798
|
+
message: `Value '${value}' not found in options.`
|
|
1799
|
+
});
|
|
1800
|
+
} else {
|
|
1801
|
+
return {
|
|
1802
|
+
valid: false,
|
|
1803
|
+
errors: [
|
|
1804
|
+
...errors,
|
|
1805
|
+
{
|
|
1806
|
+
domain: context.domain,
|
|
1807
|
+
path: context.path.join("."),
|
|
1808
|
+
message: `Value '${value}' not found in options.`
|
|
1809
|
+
}
|
|
1810
|
+
],
|
|
1811
|
+
warnings
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
} else {
|
|
1815
|
+
if (item.label) {
|
|
1816
|
+
context.roots[context.domain].fieldStates.push({
|
|
1817
|
+
path: context.path,
|
|
1818
|
+
state: {
|
|
1819
|
+
mode: isReferenceType(field.type) ? void 0 : "chose",
|
|
1820
|
+
label: item.label
|
|
1710
1821
|
}
|
|
1711
|
-
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
if (item.label) {
|
|
1715
|
-
context.roots[context.domain].fieldStates.push({
|
|
1716
|
-
path: context.path,
|
|
1717
|
-
state: {
|
|
1718
|
-
mode: isReferenceType(field.type) ? void 0 : "chose",
|
|
1719
|
-
label: item.label
|
|
1720
|
-
}
|
|
1721
|
-
});
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
if (item.nested) nested = item.nested;
|
|
1722
1825
|
}
|
|
1723
|
-
if (item.nested) nested = item.nested;
|
|
1724
1826
|
}
|
|
1725
1827
|
if (nested) {
|
|
1726
1828
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1727
1829
|
errors.push(...result.errors);
|
|
1830
|
+
warnings.push(...result.warnings);
|
|
1728
1831
|
}
|
|
1729
1832
|
return {
|
|
1730
1833
|
valid: errors.length === 0,
|
|
1731
|
-
errors
|
|
1834
|
+
errors,
|
|
1835
|
+
warnings
|
|
1732
1836
|
};
|
|
1733
1837
|
}
|
|
1734
1838
|
async function handleNestedFields(nested, value, field, context) {
|
|
1735
1839
|
const errors = [];
|
|
1840
|
+
const warnings = [];
|
|
1736
1841
|
let store = isObject(nested) ? nested.store : nested;
|
|
1737
1842
|
const domain = isObject(nested) && nested.domain ? nested.domain : void 0;
|
|
1738
1843
|
context = {
|
|
@@ -1763,7 +1868,8 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1763
1868
|
path: context.path.join("."),
|
|
1764
1869
|
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
1765
1870
|
}
|
|
1766
|
-
]
|
|
1871
|
+
],
|
|
1872
|
+
warnings
|
|
1767
1873
|
};
|
|
1768
1874
|
}
|
|
1769
1875
|
} else {
|
|
@@ -1783,17 +1889,20 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1783
1889
|
} else {
|
|
1784
1890
|
const result = await context.roots[resolvedDomain].validateFields(store, context);
|
|
1785
1891
|
errors.push(...result.errors);
|
|
1892
|
+
warnings.push(...result.warnings);
|
|
1786
1893
|
}
|
|
1787
1894
|
} else if (store) {
|
|
1788
1895
|
await context.validateNestedFields(store, context);
|
|
1789
1896
|
}
|
|
1790
1897
|
return {
|
|
1791
1898
|
valid: errors.length === 0,
|
|
1792
|
-
errors
|
|
1899
|
+
errors,
|
|
1900
|
+
warnings
|
|
1793
1901
|
};
|
|
1794
1902
|
}
|
|
1795
1903
|
async function handlePrimitiveType2(value, field, context) {
|
|
1796
1904
|
const errors = [];
|
|
1905
|
+
const warnings = [];
|
|
1797
1906
|
if (field.validate) {
|
|
1798
1907
|
if (typeof value === "string") {
|
|
1799
1908
|
if (field.validate.pattern && !new RegExp(
|
|
@@ -1847,10 +1956,12 @@ async function handlePrimitiveType2(value, field, context) {
|
|
|
1847
1956
|
if (nested) {
|
|
1848
1957
|
const result = await handleNestedFields(nested, value, field, context);
|
|
1849
1958
|
errors.push(...result.errors);
|
|
1959
|
+
warnings.push(...result.warnings);
|
|
1850
1960
|
}
|
|
1851
1961
|
return {
|
|
1852
1962
|
valid: errors.length === 0,
|
|
1853
|
-
errors
|
|
1963
|
+
errors,
|
|
1964
|
+
warnings
|
|
1854
1965
|
};
|
|
1855
1966
|
}
|
|
1856
1967
|
|