@remoteoss/json-schema-form 0.5.0-dev.20230719162322 → 0.5.0-dev.20230901130231
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 +24 -0
- package/dist/index.cjs +278 -86
- package/dist/index.js +278 -86
- package/dist/standalone.js +655 -85
- package/package.json +2 -1
- package/src/tests/checkIfConditionMatches.test.js +51 -0
- package/src/tests/conditions.test.js +58 -0
- package/src/tests/const.test.js +86 -0
- package/src/tests/createHeadlessForm.test.js +31 -10
- package/src/tests/helpers.custom.js +0 -1
- package/src/tests/helpers.js +6 -6
- package/src/tests/jsonLogic.fixtures.js +162 -0
- package/src/tests/jsonLogic.test.js +230 -0
package/dist/index.js
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.0-dev.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.5.0-dev.20230901130231
|
|
5
|
+
Generated: Fri, 01 Sep 2023 13:03:04 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -48,6 +48,69 @@ import omitBy from "lodash/omitBy";
|
|
|
48
48
|
import set from "lodash/set";
|
|
49
49
|
import { lazy } from "yup";
|
|
50
50
|
|
|
51
|
+
// src/utils.js
|
|
52
|
+
function convertDiskSizeFromTo(from, to) {
|
|
53
|
+
const units = ["bytes", "kb", "mb"];
|
|
54
|
+
return function convert(value) {
|
|
55
|
+
return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function containsHTML(str = "") {
|
|
59
|
+
return /<[a-z][\s\S]*>/i.test(str);
|
|
60
|
+
}
|
|
61
|
+
function wrapWithSpan(html, properties = {}) {
|
|
62
|
+
const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
|
|
63
|
+
return `<span ${attributes}>${html}</span>`;
|
|
64
|
+
}
|
|
65
|
+
function hasProperty(object2, propertyName) {
|
|
66
|
+
return Object.prototype.hasOwnProperty.call(object2, propertyName);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/checkIfConditionMatches.js
|
|
70
|
+
function checkIfConditionMatches(node, formValues, formFields) {
|
|
71
|
+
return Object.keys(node.if.properties).every((name) => {
|
|
72
|
+
const currentProperty = node.if.properties[name];
|
|
73
|
+
const value = formValues[name];
|
|
74
|
+
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
75
|
+
value === null;
|
|
76
|
+
const hasIfExplicit = node.if.required?.includes(name);
|
|
77
|
+
if (hasEmptyValue && !hasIfExplicit) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (hasProperty(currentProperty, "const")) {
|
|
81
|
+
return compareFormValueWithSchemaValue(value, currentProperty.const);
|
|
82
|
+
}
|
|
83
|
+
if (currentProperty.contains?.pattern) {
|
|
84
|
+
const formValue = value || [];
|
|
85
|
+
if (Array.isArray(formValue)) {
|
|
86
|
+
const pattern = new RegExp(currentProperty.contains.pattern);
|
|
87
|
+
return (value || []).some((item) => pattern.test(item));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (currentProperty.enum) {
|
|
91
|
+
return currentProperty.enum.includes(value);
|
|
92
|
+
}
|
|
93
|
+
if (currentProperty.properties) {
|
|
94
|
+
return checkIfConditionMatches(
|
|
95
|
+
{ if: currentProperty },
|
|
96
|
+
formValues[name],
|
|
97
|
+
getField(name, formFields).fields
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
const field = getField(name, formFields);
|
|
101
|
+
return validateFieldSchema(
|
|
102
|
+
{
|
|
103
|
+
options: field.options,
|
|
104
|
+
// @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
|
|
105
|
+
...currentProperty,
|
|
106
|
+
inputType: field.inputType,
|
|
107
|
+
required: true
|
|
108
|
+
},
|
|
109
|
+
value
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
51
114
|
// src/internals/helpers.js
|
|
52
115
|
import merge from "lodash/fp/merge";
|
|
53
116
|
import get from "lodash/get";
|
|
@@ -307,29 +370,108 @@ function _composeFieldCustomClosure(defaultComposeFn) {
|
|
|
307
370
|
};
|
|
308
371
|
}
|
|
309
372
|
|
|
310
|
-
// src/
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
373
|
+
// src/yupSchema.js
|
|
374
|
+
import flow from "lodash/flow";
|
|
375
|
+
import noop from "lodash/noop";
|
|
376
|
+
import { randexp } from "randexp";
|
|
377
|
+
import { string, number, boolean, object, array } from "yup";
|
|
378
|
+
|
|
379
|
+
// src/jsonLogic.js
|
|
380
|
+
import jsonLogic from "json-logic-js";
|
|
381
|
+
function createValidationChecker(schema) {
|
|
382
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
383
|
+
function createScopes(jsonSchema, key = "root") {
|
|
384
|
+
scopes.set(key, createValidationsScope(jsonSchema));
|
|
385
|
+
Object.entries(jsonSchema?.properties ?? {}).filter(([, property]) => property.type === "object" || property.type === "array").forEach(([key2, property]) => {
|
|
386
|
+
if (property.type === "array") {
|
|
387
|
+
createScopes(property.items, `${key2}[]`);
|
|
388
|
+
} else {
|
|
389
|
+
createScopes(property, key2);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
createScopes(schema);
|
|
394
|
+
return {
|
|
395
|
+
scopes,
|
|
396
|
+
getScope(name = "root") {
|
|
397
|
+
return scopes.get(name);
|
|
398
|
+
}
|
|
315
399
|
};
|
|
316
400
|
}
|
|
317
|
-
function
|
|
318
|
-
|
|
401
|
+
function createValidationsScope(schema) {
|
|
402
|
+
const validationMap = /* @__PURE__ */ new Map();
|
|
403
|
+
const computedValuesMap = /* @__PURE__ */ new Map();
|
|
404
|
+
const logic = schema?.["x-jsf-logic"] ?? {
|
|
405
|
+
validations: {},
|
|
406
|
+
computedValues: {}
|
|
407
|
+
};
|
|
408
|
+
const validations = Object.entries(logic.validations ?? {});
|
|
409
|
+
const computedValues = Object.entries(logic.computedValues ?? {});
|
|
410
|
+
validations.forEach(([id, validation]) => {
|
|
411
|
+
validationMap.set(id, validation);
|
|
412
|
+
});
|
|
413
|
+
computedValues.forEach(([id, computedValue]) => {
|
|
414
|
+
computedValuesMap.set(id, computedValue);
|
|
415
|
+
});
|
|
416
|
+
function validate(rule, values) {
|
|
417
|
+
return jsonLogic.apply(rule, replaceUndefinedValuesWithNulls(values));
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
validationMap,
|
|
421
|
+
computedValuesMap,
|
|
422
|
+
validate,
|
|
423
|
+
applyValidationRuleInCondition(id, values) {
|
|
424
|
+
const validation = validationMap.get(id);
|
|
425
|
+
return validate(validation.rule, values);
|
|
426
|
+
},
|
|
427
|
+
applyComputedValueInField(id, values) {
|
|
428
|
+
const validation = computedValuesMap.get(id);
|
|
429
|
+
return validate(validation.rule, values);
|
|
430
|
+
},
|
|
431
|
+
applyComputedValueRuleInCondition(id, values) {
|
|
432
|
+
const validation = computedValuesMap.get(id);
|
|
433
|
+
return validate(validation.rule, values);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
319
436
|
}
|
|
320
|
-
function
|
|
321
|
-
|
|
322
|
-
|
|
437
|
+
function replaceUndefinedValuesWithNulls(values = {}) {
|
|
438
|
+
return Object.entries(values).reduce((prev, [key, value]) => {
|
|
439
|
+
return { ...prev, [key]: value === void 0 ? null : value };
|
|
440
|
+
}, {});
|
|
323
441
|
}
|
|
324
|
-
function
|
|
325
|
-
|
|
442
|
+
function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
|
|
443
|
+
const { parentID = "root" } = config;
|
|
444
|
+
const validation = logic.getScope(parentID).validationMap.get(id);
|
|
445
|
+
return (yupSchema) => yupSchema.test(
|
|
446
|
+
`${field.name}-validation-${id}`,
|
|
447
|
+
validation?.errorMessage ?? "This field is invalid.",
|
|
448
|
+
(value, { parent }) => {
|
|
449
|
+
if (value === void 0 && !field.required)
|
|
450
|
+
return true;
|
|
451
|
+
return jsonLogic.apply(validation.rule, parent);
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
function calculateComputedAttributes(fieldParams, { parentID = "root" } = {}) {
|
|
456
|
+
return ({ logic, formValues }) => {
|
|
457
|
+
const { computedAttributes } = fieldParams;
|
|
458
|
+
const attributes = Object.fromEntries(
|
|
459
|
+
Object.entries(computedAttributes).map(handleComputedAttribute(logic, formValues, parentID)).filter(([, value]) => value !== null)
|
|
460
|
+
);
|
|
461
|
+
return attributes;
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function handleComputedAttribute(logic, formValues, parentID) {
|
|
465
|
+
return ([key, value]) => {
|
|
466
|
+
if (key === "const")
|
|
467
|
+
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
|
|
468
|
+
if (typeof value === "string") {
|
|
469
|
+
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
|
|
470
|
+
}
|
|
471
|
+
};
|
|
326
472
|
}
|
|
327
473
|
|
|
328
474
|
// src/yupSchema.js
|
|
329
|
-
import flow from "lodash/flow";
|
|
330
|
-
import noop from "lodash/noop";
|
|
331
|
-
import { randexp } from "randexp";
|
|
332
|
-
import { string, number, boolean, object, array } from "yup";
|
|
333
475
|
var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
|
334
476
|
var baseString = string().trim();
|
|
335
477
|
var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
|
|
@@ -452,7 +594,7 @@ var getYupSchema = ({ inputType, ...field }) => {
|
|
|
452
594
|
}
|
|
453
595
|
return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
|
|
454
596
|
};
|
|
455
|
-
function buildYupSchema(field, config) {
|
|
597
|
+
function buildYupSchema(field, config, logic) {
|
|
456
598
|
const { inputType, jsonType: jsonTypeValue, errorMessage = {}, ...propertyFields } = field;
|
|
457
599
|
const isCheckboxBoolean = typeof propertyFields.checkboxValue === "boolean";
|
|
458
600
|
let baseSchema;
|
|
@@ -525,6 +667,13 @@ function buildYupSchema(field, config) {
|
|
|
525
667
|
}) : true
|
|
526
668
|
);
|
|
527
669
|
}
|
|
670
|
+
function withConst(yupSchema) {
|
|
671
|
+
return yupSchema.test(
|
|
672
|
+
"isConst",
|
|
673
|
+
errorMessage.const ?? errorMessageFromConfig.const ?? `The only accepted value is ${propertyFields.const}.`,
|
|
674
|
+
(value) => propertyFields.required === false && value === void 0 || value === null || value === propertyFields.const
|
|
675
|
+
);
|
|
676
|
+
}
|
|
528
677
|
function withBaseSchema() {
|
|
529
678
|
const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
|
|
530
679
|
if (customErrorMsg) {
|
|
@@ -592,6 +741,14 @@ function buildYupSchema(field, config) {
|
|
|
592
741
|
if (propertyFields.accept) {
|
|
593
742
|
validators.push(withFileFormat);
|
|
594
743
|
}
|
|
744
|
+
if (propertyFields.const) {
|
|
745
|
+
validators.push(withConst);
|
|
746
|
+
}
|
|
747
|
+
if (propertyFields.requiredValidations) {
|
|
748
|
+
propertyFields.requiredValidations.forEach(
|
|
749
|
+
(id) => validators.push(yupSchemaWithCustomJSONLogic({ field, id, logic, config }))
|
|
750
|
+
);
|
|
751
|
+
}
|
|
595
752
|
return flow(validators);
|
|
596
753
|
}
|
|
597
754
|
function getNoSortEdges(fields = []) {
|
|
@@ -631,50 +788,14 @@ function hasType(type, typeName) {
|
|
|
631
788
|
function getField(fieldName, fields) {
|
|
632
789
|
return fields.find(({ name }) => name === fieldName);
|
|
633
790
|
}
|
|
634
|
-
function validateFieldSchema(field, value) {
|
|
635
|
-
const validator = buildYupSchema(field);
|
|
791
|
+
function validateFieldSchema(field, value, logic) {
|
|
792
|
+
const validator = buildYupSchema(field, {}, logic);
|
|
636
793
|
return validator().isValidSync(value);
|
|
637
794
|
}
|
|
638
795
|
function compareFormValueWithSchemaValue(formValue, schemaValue) {
|
|
639
796
|
const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
|
|
640
797
|
return String(formValue) === String(currentPropertyValue);
|
|
641
798
|
}
|
|
642
|
-
function checkIfConditionMatches(node, formValues, formFields) {
|
|
643
|
-
return Object.keys(node.if.properties).every((name) => {
|
|
644
|
-
const currentProperty = node.if.properties[name];
|
|
645
|
-
const value = formValues[name];
|
|
646
|
-
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
647
|
-
value === null;
|
|
648
|
-
const hasIfExplicit = node.if.required?.includes(name);
|
|
649
|
-
if (hasEmptyValue && !hasIfExplicit) {
|
|
650
|
-
return true;
|
|
651
|
-
}
|
|
652
|
-
if (hasProperty(currentProperty, "const")) {
|
|
653
|
-
return compareFormValueWithSchemaValue(value, currentProperty.const);
|
|
654
|
-
}
|
|
655
|
-
if (currentProperty.contains?.pattern) {
|
|
656
|
-
const formValue = value || [];
|
|
657
|
-
if (Array.isArray(formValue)) {
|
|
658
|
-
const pattern = new RegExp(currentProperty.contains.pattern);
|
|
659
|
-
return (value || []).some((item) => pattern.test(item));
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
if (currentProperty.enum) {
|
|
663
|
-
return currentProperty.enum.includes(value);
|
|
664
|
-
}
|
|
665
|
-
const field = getField(name, formFields);
|
|
666
|
-
return validateFieldSchema(
|
|
667
|
-
{
|
|
668
|
-
options: field.options,
|
|
669
|
-
// @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
|
|
670
|
-
...currentProperty,
|
|
671
|
-
inputType: field.inputType,
|
|
672
|
-
required: true
|
|
673
|
-
},
|
|
674
|
-
value
|
|
675
|
-
);
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
799
|
function isFieldFilled(fieldValue) {
|
|
679
800
|
return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
|
|
680
801
|
}
|
|
@@ -704,7 +825,16 @@ function getPrefillSubFieldValues(field, defaultValues, parentFieldKeyPath) {
|
|
|
704
825
|
initialValue[field.name] = subFieldValues;
|
|
705
826
|
}
|
|
706
827
|
} else {
|
|
707
|
-
|
|
828
|
+
if (typeof initialValue !== "object") {
|
|
829
|
+
console.warn(
|
|
830
|
+
`Field "${parentFieldKeyPath}"'s value is "${initialValue}", but should be type object.`
|
|
831
|
+
);
|
|
832
|
+
initialValue = getPrefillValues([field], {
|
|
833
|
+
// TODO nested fieldsets are not handled
|
|
834
|
+
});
|
|
835
|
+
} else {
|
|
836
|
+
initialValue = getPrefillValues([field], initialValue);
|
|
837
|
+
}
|
|
708
838
|
}
|
|
709
839
|
return initialValue;
|
|
710
840
|
}
|
|
@@ -733,7 +863,7 @@ function getPrefillValues(fields, initialValues = {}) {
|
|
|
733
863
|
});
|
|
734
864
|
return initialValues;
|
|
735
865
|
}
|
|
736
|
-
function updateField(field, requiredFields, node, formValues) {
|
|
866
|
+
function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
737
867
|
if (!field) {
|
|
738
868
|
return;
|
|
739
869
|
}
|
|
@@ -755,6 +885,17 @@ function updateField(field, requiredFields, node, formValues) {
|
|
|
755
885
|
}
|
|
756
886
|
}
|
|
757
887
|
});
|
|
888
|
+
if (field.getComputedAttributes) {
|
|
889
|
+
const computedFieldValues = field.getComputedAttributes({
|
|
890
|
+
field,
|
|
891
|
+
isRequired: fieldIsRequired,
|
|
892
|
+
node,
|
|
893
|
+
formValues,
|
|
894
|
+
config,
|
|
895
|
+
logic
|
|
896
|
+
});
|
|
897
|
+
updateValues(computedFieldValues);
|
|
898
|
+
}
|
|
758
899
|
if (field.calculateConditionalProperties) {
|
|
759
900
|
const newFieldValues = field.calculateConditionalProperties(fieldIsRequired, node);
|
|
760
901
|
updateValues(newFieldValues);
|
|
@@ -768,33 +909,46 @@ function updateField(field, requiredFields, node, formValues) {
|
|
|
768
909
|
updateValues(newFieldValues);
|
|
769
910
|
}
|
|
770
911
|
}
|
|
771
|
-
function processNode(
|
|
912
|
+
function processNode({
|
|
913
|
+
node,
|
|
914
|
+
formValues,
|
|
915
|
+
formFields,
|
|
916
|
+
accRequired = /* @__PURE__ */ new Set(),
|
|
917
|
+
parentID = "root",
|
|
918
|
+
logic
|
|
919
|
+
}) {
|
|
772
920
|
const requiredFields = new Set(accRequired);
|
|
773
921
|
Object.keys(node.properties ?? []).forEach((fieldName) => {
|
|
774
922
|
const field = getField(fieldName, formFields);
|
|
775
|
-
updateField(field, requiredFields, node, formValues);
|
|
923
|
+
updateField(field, requiredFields, node, formValues, logic, { parentID });
|
|
776
924
|
});
|
|
777
925
|
node.required?.forEach((fieldName) => {
|
|
778
926
|
requiredFields.add(fieldName);
|
|
779
|
-
updateField(getField(fieldName, formFields), requiredFields, node, formValues
|
|
927
|
+
updateField(getField(fieldName, formFields), requiredFields, node, formValues, logic, {
|
|
928
|
+
parentID
|
|
929
|
+
});
|
|
780
930
|
});
|
|
781
931
|
if (node.if) {
|
|
782
|
-
const matchesCondition = checkIfConditionMatches(node, formValues, formFields);
|
|
932
|
+
const matchesCondition = checkIfConditionMatches(node, formValues, formFields, logic);
|
|
783
933
|
if (matchesCondition && node.then) {
|
|
784
|
-
const { required: branchRequired } = processNode(
|
|
785
|
-
node.then,
|
|
934
|
+
const { required: branchRequired } = processNode({
|
|
935
|
+
node: node.then,
|
|
786
936
|
formValues,
|
|
787
937
|
formFields,
|
|
788
|
-
requiredFields
|
|
789
|
-
|
|
938
|
+
accRequired: requiredFields,
|
|
939
|
+
parentID,
|
|
940
|
+
logic
|
|
941
|
+
});
|
|
790
942
|
branchRequired.forEach((field) => requiredFields.add(field));
|
|
791
943
|
} else if (node.else) {
|
|
792
|
-
const { required: branchRequired } = processNode(
|
|
793
|
-
node.else,
|
|
944
|
+
const { required: branchRequired } = processNode({
|
|
945
|
+
node: node.else,
|
|
794
946
|
formValues,
|
|
795
947
|
formFields,
|
|
796
|
-
requiredFields
|
|
797
|
-
|
|
948
|
+
accRequired: requiredFields,
|
|
949
|
+
parentID,
|
|
950
|
+
logic
|
|
951
|
+
});
|
|
798
952
|
branchRequired.forEach((field) => requiredFields.add(field));
|
|
799
953
|
}
|
|
800
954
|
}
|
|
@@ -806,12 +960,21 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
|
|
|
806
960
|
node.anyOf.forEach(({ required = [] }) => {
|
|
807
961
|
required.forEach((fieldName) => {
|
|
808
962
|
const field = getField(fieldName, formFields);
|
|
809
|
-
updateField(field, requiredFields, node, formValues);
|
|
963
|
+
updateField(field, requiredFields, node, formValues, logic, { parentID });
|
|
810
964
|
});
|
|
811
965
|
});
|
|
812
966
|
}
|
|
813
967
|
if (node.allOf) {
|
|
814
|
-
node.allOf.map(
|
|
968
|
+
node.allOf.map(
|
|
969
|
+
(allOfNode) => processNode({
|
|
970
|
+
node: allOfNode,
|
|
971
|
+
formValues,
|
|
972
|
+
formFields,
|
|
973
|
+
accRequired: requiredFields,
|
|
974
|
+
parentID,
|
|
975
|
+
logic
|
|
976
|
+
})
|
|
977
|
+
).forEach(({ required: allOfItemRequired }) => {
|
|
815
978
|
allOfItemRequired.forEach(requiredFields.add, requiredFields);
|
|
816
979
|
});
|
|
817
980
|
}
|
|
@@ -819,7 +982,13 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
|
|
|
819
982
|
Object.entries(node.properties).forEach(([name, nestedNode]) => {
|
|
820
983
|
const inputType = getInputType(nestedNode);
|
|
821
984
|
if (inputType === supportedTypes.FIELDSET) {
|
|
822
|
-
processNode(
|
|
985
|
+
processNode({
|
|
986
|
+
node: nestedNode,
|
|
987
|
+
formValues: formValues[name] || {},
|
|
988
|
+
formFields: getField(name, formFields).fields,
|
|
989
|
+
parentID: name,
|
|
990
|
+
logic
|
|
991
|
+
});
|
|
823
992
|
}
|
|
824
993
|
});
|
|
825
994
|
}
|
|
@@ -837,11 +1006,11 @@ function clearValuesIfNotVisible(fields, formValues) {
|
|
|
837
1006
|
}
|
|
838
1007
|
});
|
|
839
1008
|
}
|
|
840
|
-
function updateFieldsProperties(fields, formValues, jsonSchema) {
|
|
1009
|
+
function updateFieldsProperties(fields, formValues, jsonSchema, logic) {
|
|
841
1010
|
if (!jsonSchema?.properties) {
|
|
842
1011
|
return;
|
|
843
1012
|
}
|
|
844
|
-
processNode(jsonSchema, formValues, fields);
|
|
1013
|
+
processNode({ node: jsonSchema, formValues, formFields: fields, logic });
|
|
845
1014
|
clearValuesIfNotVisible(fields, formValues);
|
|
846
1015
|
}
|
|
847
1016
|
var notNullOption = (opt) => opt.const !== null;
|
|
@@ -884,11 +1053,15 @@ function extractParametersFromNode(schemaNode) {
|
|
|
884
1053
|
}
|
|
885
1054
|
const presentation = pickXKey(schemaNode, "presentation") ?? {};
|
|
886
1055
|
const errorMessage = pickXKey(schemaNode, "errorMessage") ?? {};
|
|
1056
|
+
const requiredValidations = schemaNode["x-jsf-logic-validations"];
|
|
1057
|
+
const computedAttributes = schemaNode["x-jsf-logic-computedAttrs"];
|
|
1058
|
+
const decoratedComputedAttributes = getDecoratedComputedAttributes(computedAttributes);
|
|
887
1059
|
const node = omit(schemaNode, ["x-jsf-presentation", "presentation"]);
|
|
888
1060
|
const description = presentation?.description || node.description;
|
|
889
1061
|
const statementDescription = containsHTML(presentation.statement?.description) ? wrapWithSpan(presentation.statement.description, { class: "jsf-statement" }) : presentation.statement?.description;
|
|
890
1062
|
return omitBy(
|
|
891
1063
|
{
|
|
1064
|
+
const: node.const,
|
|
892
1065
|
label: node.title,
|
|
893
1066
|
readOnly: node.readOnly,
|
|
894
1067
|
...node.deprecated && {
|
|
@@ -923,6 +1096,8 @@ function extractParametersFromNode(schemaNode) {
|
|
|
923
1096
|
},
|
|
924
1097
|
// Handle [name].presentation
|
|
925
1098
|
...presentation,
|
|
1099
|
+
requiredValidations,
|
|
1100
|
+
computedAttributes: decoratedComputedAttributes,
|
|
926
1101
|
description: containsHTML(description) ? wrapWithSpan(description, {
|
|
927
1102
|
class: "jsf-description"
|
|
928
1103
|
}) : description,
|
|
@@ -959,8 +1134,8 @@ function yupToFormErrors(yupError) {
|
|
|
959
1134
|
}
|
|
960
1135
|
return errors;
|
|
961
1136
|
}
|
|
962
|
-
var handleValuesChange = (fields, jsonSchema, config) => (values) => {
|
|
963
|
-
updateFieldsProperties(fields, values, jsonSchema);
|
|
1137
|
+
var handleValuesChange = (fields, jsonSchema, config, logic) => (values) => {
|
|
1138
|
+
updateFieldsProperties(fields, values, jsonSchema, logic);
|
|
964
1139
|
const lazySchema = lazy(() => buildCompleteYupSchema(fields, config));
|
|
965
1140
|
let errors;
|
|
966
1141
|
try {
|
|
@@ -979,6 +1154,12 @@ var handleValuesChange = (fields, jsonSchema, config) => (values) => {
|
|
|
979
1154
|
formErrors: yupToFormErrors(errors)
|
|
980
1155
|
};
|
|
981
1156
|
};
|
|
1157
|
+
function getDecoratedComputedAttributes(computedAttributes) {
|
|
1158
|
+
return {
|
|
1159
|
+
...computedAttributes ?? {},
|
|
1160
|
+
...computedAttributes?.const && computedAttributes?.default ? { value: computedAttributes.const } : {}
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
982
1163
|
|
|
983
1164
|
// src/calculateConditionalProperties.js
|
|
984
1165
|
function isFieldRequired(node, field) {
|
|
@@ -1180,6 +1361,9 @@ function applyFieldsDependencies(fieldsParameters, node) {
|
|
|
1180
1361
|
applyFieldsDependencies(fieldsParameters, condition);
|
|
1181
1362
|
});
|
|
1182
1363
|
}
|
|
1364
|
+
if (node?.["x-jsf-logic"]) {
|
|
1365
|
+
applyFieldsDependencies(fieldsParameters, node["x-jsf-logic"]);
|
|
1366
|
+
}
|
|
1183
1367
|
}
|
|
1184
1368
|
function getCustomPropertiesForField(fieldParams, config) {
|
|
1185
1369
|
return config?.customProperties?.[fieldParams.name];
|
|
@@ -1191,15 +1375,16 @@ function getComposeFunctionForField(fieldParams, hasCustomizations) {
|
|
|
1191
1375
|
}
|
|
1192
1376
|
return composeFn;
|
|
1193
1377
|
}
|
|
1194
|
-
function buildField(fieldParams, config, scopedJsonSchema) {
|
|
1378
|
+
function buildField(fieldParams, config, scopedJsonSchema, logic) {
|
|
1195
1379
|
const customProperties = getCustomPropertiesForField(fieldParams, config);
|
|
1196
1380
|
const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
|
|
1197
|
-
const yupSchema = buildYupSchema(fieldParams, config);
|
|
1381
|
+
const yupSchema = buildYupSchema(fieldParams, config, logic);
|
|
1198
1382
|
const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
|
|
1199
1383
|
const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
|
|
1200
1384
|
fieldParams,
|
|
1201
1385
|
customProperties
|
|
1202
1386
|
);
|
|
1387
|
+
const getComputedAttributes = Object.keys(fieldParams.computedAttributes).length > 0 && calculateComputedAttributes(fieldParams, config);
|
|
1203
1388
|
const hasCustomValidations = !!customProperties && size(pick2(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS)) > 0;
|
|
1204
1389
|
const finalFieldParams = {
|
|
1205
1390
|
// invalid attribute cleanup
|
|
@@ -1212,6 +1397,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
|
|
|
1212
1397
|
...hasCustomValidations && {
|
|
1213
1398
|
calculateCustomValidationProperties: calculateCustomValidationPropertiesClosure
|
|
1214
1399
|
},
|
|
1400
|
+
...getComputedAttributes && { getComputedAttributes },
|
|
1215
1401
|
// field customization properties
|
|
1216
1402
|
...customProperties && { fieldCustomization: customProperties },
|
|
1217
1403
|
// base schema
|
|
@@ -1220,7 +1406,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
|
|
|
1220
1406
|
};
|
|
1221
1407
|
return composeFn(finalFieldParams);
|
|
1222
1408
|
}
|
|
1223
|
-
function getFieldsFromJSONSchema(scopedJsonSchema, config) {
|
|
1409
|
+
function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
|
|
1224
1410
|
if (!scopedJsonSchema) {
|
|
1225
1411
|
return [];
|
|
1226
1412
|
}
|
|
@@ -1244,11 +1430,11 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config) {
|
|
|
1244
1430
|
fields: () => groupArrayFields,
|
|
1245
1431
|
addFieldText: fieldParams.addFieldText
|
|
1246
1432
|
};
|
|
1247
|
-
buildField(fieldParams, config, scopedJsonSchema).forEach((groupField) => {
|
|
1433
|
+
buildField(fieldParams, config, scopedJsonSchema, logic).forEach((groupField) => {
|
|
1248
1434
|
fields.push(groupField);
|
|
1249
1435
|
});
|
|
1250
1436
|
} else {
|
|
1251
|
-
fields.push(buildField(fieldParams, config, scopedJsonSchema));
|
|
1437
|
+
fields.push(buildField(fieldParams, config, scopedJsonSchema, logic));
|
|
1252
1438
|
}
|
|
1253
1439
|
});
|
|
1254
1440
|
return fields;
|
|
@@ -1259,9 +1445,15 @@ function createHeadlessForm(jsonSchema, customConfig = {}) {
|
|
|
1259
1445
|
...customConfig
|
|
1260
1446
|
};
|
|
1261
1447
|
try {
|
|
1262
|
-
const
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1448
|
+
const logic = createValidationChecker(jsonSchema);
|
|
1449
|
+
const fields = getFieldsFromJSONSchema(jsonSchema, config, logic);
|
|
1450
|
+
const handleValidation = handleValuesChange(fields, jsonSchema, config, logic);
|
|
1451
|
+
updateFieldsProperties(
|
|
1452
|
+
fields,
|
|
1453
|
+
getPrefillValues(fields, config.initialValues),
|
|
1454
|
+
jsonSchema,
|
|
1455
|
+
logic
|
|
1456
|
+
);
|
|
1265
1457
|
return {
|
|
1266
1458
|
fields,
|
|
1267
1459
|
handleValidation,
|