@makehq/forman-schema 1.10.0 → 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 CHANGED
@@ -1151,6 +1151,7 @@ var FORMAN_TYPE_MAP2 = {
1151
1151
  };
1152
1152
  async function validateFormanWithDomainsInternal(domains, options) {
1153
1153
  const errors = [];
1154
+ const warnings = [];
1154
1155
  const roots = Object.keys(domains).reduce(
1155
1156
  (acc, domain) => {
1156
1157
  acc[domain] = {
@@ -1215,6 +1216,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1215
1216
  }
1216
1217
  );
1217
1218
  errors.push(...result.errors);
1219
+ warnings.push(...result.warnings);
1218
1220
  const restoreExtras = options?.states && domains[domain]?.restoreExtras;
1219
1221
  if (restoreExtras) {
1220
1222
  const fieldStateMap = new Map(
@@ -1250,6 +1252,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1250
1252
  return {
1251
1253
  valid: errors.length === 0,
1252
1254
  errors,
1255
+ warnings,
1253
1256
  states: errors.length === 0 && options?.states ? buildRestoreStructure(
1254
1257
  Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
1255
1258
  ) : void 0,
@@ -1260,7 +1263,8 @@ async function validateFormanValue(value, field, context) {
1260
1263
  if (isVisualType(field.type)) {
1261
1264
  return {
1262
1265
  valid: true,
1263
- errors: []
1266
+ errors: [],
1267
+ warnings: []
1264
1268
  };
1265
1269
  }
1266
1270
  const normalizedField = normalizeFormanFieldType(field);
@@ -1273,7 +1277,8 @@ async function validateFormanValue(value, field, context) {
1273
1277
  path: context.path.join("."),
1274
1278
  message: "Field is mandatory."
1275
1279
  }
1276
- ]
1280
+ ],
1281
+ warnings: []
1277
1282
  };
1278
1283
  }
1279
1284
  if (value == null || value === "") {
@@ -1282,7 +1287,8 @@ async function validateFormanValue(value, field, context) {
1282
1287
  }
1283
1288
  return {
1284
1289
  valid: true,
1285
- errors: []
1290
+ errors: [],
1291
+ warnings: []
1286
1292
  };
1287
1293
  }
1288
1294
  const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
@@ -1297,7 +1303,8 @@ async function validateFormanValue(value, field, context) {
1297
1303
  path: context.path.join("."),
1298
1304
  message: `Expected type '${expectedType}', got type '${actualType}'.`
1299
1305
  }
1300
- ]
1306
+ ],
1307
+ warnings: []
1301
1308
  };
1302
1309
  }
1303
1310
  if (containsIMLExpression(value)) {
@@ -1310,7 +1317,8 @@ async function validateFormanValue(value, field, context) {
1310
1317
  path: context.path.join("."),
1311
1318
  message: "Value contains prohibited IML expression."
1312
1319
  }
1313
- ]
1320
+ ],
1321
+ warnings: []
1314
1322
  };
1315
1323
  }
1316
1324
  if (isEditableType(normalizedField.type)) {
@@ -1325,7 +1333,8 @@ async function validateFormanValue(value, field, context) {
1325
1333
  }
1326
1334
  return {
1327
1335
  valid: true,
1328
- errors: []
1336
+ errors: [],
1337
+ warnings: []
1329
1338
  };
1330
1339
  }
1331
1340
  if (normalizedField.type === "udttype") {
@@ -1360,6 +1369,7 @@ async function validateFormanValue(value, field, context) {
1360
1369
  }
1361
1370
  async function handleCollectionType2(value, field, context) {
1362
1371
  const errors = [];
1372
+ const warnings = [];
1363
1373
  const seen = context.path.length === 0 ? context.roots[context.domain].seenFields : /* @__PURE__ */ new Set();
1364
1374
  const path = context.path;
1365
1375
  if (Array.isArray(field.spec)) {
@@ -1386,7 +1396,8 @@ async function handleCollectionType2(value, field, context) {
1386
1396
  path: context.path.join("."),
1387
1397
  message: `Failed to resolve remote resource ${subField}: ${error}`
1388
1398
  }
1389
- ]
1399
+ ],
1400
+ warnings
1390
1401
  };
