@remoteoss/json-schema-form 0.1.0-dev.20230517211625

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 ADDED
@@ -0,0 +1,1205 @@
1
+
2
+ /*!
3
+ Copyright (c) 2023 Remote Technology, Inc.
4
+ NPM Package: @remoteoss/json-schema-form@0.1.0-dev.20230517211625
5
+ Generated: Wed, 17 May 2023 21:17:44 GMT
6
+
7
+ MIT License
8
+
9
+ Copyright (c) 2023 Remote Technology, Inc.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ */
30
+ var __create = Object.create;
31
+ var __defProp = Object.defineProperty;
32
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
33
+ var __getOwnPropNames = Object.getOwnPropertyNames;
34
+ var __getProtoOf = Object.getPrototypeOf;
35
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
36
+ var __export = (target, all) => {
37
+ for (var name in all)
38
+ __defProp(target, name, { get: all[name], enumerable: true });
39
+ };
40
+ var __copyProps = (to, from, except, desc) => {
41
+ if (from && typeof from === "object" || typeof from === "function") {
42
+ for (let key of __getOwnPropNames(from))
43
+ if (!__hasOwnProp.call(to, key) && key !== except)
44
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
45
+ }
46
+ return to;
47
+ };
48
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
49
+ // If the importer is in node compatibility mode or this is not an ESM
50
+ // file that has been converted to a CommonJS file using a Babel-
51
+ // compatible transform (i.e. "__esModule" has not been set), then set
52
+ // "default" to the CommonJS "module.exports" for node compatibility.
53
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
54
+ mod
55
+ ));
56
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
57
+
58
+ // src/index.js
59
+ var src_exports = {};
60
+ __export(src_exports, {
61
+ createHeadlessForm: () => createHeadlessForm
62
+ });
63
+ module.exports = __toCommonJS(src_exports);
64
+
65
+ // src/createHeadlessForm.js
66
+ var import_get3 = __toESM(require("lodash/get"));
67
+ var import_isNil3 = __toESM(require("lodash/isNil"));
68
+ var import_omit3 = __toESM(require("lodash/omit"));
69
+ var import_omitBy2 = __toESM(require("lodash/omitBy"));
70
+ var import_pick2 = __toESM(require("lodash/pick"));
71
+ var import_size = __toESM(require("lodash/size"));
72
+
73
+ // src/calculateConditionalProperties.js
74
+ var import_merge2 = __toESM(require("lodash/merge"));
75
+ var import_omit2 = __toESM(require("lodash/omit"));
76
+
77
+ // src/helpers.js
78
+ var import_get2 = __toESM(require("lodash/get"));
79
+ var import_isNil = __toESM(require("lodash/isNil"));
80
+ var import_omit = __toESM(require("lodash/omit"));
81
+ var import_omitBy = __toESM(require("lodash/omitBy"));
82
+ var import_set = __toESM(require("lodash/set"));
83
+ var import_yup2 = require("yup");
84
+
85
+ // src/internals/helpers.js
86
+ var import_merge = __toESM(require("lodash/fp/merge"));
87
+ var import_get = __toESM(require("lodash/get"));
88
+ var import_isEmpty = __toESM(require("lodash/isEmpty"));
89
+ var import_isFunction = __toESM(require("lodash/isFunction"));
90
+ function pickXKey(node, key) {
91
+ const deprecatedKeys = ["presentation", "errorMessage"];
92
+ return (0, import_get.default)(node, `x-jsf-${key}`, deprecatedKeys.includes(key) ? node?.[key] : void 0);
93
+ }
94
+ function getFieldDescription(node, customProperties = {}) {
95
+ const nodeDescription = node?.description ? {
96
+ description: node.description
97
+ } : {};
98
+ const customDescription = customProperties?.description ? {
99
+ description: (0, import_isFunction.default)(customProperties.description) ? customProperties.description(node?.description, {
100
+ ...node,
101
+ ...customProperties
102
+ }) : customProperties.description
103
+ } : {};
104
+ const nodePresentation = pickXKey(node, "presentation");
105
+ const presentation = !(0, import_isEmpty.default)(nodePresentation) && {
106
+ presentation: { ...nodePresentation, ...customDescription }
107
+ };
108
+ return (0, import_merge.default)(nodeDescription, { ...customDescription, ...presentation });
109
+ }
110
+
111
+ // src/internals/fields.js
112
+ var jsonTypes = {
113
+ STRING: "string",
114
+ NUMBER: "number",
115
+ INTEGER: "integer",
116
+ OBJECT: "object",
117
+ ARRAY: "array",
118
+ BOOLEAN: "boolean",
119
+ NULL: "null"
120
+ };
121
+ var supportedTypes = {
122
+ TEXT: "text",
123
+ NUMBER: "number",
124
+ SELECT: "select",
125
+ FILE: "file",
126
+ RADIO: "radio",
127
+ GROUP_ARRAY: "group-array",
128
+ EMAIL: "email",
129
+ DATE: "date",
130
+ CHECKBOX: "checkbox",
131
+ FIELDSET: "fieldset"
132
+ };
133
+ var jsonTypeToInputType = {
134
+ [jsonTypes.STRING]: ({ oneOf, format }) => {
135
+ if (format === "email")
136
+ return supportedTypes.EMAIL;
137
+ if (format === "date")
138
+ return supportedTypes.DATE;
139
+ if (format === "data-url")
140
+ return supportedTypes.FILE;
141
+ if (oneOf)
142
+ return supportedTypes.RADIO;
143
+ return supportedTypes.TEXT;
144
+ },
145
+ [jsonTypes.NUMBER]: () => supportedTypes.NUMBER,
146
+ [jsonTypes.INTEGER]: () => supportedTypes.NUMBER,
147
+ [jsonTypes.OBJECT]: () => supportedTypes.FIELDSET,
148
+ [jsonTypes.ARRAY]: ({ items }) => {
149
+ if (items.properties)
150
+ return supportedTypes.GROUP_ARRAY;
151
+ return supportedTypes.SELECT;
152
+ },
153
+ [jsonTypes.BOOLEAN]: () => supportedTypes.CHECKBOX
154
+ };
155
+ function getInputType(fieldProperties, strictInputType, name) {
156
+ const presentation = pickXKey(fieldProperties, "presentation") ?? {};
157
+ const presentationInputType = presentation?.inputType;
158
+ if (presentationInputType) {
159
+ return presentationInputType;
160
+ }
161
+ if (strictInputType) {
162
+ throw Error(`Strict error: Missing inputType to field "${name || fieldProperties.title}".
163
+ You can fix the json schema or skip this error by calling createHeadlessForm(schema, { strictInputType: false })`);
164
+ }
165
+ if (!fieldProperties.type) {
166
+ if (fieldProperties.items?.properties) {
167
+ return supportedTypes.GROUP_ARRAY;
168
+ }
169
+ if (fieldProperties.properties) {
170
+ return supportedTypes.SELECT;
171
+ }
172
+ return jsonTypeToInputType[jsonTypes.STRING](fieldProperties);
173
+ }
174
+ return jsonTypeToInputType[fieldProperties.type]?.(fieldProperties);
175
+ }
176
+ function _composeFieldFile({ name, label, description, accept, required = true, ...attrs }) {
177
+ return {
178
+ type: supportedTypes.FILE,
179
+ name,
180
+ label,
181
+ description,
182
+ required,
183
+ accept,
184
+ ...attrs
185
+ };
186
+ }
187
+ function _composeFieldText({ name, label, description, required = true, ...attrs }) {
188
+ return {
189
+ type: supportedTypes.TEXT,
190
+ name,
191
+ label,
192
+ description,
193
+ required,
194
+ ...attrs
195
+ };
196
+ }
197
+ function _composeFieldEmail({ name, label, required = true, ...attrs }) {
198
+ return {
199
+ type: supportedTypes.EMAIL,
200
+ name,
201
+ label,
202
+ required,
203
+ ...attrs
204
+ };
205
+ }
206
+ function _composeFieldNumber({
207
+ name,
208
+ label,
209
+ percentage = false,
210
+ required = true,
211
+ minimum,
212
+ maximum,
213
+ ...attrs
214
+ }) {
215
+ let minValue = minimum;
216
+ let maxValue = maximum;
217
+ if (percentage) {
218
+ minValue = minValue ?? 0;
219
+ maxValue = maxValue ?? 100;
220
+ }
221
+ return {
222
+ type: supportedTypes.NUMBER,
223
+ name,
224
+ label,
225
+ percentage,
226
+ required,
227
+ minimum: minValue,
228
+ maximum: maxValue,
229
+ ...attrs
230
+ };
231
+ }
232
+ function _composeFieldDate({ name, label, required = true, ...attrs }) {
233
+ return {
234
+ type: supportedTypes.DATE,
235
+ name,
236
+ label,
237
+ required,
238
+ ...attrs
239
+ };
240
+ }
241
+ function _composeFieldRadio({ name, label, options, required = true, ...attrs }) {
242
+ return {
243
+ type: supportedTypes.RADIO,
244
+ name,
245
+ label,
246
+ options,
247
+ required,
248
+ ...attrs
249
+ };
250
+ }
251
+ function _composeFieldSelect({ name, label, options, required = true, ...attrs }) {
252
+ return {
253
+ type: supportedTypes.SELECT,
254
+ name,
255
+ label,
256
+ options,
257
+ required,
258
+ ...attrs
259
+ };
260
+ }
261
+ function _composeNthFieldGroup({ name, label, required, nthFieldGroup, ...attrs }) {
262
+ return [
263
+ {
264
+ ...nthFieldGroup,
265
+ type: supportedTypes.GROUP_ARRAY,
266
+ name,
267
+ label,
268
+ required,
269
+ ...attrs
270
+ }
271
+ ];
272
+ }
273
+ function _composeFieldCheckbox({
274
+ required = true,
275
+ name,
276
+ label,
277
+ description,
278
+ default: defaultValue,
279
+ checkboxValue,
280
+ ...attrs
281
+ }) {
282
+ return {
283
+ type: supportedTypes.CHECKBOX,
284
+ required,
285
+ name,
286
+ label,
287
+ description,
288
+ checkboxValue,
289
+ ...defaultValue && { default: defaultValue },
290
+ ...attrs
291
+ };
292
+ }
293
+ function _composeFieldset({ name, label, fields, variant, ...attrs }) {
294
+ return {
295
+ type: supportedTypes.FIELDSET,
296
+ name,
297
+ label,
298
+ fields,
299
+ variant,
300
+ ...attrs
301
+ };
302
+ }
303
+ var _composeFieldArbitraryClosure = (inputType) => (attrs) => ({
304
+ type: inputType,
305
+ ...attrs
306
+ });
307
+ var inputTypeMap = {
308
+ text: _composeFieldText,
309
+ select: _composeFieldSelect,
310
+ radio: _composeFieldRadio,
311
+ date: _composeFieldDate,
312
+ number: _composeFieldNumber,
313
+ "group-array": _composeNthFieldGroup,
314
+ fieldset: _composeFieldset,
315
+ file: _composeFieldFile,
316
+ email: _composeFieldEmail,
317
+ checkbox: _composeFieldCheckbox
318
+ };
319
+ function _composeFieldCustomClosure(defaultComposeFn) {
320
+ return ({ fieldCustomization, ...attrs }) => {
321
+ const { description, ...restFieldCustomization } = fieldCustomization;
322
+ const fieldDescription = getFieldDescription(attrs, fieldCustomization);
323
+ const { nthFieldGroup, ...restAttrs } = attrs;
324
+ const commonAttrs = {
325
+ ...restAttrs,
326
+ ...restFieldCustomization,
327
+ ...fieldDescription
328
+ };
329
+ if (attrs.inputType === supportedTypes.GROUP_ARRAY) {
330
+ return [
331
+ {
332
+ ...nthFieldGroup,
333
+ ...commonAttrs
334
+ }
335
+ ];
336
+ }
337
+ return {
338
+ ...defaultComposeFn(attrs),
339
+ ...commonAttrs
340
+ };
341
+ };
342
+ }
343
+
344
+ // src/utils.js
345
+ function convertDiskSizeFromTo(from, to) {
346
+ const units = ["bytes", "kb", "mb"];
347
+ return function convert(value) {
348
+ return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
349
+ };
350
+ }
351
+ function containsHTML(str = "") {
352
+ return /<[a-z][\s\S]*>/i.test(str);
353
+ }
354
+ function wrapWithSpan(html, properties = {}) {
355
+ const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
356
+ return `<span ${attributes}>${html}</span>`;
357
+ }
358
+ function hasProperty(object2, propertyName) {
359
+ return Object.prototype.hasOwnProperty.call(object2, propertyName);
360
+ }
361
+
362
+ // src/yupSchema.js
363
+ var import_flow = __toESM(require("lodash/flow"));
364
+ var import_noop = __toESM(require("lodash/noop"));
365
+ var import_randexp = require("randexp");
366
+ var import_yup = require("yup");
367
+ var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
368
+ var baseString = (0, import_yup.string)().trim();
369
+ var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
370
+ var convertBytesToKB = convertDiskSizeFromTo("Bytes", "KB");
371
+ var convertKbBytesToMB = convertDiskSizeFromTo("KB", "MB");
372
+ var yupSchemas = {
373
+ text: (0, import_yup.string)().trim().nullable(),
374
+ select: (0, import_yup.string)().trim().nullable(),
375
+ radio: (0, import_yup.string)().trim().nullable(),
376
+ date: (0, import_yup.string)().nullable().trim().matches(
377
+ /(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
378
+ `Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
379
+ ),
380
+ number: (0, import_yup.number)().typeError("The value must be a number").nullable(),
381
+ file: (0, import_yup.array)().nullable(),
382
+ email: (0, import_yup.string)().trim().email("Please enter a valid email address").nullable(),
383
+ fieldset: (0, import_yup.object)().nullable(),
384
+ checkbox: (0, import_yup.string)().trim().nullable(),
385
+ checkboxBool: (0, import_yup.boolean)(),
386
+ multiple: {
387
+ select: (0, import_yup.array)().nullable(),
388
+ "group-array": (0, import_yup.array)().nullable()
389
+ }
390
+ };
391
+ var yupSchemasToJsonTypes = {
392
+ string: yupSchemas.text,
393
+ number: yupSchemas.number,
394
+ integer: yupSchemas.number,
395
+ object: yupSchemas.fieldset,
396
+ array: yupSchemas.multiple.select,
397
+ boolean: yupSchemas.checkboxBool,
398
+ null: import_noop.default
399
+ };
400
+ function getRequiredErrorMessage(inputType, { inlineError, configError }) {
401
+ if (inlineError)
402
+ return inlineError;
403
+ if (configError)
404
+ return configError;
405
+ if (inputType === supportedTypes.CHECKBOX)
406
+ return "Please acknowledge this field";
407
+ return "Required field";
408
+ }
409
+ var getJsonTypeInArray = (jsonType) => Array.isArray(jsonType) ? jsonType.find((val) => val !== "null") : jsonType;
410
+ function buildYupSchema(field, config) {
411
+ const { inputType, jsonType: jsonTypeValue, errorMessage = {}, ...propertyFields } = field;
412
+ const isCheckboxBoolean = typeof propertyFields.checkboxValue === "boolean";
413
+ let baseSchema;
414
+ const jsonType = getJsonTypeInArray(jsonTypeValue);
415
+ const errorMessageFromConfig = config?.inputTypes?.[inputType]?.errorMessage || {};
416
+ if (propertyFields.multiple) {
417
+ baseSchema = yupSchemas.multiple[inputType] || yupSchemasToJsonTypes.array;
418
+ } else if (isCheckboxBoolean) {
419
+ baseSchema = yupSchemas.checkboxBool;
420
+ } else {
421
+ baseSchema = yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
422
+ }
423
+ if (!baseSchema) {
424
+ return import_noop.default;
425
+ }
426
+ const randomPlaceholder = propertyFields.pattern && (0, import_randexp.randexp)(propertyFields.pattern);
427
+ const requiredMessage = getRequiredErrorMessage(inputType, {
428
+ inlineError: errorMessage.required,
429
+ configError: errorMessageFromConfig.required
430
+ });
431
+ function withRequired(yupSchema) {
432
+ if (isCheckboxBoolean) {
433
+ return yupSchema.oneOf([true], requiredMessage).required(requiredMessage);
434
+ }
435
+ return yupSchema.required(requiredMessage);
436
+ }
437
+ function withMin(yupSchema) {
438
+ return yupSchema.min(
439
+ propertyFields.minimum,
440
+ (message) => errorMessage.minimum ?? errorMessageFromConfig.minimum ?? `Must be greater or equal to ${message.min}`
441
+ );
442
+ }
443
+ function withMinLength(yupSchema) {
444
+ return yupSchema.min(
445
+ propertyFields.minLength,
446
+ (message) => errorMessage.minLength ?? errorMessageFromConfig.minLength ?? `Please insert at least ${message.min} characters`
447
+ );
448
+ }
449
+ function withMax(yupSchema) {
450
+ return yupSchema.max(
451
+ propertyFields.maximum,
452
+ (message) => errorMessage.maximum ?? errorMessageFromConfig.maximum ?? `Must be smaller or equal to ${message.max}`
453
+ );
454
+ }
455
+ function withMaxLength(yupSchema) {
456
+ return yupSchema.max(
457
+ propertyFields.maxLength,
458
+ (message) => errorMessage.maxLength ?? errorMessageFromConfig.maxLength ?? `Please insert up to ${message.max} characters`
459
+ );
460
+ }
461
+ function withMatches(yupSchema) {
462
+ return yupSchema.matches(
463
+ propertyFields.pattern,
464
+ () => errorMessage.pattern ?? errorMessageFromConfig.pattern ?? `Must have a valid format. E.g. ${randomPlaceholder}`
465
+ );
466
+ }
467
+ function withMaxFileSize(yupSchema) {
468
+ return yupSchema.test(
469
+ "isValidFileSize",
470
+ errorMessage.maxFileSize ?? errorMessageFromConfig.maxFileSize ?? `File size too large. The limit is ${convertKbBytesToMB(propertyFields.maxFileSize)} MB.`,
471
+ (files) => !files?.some((file) => convertBytesToKB(file.size) > propertyFields.maxFileSize)
472
+ );
473
+ }
474
+ function withFileFormat(yupSchema) {
475
+ return yupSchema.test(
476
+ "isSupportedFormat",
477
+ errorMessage.accept ?? errorMessageFromConfig.accept ?? `Unsupported file format. The acceptable formats are ${propertyFields.accept}.`,
478
+ (files) => files && files?.length > 0 ? files.some((file) => {
479
+ const fileType = file.name.split(".").pop();
480
+ return propertyFields.accept.includes(fileType.toLowerCase());
481
+ }) : true
482
+ );
483
+ }
484
+ function withBaseSchema() {
485
+ const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
486
+ if (customErrorMsg) {
487
+ return baseSchema.typeError(customErrorMsg);
488
+ }
489
+ return baseSchema;
490
+ }
491
+ function buildFieldSetSchema(innerFields) {
492
+ const fieldSetShape = {};
493
+ innerFields.forEach((fieldSetfield) => {
494
+ if (fieldSetfield.fields) {
495
+ fieldSetShape[fieldSetfield.name] = (0, import_yup.object)().shape(
496
+ buildFieldSetSchema(fieldSetfield.fields)
497
+ );
498
+ } else {
499
+ fieldSetShape[fieldSetfield.name] = buildYupSchema(
500
+ {
501
+ ...fieldSetfield,
502
+ inputType: fieldSetfield.type
503
+ },
504
+ config
505
+ )();
506
+ }
507
+ });
508
+ return fieldSetShape;
509
+ }
510
+ function buildGroupArraySchema() {
511
+ return (0, import_yup.object)().shape(
512
+ propertyFields.nthFieldGroup.fields().reduce(
513
+ (schema, groupArrayField) => ({
514
+ ...schema,
515
+ [groupArrayField.name]: buildYupSchema(groupArrayField, config)()
516
+ }),
517
+ {}
518
+ )
519
+ );
520
+ }
521
+ const validators = [withBaseSchema];
522
+ if (inputType === supportedTypes.GROUP_ARRAY) {
523
+ validators[0] = () => withBaseSchema().of(buildGroupArraySchema());
524
+ } else if (inputType === supportedTypes.FIELDSET) {
525
+ validators[0] = () => withBaseSchema().shape(buildFieldSetSchema(propertyFields.fields));
526
+ }
527
+ if (propertyFields.required) {
528
+ validators.push(withRequired);
529
+ }
530
+ if (typeof propertyFields.minimum !== "undefined") {
531
+ validators.push(withMin);
532
+ }
533
+ if (typeof propertyFields.minLength !== "undefined") {
534
+ validators.push(withMinLength);
535
+ }
536
+ if (propertyFields.maximum) {
537
+ validators.push(withMax);
538
+ }
539
+ if (propertyFields.maxLength) {
540
+ validators.push(withMaxLength);
541
+ }
542
+ if (propertyFields.pattern) {
543
+ validators.push(withMatches);
544
+ }
545
+ if (propertyFields.maxFileSize) {
546
+ validators.push(withMaxFileSize);
547
+ }
548
+ if (propertyFields.accept) {
549
+ validators.push(withFileFormat);
550
+ }
551
+ return (0, import_flow.default)(validators);
552
+ }
553
+ function getNoSortEdges(fields = []) {
554
+ return fields.reduce((list, field) => {
555
+ if (field.noSortEdges) {
556
+ list.push(field.name);
557
+ }
558
+ return list;
559
+ }, []);
560
+ }
561
+ function getSchema(fields = [], config) {
562
+ const newSchema = {};
563
+ fields.forEach((field) => {
564
+ if (field.schema) {
565
+ if (field.name) {
566
+ if (field.inputType === supportedTypes.FIELDSET) {
567
+ const fieldsetSchema = buildYupSchema(field, config)();
568
+ newSchema[field.name] = fieldsetSchema;
569
+ } else {
570
+ newSchema[field.name] = field.schema;
571
+ }
572
+ } else {
573
+ Object.assign(newSchema, getSchema(field.fields, config));
574
+ }
575
+ }
576
+ });
577
+ return newSchema;
578
+ }
579
+ function buildCompleteYupSchema(fields, config) {
580
+ return (0, import_yup.object)().shape(getSchema(fields, config), getNoSortEdges(fields));
581
+ }
582
+
583
+ // src/helpers.js
584
+ function hasType(type, typeName) {
585
+ return Array.isArray(type) ? type.includes(typeName) : type === typeName;
586
+ }
587
+ function getField(fieldName, fields) {
588
+ return fields.find(({ name }) => name === fieldName);
589
+ }
590
+ function validateFieldSchema(field, value) {
591
+ const validator = buildYupSchema(field);
592
+ return validator().isValidSync(value);
593
+ }
594
+ function compareFormValueWithSchemaValue(formValue, schemaValue) {
595
+ const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
596
+ return String(formValue) === String(currentPropertyValue);
597
+ }
598
+ function checkIfConditionMatches(node, formValues, formFields) {
599
+ return Object.keys(node.if.properties).every((name) => {
600
+ const currentProperty = node.if.properties[name];
601
+ const value = formValues[name];
602
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
603
+ value === null;
604
+ const hasIfExplicit = node.if.required?.includes(name);
605
+ if (hasEmptyValue && !hasIfExplicit) {
606
+ return true;
607
+ }
608
+ if (hasProperty(currentProperty, "const")) {
609
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
610
+ }
611
+ if (currentProperty.contains?.pattern) {
612
+ const formValue = value || [];
613
+ if (Array.isArray(formValue)) {
614
+ const pattern = new RegExp(currentProperty.contains.pattern);
615
+ return (value || []).some((item) => pattern.test(item));
616
+ }
617
+ }
618
+ if (currentProperty.enum) {
619
+ return currentProperty.enum.includes(value);
620
+ }
621
+ const { inputType } = getField(name, formFields);
622
+ return validateFieldSchema({ ...currentProperty, inputType, required: true }, value);
623
+ });
624
+ }
625
+ function isFieldFilled(fieldValue) {
626
+ return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
627
+ }
628
+ function findFirstAnyOfMatch(nodes, formValues) {
629
+ return nodes.find(
630
+ ({ required }) => required?.some((fieldName) => isFieldFilled(formValues[fieldName]))
631
+ ) || nodes[0];
632
+ }
633
+ function getPrefillSubFieldValues(field, defaultValues, parentFieldKeyPath) {
634
+ let initialValue = defaultValues ?? {};
635
+ let fieldKeyPath = field.name;
636
+ if (parentFieldKeyPath) {
637
+ fieldKeyPath = fieldKeyPath ? `${parentFieldKeyPath}.${fieldKeyPath}` : parentFieldKeyPath;
638
+ }
639
+ const subFields = field.fields;
640
+ if (Array.isArray(subFields)) {
641
+ const subFieldValues = {};
642
+ subFields.forEach((subField) => {
643
+ Object.assign(
644
+ subFieldValues,
645
+ getPrefillSubFieldValues(subField, initialValue[field.name], fieldKeyPath)
646
+ );
647
+ });
648
+ if (field.inputType === supportedTypes.FIELDSET && field.valueGroupingDisabled) {
649
+ Object.assign(initialValue, subFieldValues);
650
+ } else {
651
+ initialValue[field.name] = subFieldValues;
652
+ }
653
+ } else {
654
+ initialValue = getPrefillValues([field], initialValue);
655
+ }
656
+ return initialValue;
657
+ }
658
+ function getPrefillValues(fields, initialValues = {}) {
659
+ fields.forEach((field) => {
660
+ const fieldName = field.name;
661
+ switch (field.type) {
662
+ case supportedTypes.GROUP_ARRAY: {
663
+ initialValues[fieldName] = initialValues[fieldName]?.map(
664
+ (subFieldValues) => getPrefillValues(field.fields(), subFieldValues)
665
+ );
666
+ break;
667
+ }
668
+ case supportedTypes.FIELDSET: {
669
+ const subFieldValues = getPrefillSubFieldValues(field, initialValues);
670
+ Object.assign(initialValues, subFieldValues);
671
+ break;
672
+ }
673
+ default: {
674
+ if (!initialValues[fieldName]) {
675
+ initialValues[fieldName] = field.default;
676
+ }
677
+ break;
678
+ }
679
+ }
680
+ });
681
+ return initialValues;
682
+ }
683
+ function updateField(field, requiredFields, node, formValues) {
684
+ if (!field) {
685
+ return;
686
+ }
687
+ const fieldIsRequired = requiredFields.has(field.name);
688
+ if (node.properties && hasProperty(node.properties, field.name)) {
689
+ field.isVisible = !!node.properties[field.name];
690
+ }
691
+ if (fieldIsRequired) {
692
+ field.isVisible = true;
693
+ }
694
+ const updateValues = (fieldValues) => Object.entries(fieldValues).forEach(([key, value]) => {
695
+ field[key] = typeof value === "function" ? value() : value;
696
+ if (key === "value") {
697
+ const readOnlyPropertyWasUpdated = typeof fieldValues.readOnly !== "undefined";
698
+ const isReadonlyByDefault = field.readOnly;
699
+ const isReadonly = readOnlyPropertyWasUpdated ? fieldValues.readOnly : isReadonlyByDefault;
700
+ if (!isReadonly && (value === null || field.inputType === "checkbox")) {
701
+ field.value = void 0;
702
+ }
703
+ }
704
+ });
705
+ if (field.calculateConditionalProperties) {
706
+ const newFieldValues = field.calculateConditionalProperties(fieldIsRequired, node);
707
+ updateValues(newFieldValues);
708
+ }
709
+ if (field.calculateCustomValidationProperties) {
710
+ const newFieldValues = field.calculateCustomValidationProperties(
711
+ fieldIsRequired,
712
+ node,
713
+ formValues
714
+ );
715
+ updateValues(newFieldValues);
716
+ }
717
+ }
718
+ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */ new Set()) {
719
+ const requiredFields = new Set(accRequired);
720
+ Object.keys(node.properties ?? []).forEach((fieldName) => {
721
+ const field = getField(fieldName, formFields);
722
+ updateField(field, requiredFields, node, formValues);
723
+ });
724
+ node.required?.forEach((fieldName) => {
725
+ requiredFields.add(fieldName);
726
+ updateField(getField(fieldName, formFields), requiredFields, node, formValues);
727
+ });
728
+ if (node.if) {
729
+ const matchesCondition = checkIfConditionMatches(node, formValues, formFields);
730
+ if (matchesCondition && node.then) {
731
+ const { required: branchRequired } = processNode(
732
+ node.then,
733
+ formValues,
734
+ formFields,
735
+ requiredFields
736
+ );
737
+ branchRequired.forEach((field) => requiredFields.add(field));
738
+ } else if (node.else) {
739
+ const { required: branchRequired } = processNode(
740
+ node.else,
741
+ formValues,
742
+ formFields,
743
+ requiredFields
744
+ );
745
+ branchRequired.forEach((field) => requiredFields.add(field));
746
+ }
747
+ }
748
+ if (node.anyOf) {
749
+ const firstMatchOfAnyOf = findFirstAnyOfMatch(node.anyOf, formValues);
750
+ firstMatchOfAnyOf.required?.forEach((fieldName) => {
751
+ requiredFields.add(fieldName);
752
+ });
753
+ node.anyOf.forEach(({ required = [] }) => {
754
+ required.forEach((fieldName) => {
755
+ const field = getField(fieldName, formFields);
756
+ updateField(field, requiredFields, node, formValues);
757
+ });
758
+ });
759
+ }
760
+ if (node.allOf) {
761
+ node.allOf.map((allOfNode) => processNode(allOfNode, formValues, formFields, requiredFields)).forEach(({ required: allOfItemRequired }) => {
762
+ allOfItemRequired.forEach(requiredFields.add, requiredFields);
763
+ });
764
+ }
765
+ if (node.properties) {
766
+ Object.entries(node.properties).forEach(([name, nestedNode]) => {
767
+ const inputType = getInputType(nestedNode);
768
+ if (inputType === supportedTypes.FIELDSET) {
769
+ processNode(nestedNode, formValues[name] || {}, getField(name, formFields).fields);
770
+ }
771
+ });
772
+ }
773
+ return {
774
+ required: requiredFields
775
+ };
776
+ }
777
+ function clearValuesIfNotVisible(fields, formValues) {
778
+ fields.forEach(({ isVisible = true, name, inputType, fields: nestedFields }) => {
779
+ if (!isVisible) {
780
+ formValues[name] = null;
781
+ }
782
+ if (inputType === supportedTypes.FIELDSET && nestedFields && formValues[name]) {
783
+ clearValuesIfNotVisible(nestedFields, formValues[name]);
784
+ }
785
+ });
786
+ }
787
+ function updateFieldsProperties(fields, formValues, jsonSchema) {
788
+ if (!jsonSchema?.properties) {
789
+ return;
790
+ }
791
+ processNode(jsonSchema, formValues, fields);
792
+ clearValuesIfNotVisible(fields, formValues);
793
+ }
794
+ var notNullOption = (opt) => opt.const !== null;
795
+ function getFieldOptions(node, presentation) {
796
+ function convertToOptions(nodeOptions) {
797
+ return nodeOptions.filter(notNullOption).map(({ title, const: cons, ...item }) => ({
798
+ label: title,
799
+ value: cons,
800
+ ...item
801
+ }));
802
+ }
803
+ if (presentation.options) {
804
+ return presentation.options;
805
+ }
806
+ if (node.oneOf) {
807
+ return convertToOptions(node.oneOf);
808
+ }
809
+ if (node.items?.anyOf) {
810
+ return convertToOptions(node.items.anyOf);
811
+ }
812
+ return null;
813
+ }
814
+ function extractParametersFromNode(schemaNode) {
815
+ if (!schemaNode) {
816
+ return {};
817
+ }
818
+ const presentation = pickXKey(schemaNode, "presentation") ?? {};
819
+ const errorMessage = pickXKey(schemaNode, "errorMessage") ?? {};
820
+ const node = (0, import_omit.default)(schemaNode, ["x-jsf-presentation", "presentation"]);
821
+ const description = presentation?.description || node.description;
822
+ const statementDescription = containsHTML(presentation.statement?.description) ? wrapWithSpan(presentation.statement.description, { class: "jsf-statement" }) : presentation.statement?.description;
823
+ return (0, import_omitBy.default)(
824
+ {
825
+ label: node.title,
826
+ readOnly: node.readOnly,
827
+ ...node.deprecated && {
828
+ deprecated: {
829
+ description: presentation.deprecated?.description
830
+ // @TODO/@IDEA These might be useful down the road :thinking:
831
+ // version: presentation.deprecated.version, // e.g. "1.1"
832
+ // replacement: presentation.deprecated.replacement, // e.g. ['contract_duration_type']
833
+ }
834
+ },
835
+ pattern: node.pattern,
836
+ options: getFieldOptions(node, presentation),
837
+ items: node.items,
838
+ maxLength: node.maxLength,
839
+ minLength: node.minLength,
840
+ minimum: node.minimum,
841
+ maximum: node.maximum,
842
+ maxFileSize: node.maxFileSize,
843
+ // @deprecated in favor of presentation.maxFileSize
844
+ default: node.default,
845
+ // Checkboxes conditions
846
+ // — For checkboxes that only accept one value (string)
847
+ ...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
848
+ // - For checkboxes with boolean value
849
+ ...presentation?.inputType === "checkbox" && node.type === "boolean" && {
850
+ // true is what describes this checkbox as a boolean, regardless if its required or not
851
+ checkboxValue: true
852
+ },
853
+ ...hasType(node.type, "array") && {
854
+ multiple: true
855
+ },
856
+ // Handle [name].presentation
857
+ ...presentation,
858
+ description: containsHTML(description) ? wrapWithSpan(description, {
859
+ class: "jsf-description"
860
+ }) : description,
861
+ extra: containsHTML(presentation.extra) ? wrapWithSpan(presentation.extra, { class: "jsf-extra" }) : presentation.extra,
862
+ statement: presentation.statement && {
863
+ ...presentation.statement,
864
+ description: statementDescription
865
+ },
866
+ // Support scoped conditions (fieldsets)
867
+ if: node.if,
868
+ then: node.then,
869
+ else: node.else,
870
+ anyOf: node.anyOf,
871
+ allOf: node.allOf,
872
+ errorMessage
873
+ },
874
+ import_isNil.default
875
+ );
876
+ }
877
+ function yupToFormErrors(yupError) {
878
+ if (!yupError) {
879
+ return yupError;
880
+ }
881
+ const errors = {};
882
+ if (yupError.inner) {
883
+ if (yupError.inner.length === 0) {
884
+ return (0, import_set.default)(errors, yupError.path, yupError.message);
885
+ }
886
+ yupError.inner.forEach((err) => {
887
+ if (!(0, import_get2.default)(errors, err.path)) {
888
+ (0, import_set.default)(errors, err.path, err.message);
889
+ }
890
+ });
891
+ }
892
+ return errors;
893
+ }
894
+ var handleValuesChange = (fields, jsonSchema, config) => (values) => {
895
+ updateFieldsProperties(fields, values, jsonSchema);
896
+ const lazySchema = (0, import_yup2.lazy)(() => buildCompleteYupSchema(fields, config));
897
+ let errors;
898
+ try {
899
+ lazySchema.validateSync(values, {
900
+ abortEarly: false
901
+ });
902
+ } catch (err) {
903
+ if (err.name === "ValidationError") {
904
+ errors = err;
905
+ } else {
906
+ console.warn(`Warning: An unhandled error was caught during validationSchema`, err);
907
+ }
908
+ }
909
+ return {
910
+ yupError: errors,
911
+ formErrors: yupToFormErrors(errors)
912
+ };
913
+ };
914
+
915
+ // src/calculateConditionalProperties.js
916
+ function isFieldRequired(node, inputName) {
917
+ if (node?.required) {
918
+ return node.required.includes(inputName);
919
+ }
920
+ return false;
921
+ }
922
+ function rebuildInnerFieldsRequiredProperty(fields, property) {
923
+ if (property?.properties) {
924
+ return fields.map((field) => {
925
+ if (field.fields) {
926
+ return {
927
+ ...field,
928
+ fields: rebuildInnerFieldsRequiredProperty(field.fields, property.properties[field.name])
929
+ };
930
+ }
931
+ return {
932
+ ...field,
933
+ required: isFieldRequired(property, field.name)
934
+ };
935
+ });
936
+ }
937
+ return fields.map((field) => ({
938
+ ...field,
939
+ required: isFieldRequired(property, field.name)
940
+ }));
941
+ }
942
+ function calculateConditionalProperties(fieldParams, customProperties) {
943
+ return (isRequired, conditionBranch) => {
944
+ const conditionalProperty = conditionBranch?.properties?.[fieldParams.name];
945
+ if (conditionalProperty) {
946
+ const presentation = pickXKey(conditionalProperty, "presentation") ?? {};
947
+ const fieldDescription = getFieldDescription(conditionalProperty, customProperties);
948
+ const newFieldParams = extractParametersFromNode({
949
+ ...conditionalProperty,
950
+ ...fieldDescription
951
+ });
952
+ let fieldSetFields;
953
+ if (fieldParams.inputType === supportedTypes.FIELDSET) {
954
+ fieldSetFields = rebuildInnerFieldsRequiredProperty(
955
+ fieldParams.fields,
956
+ conditionalProperty
957
+ );
958
+ newFieldParams.fields = fieldSetFields;
959
+ }
960
+ const base = {
961
+ isVisible: true,
962
+ required: isRequired,
963
+ ...presentation?.inputType && { type: presentation.inputType },
964
+ schema: buildYupSchema({
965
+ ...fieldParams,
966
+ ...newFieldParams,
967
+ // If there are inner fields (case of fieldset) they need to be updated based on the condition
968
+ fields: fieldSetFields,
969
+ required: isRequired
970
+ })
971
+ };
972
+ return (0, import_omit2.default)((0, import_merge2.default)(base, presentation, newFieldParams), ["inputType"]);
973
+ }
974
+ const isVisible = isRequired;
975
+ return {
976
+ isVisible,
977
+ required: isRequired,
978
+ schema: buildYupSchema({
979
+ ...fieldParams,
980
+ ...extractParametersFromNode(conditionBranch),
981
+ required: isRequired
982
+ })
983
+ };
984
+ };
985
+ }
986
+
987
+ // src/calculateCustomValidationProperties.js
988
+ var import_inRange = __toESM(require("lodash/inRange"));
989
+ var import_isFunction2 = __toESM(require("lodash/isFunction"));
990
+ var import_isNil2 = __toESM(require("lodash/isNil"));
991
+ var import_isObject = __toESM(require("lodash/isObject"));
992
+ var import_mapValues = __toESM(require("lodash/mapValues"));
993
+ var import_pick = __toESM(require("lodash/pick"));
994
+ var SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS = ["minimum", "maximum"];
995
+ var isCustomValidationAllowed = (fieldParams) => (customValidation, customValidationKey) => {
996
+ if ((0, import_isNil2.default)(customValidation)) {
997
+ return false;
998
+ }
999
+ const { minimum, maximum } = fieldParams;
1000
+ const isAllowed = (0, import_inRange.default)(
1001
+ customValidation,
1002
+ minimum ?? -Infinity,
1003
+ maximum ? maximum + 1 : Infinity
1004
+ );
1005
+ if (!isAllowed) {
1006
+ const errorMessage = `Custom validation for ${fieldParams.name} is not allowed because ${customValidationKey}:${customValidation} is less strict than the original range: ${minimum} to ${maximum}`;
1007
+ if (true) {
1008
+ throw new Error(errorMessage);
1009
+ } else {
1010
+ console.warn(errorMessage);
1011
+ }
1012
+ }
1013
+ return isAllowed;
1014
+ };
1015
+ function calculateCustomValidationProperties(fieldParams, customProperties) {
1016
+ return (isRequired, conditionBranch, formValues) => {
1017
+ const params = { ...fieldParams, ...conditionBranch?.properties?.[fieldParams.name] };
1018
+ const presentation = pickXKey(params, "presentation") ?? {};
1019
+ const supportedParams = (0, import_pick.default)(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS);
1020
+ const checkIfAllowed = isCustomValidationAllowed(params);
1021
+ const customErrorMessages = [];
1022
+ const fieldParamsWithNewValidation = (0, import_mapValues.default)(
1023
+ supportedParams,
1024
+ (customValidationValue, customValidationKey) => {
1025
+ const originalValidation = params[customValidationKey];
1026
+ const customValidation = (0, import_isFunction2.default)(customValidationValue) ? customValidationValue(formValues, params) : customValidationValue;
1027
+ if ((0, import_isObject.default)(customValidation)) {
1028
+ if (checkIfAllowed(customValidation[customValidationKey], customValidationKey)) {
1029
+ customErrorMessages.push(pickXKey(customValidation, "errorMessage"));
1030
+ return customValidation[customValidationKey];
1031
+ }
1032
+ return originalValidation;
1033
+ }
1034
+ return checkIfAllowed(customValidation, customValidationKey) ? customValidation : originalValidation;
1035
+ }
1036
+ );
1037
+ const errorMessage = Object.assign({ ...params.errorMessage }, ...customErrorMessages);
1038
+ return {
1039
+ ...params,
1040
+ ...fieldParamsWithNewValidation,
1041
+ type: presentation?.inputType || params.inputType,
1042
+ errorMessage,
1043
+ required: isRequired,
1044
+ schema: buildYupSchema({
1045
+ ...params,
1046
+ ...fieldParamsWithNewValidation,
1047
+ errorMessage,
1048
+ required: isRequired
1049
+ })
1050
+ };
1051
+ };
1052
+ }
1053
+
1054
+ // src/createHeadlessForm.js
1055
+ function sortByOrderOrPosition(a, b, order) {
1056
+ if (order) {
1057
+ return order.indexOf(a.name) - order.indexOf(b.name);
1058
+ }
1059
+ return a.position - b.position;
1060
+ }
1061
+ function removeInvalidAttributes(fields) {
1062
+ return (0, import_omit3.default)(fields, ["items", "maxFileSize", "isDynamic"]);
1063
+ }
1064
+ function buildFieldParameters(name, fieldProperties, required = [], config = {}) {
1065
+ const { position } = pickXKey(fieldProperties, "presentation") ?? {};
1066
+ let fields;
1067
+ const inputType = getInputType(fieldProperties, config.strictInputType, name);
1068
+ if (inputType === supportedTypes.FIELDSET) {
1069
+ fields = getFieldsFromJSONSchema(fieldProperties, {
1070
+ customProperties: (0, import_get3.default)(config, `customProperties.${name}`, {})
1071
+ });
1072
+ }
1073
+ const result = {
1074
+ name,
1075
+ inputType,
1076
+ jsonType: fieldProperties.type,
1077
+ type: inputType,
1078
+ // @deprecated in favor of inputType,
1079
+ required: required?.includes(name) ?? false,
1080
+ fields,
1081
+ position,
1082
+ ...extractParametersFromNode(fieldProperties)
1083
+ };
1084
+ return (0, import_omitBy2.default)(result, import_isNil3.default);
1085
+ }
1086
+ function convertJSONSchemaPropertiesToFieldParameters({ properties, required, "x-jsf-order": order }, config = {}) {
1087
+ const sortFields = (a, b) => sortByOrderOrPosition(a, b, order);
1088
+ return Object.entries(properties).filter(([, value]) => typeof value === "object").map(([key, value]) => buildFieldParameters(key, value, required, config)).sort(sortFields).map(({ position, ...fieldParams }) => fieldParams);
1089
+ }
1090
+ function applyFieldsDependencies(fieldsParameters, node) {
1091
+ if (node?.then) {
1092
+ fieldsParameters.filter(
1093
+ ({ name }) => node.then?.properties?.[name] || node.then?.required?.includes(name) || node.else?.properties?.[name] || node.else?.required?.includes(name)
1094
+ ).forEach((property) => {
1095
+ property.isDynamic = true;
1096
+ });
1097
+ applyFieldsDependencies(fieldsParameters, node.then);
1098
+ }
1099
+ if (node?.anyOf) {
1100
+ fieldsParameters.filter(({ name }) => node.anyOf.some(({ required }) => required?.includes(name))).forEach((property) => {
1101
+ property.isDynamic = true;
1102
+ });
1103
+ applyFieldsDependencies(fieldsParameters, node.then);
1104
+ }
1105
+ if (node?.allOf) {
1106
+ node.allOf.forEach((condition) => {
1107
+ applyFieldsDependencies(fieldsParameters, condition);
1108
+ });
1109
+ }
1110
+ }
1111
+ function getCustomPropertiesForField(fieldParams, config) {
1112
+ return config?.customProperties?.[fieldParams.name];
1113
+ }
1114
+ function getComposeFunctionForField(fieldParams, hasCustomizations) {
1115
+ const composeFn = inputTypeMap[fieldParams.inputType] || _composeFieldArbitraryClosure(fieldParams.inputType);
1116
+ if (hasCustomizations) {
1117
+ return _composeFieldCustomClosure(composeFn);
1118
+ }
1119
+ return composeFn;
1120
+ }
1121
+ function buildField(fieldParams, config, scopedJsonSchema) {
1122
+ const customProperties = getCustomPropertiesForField(fieldParams, config);
1123
+ const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
1124
+ const yupSchema = buildYupSchema(fieldParams, config);
1125
+ const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
1126
+ const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
1127
+ fieldParams,
1128
+ customProperties
1129
+ );
1130
+ const hasCustomValidations = !!customProperties && (0, import_size.default)((0, import_pick2.default)(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS)) > 0;
1131
+ const finalFieldParams = {
1132
+ // invalid attribute cleanup
1133
+ ...removeInvalidAttributes(fieldParams),
1134
+ // calculateConditionalProperties function if needed
1135
+ ...!!calculateConditionalFieldsClosure && {
1136
+ calculateConditionalProperties: calculateConditionalFieldsClosure
1137
+ },
1138
+ // calculateCustomValidationProperties function if needed
1139
+ ...hasCustomValidations && {
1140
+ calculateCustomValidationProperties: calculateCustomValidationPropertiesClosure
1141
+ },
1142
+ // field customization properties
1143
+ ...customProperties && { fieldCustomization: customProperties },
1144
+ // base schema
1145
+ schema: yupSchema(),
1146
+ scopedJsonSchema
1147
+ };
1148
+ return composeFn(finalFieldParams);
1149
+ }
1150
+ function getFieldsFromJSONSchema(scopedJsonSchema, config) {
1151
+ if (!scopedJsonSchema) {
1152
+ return [];
1153
+ }
1154
+ const fieldParamsList = convertJSONSchemaPropertiesToFieldParameters(scopedJsonSchema, config);
1155
+ applyFieldsDependencies(fieldParamsList, scopedJsonSchema);
1156
+ const fields = [];
1157
+ fieldParamsList.forEach((fieldParams) => {
1158
+ if (fieldParams.inputType === "group-array") {
1159
+ const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
1160
+ const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
1161
+ groupArrayItem.nameKey = groupArrayItem.name;
1162
+ const customProperties = null;
1163
+ const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
1164
+ return composeFn(groupArrayItem);
1165
+ });
1166
+ fieldParams.nameKey = fieldParams.name;
1167
+ fieldParams.nthFieldGroup = {
1168
+ name: fieldParams.name,
1169
+ label: fieldParams.label,
1170
+ description: fieldParams.description,
1171
+ fields: () => groupArrayFields,
1172
+ addFieldText: fieldParams.addFieldText
1173
+ };
1174
+ buildField(fieldParams, config, scopedJsonSchema).forEach((groupField) => {
1175
+ fields.push(groupField);
1176
+ });
1177
+ } else {
1178
+ fields.push(buildField(fieldParams, config, scopedJsonSchema));
1179
+ }
1180
+ });
1181
+ return fields;
1182
+ }
1183
+ function createHeadlessForm(jsonSchema, customConfig = {}) {
1184
+ const config = {
1185
+ strictInputType: true,
1186
+ ...customConfig
1187
+ };
1188
+ try {
1189
+ const fields = getFieldsFromJSONSchema(jsonSchema, config);
1190
+ const handleValidation = handleValuesChange(fields, jsonSchema, config);
1191
+ updateFieldsProperties(fields, getPrefillValues(fields, config.initialValues), jsonSchema);
1192
+ return {
1193
+ fields,
1194
+ handleValidation,
1195
+ isError: false
1196
+ };
1197
+ } catch (error) {
1198
+ console.error("JSON Schema invalid!", error);
1199
+ return {
1200
+ fields: [],
1201
+ isError: true,
1202
+ error
1203
+ };
1204
+ }
1205
+ }