@makehq/forman-schema 1.9.5 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +69 -6
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +69 -6
- 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",
|
|
@@ -1115,6 +1156,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1115
1156
|
acc[domain] = {
|
|
1116
1157
|
seenFields: /* @__PURE__ */ new Set(),
|
|
1117
1158
|
fieldStates: [],
|
|
1159
|
+
schemaFields: [],
|
|
1118
1160
|
validateFields: (fields, context) => {
|
|
1119
1161
|
return validateFormanValue(
|
|
1120
1162
|
domains[domain].values,
|
|
@@ -1150,6 +1192,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1150
1192
|
path: [],
|
|
1151
1193
|
tail: [],
|
|
1152
1194
|
strict: options?.strict === true,
|
|
1195
|
+
domainAliases: options?.domainAliases ?? {},
|
|
1153
1196
|
validateNestedFields: () => {
|
|
1154
1197
|
throw new Error("Cannot validate nested fields without parent field.");
|
|
1155
1198
|
},
|
|
@@ -1192,12 +1235,25 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1192
1235
|
}
|
|
1193
1236
|
}
|
|
1194
1237
|
}
|
|
1238
|
+
if (options?.strict) {
|
|
1239
|
+
for (const domain of Object.keys(domains)) {
|
|
1240
|
+
if (!domains[domain]) continue;
|
|
1241
|
+
const root = roots[domain];
|
|
1242
|
+
for (const key of Object.keys(domains[domain].values)) {
|
|
1243
|
+
if (!root.seenFields.has(key)) {
|
|
1244
|
+
root.seenFields.add(key);
|
|
1245
|
+
errors.push({ domain, path: "", message: `Unknown field '${key}'.` });
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1195
1250
|
return {
|
|
1196
1251
|
valid: errors.length === 0,
|
|
1197
1252
|
errors,
|
|
1198
1253
|
states: errors.length === 0 && options?.states ? buildRestoreStructure(
|
|
1199
1254
|
Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
|
|
1200
|
-
) : void 0
|
|
1255
|
+
) : void 0,
|
|
1256
|
+
schemas: errors.length === 0 && options?.schemas ? Object.fromEntries(Object.keys(domains).map((domain) => [domain, roots[domain].schemaFields])) : void 0
|
|
1201
1257
|
};
|
|
1202
1258
|
}
|
|
1203
1259
|
async function validateFormanValue(value, field, context) {
|
|
@@ -1346,6 +1402,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1346
1402
|
continue;
|
|
1347
1403
|
}
|
|
1348
1404
|
if (context.strict && !seen.has(subField.name)) seen.add(subField.name);
|
|
1405
|
+
if (path.length === 0) {
|
|
1406
|
+
context.roots[context.domain].schemaFields.push(clampFieldForSchema(subField));
|
|
1407
|
+
}
|
|
1349
1408
|
const result = await validateFormanValue(value[subField.name], subField, {
|
|
1350
1409
|
...context,
|
|
1351
1410
|
path: [...path, subField.name],
|
|
@@ -1363,6 +1422,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1363
1422
|
continue;
|
|
1364
1423
|
}
|
|
1365
1424
|
if (context2.strict && !seen.has(subField2.name)) seen.add(subField2.name);
|
|
1425
|
+
if (path.length === 0) {
|
|
1426
|
+
context2.roots[context2.domain].schemaFields.push(clampFieldForSchema(subField2));
|
|
1427
|
+
}
|
|
1366
1428
|
const result2 = await validateFormanValue(value[subField2.name], subField2, {
|
|
1367
1429
|
...context2,
|
|
1368
1430
|
path: [...path, subField2.name]
|
|
@@ -1374,7 +1436,7 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1374
1436
|
errors.push(...result.errors);
|
|
1375
1437
|
}
|
|
1376
1438
|
}
|
|
1377
|
-
if (context.strict) {
|
|
1439
|
+
if (context.strict && context.path.length > 0) {
|
|
1378
1440
|
for (const key of Object.keys(value)) {
|
|
1379
1441
|
if (!seen.has(key)) {
|
|
1380
1442
|
seen.add(key);
|
|
@@ -1788,15 +1850,16 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1788
1850
|
}
|
|
1789
1851
|
store = resolvedStore;
|
|
1790
1852
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1853
|
+
const resolvedDomain = domain ? context.domainAliases[domain] ?? domain : domain;
|
|
1854
|
+
if (store && resolvedDomain && resolvedDomain !== context.domain) {
|
|
1855
|
+
if (!context.roots[resolvedDomain]) {
|
|
1793
1856
|
errors.push({
|
|
1794
1857
|
domain: context.domain,
|
|
1795
1858
|
path: context.path.join("."),
|
|
1796
|
-
message: `Unable to process nested fields: Domain '${domain}' not found.`
|
|
1859
|
+
message: resolvedDomain !== domain ? `Unable to process nested fields: Resolved domain '${resolvedDomain}' (from alias '${domain}') not found.` : `Unable to process nested fields: Domain '${domain}' not found.`
|
|
1797
1860
|
});
|
|
1798
1861
|
} else {
|
|
1799
|
-
const result = await context.roots[
|
|
1862
|
+
const result = await context.roots[resolvedDomain].validateFields(store, context);
|
|
1800
1863
|
errors.push(...result.errors);
|
|
1801
1864
|
}
|
|
1802
1865
|
} else if (store) {
|
package/dist/index.d.cts
CHANGED
|
@@ -199,6 +199,8 @@ type FormanValidationResult = {
|
|
|
199
199
|
}[];
|
|
200
200
|
/** States of fields grouped by domain */
|
|
201
201
|
states?: Record<string, FormanSchemaFieldState>;
|
|
202
|
+
/** Resolved schema fields per domain */
|
|
203
|
+
schemas?: Record<string, FormanSchemaField[]>;
|
|
202
204
|
};
|
|
203
205
|
type FormanSchemaFieldState = {
|
|
204
206
|
mode?: 'chose' | 'edit';
|
|
@@ -214,8 +216,12 @@ type FormanValidationOptions = {
|
|
|
214
216
|
strict?: boolean;
|
|
215
217
|
/** Whether to generate states for fields */
|
|
216
218
|
states?: boolean;
|
|
219
|
+
/** Whether to collect resolved schema fields per domain */
|
|
220
|
+
schemas?: boolean;
|
|
217
221
|
/** Remote resource resolver */
|
|
218
222
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
223
|
+
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
|
224
|
+
domainAliases?: Record<string, string>;
|
|
219
225
|
};
|
|
220
226
|
|
|
221
227
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -199,6 +199,8 @@ type FormanValidationResult = {
|
|
|
199
199
|
}[];
|
|
200
200
|
/** States of fields grouped by domain */
|
|
201
201
|
states?: Record<string, FormanSchemaFieldState>;
|
|
202
|
+
/** Resolved schema fields per domain */
|
|
203
|
+
schemas?: Record<string, FormanSchemaField[]>;
|
|
202
204
|
};
|
|
203
205
|
type FormanSchemaFieldState = {
|
|
204
206
|
mode?: 'chose' | 'edit';
|
|
@@ -214,8 +216,12 @@ type FormanValidationOptions = {
|
|
|
214
216
|
strict?: boolean;
|
|
215
217
|
/** Whether to generate states for fields */
|
|
216
218
|
states?: boolean;
|
|
219
|
+
/** Whether to collect resolved schema fields per domain */
|
|
220
|
+
schemas?: boolean;
|
|
217
221
|
/** Remote resource resolver */
|
|
218
222
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
223
|
+
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
|
224
|
+
domainAliases?: Record<string, string>;
|
|
219
225
|
};
|
|
220
226
|
|
|
221
227
|
/**
|
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",
|
|
@@ -1086,6 +1127,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1086
1127
|
acc[domain] = {
|
|
1087
1128
|
seenFields: /* @__PURE__ */ new Set(),
|
|
1088
1129
|
fieldStates: [],
|
|
1130
|
+
schemaFields: [],
|
|
1089
1131
|
validateFields: (fields, context) => {
|
|
1090
1132
|
return validateFormanValue(
|
|
1091
1133
|
domains[domain].values,
|
|
@@ -1121,6 +1163,7 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1121
1163
|
path: [],
|
|
1122
1164
|
tail: [],
|
|
1123
1165
|
strict: options?.strict === true,
|
|
1166
|
+
domainAliases: options?.domainAliases ?? {},
|
|
1124
1167
|
validateNestedFields: () => {
|
|
1125
1168
|
throw new Error("Cannot validate nested fields without parent field.");
|
|
1126
1169
|
},
|
|
@@ -1163,12 +1206,25 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1163
1206
|
}
|
|
1164
1207
|
}
|
|
1165
1208
|
}
|
|
1209
|
+
if (options?.strict) {
|
|
1210
|
+
for (const domain of Object.keys(domains)) {
|
|
1211
|
+
if (!domains[domain]) continue;
|
|
1212
|
+
const root = roots[domain];
|
|
1213
|
+
for (const key of Object.keys(domains[domain].values)) {
|
|
1214
|
+
if (!root.seenFields.has(key)) {
|
|
1215
|
+
root.seenFields.add(key);
|
|
1216
|
+
errors.push({ domain, path: "", message: `Unknown field '${key}'.` });
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1166
1221
|
return {
|
|
1167
1222
|
valid: errors.length === 0,
|
|
1168
1223
|
errors,
|
|
1169
1224
|
states: errors.length === 0 && options?.states ? buildRestoreStructure(
|
|
1170
1225
|
Object.keys(domains).map((domain) => roots[domain].fieldStates.map((state) => ({ domain, ...state }))).flat()
|
|
1171
|
-
) : void 0
|
|
1226
|
+
) : void 0,
|
|
1227
|
+
schemas: errors.length === 0 && options?.schemas ? Object.fromEntries(Object.keys(domains).map((domain) => [domain, roots[domain].schemaFields])) : void 0
|
|
1172
1228
|
};
|
|
1173
1229
|
}
|
|
1174
1230
|
async function validateFormanValue(value, field, context) {
|
|
@@ -1317,6 +1373,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1317
1373
|
continue;
|
|
1318
1374
|
}
|
|
1319
1375
|
if (context.strict && !seen.has(subField.name)) seen.add(subField.name);
|
|
1376
|
+
if (path.length === 0) {
|
|
1377
|
+
context.roots[context.domain].schemaFields.push(clampFieldForSchema(subField));
|
|
1378
|
+
}
|
|
1320
1379
|
const result = await validateFormanValue(value[subField.name], subField, {
|
|
1321
1380
|
...context,
|
|
1322
1381
|
path: [...path, subField.name],
|
|
@@ -1334,6 +1393,9 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1334
1393
|
continue;
|
|
1335
1394
|
}
|
|
1336
1395
|
if (context2.strict && !seen.has(subField2.name)) seen.add(subField2.name);
|
|
1396
|
+
if (path.length === 0) {
|
|
1397
|
+
context2.roots[context2.domain].schemaFields.push(clampFieldForSchema(subField2));
|
|
1398
|
+
}
|
|
1337
1399
|
const result2 = await validateFormanValue(value[subField2.name], subField2, {
|
|
1338
1400
|
...context2,
|
|
1339
1401
|
path: [...path, subField2.name]
|
|
@@ -1345,7 +1407,7 @@ async function handleCollectionType2(value, field, context) {
|
|
|
1345
1407
|
errors.push(...result.errors);
|
|
1346
1408
|
}
|
|
1347
1409
|
}
|
|
1348
|
-
if (context.strict) {
|
|
1410
|
+
if (context.strict && context.path.length > 0) {
|
|
1349
1411
|
for (const key of Object.keys(value)) {
|
|
1350
1412
|
if (!seen.has(key)) {
|
|
1351
1413
|
seen.add(key);
|
|
@@ -1759,15 +1821,16 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1759
1821
|
}
|
|
1760
1822
|
store = resolvedStore;
|
|
1761
1823
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1824
|
+
const resolvedDomain = domain ? context.domainAliases[domain] ?? domain : domain;
|
|
1825
|
+
if (store && resolvedDomain && resolvedDomain !== context.domain) {
|
|
1826
|
+
if (!context.roots[resolvedDomain]) {
|
|
1764
1827
|
errors.push({
|
|
1765
1828
|
domain: context.domain,
|
|
1766
1829
|
path: context.path.join("."),
|
|
1767
|
-
message: `Unable to process nested fields: Domain '${domain}' not found.`
|
|
1830
|
+
message: resolvedDomain !== domain ? `Unable to process nested fields: Resolved domain '${resolvedDomain}' (from alias '${domain}') not found.` : `Unable to process nested fields: Domain '${domain}' not found.`
|
|
1768
1831
|
});
|
|
1769
1832
|
} else {
|
|
1770
|
-
const result = await context.roots[
|
|
1833
|
+
const result = await context.roots[resolvedDomain].validateFields(store, context);
|
|
1771
1834
|
errors.push(...result.errors);
|
|
1772
1835
|
}
|
|
1773
1836
|
} else if (store) {
|