1391
1402
  }
1392
1403
  }
@@ -1430,10 +1441,12 @@ async function handleCollectionType2(value, field, context) {
1430
1441
  path: [...path, subField2.name]
1431
1442
  });
1432
1443
  errors.push(...result2.errors);
1444
+ warnings.push(...result2.warnings);
1433
1445
  }
1434
1446
  }
1435
1447
  });
1436
1448
  errors.push(...result.errors);
1449
+ warnings.push(...result.warnings);
1437
1450
  }
1438
1451
  }
1439
1452
  if (context.strict && context.path.length > 0) {
@@ -1450,11 +1463,13 @@ async function handleCollectionType2(value, field, context) {
1450
1463
  }
1451
1464
  return {
1452
1465
  valid: errors.length === 0,
1453
- errors
1466
+ errors,
1467
+ warnings
1454
1468
  };
1455
1469
  }
1456
1470
  async function handleArrayType2(value, field, context) {
1457
1471
  const errors = [];
1472
+ const warnings = [];
1458
1473
  if (field.spec) {
1459
1474
  for (const [index, item] of value.entries()) {
1460
1475
  const result = await validateFormanValue(
@@ -1463,6 +1478,7 @@ async function handleArrayType2(value, field, context) {
1463
1478
  { ...context, path: [...context.path, index] }
1464
1479
  );
1465
1480
  errors.push(...result.errors);
1481
+ warnings.push(...result.warnings);
1466
1482
  }
1467
1483
  }
1468
1484
  if (field.validate) {
@@ -1483,7 +1499,8 @@ async function handleArrayType2(value, field, context) {
1483
1499
  }
1484
1500
  return {
1485
1501
  valid: errors.length === 0,
1486
- errors
1502
+ errors,
1503
+ warnings
1487
1504
  };
1488
1505
  }
1489
1506
  async function handleFilterType2(value, field, context) {
@@ -1540,6 +1557,7 @@ async function handleFilterType2(value, field, context) {
1540
1557
  }
1541
1558
  async function handlePathType(value, field, context) {
1542
1559
  const errors = [];
1560
+ const warnings = [];
1543
1561
  if (typeof value !== "string") {
1544
1562
  return {
1545
1563
  valid: false,
@@ -1550,7 +1568,8 @@ async function handlePathType(value, field, context) {
1550
1568
  path: context.path.join("."),
1551
1569
  message: `Expected type 'string' for path, got type '${typeof value}'.`
1552
1570
  }
1553
- ]
1571
+ ],
1572
+ warnings
1554
1573
  };
1555
1574
  }
1556
1575
  let showRoot = true;
@@ -1575,7 +1594,8 @@ async function handlePathType(value, field, context) {
1575
1594
  path: context.path.join("."),
1576
1595
  message: `Single level path cannot contain slashes.`
1577
1596
  }
1578
- ]
1597
+ ],
1598
+ warnings
1579
1599
  };
1580
1600
  }
1581
1601
  let nested = field.nested ? field.nested : isObject(field.options) ? field.options.nested : void 0;
@@ -1584,7 +1604,8 @@ async function handlePathType(value, field, context) {
1584
1604
  if (showRoot && value === "/" && field.type === "folder") {
1585
1605
  return {
1586
1606
  valid: true,
1587
- errors: []
1607
+ errors: [],
1608
+ warnings
1588
1609
  };
1589
1610
  }
1590
1611
  if (levels.length < 2) {
@@ -1597,11 +1618,13 @@ async function handlePathType(value, field, context) {
1597
1618
  path: context.path.join("."),
1598
1619
  message: `Invalid path "${value}" encountered.`
1599
1620
  }
1600
- ]
1621
+ ],
1622
+ warnings
1601
1623
  };
1602
1624
  }
1603
1625
  const selectedPath = [];
1604
1626
  let levelOptions = [];
1627
+ let optionsFromRPC = false;
1605
1628
  for (let levelIndex = 0; levelIndex < levels.length - 1; ++levelIndex) {
1606
1629
  const isLastLevel = levelIndex === levels.length - 2;
1607
1630
  const levelSelectedValue = levels[levelIndex + 1];
@@ -1616,7 +1639,8 @@ async function handlePathType(value, field, context) {
1616
1639
  path: context.path.join("."),
1617
1640
  message: `Invalid selected value of "${value}" encountered.`
1618
1641
  }
1619
- ]
1642
+ ],
1643
+ warnings
1620
1644
  };
