@makehq/forman-schema 1.2.1 → 1.2.3
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 +48 -29
- package/dist/index.d.cts +69 -2
- package/dist/index.d.ts +69 -2
- package/dist/index.js +48 -29
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,12 +32,20 @@ function noEmpty(text) {
|
|
|
32
32
|
function isObject(value) {
|
|
33
33
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34
34
|
}
|
|
35
|
+
function isOptionGroup(value) {
|
|
36
|
+
return "options" in value && Array.isArray(value.options);
|
|
37
|
+
}
|
|
35
38
|
|
|
36
39
|
// src/forman.ts
|
|
37
40
|
var SchemaConversionError = class extends Error {
|
|
41
|
+
/** Field that caused the error */
|
|
42
|
+
field;
|
|
43
|
+
/**
|
|
44
|
+
* @param message The error message
|
|
45
|
+
* @param field The field that caused the error
|
|
46
|
+
*/
|
|
38
47
|
constructor(message, field) {
|
|
39
48
|
super(message);
|
|
40
|
-
this.field = field;
|
|
41
49
|
this.name = "SchemaConversionError";
|
|
42
50
|
}
|
|
43
51
|
};
|
|
@@ -236,41 +244,52 @@ function handleArrayType(field, result, context) {
|
|
|
236
244
|
return result;
|
|
237
245
|
}
|
|
238
246
|
function handleSelectType(field, result, context) {
|
|
239
|
-
const
|
|
247
|
+
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
240
248
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
241
249
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
242
|
-
if (typeof
|
|
250
|
+
if (typeof optionsOrGroups === "string") {
|
|
243
251
|
Object.defineProperty(result, "x-fetch", {
|
|
244
252
|
configurable: true,
|
|
245
253
|
enumerable: true,
|
|
246
254
|
writable: true,
|
|
247
|
-
value: appendQueryString(
|
|
248
|
-
});
|
|
249
|
-
} else if (options?.some((option) => option.label || option.nested)) {
|
|
250
|
-
result.oneOf = (options || []).map((option) => {
|
|
251
|
-
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
252
|
-
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
253
|
-
if (localNested) {
|
|
254
|
-
context.addConditionalFields(
|
|
255
|
-
field.name,
|
|
256
|
-
option.value,
|
|
257
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : toJSONSchemaInternal(
|
|
258
|
-
{ type: "collection", spec: localNested },
|
|
259
|
-
{
|
|
260
|
-
...context,
|
|
261
|
-
domain: localDomain,
|
|
262
|
-
tail: [...context.tail, field.name]
|
|
263
|
-
}
|
|
264
|
-
)
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
return {
|
|
268
|
-
title: noEmpty(option.label),
|
|
269
|
-
const: option.value
|
|
270
|
-
};
|
|
255
|
+
value: appendQueryString(optionsOrGroups, context.domain, context.tail)
|
|
271
256
|
});
|
|
272
257
|
} else {
|
|
273
|
-
|
|
258
|
+
const options = optionsOrGroups?.some(isOptionGroup) ? optionsOrGroups.flatMap(
|
|
259
|
+
(group) => group.options.map((option) => ({
|
|
260
|
+
...option,
|
|
261
|
+
label: `${group.label}: ${option.label || option.value}`
|
|
262
|
+
}))
|
|
263
|
+
) : optionsOrGroups || [];
|
|
264
|
+
if (options?.some((option) => {
|
|
265
|
+
if (isOptionGroup(option)) return option.options.some((option2) => option2.label || option2.nested);
|
|
266
|
+
return option.label || option.nested;
|
|
267
|
+
})) {
|
|
268
|
+
result.oneOf = (options || []).map((option) => {
|
|
269
|
+
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
270
|
+
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
271
|
+
if (localNested) {
|
|
272
|
+
context.addConditionalFields(
|
|
273
|
+
field.name,
|
|
274
|
+
option.value,
|
|
275
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : toJSONSchemaInternal(
|
|
276
|
+
{ type: "collection", spec: localNested },
|
|
277
|
+
{
|
|
278
|
+
...context,
|
|
279
|
+
domain: localDomain,
|
|
280
|
+
tail: [...context.tail, field.name]
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
title: noEmpty(option.label),
|
|
287
|
+
const: option.value
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
} else {
|
|
291
|
+
result.enum = (options || []).map((option) => option.value);
|
|
292
|
+
}
|
|
274
293
|
}
|
|
275
294
|
if (nested && domain && domain !== context.domain) {
|
|
276
295
|
if (typeof nested === "string") {
|
|
@@ -292,7 +311,7 @@ function handleSelectType(field, result, context) {
|
|
|
292
311
|
configurable: true,
|
|
293
312
|
enumerable: true,
|
|
294
313
|
writable: true,
|
|
295
|
-
value: typeof nested === "string" ? { $ref: nested } : toJSONSchemaInternal(
|
|
314
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
296
315
|
{ type: "collection", spec: nested },
|
|
297
316
|
{
|
|
298
317
|
...context,
|
package/dist/index.d.cts
CHANGED
|
@@ -34,7 +34,7 @@ type FormanSchemaField = {
|
|
|
34
34
|
/** Default value for the field */
|
|
35
35
|
default?: FormanSchemaValue;
|
|
36
36
|
/** Available options for select type fields */
|
|
37
|
-
options?: FormanSchemaOption[] | FormanSchemaExtendedOptions | string;
|
|
37
|
+
options?: FormanSchemaOption[] | FormanSchemaOptionGroup[] | FormanSchemaExtendedOptions | string;
|
|
38
38
|
/** Help text or description for the field */
|
|
39
39
|
help?: string;
|
|
40
40
|
/** Sub-fields specification for collection or array types */
|
|
@@ -47,25 +47,92 @@ type FormanSchemaField = {
|
|
|
47
47
|
nested?: FormanSchemaNested;
|
|
48
48
|
/** Validation rules */
|
|
49
49
|
validate?: FormanSchemaValidation;
|
|
50
|
+
/** Whether the field is disabled (`false` by default) */
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
/** Whether the field is mappable */
|
|
53
|
+
mappable?: boolean;
|
|
54
|
+
/** Whether the user will be able to insert new lines in GUI (a textarea will be displayed instead of the text field) */
|
|
55
|
+
multiline?: boolean;
|
|
56
|
+
/** Specifies how to treat HTML tags in the field (text only) */
|
|
57
|
+
tags?: 'strip' | 'stripall' | 'escape';
|
|
58
|
+
/** Allowed extension or array of allowed extensions. (filename only) */
|
|
59
|
+
extension?: string | string[];
|
|
60
|
+
/** Semantic type for the field */
|
|
61
|
+
semantic?: string;
|
|
62
|
+
/** Whether to allow time selection (date only, `true` by default) */
|
|
63
|
+
time?: boolean;
|
|
64
|
+
/** Whether the properties of the object will be in the same order as they are defined in the spec (collection only) */
|
|
65
|
+
sequence?: boolean;
|
|
66
|
+
/** Codepage for the field (buffer only) */
|
|
67
|
+
codepage?: string;
|
|
68
|
+
/** Whether the field is grouped (select only) */
|
|
69
|
+
grouped?: boolean;
|
|
70
|
+
/** Whether a mapped value in the select should be validated against the option values. If true, the value is treated as a dynamic and validation is disabled. The value is set to `true` automatically if select options are generated using RPC. */
|
|
71
|
+
dynamic?: boolean;
|
|
72
|
+
/** Mode for the field (select only) */
|
|
73
|
+
mode?: 'edit' | 'choose';
|
|
74
|
+
/** Sort order for the field (select only) */
|
|
75
|
+
sort?: string;
|
|
76
|
+
/** Adds an extra button to the field which opens an extra form. When the form is submitted, a specified RPC is called and the result is set as a new value of the parameter. */
|
|
77
|
+
rpc?: FormanSchemaRPCButton;
|
|
50
78
|
} & Record<`x-${string}`, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* RPC button allows for dynamic value retrieval from an external source
|
|
81
|
+
*/
|
|
82
|
+
type FormanSchemaRPCButton = {
|
|
83
|
+
/** RPC button label */
|
|
84
|
+
label: string;
|
|
85
|
+
/** RPC button URL */
|
|
86
|
+
url: string;
|
|
87
|
+
/** RPC button parameters */
|
|
88
|
+
parameters: FormanSchemaField[];
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Valid Forman Schema values
|
|
92
|
+
*/
|
|
51
93
|
type FormanSchemaValue = string | number | boolean | null;
|
|
94
|
+
/**
|
|
95
|
+
* Option for a select field
|
|
96
|
+
*/
|
|
52
97
|
type FormanSchemaOption = {
|
|
53
98
|
/** Option value */
|
|
54
99
|
value: FormanSchemaValue;
|
|
55
100
|
/** Option label */
|
|
56
101
|
label?: string;
|
|
102
|
+
/** Whether the option is the default */
|
|
103
|
+
default?: boolean;
|
|
57
104
|
/** Nested fields for this option */
|
|
58
105
|
nested?: FormanSchemaNested;
|
|
59
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* Option group for a select field
|
|
109
|
+
*/
|
|
110
|
+
type FormanSchemaOptionGroup = {
|
|
111
|
+
/** Group label */
|
|
112
|
+
label: string;
|
|
113
|
+
/** Group options */
|
|
114
|
+
options: FormanSchemaOption[];
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Extended options for a select field
|
|
118
|
+
*/
|
|
60
119
|
type FormanSchemaExtendedOptions = {
|
|
61
120
|
/** Store for the options */
|
|
62
|
-
store: FormanSchemaOption[] | string;
|
|
121
|
+
store: FormanSchemaOption[] | FormanSchemaOptionGroup[] | string;
|
|
63
122
|
/** Nested fields for every option */
|
|
64
123
|
nested?: FormanSchemaNested;
|
|
65
124
|
};
|
|
125
|
+
/**
|
|
126
|
+
* Nested fields
|
|
127
|
+
*/
|
|
66
128
|
type FormanSchemaNested = FormanSchemaField[] | string | FormanSchemaExtendedNested;
|
|
129
|
+
/**
|
|
130
|
+
* Extended nested fields
|
|
131
|
+
*/
|
|
67
132
|
type FormanSchemaExtendedNested = {
|
|
133
|
+
/** Store for the nested fields */
|
|
68
134
|
store: FormanSchemaField[] | string;
|
|
135
|
+
/** Domain for the nested fields */
|
|
69
136
|
domain?: string;
|
|
70
137
|
};
|
|
71
138
|
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ type FormanSchemaField = {
|
|
|
34
34
|
/** Default value for the field */
|
|
35
35
|
default?: FormanSchemaValue;
|
|
36
36
|
/** Available options for select type fields */
|
|
37
|
-
options?: FormanSchemaOption[] | FormanSchemaExtendedOptions | string;
|
|
37
|
+
options?: FormanSchemaOption[] | FormanSchemaOptionGroup[] | FormanSchemaExtendedOptions | string;
|
|
38
38
|
/** Help text or description for the field */
|
|
39
39
|
help?: string;
|
|
40
40
|
/** Sub-fields specification for collection or array types */
|
|
@@ -47,25 +47,92 @@ type FormanSchemaField = {
|
|
|
47
47
|
nested?: FormanSchemaNested;
|
|
48
48
|
/** Validation rules */
|
|
49
49
|
validate?: FormanSchemaValidation;
|
|
50
|
+
/** Whether the field is disabled (`false` by default) */
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
/** Whether the field is mappable */
|
|
53
|
+
mappable?: boolean;
|
|
54
|
+
/** Whether the user will be able to insert new lines in GUI (a textarea will be displayed instead of the text field) */
|
|
55
|
+
multiline?: boolean;
|
|
56
|
+
/** Specifies how to treat HTML tags in the field (text only) */
|
|
57
|
+
tags?: 'strip' | 'stripall' | 'escape';
|
|
58
|
+
/** Allowed extension or array of allowed extensions. (filename only) */
|
|
59
|
+
extension?: string | string[];
|
|
60
|
+
/** Semantic type for the field */
|
|
61
|
+
semantic?: string;
|
|
62
|
+
/** Whether to allow time selection (date only, `true` by default) */
|
|
63
|
+
time?: boolean;
|
|
64
|
+
/** Whether the properties of the object will be in the same order as they are defined in the spec (collection only) */
|
|
65
|
+
sequence?: boolean;
|
|
66
|
+
/** Codepage for the field (buffer only) */
|
|
67
|
+
codepage?: string;
|
|
68
|
+
/** Whether the field is grouped (select only) */
|
|
69
|
+
grouped?: boolean;
|
|
70
|
+
/** Whether a mapped value in the select should be validated against the option values. If true, the value is treated as a dynamic and validation is disabled. The value is set to `true` automatically if select options are generated using RPC. */
|
|
71
|
+
dynamic?: boolean;
|
|
72
|
+
/** Mode for the field (select only) */
|
|
73
|
+
mode?: 'edit' | 'choose';
|
|
74
|
+
/** Sort order for the field (select only) */
|
|
75
|
+
sort?: string;
|
|
76
|
+
/** Adds an extra button to the field which opens an extra form. When the form is submitted, a specified RPC is called and the result is set as a new value of the parameter. */
|
|
77
|
+
rpc?: FormanSchemaRPCButton;
|
|
50
78
|
} & Record<`x-${string}`, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* RPC button allows for dynamic value retrieval from an external source
|
|
81
|
+
*/
|
|
82
|
+
type FormanSchemaRPCButton = {
|
|
83
|
+
/** RPC button label */
|
|
84
|
+
label: string;
|
|
85
|
+
/** RPC button URL */
|
|
86
|
+
url: string;
|
|
87
|
+
/** RPC button parameters */
|
|
88
|
+
parameters: FormanSchemaField[];
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Valid Forman Schema values
|
|
92
|
+
*/
|
|
51
93
|
type FormanSchemaValue = string | number | boolean | null;
|
|
94
|
+
/**
|
|
95
|
+
* Option for a select field
|
|
96
|
+
*/
|
|
52
97
|
type FormanSchemaOption = {
|
|
53
98
|
/** Option value */
|
|
54
99
|
value: FormanSchemaValue;
|
|
55
100
|
/** Option label */
|
|
56
101
|
label?: string;
|
|
102
|
+
/** Whether the option is the default */
|
|
103
|
+
default?: boolean;
|
|
57
104
|
/** Nested fields for this option */
|
|
58
105
|
nested?: FormanSchemaNested;
|
|
59
106
|
};
|
|
107
|
+
/**
|
|
108
|
+
* Option group for a select field
|
|
109
|
+
*/
|
|
110
|
+
type FormanSchemaOptionGroup = {
|
|
111
|
+
/** Group label */
|
|
112
|
+
label: string;
|
|
113
|
+
/** Group options */
|
|
114
|
+
options: FormanSchemaOption[];
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Extended options for a select field
|
|
118
|
+
*/
|
|
60
119
|
type FormanSchemaExtendedOptions = {
|
|
61
120
|
/** Store for the options */
|
|
62
|
-
store: FormanSchemaOption[] | string;
|
|
121
|
+
store: FormanSchemaOption[] | FormanSchemaOptionGroup[] | string;
|
|
63
122
|
/** Nested fields for every option */
|
|
64
123
|
nested?: FormanSchemaNested;
|
|
65
124
|
};
|
|
125
|
+
/**
|
|
126
|
+
* Nested fields
|
|
127
|
+
*/
|
|
66
128
|
type FormanSchemaNested = FormanSchemaField[] | string | FormanSchemaExtendedNested;
|
|
129
|
+
/**
|
|
130
|
+
* Extended nested fields
|
|
131
|
+
*/
|
|
67
132
|
type FormanSchemaExtendedNested = {
|
|
133
|
+
/** Store for the nested fields */
|
|
68
134
|
store: FormanSchemaField[] | string;
|
|
135
|
+
/** Domain for the nested fields */
|
|
69
136
|
domain?: string;
|
|
70
137
|
};
|
|
71
138
|
|
package/dist/index.js
CHANGED
|
@@ -5,12 +5,20 @@ function noEmpty(text) {
|
|
|
5
5
|
function isObject(value) {
|
|
6
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
7
|
}
|
|
8
|
+
function isOptionGroup(value) {
|
|
9
|
+
return "options" in value && Array.isArray(value.options);
|
|
10
|
+
}
|
|
8
11
|
|
|
9
12
|
// src/forman.ts
|
|
10
13
|
var SchemaConversionError = class extends Error {
|
|
14
|
+
/** Field that caused the error */
|
|
15
|
+
field;
|
|
16
|
+
/**
|
|
17
|
+
* @param message The error message
|
|
18
|
+
* @param field The field that caused the error
|
|
19
|
+
*/
|
|
11
20
|
constructor(message, field) {
|
|
12
21
|
super(message);
|
|
13
|
-
this.field = field;
|
|
14
22
|
this.name = "SchemaConversionError";
|
|
15
23
|
}
|
|
16
24
|
};
|
|
@@ -209,41 +217,52 @@ function handleArrayType(field, result, context) {
|
|
|
209
217
|
return result;
|
|
210
218
|
}
|
|
211
219
|
function handleSelectType(field, result, context) {
|
|
212
|
-
const
|
|
220
|
+
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
213
221
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
214
222
|
const domain = isObject(field.options) ? isObject(field.options.nested) && field.options.nested.domain ? field.options.nested.domain : void 0 : void 0;
|
|
215
|
-
if (typeof
|
|
223
|
+
if (typeof optionsOrGroups === "string") {
|
|
216
224
|
Object.defineProperty(result, "x-fetch", {
|
|
217
225
|
configurable: true,
|
|
218
226
|
enumerable: true,
|
|
219
227
|
writable: true,
|
|
220
|
-
value: appendQueryString(
|
|
221
|
-
});
|
|
222
|
-
} else if (options?.some((option) => option.label || option.nested)) {
|
|
223
|
-
result.oneOf = (options || []).map((option) => {
|
|
224
|
-
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
225
|
-
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
226
|
-
if (localNested) {
|
|
227
|
-
context.addConditionalFields(
|
|
228
|
-
field.name,
|
|
229
|
-
option.value,
|
|
230
|
-
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : toJSONSchemaInternal(
|
|
231
|
-
{ type: "collection", spec: localNested },
|
|
232
|
-
{
|
|
233
|
-
...context,
|
|
234
|
-
domain: localDomain,
|
|
235
|
-
tail: [...context.tail, field.name]
|
|
236
|
-
}
|
|
237
|
-
)
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
return {
|
|
241
|
-
title: noEmpty(option.label),
|
|
242
|
-
const: option.value
|
|
243
|
-
};
|
|
228
|
+
value: appendQueryString(optionsOrGroups, context.domain, context.tail)
|
|
244
229
|
});
|
|
245
230
|
} else {
|
|
246
|
-
|
|
231
|
+
const options = optionsOrGroups?.some(isOptionGroup) ? optionsOrGroups.flatMap(
|
|
232
|
+
(group) => group.options.map((option) => ({
|
|
233
|
+
...option,
|
|
234
|
+
label: `${group.label}: ${option.label || option.value}`
|
|
235
|
+
}))
|
|
236
|
+
) : optionsOrGroups || [];
|
|
237
|
+
if (options?.some((option) => {
|
|
238
|
+
if (isOptionGroup(option)) return option.options.some((option2) => option2.label || option2.nested);
|
|
239
|
+
return option.label || option.nested;
|
|
240
|
+
})) {
|
|
241
|
+
result.oneOf = (options || []).map((option) => {
|
|
242
|
+
const localNested = (isObject(option.nested) ? option.nested.store : option.nested) || nested;
|
|
243
|
+
const localDomain = (isObject(option.nested) && option.nested.domain ? option.nested.domain : domain) || context.domain;
|
|
244
|
+
if (localNested) {
|
|
245
|
+
context.addConditionalFields(
|
|
246
|
+
field.name,
|
|
247
|
+
option.value,
|
|
248
|
+
typeof localNested === "string" ? appendQueryString(localNested, localDomain, [...context.tail, field.name]) : toJSONSchemaInternal(
|
|
249
|
+
{ type: "collection", spec: localNested },
|
|
250
|
+
{
|
|
251
|
+
...context,
|
|
252
|
+
domain: localDomain,
|
|
253
|
+
tail: [...context.tail, field.name]
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
title: noEmpty(option.label),
|
|
260
|
+
const: option.value
|
|
261
|
+
};
|
|
262
|
+
});
|
|
263
|
+
} else {
|
|
264
|
+
result.enum = (options || []).map((option) => option.value);
|
|
265
|
+
}
|
|
247
266
|
}
|
|
248
267
|
if (nested && domain && domain !== context.domain) {
|
|
249
268
|
if (typeof nested === "string") {
|
|
@@ -265,7 +284,7 @@ function handleSelectType(field, result, context) {
|
|
|
265
284
|
configurable: true,
|
|
266
285
|
enumerable: true,
|
|
267
286
|
writable: true,
|
|
268
|
-
value: typeof nested === "string" ? { $ref: nested } : toJSONSchemaInternal(
|
|
287
|
+
value: typeof nested === "string" ? { $ref: appendQueryString(nested, context.domain, [...context.tail, field.name]) } : toJSONSchemaInternal(
|
|
269
288
|
{ type: "collection", spec: nested },
|
|
270
289
|
{
|
|
271
290
|
...context,
|