@makehq/forman-schema 1.3.3 → 1.4.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 +73 -19
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +73 -19
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -90,6 +90,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
90
90
|
udt: "number",
|
|
91
91
|
array: "array",
|
|
92
92
|
collection: "object",
|
|
93
|
+
dynamicCollection: "object",
|
|
93
94
|
text: "string",
|
|
94
95
|
number: "number",
|
|
95
96
|
boolean: "boolean",
|
|
@@ -154,6 +155,7 @@ function toJSONSchemaInternal(field, context = createDefaultContext()) {
|
|
|
154
155
|
};
|
|
155
156
|
switch (normalizedField.type) {
|
|
156
157
|
case "collection":
|
|
158
|
+
case "dynamicCollection":
|
|
157
159
|
return handleCollectionType(normalizedField, result, context);
|
|
158
160
|
case "array":
|
|
159
161
|
return handleArrayType(normalizedField, result, context);
|
|
@@ -245,6 +247,7 @@ function handleArrayType(field, result, context) {
|
|
|
245
247
|
function handleSelectType(field, result, context) {
|
|
246
248
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
247
249
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
250
|
+
const nestedContainsStrings = Array.isArray(nested) && nested.some((item) => typeof item === "string");
|
|
248
251
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
249
252
|
if (typeof optionsOrGroups === "string") {
|
|
250
253
|
Object.defineProperty(result, "x-fetch", {
|
|
@@ -266,12 +269,33 @@ function handleSelectType(field, result, context) {
|
|
|
266
269
|
})) {
|
|
267
270
|
result.oneOf = (options || []).map((option) => {
|
|
268
271
|
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
272
|
+
const localNestedContainsStrings = Array.isArray(localNested) && localNested.some((item) => typeof item === "string");
|
|
269
273
|
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
270
274
|
if (localNested) {
|
|
271
275
|
context.addConditionalFields(
|
|
272
276
|
field.name,
|
|
273
277
|
option.value,
|
|
274
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) :
|
|
278
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : localNestedContainsStrings ? {
|
|
279
|
+
type: "object",
|
|
280
|
+
allOf: localNested.map(
|
|
281
|
+
(item) => typeof item === "string" ? {
|
|
282
|
+
$ref: appendQueryString(item, localDomain, [
|
|
283
|
+
...context.tail,
|
|
284
|
+
field.name
|
|
285
|
+
])
|
|
286
|
+
} : toJSONSchemaInternal(
|
|
287
|
+
{
|
|
288
|
+
type: "collection",
|
|
289
|
+
spec: [item]
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
...context,
|
|
293
|
+
domain: localDomain,
|
|
294
|
+
tail: [...context.tail, field.name]
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
)
|
|
298
|
+
} : toJSONSchemaInternal(
|
|
275
299
|
{ type: "collection", spec: localNested },
|
|
276
300
|
{
|
|
277
301
|
...context,
|
|
@@ -291,7 +315,7 @@ function handleSelectType(field, result, context) {
|
|
|
291
315
|
}
|
|
292
316
|
}
|
|
293
317
|
if (nested && domain && domain !== context.domain) {
|
|
294
|
-
if (typeof nested === "string") {
|
|
318
|
+
if (typeof nested === "string" || nestedContainsStrings) {
|
|
295
319
|
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
296
320
|
}
|
|
297
321
|
let root = context.roots[domain];
|
|
@@ -310,7 +334,19 @@ function handleSelectType(field, result, context) {
|
|
|
310
334
|
configurable: true,
|
|
311
335
|
enumerable: true,
|
|
312
336
|
writable: true,
|
|
313
|
-
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } :
|
|
337
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : nestedContainsStrings ? {
|
|
338
|
+
type: "object",
|
|
339
|
+
allOf: nested.map(
|
|
340
|
+
(item) => typeof item === "string" ? { $ref: appendQueryString(item, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
341
|
+
{ type: "collection", spec: [item] },
|
|
342
|
+
{
|
|
343
|
+
...context,
|
|
344
|
+
domain: domain || context.domain,
|
|
345
|
+
tail: [...context.tail, field.name]
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
)
|
|
349
|
+
} : toJSONSchemaInternal(
|
|
314
350
|
{ type: "collection", spec: nested },
|
|
315
351
|
{
|
|
316
352
|
...context,
|
|
@@ -727,21 +763,32 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
727
763
|
tail: field.name ? [...context.tail, { name: field.name, value }] : context.tail
|
|
728
764
|
};
|
|
729
765
|
if (typeof store === "string") {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
766
|
+
store = [store];
|
|
767
|
+
}
|
|
768
|
+
if (Array.isArray(store) && store.some((item) => typeof item === "string")) {
|
|
769
|
+
const resolvedStore = [];
|
|
770
|
+
for (const item of store) {
|
|
771
|
+
if (typeof item === "string") {
|
|
772
|
+
try {
|
|
773
|
+
resolvedStore.push(...await context.resolveRemote(item, context));
|
|
774
|
+
} catch (error) {
|
|
775
|
+
return {
|
|
776
|
+
valid: false,
|
|
777
|
+
errors: [
|
|
778
|
+
...errors,
|
|
779
|
+
{
|
|
780
|
+
domain: context.domain,
|
|
781
|
+
path: context.path.join("."),
|
|
782
|
+
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
783
|
+
}
|
|
784
|
+
]
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
resolvedStore.push(item);
|
|
789
|
+
}
|
|
744
790
|
}
|
|
791
|
+
store = resolvedStore;
|
|
745
792
|
}
|
|
746
793
|
if (store && domain && domain !== context.domain) {
|
|
747
794
|
if (!context.roots[domain]) {
|
|
@@ -845,12 +892,19 @@ var JSON_PRIMITIVE_TYPE_MAP = {
|
|
|
845
892
|
function toFormanSchema(field) {
|
|
846
893
|
switch (field.type) {
|
|
847
894
|
case "object":
|
|
848
|
-
|
|
895
|
+
if (!field.properties || !Object.entries(field.properties).length) {
|
|
896
|
+
return {
|
|
897
|
+
type: "dynamicCollection",
|
|
898
|
+
label: noEmpty(field.title),
|
|
899
|
+
help: noEmpty(field.description)
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
const spec = Object.entries(field.properties).filter(([name, property]) => !!property).map(([name, property]) => {
|
|
849
903
|
const subField = toFormanSchema(property);
|
|
850
904
|
subField.name = name;
|
|
851
905
|
subField.required = field.required?.includes(name) || false;
|
|
852
906
|
return subField;
|
|
853
|
-
})
|
|
907
|
+
});
|
|
854
908
|
return {
|
|
855
909
|
type: "collection",
|
|
856
910
|
label: noEmpty(field.title),
|
package/dist/index.d.cts
CHANGED
|
@@ -138,7 +138,7 @@ type FormanSchemaExtendedOptions = {
|
|
|
138
138
|
/**
|
|
139
139
|
* Nested fields
|
|
140
140
|
*/
|
|
141
|
-
type FormanSchemaNested = FormanSchemaField[] | string | FormanSchemaExtendedNested;
|
|
141
|
+
type FormanSchemaNested = (FormanSchemaField | string)[] | string | FormanSchemaExtendedNested;
|
|
142
142
|
/**
|
|
143
143
|
* Extended nested fields
|
|
144
144
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -138,7 +138,7 @@ type FormanSchemaExtendedOptions = {
|
|
|
138
138
|
/**
|
|
139
139
|
* Nested fields
|
|
140
140
|
*/
|
|
141
|
-
type FormanSchemaNested = FormanSchemaField[] | string | FormanSchemaExtendedNested;
|
|
141
|
+
type FormanSchemaNested = (FormanSchemaField | string)[] | string | FormanSchemaExtendedNested;
|
|
142
142
|
/**
|
|
143
143
|
* Extended nested fields
|
|
144
144
|
*/
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
61
61
|
udt: "number",
|
|
62
62
|
array: "array",
|
|
63
63
|
collection: "object",
|
|
64
|
+
dynamicCollection: "object",
|
|
64
65
|
text: "string",
|
|
65
66
|
number: "number",
|
|
66
67
|
boolean: "boolean",
|
|
@@ -125,6 +126,7 @@ function toJSONSchemaInternal(field, context = createDefaultContext()) {
|
|
|
125
126
|
};
|
|
126
127
|
switch (normalizedField.type) {
|
|
127
128
|
case "collection":
|
|
129
|
+
case "dynamicCollection":
|
|
128
130
|
return handleCollectionType(normalizedField, result, context);
|
|
129
131
|
case "array":
|
|
130
132
|
return handleArrayType(normalizedField, result, context);
|
|
@@ -216,6 +218,7 @@ function handleArrayType(field, result, context) {
|
|
|
216
218
|
function handleSelectType(field, result, context) {
|
|
217
219
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
218
220
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
221
|
+
const nestedContainsStrings = Array.isArray(nested) && nested.some((item) => typeof item === "string");
|
|
219
222
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
220
223
|
if (typeof optionsOrGroups === "string") {
|
|
221
224
|
Object.defineProperty(result, "x-fetch", {
|
|
@@ -237,12 +240,33 @@ function handleSelectType(field, result, context) {
|
|
|
237
240
|
})) {
|
|
238
241
|
result.oneOf = (options || []).map((option) => {
|
|
239
242
|
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
243
|
+
const localNestedContainsStrings = Array.isArray(localNested) && localNested.some((item) => typeof item === "string");
|
|
240
244
|
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
241
245
|
if (localNested) {
|
|
242
246
|
context.addConditionalFields(
|
|
243
247
|
field.name,
|
|
244
248
|
option.value,
|
|
245
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) :
|
|
249
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : localNestedContainsStrings ? {
|
|
250
|
+
type: "object",
|
|
251
|
+
allOf: localNested.map(
|
|
252
|
+
(item) => typeof item === "string" ? {
|
|
253
|
+
$ref: appendQueryString(item, localDomain, [
|
|
254
|
+
...context.tail,
|
|
255
|
+
field.name
|
|
256
|
+
])
|
|
257
|
+
} : toJSONSchemaInternal(
|
|
258
|
+
{
|
|
259
|
+
type: "collection",
|
|
260
|
+
spec: [item]
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
...context,
|
|
264
|
+
domain: localDomain,
|
|
265
|
+
tail: [...context.tail, field.name]
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
)
|
|
269
|
+
} : toJSONSchemaInternal(
|
|
246
270
|
{ type: "collection", spec: localNested },
|
|
247
271
|
{
|
|
248
272
|
...context,
|
|
@@ -262,7 +286,7 @@ function handleSelectType(field, result, context) {
|
|
|
262
286
|
}
|
|
263
287
|
}
|
|
264
288
|
if (nested && domain && domain !== context.domain) {
|
|
265
|
-
if (typeof nested === "string") {
|
|
289
|
+
if (typeof nested === "string" || nestedContainsStrings) {
|
|
266
290
|
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
267
291
|
}
|
|
268
292
|
let root = context.roots[domain];
|
|
@@ -281,7 +305,19 @@ function handleSelectType(field, result, context) {
|
|
|
281
305
|
configurable: true,
|
|
282
306
|
enumerable: true,
|
|
283
307
|
writable: true,
|
|
284
|
-
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } :
|
|
308
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : nestedContainsStrings ? {
|
|
309
|
+
type: "object",
|
|
310
|
+
allOf: nested.map(
|
|
311
|
+
(item) => typeof item === "string" ? { $ref: appendQueryString(item, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
312
|
+
{ type: "collection", spec: [item] },
|
|
313
|
+
{
|
|
314
|
+
...context,
|
|
315
|
+
domain: domain || context.domain,
|
|
316
|
+
tail: [...context.tail, field.name]
|
|
317
|
+
}
|
|
318
|
+
)
|
|
319
|
+
)
|
|
320
|
+
} : toJSONSchemaInternal(
|
|
285
321
|
{ type: "collection", spec: nested },
|
|
286
322
|
{
|
|
287
323
|
...context,
|
|
@@ -698,21 +734,32 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
698
734
|
tail: field.name ? [...context.tail, { name: field.name, value }] : context.tail
|
|
699
735
|
};
|
|
700
736
|
if (typeof store === "string") {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
737
|
+
store = [store];
|
|
738
|
+
}
|
|
739
|
+
if (Array.isArray(store) && store.some((item) => typeof item === "string")) {
|
|
740
|
+
const resolvedStore = [];
|
|
741
|
+
for (const item of store) {
|
|
742
|
+
if (typeof item === "string") {
|
|
743
|
+
try {
|
|
744
|
+
resolvedStore.push(...await context.resolveRemote(item, context));
|
|
745
|
+
} catch (error) {
|
|
746
|
+
return {
|
|
747
|
+
valid: false,
|
|
748
|
+
errors: [
|
|
749
|
+
...errors,
|
|
750
|
+
{
|
|
751
|
+
domain: context.domain,
|
|
752
|
+
path: context.path.join("."),
|
|
753
|
+
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
754
|
+
}
|
|
755
|
+
]
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
resolvedStore.push(item);
|
|
760
|
+
}
|
|
715
761
|
}
|
|
762
|
+
store = resolvedStore;
|
|
716
763
|
}
|
|
717
764
|
if (store && domain && domain !== context.domain) {
|
|
718
765
|
if (!context.roots[domain]) {
|
|
@@ -816,12 +863,19 @@ var JSON_PRIMITIVE_TYPE_MAP = {
|
|
|
816
863
|
function toFormanSchema(field) {
|
|
817
864
|
switch (field.type) {
|
|
818
865
|
case "object":
|
|
819
|
-
|
|
866
|
+
if (!field.properties || !Object.entries(field.properties).length) {
|
|
867
|
+
return {
|
|
868
|
+
type: "dynamicCollection",
|
|
869
|
+
label: noEmpty(field.title),
|
|
870
|
+
help: noEmpty(field.description)
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
const spec = Object.entries(field.properties).filter(([name, property]) => !!property).map(([name, property]) => {
|
|
820
874
|
const subField = toFormanSchema(property);
|
|
821
875
|
subField.name = name;
|
|
822
876
|
subField.required = field.required?.includes(name) || false;
|
|
823
877
|
return subField;
|
|
824
|
-
})
|
|
878
|
+
});
|
|
825
879
|
return {
|
|
826
880
|
type: "collection",
|
|
827
881
|
label: noEmpty(field.title),
|