1621
1645
  }
1622
1646
  if (typeof options === "string") {
@@ -1624,6 +1648,7 @@ async function handlePathType(value, field, context) {
1624
1648
  levelOptions = await context.resolveRemote(options, context, {
1625
1649
  [field.name]: (showRoot && !selectedPathValue.startsWith("/") ? "/" : "") + selectedPathValue
1626
1650
  });
1651
+ optionsFromRPC = true;
1627
1652
  } catch (error) {
1628
1653
  return {
1629
1654
  valid: false,
@@ -1634,7 +1659,8 @@ async function handlePathType(value, field, context) {
1634
1659
  path: context.path.join("."),
1635
1660
  message: `Failed to resolve remote resource ${options}: ${error}`
1636
1661
  }
1637
- ]
1662
+ ],
1663
+ warnings
1638
1664
  };
1639
1665
  }
1640
1666
  } else if (isLastLevel) {
@@ -1651,6 +1677,14 @@ async function handlePathType(value, field, context) {
1651
1677
  });
1652
1678
  const selectedOption = selectableOptions.find((candidate) => candidate.value === levelSelectedValue);
1653
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
+ }
1654
1688
  return {
1655
1689
  valid: false,
1656
1690
  errors: [
@@ -1660,7 +1694,8 @@ async function handlePathType(value, field, context) {
1660
1694
  path: context.path.join("."),
1661
1695
  message: `Path '${levelSelectedValue}' not found in options.`
1662
1696
  }
1663
- ]
1697
+ ],
1698
+ warnings
1664
1699
  };
1665
1700
  }
1666
1701
  selectedPath.push(selectedOption);
@@ -1677,16 +1712,20 @@ async function handlePathType(value, field, context) {
1677
1712
  if (nested) {
1678
1713
  const result = await handleNestedFields(nested, value, field, context);
1679
1714
  errors.push(...result.errors);
1715
+ warnings.push(...result.warnings);
1680
1716
  }
1681
1717
  return {
1682
1718
  valid: errors.length === 0,
1683
- errors
1719
+ errors,
1720
+ warnings
1684
1721
  };
1685
1722
  }
1686
1723
  async function handleSelectType(value, field, context) {
1687
1724
  const errors = [];
1725
+ const warnings = [];
1688
1726
  let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
1689
1727
  let nested = extractNestedFromField(field);
1728
+ let optionsFromRPC = false;
1690
1729
  if (typeof optionsOrGroups === "string") {
1691
1730
  try {
1692
1731
  const resolved = await context.resolveRemote(optionsOrGroups, context);
@@ -1700,10 +1739,12 @@ async function handleSelectType(value, field, context) {
1700
1739
  path: context.path.join("."),
1701
1740
  message: `Remote resource ${optionsOrGroups} returned no data.`
1702
1741
  }
1703
- ]
1742
+ ],
1743
+ warnings
1704
1744
  };
1705
1745
  }
1706
1746
  optionsOrGroups = Array.isArray(resolved) ? resolved : [resolved];
1747
+ optionsFromRPC = true;
1707
1748
  } catch (error) {
1708
1749
  return {
1709
1750
  valid: false,
@@ -1714,7 +1755,8 @@ async function handleSelectType(value, field, context) {
1714
1755
  path: context.path.join("."),
1715
1756
  message: `Failed to resolve remote resource ${optionsOrGroups}: ${error}`
1716
1757
  }
1717
- ]
1758
+ ],
1759
+ warnings
1718
1760
  };
1719
1761
  }
1720
1762
  }
@@ -1729,7 +1771,8 @@ async function handleSelectType(value, field, context) {
1729
1771
  path: context.path.join("."),
1730
1772
  message: `Value is not an array.`
1731
1773
  }
1732
- ]
1774
+ ],
1775
+ warnings
1733
1776
  };
1734
1777
  }
