@remoteoss/json-schema-form 0.5.0-dev.20230810172154 → 0.5.1-dev.20230913083845
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/CHANGELOG.md +19 -0
- package/dist/index.cjs +379 -37
- package/dist/index.js +379 -37
- package/dist/standalone.js +757 -37
- package/package.json +2 -1
- package/src/tests/const.test.js +98 -0
- package/src/tests/createHeadlessForm.test.js +34 -12
- package/src/tests/helpers.custom.js +0 -1
- package/src/tests/helpers.js +5 -5
- package/src/tests/jsonLogic.fixtures.js +441 -0
- package/src/tests/jsonLogic.test.js +348 -0
- package/src/tests/testUtils.js +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
#### 0.5.0-beta.0 (2023-09-12)
|
|
2
|
+
|
|
3
|
+
##### Changes
|
|
4
|
+
|
|
5
|
+
- Computed Attributes ([#36](https://github.com/remoteoss/json-schema-form/pull/36)) ([80c29589](https://github.com/remoteoss/json-schema-form/commit/80c29589ac0972e0f33add70a59df15a46db1b43))
|
|
6
|
+
- JSON Logic Skeleton ([#35](https://github.com/remoteoss/json-schema-form/pull/35)) ([63149ae8](https://github.com/remoteoss/json-schema-form/commit/63149ae863cf1b5ad76a3b2a49c7f343e55ce07b))
|
|
7
|
+
|
|
8
|
+
#### 0.4.5-beta.0 (2023-08-31)
|
|
9
|
+
|
|
10
|
+
##### Changes
|
|
11
|
+
|
|
12
|
+
* Allow validation of consts to support single values ([#34](https://github.com/remoteoss/json-schema-form/pull/34)) ([bf07870d](https://github.com/remoteoss/json-schema-form/commit/bf07870d407d9b9b078882a078b9e4c7928df868))
|
|
13
|
+
|
|
14
|
+
#### 0.4.4-beta.0 (2023-08-30)
|
|
15
|
+
|
|
16
|
+
##### Chores
|
|
17
|
+
|
|
18
|
+
* **fieldset:** ignore values not matching the field type ([#44](https://github.com/remoteoss/json-schema-form/pull/44)) ([f0af54e5](https://github.com/remoteoss/json-schema-form/commit/f0af54e5d425fb78524ab150bb31629d00369a61))
|
|
19
|
+
|
|
1
20
|
#### 0.4.3-beta.0 (2023-08-09)
|
|
2
21
|
|
|
3
22
|
##### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2023 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.5.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.5.1-dev.20230913083845
|
|
5
|
+
Generated: Wed, 13 Sep 2023 08:39:03 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -91,6 +91,13 @@ function convertDiskSizeFromTo(from, to) {
|
|
|
91
91
|
return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
+
function containsHTML(str = "") {
|
|
95
|
+
return /<[a-z][\s\S]*>/i.test(str);
|
|
96
|
+
}
|
|
97
|
+
function wrapWithSpan(html, properties = {}) {
|
|
98
|
+
const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
|
|
99
|
+
return `<span ${attributes}>${html}</span>`;
|
|
100
|
+
}
|
|
94
101
|
function hasProperty(object2, propertyName) {
|
|
95
102
|
return Object.prototype.hasOwnProperty.call(object2, propertyName);
|
|
96
103
|
}
|
|
@@ -404,6 +411,252 @@ var import_flow = __toESM(require("lodash/flow"));
|
|
|
404
411
|
var import_noop = __toESM(require("lodash/noop"));
|
|
405
412
|
var import_randexp = require("randexp");
|
|
406
413
|
var import_yup = require("yup");
|
|
414
|
+
|
|
415
|
+
// src/jsonLogic.js
|
|
416
|
+
var import_json_logic_js = __toESM(require("json-logic-js"));
|
|
417
|
+
function createValidationChecker(schema) {
|
|
418
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
419
|
+
function createScopes(jsonSchema, key = "root") {
|
|
420
|
+
const sampleEmptyObject = buildSampleEmptyObject(schema);
|
|
421
|
+
scopes.set(key, createValidationsScope(jsonSchema));
|
|
422
|
+
Object.entries(jsonSchema?.properties ?? {}).filter(([, property]) => property.type === "object" || property.type === "array").forEach(([key2, property]) => {
|
|
423
|
+
if (property.type === "array") {
|
|
424
|
+
createScopes(property.items, `${key2}[]`);
|
|
425
|
+
} else {
|
|
426
|
+
createScopes(property, key2);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
validateInlineRules(jsonSchema, sampleEmptyObject);
|
|
430
|
+
}
|
|
431
|
+
createScopes(schema);
|
|
432
|
+
return {
|
|
433
|
+
scopes,
|
|
434
|
+
getScope(name = "root") {
|
|
435
|
+
return scopes.get(name);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function createValidationsScope(schema) {
|
|
440
|
+
const validationMap = /* @__PURE__ */ new Map();
|
|
441
|
+
const computedValuesMap = /* @__PURE__ */ new Map();
|
|
442
|
+
const logic = schema?.["x-jsf-logic"] ?? {
|
|
443
|
+
validations: {},
|
|
444
|
+
computedValues: {}
|
|
445
|
+
};
|
|
446
|
+
const validations = Object.entries(logic.validations ?? {});
|
|
447
|
+
const computedValues = Object.entries(logic.computedValues ?? {});
|
|
448
|
+
const sampleEmptyObject = buildSampleEmptyObject(schema);
|
|
449
|
+
validations.forEach(([id, validation]) => {
|
|
450
|
+
if (!validation.rule) {
|
|
451
|
+
throw Error(`[json-schema-form] json-logic error: Validation "${id}" has missing rule.`);
|
|
452
|
+
}
|
|
453
|
+
checkRuleIntegrity(validation.rule, id, sampleEmptyObject);
|
|
454
|
+
validationMap.set(id, validation);
|
|
455
|
+
});
|
|
456
|
+
computedValues.forEach(([id, computedValue]) => {
|
|
457
|
+
if (!computedValue.rule) {
|
|
458
|
+
throw Error(`[json-schema-form] json-logic error: Computed value "${id}" has missing rule.`);
|
|
459
|
+
}
|
|
460
|
+
checkRuleIntegrity(computedValue.rule, id, sampleEmptyObject);
|
|
461
|
+
computedValuesMap.set(id, computedValue);
|
|
462
|
+
});
|
|
463
|
+
function validate(rule, values) {
|
|
464
|
+
return import_json_logic_js.default.apply(rule, replaceUndefinedValuesWithNulls(values));
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
validationMap,
|
|
468
|
+
computedValuesMap,
|
|
469
|
+
validate,
|
|
470
|
+
applyValidationRuleInCondition(id, values) {
|
|
471
|
+
const validation = validationMap.get(id);
|
|
472
|
+
return validate(validation.rule, values);
|
|
473
|
+
},
|
|
474
|
+
applyComputedValueInField(id, values, fieldName) {
|
|
475
|
+
const validation = computedValuesMap.get(id);
|
|
476
|
+
if (validation === void 0) {
|
|
477
|
+
throw Error(
|
|
478
|
+
`[json-schema-form] json-logic error: Computed value "${id}" doesn't exist in field "${fieldName}".`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
return validate(validation.rule, values);
|
|
482
|
+
},
|
|
483
|
+
applyComputedValueRuleInCondition(id, values) {
|
|
484
|
+
const validation = computedValuesMap.get(id);
|
|
485
|
+
return validate(validation.rule, values);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function replaceUndefinedValuesWithNulls(values = {}) {
|
|
490
|
+
return Object.entries(values).reduce((prev, [key, value]) => {
|
|
491
|
+
return { ...prev, [key]: value === void 0 ? null : value };
|
|
492
|
+
}, {});
|
|
493
|
+
}
|
|
494
|
+
function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
|
|
495
|
+
const { parentID = "root" } = config;
|
|
496
|
+
const validation = logic.getScope(parentID).validationMap.get(id);
|
|
497
|
+
if (validation === void 0) {
|
|
498
|
+
throw Error(
|
|
499
|
+
`[json-schema-form] json-logic error: "${field.name}" required validation "${id}" doesn't exist.`
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
return (yupSchema) => yupSchema.test(
|
|
503
|
+
`${field.name}-validation-${id}`,
|
|
504
|
+
validation?.errorMessage ?? "This field is invalid.",
|
|
505
|
+
(value, { parent }) => {
|
|
506
|
+
if (value === void 0 && !field.required)
|
|
507
|
+
return true;
|
|
508
|
+
return import_json_logic_js.default.apply(validation.rule, parent);
|
|
509
|
+
}
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
var HANDLEBARS_REGEX = /\{\{([^{}]+)\}\}/g;
|
|
513
|
+
function replaceHandlebarsTemplates({
|
|
514
|
+
value: toReplace,
|
|
515
|
+
logic,
|
|
516
|
+
formValues,
|
|
517
|
+
parentID,
|
|
518
|
+
name: fieldName
|
|
519
|
+
}) {
|
|
520
|
+
if (typeof toReplace === "string") {
|
|
521
|
+
return toReplace.replace(HANDLEBARS_REGEX, (match, key) => {
|
|
522
|
+
return logic.getScope(parentID).applyComputedValueInField(key.trim(), formValues, fieldName);
|
|
523
|
+
});
|
|
524
|
+
} else if (typeof toReplace === "object") {
|
|
525
|
+
const { value, ...rules } = toReplace;
|
|
526
|
+
if (Object.keys(rules).length > 1 && !value) {
|
|
527
|
+
throw Error("Cannot define multiple rules without a template string with key `value`.");
|
|
528
|
+
}
|
|
529
|
+
const computedTemplateValue = Object.entries(rules).reduce((prev, [key, rule]) => {
|
|
530
|
+
const computedValue = logic.getScope(parentID).evaluateValidation(rule, formValues);
|
|
531
|
+
return prev.replaceAll(`{{${key}}}`, computedValue);
|
|
532
|
+
}, value);
|
|
533
|
+
return computedTemplateValue.replace(/\{\{([^{}]+)\}\}/g, (match, key) => {
|
|
534
|
+
return logic.getScope(parentID).applyComputedValueInField(key.trim(), formValues, fieldName);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return toReplace;
|
|
538
|
+
}
|
|
539
|
+
function calculateComputedAttributes(fieldParams, { parentID = "root" } = {}) {
|
|
540
|
+
return ({ logic, isRequired, config, formValues }) => {
|
|
541
|
+
const { name, computedAttributes } = fieldParams;
|
|
542
|
+
const attributes = Object.fromEntries(
|
|
543
|
+
Object.entries(computedAttributes).map(handleComputedAttribute(logic, formValues, parentID, name)).filter(([, value]) => value !== null)
|
|
544
|
+
);
|
|
545
|
+
return {
|
|
546
|
+
...attributes,
|
|
547
|
+
schema: buildYupSchema(
|
|
548
|
+
{ ...fieldParams, ...attributes, required: isRequired },
|
|
549
|
+
config,
|
|
550
|
+
logic
|
|
551
|
+
)
|
|
552
|
+
};
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function handleComputedAttribute(logic, formValues, parentID, name) {
|
|
556
|
+
return ([key, value]) => {
|
|
557
|
+
switch (key) {
|
|
558
|
+
case "description":
|
|
559
|
+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
560
|
+
case "title":
|
|
561
|
+
return ["label", replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
562
|
+
case "x-jsf-errorMessage":
|
|
563
|
+
return [
|
|
564
|
+
"errorMessage",
|
|
565
|
+
handleNestedObjectForComputedValues(value, formValues, parentID, logic, name)
|
|
566
|
+
];
|
|
567
|
+
case "x-jsf-presentation": {
|
|
568
|
+
if (value.statement) {
|
|
569
|
+
return [
|
|
570
|
+
"statement",
|
|
571
|
+
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name)
|
|
572
|
+
];
|
|
573
|
+
}
|
|
574
|
+
return [
|
|
575
|
+
key,
|
|
576
|
+
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name)
|
|
577
|
+
];
|
|
578
|
+
}
|
|
579
|
+
case "const":
|
|
580
|
+
default:
|
|
581
|
+
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues, name)];
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
function handleNestedObjectForComputedValues(values, formValues, parentID, logic, name) {
|
|
586
|
+
return Object.fromEntries(
|
|
587
|
+
Object.entries(values).map(([key, value]) => {
|
|
588
|
+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
589
|
+
})
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
function buildSampleEmptyObject(schema = {}) {
|
|
593
|
+
const sample = {};
|
|
594
|
+
if (typeof schema !== "object" || !schema.properties) {
|
|
595
|
+
return schema;
|
|
596
|
+
}
|
|
597
|
+
for (const key in schema.properties) {
|
|
598
|
+
if (schema.properties[key].type === "object") {
|
|
599
|
+
sample[key] = buildSampleEmptyObject(schema.properties[key]);
|
|
600
|
+
} else if (schema.properties[key].type === "array") {
|
|
601
|
+
const itemSchema = schema.properties[key].items;
|
|
602
|
+
sample[key] = buildSampleEmptyObject(itemSchema);
|
|
603
|
+
} else {
|
|
604
|
+
sample[key] = true;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return sample;
|
|
608
|
+
}
|
|
609
|
+
function validateInlineRules(jsonSchema, sampleEmptyObject) {
|
|
610
|
+
const properties = (jsonSchema?.properties || jsonSchema?.items?.properties) ?? {};
|
|
611
|
+
Object.entries(properties).filter(([, property]) => property["x-jsf-logic-computedAttrs"] !== void 0).forEach(([fieldName, property]) => {
|
|
612
|
+
Object.entries(property["x-jsf-logic-computedAttrs"]).filter(([, value]) => typeof value === "object").forEach(([key, item]) => {
|
|
613
|
+
Object.values(item).forEach((rule) => {
|
|
614
|
+
checkRuleIntegrity(
|
|
615
|
+
rule,
|
|
616
|
+
fieldName,
|
|
617
|
+
sampleEmptyObject,
|
|
618
|
+
(item2) => `[json-schema-form] json-logic error: fieldName "${item2.var}" doesn't exist in field "${fieldName}.x-jsf-logic-computedAttrs.${key}".`
|
|
619
|
+
);
|
|
620
|
+
});
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
function checkRuleIntegrity(rule, id, data, errorMessage = (item) => `[json-schema-form] json-logic error: rule "${id}" has no variable "${item.var}".`) {
|
|
625
|
+
Object.entries(rule ?? {}).map(([operator, subRule]) => {
|
|
626
|
+
if (!Array.isArray(subRule) && subRule !== null && subRule !== void 0)
|
|
627
|
+
return;
|
|
628
|
+
throwIfUnknownOperator(operator, subRule, id);
|
|
629
|
+
subRule.map((item) => {
|
|
630
|
+
const isVar = item !== null && typeof item === "object" && Object.hasOwn(item, "var");
|
|
631
|
+
if (isVar) {
|
|
632
|
+
const exists = import_json_logic_js.default.apply({ var: removeIndicesFromPath(item.var) }, data);
|
|
633
|
+
if (exists === null) {
|
|
634
|
+
throw Error(errorMessage(item));
|
|
635
|
+
}
|
|
636
|
+
} else {
|
|
637
|
+
checkRuleIntegrity(item, id, data);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
function throwIfUnknownOperator(operator, subRule, id) {
|
|
643
|
+
try {
|
|
644
|
+
import_json_logic_js.default.apply({ [operator]: subRule });
|
|
645
|
+
} catch (e) {
|
|
646
|
+
if (e.message === `Unrecognized operation ${operator}`) {
|
|
647
|
+
throw Error(
|
|
648
|
+
`[json-schema-form] json-logic error: in "${id}" rule there is an unknown operator "${operator}".`
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
var regexToGetIndices = /\.\d+\./g;
|
|
654
|
+
function removeIndicesFromPath(path) {
|
|
655
|
+
const intermediatePath = path.replace(regexToGetIndices, ".");
|
|
656
|
+
return intermediatePath.replace(/\.\d+$/, "");
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/yupSchema.js
|
|
407
660
|
var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
|
408
661
|
var baseString = (0, import_yup.string)().trim();
|
|
409
662
|
var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
|
|
@@ -526,7 +779,7 @@ var getYupSchema = ({ inputType, ...field }) => {
|
|
|
526
779
|
}
|
|
527
780
|
return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
|
|
528
781
|
};
|
|
529
|
-
function buildYupSchema(field, config) {
|
|
782
|
+
function buildYupSchema(field, config, logic) {
|
|
530
783
|
const { inputType, jsonType: jsonTypeValue, errorMessage = {}, ...propertyFields } = field;
|
|
531
784
|
const isCheckboxBoolean = typeof propertyFields.checkboxValue === "boolean";
|
|
532
785
|
let baseSchema;
|
|
@@ -599,6 +852,13 @@ function buildYupSchema(field, config) {
|
|
|
599
852
|
}) : true
|
|
600
853
|
);
|
|
601
854
|
}
|
|
855
|
+
function withConst(yupSchema) {
|
|
856
|
+
return yupSchema.test(
|
|
857
|
+
"isConst",
|
|
858
|
+
errorMessage.const ?? errorMessageFromConfig.const ?? `The only accepted value is ${propertyFields.const}.`,
|
|
859
|
+
(value) => propertyFields.required === false && value === void 0 || value === null || value === propertyFields.const
|
|
860
|
+
);
|
|
861
|
+
}
|
|
602
862
|
function withBaseSchema() {
|
|
603
863
|
const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
|
|
604
864
|
if (customErrorMsg) {
|
|
@@ -666,6 +926,14 @@ function buildYupSchema(field, config) {
|
|
|
666
926
|
if (propertyFields.accept) {
|
|
667
927
|
validators.push(withFileFormat);
|
|
668
928
|
}
|
|
929
|
+
if (propertyFields.const) {
|
|
930
|
+
validators.push(withConst);
|
|
931
|
+
}
|
|
932
|
+
if (propertyFields.requiredValidations) {
|
|
933
|
+
propertyFields.requiredValidations.forEach(
|
|
934
|
+
(id) => validators.push(yupSchemaWithCustomJSONLogic({ field, id, logic, config }))
|
|
935
|
+
);
|
|
936
|
+
}
|
|
669
937
|
return (0, import_flow.default)(validators);
|
|
670
938
|
}
|
|
671
939
|
function getNoSortEdges(fields = []) {
|
|
@@ -705,8 +973,8 @@ function hasType(type, typeName) {
|
|
|
705
973
|
function getField(fieldName, fields) {
|
|
706
974
|
return fields.find(({ name }) => name === fieldName);
|
|
707
975
|
}
|
|
708
|
-
function validateFieldSchema(field, value) {
|
|
709
|
-
const validator = buildYupSchema(field);
|
|
976
|
+
function validateFieldSchema(field, value, logic) {
|
|
977
|
+
const validator = buildYupSchema(field, {}, logic);
|
|
710
978
|
return validator().isValidSync(value);
|
|
711
979
|
}
|
|
712
980
|
function compareFormValueWithSchemaValue(formValue, schemaValue) {
|
|
@@ -742,7 +1010,16 @@ function getPrefillSubFieldValues(field, defaultValues, parentFieldKeyPath) {
|
|
|
742
1010
|
initialValue[field.name] = subFieldValues;
|
|
743
1011
|
}
|
|
744
1012
|
} else {
|
|
745
|
-
|
|
1013
|
+
if (typeof initialValue !== "object") {
|
|
1014
|
+
console.warn(
|
|
1015
|
+
`Field "${parentFieldKeyPath}"'s value is "${initialValue}", but should be type object.`
|
|
1016
|
+
);
|
|
1017
|
+
initialValue = getPrefillValues([field], {
|
|
1018
|
+
// TODO nested fieldsets are not handled
|
|
1019
|
+
});
|
|
1020
|
+
} else {
|
|
1021
|
+
initialValue = getPrefillValues([field], initialValue);
|
|
1022
|
+
}
|
|
746
1023
|
}
|
|
747
1024
|
return initialValue;
|
|
748
1025
|
}
|
|
@@ -771,7 +1048,7 @@ function getPrefillValues(fields, initialValues = {}) {
|
|
|
771
1048
|
});
|
|
772
1049
|
return initialValues;
|
|
773
1050
|
}
|
|
774
|
-
function updateField(field, requiredFields, node, formValues) {
|
|
1051
|
+
function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
775
1052
|
if (!field) {
|
|
776
1053
|
return;
|
|
777
1054
|
}
|
|
@@ -793,6 +1070,17 @@ function updateField(field, requiredFields, node, formValues) {
|
|
|
793
1070
|
}
|
|
794
1071
|
}
|
|
795
1072
|
});
|
|
1073
|
+
if (field.getComputedAttributes) {
|
|
1074
|
+
const computedFieldValues = field.getComputedAttributes({
|
|
1075
|
+
field,
|
|
1076
|
+
isRequired: fieldIsRequired,
|
|
1077
|
+
node,
|
|
1078
|
+
formValues,
|
|
1079
|
+
config,
|
|
1080
|
+
logic
|
|
1081
|
+
});
|
|
1082
|
+
updateValues(computedFieldValues);
|
|
1083
|
+
}
|
|
796
1084
|
if (field.calculateConditionalProperties) {
|
|
797
1085
|
const newFieldValues = field.calculateConditionalProperties(fieldIsRequired, node);
|
|
798
1086
|
updateValues(newFieldValues);
|
|
@@ -806,33 +1094,46 @@ function updateField(field, requiredFields, node, formValues) {
|
|
|
806
1094
|
updateValues(newFieldValues);
|
|
807
1095
|
}
|
|
808
1096
|
}
|
|
809
|
-
function processNode(
|
|
1097
|
+
function processNode({
|
|
1098
|
+
node,
|
|
1099
|
+
formValues,
|
|
1100
|
+
formFields,
|
|
1101
|
+
accRequired = /* @__PURE__ */ new Set(),
|
|
1102
|
+
parentID = "root",
|
|
1103
|
+
logic
|
|
1104
|
+
}) {
|
|
810
1105
|
const requiredFields = new Set(accRequired);
|
|
811
1106
|
Object.keys(node.properties ?? []).forEach((fieldName) => {
|
|
812
1107
|
const field = getField(fieldName, formFields);
|
|
813
|
-
updateField(field, requiredFields, node, formValues);
|
|
1108
|
+
updateField(field, requiredFields, node, formValues, logic, { parentID });
|
|
814
1109
|
});
|
|
815
1110
|
node.required?.forEach((fieldName) => {
|
|
816
1111
|
requiredFields.add(fieldName);
|
|
817
|
-
updateField(getField(fieldName, formFields), requiredFields, node, formValues
|
|
1112
|
+
updateField(getField(fieldName, formFields), requiredFields, node, formValues, logic, {
|
|
1113
|
+
parentID
|
|
1114
|
+
});
|
|
818
1115
|
});
|
|
819
1116
|
if (node.if) {
|
|
820
|
-
const matchesCondition = checkIfConditionMatches(node, formValues, formFields);
|
|
1117
|
+
const matchesCondition = checkIfConditionMatches(node, formValues, formFields, logic);
|
|
821
1118
|
if (matchesCondition && node.then) {
|
|
822
|
-
const { required: branchRequired } = processNode(
|
|
823
|
-
node.then,
|
|
1119
|
+
const { required: branchRequired } = processNode({
|
|
1120
|
+
node: node.then,
|
|
824
1121
|
formValues,
|
|
825
1122
|
formFields,
|
|
826
|
-
requiredFields
|
|
827
|
-
|
|
1123
|
+
accRequired: requiredFields,
|
|
1124
|
+
parentID,
|
|
1125
|
+
logic
|
|
1126
|
+
});
|
|
828
1127
|
branchRequired.forEach((field) => requiredFields.add(field));
|
|
829
1128
|
} else if (node.else) {
|
|
830
|
-
const { required: branchRequired } = processNode(
|
|
831
|
-
node.else,
|
|
1129
|
+
const { required: branchRequired } = processNode({
|
|
1130
|
+
node: node.else,
|
|
832
1131
|
formValues,
|
|
833
1132
|
formFields,
|
|
834
|
-
requiredFields
|
|
835
|
-
|
|
1133
|
+
accRequired: requiredFields,
|
|
1134
|
+
parentID,
|
|
1135
|
+
logic
|
|
1136
|
+
});
|
|
836
1137
|
branchRequired.forEach((field) => requiredFields.add(field));
|
|
837
1138
|
}
|
|
838
1139
|
}
|
|
@@ -844,12 +1145,21 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
|
|
|
844
1145
|
node.anyOf.forEach(({ required = [] }) => {
|
|
845
1146
|
required.forEach((fieldName) => {
|
|
846
1147
|
const field = getField(fieldName, formFields);
|
|
847
|
-
updateField(field, requiredFields, node, formValues);
|
|
1148
|
+
updateField(field, requiredFields, node, formValues, logic, { parentID });
|
|
848
1149
|
});
|
|
849
1150
|
});
|
|
850
1151
|
}
|
|
851
1152
|
if (node.allOf) {
|
|
852
|
-
node.allOf.map(
|
|
1153
|
+
node.allOf.map(
|
|
1154
|
+
(allOfNode) => processNode({
|
|
1155
|
+
node: allOfNode,
|
|
1156
|
+
formValues,
|
|
1157
|
+
formFields,
|
|
1158
|
+
accRequired: requiredFields,
|
|
1159
|
+
parentID,
|
|
1160
|
+
logic
|
|
1161
|
+
})
|
|
1162
|
+
).forEach(({ required: allOfItemRequired }) => {
|
|
853
1163
|
allOfItemRequired.forEach(requiredFields.add, requiredFields);
|
|
854
1164
|
});
|
|
855
1165
|
}
|
|
@@ -857,7 +1167,13 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
|
|
|
857
1167
|
Object.entries(node.properties).forEach(([name, nestedNode]) => {
|
|
858
1168
|
const inputType = getInputType(nestedNode);
|
|
859
1169
|
if (inputType === supportedTypes.FIELDSET) {
|
|
860
|
-
processNode(
|
|
1170
|
+
processNode({
|
|
1171
|
+
node: nestedNode,
|
|
1172
|
+
formValues: formValues[name] || {},
|
|
1173
|
+
formFields: getField(name, formFields).fields,
|
|
1174
|
+
parentID: name,
|
|
1175
|
+
logic
|
|
1176
|
+
});
|
|
861
1177
|
}
|
|
862
1178
|
});
|
|
863
1179
|
}
|
|
@@ -875,11 +1191,11 @@ function clearValuesIfNotVisible(fields, formValues) {
|
|
|
875
1191
|
}
|
|
876
1192
|
});
|
|
877
1193
|
}
|
|
878
|
-
function updateFieldsProperties(fields, formValues, jsonSchema) {
|
|
1194
|
+
function updateFieldsProperties(fields, formValues, jsonSchema, logic) {
|
|
879
1195
|
if (!jsonSchema?.properties) {
|
|
880
1196
|
return;
|
|
881
1197
|
}
|
|
882
|
-
processNode(jsonSchema, formValues, fields);
|
|
1198
|
+
processNode({ node: jsonSchema, formValues, formFields: fields, logic });
|
|
883
1199
|
clearValuesIfNotVisible(fields, formValues);
|
|
884
1200
|
}
|
|
885
1201
|
var notNullOption = (opt) => opt.const !== null;
|
|
@@ -922,11 +1238,16 @@ function extractParametersFromNode(schemaNode) {
|
|
|
922
1238
|
}
|
|
923
1239
|
const presentation = pickXKey(schemaNode, "presentation") ?? {};
|
|
924
1240
|
const errorMessage = pickXKey(schemaNode, "errorMessage") ?? {};
|
|
1241
|
+
const requiredValidations = schemaNode["x-jsf-logic-validations"];
|
|
1242
|
+
const computedAttributes = schemaNode["x-jsf-logic-computedAttrs"];
|
|
1243
|
+
const decoratedComputedAttributes = getDecoratedComputedAttributes(computedAttributes);
|
|
925
1244
|
const node = (0, import_omit.default)(schemaNode, ["x-jsf-presentation", "presentation"]);
|
|
926
1245
|
const description = presentation?.description || node.description;
|
|
927
|
-
const statementDescription = presentation.statement?.description;
|
|
1246
|
+
const statementDescription = containsHTML(presentation.statement?.description) ? wrapWithSpan(presentation.statement.description, { class: "jsf-statement" }) : presentation.statement?.description;
|
|
928
1247
|
return (0, import_omitBy.default)(
|
|
929
1248
|
{
|
|
1249
|
+
const: node.const,
|
|
1250
|
+
...node.const && node.default ? { value: node.const } : {},
|
|
930
1251
|
label: node.title,
|
|
931
1252
|
readOnly: node.readOnly,
|
|
932
1253
|
...node.deprecated && {
|
|
@@ -961,8 +1282,12 @@ function extractParametersFromNode(schemaNode) {
|
|
|
961
1282
|
},
|
|
962
1283
|
// Handle [name].presentation
|
|
963
1284
|
...presentation,
|
|
964
|
-
|
|
965
|
-
|
|
1285
|
+
requiredValidations,
|
|
1286
|
+
computedAttributes: decoratedComputedAttributes,
|
|
1287
|
+
description: containsHTML(description) ? wrapWithSpan(description, {
|
|
1288
|
+
class: "jsf-description"
|
|
1289
|
+
}) : description,
|
|
1290
|
+
extra: containsHTML(presentation.extra) ? wrapWithSpan(presentation.extra, { class: "jsf-extra" }) : presentation.extra,
|
|
966
1291
|
statement: presentation.statement && {
|
|
967
1292
|
...presentation.statement,
|
|
968
1293
|
description: statementDescription
|
|
@@ -995,8 +1320,8 @@ function yupToFormErrors(yupError) {
|
|
|
995
1320
|
}
|
|
996
1321
|
return errors;
|
|
997
1322
|
}
|
|
998
|
-
var handleValuesChange = (fields, jsonSchema, config) => (values) => {
|
|
999
|
-
updateFieldsProperties(fields, values, jsonSchema);
|
|
1323
|
+
var handleValuesChange = (fields, jsonSchema, config, logic) => (values) => {
|
|
1324
|
+
updateFieldsProperties(fields, values, jsonSchema, logic);
|
|
1000
1325
|
const lazySchema = (0, import_yup2.lazy)(() => buildCompleteYupSchema(fields, config));
|
|
1001
1326
|
let errors;
|
|
1002
1327
|
try {
|
|
@@ -1015,6 +1340,12 @@ var handleValuesChange = (fields, jsonSchema, config) => (values) => {
|
|
|
1015
1340
|
formErrors: yupToFormErrors(errors)
|
|
1016
1341
|
};
|
|
1017
1342
|
};
|
|
1343
|
+
function getDecoratedComputedAttributes(computedAttributes) {
|
|
1344
|
+
return {
|
|
1345
|
+
...computedAttributes ?? {},
|
|
1346
|
+
...computedAttributes?.const && computedAttributes?.default ? { value: computedAttributes.const } : {}
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1018
1349
|
|
|
1019
1350
|
// src/calculateConditionalProperties.js
|
|
1020
1351
|
function isFieldRequired(node, field) {
|
|
@@ -1216,6 +1547,9 @@ function applyFieldsDependencies(fieldsParameters, node) {
|
|
|
1216
1547
|
applyFieldsDependencies(fieldsParameters, condition);
|
|
1217
1548
|
});
|
|
1218
1549
|
}
|
|
1550
|
+
if (node?.["x-jsf-logic"]) {
|
|
1551
|
+
applyFieldsDependencies(fieldsParameters, node["x-jsf-logic"]);
|
|
1552
|
+
}
|
|
1219
1553
|
}
|
|
1220
1554
|
function getCustomPropertiesForField(fieldParams, config) {
|
|
1221
1555
|
return config?.customProperties?.[fieldParams.name];
|
|
@@ -1227,15 +1561,16 @@ function getComposeFunctionForField(fieldParams, hasCustomizations) {
|
|
|
1227
1561
|
}
|
|
1228
1562
|
return composeFn;
|
|
1229
1563
|
}
|
|
1230
|
-
function buildField(fieldParams, config, scopedJsonSchema) {
|
|
1564
|
+
function buildField(fieldParams, config, scopedJsonSchema, logic) {
|
|
1231
1565
|
const customProperties = getCustomPropertiesForField(fieldParams, config);
|
|
1232
1566
|
const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
|
|
1233
|
-
const yupSchema = buildYupSchema(fieldParams, config);
|
|
1567
|
+
const yupSchema = buildYupSchema(fieldParams, config, logic);
|
|
1234
1568
|
const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
|
|
1235
1569
|
const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
|
|
1236
1570
|
fieldParams,
|
|
1237
1571
|
customProperties
|
|
1238
1572
|
);
|
|
1573
|
+
const getComputedAttributes = Object.keys(fieldParams.computedAttributes).length > 0 && calculateComputedAttributes(fieldParams, config);
|
|
1239
1574
|
const hasCustomValidations = !!customProperties && (0, import_size.default)((0, import_pick2.default)(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS)) > 0;
|
|
1240
1575
|
const finalFieldParams = {
|
|
1241
1576
|
// invalid attribute cleanup
|
|
@@ -1248,6 +1583,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
|
|
|
1248
1583
|
...hasCustomValidations && {
|
|
1249
1584
|
calculateCustomValidationProperties: calculateCustomValidationPropertiesClosure
|
|
1250
1585
|
},
|
|
1586
|
+
...getComputedAttributes && { getComputedAttributes },
|
|
1251
1587
|
// field customization properties
|
|
1252
1588
|
...customProperties && { fieldCustomization: customProperties },
|
|
1253
1589
|
// base schema
|
|
@@ -1256,7 +1592,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
|
|
|
1256
1592
|
};
|
|
1257
1593
|
return composeFn(finalFieldParams);
|
|
1258
1594
|
}
|
|
1259
|
-
function getFieldsFromJSONSchema(scopedJsonSchema, config) {
|
|
1595
|
+
function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
|
|
1260
1596
|
if (!scopedJsonSchema) {
|
|
1261
1597
|
return [];
|
|
1262
1598
|
}
|
|
@@ -1280,11 +1616,11 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config) {
|
|
|
1280
1616
|
fields: () => groupArrayFields,
|
|
1281
1617
|
addFieldText: fieldParams.addFieldText
|
|
1282
1618
|
};
|
|
1283
|
-
buildField(fieldParams, config, scopedJsonSchema).forEach((groupField) => {
|
|
1619
|
+
buildField(fieldParams, config, scopedJsonSchema, logic).forEach((groupField) => {
|
|
1284
1620
|
fields.push(groupField);
|
|
1285
1621
|
});
|
|
1286
1622
|
} else {
|
|
1287
|
-
fields.push(buildField(fieldParams, config, scopedJsonSchema));
|
|
1623
|
+
fields.push(buildField(fieldParams, config, scopedJsonSchema, logic));
|
|
1288
1624
|
}
|
|
1289
1625
|
});
|
|
1290
1626
|
return fields;
|
|
@@ -1295,9 +1631,15 @@ function createHeadlessForm(jsonSchema, customConfig = {}) {
|
|
|
1295
1631
|
...customConfig
|
|
1296
1632
|
};
|
|
1297
1633
|
try {
|
|
1298
|
-
const
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1634
|
+
const logic = createValidationChecker(jsonSchema);
|
|
1635
|
+
const fields = getFieldsFromJSONSchema(jsonSchema, config, logic);
|
|
1636
|
+
const handleValidation = handleValuesChange(fields, jsonSchema, config, logic);
|
|
1637
|
+
updateFieldsProperties(
|
|
1638
|
+
fields,
|
|
1639
|
+
getPrefillValues(fields, config.initialValues),
|
|
1640
|
+
jsonSchema,
|
|
1641
|
+
logic
|
|
1642
|
+
);
|
|
1301
1643
|
return {
|
|
1302
1644
|
fields,
|
|
1303
1645
|
handleValidation,
|