@makehq/forman-schema 1.5.0 → 1.7.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 +1 -0
- package/dist/index.cjs +156 -4
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +156 -4
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -152,6 +152,67 @@ function buildRestoreStructure(items) {
|
|
|
152
152
|
}
|
|
153
153
|
return result;
|
|
154
154
|
}
|
|
155
|
+
var IML_FILTER_ENTRY_TYPES = ["null", "boolean", "number", "string"];
|
|
156
|
+
var IML_UNARY_FILTER_OPERATORS = ["exist", "notexist"];
|
|
157
|
+
var IML_BINARY_FILTER_OPERATORS = [
|
|
158
|
+
"text:equal",
|
|
159
|
+
"text:equal:ci",
|
|
160
|
+
"text:notequal",
|
|
161
|
+
"text:notequal:ci",
|
|
162
|
+
"text:contain",
|
|
163
|
+
"text:contain:ci",
|
|
164
|
+
"text:notcontain",
|
|
165
|
+
"text:notcontain:ci",
|
|
166
|
+
"text:startwith",
|
|
167
|
+
"text:startwith:ci",
|
|
168
|
+
"text:notstartwith",
|
|
169
|
+
"text:notstartwith:ci",
|
|
170
|
+
"text:endwith",
|
|
171
|
+
"text:endwith:ci",
|
|
172
|
+
"text:notendwith",
|
|
173
|
+
"text:notendwith:ci",
|
|
174
|
+
"text:pattern",
|
|
175
|
+
"text:pattern:ci",
|
|
176
|
+
"text:notpattern",
|
|
177
|
+
"text:notpattern:ci",
|
|
178
|
+
"number:equal",
|
|
179
|
+
"number:notequal",
|
|
180
|
+
"number:greater",
|
|
181
|
+
"number:less",
|
|
182
|
+
"number:greaterorequal",
|
|
183
|
+
"number:lessorequal",
|
|
184
|
+
"date:equal",
|
|
185
|
+
"date:notequal",
|
|
186
|
+
"date:greater",
|
|
187
|
+
"date:less",
|
|
188
|
+
"date:greaterorequal",
|
|
189
|
+
"date:lessorequal",
|
|
190
|
+
"time:equal",
|
|
191
|
+
"time:notequal",
|
|
192
|
+
"time:greater",
|
|
193
|
+
"time:less",
|
|
194
|
+
"time:greaterorequal",
|
|
195
|
+
"time:lessorequal",
|
|
196
|
+
"semver:equal",
|
|
197
|
+
"semver:notequal",
|
|
198
|
+
"semver:greater",
|
|
199
|
+
"semver:less",
|
|
200
|
+
"semver:greaterorequal",
|
|
201
|
+
"semver:lessorequal",
|
|
202
|
+
"array:contain",
|
|
203
|
+
"array:contain:ci",
|
|
204
|
+
"array:notcontain",
|
|
205
|
+
"array:notcontain:ci",
|
|
206
|
+
"array:equal",
|
|
207
|
+
"array:notequal",
|
|
208
|
+
"array:greater",
|
|
209
|
+
"array:less",
|
|
210
|
+
"array:greaterorequal",
|
|
211
|
+
"array:lessorequal",
|
|
212
|
+
"boolean:equal",
|
|
213
|
+
"boolean:notequal"
|
|
214
|
+
];
|
|
215
|
+
var IML_FILTER_OPERATORS = [...IML_UNARY_FILTER_OPERATORS, ...IML_BINARY_FILTER_OPERATORS];
|
|
155
216
|
|
|
156
217
|
// src/forman.ts
|
|
157
218
|
var SchemaConversionError = class extends Error {
|
|
@@ -177,6 +238,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
177
238
|
collection: "object",
|
|
178
239
|
dynamicCollection: "object",
|
|
179
240
|
text: "string",
|
|
241
|
+
editor: "string",
|
|
180
242
|
number: "number",
|
|
181
243
|
boolean: "boolean",
|
|
182
244
|
date: "string",
|
|
@@ -187,6 +249,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
187
249
|
email: "string",
|
|
188
250
|
filename: "string",
|
|
189
251
|
file: "string",
|
|
252
|
+
filter: "array",
|
|
190
253
|
folder: "string",
|
|
191
254
|
hidden: void 0,
|
|
192
255
|
integer: "number",
|
|
@@ -253,6 +316,8 @@ function toJSONSchemaInternal(field, context = createDefaultContext()) {
|
|
|
253
316
|
case "file":
|
|
254
317
|
case "folder":
|
|
255
318
|
return handleSelectType(normalizedField, result, context);
|
|
319
|
+
case "filter":
|
|
320
|
+
return handleFilterType(normalizedField, result, context);
|
|
256
321
|
default:
|
|
257
322
|
return handlePrimitiveType(normalizedField, result);
|
|
258
323
|
}
|
|
@@ -263,6 +328,12 @@ function handleCollectionType(field, result, context) {
|
|
|
263
328
|
required: []
|
|
264
329
|
});
|
|
265
330
|
function addField(subField, tail) {
|
|
331
|
+
if (typeof subField === "string") {
|
|
332
|
+
const value = { $ref: appendQueryString(subField, context.domain, tail || context.tail) };
|
|
333
|
+
result.allOf ||= [];
|
|
334
|
+
result.allOf.push(value);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
266
337
|
if (isVisualType(subField.type)) {
|
|
267
338
|
return;
|
|
268
339
|
}
|
|
@@ -329,6 +400,41 @@ function handleArrayType(field, result, context) {
|
|
|
329
400
|
}
|
|
330
401
|
return result;
|
|
331
402
|
}
|
|
403
|
+
function handleFilterType(field, result, context) {
|
|
404
|
+
const filterItems = {
|
|
405
|
+
oneOf: [
|
|
406
|
+
{
|
|
407
|
+
type: "object",
|
|
408
|
+
properties: {
|
|
409
|
+
a: { type: IML_FILTER_ENTRY_TYPES },
|
|
410
|
+
o: { enum: IML_UNARY_FILTER_OPERATORS }
|
|
411
|
+
},
|
|
412
|
+
required: ["a", "o"]
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
type: "object",
|
|
416
|
+
properties: {
|
|
417
|
+
a: { type: IML_FILTER_ENTRY_TYPES },
|
|
418
|
+
b: { type: IML_FILTER_ENTRY_TYPES },
|
|
419
|
+
o: { enum: IML_BINARY_FILTER_OPERATORS }
|
|
420
|
+
},
|
|
421
|
+
required: ["a", "b", "o"]
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
};
|
|
425
|
+
const logic = field.logic ?? "default";
|
|
426
|
+
result.items = ["and", "or"].includes(logic) ? filterItems : {
|
|
427
|
+
type: "array",
|
|
428
|
+
items: filterItems
|
|
429
|
+
};
|
|
430
|
+
Object.defineProperty(result, "x-filter", {
|
|
431
|
+
configurable: true,
|
|
432
|
+
enumerable: true,
|
|
433
|
+
writable: true,
|
|
434
|
+
value: logic
|
|
435
|
+
});
|
|
436
|
+
return result;
|
|
437
|
+
}
|
|
332
438
|
function handleSelectType(field, result, context) {
|
|
333
439
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
334
440
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
@@ -400,9 +506,7 @@ function handleSelectType(field, result, context) {
|
|
|
400
506
|
}
|
|
401
507
|
}
|
|
402
508
|
if (nested && domain && domain !== context.domain) {
|
|
403
|
-
|
|
404
|
-
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
405
|
-
}
|
|
509
|
+
const normalizedNested = typeof nested === "string" ? [nested] : nested;
|
|
406
510
|
let root = context.roots[domain];
|
|
407
511
|
if (!root) {
|
|
408
512
|
const buffer = [];
|
|
@@ -413,7 +517,7 @@ function handleSelectType(field, result, context) {
|
|
|
413
517
|
}
|
|
414
518
|
};
|
|
415
519
|
}
|
|
416
|
-
root.addFields(
|
|
520
|
+
root.addFields(normalizedNested, [...context.tail, field.name]);
|
|
417
521
|
} else if (nested) {
|
|
418
522
|
Object.defineProperty(result, "x-nested", {
|
|
419
523
|
configurable: true,
|
|
@@ -485,6 +589,7 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
485
589
|
email: "string",
|
|
486
590
|
filename: "string",
|
|
487
591
|
file: "string",
|
|
592
|
+
filter: "array",
|
|
488
593
|
folder: "string",
|
|
489
594
|
hidden: void 0,
|
|
490
595
|
integer: "number",
|
|
@@ -648,6 +753,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
648
753
|
case "file":
|
|
649
754
|
case "folder":
|
|
650
755
|
return handleSelectType2(value, normalizedField, context);
|
|
756
|
+
case "filter":
|
|
757
|
+
return handleFilterType2(value, normalizedField, context);
|
|
651
758
|
default:
|
|
652
759
|
return handlePrimitiveType2(value, normalizedField, context);
|
|
653
760
|
}
|
|
@@ -774,6 +881,42 @@ async function handleArrayType2(value, field, context) {
|
|
|
774
881
|
errors
|
|
775
882
|
};
|
|
776
883
|
}
|
|
884
|
+
async function handleFilterType2(value, field, context) {
|
|
885
|
+
const filterEntry = {
|
|
886
|
+
type: "collection",
|
|
887
|
+
spec: [
|
|
888
|
+
{
|
|
889
|
+
name: "a",
|
|
890
|
+
type: "any",
|
|
891
|
+
required: true
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
name: "b",
|
|
895
|
+
type: "any"
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
name: "o",
|
|
899
|
+
type: "text",
|
|
900
|
+
validate: {
|
|
901
|
+
enum: IML_FILTER_OPERATORS
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
]
|
|
905
|
+
};
|
|
906
|
+
const inlineSchema = ["and", "or"].includes(field.logic ?? "default") ? {
|
|
907
|
+
name: field.name,
|
|
908
|
+
type: "array",
|
|
909
|
+
spec: filterEntry
|
|
910
|
+
} : {
|
|
911
|
+
name: field.name,
|
|
912
|
+
type: "array",
|
|
913
|
+
spec: {
|
|
914
|
+
type: "array",
|
|
915
|
+
spec: filterEntry
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
return handleArrayType2(value, inlineSchema, context);
|
|
919
|
+
}
|
|
777
920
|
async function handleSelectType2(value, field, context) {
|
|
778
921
|
const errors = [];
|
|
779
922
|
let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
@@ -1018,6 +1161,15 @@ function toFormanSchema(field) {
|
|
|
1018
1161
|
spec
|
|
1019
1162
|
};
|
|
1020
1163
|
case "array":
|
|
1164
|
+
const filterLogic = Object.getOwnPropertyDescriptor(field, "x-filter");
|
|
1165
|
+
if (filterLogic) {
|
|
1166
|
+
return {
|
|
1167
|
+
type: "filter",
|
|
1168
|
+
label: noEmpty(field.title),
|
|
1169
|
+
help: noEmpty(field.description),
|
|
1170
|
+
logic: filterLogic.value === "default" ? void 0 : filterLogic.value
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1021
1173
|
const items = field.items && isObject(field.items) ? field.items : void 0;
|
|
1022
1174
|
const formanSchema = {
|
|
1023
1175
|
type: "array",
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ import { JSONSchema7 } from 'json-schema';
|
|
|
3
3
|
/**
|
|
4
4
|
* Valid Forman Schema field types
|
|
5
5
|
*/
|
|
6
|
-
type FormanSchemaFieldType = 'aiagent' | 'account' | 'hook' | 'device' | 'keychain' | 'datastore' | 'udt' | 'scenario' | 'array' | 'collection' | 'text' | 'number' | 'boolean' | 'date' | 'json' | 'buffer' | 'cert' | 'color' | 'email' | 'filename' | 'file' | 'folder' | 'hidden' | 'integer' | 'uinteger' | 'path' | 'pkey' | 'port' | 'select' | 'time' | 'timestamp' | 'timezone' | 'url' | 'uuid' | `account:${string}` | `hook:${string}` | `keychain:${string}` | 'banner' | 'markdown' | 'html' | 'separator' | string;
|
|
6
|
+
type FormanSchemaFieldType = 'aiagent' | 'account' | 'hook' | 'device' | 'keychain' | 'datastore' | 'udt' | 'scenario' | 'array' | 'collection' | 'text' | 'number' | 'boolean' | 'date' | 'json' | 'buffer' | 'cert' | 'color' | 'email' | 'filename' | 'file' | 'filter' | 'folder' | 'hidden' | 'integer' | 'uinteger' | 'path' | 'pkey' | 'port' | 'select' | 'time' | 'timestamp' | 'timezone' | 'url' | 'uuid' | `account:${string}` | `hook:${string}` | `keychain:${string}` | 'banner' | 'markdown' | 'html' | 'separator' | string;
|
|
7
7
|
/**
|
|
8
8
|
* Validation configuration for Forman Schema fields
|
|
9
9
|
*/
|
|
@@ -79,6 +79,8 @@ type FormanSchemaField = {
|
|
|
79
79
|
sort?: string;
|
|
80
80
|
/** 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. */
|
|
81
81
|
rpc?: FormanSchemaRPCButton;
|
|
82
|
+
/** Definition of boolean logic to apply (filter only) */
|
|
83
|
+
logic?: 'and' | 'or' | 'reverse';
|
|
82
84
|
} & Record<`x-${string}`, unknown>;
|
|
83
85
|
/**
|
|
84
86
|
* RPC button allows for dynamic value retrieval from an external source
|
|
@@ -144,7 +146,7 @@ type FormanSchemaNested = (FormanSchemaField | string)[] | string | FormanSchema
|
|
|
144
146
|
*/
|
|
145
147
|
type FormanSchemaExtendedNested = {
|
|
146
148
|
/** Store for the nested fields */
|
|
147
|
-
store: FormanSchemaField[] | string;
|
|
149
|
+
store: (FormanSchemaField | string)[] | string;
|
|
148
150
|
/** Domain for the nested fields */
|
|
149
151
|
domain?: string;
|
|
150
152
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { JSONSchema7 } from 'json-schema';
|
|
|
3
3
|
/**
|
|
4
4
|
* Valid Forman Schema field types
|
|
5
5
|
*/
|
|
6
|
-
type FormanSchemaFieldType = 'aiagent' | 'account' | 'hook' | 'device' | 'keychain' | 'datastore' | 'udt' | 'scenario' | 'array' | 'collection' | 'text' | 'number' | 'boolean' | 'date' | 'json' | 'buffer' | 'cert' | 'color' | 'email' | 'filename' | 'file' | 'folder' | 'hidden' | 'integer' | 'uinteger' | 'path' | 'pkey' | 'port' | 'select' | 'time' | 'timestamp' | 'timezone' | 'url' | 'uuid' | `account:${string}` | `hook:${string}` | `keychain:${string}` | 'banner' | 'markdown' | 'html' | 'separator' | string;
|
|
6
|
+
type FormanSchemaFieldType = 'aiagent' | 'account' | 'hook' | 'device' | 'keychain' | 'datastore' | 'udt' | 'scenario' | 'array' | 'collection' | 'text' | 'number' | 'boolean' | 'date' | 'json' | 'buffer' | 'cert' | 'color' | 'email' | 'filename' | 'file' | 'filter' | 'folder' | 'hidden' | 'integer' | 'uinteger' | 'path' | 'pkey' | 'port' | 'select' | 'time' | 'timestamp' | 'timezone' | 'url' | 'uuid' | `account:${string}` | `hook:${string}` | `keychain:${string}` | 'banner' | 'markdown' | 'html' | 'separator' | string;
|
|
7
7
|
/**
|
|
8
8
|
* Validation configuration for Forman Schema fields
|
|
9
9
|
*/
|
|
@@ -79,6 +79,8 @@ type FormanSchemaField = {
|
|
|
79
79
|
sort?: string;
|
|
80
80
|
/** 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. */
|
|
81
81
|
rpc?: FormanSchemaRPCButton;
|
|
82
|
+
/** Definition of boolean logic to apply (filter only) */
|
|
83
|
+
logic?: 'and' | 'or' | 'reverse';
|
|
82
84
|
} & Record<`x-${string}`, unknown>;
|
|
83
85
|
/**
|
|
84
86
|
* RPC button allows for dynamic value retrieval from an external source
|
|
@@ -144,7 +146,7 @@ type FormanSchemaNested = (FormanSchemaField | string)[] | string | FormanSchema
|
|
|
144
146
|
*/
|
|
145
147
|
type FormanSchemaExtendedNested = {
|
|
146
148
|
/** Store for the nested fields */
|
|
147
|
-
store: FormanSchemaField[] | string;
|
|
149
|
+
store: (FormanSchemaField | string)[] | string;
|
|
148
150
|
/** Domain for the nested fields */
|
|
149
151
|
domain?: string;
|
|
150
152
|
};
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,67 @@ function buildRestoreStructure(items) {
|
|
|
123
123
|
}
|
|
124
124
|
return result;
|
|
125
125
|
}
|
|
126
|
+
var IML_FILTER_ENTRY_TYPES = ["null", "boolean", "number", "string"];
|
|
127
|
+
var IML_UNARY_FILTER_OPERATORS = ["exist", "notexist"];
|
|
128
|
+
var IML_BINARY_FILTER_OPERATORS = [
|
|
129
|
+
"text:equal",
|
|
130
|
+
"text:equal:ci",
|
|
131
|
+
"text:notequal",
|
|
132
|
+
"text:notequal:ci",
|
|
133
|
+
"text:contain",
|
|
134
|
+
"text:contain:ci",
|
|
135
|
+
"text:notcontain",
|
|
136
|
+
"text:notcontain:ci",
|
|
137
|
+
"text:startwith",
|
|
138
|
+
"text:startwith:ci",
|
|
139
|
+
"text:notstartwith",
|
|
140
|
+
"text:notstartwith:ci",
|
|
141
|
+
"text:endwith",
|
|
142
|
+
"text:endwith:ci",
|
|
143
|
+
"text:notendwith",
|
|
144
|
+
"text:notendwith:ci",
|
|
145
|
+
"text:pattern",
|
|
146
|
+
"text:pattern:ci",
|
|
147
|
+
"text:notpattern",
|
|
148
|
+
"text:notpattern:ci",
|
|
149
|
+
"number:equal",
|
|
150
|
+
"number:notequal",
|
|
151
|
+
"number:greater",
|
|
152
|
+
"number:less",
|
|
153
|
+
"number:greaterorequal",
|
|
154
|
+
"number:lessorequal",
|
|
155
|
+
"date:equal",
|
|
156
|
+
"date:notequal",
|
|
157
|
+
"date:greater",
|
|
158
|
+
"date:less",
|
|
159
|
+
"date:greaterorequal",
|
|
160
|
+
"date:lessorequal",
|
|
161
|
+
"time:equal",
|
|
162
|
+
"time:notequal",
|
|
163
|
+
"time:greater",
|
|
164
|
+
"time:less",
|
|
165
|
+
"time:greaterorequal",
|
|
166
|
+
"time:lessorequal",
|
|
167
|
+
"semver:equal",
|
|
168
|
+
"semver:notequal",
|
|
169
|
+
"semver:greater",
|
|
170
|
+
"semver:less",
|
|
171
|
+
"semver:greaterorequal",
|
|
172
|
+
"semver:lessorequal",
|
|
173
|
+
"array:contain",
|
|
174
|
+
"array:contain:ci",
|
|
175
|
+
"array:notcontain",
|
|
176
|
+
"array:notcontain:ci",
|
|
177
|
+
"array:equal",
|
|
178
|
+
"array:notequal",
|
|
179
|
+
"array:greater",
|
|
180
|
+
"array:less",
|
|
181
|
+
"array:greaterorequal",
|
|
182
|
+
"array:lessorequal",
|
|
183
|
+
"boolean:equal",
|
|
184
|
+
"boolean:notequal"
|
|
185
|
+
];
|
|
186
|
+
var IML_FILTER_OPERATORS = [...IML_UNARY_FILTER_OPERATORS, ...IML_BINARY_FILTER_OPERATORS];
|
|
126
187
|
|
|
127
188
|
// src/forman.ts
|
|
128
189
|
var SchemaConversionError = class extends Error {
|
|
@@ -148,6 +209,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
148
209
|
collection: "object",
|
|
149
210
|
dynamicCollection: "object",
|
|
150
211
|
text: "string",
|
|
212
|
+
editor: "string",
|
|
151
213
|
number: "number",
|
|
152
214
|
boolean: "boolean",
|
|
153
215
|
date: "string",
|
|
@@ -158,6 +220,7 @@ var FORMAN_TYPE_MAP = {
|
|
|
158
220
|
email: "string",
|
|
159
221
|
filename: "string",
|
|
160
222
|
file: "string",
|
|
223
|
+
filter: "array",
|
|
161
224
|
folder: "string",
|
|
162
225
|
hidden: void 0,
|
|
163
226
|
integer: "number",
|
|
@@ -224,6 +287,8 @@ function toJSONSchemaInternal(field, context = createDefaultContext()) {
|
|
|
224
287
|
case "file":
|
|
225
288
|
case "folder":
|
|
226
289
|
return handleSelectType(normalizedField, result, context);
|
|
290
|
+
case "filter":
|
|
291
|
+
return handleFilterType(normalizedField, result, context);
|
|
227
292
|
default:
|
|
228
293
|
return handlePrimitiveType(normalizedField, result);
|
|
229
294
|
}
|
|
@@ -234,6 +299,12 @@ function handleCollectionType(field, result, context) {
|
|
|
234
299
|
required: []
|
|
235
300
|
});
|
|
236
301
|
function addField(subField, tail) {
|
|
302
|
+
if (typeof subField === "string") {
|
|
303
|
+
const value = { $ref: appendQueryString(subField, context.domain, tail || context.tail) };
|
|
304
|
+
result.allOf ||= [];
|
|
305
|
+
result.allOf.push(value);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
237
308
|
if (isVisualType(subField.type)) {
|
|
238
309
|
return;
|
|
239
310
|
}
|
|
@@ -300,6 +371,41 @@ function handleArrayType(field, result, context) {
|
|
|
300
371
|
}
|
|
301
372
|
return result;
|
|
302
373
|
}
|
|
374
|
+
function handleFilterType(field, result, context) {
|
|
375
|
+
const filterItems = {
|
|
376
|
+
oneOf: [
|
|
377
|
+
{
|
|
378
|
+
type: "object",
|
|
379
|
+
properties: {
|
|
380
|
+
a: { type: IML_FILTER_ENTRY_TYPES },
|
|
381
|
+
o: { enum: IML_UNARY_FILTER_OPERATORS }
|
|
382
|
+
},
|
|
383
|
+
required: ["a", "o"]
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
type: "object",
|
|
387
|
+
properties: {
|
|
388
|
+
a: { type: IML_FILTER_ENTRY_TYPES },
|
|
389
|
+
b: { type: IML_FILTER_ENTRY_TYPES },
|
|
390
|
+
o: { enum: IML_BINARY_FILTER_OPERATORS }
|
|
391
|
+
},
|
|
392
|
+
required: ["a", "b", "o"]
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
};
|
|
396
|
+
const logic = field.logic ?? "default";
|
|
397
|
+
result.items = ["and", "or"].includes(logic) ? filterItems : {
|
|
398
|
+
type: "array",
|
|
399
|
+
items: filterItems
|
|
400
|
+
};
|
|
401
|
+
Object.defineProperty(result, "x-filter", {
|
|
402
|
+
configurable: true,
|
|
403
|
+
enumerable: true,
|
|
404
|
+
writable: true,
|
|
405
|
+
value: logic
|
|
406
|
+
});
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
303
409
|
function handleSelectType(field, result, context) {
|
|
304
410
|
const optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
305
411
|
const nested = isObject(field.options) ? isObject(field.options.nested) ? field.options.nested.store : field.options.nested : void 0;
|
|
@@ -371,9 +477,7 @@ function handleSelectType(field, result, context) {
|
|
|
371
477
|
}
|
|
372
478
|
}
|
|
373
479
|
if (nested && domain && domain !== context.domain) {
|
|
374
|
-
|
|
375
|
-
throw new SchemaConversionError("Dynamic nested fields with domain change are not supported.");
|
|
376
|
-
}
|
|
480
|
+
const normalizedNested = typeof nested === "string" ? [nested] : nested;
|
|
377
481
|
let root = context.roots[domain];
|
|
378
482
|
if (!root) {
|
|
379
483
|
const buffer = [];
|
|
@@ -384,7 +488,7 @@ function handleSelectType(field, result, context) {
|
|
|
384
488
|
}
|
|
385
489
|
};
|
|
386
490
|
}
|
|
387
|
-
root.addFields(
|
|
491
|
+
root.addFields(normalizedNested, [...context.tail, field.name]);
|
|
388
492
|
} else if (nested) {
|
|
389
493
|
Object.defineProperty(result, "x-nested", {
|
|
390
494
|
configurable: true,
|
|
@@ -456,6 +560,7 @@ var FORMAN_TYPE_MAP2 = {
|
|
|
456
560
|
email: "string",
|
|
457
561
|
filename: "string",
|
|
458
562
|
file: "string",
|
|
563
|
+
filter: "array",
|
|
459
564
|
folder: "string",
|
|
460
565
|
hidden: void 0,
|
|
461
566
|
integer: "number",
|
|
@@ -619,6 +724,8 @@ async function validateFormanValue(value, field, context) {
|
|
|
619
724
|
case "file":
|
|
620
725
|
case "folder":
|
|
621
726
|
return handleSelectType2(value, normalizedField, context);
|
|
727
|
+
case "filter":
|
|
728
|
+
return handleFilterType2(value, normalizedField, context);
|
|
622
729
|
default:
|
|
623
730
|
return handlePrimitiveType2(value, normalizedField, context);
|
|
624
731
|
}
|
|
@@ -745,6 +852,42 @@ async function handleArrayType2(value, field, context) {
|
|
|
745
852
|
errors
|
|
746
853
|
};
|
|
747
854
|
}
|
|
855
|
+
async function handleFilterType2(value, field, context) {
|
|
856
|
+
const filterEntry = {
|
|
857
|
+
type: "collection",
|
|
858
|
+
spec: [
|
|
859
|
+
{
|
|
860
|
+
name: "a",
|
|
861
|
+
type: "any",
|
|
862
|
+
required: true
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
name: "b",
|
|
866
|
+
type: "any"
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
name: "o",
|
|
870
|
+
type: "text",
|
|
871
|
+
validate: {
|
|
872
|
+
enum: IML_FILTER_OPERATORS
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
]
|
|
876
|
+
};
|
|
877
|
+
const inlineSchema = ["and", "or"].includes(field.logic ?? "default") ? {
|
|
878
|
+
name: field.name,
|
|
879
|
+
type: "array",
|
|
880
|
+
spec: filterEntry
|
|
881
|
+
} : {
|
|
882
|
+
name: field.name,
|
|
883
|
+
type: "array",
|
|
884
|
+
spec: {
|
|
885
|
+
type: "array",
|
|
886
|
+
spec: filterEntry
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
return handleArrayType2(value, inlineSchema, context);
|
|
890
|
+
}
|
|
748
891
|
async function handleSelectType2(value, field, context) {
|
|
749
892
|
const errors = [];
|
|
750
893
|
let optionsOrGroups = isObject(field.options) ? field.options.store : field.options;
|
|
@@ -989,6 +1132,15 @@ function toFormanSchema(field) {
|
|
|
989
1132
|
spec
|
|
990
1133
|
};
|
|
991
1134
|
case "array":
|
|
1135
|
+
const filterLogic = Object.getOwnPropertyDescriptor(field, "x-filter");
|
|
1136
|
+
if (filterLogic) {
|
|
1137
|
+
return {
|
|
1138
|
+
type: "filter",
|
|
1139
|
+
label: noEmpty(field.title),
|
|
1140
|
+
help: noEmpty(field.description),
|
|
1141
|
+
logic: filterLogic.value === "default" ? void 0 : filterLogic.value
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
992
1144
|
const items = field.items && isObject(field.items) ? field.items : void 0;
|
|
993
1145
|
const formanSchema = {
|
|
994
1146
|
type: "array",
|