1735
1778
  for (const singleValue of value) {
@@ -1739,7 +1782,7 @@ async function handleSelectType(value, field, context) {
1739
1782
  optionsOrGroups
1740
1783
  );
1741
1784
  if (!found) {
1742
- errors.push({
1785
+ (optionsFromRPC ? warnings : errors).push({
1743
1786
  domain: context.domain,
1744
1787
  path: context.path.join("."),
1745
1788
  message: `Value '${singleValue}' not found in options.`
@@ -1777,40 +1820,53 @@ async function handleSelectType(value, field, context) {
1777
1820
  } else {
1778
1821
  const item = findValueInSelectOptions(field, value, optionsOrGroups);
1779
1822
  if (!item) {
1780
- return {
1781
- valid: false,
1782
- errors: [
1783
- ...errors,
1784
- {
1785
- domain: context.domain,
1786
- path: context.path.join("."),
1787
- message: `Value '${value}' not found in options.`
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
1788
1850
  }
1789
- ]
1790
- };
1791
- }
1792
- if (item.label) {
1793
- context.roots[context.domain].fieldStates.push({
1794
- path: context.path,
1795
- state: {
1796
- mode: isReferenceType(field.type) ? void 0 : "chose",
1797
- label: item.label
1798
- }
1799
- });
1851
+ });
1852
+ }
1853
+ if (item.nested) nested = item.nested;
1800
1854
  }
1801
- if (item.nested) nested = item.nested;
1802
1855
  }
1803
1856
  if (nested) {
1804
1857
  const result = await handleNestedFields(nested, value, field, context);
1805
1858
  errors.push(...result.errors);
1859
+ warnings.push(...result.warnings);
1806
1860
  }
1807
1861
  return {
1808
1862
  valid: errors.length === 0,
1809
- errors
1863
+ errors,
1864
+ warnings
1810
1865
  };
1811
1866
  }
1812
1867
  async function handleNestedFields(nested, value, field, context) {
1813
1868
  const errors = [];
1869
+ const warnings = [];
1814
1870
  let store = isObject(nested) ? nested.store : nested;
1815
1871
  const domain = isObject(nested) && nested.domain ? nested.domain : void 0;
1816
1872
  context = {
@@ -1841,7 +1897,8 @@ async function handleNestedFields(nested, value, field, context) {
1841
1897
  path: context.path.join("."),
1842
1898
  message: `Failed to resolve remote resource ${item}: ${error}`
1843
1899
  }
1844
- ]
1900
+ ],
1901
+ warnings
1845
1902
  };
1846
1903
  }
1847
1904
  } else {
@@ -1861,17 +1918,20 @@ async function handleNestedFields(nested, value, field, context) {
1861
1918
  } else {
1862
1919
  const result = await context.roots[resolvedDomain].validateFields(store, context);
1863
1920
  errors.push(...result.errors);
1921
+ warnings.push(...result.warnings);
1864
1922
  }
1865
1923
  } else if (store) {
1866
1924
  await context.validateNestedFields(store, context);
1867
1925
  }
1868
1926
  return {
1869
1927
  valid: errors.length === 0,
1870
- errors
1928
+ errors,
1929
+ warnings
1871
1930
  };
1872
1931
  }
