@makehq/forman-schema 1.13.2 → 1.14.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 +26 -0
- package/dist/index.cjs +58 -23
- package/dist/index.d.cts +58 -3
- package/dist/index.d.ts +58 -3
- package/dist/index.js +57 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Conversion and validation utilities for Forman Schema.
|
|
4
4
|
|
|
5
|
+
## v1.14.0 — advanced field tracking
|
|
6
|
+
|
|
7
|
+
Non-breaking minor release. New surface for working with `advanced: true` Forman fields:
|
|
8
|
+
|
|
9
|
+
- `toJSONSchema(field, options?)` still returns a bare `JSONSchema7` — fully backward-compatible.
|
|
10
|
+
- Fields marked `advanced: true` are now stamped with `x-advanced: true` on the JSON Schema output, and round-trip through `toFormanSchema` (which restores `advanced: true`).
|
|
11
|
+
- New option `excludeAdvancedFields?: boolean` (default `false`). When `true`, advanced sub-fields of a collection are omitted from the schema.
|
|
12
|
+
- New function `toJSONSchemaAdvanced(field, options?)` returns `{ schema: JSONSchema7, skippedPaths?: { advanced?: string[] } }`. Use it to learn which advanced fields were dropped (e.g. to render a "show advanced" toggle). `toJSONSchema` delegates to it internally and returns just `.schema`.
|
|
13
|
+
|
|
5
14
|
## Installation
|
|
6
15
|
|
|
7
16
|
```bash
|
|
@@ -33,6 +42,23 @@ const formanField = {
|
|
|
33
42
|
const jsonSchema = toJSONSchema(formanField);
|
|
34
43
|
```
|
|
35
44
|
|
|
45
|
+
Advanced fields (`advanced: true`) are included by default and stamped with `x-advanced: true`. To omit them from the rendered schema, pass `{ excludeAdvancedFields: true }`:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const jsonSchema = toJSONSchema(formanField, { excludeAdvancedFields: true });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If you also need to know **which** advanced fields were dropped (e.g. to render a "show advanced" toggle), use `toJSONSchemaAdvanced`:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { toJSONSchemaAdvanced } from '@makehq/forman-schema';
|
|
55
|
+
|
|
56
|
+
const { schema, skippedPaths } = toJSONSchemaAdvanced(formanField, { excludeAdvancedFields: true });
|
|
57
|
+
// skippedPaths?.advanced is an array of dot-notation paths like ['wrapper.field', 'wrapper.arr[].nested']
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The filter applies to **sub-fields of a collection** — including nested-by-option fields, array-of-collection items, composite expansions (`udtspec`, `udttype`), and cross-domain buffered fields. It does **not** apply to: the top-level field passed in (always converted), or the item type of an array whose `spec` is a single primitive field. To hide an entire array or any other top-level structure, mark the _parent_ field as `advanced: true`.
|
|
61
|
+
|
|
36
62
|
### Converting from JSON Schema to Forman Schema
|
|
37
63
|
|
|
38
64
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
toFormanSchema: () => toFormanSchema,
|
|
24
24
|
toJSONSchema: () => toJSONSchema,
|
|
25
|
+
toJSONSchemaAdvanced: () => toJSONSchemaAdvanced,
|
|
25
26
|
validateForman: () => validateForman,
|
|
26
27
|
validateFormanWithDomains: () => validateFormanWithDomains
|
|
27
28
|
});
|
|
@@ -607,13 +608,15 @@ function appendQueryString(path, domain, tail) {
|
|
|
607
608
|
const separator = path.includes("?") ? "&" : "?";
|
|
608
609
|
return `${path}${separator}${queryString}`;
|
|
609
610
|
}
|
|
610
|
-
function createDefaultContext() {
|
|
611
|
+
function createDefaultContext(options) {
|
|
611
612
|
return {
|
|
612
613
|
domain: "default",
|
|
613
614
|
tail: [],
|
|
614
615
|
path: [],
|
|
615
616
|
roots: {},
|
|
616
617
|
definitions: {},
|
|
618
|
+
excludeAdvancedFields: options?.excludeAdvancedFields ?? false,
|
|
619
|
+
skippedPaths: {},
|
|
617
620
|
addConditionalFields: () => {
|
|
618
621
|
throw new SchemaConversionError("Cannot serialize nested fields without parent field.");
|
|
619
622
|
}
|
|
@@ -695,6 +698,7 @@ function handleCollectionType(field, result, context) {
|
|
|
695
698
|
properties: {},
|
|
696
699
|
required: []
|
|
697
700
|
});
|
|
701
|
+
const collectionPath = field.name ? [...context.path, field.name] : context.path;
|
|
698
702
|
function addField(subField, tail) {
|
|
699
703
|
if (typeof subField === "string") {
|
|
700
704
|
const value = { $ref: appendQueryString(subField, context.domain, tail || context.tail) };
|
|
@@ -707,28 +711,41 @@ function handleCollectionType(field, result, context) {
|
|
|
707
711
|
}
|
|
708
712
|
if (!subField.name) return;
|
|
709
713
|
if (result.properties && Object.hasOwn(result.properties, subField.name)) return;
|
|
714
|
+
if (subField.advanced === true && context.excludeAdvancedFields) {
|
|
715
|
+
(context.skippedPaths.advanced ||= []).push([...collectionPath, subField.name].join("."));
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
710
718
|
if (subField.required) {
|
|
711
719
|
result.required.push(subField.name);
|
|
712
720
|
}
|
|
721
|
+
const subSchema = toJSONSchemaInternal(subField, {
|
|
722
|
+
...context,
|
|
723
|
+
domain: field["x-domain-root"] || context.domain,
|
|
724
|
+
tail: tail || context.tail,
|
|
725
|
+
path: collectionPath,
|
|
726
|
+
addConditionalFields: (name, value, nested) => {
|
|
727
|
+
result.allOf ||= [];
|
|
728
|
+
result.allOf.push({
|
|
729
|
+
if: {
|
|
730
|
+
properties: {
|
|
731
|
+
[name]: { const: value }
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
then: typeof nested === "string" ? { $ref: nested } : nested
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
if (subField.advanced) {
|
|
739
|
+
Object.defineProperty(subSchema, "x-advanced", {
|
|
740
|
+
configurable: true,
|
|
741
|
+
enumerable: true,
|
|
742
|
+
writable: true,
|
|
743
|
+
value: true
|
|
744
|
+
});
|
|
745
|
+
}
|
|
713
746
|
Object.defineProperty(result.properties, subField.name, {
|
|
714
747
|
enumerable: true,
|
|
715
|
-
value:
|
|
716
|
-
...context,
|
|
717
|
-
domain: field["x-domain-root"] || context.domain,
|
|
718
|
-
tail: tail || context.tail,
|
|
719
|
-
path: [...context.path, field.name],
|
|
720
|
-
addConditionalFields: (name, value, nested) => {
|
|
721
|
-
result.allOf ||= [];
|
|
722
|
-
result.allOf.push({
|
|
723
|
-
if: {
|
|
724
|
-
properties: {
|
|
725
|
-
[name]: { const: value }
|
|
726
|
-
}
|
|
727
|
-
},
|
|
728
|
-
then: typeof nested === "string" ? { $ref: nested } : nested
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
})
|
|
748
|
+
value: subSchema
|
|
732
749
|
});
|
|
733
750
|
}
|
|
734
751
|
if (field["x-domain-root"]) {
|
|
@@ -2074,6 +2091,13 @@ var JSON_PRIMITIVE_TYPE_MAP = {
|
|
|
2074
2091
|
boolean: "boolean"
|
|
2075
2092
|
};
|
|
2076
2093
|
function toFormanSchema(field) {
|
|
2094
|
+
const result = toFormanSchemaInternal(field);
|
|
2095
|
+
if (Object.getOwnPropertyDescriptor(field, "x-advanced")?.value === true) {
|
|
2096
|
+
result.advanced = true;
|
|
2097
|
+
}
|
|
2098
|
+
return result;
|
|
2099
|
+
}
|
|
2100
|
+
function toFormanSchemaInternal(field) {
|
|
2077
2101
|
const compositeType = Object.getOwnPropertyDescriptor(field, "x-composite")?.value;
|
|
2078
2102
|
if (compositeType === "udttype") return udttypeCollapse(field);
|
|
2079
2103
|
if (compositeType === "udtspec") return udtspecCollapse(field);
|
|
@@ -2209,18 +2233,28 @@ function handleSearchDirective(formanField, directive) {
|
|
|
2209
2233
|
}
|
|
2210
2234
|
|
|
2211
2235
|
// src/index.ts
|
|
2212
|
-
function
|
|
2213
|
-
const context = createDefaultContext();
|
|
2214
|
-
const
|
|
2236
|
+
function toJSONSchemaAdvanced(field, options) {
|
|
2237
|
+
const context = createDefaultContext(options);
|
|
2238
|
+
const schema = toJSONSchemaInternal(field, context);
|
|
2215
2239
|
if (Object.keys(context.definitions ?? {}).length > 0) {
|
|
2216
|
-
Object.defineProperty(
|
|
2240
|
+
Object.defineProperty(schema, "definitions", {
|
|
2217
2241
|
configurable: true,
|
|
2218
2242
|
enumerable: true,
|
|
2219
2243
|
writable: true,
|
|
2220
2244
|
value: context.definitions
|
|
2221
2245
|
});
|
|
2222
2246
|
}
|
|
2223
|
-
|
|
2247
|
+
const skippedPaths = {};
|
|
2248
|
+
if (context.skippedPaths.advanced?.length) {
|
|
2249
|
+
skippedPaths.advanced = context.skippedPaths.advanced;
|
|
2250
|
+
}
|
|
2251
|
+
return {
|
|
2252
|
+
schema,
|
|
2253
|
+
...Object.keys(skippedPaths).length > 0 ? { skippedPaths } : {}
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
function toJSONSchema(field, options) {
|
|
2257
|
+
return toJSONSchemaAdvanced(field, options).schema;
|
|
2224
2258
|
}
|
|
2225
2259
|
function validateFormanWithDomains(domains, options) {
|
|
2226
2260
|
return validateFormanWithDomainsInternal(domains, options);
|
|
@@ -2235,6 +2269,7 @@ function validateForman(values, schema, options, restoreExtras) {
|
|
|
2235
2269
|
0 && (module.exports = {
|
|
2236
2270
|
toFormanSchema,
|
|
2237
2271
|
toJSONSchema,
|
|
2272
|
+
toJSONSchemaAdvanced,
|
|
2238
2273
|
validateForman,
|
|
2239
2274
|
validateFormanWithDomains
|
|
2240
2275
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -222,6 +222,30 @@ type FormanSchemaFieldState = {
|
|
|
222
222
|
nested?: Record<string, FormanSchemaFieldState>;
|
|
223
223
|
items?: Record<string, FormanSchemaFieldState>[];
|
|
224
224
|
};
|
|
225
|
+
/**
|
|
226
|
+
* Options for converting a Forman Schema to JSON Schema
|
|
227
|
+
*/
|
|
228
|
+
type FormanJsonSchemaOptions = {
|
|
229
|
+
/**
|
|
230
|
+
* Exclude fields marked `advanced: true` from the rendered schema. Defaults to `false`
|
|
231
|
+
* (advanced fields are included and stamped with `x-advanced: true`). When `true`,
|
|
232
|
+
* advanced fields are omitted; their dot-notation paths are reported on
|
|
233
|
+
* `toJSONSchemaAdvanced`'s `skippedPaths.advanced` so the caller can re-request them.
|
|
234
|
+
*/
|
|
235
|
+
excludeAdvancedFields?: boolean;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Result of converting a Forman Schema to JSON Schema
|
|
239
|
+
*/
|
|
240
|
+
type FormanJsonSchemaResult = {
|
|
241
|
+
/** The converted JSON Schema */
|
|
242
|
+
schema: JSONSchema7;
|
|
243
|
+
/** Paths to fields that were skipped during conversion. Present only when at least one field was skipped. */
|
|
244
|
+
skippedPaths?: {
|
|
245
|
+
/** Dot-notation paths of advanced fields that were skipped. Present only when at least one advanced field was skipped. */
|
|
246
|
+
advanced?: string[];
|
|
247
|
+
};
|
|
248
|
+
};
|
|
225
249
|
type FormanValidationOptions = {
|
|
226
250
|
/** Unknown fields are not allowed when strict is true */
|
|
227
251
|
strict?: boolean;
|
|
@@ -246,12 +270,43 @@ type FormanValidationOptions = {
|
|
|
246
270
|
*/
|
|
247
271
|
declare function toFormanSchema(field: JSONSchema7): FormanSchemaField;
|
|
248
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Converts a Forman Schema field to its JSON Schema equivalent and reports the paths of any
|
|
275
|
+
* fields that were skipped during conversion.
|
|
276
|
+
*
|
|
277
|
+
* **Advanced fields** (`advanced: true`) are included by default and stamped with
|
|
278
|
+
* `x-advanced: true` on the JSON Schema (the marker round-trips through `toFormanSchema`).
|
|
279
|
+
* Pass `{ excludeAdvancedFields: true }` to omit them — when excluded, the affected
|
|
280
|
+
* dot-notation paths are reported on `skippedPaths.advanced`. The filter applies to sub-fields
|
|
281
|
+
* of a collection (main form, nested-by-option, array-of-collection items, composite
|
|
282
|
+
* expansions, cross-domain buffered fields). It does NOT apply to the top-level field passed
|
|
283
|
+
* here, nor to the item type of an array whose `spec` is a single primitive field. Mark the
|
|
284
|
+
* parent as `advanced: true` to hide such structures.
|
|
285
|
+
*
|
|
286
|
+
* Known limitation: composite types (`udtspec`, `udttype`) are memoized in
|
|
287
|
+
* `definitions[type]`; advanced fields inside a composite template are recorded with the
|
|
288
|
+
* path of the FIRST usage only. See the comment near `compositeHandlers` in `src/forman.ts`.
|
|
289
|
+
*
|
|
290
|
+
* If you don't need `skippedPaths`, use {@link toJSONSchema} which returns just the schema.
|
|
291
|
+
*
|
|
292
|
+
* @param field The Forman Schema field to convert
|
|
293
|
+
* @param options Conversion options
|
|
294
|
+
* @returns The conversion result `{ schema, skippedPaths? }`. `skippedPaths` is omitted when nothing was skipped.
|
|
295
|
+
*/
|
|
296
|
+
declare function toJSONSchemaAdvanced(field: FormanSchemaField, options?: FormanJsonSchemaOptions): FormanJsonSchemaResult;
|
|
249
297
|
/**
|
|
250
298
|
* Converts a Forman Schema field to its JSON Schema equivalent.
|
|
299
|
+
*
|
|
300
|
+
* Advanced fields (`advanced: true`) are included by default and stamped with `x-advanced: true`.
|
|
301
|
+
* Pass `{ excludeAdvancedFields: true }` to omit them. If you need to know *which* advanced
|
|
302
|
+
* fields were dropped (e.g. to render a "show advanced" toggle), use {@link toJSONSchemaAdvanced}
|
|
303
|
+
* which returns `{ schema, skippedPaths? }`.
|
|
304
|
+
*
|
|
251
305
|
* @param field The Forman Schema field to convert
|
|
252
|
-
* @
|
|
306
|
+
* @param options Conversion options
|
|
307
|
+
* @returns The equivalent JSON Schema
|
|
253
308
|
*/
|
|
254
|
-
declare function toJSONSchema(field: FormanSchemaField): JSONSchema7;
|
|
309
|
+
declare function toJSONSchema(field: FormanSchemaField, options?: FormanJsonSchemaOptions): JSONSchema7;
|
|
255
310
|
/**
|
|
256
311
|
* Validates a Forman domains against schemas
|
|
257
312
|
* @param domains The domains to validate
|
|
@@ -279,4 +334,4 @@ declare function validateFormanWithDomains(domains: Record<string, {
|
|
|
279
334
|
*/
|
|
280
335
|
declare function validateForman(values: Record<string, unknown>, schema: FormanSchemaField[], options?: FormanValidationOptions, restoreExtras?: Record<string, Record<string, unknown>>): Promise<FormanValidationResult>;
|
|
281
336
|
|
|
282
|
-
export { 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, validateForman, validateFormanWithDomains };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -222,6 +222,30 @@ type FormanSchemaFieldState = {
|
|
|
222
222
|
nested?: Record<string, FormanSchemaFieldState>;
|
|
223
223
|
items?: Record<string, FormanSchemaFieldState>[];
|
|
224
224
|
};
|
|
225
|
+
/**
|
|
226
|
+
* Options for converting a Forman Schema to JSON Schema
|
|
227
|
+
*/
|
|
228
|
+
type FormanJsonSchemaOptions = {
|
|
229
|
+
/**
|
|
230
|
+
* Exclude fields marked `advanced: true` from the rendered schema. Defaults to `false`
|
|
231
|
+
* (advanced fields are included and stamped with `x-advanced: true`). When `true`,
|
|
232
|
+
* advanced fields are omitted; their dot-notation paths are reported on
|
|
233
|
+
* `toJSONSchemaAdvanced`'s `skippedPaths.advanced` so the caller can re-request them.
|
|
234
|
+
*/
|
|
235
|
+
excludeAdvancedFields?: boolean;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Result of converting a Forman Schema to JSON Schema
|
|
239
|
+
*/
|
|
240
|
+
type FormanJsonSchemaResult = {
|
|
241
|
+
/** The converted JSON Schema */
|
|
242
|
+
schema: JSONSchema7;
|
|
243
|
+
/** Paths to fields that were skipped during conversion. Present only when at least one field was skipped. */
|
|
244
|
+
skippedPaths?: {
|
|
245
|
+
/** Dot-notation paths of advanced fields that were skipped. Present only when at least one advanced field was skipped. */
|
|
246
|
+
advanced?: string[];
|
|
247
|
+
};
|
|
248
|
+
};
|
|
225
249
|
type FormanValidationOptions = {
|
|
226
250
|
/** Unknown fields are not allowed when strict is true */
|
|
227
251
|
strict?: boolean;
|
|
@@ -246,12 +270,43 @@ type FormanValidationOptions = {
|
|
|
246
270
|
*/
|
|
247
271
|
declare function toFormanSchema(field: JSONSchema7): FormanSchemaField;
|
|
248
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Converts a Forman Schema field to its JSON Schema equivalent and reports the paths of any
|
|
275
|
+
* fields that were skipped during conversion.
|
|
276
|
+
*
|
|
277
|
+
* **Advanced fields** (`advanced: true`) are included by default and stamped with
|
|
278
|
+
* `x-advanced: true` on the JSON Schema (the marker round-trips through `toFormanSchema`).
|
|
279
|
+
* Pass `{ excludeAdvancedFields: true }` to omit them — when excluded, the affected
|
|
280
|
+
* dot-notation paths are reported on `skippedPaths.advanced`. The filter applies to sub-fields
|
|
281
|
+
* of a collection (main form, nested-by-option, array-of-collection items, composite
|
|
282
|
+
* expansions, cross-domain buffered fields). It does NOT apply to the top-level field passed
|
|
283
|
+
* here, nor to the item type of an array whose `spec` is a single primitive field. Mark the
|
|
284
|
+
* parent as `advanced: true` to hide such structures.
|
|
285
|
+
*
|
|
286
|
+
* Known limitation: composite types (`udtspec`, `udttype`) are memoized in
|
|
287
|
+
* `definitions[type]`; advanced fields inside a composite template are recorded with the
|
|
288
|
+
* path of the FIRST usage only. See the comment near `compositeHandlers` in `src/forman.ts`.
|
|
289
|
+
*
|
|
290
|
+
* If you don't need `skippedPaths`, use {@link toJSONSchema} which returns just the schema.
|
|
291
|
+
*
|
|
292
|
+
* @param field The Forman Schema field to convert
|
|
293
|
+
* @param options Conversion options
|
|
294
|
+
* @returns The conversion result `{ schema, skippedPaths? }`. `skippedPaths` is omitted when nothing was skipped.
|
|
295
|
+
*/
|
|
296
|
+
declare function toJSONSchemaAdvanced(field: FormanSchemaField, options?: FormanJsonSchemaOptions): FormanJsonSchemaResult;
|
|
249
297
|
/**
|
|
250
298
|
* Converts a Forman Schema field to its JSON Schema equivalent.
|
|
299
|
+
*
|
|
300
|
+
* Advanced fields (`advanced: true`) are included by default and stamped with `x-advanced: true`.
|
|
301
|
+
* Pass `{ excludeAdvancedFields: true }` to omit them. If you need to know *which* advanced
|
|
302
|
+
* fields were dropped (e.g. to render a "show advanced" toggle), use {@link toJSONSchemaAdvanced}
|
|
303
|
+
* which returns `{ schema, skippedPaths? }`.
|
|
304
|
+
*
|
|
251
305
|
* @param field The Forman Schema field to convert
|
|
252
|
-
* @
|
|
306
|
+
* @param options Conversion options
|
|
307
|
+
* @returns The equivalent JSON Schema
|
|
253
308
|
*/
|
|
254
|
-
declare function toJSONSchema(field: FormanSchemaField): JSONSchema7;
|
|
309
|
+
declare function toJSONSchema(field: FormanSchemaField, options?: FormanJsonSchemaOptions): JSONSchema7;
|
|
255
310
|
/**
|
|
256
311
|
* Validates a Forman domains against schemas
|
|
257
312
|
* @param domains The domains to validate
|
|
@@ -279,4 +334,4 @@ declare function validateFormanWithDomains(domains: Record<string, {
|
|
|
279
334
|
*/
|
|
280
335
|
declare function validateForman(values: Record<string, unknown>, schema: FormanSchemaField[], options?: FormanValidationOptions, restoreExtras?: Record<string, Record<string, unknown>>): Promise<FormanValidationResult>;
|
|
281
336
|
|
|
282
|
-
export { 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, validateForman, validateFormanWithDomains };
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -578,13 +578,15 @@ function appendQueryString(path, domain, tail) {
|
|
|
578
578
|
const separator = path.includes("?") ? "&" : "?";
|
|
579
579
|
return `${path}${separator}${queryString}`;
|
|
580
580
|
}
|
|
581
|
-
function createDefaultContext() {
|
|
581
|
+
function createDefaultContext(options) {
|
|
582
582
|
return {
|
|
583
583
|
domain: "default",
|
|
584
584
|
tail: [],
|
|
585
585
|
path: [],
|
|
586
586
|
roots: {},
|
|
587
587
|
definitions: {},
|
|
588
|
+
excludeAdvancedFields: options?.excludeAdvancedFields ?? false,
|
|
589
|
+
skippedPaths: {},
|
|
588
590
|
addConditionalFields: () => {
|
|
589
591
|
throw new SchemaConversionError("Cannot serialize nested fields without parent field.");
|
|
590
592
|
}
|
|
@@ -666,6 +668,7 @@ function handleCollectionType(field, result, context) {
|
|
|
666
668
|
properties: {},
|
|
667
669
|
required: []
|
|
668
670
|
});
|
|
671
|
+
const collectionPath = field.name ? [...context.path, field.name] : context.path;
|
|
669
672
|
function addField(subField, tail) {
|
|
670
673
|
if (typeof subField === "string") {
|
|
671
674
|
const value = { $ref: appendQueryString(subField, context.domain, tail || context.tail) };
|
|
@@ -678,28 +681,41 @@ function handleCollectionType(field, result, context) {
|
|
|
678
681
|
}
|
|
679
682
|
if (!subField.name) return;
|
|
680
683
|
if (result.properties && Object.hasOwn(result.properties, subField.name)) return;
|
|
684
|
+
if (subField.advanced === true && context.excludeAdvancedFields) {
|
|
685
|
+
(context.skippedPaths.advanced ||= []).push([...collectionPath, subField.name].join("."));
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
681
688
|
if (subField.required) {
|
|
682
689
|
result.required.push(subField.name);
|
|
683
690
|
}
|
|
691
|
+
const subSchema = toJSONSchemaInternal(subField, {
|
|
692
|
+
...context,
|
|
693
|
+
domain: field["x-domain-root"] || context.domain,
|
|
694
|
+
tail: tail || context.tail,
|
|
695
|
+
path: collectionPath,
|
|
696
|
+
addConditionalFields: (name, value, nested) => {
|
|
697
|
+
result.allOf ||= [];
|
|
698
|
+
result.allOf.push({
|
|
699
|
+
if: {
|
|
700
|
+
properties: {
|
|
701
|
+
[name]: { const: value }
|
|
702
|
+
}
|
|
703
|
+
},
|
|
704
|
+
then: typeof nested === "string" ? { $ref: nested } : nested
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
if (subField.advanced) {
|
|
709
|
+
Object.defineProperty(subSchema, "x-advanced", {
|
|
710
|
+
configurable: true,
|
|
711
|
+
enumerable: true,
|
|
712
|
+
writable: true,
|
|
713
|
+
value: true
|
|
714
|
+
});
|
|
715
|
+
}
|
|
684
716
|
Object.defineProperty(result.properties, subField.name, {
|
|
685
717
|
enumerable: true,
|
|
686
|
-
value:
|
|
687
|
-
...context,
|
|
688
|
-
domain: field["x-domain-root"] || context.domain,
|
|
689
|
-
tail: tail || context.tail,
|
|
690
|
-
path: [...context.path, field.name],
|
|
691
|
-
addConditionalFields: (name, value, nested) => {
|
|
692
|
-
result.allOf ||= [];
|
|
693
|
-
result.allOf.push({
|
|
694
|
-
if: {
|
|
695
|
-
properties: {
|
|
696
|
-
[name]: { const: value }
|
|
697
|
-
}
|
|
698
|
-
},
|
|
699
|
-
then: typeof nested === "string" ? { $ref: nested } : nested
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
})
|
|
718
|
+
value: subSchema
|
|
703
719
|
});
|
|
704
720
|
}
|
|
705
721
|
if (field["x-domain-root"]) {
|
|
@@ -2045,6 +2061,13 @@ var JSON_PRIMITIVE_TYPE_MAP = {
|
|
|
2045
2061
|
boolean: "boolean"
|
|
2046
2062
|
};
|
|
2047
2063
|
function toFormanSchema(field) {
|
|
2064
|
+
const result = toFormanSchemaInternal(field);
|
|
2065
|
+
if (Object.getOwnPropertyDescriptor(field, "x-advanced")?.value === true) {
|
|
2066
|
+
result.advanced = true;
|
|
2067
|
+
}
|
|
2068
|
+
return result;
|
|
2069
|
+
}
|
|
2070
|
+
function toFormanSchemaInternal(field) {
|
|
2048
2071
|
const compositeType = Object.getOwnPropertyDescriptor(field, "x-composite")?.value;
|
|
2049
2072
|
if (compositeType === "udttype") return udttypeCollapse(field);
|
|
2050
2073
|
if (compositeType === "udtspec") return udtspecCollapse(field);
|
|
@@ -2180,18 +2203,28 @@ function handleSearchDirective(formanField, directive) {
|
|
|
2180
2203
|
}
|
|
2181
2204
|
|
|
2182
2205
|
// src/index.ts
|
|
2183
|
-
function
|
|
2184
|
-
const context = createDefaultContext();
|
|
2185
|
-
const
|
|
2206
|
+
function toJSONSchemaAdvanced(field, options) {
|
|
2207
|
+
const context = createDefaultContext(options);
|
|
2208
|
+
const schema = toJSONSchemaInternal(field, context);
|
|
2186
2209
|
if (Object.keys(context.definitions ?? {}).length > 0) {
|
|
2187
|
-
Object.defineProperty(
|
|
2210
|
+
Object.defineProperty(schema, "definitions", {
|
|
2188
2211
|
configurable: true,
|
|
2189
2212
|
enumerable: true,
|
|
2190
2213
|
writable: true,
|
|
2191
2214
|
value: context.definitions
|
|
2192
2215
|
});
|
|
2193
2216
|
}
|
|
2194
|
-
|
|
2217
|
+
const skippedPaths = {};
|
|
2218
|
+
if (context.skippedPaths.advanced?.length) {
|
|
2219
|
+
skippedPaths.advanced = context.skippedPaths.advanced;
|
|
2220
|
+
}
|
|
2221
|
+
return {
|
|
2222
|
+
schema,
|
|
2223
|
+
...Object.keys(skippedPaths).length > 0 ? { skippedPaths } : {}
|
|
2224
|
+
};
|
|
2225
|
+
}
|
|
2226
|
+
function toJSONSchema(field, options) {
|
|
2227
|
+
return toJSONSchemaAdvanced(field, options).schema;
|
|
2195
2228
|
}
|
|
2196
2229
|
function validateFormanWithDomains(domains, options) {
|
|
2197
2230
|
return validateFormanWithDomainsInternal(domains, options);
|
|
@@ -2205,6 +2238,7 @@ function validateForman(values, schema, options, restoreExtras) {
|
|
|
2205
2238
|
export {
|
|
2206
2239
|
toFormanSchema,
|
|
2207
2240
|
toJSONSchema,
|
|
2241
|
+
toJSONSchemaAdvanced,
|
|
2208
2242
|
validateForman,
|
|
2209
2243
|
validateFormanWithDomains
|
|
2210
2244
|
};
|