@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 CHANGED
@@ -1,3 +1,27 @@
1
+ #### 0.4.5-beta.0 (2023-08-31)
2
+
3
+ ##### Changes
4
+
5
+ * 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))
6
+
7
+ #### 0.4.4-beta.0 (2023-08-30)
8
+
9
+ ##### Chores
10
+
11
+ * **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))
12
+
13
+ #### 0.4.3-beta.0 (2023-08-09)
14
+
15
+ ##### Bug fixes
16
+
17
+ * **conditions:** Validate a deeply nested if (e.g. checking an object with a number property) in an if property now doesn't break the form. ([#33](https://github.com/remoteoss/json-schema-form/pull/33)) ([e34cfcc](https://github.com/remoteoss/json-schema-form/commit/e34cfccaf45f1460b346f3cff0c797b3d11259e3))
18
+
19
+ #### 0.4.2-beta.0 (2023-07-20)
20
+
21
+ ##### Bug Fixes
22
+
23
+ * **date:** Validate based on minDate and maxDate ([#30](https://github.com/remoteoss/json-schema-form/pull/30)) ([01c0143e](https://github.com/remoteoss/json-schema-form/commit/01c0143ea4a3775f9489ae6cb8fd99a90b3f1394))
24
+
1
25
  #### 0.4.1-beta.0 (2023-07-03)
2
26
 
3
27
  ##### 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.0-dev.20230719162322
5
- Generated: Wed, 19 Jul 2023 16:23:38 GMT
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
 
@@ -84,6 +84,69 @@ var import_omitBy = __toESM(require("lodash/omitBy"));
84
84
  var import_set = __toESM(require("lodash/set"));
85
85
  var import_yup2 = require("yup");
86
86
 
87
+ // src/utils.js
88
+ function convertDiskSizeFromTo(from, to) {
89
+ const units = ["bytes", "kb", "mb"];
90
+ return function convert(value) {
91
+ return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
92
+ };
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
+ }
101
+ function hasProperty(object2, propertyName) {
102
+ return Object.prototype.hasOwnProperty.call(object2, propertyName);
103
+ }
104
+
105
+ // src/checkIfConditionMatches.js
106
+ function checkIfConditionMatches(node, formValues, formFields) {
107
+ return Object.keys(node.if.properties).every((name) => {
108
+ const currentProperty = node.if.properties[name];
109
+ const value = formValues[name];
110
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
111
+ value === null;
112
+ const hasIfExplicit = node.if.required?.includes(name);
113
+ if (hasEmptyValue && !hasIfExplicit) {
114
+ return true;
115
+ }
116
+ if (hasProperty(currentProperty, "const")) {
117
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
118
+ }
119
+ if (currentProperty.contains?.pattern) {
120
+ const formValue = value || [];
121
+ if (Array.isArray(formValue)) {
122
+ const pattern = new RegExp(currentProperty.contains.pattern);
123
+ return (value || []).some((item) => pattern.test(item));
124
+ }
125
+ }
126
+ if (currentProperty.enum) {
127
+ return currentProperty.enum.includes(value);
128
+ }
129
+ if (currentProperty.properties) {
130
+ return checkIfConditionMatches(
131
+ { if: currentProperty },
132
+ formValues[name],
133
+ getField(name, formFields).fields
134
+ );
135
+ }
136
+ const field = getField(name, formFields);
137
+ return validateFieldSchema(
138
+ {
139
+ options: field.options,
140
+ // @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
141
+ ...currentProperty,
142
+ inputType: field.inputType,
143
+ required: true
144
+ },
145
+ value
146
+ );
147
+ });
148
+ }
149
+
87
150
  // src/internals/helpers.js
88
151
  var import_merge = __toESM(require("lodash/fp/merge"));
89
152
  var import_get = __toESM(require("lodash/get"));
@@ -343,29 +406,108 @@ function _composeFieldCustomClosure(defaultComposeFn) {
343
406
  };
344
407
  }
345
408
 
346
- // src/utils.js
347
- function convertDiskSizeFromTo(from, to) {
348
- const units = ["bytes", "kb", "mb"];
349
- return function convert(value) {
350
- return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
409
+ // src/yupSchema.js
410
+ var import_flow = __toESM(require("lodash/flow"));
411
+ var import_noop = __toESM(require("lodash/noop"));
412
+ var import_randexp = require("randexp");
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
+ scopes.set(key, createValidationsScope(jsonSchema));
421
+ Object.entries(jsonSchema?.properties ?? {}).filter(([, property]) => property.type === "object" || property.type === "array").forEach(([key2, property]) => {
422
+ if (property.type === "array") {
423
+ createScopes(property.items, `${key2}[]`);
424
+ } else {
425
+ createScopes(property, key2);
426
+ }
427
+ });
428
+ }
429
+ createScopes(schema);
430
+ return {
431
+ scopes,
432
+ getScope(name = "root") {
433
+ return scopes.get(name);
434
+ }
351
435
  };
352
436
  }
353
- function containsHTML(str = "") {
354
- return /<[a-z][\s\S]*>/i.test(str);
437
+ function createValidationsScope(schema) {
438
+ const validationMap = /* @__PURE__ */ new Map();
439
+ const computedValuesMap = /* @__PURE__ */ new Map();
440
+ const logic = schema?.["x-jsf-logic"] ?? {
441
+ validations: {},
442
+ computedValues: {}
443
+ };
444
+ const validations = Object.entries(logic.validations ?? {});
445
+ const computedValues = Object.entries(logic.computedValues ?? {});
446
+ validations.forEach(([id, validation]) => {
447
+ validationMap.set(id, validation);
448
+ });
449
+ computedValues.forEach(([id, computedValue]) => {
450
+ computedValuesMap.set(id, computedValue);
451
+ });
452
+ function validate(rule, values) {
453
+ return import_json_logic_js.default.apply(rule, replaceUndefinedValuesWithNulls(values));
454
+ }
455
+ return {
456
+ validationMap,
457
+ computedValuesMap,
458
+ validate,
459
+ applyValidationRuleInCondition(id, values) {
460
+ const validation = validationMap.get(id);
461
+ return validate(validation.rule, values);
462
+ },
463
+ applyComputedValueInField(id, values) {
464
+ const validation = computedValuesMap.get(id);
465
+ return validate(validation.rule, values);
466
+ },
467
+ applyComputedValueRuleInCondition(id, values) {
468
+ const validation = computedValuesMap.get(id);
469
+ return validate(validation.rule, values);
470
+ }
471
+ };
355
472
  }
356
- function wrapWithSpan(html, properties = {}) {
357
- const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
358
- return `<span ${attributes}>${html}</span>`;
473
+ function replaceUndefinedValuesWithNulls(values = {}) {
474
+ return Object.entries(values).reduce((prev, [key, value]) => {
475
+ return { ...prev, [key]: value === void 0 ? null : value };
476
+ }, {});
359
477
  }
360
- function hasProperty(object2, propertyName) {
361
- return Object.prototype.hasOwnProperty.call(object2, propertyName);
478
+ function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
479
+ const { parentID = "root" } = config;
480
+ const validation = logic.getScope(parentID).validationMap.get(id);
481
+ return (yupSchema) => yupSchema.test(
482
+ `${field.name}-validation-${id}`,
483
+ validation?.errorMessage ?? "This field is invalid.",
484
+ (value, { parent }) => {
485
+ if (value === void 0 && !field.required)
486
+ return true;
487
+ return import_json_logic_js.default.apply(validation.rule, parent);
488
+ }
489
+ );
490
+ }
491
+ function calculateComputedAttributes(fieldParams, { parentID = "root" } = {}) {
492
+ return ({ logic, formValues }) => {
493
+ const { computedAttributes } = fieldParams;
494
+ const attributes = Object.fromEntries(
495
+ Object.entries(computedAttributes).map(handleComputedAttribute(logic, formValues, parentID)).filter(([, value]) => value !== null)
496
+ );
497
+ return attributes;
498
+ };
499
+ }
500
+ function handleComputedAttribute(logic, formValues, parentID) {
501
+ return ([key, value]) => {
502
+ if (key === "const")
503
+ return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
504
+ if (typeof value === "string") {
505
+ return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
506
+ }
507
+ };
362
508
  }
363
509
 
364
510
  // src/yupSchema.js
365
- var import_flow = __toESM(require("lodash/flow"));
366
- var import_noop = __toESM(require("lodash/noop"));
367
- var import_randexp = require("randexp");
368
- var import_yup = require("yup");
369
511
  var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
370
512
  var baseString = (0, import_yup.string)().trim();
371
513
  var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
@@ -488,7 +630,7 @@ var getYupSchema = ({ inputType, ...field }) => {
488
630
  }
489
631
  return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
490
632
  };
491
- function buildYupSchema(field, config) {
633
+ function buildYupSchema(field, config, logic) {
492
634
  const { inputType, jsonType: jsonTypeValue, errorMessage = {}, ...propertyFields } = field;
493
635
  const isCheckboxBoolean = typeof propertyFields.checkboxValue === "boolean";
494
636
  let baseSchema;
@@ -561,6 +703,13 @@ function buildYupSchema(field, config) {
561
703
  }) : true
562
704
  );
563
705
  }
706
+ function withConst(yupSchema) {
707
+ return yupSchema.test(
708
+ "isConst",
709
+ errorMessage.const ?? errorMessageFromConfig.const ?? `The only accepted value is ${propertyFields.const}.`,
710
+ (value) => propertyFields.required === false && value === void 0 || value === null || value === propertyFields.const
711
+ );
712
+ }
564
713
  function withBaseSchema() {
565
714
  const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
566
715
  if (customErrorMsg) {
@@ -628,6 +777,14 @@ function buildYupSchema(field, config) {
628
777
  if (propertyFields.accept) {
629
778
  validators.push(withFileFormat);
630
779
  }
780
+ if (propertyFields.const) {
781
+ validators.push(withConst);
782
+ }
783
+ if (propertyFields.requiredValidations) {
784
+ propertyFields.requiredValidations.forEach(
785
+ (id) => validators.push(yupSchemaWithCustomJSONLogic({ field, id, logic, config }))
786
+ );
787
+ }
631
788
  return (0, import_flow.default)(validators);
632
789
  }
633
790
  function getNoSortEdges(fields = []) {
@@ -667,50 +824,14 @@ function hasType(type, typeName) {
667
824
  function getField(fieldName, fields) {
668
825
  return fields.find(({ name }) => name === fieldName);
669
826
  }
670
- function validateFieldSchema(field, value) {
671
- const validator = buildYupSchema(field);
827
+ function validateFieldSchema(field, value, logic) {
828
+ const validator = buildYupSchema(field, {}, logic);
672
829
  return validator().isValidSync(value);
673
830
  }
674
831
  function compareFormValueWithSchemaValue(formValue, schemaValue) {
675
832
  const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
676
833
  return String(formValue) === String(currentPropertyValue);
677
834
  }
678
- function checkIfConditionMatches(node, formValues, formFields) {
679
- return Object.keys(node.if.properties).every((name) => {
680
- const currentProperty = node.if.properties[name];
681
- const value = formValues[name];
682
- const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
683
- value === null;
684
- const hasIfExplicit = node.if.required?.includes(name);
685
- if (hasEmptyValue && !hasIfExplicit) {
686
- return true;
687
- }
688
- if (hasProperty(currentProperty, "const")) {
689
- return compareFormValueWithSchemaValue(value, currentProperty.const);
690
- }
691
- if (currentProperty.contains?.pattern) {
692
- const formValue = value || [];
693
- if (Array.isArray(formValue)) {
694
- const pattern = new RegExp(currentProperty.contains.pattern);
695
- return (value || []).some((item) => pattern.test(item));
696
- }
697
- }
698
- if (currentProperty.enum) {
699
- return currentProperty.enum.includes(value);
700
- }
701
- const field = getField(name, formFields);
702
- return validateFieldSchema(
703
- {
704
- options: field.options,
705
- // @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
706
- ...currentProperty,
707
- inputType: field.inputType,
708
- required: true
709
- },
710
- value
711
- );
712
- });
713
- }
714
835
  function isFieldFilled(fieldValue) {
715
836
  return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
716
837
  }
@@ -740,7 +861,16 @@ function getPrefillSubFieldValues(field, defaultValues, parentFieldKeyPath) {
740
861
  initialValue[field.name] = subFieldValues;
741
862
  }
742
863
  } else {
743
- initialValue = getPrefillValues([field], initialValue);
864
+ if (typeof initialValue !== "object") {
865
+ console.warn(
866
+ `Field "${parentFieldKeyPath}"'s value is "${initialValue}", but should be type object.`
867
+ );
868
+ initialValue = getPrefillValues([field], {
869
+ // TODO nested fieldsets are not handled
870
+ });
871
+ } else {
872
+ initialValue = getPrefillValues([field], initialValue);
873
+ }
744
874
  }
745
875
  return initialValue;
746
876
  }
@@ -769,7 +899,7 @@ function getPrefillValues(fields, initialValues = {}) {
769
899
  });
770
900
  return initialValues;
771
901
  }
772
- function updateField(field, requiredFields, node, formValues) {
902
+ function updateField(field, requiredFields, node, formValues, logic, config) {
773
903
  if (!field) {
774
904
  return;
775
905
  }
@@ -791,6 +921,17 @@ function updateField(field, requiredFields, node, formValues) {
791
921
  }
792
922
  }
793
923
  });
924
+ if (field.getComputedAttributes) {
925
+ const computedFieldValues = field.getComputedAttributes({
926
+ field,
927
+ isRequired: fieldIsRequired,
928
+ node,
929
+ formValues,
930
+ config,
931
+ logic
932
+ });
933
+ updateValues(computedFieldValues);
934
+ }
794
935
  if (field.calculateConditionalProperties) {
795
936
  const newFieldValues = field.calculateConditionalProperties(fieldIsRequired, node);
796
937
  updateValues(newFieldValues);
@@ -804,33 +945,46 @@ function updateField(field, requiredFields, node, formValues) {
804
945
  updateValues(newFieldValues);
805
946
  }
806
947
  }
807
- function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */ new Set()) {
948
+ function processNode({
949
+ node,
950
+ formValues,
951
+ formFields,
952
+ accRequired = /* @__PURE__ */ new Set(),
953
+ parentID = "root",
954
+ logic
955
+ }) {
808
956
  const requiredFields = new Set(accRequired);
809
957
  Object.keys(node.properties ?? []).forEach((fieldName) => {
810
958
  const field = getField(fieldName, formFields);
811
- updateField(field, requiredFields, node, formValues);
959
+ updateField(field, requiredFields, node, formValues, logic, { parentID });
812
960
  });
813
961
  node.required?.forEach((fieldName) => {
814
962
  requiredFields.add(fieldName);
815
- updateField(getField(fieldName, formFields), requiredFields, node, formValues);
963
+ updateField(getField(fieldName, formFields), requiredFields, node, formValues, logic, {
964
+ parentID
965
+ });
816
966
  });
817
967
  if (node.if) {
818
- const matchesCondition = checkIfConditionMatches(node, formValues, formFields);
968
+ const matchesCondition = checkIfConditionMatches(node, formValues, formFields, logic);
819
969
  if (matchesCondition && node.then) {
820
- const { required: branchRequired } = processNode(
821
- node.then,
970
+ const { required: branchRequired } = processNode({
971
+ node: node.then,
822
972
  formValues,
823
973
  formFields,
824
- requiredFields
825
- );
974
+ accRequired: requiredFields,
975
+ parentID,
976
+ logic
977
+ });
826
978
  branchRequired.forEach((field) => requiredFields.add(field));
827
979
  } else if (node.else) {
828
- const { required: branchRequired } = processNode(
829
- node.else,
980
+ const { required: branchRequired } = processNode({
981
+ node: node.else,
830
982
  formValues,
831
983
  formFields,
832
- requiredFields
833
- );
984
+ accRequired: requiredFields,
985
+ parentID,
986
+ logic
987
+ });
834
988
  branchRequired.forEach((field) => requiredFields.add(field));
835
989
  }
836
990
  }
@@ -842,12 +996,21 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
842
996
  node.anyOf.forEach(({ required = [] }) => {
843
997
  required.forEach((fieldName) => {
844
998
  const field = getField(fieldName, formFields);
845
- updateField(field, requiredFields, node, formValues);
999
+ updateField(field, requiredFields, node, formValues, logic, { parentID });
846
1000
  });
847
1001
  });
848
1002
  }
849
1003
  if (node.allOf) {
850
- node.allOf.map((allOfNode) => processNode(allOfNode, formValues, formFields, requiredFields)).forEach(({ required: allOfItemRequired }) => {
1004
+ node.allOf.map(
1005
+ (allOfNode) => processNode({
1006
+ node: allOfNode,
1007
+ formValues,
1008
+ formFields,
1009
+ accRequired: requiredFields,
1010
+ parentID,
1011
+ logic
1012
+ })
1013
+ ).forEach(({ required: allOfItemRequired }) => {
851
1014
  allOfItemRequired.forEach(requiredFields.add, requiredFields);
852
1015
  });
853
1016
  }
@@ -855,7 +1018,13 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
855
1018
  Object.entries(node.properties).forEach(([name, nestedNode]) => {
856
1019
  const inputType = getInputType(nestedNode);
857
1020
  if (inputType === supportedTypes.FIELDSET) {
858
- processNode(nestedNode, formValues[name] || {}, getField(name, formFields).fields);
1021
+ processNode({
1022
+ node: nestedNode,
1023
+ formValues: formValues[name] || {},
1024
+ formFields: getField(name, formFields).fields,
1025
+ parentID: name,
1026
+ logic
1027
+ });
859
1028
  }
860
1029
  });
861
1030
  }
@@ -873,11 +1042,11 @@ function clearValuesIfNotVisible(fields, formValues) {
873
1042
  }
874
1043
  });