1873
1932
  async function handlePrimitiveType2(value, field, context) {
1874
1933
  const errors = [];
1934
+ const warnings = [];
1875
1935
  if (field.validate) {
1876
1936
  if (typeof value === "string") {
1877
1937
  if (field.validate.pattern && !new RegExp(
@@ -1925,10 +1985,12 @@ async function handlePrimitiveType2(value, field, context) {
1925
1985
  if (nested) {
1926
1986
  const result = await handleNestedFields(nested, value, field, context);
1927
1987
  errors.push(...result.errors);
1988
+ warnings.push(...result.warnings);
1928
1989
  }
1929
1990
  return {
1930
1991
  valid: errors.length === 0,
1931
- errors
1992
+ errors,
1993
+ warnings
1932
1994
  };
1933
1995
  }
1934
1996
 
package/dist/index.d.cts CHANGED
@@ -197,6 +197,15 @@ 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>;
202
211
  /** Resolved schema fields per domain */
package/dist/index.d.ts CHANGED
@@ -197,6 +197,15 @@ 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>;
202
211
  /** Resolved schema fields per domain */
package/dist/index.js CHANGED
@@ -1122,6 +1122,7 @@ var FORMAN_TYPE_MAP2 = {
1122
1122
  };
1123
1123
  async function validateFormanWithDomainsInternal(domains, options) {
1124
1124
  const errors = [];
1125
+ const warnings = [];
1125
1126
  const roots = Object.keys(domains).reduce(
1126
1127
  (acc, domain) => {
1127
1128
  acc[domain] = {
@@ -1186,6 +1187,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1186
1187
  }
1187
1188
  );
1188
1189
  errors.push(...result.errors);
1190
+ warnings.push(...result.warnings);
1189
1191
  const restoreExtras = options?.states && domains[domain]?.restoreExtras;
1190
1192
  if (restoreExtras) {
1191
1193
  const fieldStateMap = new Map(
@@ -1221,6 +1223,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1221
1223
  return {
1222
1224
  valid: errors.length === 0,
1223
1225
  errors,
1226
+ warnings,
1224
1227
  states: errors.length === 0 && options?.states ? buildRestoreStructure(
1225
1228
  Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
1226
1229
  ) : void 0,
@@ -1231,7 +1234,8 @@ async function validateFormanValue(value, field, context) {
1231
1234
  if (isVisualType(field.type)) {
1232
1235
  return {
1233
1236
  valid: true,
1234
- errors: []
1237
+ errors: [],
1238
+ warnings: []
1235
1239
  };
1236
1240
  }
1237
1241
  const normalizedField = normalizeFormanFieldType(field);
@@ -1244,7 +1248,8 @@ async function validateFormanValue(value, field, context) {
1244
1248
  path: context.path.join("."),
1245
1249
  message: "Field is mandatory."
1246
1250
  }
1247
- ]
1251
+ ],
1252
+ warnings: []
1248
1253
  };
1249
1254
  }
1250
1255
  if (value == null || value === "") {
@@ -1253,7 +1258,8 @@ async function validateFormanValue(value, field, context) {
1253
1258
  }
1254
1259
  return {
1255
1260
  valid: true,
1256
- errors: []
1261
+ errors: [],
1262
+ warnings: []
1257
1263
  };
1258
1264
  }
1259
1265
  const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
@@ -1268,7 +1274,8 @@ async function validateFormanValue(value, field, context) {
1268
1274
  path: context.path.join("."),
1269
1275
  message: `Expected type '${expectedType}', got type '${actualType}'.`
1270
1276
  }
1271
- ]
1277
+ ],
1278
+ warnings: []
1272
1279
  };
1273
1280
  }
1274
1281
  if (containsIMLExpression(value)) {
@@ -1281,7 +1288,8 @@ async function validateFormanValue(value, field, context) {
1281
1288
  path: context.path.join("."),
1282
1289
  message: "Value contains prohibited IML expression."
1283
1290
  }
1284
- ]
1291
+ ],
1292
+ warnings: []
1285
1293
  };
1286
1294
  }
1287
1295
  if (isEditableType(normalizedField.type)) {
@@ -1296,7 +1304,8 @@ async function validateFormanValue(value, field, context) {
1296
1304
  }
1297
1305
  return {
1298
1306
  valid: true,
1299
- errors: []
1307
+ errors: [],
1308
+ warnings: []
1300
1309
  };
1301
1310
  }
1302
1311
  if (normalizedField.type === "udttype") {
@@ -1331,6 +1340,7 @@ async function validateFormanValue(value, field, context) {
1331
1340
  }
1332
1341
  async function handleCollectionType2(value, field, context) {
1333
1342
  const errors = [];
1343
+ const warnings = [];
1334
1344
  const seen = context.path.length === 0 ? context.roots[context.domain].seenFields : /* @__PURE__ */ new Set();
1335
1345
  const path = context.path;
1336
1346
  if (Array.isArray(field.spec)) {
@@ -1357,7 +1367,8 @@ async function handleCollectionType2(value, field, context) {
1357
1367
  path: context.path.join("."),
1358
1368
  message: `Failed to resolve remote resource ${subField}: ${error}`
1359
1369
  }
1360
- ]
1370
+ ],
1371
+ warnings
1361
1372
  };
