@remoteoss/json-schema-form 0.4.4-dev.20230830125207 → 0.4.6-dev.20230911130751

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.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.4.4-dev.20230830125207
5
- Generated: Wed, 30 Aug 2023 12:52:17 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.6-dev.20230911130751
5
+ Generated: Mon, 11 Sep 2023 13:08:22 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -375,6 +375,103 @@ import flow from "lodash/flow";
375
375
  import noop from "lodash/noop";
376
376
  import { randexp } from "randexp";
377
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
+ }
399
+ };
400
+ }
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
+ };
436
+ }
437
+ function replaceUndefinedValuesWithNulls(values = {}) {
438
+ return Object.entries(values).reduce((prev, [key, value]) => {
439
+ return { ...prev, [key]: value === void 0 ? null : value };
440
+ }, {});
441
+ }
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
+ };
472
+ }
473
+
474
+ // src/yupSchema.js
378
475
  var DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
379
476
  var baseString = string().trim();
380
477
  var todayDateHint = (/* @__PURE__ */ new Date()).toISOString().substring(0, 10);
@@ -497,7 +594,7 @@ var getYupSchema = ({ inputType, ...field }) => {
497
594
  }
498
595
  return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
499
596
  };
500
- function buildYupSchema(field, config) {
597
+ function buildYupSchema(field, config, logic) {
501
598
  const { inputType, jsonType: jsonTypeValue, errorMessage = {}, ...propertyFields } = field;
502
599
  const isCheckboxBoolean = typeof propertyFields.checkboxValue === "boolean";
503
600
  let baseSchema;
@@ -570,6 +667,13 @@ function buildYupSchema(field, config) {
570
667
  }) : true
571
668
  );
572
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
+ }
573
677
  function withBaseSchema() {
574
678
  const customErrorMsg = errorMessage.type || errorMessageFromConfig.type;
575
679
  if (customErrorMsg) {
@@ -637,6 +741,14 @@ function buildYupSchema(field, config) {
637
741
  if (propertyFields.accept) {
638
742
  validators.push(withFileFormat);
639
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
+ }
640
752
  return flow(validators);
641
753
  }
642
754
  function getNoSortEdges(fields = []) {
@@ -676,8 +788,8 @@ function hasType(type, typeName) {
676
788
  function getField(fieldName, fields) {
677
789
  return fields.find(({ name }) => name === fieldName);
678
790
  }
679
- function validateFieldSchema(field, value) {
680
- const validator = buildYupSchema(field);
791
+ function validateFieldSchema(field, value, logic) {
792
+ const validator = buildYupSchema(field, {}, logic);
681
793
  return validator().isValidSync(value);
682
794
  }
683
795
  function compareFormValueWithSchemaValue(formValue, schemaValue) {
@@ -751,7 +863,7 @@ function getPrefillValues(fields, initialValues = {}) {
751
863
  });
752
864
  return initialValues;
753
865
  }
754
- function updateField(field, requiredFields, node, formValues) {
866
+ function updateField(field, requiredFields, node, formValues, logic, config) {
755
867
  if (!field) {
756
868
  return;
757
869
  }
@@ -773,6 +885,17 @@ function updateField(field, requiredFields, node, formValues) {
773
885
  }
774
886
  }
775
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
+ }
776
899
  if (field.calculateConditionalProperties) {
777
900
  const newFieldValues = field.calculateConditionalProperties(fieldIsRequired, node);
778
901
  updateValues(newFieldValues);
@@ -786,33 +909,46 @@ function updateField(field, requiredFields, node, formValues) {
786
909
  updateValues(newFieldValues);
787
910
  }
788
911
  }
789
- function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */ new Set()) {
912
+ function processNode({
913
+ node,
914
+ formValues,
915
+ formFields,
916
+ accRequired = /* @__PURE__ */ new Set(),
917
+ parentID = "root",
918
+ logic
919
+ }) {
790
920
  const requiredFields = new Set(accRequired);
791
921
  Object.keys(node.properties ?? []).forEach((fieldName) => {
792
922
  const field = getField(fieldName, formFields);
793
- updateField(field, requiredFields, node, formValues);
923
+ updateField(field, requiredFields, node, formValues, logic, { parentID });
794
924
  });
795
925
  node.required?.forEach((fieldName) => {
796
926
  requiredFields.add(fieldName);
797
- updateField(getField(fieldName, formFields), requiredFields, node, formValues);
927
+ updateField(getField(fieldName, formFields), requiredFields, node, formValues, logic, {
928
+ parentID
929
+ });
798
930
  });
799
931
  if (node.if) {
800
- const matchesCondition = checkIfConditionMatches(node, formValues, formFields);
932
+ const matchesCondition = checkIfConditionMatches(node, formValues, formFields, logic);
801
933
  if (matchesCondition && node.then) {
802
- const { required: branchRequired } = processNode(
803
- node.then,
934
+ const { required: branchRequired } = processNode({
935
+ node: node.then,
804
936
  formValues,
805
937
  formFields,
806
- requiredFields
807
- );
938
+ accRequired: requiredFields,
939
+ parentID,
940
+ logic
941
+ });
808
942
  branchRequired.forEach((field) => requiredFields.add(field));
809
943
  } else if (node.else) {
810
- const { required: branchRequired } = processNode(
811
- node.else,
944
+ const { required: branchRequired } = processNode({
945
+ node: node.else,
812
946
  formValues,
813
947
  formFields,
814
- requiredFields
815
- );
948
+ accRequired: requiredFields,
949
+ parentID,
950
+ logic
951
+ });
816
952
  branchRequired.forEach((field) => requiredFields.add(field));
817
953
  }
818
954
  }
@@ -824,12 +960,21 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
824
960
  node.anyOf.forEach(({ required = [] }) => {
825
961
  required.forEach((fieldName) => {
826
962
  const field = getField(fieldName, formFields);
827
- updateField(field, requiredFields, node, formValues);
963
+ updateField(field, requiredFields, node, formValues, logic, { parentID });
828
964
  });
829
965
  });
830
966
  }
831
967
  if (node.allOf) {
832
- node.allOf.map((allOfNode) => processNode(allOfNode, formValues, formFields, requiredFields)).forEach(({ required: allOfItemRequired }) => {
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 }) => {
833
978
  allOfItemRequired.forEach(requiredFields.add, requiredFields);
834
979
  });
835
980
  }
@@ -837,7 +982,13 @@ function processNode(node, formValues, formFields, accRequired = /* @__PURE__ */
837
982
  Object.entries(node.properties).forEach(([name, nestedNode]) => {
838
983
  const inputType = getInputType(nestedNode);
839
984
  if (inputType === supportedTypes.FIELDSET) {
840
- processNode(nestedNode, formValues[name] || {}, getField(name, formFields).fields);
985
+ processNode({
986
+ node: nestedNode,
987
+ formValues: formValues[name] || {},
988
+ formFields: getField(name, formFields).fields,
989
+ parentID: name,
990
+ logic
991
+ });
841
992
  }
842
993
  });
843
994
  }
@@ -855,11 +1006,11 @@ function clearValuesIfNotVisible(fields, formValues) {
855
1006
  }
856
1007
  });
857
1008
  }
