@makehq/forman-schema 1.14.0 → 1.15.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/README.md +51 -1
- package/dist/index.cjs +58 -4
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +58 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,56 @@ const jsonSchemaField = {
|
|
|
80
80
|
const formanSchema = toFormanSchema(jsonSchemaField);
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
### JSON fields (`type: 'json'`)
|
|
84
|
+
|
|
85
|
+
A `json` field can carry an explicit `schema` (a JSON Schema). This lets you author complex parts of a form directly in JSON Schema and mix them with primitive Forman fields:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
const formanField = {
|
|
89
|
+
type: 'collection',
|
|
90
|
+
spec: [
|
|
91
|
+
{ name: 'title', type: 'text' },
|
|
92
|
+
{
|
|
93
|
+
name: 'input',
|
|
94
|
+
type: 'json',
|
|
95
|
+
schema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
name: { type: 'string' },
|
|
99
|
+
age: { type: 'number' },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
On conversion, the `schema` is **echoed verbatim** into the JSON Schema output (the field's `label`/`help` fill in `title`/`description` only when the schema omits them). An enumerable `x-json` marker is added so `toFormanSchema` can recover the `json` type; it survives JSON serialization. A `json` field **without** a `schema` renders as a plain object schema (`{ type: 'object' }`), since a JSON value is most naturally an object.
|
|
108
|
+
|
|
109
|
+
#### External validators
|
|
110
|
+
|
|
111
|
+
The library cannot validate a JSON value against an arbitrary JSON Schema on its own — it has **no JSON Schema validator built in**. Validation of `json` fields is therefore opt-in: **a `json` value is not validated unless you provide a `validateJson` callback.** Without it, the value passes through untouched.
|
|
112
|
+
|
|
113
|
+
This is the first of a general **external validator** concept: a callback that performs validation the library can't, and returns a `FormanExternalValidationResult` verdict (`{ valid, errors?, warnings? }`) that is spliced into the overall result. The callback may be async (awaited), and its `errors`/`warnings` are stamped with the field's domain and path automatically. A `valid: false` verdict always fails validation, even when it carries no messages.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { validateForman, type FormanExternalValidationResult } from '@makehq/forman-schema';
|
|
117
|
+
import Ajv from 'ajv'; // any JSON Schema validator works
|
|
118
|
+
|
|
119
|
+
const ajv = new Ajv({ allErrors: true });
|
|
120
|
+
|
|
121
|
+
const result = await validateForman({ input: { name: 'Alice', age: 30 } }, schema, {
|
|
122
|
+
async validateJson(schema, value): Promise<FormanExternalValidationResult> {
|
|
123
|
+
const validate = ajv.compile(schema);
|
|
124
|
+
if (validate(value)) return { valid: true };
|
|
125
|
+
return {
|
|
126
|
+
valid: false,
|
|
127
|
+
errors: (validate.errors ?? []).map(e => `${e.instancePath} ${e.message}`),
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
83
133
|
### Validation
|
|
84
134
|
|
|
85
135
|
Validate Forman values against a Forman Schema. Two entry points are available:
|
|
@@ -217,7 +267,7 @@ const result = await validateFormanWithDomains(
|
|
|
217
267
|
- hidden → string
|
|
218
268
|
- hook → number
|
|
219
269
|
- integer → number
|
|
220
|
-
- json →
|
|
270
|
+
- json → object (or its `schema` echoed verbatim when provided — see [JSON fields](#json-fields-type-json))
|
|
221
271
|
- keychain → number
|
|
222
272
|
- number → number
|
|
223
273
|
- path → string
|
package/dist/index.cjs
CHANGED
|
@@ -561,7 +561,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
561
561
|
boolean: "boolean",
|
|
562
562
|
checkbox: "boolean",
|
|
563
563
|
date: "string",
|
|
564
|
-
json: "
|
|
564
|
+
json: "object",
|
|
565
565
|
buffer: "string",
|
|
566
566
|
cert: "string",
|
|
567
567
|
color: "string",
|
|
@@ -671,6 +671,8 @@ function toJSONSchemaInternal(field, context) {
|
|
|
671
671
|
case "collection":
|
|
672
672
|
case "dynamicCollection":
|
|
673
673
|
return handleCollectionType(normalizedField, result, context);
|
|
674
|
+
case "json":
|
|
675
|
+
return handleJsonType(normalizedField, result);
|
|
674
676
|
case "array":
|
|
675
677
|
case "filestorage":
|
|
676
678
|
return handleArrayType(normalizedField, result, context);
|
|
@@ -1027,6 +1029,20 @@ function handleSelectOrPathType(field, result, context) {
|
|
|
1027
1029
|
if (field.rpc) result = processRpcDirective(field, result, context);
|
|
1028
1030
|
return result;
|
|
1029
1031
|
}
|
|
1032
|
+
function handleJsonType(field, result) {
|
|
1033
|
+
if (!isObject(field.schema)) {
|
|
1034
|
+
return result;
|
|
1035
|
+
}
|
|
1036
|
+
delete result.type;
|
|
1037
|
+
Object.assign(result, field.schema);
|
|
1038
|
+
Object.defineProperty(result, "x-json", {
|
|
1039
|
+
configurable: true,
|
|
1040
|
+
enumerable: true,
|
|
1041
|
+
writable: true,
|
|
1042
|
+
value: true
|
|
1043
|
+
});
|
|
1044
|
+
return result;
|
|
1045
|
+
}
|
|
1030
1046
|
function handlePrimitiveType(field, result, context) {
|
|
1031
1047
|
if (field.default !== "" && field.default != null) {
|
|
1032
1048
|
result.default = field.default;
|
|
@@ -1146,7 +1162,8 @@ var SCHEMA_STRIP_KEYS = [
|
|
|
1146
1162
|
"tags",
|
|
1147
1163
|
"extension",
|
|
1148
1164
|
"codepage",
|
|
1149
|
-
"logic"
|
|
1165
|
+
"logic",
|
|
1166
|
+
"schema"
|
|
1150
1167
|
];
|
|
1151
1168
|
function clampFieldForSchema(field) {
|
|
1152
1169
|
const clamped = { ...field };
|
|
@@ -1191,7 +1208,7 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
1191
1208
|
boolean: "boolean",
|
|
1192
1209
|
checkbox: "boolean",
|
|
1193
1210
|
date: "string",
|
|
1194
|
-
json:
|
|
1211
|
+
json: void 0,
|
|
1195
1212
|
buffer: "string",
|
|
1196
1213
|
cert: "string",
|
|
1197
1214
|
color: "string",
|
|
@@ -1286,7 +1303,8 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1286
1303
|
...data,
|
|
1287
1304
|
...localData
|
|
1288
1305
|
});
|
|
1289
|
-
}
|
|
1306
|
+
},
|
|
1307
|
+
validateJson: options?.validateJson
|
|
1290
1308
|
}
|
|
1291
1309
|
);
|
|
1292
1310
|
errors.push(...result.errors);
|
|
@@ -1418,6 +1436,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1418
1436
|
return validateFormanValue(value, udtspecExpand({ ...normalizedField }), context);
|
|
1419
1437
|
}
|
|
1420
1438
|
switch (normalizedField.type) {
|
|
1439
|
+
case "json":
|
|
1440
|
+
return handleJsonType2(value, normalizedField, context);
|
|
1421
1441
|
case "collection":
|
|
1422
1442
|
return handleCollectionType2(value, normalizedField, context);
|
|
1423
1443
|
case "array":
|
|
@@ -2018,6 +2038,35 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
2018
2038
|
warnings
|
|
2019
2039
|
};
|
|
2020
2040
|
}
|
|
2041
|
+
async function handleJsonType2(value, field, context) {
|
|
2042
|
+
const errors = [];
|
|
2043
|
+
const warnings = [];
|
|
2044
|
+
if (!isObject(field.schema) || !context.validateJson) {
|
|
2045
|
+
return { valid: true, errors, warnings };
|
|
2046
|
+
}
|
|
2047
|
+
const path = context.path.join(".");
|
|
2048
|
+
let fragment;
|
|
2049
|
+
try {
|
|
2050
|
+
fragment = await context.validateJson(field.schema, value);
|
|
2051
|
+
} catch (err) {
|
|
2052
|
+
const message = err instanceof Error ? err.message : "JSON schema validation failed unexpectedly.";
|
|
2053
|
+
return { valid: false, errors: [{ domain: context.domain, path, message }], warnings };
|
|
2054
|
+
}
|
|
2055
|
+
for (const message of fragment.errors ?? []) {
|
|
2056
|
+
errors.push({ domain: context.domain, path, message });
|
|
2057
|
+
}
|
|
2058
|
+
for (const message of fragment.warnings ?? []) {
|
|
2059
|
+
warnings.push({ domain: context.domain, path, message });
|
|
2060
|
+
}
|
|
2061
|
+
if (fragment.valid === false && errors.length === 0) {
|
|
2062
|
+
errors.push({ domain: context.domain, path, message: "JSON value failed schema validation." });
|
|
2063
|
+
}
|
|
2064
|
+
return {
|
|
2065
|
+
valid: errors.length === 0,
|
|
2066
|
+
errors,
|
|
2067
|
+
warnings
|
|
2068
|
+
};
|
|
2069
|
+
}
|
|
2021
2070
|
async function handlePrimitiveType2(value, field, context) {
|
|
2022
2071
|
const errors = [];
|
|
2023
2072
|
const warnings = [];
|
|
@@ -2098,6 +2147,11 @@ function toFormanSchema(field) {
|
|
|
2098
2147
|
return result;
|
|
2099
2148
|
}
|
|
2100
2149
|
function toFormanSchemaInternal(field) {
|
|
2150
|
+
if (Object.getOwnPropertyDescriptor(field, "x-json")?.value === true) {
|
|
2151
|
+
const schema = { ...field };
|
|
2152
|
+
delete schema["x-json"];
|
|
2153
|
+
return { type: "json", schema };
|
|
2154
|
+
}
|
|
2101
2155
|
const compositeType = Object.getOwnPropertyDescriptor(field, "x-composite")?.value;
|
|
2102
2156
|
if (compositeType === "udttype") return udttypeCollapse(field);
|
|
2103
2157
|
if (compositeType === "udtspec") return udtspecCollapse(field);
|
package/dist/index.d.cts
CHANGED
|
@@ -41,6 +41,8 @@ type FormanSchemaField = {
|
|
|
41
41
|
help?: string;
|
|
42
42
|
/** Sub-fields specification for collection or array types */
|
|
43
43
|
spec?: FormanSchemaField[] | FormanSchemaField;
|
|
44
|
+
/** JSON Schema for `json` typed fields */
|
|
45
|
+
schema?: JSONSchema7;
|
|
44
46
|
/** Hide field behind advanced toggle */
|
|
45
47
|
advanced?: boolean;
|
|
46
48
|
/** Human readable label for the field */
|
|
@@ -246,6 +248,19 @@ type FormanJsonSchemaResult = {
|
|
|
246
248
|
advanced?: string[];
|
|
247
249
|
};
|
|
248
250
|
};
|
|
251
|
+
/**
|
|
252
|
+
* Verdict fragment returned by an external validation callback (e.g. `validateJson`) that the
|
|
253
|
+
* library cannot perform itself. Spliced into the overall validation result: `errors`/`warnings`
|
|
254
|
+
* are stamped with the field's domain and path.
|
|
255
|
+
*/
|
|
256
|
+
type FormanExternalValidationResult = {
|
|
257
|
+
/** Whether the value is valid. A `false` verdict always fails validation, even with no messages. */
|
|
258
|
+
valid: boolean;
|
|
259
|
+
/** Error messages (cause validation to fail) */
|
|
260
|
+
errors?: string[];
|
|
261
|
+
/** Warning messages (do not affect validity) */
|
|
262
|
+
warnings?: string[];
|
|
263
|
+
};
|
|
249
264
|
type FormanValidationOptions = {
|
|
250
265
|
/** Unknown fields are not allowed when strict is true */
|
|
251
266
|
strict?: boolean;
|
|
@@ -255,6 +270,10 @@ type FormanValidationOptions = {
|
|
|
255
270
|
schemas?: boolean;
|
|
256
271
|
/** Remote resource resolver */
|
|
257
272
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
273
|
+
/** Validator for `json` typed fields. Receives the field's JSON Schema and the value, and
|
|
274
|
+
* returns (or resolves to) a result fragment that is spliced into the overall validation
|
|
275
|
+
* result. When omitted, `json` fields with a `schema` pass without schema validation. */
|
|
276
|
+
validateJson?(schema: JSONSchema7, value: unknown): FormanExternalValidationResult | Promise<FormanExternalValidationResult>;
|
|
258
277
|
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
|
259
278
|
domainAliases?: Record<string, string>;
|
|
260
279
|
/** Whether to allow dynamic values (IML expressions, unresolved RPC options).
|
|
@@ -334,4 +353,4 @@ declare function validateFormanWithDomains(domains: Record<string, {
|
|
|
334
353
|
*/
|
|
335
354
|
declare function validateForman(values: Record<string, unknown>, schema: FormanSchemaField[], options?: FormanValidationOptions, restoreExtras?: Record<string, Record<string, unknown>>): Promise<FormanValidationResult>;
|
|
336
355
|
|
|
337
|
-
export { type FormanJsonSchemaOptions, type FormanJsonSchemaResult, type FormanSchemaDirectoryOption, type FormanSchemaExtendedNested, type FormanSchemaExtendedOptions, type FormanSchemaField, type FormanSchemaFieldType, type FormanSchemaNested, type FormanSchemaOption, type FormanSchemaOptionGroup, type FormanSchemaPathExtendedOptions, type FormanSchemaRPCButton, type FormanSchemaValue, type FormanValidationOptions, type FormanValidationResult, toFormanSchema, toJSONSchema, toJSONSchemaAdvanced, validateForman, validateFormanWithDomains };
|
|
356
|
+
export { type FormanExternalValidationResult, type FormanJsonSchemaOptions, type FormanJsonSchemaResult, type FormanSchemaDirectoryOption, type FormanSchemaExtendedNested, type FormanSchemaExtendedOptions, type FormanSchemaField, type FormanSchemaFieldType, type FormanSchemaNested, type FormanSchemaOption, type FormanSchemaOptionGroup, type FormanSchemaPathExtendedOptions, type FormanSchemaRPCButton, type FormanSchemaValue, type FormanValidationOptions, type FormanValidationResult, toFormanSchema, toJSONSchema, toJSONSchemaAdvanced, validateForman, validateFormanWithDomains };
|
package/dist/index.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ type FormanSchemaField = {
|
|
|
41
41
|
help?: string;
|
|
42
42
|
/** Sub-fields specification for collection or array types */
|
|
43
43
|
spec?: FormanSchemaField[] | FormanSchemaField;
|
|
44
|
+
/** JSON Schema for `json` typed fields */
|
|
45
|
+
schema?: JSONSchema7;
|
|
44
46
|
/** Hide field behind advanced toggle */
|
|
45
47
|
advanced?: boolean;
|
|
46
48
|
/** Human readable label for the field */
|
|
@@ -246,6 +248,19 @@ type FormanJsonSchemaResult = {
|
|
|
246
248
|
advanced?: string[];
|
|
247
249
|
};
|
|
248
250
|
};
|
|
251
|
+
/**
|
|
252
|
+
* Verdict fragment returned by an external validation callback (e.g. `validateJson`) that the
|
|
253
|
+
* library cannot perform itself. Spliced into the overall validation result: `errors`/`warnings`
|
|
254
|
+
* are stamped with the field's domain and path.
|
|
255
|
+
*/
|
|
256
|
+
type FormanExternalValidationResult = {
|
|
257
|
+
/** Whether the value is valid. A `false` verdict always fails validation, even with no messages. */
|
|
258
|
+
valid: boolean;
|
|
259
|
+
/** Error messages (cause validation to fail) */
|
|
260
|
+
errors?: string[];
|
|
261
|
+
/** Warning messages (do not affect validity) */
|
|
262
|
+
warnings?: string[];
|
|
263
|
+
};
|
|
249
264
|
type FormanValidationOptions = {
|
|
250
265
|
/** Unknown fields are not allowed when strict is true */
|
|
251
266
|
strict?: boolean;
|
|
@@ -255,6 +270,10 @@ type FormanValidationOptions = {
|
|
|
255
270
|
schemas?: boolean;
|
|
256
271
|
/** Remote resource resolver */
|
|
257
272
|
resolveRemote?(path: string, data: Record<string, unknown>): Promise<unknown>;
|
|
273
|
+
/** Validator for `json` typed fields. Receives the field's JSON Schema and the value, and
|
|
274
|
+
* returns (or resolves to) a result fragment that is spliced into the overall validation
|
|
275
|
+
* result. When omitted, `json` fields with a `schema` pass without schema validation. */
|
|
276
|
+
validateJson?(schema: JSONSchema7, value: unknown): FormanExternalValidationResult | Promise<FormanExternalValidationResult>;
|
|
258
277
|
/** Maps domain names used in nested.domain to actual domain keys passed to validateFormanWithDomains */
|
|
259
278
|
domainAliases?: Record<string, string>;
|
|
260
279
|
/** Whether to allow dynamic values (IML expressions, unresolved RPC options).
|
|
@@ -334,4 +353,4 @@ declare function validateFormanWithDomains(domains: Record<string, {
|
|
|
334
353
|
*/
|
|
335
354
|
declare function validateForman(values: Record<string, unknown>, schema: FormanSchemaField[], options?: FormanValidationOptions, restoreExtras?: Record<string, Record<string, unknown>>): Promise<FormanValidationResult>;
|
|
336
355
|
|
|
337
|
-
export { type FormanJsonSchemaOptions, type FormanJsonSchemaResult, type FormanSchemaDirectoryOption, type FormanSchemaExtendedNested, type FormanSchemaExtendedOptions, type FormanSchemaField, type FormanSchemaFieldType, type FormanSchemaNested, type FormanSchemaOption, type FormanSchemaOptionGroup, type FormanSchemaPathExtendedOptions, type FormanSchemaRPCButton, type FormanSchemaValue, type FormanValidationOptions, type FormanValidationResult, toFormanSchema, toJSONSchema, toJSONSchemaAdvanced, validateForman, validateFormanWithDomains };
|
|
356
|
+
export { type FormanExternalValidationResult, type FormanJsonSchemaOptions, type FormanJsonSchemaResult, type FormanSchemaDirectoryOption, type FormanSchemaExtendedNested, type FormanSchemaExtendedOptions, type FormanSchemaField, type FormanSchemaFieldType, type FormanSchemaNested, type FormanSchemaOption, type FormanSchemaOptionGroup, type FormanSchemaPathExtendedOptions, type FormanSchemaRPCButton, type FormanSchemaValue, type FormanValidationOptions, type FormanValidationResult, toFormanSchema, toJSONSchema, toJSONSchemaAdvanced, validateForman, validateFormanWithDomains };
|
package/dist/index.js
CHANGED
|
@@ -531,7 +531,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
531
531
|
boolean: "boolean",
|
|
532
532
|
checkbox: "boolean",
|
|
533
533
|
date: "string",
|
|
534
|
-
json: "
|
|
534
|
+
json: "object",
|
|
535
535
|
buffer: "string",
|
|
536
536
|
cert: "string",
|
|
537
537
|
color: "string",
|
|
@@ -641,6 +641,8 @@ function toJSONSchemaInternal(field, context) {
|
|
|
641
641
|
case "collection":
|
|
642
642
|
case "dynamicCollection":
|
|
643
643
|
return handleCollectionType(normalizedField, result, context);
|
|
644
|
+
case "json":
|
|
645
|
+
return handleJsonType(normalizedField, result);
|
|
644
646
|
case "array":
|
|
645
647
|
case "filestorage":
|
|
646
648
|
return handleArrayType(normalizedField, result, context);
|
|
@@ -997,6 +999,20 @@ function handleSelectOrPathType(field, result, context) {
|
|
|
997
999
|
if (field.rpc) result = processRpcDirective(field, result, context);
|
|
998
1000
|
return result;
|
|
999
1001
|
}
|
|
1002
|
+
function handleJsonType(field, result) {
|
|
1003
|
+
if (!isObject(field.schema)) {
|
|
1004
|
+
return result;
|
|
1005
|
+
}
|
|
1006
|
+
delete result.type;
|
|
1007
|
+
Object.assign(result, field.schema);
|
|
1008
|
+
Object.defineProperty(result, "x-json", {
|
|
1009
|
+
configurable: true,
|
|
1010
|
+
enumerable: true,
|
|
1011
|
+
writable: true,
|
|
1012
|
+
value: true
|
|
1013
|
+
});
|
|
1014
|
+
return result;
|
|
1015
|
+
}
|
|
1000
1016
|
function handlePrimitiveType(field, result, context) {
|
|
1001
1017
|
if (field.default !== "" && field.default != null) {
|
|
1002
1018
|
result.default = field.default;
|
|
@@ -1116,7 +1132,8 @@ var SCHEMA_STRIP_KEYS = [
|
|
|
1116
1132
|
"tags",
|
|
1117
1133
|
"extension",
|
|
1118
1134
|
"codepage",
|
|
1119
|
-
"logic"
|
|
1135
|
+
"logic",
|
|
1136
|
+
"schema"
|
|
1120
1137
|
];
|
|
1121
1138
|
function clampFieldForSchema(field) {
|
|
1122
1139
|
const clamped = { ...field };
|
|
@@ -1161,7 +1178,7 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
1161
1178
|
boolean: "boolean",
|
|
1162
1179
|
checkbox: "boolean",
|
|
1163
1180
|
date: "string",
|
|
1164
|
-
json:
|
|
1181
|
+
json: void 0,
|
|
1165
1182
|
buffer: "string",
|
|
1166
1183
|
cert: "string",
|
|
1167
1184
|
color: "string",
|
|
@@ -1256,7 +1273,8 @@ async function validateFormanWithDomainsInternal(domains, options) {
|
|
|
1256
1273
|
...data,
|
|
1257
1274
|
...localData
|
|
1258
1275
|
});
|
|
1259
|
-
}
|
|
1276
|
+
},
|
|
1277
|
+
validateJson: options?.validateJson
|
|
1260
1278
|
}
|
|
1261
1279
|
);
|
|
1262
1280
|
errors.push(...result.errors);
|
|
@@ -1388,6 +1406,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
1388
1406
|
return validateFormanValue(value, udtspecExpand({ ...normalizedField }), context);
|
|
1389
1407
|
}
|
|
1390
1408
|
switch (normalizedField.type) {
|
|
1409
|
+
case "json":
|
|
1410
|
+
return handleJsonType2(value, normalizedField, context);
|
|
1391
1411
|
case "collection":
|
|
1392
1412
|
return handleCollectionType2(value, normalizedField, context);
|
|
1393
1413
|
case "array":
|
|
@@ -1988,6 +2008,35 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
1988
2008
|
warnings
|
|
1989
2009
|
};
|
|
1990
2010
|
}
|
|
2011
|
+
async function handleJsonType2(value, field, context) {
|
|
2012
|
+
const errors = [];
|
|
2013
|
+
const warnings = [];
|
|
2014
|
+
if (!isObject(field.schema) || !context.validateJson) {
|
|
2015
|
+
return { valid: true, errors, warnings };
|
|
2016
|
+
}
|
|
2017
|
+
const path = context.path.join(".");
|
|
2018
|
+
let fragment;
|
|
2019
|
+
try {
|
|
2020
|
+
fragment = await context.validateJson(field.schema, value);
|
|
2021
|
+
} catch (err) {
|
|
2022
|
+
const message = err instanceof Error ? err.message : "JSON schema validation failed unexpectedly.";
|
|
2023
|
+
return { valid: false, errors: [{ domain: context.domain, path, message }], warnings };
|
|
2024
|
+
}
|
|
2025
|
+
for (const message of fragment.errors ?? []) {
|
|
2026
|
+
errors.push({ domain: context.domain, path, message });
|
|
2027
|
+
}
|
|
2028
|
+
for (const message of fragment.warnings ?? []) {
|
|
2029
|
+
warnings.push({ domain: context.domain, path, message });
|
|
2030
|
+
}
|
|
2031
|
+
if (fragment.valid === false && errors.length === 0) {
|
|
2032
|
+
errors.push({ domain: context.domain, path, message: "JSON value failed schema validation." });
|
|
2033
|
+
}
|
|
2034
|
+
return {
|
|
2035
|
+
valid: errors.length === 0,
|
|
2036
|
+
errors,
|
|
2037
|
+
warnings
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
1991
2040
|
async function handlePrimitiveType2(value, field, context) {
|
|
1992
2041
|
const errors = [];
|
|
1993
2042
|
const warnings = [];
|
|
@@ -2068,6 +2117,11 @@ function toFormanSchema(field) {
|
|
|
2068
2117
|
return result;
|
|
2069
2118
|
}
|
|
2070
2119
|
function toFormanSchemaInternal(field) {
|
|
2120
|
+
if (Object.getOwnPropertyDescriptor(field, "x-json")?.value === true) {
|
|
2121
|
+
const schema = { ...field };
|
|
2122
|
+
delete schema["x-json"];
|
|
2123
|
+
return { type: "json", schema };
|
|
2124
|
+
}
|
|
2071
2125
|
const compositeType = Object.getOwnPropertyDescriptor(field, "x-composite")?.value;
|
|
2072
2126
|
if (compositeType === "udttype") return udttypeCollapse(field);
|
|
2073
2127
|
if (compositeType === "udtspec") return udtspecCollapse(field);
|