1362
1373
  }
1363
1374
  }
@@ -1401,10 +1412,12 @@ async function handleCollectionType2(value, field, context) {
1401
1412
  path: [...path, subField2.name]
1402
1413
  });
1403
1414
  errors.push(...result2.errors);
1415
+ warnings.push(...result2.warnings);
1404
1416
  }
1405
1417
  }
1406
1418
  });
1407
1419
  errors.push(...result.errors);
1420
+ warnings.push(...result.warnings);
1408
1421
  }
1409
1422
  }
1410
1423
  if (context.strict && context.path.length > 0) {
@@ -1421,11 +1434,13 @@ async function handleCollectionType2(value, field, context) {
1421
1434
  }
1422
1435
  return {
1423
1436
  valid: errors.length === 0,
1424
- errors
1437
+ errors,
1438
+ warnings
1425
1439
  };
1426
1440
  }
1427
1441
  async function handleArrayType2(value, field, context) {
1428
1442
  const errors = [];
1443
+ const warnings = [];
1429
1444
  if (field.spec) {
1430
1445
  for (const [index, item] of value.entries()) {
1431
1446
  const result = await validateFormanValue(
@@ -1434,6 +1449,7 @@ async function handleArrayType2(value, field, context) {
1434
1449
  { ...context, path: [...context.path, index] }
1435
1450
  );
1436
1451
  errors.push(...result.errors);
1452
+ warnings.push(...result.warnings);
1437
1453
  }
1438
1454
  }
1439
1455
  if (field.validate) {
@@ -1454,7 +1470,8 @@ async function handleArrayType2(value, field, context) {
1454
1470
  }
1455
1471
  return {
1456
1472
  valid: errors.length === 0,
1457
- errors
1473
+ errors,
1474
+ warnings
1458
1475
  };
1459
1476
  }
1460
1477
  async function handleFilterType2(value, field, context) {
@@ -1511,6 +1528,7 @@ async function handleFilterType2(value, field, context) {
1511
1528
  }
1512
1529
  async function handlePathType(value, field, context) {
1513
1530
  const errors = [];
1531
+ const warnings = [];
1514
1532
  if (typeof value !== "string") {
1515
1533
  return {
1516
1534
  valid: false,
@@ -1521,7 +1539,8 @@ async function handlePathType(value, field, context) {
1521
1539
  path: context.path.join("."),
1522
1540
  message: `Expected type 'string' for path, got type '${typeof value}'.`
1523
1541
  }
1524
- ]
1542
+ ],
1543
+ warnings
1525
1544
  };
1526
1545
  }
1527
1546
  let showRoot = true;
@@ -1546,7 +1565,8 @@ async function handlePathType(value, field, context) {
1546
1565
  path: context.path.join("."),
1547
1566
  message: `Single level path cannot contain slashes.`
1548
1567
  }
1549
- ]
1568
+ ],
1569
+ warnings
1550
1570
  };
1551
1571
  }
1552
1572
  let nested = field.nested ? field.nested : isObject(field.options) ? field.options.nested : void 0;
@@ -1555,7 +1575,8 @@ async function handlePathType(value, field, context) {
1555
1575
  if (showRoot && value === "/" && field.type === "folder") {
1556
1576
  return {
1557
1577
  valid: true,
1558
- errors: []
1578
+ errors: [],
1579
+ warnings
1559
1580
  };
1560
1581
  }
1561
1582
  if (levels.length < 2) {
@@ -1568,11 +1589,13 @@ async function handlePathType(value, field, context) {
1568
1589
  path: context.path.join("."),
1569
1590
  message: `Invalid path "${value}" encountered.`
1570
1591
  }
1571
- ]
1592
+ ],
1593
+ warnings
1572
1594
  };
1573
1595
  }
1574
1596
  const selectedPath = [];
1575
1597
  let levelOptions = [];