875
1044
  }
876
- function updateFieldsProperties(fields, formValues, jsonSchema) {
1045
+ function updateFieldsProperties(fields, formValues, jsonSchema, logic) {
877
1046
  if (!jsonSchema?.properties) {
878
1047
  return;
879
1048
  }
880
- processNode(jsonSchema, formValues, fields);
1049
+ processNode({ node: jsonSchema, formValues, formFields: fields, logic });
881
1050
  clearValuesIfNotVisible(fields, formValues);
882
1051
  }
883
1052
  var notNullOption = (opt) => opt.const !== null;
@@ -920,11 +1089,15 @@ function extractParametersFromNode(schemaNode) {
920
1089
  }
921
1090
  const presentation = pickXKey(schemaNode, "presentation") ?? {};
922
1091
  const errorMessage = pickXKey(schemaNode, "errorMessage") ?? {};
1092
+ const requiredValidations = schemaNode["x-jsf-logic-validations"];
1093
+ const computedAttributes = schemaNode["x-jsf-logic-computedAttrs"];
1094
+ const decoratedComputedAttributes = getDecoratedComputedAttributes(computedAttributes);
923
1095
  const node = (0, import_omit.default)(schemaNode, ["x-jsf-presentation", "presentation"]);
924
1096
  const description = presentation?.description || node.description;
925
1097
  const statementDescription = containsHTML(presentation.statement?.description) ? wrapWithSpan(presentation.statement.description, { class: "jsf-statement" }) : presentation.statement?.description;
926
1098
  return (0, import_omitBy.default)(
927
1099
  {
1100
+ const: node.const,
928
1101
  label: node.title,
929
1102
  readOnly: node.readOnly,
930
1103
  ...node.deprecated && {
@@ -959,6 +1132,8 @@ function extractParametersFromNode(schemaNode) {
959
1132
  },
960
1133
  // Handle [name].presentation
961
1134
  ...presentation,
1135
+ requiredValidations,
1136
+ computedAttributes: decoratedComputedAttributes,
962
1137
  description: containsHTML(description) ? wrapWithSpan(description, {
963
1138
  class: "jsf-description"
964
1139
  }) : description,
@@ -995,8 +1170,8 @@ function yupToFormErrors(yupError) {
995
1170
  }
996
1171
  return errors;
997
1172
  }
998
- var handleValuesChange = (fields, jsonSchema, config) => (values) => {
999
- updateFieldsProperties(fields, values, jsonSchema);
1173
+ var handleValuesChange = (fields, jsonSchema, config, logic) => (values) => {
1174
+ updateFieldsProperties(fields, values, jsonSchema, logic);
1000
1175
  const lazySchema = (0, import_yup2.lazy)(() => buildCompleteYupSchema(fields, config));
1001
1176
  let errors;
1002
1177
  try {
@@ -1015,6 +1190,12 @@ var handleValuesChange = (fields, jsonSchema, config) => (values) => {
1015
1190
  formErrors: yupToFormErrors(errors)
1016
1191
  };
1017
1192
  };
1193
+ function getDecoratedComputedAttributes(computedAttributes) {
1194
+ return {
1195
+ ...computedAttributes ?? {},
1196
+ ...computedAttributes?.const && computedAttributes?.default ? { value: computedAttributes.const } : {}
1197
+ };
1198
+ }
1018
1199
 
1019
1200
  // src/calculateConditionalProperties.js
1020
1201
  function isFieldRequired(node, field) {
@@ -1216,6 +1397,9 @@ function applyFieldsDependencies(fieldsParameters, node) {
1216
1397
  applyFieldsDependencies(fieldsParameters, condition);
1217
1398
  });
1218
1399
  }
1400
+ if (node?.["x-jsf-logic"]) {
1401
+ applyFieldsDependencies(fieldsParameters, node["x-jsf-logic"]);
1402
+ }
1219
1403
  }
1220
1404
  function getCustomPropertiesForField(fieldParams, config) {
1221
1405
  return config?.customProperties?.[fieldParams.name];
@@ -1227,15 +1411,16 @@ function getComposeFunctionForField(fieldParams, hasCustomizations) {
1227
1411
  }
1228
1412
  return composeFn;
1229
1413
  }
1230
- function buildField(fieldParams, config, scopedJsonSchema) {
1414
+ function buildField(fieldParams, config, scopedJsonSchema, logic) {
1231
1415
  const customProperties = getCustomPropertiesForField(fieldParams, config);
1232
1416
  const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
1233
- const yupSchema = buildYupSchema(fieldParams, config);
1417
+ const yupSchema = buildYupSchema(fieldParams, config, logic);
1234
1418
  const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
1235
1419
  const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
1236
1420
  fieldParams,
1237
1421
  customProperties
1238
1422
  );
1423
+ const getComputedAttributes = Object.keys(fieldParams.computedAttributes).length > 0 && calculateComputedAttributes(fieldParams, config);
1239
1424
  const hasCustomValidations = !!customProperties && (0, import_size.default)((0, import_pick2.default)(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS)) > 0;
1240
1425
  const finalFieldParams = {
1241
1426
  // invalid attribute cleanup
@@ -1248,6 +1433,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
1248
1433
  ...hasCustomValidations && {
1249
1434
  calculateCustomValidationProperties: calculateCustomValidationPropertiesClosure
1250
1435
  },
1436
+ ...getComputedAttributes && { getComputedAttributes },
1251
1437
  // field customization properties
1252
1438
  ...customProperties && { fieldCustomization: customProperties },
1253
1439
  // base schema
@@ -1256,7 +1442,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
1256
1442
  };
1257
1443
  return composeFn(finalFieldParams);
1258
1444
  }
1259
- function getFieldsFromJSONSchema(scopedJsonSchema, config) {
1445
+ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1260
1446
  if (!scopedJsonSchema) {
1261
1447
  return [];
1262
1448
  }
@@ -1280,11 +1466,11 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config) {
1280
1466
  fields: () => groupArrayFields,
1281
1467
  addFieldText: fieldParams.addFieldText
1282
1468
  };
1283
- buildField(fieldParams, config, scopedJsonSchema).forEach((groupField) => {
1469
+ buildField(fieldParams, config, scopedJsonSchema, logic).forEach((groupField) => {
1284
1470
  fields.push(groupField);
1285
1471
  });
1286
1472
  } else {
1287
- fields.push(buildField(fieldParams, config, scopedJsonSchema));
1473
+ fields.push(buildField(fieldParams, config, scopedJsonSchema, logic));
1288
1474
  }
1289
1475
  });
1290
1476
  return fields;
@@ -1295,9 +1481,15 @@ function createHeadlessForm(jsonSchema, customConfig = {}) {
1295
1481
  ...customConfig
1296
1482
  };
1297
1483
  try {
1298
- const fields = getFieldsFromJSONSchema(jsonSchema, config);
1299
- const handleValidation = handleValuesChange(fields, jsonSchema, config);
1300
- updateFieldsProperties(fields, getPrefillValues(fields, config.initialValues), jsonSchema);
1484
+ const logic = createValidationChecker(jsonSchema);
1485
+ const fields = getFieldsFromJSONSchema(jsonSchema, config, logic);
1486
+ const handleValidation = handleValuesChange(fields, jsonSchema, config, logic);
1487
+ updateFieldsProperties(
1488
+ fields,
1489
+ getPrefillValues(fields, config.initialValues),
1490
+ jsonSchema,
1491
+ logic
1492
+ );
1301
1493
  return {
1302
1494
  fields,
1303
1495
  handleValidation,