@makehq/forman-schema 1.11.0 → 1.12.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
@@ -1158,6 +1158,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1158
1158
  seenFields: /* @__PURE__ */ new Set(),
1159
1159
  fieldStates: [],
1160
1160
  schemaFields: [],
1161
+ allowDynamicValues: domains[domain].allowDynamicValues ?? options?.allowDynamicValues ?? false,
1161
1162
  validateFields: (fields, context) => {
1162
1163
  return validateFormanValue(
1163
1164
  domains[domain].values,
@@ -1308,7 +1309,7 @@ async function validateFormanValue(value, field, context) {
1308
1309
  };
1309
1310
  }
1310
1311
  if (containsIMLExpression(value)) {
1311
- if (normalizedField.mappable === false) {
1312
+ if (normalizedField.mappable === false || !context.roots[context.domain].allowDynamicValues) {
1312
1313
  return {
1313
1314
  valid: false,
1314
1315
  errors: [
@@ -1775,6 +1776,7 @@ async function handleSelectType(value, field, context) {
1775
1776
  warnings
1776
1777
  };
1777
1778
  }
1779
+ let hasUnresolvedValue = false;
1778
1780
  for (const singleValue of value) {
1779
1781
  const found = findValueInSelectOptions(
1780
1782
  field,
@@ -1782,13 +1784,20 @@ async function handleSelectType(value, field, context) {
1782
1784
  optionsOrGroups
1783
1785
  );
1784
1786
  if (!found) {
1785
- (optionsFromRPC ? warnings : errors).push({
1787
+ (optionsFromRPC && context.roots[context.domain].allowDynamicValues ? warnings : errors).push({
1786
1788
  domain: context.domain,
1787
1789
  path: context.path.join("."),
1788
1790
  message: `Value '${singleValue}' not found in options.`
1789
1791
  });
1792
+ hasUnresolvedValue = true;
1790
1793
  }
1791
1794
  }
1795
+ if (optionsFromRPC && context.roots[context.domain].allowDynamicValues && hasUnresolvedValue) {
1796
+ context.roots[context.domain].fieldStates.push({
1797
+ path: context.path,
1798
+ state: { mode: "edit" }
1799
+ });
1800
+ }
1792
1801
  if (field.validate) {
1793
1802
  if (field.validate.minItems !== void 0 && value.length < field.validate.minItems) {
1794
1803
  errors.push({
@@ -1820,12 +1829,16 @@ async function handleSelectType(value, field, context) {
1820
1829
  } else {
1821
1830
  const item = findValueInSelectOptions(field, value, optionsOrGroups);
1822
1831
  if (!item) {
1823
- if (optionsFromRPC) {
1832
+ if (optionsFromRPC && context.roots[context.domain].allowDynamicValues) {
1824
1833
  warnings.push({
1825
1834
  domain: context.domain,
1826
1835
  path: context.path.join("."),
1827
1836
  message: `Value '${value}' not found in options.`
1828
1837
  });
1838
+ context.roots[context.domain].fieldStates.push({
1839
+ path: context.path,
1840
+ state: { mode: "edit" }
1841
+ });
1829
1842
  } else {
1830
1843
  return {
1831
1844
  valid: false,
@@ -2146,7 +2159,10 @@ function validateFormanWithDomains(domains, options) {
2146
2159
  return validateFormanWithDomainsInternal(domains, options);
2147
2160
  }
2148
2161
  function validateForman(values, schema, options, restoreExtras) {
2149
- return validateFormanWithDomains({ default: { values, schema, restoreExtras } }, options);
2162
+ return validateFormanWithDomains(
2163
+ { default: { values, schema, restoreExtras, allowDynamicValues: options?.allowDynamicValues } },
2164
+ options
2165
+ );
2150
2166
  }
2151
2167
  // Annotate the CommonJS export names for ESM import in node:
2152
2168
  0 && (module.exports = {
package/dist/index.d.cts CHANGED
@@ -231,6 +231,10 @@ type FormanValidationOptions = {
231
231
  resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
232
232
  /** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
233
233
  domainAliases?: Record<string, string>;
234
+ /** Whether to allow dynamic values (IML expressions, unresolved RPC options).
235
+ * When false (default), IML expressions cause errors and unresolved RPC options are treated as errors.
236
+ * Applies as a global default; can be overridden per-domain in validateFormanWithDomains(). */
237
+ allowDynamicValues?: boolean;
234
238
  };
235
239
 
236
240
  /**
@@ -257,6 +261,9 @@ declare function validateFormanWithDomains(domains: Record<string, {
257
261
  schema: FormanSchemaField[];
258
262
  /** Extra values injected into restore states, keyed by string path (dot notation, `[index]`, backtick-escaping). */
259
263
  restoreExtras?: Record<string, Record<string, unknown>>;
264
+ /** Whether the domain allows dynamic values (IML expressions, unresolved RPC select options).
265
+ * Defaults to false. When false, IML expressions cause errors and unresolved RPC options are treated as errors. */
266
+ allowDynamicValues?: boolean;
260
267
  }>, options?: FormanValidationOptions): Promise<FormanValidationResult>;
261
268
  /**
262
269
  * Validates a simple Forman values against a schema
package/dist/index.d.ts CHANGED
@@ -231,6 +231,10 @@ type FormanValidationOptions = {
231
231
  resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
232
232
  /** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
233
233
  domainAliases?: Record<string, string>;
234
+ /** Whether to allow dynamic values (IML expressions, unresolved RPC options).
235
+ * When false (default), IML expressions cause errors and unresolved RPC options are treated as errors.
236
+ * Applies as a global default; can be overridden per-domain in validateFormanWithDomains(). */
237
+ allowDynamicValues?: boolean;
234
238
  };
235
239
 
236
240
  /**
@@ -257,6 +261,9 @@ declare function validateFormanWithDomains(domains: Record<string, {
257
261
  schema: FormanSchemaField[];
258
262
  /** Extra values injected into restore states, keyed by string path (dot notation, `[index]`, backtick-escaping). */
259
263
  restoreExtras?: Record<string, Record<string, unknown>>;
264
+ /** Whether the domain allows dynamic values (IML expressions, unresolved RPC select options).
265
+ * Defaults to false. When false, IML expressions cause errors and unresolved RPC options are treated as errors. */
266
+ allowDynamicValues?: boolean;
260
267
  }>, options?: FormanValidationOptions): Promise<FormanValidationResult>;
261
268
  /**
262
269
  * Validates a simple Forman values against a schema
package/dist/index.js CHANGED
@@ -1129,6 +1129,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
1129
1129
  seenFields: /* @__PURE__ */ new Set(),
1130
1130
  fieldStates: [],
1131
1131
  schemaFields: [],
1132
+ allowDynamicValues: domains[domain].allowDynamicValues ?? options?.allowDynamicValues ?? false,
1132
1133
  validateFields: (fields, context) => {
1133
1134
  return validateFormanValue(
1134
1135
  domains[domain].values,
@@ -1279,7 +1280,7 @@ async function validateFormanValue(value, field, context) {
1279
1280
  };
1280
1281
  }
1281
1282
  if (containsIMLExpression(value)) {
1282
- if (normalizedField.mappable === false) {
1283
+ if (normalizedField.mappable === false || !context.roots[context.domain].allowDynamicValues) {
1283
1284
  return {
1284
1285
  valid: false,
1285
1286
  errors: [
@@ -1746,6 +1747,7 @@ async function handleSelectType(value, field, context) {
1746
1747
  warnings
1747
1748
  };
1748
1749
  }
1750
+ let hasUnresolvedValue = false;
1749
1751
  for (const singleValue of value) {
1750
1752
  const found = findValueInSelectOptions(
1751
1753
  field,
@@ -1753,13 +1755,20 @@ async function handleSelectType(value, field, context) {
1753
1755
  optionsOrGroups
1754
1756
  );
1755
1757
  if (!found) {
1756
- (optionsFromRPC ? warnings : errors).push({
1758
+ (optionsFromRPC && context.roots[context.domain].allowDynamicValues ? warnings : errors).push({
1757
1759
  domain: context.domain,
1758
1760
  path: context.path.join("."),
1759
1761
  message: `Value '${singleValue}' not found in options.`
1760
1762
  });
1763
+ hasUnresolvedValue = true;
1761
1764
  }
1762
1765
  }
1766
+ if (optionsFromRPC && context.roots[context.domain].allowDynamicValues && hasUnresolvedValue) {
1767
+ context.roots[context.domain].fieldStates.push({
1768
+ path: context.path,
1769
+ state: { mode: "edit" }
1770
+ });
1771
+ }
1763
1772
  if (field.validate) {
1764
1773
  if (field.validate.minItems !== void 0 && value.length < field.validate.minItems) {
1765
1774
  errors.push({
@@ -1791,12 +1800,16 @@ async function handleSelectType(value, field, context) {
1791
1800
  } else {
1792
1801
  const item = findValueInSelectOptions(field, value, optionsOrGroups);
1793
1802
  if (!item) {
1794
- if (optionsFromRPC) {
1803
+ if (optionsFromRPC && context.roots[context.domain].allowDynamicValues) {
1795
1804
  warnings.push({
1796
1805
  domain: context.domain,
1797
1806
  path: context.path.join("."),
1798
1807
  message: `Value '${value}' not found in options.`
1799
1808
  });
1809
+ context.roots[context.domain].fieldStates.push({
1810
+ path: context.path,
1811
+ state: { mode: "edit" }
1812
+ });
1800
1813
  } else {
1801
1814
  return {
1802
1815
  valid: false,
@@ -2117,7 +2130,10 @@ function validateFormanWithDomains(domains, options) {
2117
2130
  return validateFormanWithDomainsInternal(domains, options);
2118
2131
  }
2119
2132
  function validateForman(values, schema, options, restoreExtras) {
2120
- return validateFormanWithDomains({ default: { values, schema, restoreExtras } }, options);
2133
+ return validateFormanWithDomains(
2134
+ { default: { values, schema, restoreExtras, allowDynamicValues: options?.allowDynamicValues } },
2135
+ options
2136
+ );
2121
2137
  }
2122
2138
  export {
2123
2139
  toFormanSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makehq/forman-schema",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Forman Schema Tools",
5
5
  "license": "MIT",
6
6
  "author": "Make",