1598
+ let optionsFromRPC = false;
1576
1599
  for (let levelIndex = 0; levelIndex < levels.length - 1; ++levelIndex) {
1577
1600
  const isLastLevel = levelIndex === levels.length - 2;
1578
1601
  const levelSelectedValue = levels[levelIndex + 1];
@@ -1587,7 +1610,8 @@ async function handlePathType(value, field, context) {
1587
1610
  path: context.path.join("."),
1588
1611
  message: `Invalid selected value of "${value}" encountered.`
1589
1612
  }
1590
- ]
1613
+ ],
1614
+ warnings
1591
1615
  };
1592
1616
  }
1593
1617
  if (typeof options === "string") {
@@ -1595,6 +1619,7 @@ async function handlePathType(value, field, context) {
1595
1619
  levelOptions = await context.resolveRemote(options, context, {
1596
1620
  [field.name]: (showRoot && !selectedPathValue.startsWith("/") ? "/" : "") + selectedPathValue
1597
1621
  });
1622
+ optionsFromRPC = true;
1598
1623
  } catch (error) {
1599
1624
  return {
1600
1625
  valid: false,
@@ -1605,7 +1630,8 @@ async function handlePathType(value, field, context) {
1605
1630
  path: context.path.join("."),
1606
1631
  message: `Failed to resolve remote resource ${options}: ${error}`
1607
1632
  }
1608
- ]
1633
+ ],
1634
+ warnings
1609
1635
  };
1610
1636
  }
1611
1637
  } else if (isLastLevel) {
@@ -1622,6 +1648,14 @@ async function handlePathType(value, field, context) {
1622
1648
  });
1623
1649
  const selectedOption = selectableOptions.find((candidate) => candidate.value === levelSelectedValue);
1624
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
+ }
1625
1659
  return {
1626
1660
  valid: false,
1627
1661
  errors: [
@@ -1631,7 +1665,8 @@ async function handlePathType(value, field, context) {
1631
1665
  path: context.path.join("."),
1632
1666
  message: `Path '${levelSelectedValue}' not found in options.`
1633
1667
  }
1634
- ]
1668
+ ],
1669
+ warnings
1635
1670
  };
1636
1671
  }
1637
1672
  selectedPath.push(selectedOption);
@@ -1648,16 +1683,20 @@ async function handlePathType(value, field, context) {
1648
1683
  if (nested) {
1649
1684
  const result = await handleNestedFields(nested, value, field, context);
1650
1685
  errors.push(...result.errors);
1686
+ warnings.push(...result.warnings);
1651
1687
  }
1652
1688
  return {
1653
1689
  valid: errors.length === 0,
1654
- errors
1690
+ errors,
1691
+ warnings
1655
1692
  };
1656
1693
  }
1657
1694
  async function handleSelectType(value, field, context) {
1658
1695
  const errors = [];
1696
+ const warnings = [];
1659
1697
  let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
1660
1698
  let nested = extractNestedFromField(field);
1699
+ let optionsFromRPC = false;
1661
1700
  if (typeof optionsOrGroups === "string") {
1662
1701
  try {
1663
1702
  const resolved = await context.resolveRemote(optionsOrGroups, context);
@@ -1671,10 +1710,12 @@ async function handleSelectType(value, field, context) {
1671
1710
  path: context.path.join("."),
1672
1711
  message: `Remote resource ${optionsOrGroups} returned no data.`
1673
1712
  }
1674
- ]
1713
+ ],
1714
+ warnings
1675
1715
  };
1676
1716
  }
1677
1717
  optionsOrGroups = Array.isArray(resolved) ? resolved : [resolved];
1718
+ optionsFromRPC = true;
1678
1719
  } catch (error) {
1679
1720
  return {
1680
1721
  valid: false,
@@ -1685,7 +1726,8 @@ async function handleSelectType(value, field, context) {
1685
1726
  path: context.path.join("."),
1686
1727
  message: `Failed to resolve remote resource ${optionsOrGroups}: ${error}`
1687
1728
  }
1688
- ]
1729
+ ],
1730
+ warnings
1689
1731
  };
1690
1732
  }
1691
1733
  }
@@ -1700,7 +1742,8 @@ async function handleSelectType(value, field, context) {
1700
1742
  path: context.path.join("."),
1701
1743
  message: `Value is not an array.`
1702
1744
  }
1703
- ]
1745
+ ],
1746
+ warnings
1704
1747
  };
