@makehq/forman-schema 1.3.4 → 1.4.1
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 +67 -18
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +67 -18
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -42,6 +42,10 @@ function containsIMLExpression(value) {
|
|
|
42
42
|
if (typeof value !== "string") return false;
|
|
43
43
|
return value.indexOf("{{") > -1 && value.indexOf("}}") > -1;
|
|
44
44
|
}
|
|
45
|
+
function isPrimitiveIMLExpression(value) {
|
|
46
|
+
if (typeof value !== "string") return false;
|
|
47
|
+
return value.lastIndexOf("{{") === 0 && value.indexOf("}}") === value.length - 2;
|
|
48
|
+
}
|
|
45
49
|
var API_ENDPOINTS = {
|
|
46
50
|
account: "api://connections/{{kind}}",
|
|
47
51
|
aiagent: "api://ai-agents/v1/agents",
|
|
@@ -247,6 +251,7 @@ function handleArrayType(field, result, context) {
|
|
|
247
251
|
function handleSelectType(field, result, context) {
|
|
248
252
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
249
253
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
254
|
+
const nestedContainsStrings = Array.isArray(nested) && nested.some((item) => typeof item === "string");
|
|
250
255
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
251
256
|
if (typeof optionsOrGroups === "string") {
|
|
252
257
|
Object.defineProperty(result, "x-fetch", {
|
|
@@ -268,12 +273,33 @@ function handleSelectType(field, result, context) {
|
|
|
268
273
|
})) {
|
|
269
274
|
result.oneOf = (options || []).map((option) => {
|
|
270
275
|
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
276
|
+
const localNestedContainsStrings = Array.isArray(localNested) && localNested.some((item) => typeof item === "string");
|
|
271
277
|
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
272
278
|
if (localNested) {
|
|
273
279
|
context.addConditionalFields(
|
|
274
280
|
field.name,
|
|
275
281
|
option.value,
|
|
276
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) :
|
|
282
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : localNestedContainsStrings ? {
|
|
283
|
+
type: "object",
|
|
284
|
+
allOf: localNested.map(
|
|
285
|
+
(item) => typeof item === "string" ? {
|
|
286
|
+
$ref: appendQueryString(item, localDomain, [
|
|
287
|
+
...context.tail,
|
|
288
|
+
field.name
|
|
289
|
+
])
|
|
290
|
+
} : toJSONSchemaInternal(
|
|
291
|
+
{
|
|
292
|
+
type: "collection",
|
|
293
|
+
spec: [item]
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
...context,
|
|
297
|
+
domain: localDomain,
|
|
298
|
+
tail: [...context.tail, field.name]
|
|
299
|
+
}
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
} : toJSONSchemaInternal(
|
|
277
303
|
{ type: "collection", spec: localNested },
|
|
278
304
|
{
|
|
279
305
|
...context,
|
|
@@ -293,7 +319,7 @@ function handleSelectType(field, result, context) {
|
|
|
293
319
|
}
|
|
294
320
|
}
|
|
295
321
|
if (nested && domain && domain !== context.domain) {
|
|
296
|
-
if (typeof nested === "string") {
|
|
322
|
+
if (typeof nested === "string" || nestedContainsStrings) {
|
|
297
323
|
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
298
324
|
}
|
|
299
325
|
let root = context.roots[domain];
|
|
@@ -312,7 +338,19 @@ function handleSelectType(field, result, context) {
|
|
|
312
338
|
configurable: true,
|
|
313
339
|
enumerable: true,
|
|
314
340
|
writable: true,
|
|
315
|
-
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } :
|
|
341
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : nestedContainsStrings ? {
|
|
342
|
+
type: "object",
|
|
343
|
+
allOf: nested.map(
|
|
344
|
+
(item) => typeof item === "string" ? { $ref: appendQueryString(item, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
345
|
+
{ type: "collection", spec: [item] },
|
|
346
|
+
{
|
|
347
|
+
...context,
|
|
348
|
+
domain: domain || context.domain,
|
|
349
|
+
tail: [...context.tail, field.name]
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
} : toJSONSchemaInternal(
|
|
316
354
|
{ type: "collection", spec: nested },
|
|
317
355
|
{
|
|
318
356
|
...context,
|
|
@@ -478,7 +516,7 @@ async function validateFormanValue(value, field, context) {
|
|
|
478
516
|
const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
|
|
479
517
|
let actualType = typeof value;
|
|
480
518
|
if (actualType === "object" && Array.isArray(value)) actualType = "array";
|
|
481
|
-
if (expectedType && expectedType !== actualType) {
|
|
519
|
+
if (expectedType && expectedType !== actualType && !isPrimitiveIMLExpression(value)) {
|
|
482
520
|
return {
|
|
483
521
|
valid: false,
|
|
484
522
|
errors: [
|
|
@@ -729,21 +767,32 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
729
767
|
tail: field.name ? [...context.tail, { name: field.name, value }] : context.tail
|
|
730
768
|
};
|
|
731
769
|
if (typeof store === "string") {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
770
|
+
store = [store];
|
|
771
|
+
}
|
|
772
|
+
if (Array.isArray(store) && store.some((item) => typeof item === "string")) {
|
|
773
|
+
const resolvedStore = [];
|
|
774
|
+
for (const item of store) {
|
|
775
|
+
if (typeof item === "string") {
|
|
776
|
+
try {
|
|
777
|
+
resolvedStore.push(...await context.resolveRemote(item, context));
|
|
778
|
+
} catch (error) {
|
|
779
|
+
return {
|
|
780
|
+
valid: false,
|
|
781
|
+
errors: [
|
|
782
|
+
...errors,
|
|
783
|
+
{
|
|
784
|
+
domain: context.domain,
|
|
785
|
+
path: context.path.join("."),
|
|
786
|
+
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
787
|
+
}
|
|
788
|
+
]
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
} else {
|
|
792
|
+
resolvedStore.push(item);
|
|
793
|
+
}
|
|
746
794
|
}
|
|
795
|
+
store = resolvedStore;
|
|
747
796
|
}
|
|
748
797
|
if (store && domain && domain !== context.domain) {
|
|
749
798
|
if (!context.roots[domain]) {
|
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
|
@@ -13,6 +13,10 @@ function containsIMLExpression(value) {
|
|
|
13
13
|
if (typeof value !== "string") return false;
|
|
14
14
|
return value.indexOf("{{") > -1 && value.indexOf("}}") > -1;
|
|
15
15
|
}
|
|
16
|
+
function isPrimitiveIMLExpression(value) {
|
|
17
|
+
if (typeof value !== "string") return false;
|
|
18
|
+
return value.lastIndexOf("{{") === 0 && value.indexOf("}}") === value.length - 2;
|
|
19
|
+
}
|
|
16
20
|
var API_ENDPOINTS = {
|
|
17
21
|
account: "api://connections/{{kind}}",
|
|
18
22
|
aiagent: "api://ai-agents/v1/agents",
|
|
@@ -218,6 +222,7 @@ function handleArrayType(field, result, context) {
|
|
|
218
222
|
function handleSelectType(field, result, context) {
|
|
219
223
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
220
224
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
225
|
+
const nestedContainsStrings = Array.isArray(nested) && nested.some((item) => typeof item === "string");
|
|
221
226
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
222
227
|
if (typeof optionsOrGroups === "string") {
|
|
223
228
|
Object.defineProperty(result, "x-fetch", {
|
|
@@ -239,12 +244,33 @@ function handleSelectType(field, result, context) {
|
|
|
239
244
|
})) {
|
|
240
245
|
result.oneOf = (options || []).map((option) => {
|
|
241
246
|
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
247
|
+
const localNestedContainsStrings = Array.isArray(localNested) && localNested.some((item) => typeof item === "string");
|
|
242
248
|
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
243
249
|
if (localNested) {
|
|
244
250
|
context.addConditionalFields(
|
|
245
251
|
field.name,
|
|
246
252
|
option.value,
|
|
247
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) :
|
|
253
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : localNestedContainsStrings ? {
|
|
254
|
+
type: "object",
|
|
255
|
+
allOf: localNested.map(
|
|
256
|
+
(item) => typeof item === "string" ? {
|
|
257
|
+
$ref: appendQueryString(item, localDomain, [
|
|
258
|
+
...context.tail,
|
|
259
|
+
field.name
|
|
260
|
+
])
|
|
261
|
+
} : toJSONSchemaInternal(
|
|
262
|
+
{
|
|
263
|
+
type: "collection",
|
|
264
|
+
spec: [item]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
...context,
|
|
268
|
+
domain: localDomain,
|
|
269
|
+
tail: [...context.tail, field.name]
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
} : toJSONSchemaInternal(
|
|
248
274
|
{ type: "collection", spec: localNested },
|
|
249
275
|
{
|
|
250
276
|
...context,
|
|
@@ -264,7 +290,7 @@ function handleSelectType(field, result, context) {
|
|
|
264
290
|
}
|
|
265
291
|
}
|
|
266
292
|
if (nested && domain && domain !== context.domain) {
|
|
267
|
-
if (typeof nested === "string") {
|
|
293
|
+
if (typeof nested === "string" || nestedContainsStrings) {
|
|
268
294
|
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
269
295
|
}
|
|
270
296
|
let root = context.roots[domain];
|
|
@@ -283,7 +309,19 @@ function handleSelectType(field, result, context) {
|
|
|
283
309
|
configurable: true,
|
|
284
310
|
enumerable: true,
|
|
285
311
|
writable: true,
|
|
286
|
-
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } :
|
|
312
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : nestedContainsStrings ? {
|
|
313
|
+
type: "object",
|
|
314
|
+
allOf: nested.map(
|
|
315
|
+
(item) => typeof item === "string" ? { $ref: appendQueryString(item, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
316
|
+
{ type: "collection", spec: [item] },
|
|
317
|
+
{
|
|
318
|
+
...context,
|
|
319
|
+
domain: domain || context.domain,
|
|
320
|
+
tail: [...context.tail, field.name]
|
|
321
|
+
}
|
|
322
|
+
)
|
|
323
|
+
)
|
|
324
|
+
} : toJSONSchemaInternal(
|
|
287
325
|
{ type: "collection", spec: nested },
|
|
288
326
|
{
|
|
289
327
|
...context,
|
|
@@ -449,7 +487,7 @@ async function validateFormanValue(value, field, context) {
|
|
|
449
487
|
const expectedType = FORMAN_TYPE_MAP2[normalizedField.type];
|
|
450
488
|
let actualType = typeof value;
|
|
451
489
|
if (actualType === "object" && Array.isArray(value)) actualType = "array";
|
|
452
|
-
if (expectedType && expectedType !== actualType) {
|
|
490
|
+
if (expectedType && expectedType !== actualType && !isPrimitiveIMLExpression(value)) {
|
|
453
491
|
return {
|
|
454
492
|
valid: false,
|
|
455
493
|
errors: [
|
|
@@ -700,21 +738,32 @@ async function handleNestedFields(nested, value, field, context) {
|
|
|
700
738
|
tail: field.name ? [...context.tail, { name: field.name, value }] : context.tail
|
|
701
739
|
};
|
|
702
740
|
if (typeof store === "string") {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
741
|
+
store = [store];
|
|
742
|
+
}
|
|
743
|
+
if (Array.isArray(store) && store.some((item) => typeof item === "string")) {
|
|
744
|
+
const resolvedStore = [];
|
|
745
|
+
for (const item of store) {
|
|
746
|
+
if (typeof item === "string") {
|
|
747
|
+
try {
|
|
748
|
+
resolvedStore.push(...await context.resolveRemote(item, context));
|
|
749
|
+
} catch (error) {
|
|
750
|
+
return {
|
|
751
|
+
valid: false,
|
|
752
|
+
errors: [
|
|
753
|
+
...errors,
|
|
754
|
+
{
|
|
755
|
+
domain: context.domain,
|
|
756
|
+
path: context.path.join("."),
|
|
757
|
+
message: `Failed to resolve remote resource ${item}: ${error}`
|
|
758
|
+
}
|
|
759
|
+
]
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
resolvedStore.push(item);
|
|
764
|
+
}
|
|
717
765
|
}
|
|
766
|
+
store = resolvedStore;
|
|
718
767
|
}
|
|
719
768
|
if (store && domain && domain !== context.domain) {
|
|
720
769
|
if (!context.roots[domain]) {
|