@remoteoss/json-schema-form 0.6.4-beta.0 → 0.6.5-dev.20230918083235
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 +474 -373
- package/dist/index.js +474 -373
- package/dist/standalone.js +1388 -1287
- package/package.json +1 -1
- package/src/tests/checkIfConditionMatches.test.js +6 -6
- package/src/tests/jsonLogic.fixtures.js +405 -1
- package/src/tests/jsonLogic.test.js +201 -42
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.6.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.6.5-dev.20230918083235
|
|
5
|
+
Generated: Mon, 18 Sep 2023 08:33:03 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -103,8 +103,8 @@ function hasProperty(object2, propertyName) {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// src/checkIfConditionMatches.js
|
|
106
|
-
function
|
|
107
|
-
return Object.keys(node.if.properties).every((name) => {
|
|
106
|
+
function checkIfConditionMatchesProperties(node, formValues, formFields, logic) {
|
|
107
|
+
return Object.keys(node.if.properties ?? {}).every((name) => {
|
|
108
108
|
const currentProperty = node.if.properties[name];
|
|
109
109
|
const value = formValues[name];
|
|
110
110
|
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
@@ -127,10 +127,11 @@ function checkIfConditionMatches(node, formValues, formFields) {
|
|
|
127
127
|
return currentProperty.enum.includes(value);
|
|
128
128
|
}
|
|
129
129
|
if (currentProperty.properties) {
|
|
130
|
-
return
|
|
130
|
+
return checkIfConditionMatchesProperties(
|
|
131
131
|
{ if: currentProperty },
|
|
132
132
|
formValues[name],
|
|
133
|
-
getField(name, formFields).fields
|
|
133
|
+
getField(name, formFields).fields,
|
|
134
|
+
logic
|
|
134
135
|
);
|
|
135
136
|
}
|
|
136
137
|
const field = getField(name, formFields);
|
|
@@ -146,6 +147,23 @@ function checkIfConditionMatches(node, formValues, formFields) {
|
|
|
146
147
|
);
|
|
147
148
|
});
|
|
148
149
|
}
|
|
150
|
+
function checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID) {
|
|
151
|
+
const validationsMatch = Object.entries(node.if.validations ?? {}).every(([name, property]) => {
|
|
152
|
+
const currentValue = logic.getScope(parentID).applyValidationRuleInCondition(name, formValues);
|
|
153
|
+
if (Object.hasOwn(property, "const") && currentValue === property.const)
|
|
154
|
+
return true;
|
|
155
|
+
return false;
|
|
156
|
+
});
|
|
157
|
+
const computedValuesMatch = Object.entries(node.if.computedValues ?? {}).every(
|
|
158
|
+
([name, property]) => {
|
|
159
|
+
const currentValue = logic.getScope(parentID).applyComputedValueRuleInCondition(name, formValues);
|
|
160
|
+
if (Object.hasOwn(property, "const") && currentValue === property.const)
|
|
161
|
+
return true;
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
return computedValuesMatch && validationsMatch;
|
|
166
|
+
}
|
|
149
167
|
|
|
150
168
|
// src/internals/helpers.js
|
|
151
169
|
var import_merge = __toESM(require("lodash/fp/merge"));
|
|
@@ -406,261 +424,14 @@ function _composeFieldCustomClosure(defaultComposeFn) {
|
|
|
406
424
|
};
|
|
407
425
|
}
|
|
408
426
|
|
|
427
|
+
// src/jsonLogic.js
|
|
428
|
+
var import_json_logic_js = __toESM(require("json-logic-js"));
|
|
429
|
+
|
|
409
430
|
// src/yupSchema.js
|
|
410
431
|
var import_flow = __toESM(require("lodash/flow"));
|
|
411
432
|
var import_noop = __toESM(require("lodash/noop"));
|
|
412
433
|
var import_randexp = require("randexp");
|
|
413
434
|
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).validate(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
|
-
if (typeof value === "object" && value.rule) {
|
|
582
|
-
return [key, logic.getScope(parentID).validate(value.rule, formValues)];
|
|
583
|
-
}
|
|
584
|
-
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues, name)];
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
function handleNestedObjectForComputedValues(values, formValues, parentID, logic, name) {
|
|
590
|
-
return Object.fromEntries(
|
|
591
|
-
Object.entries(values).map(([key, value]) => {
|
|
592
|
-
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
593
|
-
})
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
function buildSampleEmptyObject(schema = {}) {
|
|
597
|
-
const sample = {};
|
|
598
|
-
if (typeof schema !== "object" || !schema.properties) {
|
|
599
|
-
return schema;
|
|
600
|
-
}
|
|
601
|
-
for (const key in schema.properties) {
|
|
602
|
-
if (schema.properties[key].type === "object") {
|
|
603
|
-
sample[key] = buildSampleEmptyObject(schema.properties[key]);
|
|
604
|
-
} else if (schema.properties[key].type === "array") {
|
|
605
|
-
const itemSchema = schema.properties[key].items;
|
|
606
|
-
sample[key] = buildSampleEmptyObject(itemSchema);
|
|
607
|
-
} else {
|
|
608
|
-
sample[key] = true;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return sample;
|
|
612
|
-
}
|
|
613
|
-
function validateInlineRules(jsonSchema, sampleEmptyObject) {
|
|
614
|
-
const properties = (jsonSchema?.properties || jsonSchema?.items?.properties) ?? {};
|
|
615
|
-
Object.entries(properties).filter(([, property]) => property["x-jsf-logic-computedAttrs"] !== void 0).forEach(([fieldName, property]) => {
|
|
616
|
-
Object.entries(property["x-jsf-logic-computedAttrs"]).filter(([, value]) => typeof value === "object").forEach(([key, item]) => {
|
|
617
|
-
Object.values(item).forEach((rule) => {
|
|
618
|
-
checkRuleIntegrity(
|
|
619
|
-
rule,
|
|
620
|
-
fieldName,
|
|
621
|
-
sampleEmptyObject,
|
|
622
|
-
(item2) => `[json-schema-form] json-logic error: fieldName "${item2.var}" doesn't exist in field "${fieldName}.x-jsf-logic-computedAttrs.${key}".`
|
|
623
|
-
);
|
|
624
|
-
});
|
|
625
|
-
});
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
function checkRuleIntegrity(rule, id, data, errorMessage = (item) => `[json-schema-form] json-logic error: rule "${id}" has no variable "${item.var}".`) {
|
|
629
|
-
Object.entries(rule ?? {}).map(([operator, subRule]) => {
|
|
630
|
-
if (!Array.isArray(subRule) && subRule !== null && subRule !== void 0)
|
|
631
|
-
return;
|
|
632
|
-
throwIfUnknownOperator(operator, subRule, id);
|
|
633
|
-
subRule.map((item) => {
|
|
634
|
-
const isVar = item !== null && typeof item === "object" && Object.hasOwn(item, "var");
|
|
635
|
-
if (isVar) {
|
|
636
|
-
const exists = import_json_logic_js.default.apply({ var: removeIndicesFromPath(item.var) }, data);
|
|
637
|
-
if (exists === null) {
|
|
638
|
-
throw Error(errorMessage(item));
|
|
639
|
-
}
|
|
640
|
-
} else {
|
|
641
|
-
checkRuleIntegrity(item, id, data);
|
|
642
|
-
}
|
|
643
|
-
});
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
function throwIfUnknownOperator(operator, subRule, id) {
|
|
647
|
-
try {
|
|
648
|
-
import_json_logic_js.default.apply({ [operator]: subRule });
|
|
649
|
-
} catch (e) {
|
|
650
|
-
if (e.message === `Unrecognized operation ${operator}`) {
|
|
651
|
-
throw Error(
|
|
652
|
-
`[json-schema-form] json-logic error: in "${id}" rule there is an unknown operator "${operator}".`
|
|
653
|
-
);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
var regexToGetIndices = /\.\d+\./g;
|
|
658
|
-
function removeIndicesFromPath(path) {
|
|
659
|
-
const intermediatePath = path.replace(regexToGetIndices, ".");
|
|
660
|
-
return intermediatePath.replace(/\.\d+$/, "");
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
// src/yupSchema.js
|
|
664
435
|
var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
|
665
436
|
var baseString = (0, import_yup.string)().trim();
|
|
666
437
|
var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
|
|
@@ -856,118 +627,414 @@ function buildYupSchema(field, config, logic) {
|
|
|
856
627
|
}) : true
|
|
857
628
|
);
|
|
858
629
|
}
|
|
859
|
-
function withConst(yupSchema) {
|
|
860
|
-
return yupSchema.test(
|
|
861
|
-
"isConst",
|
|
862
|
-
errorMessage.const ?? errorMessageFromConfig.const ?? `The only accepted value is ${propertyFields.const}.`,
|
|
863
|
-
(value) => propertyFields.required === false && value === void 0 || value === null || value === propertyFields.const
|
|
630
|
+
function withConst(yupSchema) {
|
|
631
|
+
return yupSchema.test(
|
|
632
|
+
"isConst",
|
|
633
|
+
errorMessage.const ?? errorMessageFromConfig.const ?? `The only accepted value is ${propertyFields.const}.`,
|
|
634
|
+
(value) => propertyFields.required === false && value === void 0 || value === null || value === propertyFields.const
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
function withBaseSchema() {
|
|
638
|
+
const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
|
|
639
|
+
if (customErrorMsg) {
|
|
640
|
+
return baseSchema.typeError(customErrorMsg);
|
|
641
|
+
}
|
|
642
|
+
return baseSchema;
|
|
643
|
+
}
|
|
644
|
+
function buildFieldSetSchema(innerFields) {
|
|
645
|
+
const fieldSetShape = {};
|
|
646
|
+
innerFields.forEach((fieldSetfield) => {
|
|
647
|
+
if (fieldSetfield.fields) {
|
|
648
|
+
fieldSetShape[fieldSetfield.name] = (0, import_yup.object)().shape(
|
|
649
|
+
buildFieldSetSchema(fieldSetfield.fields)
|
|
650
|
+
);
|
|
651
|
+
} else {
|
|
652
|
+
fieldSetShape[fieldSetfield.name] = buildYupSchema(
|
|
653
|
+
{
|
|
654
|
+
...fieldSetfield,
|
|
655
|
+
inputType: fieldSetfield.type
|
|
656
|
+
},
|
|
657
|
+
config
|
|
658
|
+
)();
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
return fieldSetShape;
|
|
662
|
+
}
|
|
663
|
+
function buildGroupArraySchema() {
|
|
664
|
+
return (0, import_yup.object)().shape(
|
|
665
|
+
propertyFields.nthFieldGroup.fields().reduce(
|
|
666
|
+
(schema, groupArrayField) => ({
|
|
667
|
+
...schema,
|
|
668
|
+
[groupArrayField.name]: buildYupSchema(groupArrayField, config)()
|
|
669
|
+
}),
|
|
670
|
+
{}
|
|
671
|
+
)
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
const validators = [withBaseSchema];
|
|
675
|
+
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
676
|
+
validators[0] = () => withBaseSchema().of(buildGroupArraySchema());
|
|
677
|
+
} else if (inputType === supportedTypes.FIELDSET) {
|
|
678
|
+
validators[0] = () => withBaseSchema().shape(buildFieldSetSchema(propertyFields.fields));
|
|
679
|
+
}
|
|
680
|
+
if (propertyFields.required) {
|
|
681
|
+
validators.push(withRequired);
|
|
682
|
+
}
|
|
683
|
+
if (typeof propertyFields.minimum !== "undefined") {
|
|
684
|
+
validators.push(withMin);
|
|
685
|
+
}
|
|
686
|
+
if (typeof propertyFields.minLength !== "undefined") {
|
|
687
|
+
validators.push(withMinLength);
|
|
688
|
+
}
|
|
689
|
+
if (propertyFields.maximum !== void 0) {
|
|
690
|
+
validators.push(withMax);
|
|
691
|
+
}
|
|
692
|
+
if (propertyFields.maxLength) {
|
|
693
|
+
validators.push(withMaxLength);
|
|
694
|
+
}
|
|
695
|
+
if (propertyFields.pattern) {
|
|
696
|
+
validators.push(withMatches);
|
|
697
|
+
}
|
|
698
|
+
if (propertyFields.maxFileSize) {
|
|
699
|
+
validators.push(withMaxFileSize);
|
|
700
|
+
}
|
|
701
|
+
if (propertyFields.accept) {
|
|
702
|
+
validators.push(withFileFormat);
|
|
703
|
+
}
|
|
704
|
+
if (propertyFields.const) {
|
|
705
|
+
validators.push(withConst);
|
|
706
|
+
}
|
|
707
|
+
if (propertyFields.jsonLogicValidations) {
|
|
708
|
+
propertyFields.jsonLogicValidations.forEach(
|
|
709
|
+
(id) => validators.push(yupSchemaWithCustomJSONLogic({ field, id, logic, config }))
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
return (0, import_flow.default)(validators);
|
|
713
|
+
}
|
|
714
|
+
function getNoSortEdges(fields = []) {
|
|
715
|
+
return fields.reduce((list, field) => {
|
|
716
|
+
if (field.noSortEdges) {
|
|
717
|
+
list.push(field.name);
|
|
718
|
+
}
|
|
719
|
+
return list;
|
|
720
|
+
}, []);
|
|
721
|
+
}
|
|
722
|
+
function getSchema(fields = [], config) {
|
|
723
|
+
const newSchema = {};
|
|
724
|
+
fields.forEach((field) => {
|
|
725
|
+
if (field.schema) {
|
|
726
|
+
if (field.name) {
|
|
727
|
+
if (field.inputType === supportedTypes.FIELDSET) {
|
|
728
|
+
const fieldsetSchema = buildYupSchema(field, config)();
|
|
729
|
+
newSchema[field.name] = fieldsetSchema;
|
|
730
|
+
} else {
|
|
731
|
+
newSchema[field.name] = field.schema;
|
|
732
|
+
}
|
|
733
|
+
} else {
|
|
734
|
+
Object.assign(newSchema, getSchema(field.fields, config));
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
return newSchema;
|
|
739
|
+
}
|
|
740
|
+
function buildCompleteYupSchema(fields, config) {
|
|
741
|
+
return (0, import_yup.object)().shape(getSchema(fields, config), getNoSortEdges(fields));
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/jsonLogic.js
|
|
745
|
+
function createValidationChecker(schema) {
|
|
746
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
747
|
+
function createScopes(jsonSchema, key = "root") {
|
|
748
|
+
const sampleEmptyObject = buildSampleEmptyObject(schema);
|
|
749
|
+
scopes.set(key, createValidationsScope(jsonSchema));
|
|
750
|
+
Object.entries(jsonSchema?.properties ?? {}).filter(([, property]) => property.type === "object" || property.type === "array").forEach(([key2, property]) => {
|
|
751
|
+
if (property.type === "array") {
|
|
752
|
+
createScopes(property.items, `${key2}[]`);
|
|
753
|
+
} else {
|
|
754
|
+
createScopes(property, key2);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
validateInlineRules(jsonSchema, sampleEmptyObject);
|
|
758
|
+
}
|
|
759
|
+
createScopes(schema);
|
|
760
|
+
return {
|
|
761
|
+
scopes,
|
|
762
|
+
getScope(name = "root") {
|
|
763
|
+
return scopes.get(name);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
function createValidationsScope(schema) {
|
|
768
|
+
const validationMap = /* @__PURE__ */ new Map();
|
|
769
|
+
const computedValuesMap = /* @__PURE__ */ new Map();
|
|
770
|
+
const logic = schema?.["x-jsf-logic"] ?? {
|
|
771
|
+
validations: {},
|
|
772
|
+
computedValues: {}
|
|
773
|
+
};
|
|
774
|
+
const validations = Object.entries(logic.validations ?? {});
|
|
775
|
+
const computedValues = Object.entries(logic.computedValues ?? {});
|
|
776
|
+
const sampleEmptyObject = buildSampleEmptyObject(schema);
|
|
777
|
+
validations.forEach(([id, validation]) => {
|
|
778
|
+
if (!validation.rule) {
|
|
779
|
+
throw Error(`[json-schema-form] json-logic error: Validation "${id}" has missing rule.`);
|
|
780
|
+
}
|
|
781
|
+
checkRuleIntegrity(validation.rule, id, sampleEmptyObject);
|
|
782
|
+
validationMap.set(id, validation);
|
|
783
|
+
});
|
|
784
|
+
computedValues.forEach(([id, computedValue]) => {
|
|
785
|
+
if (!computedValue.rule) {
|
|
786
|
+
throw Error(`[json-schema-form] json-logic error: Computed value "${id}" has missing rule.`);
|
|
787
|
+
}
|
|
788
|
+
checkRuleIntegrity(computedValue.rule, id, sampleEmptyObject);
|
|
789
|
+
computedValuesMap.set(id, computedValue);
|
|
790
|
+
});
|
|
791
|
+
function validate(rule, values) {
|
|
792
|
+
return import_json_logic_js.default.apply(
|
|
793
|
+
rule,
|
|
794
|
+
replaceUndefinedValuesWithNulls({ ...sampleEmptyObject, ...values })
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
return {
|
|
798
|
+
validationMap,
|
|
799
|
+
computedValuesMap,
|
|
800
|
+
validate,
|
|
801
|
+
applyValidationRuleInCondition(id, values) {
|
|
802
|
+
const validation = validationMap.get(id);
|
|
803
|
+
return validate(validation.rule, values);
|
|
804
|
+
},
|
|
805
|
+
applyComputedValueInField(id, values, fieldName) {
|
|
806
|
+
const validation = computedValuesMap.get(id);
|
|
807
|
+
if (validation === void 0) {
|
|
808
|
+
throw Error(
|
|
809
|
+
`[json-schema-form] json-logic error: Computed value "${id}" doesn't exist in field "${fieldName}".`
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
return validate(validation.rule, values);
|
|
813
|
+
},
|
|
814
|
+
applyComputedValueRuleInCondition(id, values) {
|
|
815
|
+
const validation = computedValuesMap.get(id);
|
|
816
|
+
return validate(validation.rule, values);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
function replaceUndefinedValuesWithNulls(values = {}) {
|
|
821
|
+
return Object.entries(values).reduce((prev, [key, value]) => {
|
|
822
|
+
return { ...prev, [key]: value === void 0 || value === null ? NaN : value };
|
|
823
|
+
}, {});
|
|
824
|
+
}
|
|
825
|
+
function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
|
|
826
|
+
const { parentID = "root" } = config;
|
|
827
|
+
const validation = logic.getScope(parentID).validationMap.get(id);
|
|
828
|
+
if (validation === void 0) {
|
|
829
|
+
throw Error(
|
|
830
|
+
`[json-schema-form] json-logic error: "${field.name}" required validation "${id}" doesn't exist.`
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
return (yupSchema) => yupSchema.test(
|
|
834
|
+
`${field.name}-validation-${id}`,
|
|
835
|
+
validation?.errorMessage ?? "This field is invalid.",
|
|
836
|
+
(value, { parent }) => {
|
|
837
|
+
if (value === void 0 && !field.required)
|
|
838
|
+
return true;
|
|
839
|
+
return import_json_logic_js.default.apply(validation.rule, parent);
|
|
840
|
+
}
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
var HANDLEBARS_REGEX = /\{\{([^{}]+)\}\}/g;
|
|
844
|
+
function replaceHandlebarsTemplates({
|
|
845
|
+
value: toReplace,
|
|
846
|
+
logic,
|
|
847
|
+
formValues,
|
|
848
|
+
parentID,
|
|
849
|
+
name: fieldName
|
|
850
|
+
}) {
|
|
851
|
+
if (typeof toReplace === "string") {
|
|
852
|
+
return toReplace.replace(HANDLEBARS_REGEX, (match, key) => {
|
|
853
|
+
return logic.getScope(parentID).applyComputedValueInField(key.trim(), formValues, fieldName);
|
|
854
|
+
});
|
|
855
|
+
} else if (typeof toReplace === "object") {
|
|
856
|
+
const { value, ...rules } = toReplace;
|
|
857
|
+
if (Object.keys(rules).length > 1 && !value) {
|
|
858
|
+
throw Error("Cannot define multiple rules without a template string with key `value`.");
|
|
859
|
+
}
|
|
860
|
+
const computedTemplateValue = Object.entries(rules).reduce((prev, [key, rule]) => {
|
|
861
|
+
const computedValue = logic.getScope(parentID).validate(rule, formValues);
|
|
862
|
+
return prev.replaceAll(`{{${key}}}`, computedValue);
|
|
863
|
+
}, value);
|
|
864
|
+
return computedTemplateValue.replace(/\{\{([^{}]+)\}\}/g, (match, key) => {
|
|
865
|
+
return logic.getScope(parentID).applyComputedValueInField(key.trim(), formValues, fieldName);
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
return toReplace;
|
|
869
|
+
}
|
|
870
|
+
function calculateComputedAttributes(fieldParams, { parentID = "root" } = {}) {
|
|
871
|
+
return ({ logic, isRequired, config, formValues }) => {
|
|
872
|
+
const { name, computedAttributes } = fieldParams;
|
|
873
|
+
const attributes = Object.fromEntries(
|
|
874
|
+
Object.entries(computedAttributes).map(handleComputedAttribute(logic, formValues, parentID, name)).filter(([, value]) => value !== null)
|
|
864
875
|
);
|
|
876
|
+
return {
|
|
877
|
+
...attributes,
|
|
878
|
+
schema: buildYupSchema(
|
|
879
|
+
{ ...fieldParams, ...attributes, required: isRequired },
|
|
880
|
+
config,
|
|
881
|
+
logic
|
|
882
|
+
)
|
|
883
|
+
};
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function handleComputedAttribute(logic, formValues, parentID, name) {
|
|
887
|
+
return ([key, value]) => {
|
|
888
|
+
switch (key) {
|
|
889
|
+
case "description":
|
|
890
|
+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
891
|
+
case "title":
|
|
892
|
+
return ["label", replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
893
|
+
case "x-jsf-errorMessage":
|
|
894
|
+
return [
|
|
895
|
+
"errorMessage",
|
|
896
|
+
handleNestedObjectForComputedValues(value, formValues, parentID, logic, name)
|
|
897
|
+
];
|
|
898
|
+
case "x-jsf-presentation": {
|
|
899
|
+
if (value.statement) {
|
|
900
|
+
return [
|
|
901
|
+
"statement",
|
|
902
|
+
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name)
|
|
903
|
+
];
|
|
904
|
+
}
|
|
905
|
+
return [
|
|
906
|
+
key,
|
|
907
|
+
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name)
|
|
908
|
+
];
|
|
909
|
+
}
|
|
910
|
+
case "const":
|
|
911
|
+
default: {
|
|
912
|
+
if (typeof value === "object" && value.rule) {
|
|
913
|
+
return [key, logic.getScope(parentID).validate(value.rule, formValues)];
|
|
914
|
+
}
|
|
915
|
+
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues, name)];
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
function handleNestedObjectForComputedValues(values, formValues, parentID, logic, name) {
|
|
921
|
+
return Object.fromEntries(
|
|
922
|
+
Object.entries(values).map(([key, value]) => {
|
|
923
|
+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
|
|
924
|
+
})
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
function buildSampleEmptyObject(schema = {}) {
|
|
928
|
+
const sample = {};
|
|
929
|
+
if (typeof schema !== "object" || !schema.properties) {
|
|
930
|
+
return schema;
|
|
865
931
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
932
|
+
for (const key in schema.properties) {
|
|
933
|
+
if (schema.properties[key].type === "object") {
|
|
934
|
+
sample[key] = buildSampleEmptyObject(schema.properties[key]);
|
|
935
|
+
} else if (schema.properties[key].type === "array") {
|
|
936
|
+
const itemSchema = schema.properties[key].items;
|
|
937
|
+
sample[key] = buildSampleEmptyObject(itemSchema);
|
|
938
|
+
} else {
|
|
939
|
+
sample[key] = true;
|
|
870
940
|
}
|
|
871
|
-
return baseSchema;
|
|
872
941
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
942
|
+
return sample;
|
|
943
|
+
}
|
|
944
|
+
function validateInlineRules(jsonSchema, sampleEmptyObject) {
|
|
945
|
+
const properties = (jsonSchema?.properties || jsonSchema?.items?.properties) ?? {};
|
|
946
|
+
Object.entries(properties).filter(([, property]) => property["x-jsf-logic-computedAttrs"] !== void 0).forEach(([fieldName, property]) => {
|
|
947
|
+
Object.entries(property["x-jsf-logic-computedAttrs"]).filter(([, value]) => typeof value === "object").forEach(([key, item]) => {
|
|
948
|
+
Object.values(item).forEach((rule) => {
|
|
949
|
+
checkRuleIntegrity(
|
|
950
|
+
rule,
|
|
951
|
+
fieldName,
|
|
952
|
+
sampleEmptyObject,
|
|
953
|
+
(item2) => `[json-schema-form] json-logic error: fieldName "${item2.var}" doesn't exist in field "${fieldName}.x-jsf-logic-computedAttrs.${key}".`
|
|
879
954
|
);
|
|
955
|
+
});
|
|
956
|
+
});
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
function checkRuleIntegrity(rule, id, data, errorMessage = (item) => `[json-schema-form] json-logic error: rule "${id}" has no variable "${item.var}".`) {
|
|
960
|
+
Object.entries(rule ?? {}).map(([operator, subRule]) => {
|
|
961
|
+
if (!Array.isArray(subRule) && subRule !== null && subRule !== void 0)
|
|
962
|
+
return;
|
|
963
|
+
throwIfUnknownOperator(operator, subRule, id);
|
|
964
|
+
subRule.map((item) => {
|
|
965
|
+
const isVar = item !== null && typeof item === "object" && Object.hasOwn(item, "var");
|
|
966
|
+
if (isVar) {
|
|
967
|
+
const exists = import_json_logic_js.default.apply({ var: removeIndicesFromPath(item.var) }, data);
|
|
968
|
+
if (exists === null) {
|
|
969
|
+
throw Error(errorMessage(item));
|
|
970
|
+
}
|
|
880
971
|
} else {
|
|
881
|
-
|
|
882
|
-
{
|
|
883
|
-
...fieldSetfield,
|
|
884
|
-
inputType: fieldSetfield.type
|
|
885
|
-
},
|
|
886
|
-
config
|
|
887
|
-
)();
|
|
972
|
+
checkRuleIntegrity(item, id, data);
|
|
888
973
|
}
|
|
889
974
|
});
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
);
|
|
902
|
-
}
|
|
903
|
-
const validators = [withBaseSchema];
|
|
904
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
905
|
-
validators[0] = () => withBaseSchema().of(buildGroupArraySchema());
|
|
906
|
-
} else if (inputType === supportedTypes.FIELDSET) {
|
|
907
|
-
validators[0] = () => withBaseSchema().shape(buildFieldSetSchema(propertyFields.fields));
|
|
908
|
-
}
|
|
909
|
-
if (propertyFields.required) {
|
|
910
|
-
validators.push(withRequired);
|
|
911
|
-
}
|
|
912
|
-
if (typeof propertyFields.minimum !== "undefined") {
|
|
913
|
-
validators.push(withMin);
|
|
914
|
-
}
|
|
915
|
-
if (typeof propertyFields.minLength !== "undefined") {
|
|
916
|
-
validators.push(withMinLength);
|
|
917
|
-
}
|
|
918
|
-
if (propertyFields.maximum !== void 0) {
|
|
919
|
-
validators.push(withMax);
|
|
920
|
-
}
|
|
921
|
-
if (propertyFields.maxLength) {
|
|
922
|
-
validators.push(withMaxLength);
|
|
923
|
-
}
|
|
924
|
-
if (propertyFields.pattern) {
|
|
925
|
-
validators.push(withMatches);
|
|
926
|
-
}
|
|
927
|
-
if (propertyFields.maxFileSize) {
|
|
928
|
-
validators.push(withMaxFileSize);
|
|
929
|
-
}
|
|
930
|
-
if (propertyFields.accept) {
|
|
931
|
-
validators.push(withFileFormat);
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
function throwIfUnknownOperator(operator, subRule, id) {
|
|
978
|
+
try {
|
|
979
|
+
import_json_logic_js.default.apply({ [operator]: subRule });
|
|
980
|
+
} catch (e) {
|
|
981
|
+
if (e.message === `Unrecognized operation ${operator}`) {
|
|
982
|
+
throw Error(
|
|
983
|
+
`[json-schema-form] json-logic error: in "${id}" rule there is an unknown operator "${operator}".`
|
|
984
|
+
);
|
|
985
|
+
}
|
|
932
986
|
}
|
|
933
|
-
|
|
934
|
-
|
|
987
|
+
}
|
|
988
|
+
var regexToGetIndices = /\.\d+\./g;
|
|
989
|
+
function removeIndicesFromPath(path) {
|
|
990
|
+
const intermediatePath = path.replace(regexToGetIndices, ".");
|
|
991
|
+
return intermediatePath.replace(/\.\d+$/, "");
|
|
992
|
+
}
|
|
993
|
+
function processJSONLogicNode({
|
|
994
|
+
node,
|
|
995
|
+
formFields,
|
|
996
|
+
formValues,
|
|
997
|
+
accRequired,
|
|
998
|
+
parentID,
|
|
999
|
+
logic
|
|
1000
|
+
}) {
|
|
1001
|
+
const requiredFields = new Set(accRequired);
|
|
1002
|
+
if (node.allOf) {
|
|
1003
|
+
node.allOf.map(
|
|
1004
|
+
(allOfNode) => processJSONLogicNode({ node: allOfNode, formValues, formFields, logic, parentID })
|
|
1005
|
+
).forEach(({ required: allOfItemRequired }) => {
|
|
1006
|
+
allOfItemRequired.forEach(requiredFields.add, requiredFields);
|
|
1007
|
+
});
|
|
935
1008
|
}
|
|
936
|
-
if (
|
|
937
|
-
|
|
938
|
-
|
|
1009
|
+
if (node.if) {
|
|
1010
|
+
const matchesPropertyCondition = checkIfConditionMatchesProperties(
|
|
1011
|
+
node,
|
|
1012
|
+
formValues,
|
|
1013
|
+
formFields,
|
|
1014
|
+
logic
|
|
939
1015
|
);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
if (field.noSortEdges) {
|
|
946
|
-
list.push(field.name);
|
|
1016
|
+
const matchesValidationsAndComputedValues = matchesPropertyCondition && checkIfMatchesValidationsAndComputedValues(node, formValues, logic, parentID);
|
|
1017
|
+
const isConditionMatch = matchesPropertyCondition && matchesValidationsAndComputedValues;
|
|
1018
|
+
let nextNode;
|
|
1019
|
+
if (isConditionMatch && node.then) {
|
|
1020
|
+
nextNode = node.then;
|
|
947
1021
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
}
|
|
951
|
-
function getSchema(fields = [], config) {
|
|
952
|
-
const newSchema = {};
|
|
953
|
-
fields.forEach((field) => {
|
|
954
|
-
if (field.schema) {
|
|
955
|
-
if (field.name) {
|
|
956
|
-
if (field.inputType === supportedTypes.FIELDSET) {
|
|
957
|
-
const fieldsetSchema = buildYupSchema(field, config)();
|
|
958
|
-
newSchema[field.name] = fieldsetSchema;
|
|
959
|
-
} else {
|
|
960
|
-
newSchema[field.name] = field.schema;
|
|
961
|
-
}
|
|
962
|
-
} else {
|
|
963
|
-
Object.assign(newSchema, getSchema(field.fields, config));
|
|
964
|
-
}
|
|
1022
|
+
if (!isConditionMatch && node.else) {
|
|
1023
|
+
nextNode = node.else;
|
|
965
1024
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1025
|
+
if (nextNode) {
|
|
1026
|
+
const { required: branchRequired } = processNode({
|
|
1027
|
+
node: nextNode,
|
|
1028
|
+
formValues,
|
|
1029
|
+
formFields,
|
|
1030
|
+
accRequired,
|
|
1031
|
+
logic,
|
|
1032
|
+
parentID
|
|
1033
|
+
});
|
|
1034
|
+
branchRequired.forEach((field) => requiredFields.add(field));
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
return { required: requiredFields };
|
|
971
1038
|
}
|
|
972
1039
|
|
|
973
1040
|
// src/helpers.js
|
|
@@ -1086,7 +1153,11 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1086
1153
|
updateValues(computedFieldValues);
|
|
1087
1154
|
}
|
|
1088
1155
|
if (field.calculateConditionalProperties) {
|
|
1089
|
-
const newFieldValues = field.calculateConditionalProperties(
|
|
1156
|
+
const newFieldValues = field.calculateConditionalProperties({
|
|
1157
|
+
isRequired: fieldIsRequired,
|
|
1158
|
+
conditionBranch: node,
|
|
1159
|
+
formValues
|
|
1160
|
+
});
|
|
1090
1161
|
updateValues(newFieldValues);
|
|
1091
1162
|
}
|
|
1092
1163
|
if (field.calculateCustomValidationProperties) {
|
|
@@ -1118,7 +1189,7 @@ function processNode({
|
|
|
1118
1189
|
});
|
|
1119
1190
|
});
|
|
1120
1191
|
if (node.if) {
|
|
1121
|
-
const matchesCondition =
|
|
1192
|
+
const matchesCondition = checkIfConditionMatchesProperties(node, formValues, formFields, logic);
|
|
1122
1193
|
if (matchesCondition && node.then) {
|
|
1123
1194
|
const { required: branchRequired } = processNode({
|
|
1124
1195
|
node: node.then,
|
|
@@ -1181,6 +1252,17 @@ function processNode({
|
|
|
1181
1252
|
}
|
|
1182
1253
|
});
|
|
1183
1254
|
}
|
|
1255
|
+
if (node["x-jsf-logic"]) {
|
|
1256
|
+
const { required: requiredFromLogic } = processJSONLogicNode({
|
|
1257
|
+
node: node["x-jsf-logic"],
|
|
1258
|
+
formValues,
|
|
1259
|
+
formFields,
|
|
1260
|
+
accRequired: requiredFields,
|
|
1261
|
+
parentID,
|
|
1262
|
+
logic
|
|
1263
|
+
});
|
|
1264
|
+
requiredFromLogic.forEach((field) => requiredFields.add(field));
|
|
1265
|
+
}
|
|
1184
1266
|
return {
|
|
1185
1267
|
required: requiredFields
|
|
1186
1268
|
};
|
|
@@ -1242,7 +1324,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
1242
1324
|
}
|
|
1243
1325
|
const presentation = pickXKey(schemaNode, "presentation") ?? {};
|
|
1244
1326
|
const errorMessage = pickXKey(schemaNode, "errorMessage") ?? {};
|
|
1245
|
-
const
|
|
1327
|
+
const jsonLogicValidations = schemaNode["x-jsf-logic-validations"];
|
|
1246
1328
|
const computedAttributes = schemaNode["x-jsf-logic-computedAttrs"];
|
|
1247
1329
|
const decoratedComputedAttributes = getDecoratedComputedAttributes(computedAttributes);
|
|
1248
1330
|
const node = (0, import_omit.default)(schemaNode, ["x-jsf-presentation", "presentation"]);
|
|
@@ -1286,7 +1368,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
1286
1368
|
},
|
|
1287
1369
|
// Handle [name].presentation
|
|
1288
1370
|
...presentation,
|
|
1289
|
-
|
|
1371
|
+
jsonLogicValidations,
|
|
1290
1372
|
computedAttributes: decoratedComputedAttributes,
|
|
1291
1373
|
description: containsHTML(description) ? wrapWithSpan(description, {
|
|
1292
1374
|
class: "jsf-description"
|
|
@@ -1386,8 +1468,8 @@ function rebuildFieldset(fields, property) {
|
|
|
1386
1468
|
required: isFieldRequired(property, field)
|
|
1387
1469
|
}));
|
|
1388
1470
|
}
|
|
1389
|
-
function calculateConditionalProperties(fieldParams, customProperties) {
|
|
1390
|
-
return (isRequired, conditionBranch) => {
|
|
1471
|
+
function calculateConditionalProperties({ fieldParams, customProperties, logic, config }) {
|
|
1472
|
+
return ({ isRequired, conditionBranch, formValues }) => {
|
|
1391
1473
|
const conditionalProperty = conditionBranch?.properties?.[fieldParams.name];
|
|
1392
1474
|
if (conditionalProperty) {
|
|
1393
1475
|
const presentation = pickXKey(conditionalProperty, "presentation") ?? {};
|
|
@@ -1401,17 +1483,31 @@ function calculateConditionalProperties(fieldParams, customProperties) {
|
|
|
1401
1483
|
fieldSetFields = rebuildFieldset(fieldParams.fields, conditionalProperty);
|
|
1402
1484
|
newFieldParams.fields = fieldSetFields;
|
|
1403
1485
|
}
|
|
1486
|
+
const { computedAttributes, ...restNewFieldParams } = newFieldParams;
|
|
1487
|
+
const calculatedComputedAttributes = computedAttributes ? calculateComputedAttributes(newFieldParams, config)({ logic, formValues }) : {};
|
|
1488
|
+
const jsonLogicValidations = [
|
|
1489
|
+
...fieldParams.jsonLogicValidations ?? [],
|
|
1490
|
+
...restNewFieldParams.jsonLogicValidations ?? []
|
|
1491
|
+
];
|
|
1404
1492
|
const base = {
|
|
1405
1493
|
isVisible: true,
|
|
1406
1494
|
required: isRequired,
|
|
1407
1495
|
...presentation?.inputType && { type: presentation.inputType },
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1496
|
+
...calculatedComputedAttributes,
|
|
1497
|
+
...calculatedComputedAttributes.value ? { value: calculatedComputedAttributes.value } : { value: void 0 },
|
|
1498
|
+
schema: buildYupSchema(
|
|
1499
|
+
{
|
|
1500
|
+
...fieldParams,
|
|
1501
|
+
...restNewFieldParams,
|
|
1502
|
+
...calculatedComputedAttributes,
|
|
1503
|
+
jsonLogicValidations,
|
|
1504
|
+
// If there are inner fields (case of fieldset) they need to be updated based on the condition
|
|
1505
|
+
fields: fieldSetFields,
|
|
1506
|
+
required: isRequired
|
|
1507
|
+
},
|
|
1508
|
+
config,
|
|
1509
|
+
logic
|
|
1510
|
+
)
|
|
1415
1511
|
};
|
|
1416
1512
|
return (0, import_omit2.default)((0, import_merge2.default)(base, presentation, newFieldParams), ["inputType"]);
|
|
1417
1513
|
}
|
|
@@ -1505,14 +1601,19 @@ function sortByOrderOrPosition(a, b, order) {
|
|
|
1505
1601
|
function removeInvalidAttributes(fields) {
|
|
1506
1602
|
return (0, import_omit3.default)(fields, ["items", "maxFileSize", "isDynamic"]);
|
|
1507
1603
|
}
|
|
1508
|
-
function buildFieldParameters(name, fieldProperties, required = [], config = {}) {
|
|
1604
|
+
function buildFieldParameters(name, fieldProperties, required = [], config = {}, logic) {
|
|
1509
1605
|
const { position } = pickXKey(fieldProperties, "presentation") ?? {};
|
|
1510
1606
|
let fields;
|
|
1511
1607
|
const inputType = getInputType(fieldProperties, config.strictInputType, name);
|
|
1512
1608
|
if (inputType === supportedTypes.FIELDSET) {
|
|
1513
|
-
fields = getFieldsFromJSONSchema(
|
|
1514
|
-
|
|
1515
|
-
|
|
1609
|
+
fields = getFieldsFromJSONSchema(
|
|
1610
|
+
fieldProperties,
|
|
1611
|
+
{
|
|
1612
|
+
customProperties: (0, import_get3.default)(config, `customProperties.${name}`, {}),
|
|
1613
|
+
parentID: name
|
|
1614
|
+
},
|
|
1615
|
+
logic
|
|
1616
|
+
);
|
|
1516
1617
|
}
|
|
1517
1618
|
const result = {
|
|
1518
1619
|
name,
|
|
@@ -1569,7 +1670,7 @@ function buildField(fieldParams, config, scopedJsonSchema, logic) {
|
|
|
1569
1670
|
const customProperties = getCustomPropertiesForField(fieldParams, config);
|
|
1570
1671
|
const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
|
|
1571
1672
|
const yupSchema = buildYupSchema(fieldParams, config, logic);
|
|
1572
|
-
const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
|
|
1673
|
+
const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties({ fieldParams, customProperties, logic, config });
|
|
1573
1674
|
const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
|
|
1574
1675
|
fieldParams,
|
|
1575
1676
|
customProperties
|