1705
1748
  }
1706
1749
  for (const singleValue of value) {
@@ -1710,7 +1753,7 @@ async function handleSelectType(value, field, context) {
1710
1753
  optionsOrGroups
1711
1754
  );
1712
1755
  if (!found) {
1713
- errors.push({
1756
+ (optionsFromRPC ? warnings : errors).push({
1714
1757
  domain: context.domain,
1715
1758
  path: context.path.join("."),
1716
1759
  message: `Value '${singleValue}' not found in options.`
@@ -1748,40 +1791,53 @@ async function handleSelectType(value, field, context) {
1748
1791
  } else {
1749
1792
  const item = findValueInSelectOptions(field, value, optionsOrGroups);
1750
1793
  if (!item) {
1751
- return {
1752
- valid: false,
1753
- errors: [
1754
- ...errors,
1755
- {
1756
- domain: context.domain,
1757
- path: context.path.join("."),
1758
- message: `Value '${value}' not found in options.`
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
1759
1821
  }
1760
- ]
1761
- };
1762
- }
1763
- if (item.label) {
1764
- context.roots[context.domain].fieldStates.push({
1765
- path: context.path,
1766
- state: {
1767
- mode: isReferenceType(field.type) ? void 0 : "chose",
1768
- label: item.label
1769
- }
1770
- });
1822
+ });
1823
+ }
1824
+ if (item.nested) nested = item.nested;
1771
1825
  }
1772
- if (item.nested) nested = item.nested;
1773
1826
  }
1774
1827
  if (nested) {
1775
1828
  const result = await handleNestedFields(nested, value, field, context);
1776
1829
  errors.push(...result.errors);
1830
+ warnings.push(...result.warnings);
1777
1831
  }
1778
1832
  return {
1779
1833
  valid: errors.length === 0,
1780
- errors
1834
+ errors,
1835
+ warnings
1781
1836
  };
1782
1837
  }
1783
1838
  async function handleNestedFields(nested, value, field, context) {
1784
1839
  const errors = [];
1840
+ const warnings = [];
1785
1841
  let store = isObject(nested) ? nested.store : nested;
1786
1842
  const domain = isObject(nested) && nested.domain ? nested.domain : void 0;
1787
1843
  context = {
@@ -1812,7 +1868,8 @@ async function handleNestedFields(nested, value, field, context) {
1812
1868
  path: context.path.join("."),
1813
1869
  message: `Failed to resolve remote resource ${item}: ${error}`
1814
1870
  }
1815
- ]
1871
+ ],
1872
+ warnings
1816
1873
  };
1817
1874
  }
1818
1875
  } else {
@@ -1832,17 +1889,20 @@ async function handleNestedFields(nested, value, field, context) {
1832
1889
  } else {
1833
1890
  const result = await context.roots[resolvedDomain].validateFields(store, context);
1834
1891
  errors.push(...result.errors);
1892
+ warnings.push(...result.warnings);
1835
1893
  }
1836
1894
  } else if (store) {
1837
1895
  await context.validateNestedFields(store, context);
1838
1896
  }
1839
1897
  return {
1840
1898
  valid: errors.length === 0,
1841
- errors
1899
+ errors,
1900
+ warnings
1842
1901
  };
1843
1902
  }
1844
1903
  async function handlePrimitiveType2(value, field, context) {
1845
1904
  const errors = [];
1905
+ const warnings = [];
1846
1906
  if (field.validate) {
1847
1907
  if (typeof value === "string") {
1848
1908
  if (field.validate.pattern && !new RegExp(
@@ -1896,10 +1956,12 @@ async function handlePrimitiveType2(value, field, context) {
1896
1956
  if (nested) {
1897
1957
  const result = await handleNestedFields(nested, value, field, context);
1898
1958
  errors.push(...result.errors);
1959
+ warnings.push(...result.warnings);
1899
1960
  }
1900
1961
  return {
1901
1962
  valid: errors.length === 0,
1902
- errors
1963
+ errors,
1964
+ warnings
1903
1965
  };
1904
1966
  }
1905
1967
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makehq/forman-schema",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Forman Schema Tools",
5
5
  "license": "MIT",
6
6
  "author": "Make",