858
- function updateFieldsProperties(fields, formValues, jsonSchema) {
1009
+ function updateFieldsProperties(fields, formValues, jsonSchema, logic) {
859
1010
  if (!jsonSchema?.properties) {
860
1011
  return;
861
1012
  }
862
- processNode(jsonSchema, formValues, fields);
1013
+ processNode({ node: jsonSchema, formValues, formFields: fields, logic });
863
1014
  clearValuesIfNotVisible(fields, formValues);
864
1015
  }
865
1016
  var notNullOption = (opt) => opt.const !== null;
@@ -902,11 +1053,16 @@ function extractParametersFromNode(schemaNode) {
902
1053
  }
903
1054
  const presentation = pickXKey(schemaNode, "presentation") ?? {};
904
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);
905
1059
  const node = omit(schemaNode, ["x-jsf-presentation", "presentation"]);
906
1060
  const description = presentation?.description || node.description;
907
1061
  const statementDescription = containsHTML(presentation.statement?.description) ? wrapWithSpan(presentation.statement.description, { class: "jsf-statement" }) : presentation.statement?.description;
908
1062
  return omitBy(
909
1063
  {
1064
+ const: node.const,
1065
+ ...node.const && node.default ? { value: node.const } : {},
910
1066
  label: node.title,
911
1067
  readOnly: node.readOnly,
912
1068
  ...node.deprecated && {
@@ -941,6 +1097,8 @@ function extractParametersFromNode(schemaNode) {
941
1097
  },
942
1098
  // Handle [name].presentation
943
1099
  ...presentation,
1100
+ requiredValidations,
1101
+ computedAttributes: decoratedComputedAttributes,
944
1102
  description: containsHTML(description) ? wrapWithSpan(description, {
945
1103
  class: "jsf-description"
946
1104
  }) : description,
@@ -977,8 +1135,8 @@ function yupToFormErrors(yupError) {
977
1135
  }
978
1136
  return errors;
979
1137
  }
980
- var handleValuesChange = (fields, jsonSchema, config) => (values) => {
981
- updateFieldsProperties(fields, values, jsonSchema);
1138
+ var handleValuesChange = (fields, jsonSchema, config, logic) => (values) => {
1139
+ updateFieldsProperties(fields, values, jsonSchema, logic);
982
1140
  const lazySchema = lazy(() => buildCompleteYupSchema(fields, config));
983
1141
  let errors;
984
1142
  try {
@@ -997,6 +1155,12 @@ var handleValuesChange = (fields, jsonSchema, config) => (values) => {
997
1155
  formErrors: yupToFormErrors(errors)
998
1156
  };
999
1157
  };
1158
+ function getDecoratedComputedAttributes(computedAttributes) {
1159
+ return {
1160
+ ...computedAttributes ?? {},
1161
+ ...computedAttributes?.const && computedAttributes?.default ? { value: computedAttributes.const } : {}
1162
+ };
1163
+ }
1000
1164
 
1001
1165
  // src/calculateConditionalProperties.js
1002
1166
  function isFieldRequired(node, field) {
@@ -1198,6 +1362,9 @@ function applyFieldsDependencies(fieldsParameters, node) {
1198
1362
  applyFieldsDependencies(fieldsParameters, condition);
1199
1363
  });
1200
1364
  }
1365
+ if (node?.["x-jsf-logic"]) {
1366
+ applyFieldsDependencies(fieldsParameters, node["x-jsf-logic"]);
1367
+ }
1201
1368
  }
1202
1369
  function getCustomPropertiesForField(fieldParams, config) {
1203
1370
  return config?.customProperties?.[fieldParams.name];
@@ -1209,15 +1376,16 @@ function getComposeFunctionForField(fieldParams, hasCustomizations) {
1209
1376
  }
1210
1377
  return composeFn;
1211
1378
  }
1212
- function buildField(fieldParams, config, scopedJsonSchema) {
1379
+ function buildField(fieldParams, config, scopedJsonSchema, logic) {
1213
1380
  const customProperties = getCustomPropertiesForField(fieldParams, config);
1214
1381
  const composeFn = getComposeFunctionForField(fieldParams, !!customProperties);
1215
- const yupSchema = buildYupSchema(fieldParams, config);
1382
+ const yupSchema = buildYupSchema(fieldParams, config, logic);
1216
1383
  const calculateConditionalFieldsClosure = fieldParams.isDynamic && calculateConditionalProperties(fieldParams, customProperties);
1217
1384
  const calculateCustomValidationPropertiesClosure = calculateCustomValidationProperties(
1218
1385
  fieldParams,
1219
1386
  customProperties
1220
1387
  );
1388
+ const getComputedAttributes = Object.keys(fieldParams.computedAttributes).length > 0 && calculateComputedAttributes(fieldParams, config);
1221
1389
  const hasCustomValidations = !!customProperties && size(pick2(customProperties, SUPPORTED_CUSTOM_VALIDATION_FIELD_PARAMS)) > 0;
1222
1390
  const finalFieldParams = {
1223
1391
  // invalid attribute cleanup
@@ -1230,6 +1398,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
1230
1398
  ...hasCustomValidations && {
1231
1399
  calculateCustomValidationProperties: calculateCustomValidationPropertiesClosure
1232
1400
  },
1401
+ ...getComputedAttributes && { getComputedAttributes },
1233
1402
  // field customization properties
1234
1403
  ...customProperties && { fieldCustomization: customProperties },
1235
1404
  // base schema
@@ -1238,7 +1407,7 @@ function buildField(fieldParams, config, scopedJsonSchema) {
1238
1407
  };
1239
1408
  return composeFn(finalFieldParams);
1240
1409
  }
1241
- function getFieldsFromJSONSchema(scopedJsonSchema, config) {
1410
+ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
1242
1411
  if (!scopedJsonSchema) {
1243
1412
  return [];
1244
1413
  }
@@ -1262,11 +1431,11 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config) {
1262
1431
  fields: () => groupArrayFields,
1263
1432
  addFieldText: fieldParams.addFieldText
1264
1433
  };
1265
- buildField(fieldParams, config, scopedJsonSchema).forEach((groupField) => {
1434
+ buildField(fieldParams, config, scopedJsonSchema, logic).forEach((groupField) => {
1266
1435
  fields.push(groupField);
1267
1436
  });
1268
1437
  } else {
1269
- fields.push(buildField(fieldParams, config, scopedJsonSchema));
1438
+ fields.push(buildField(fieldParams, config, scopedJsonSchema, logic));
1270
1439
  }
1271
1440
  });
1272
1441
  return fields;
@@ -1277,9 +1446,15 @@ function createHeadlessForm(jsonSchema, customConfig = {}) {
1277
1446
  ...customConfig
1278
1447
  };
1279
1448
  try {
1280
- const fields = getFieldsFromJSONSchema(jsonSchema, config);
1281
- const handleValidation = handleValuesChange(fields, jsonSchema, config);
1282
- updateFieldsProperties(fields, getPrefillValues(fields, config.initialValues), jsonSchema);
1449
+ const logic = createValidationChecker(jsonSchema);
1450
+ const fields = getFieldsFromJSONSchema(jsonSchema, config, logic);
1451
+ const handleValidation = handleValuesChange(fields, jsonSchema, config, logic);
1452
+ updateFieldsProperties(
1453
+ fields,
1454
+ getPrefillValues(fields, config.initialValues),
1455
+ jsonSchema,
1456
+ logic
1457
+ );
1283
1458
  return {
1284
1459
  fields,
1285
1460
  handleValidation,