@remoteoss/json-schema-form 0.4.2-beta.0 → 0.4.3-beta.0

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,9 @@
1
+ #### 0.4.3-beta.0 (2023-08-09)
2
+
3
+ ##### Bug fixes
4
+
5
+ * **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))
6
+
1
7
  #### 0.4.2-beta.0 (2023-07-20)
2
8
 
3
9
  ##### 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.4.2-beta.0
5
- Generated: Thu, 20 Jul 2023 11:13:46 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.3-beta.0
5
+ Generated: Wed, 09 Aug 2023 08:39:30 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,24 +406,6 @@ 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()));
351
- };
352
- }
353
- function containsHTML(str = "") {
354
- return /<[a-z][\s\S]*>/i.test(str);
355
- }
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>`;
359
- }
360
- function hasProperty(object2, propertyName) {
361
- return Object.prototype.hasOwnProperty.call(object2, propertyName);
362
- }
363
-
364
409
  // src/yupSchema.js
365
410
  var import_flow = __toESM(require("lodash/flow"));
366
411
  var import_noop = __toESM(require("lodash/noop"));
@@ -675,42 +720,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
675
720
  const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
676
721
  return String(formValue) === String(currentPropertyValue);
677
722
  }
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
723
  function isFieldFilled(fieldValue) {
715
724
  return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
716
725
  }
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.2-beta.0
5
- Generated: Thu, 20 Jul 2023 11:13:46 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.3-beta.0
5
+ Generated: Wed, 09 Aug 2023 08:39:30 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,24 +370,6 @@ function _composeFieldCustomClosure(defaultComposeFn) {
307
370
  };
308
371
  }
309
372
 
310
- // src/utils.js
311
- function convertDiskSizeFromTo(from, to) {
312
- const units = ["bytes", "kb", "mb"];
313
- return function convert(value) {
314
- return value * Math.pow(1024, units.indexOf(from.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
315
- };
316
- }
317
- function containsHTML(str = "") {
318
- return /<[a-z][\s\S]*>/i.test(str);
319
- }
320
- function wrapWithSpan(html, properties = {}) {
321
- const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
322
- return `<span ${attributes}>${html}</span>`;
323
- }
324
- function hasProperty(object2, propertyName) {
325
- return Object.prototype.hasOwnProperty.call(object2, propertyName);
326
- }
327
-
328
373
  // src/yupSchema.js
329
374
  import flow from "lodash/flow";
330
375
  import noop from "lodash/noop";
@@ -639,42 +684,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
639
684
  const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
640
685
  return String(formValue) === String(currentPropertyValue);
641
686
  }
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
687
  function isFieldFilled(fieldValue) {
679
688
  return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
680
689
  }
@@ -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.2-beta.0
5
- Generated: Thu, 20 Jul 2023 11:13:46 GMT
4
+ NPM Package: @remoteoss/json-schema-form@0.4.3-beta.0
5
+ Generated: Wed, 09 Aug 2023 08:39:30 GMT
6
6
 
7
7
  MIT License
8
8
 
@@ -11025,6 +11025,69 @@ var lazy = function lazy2(fn) {
11025
11025
  return new Lazy_default(fn);
11026
11026
  };
11027
11027
 
11028
+ // src/utils.js
11029
+ function convertDiskSizeFromTo(from2, to) {
11030
+ const units = ["bytes", "kb", "mb"];
11031
+ return function convert(value) {
11032
+ return value * Math.pow(1024, units.indexOf(from2.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
11033
+ };
11034
+ }
11035
+ function containsHTML(str = "") {
11036
+ return /<[a-z][\s\S]*>/i.test(str);
11037
+ }
11038
+ function wrapWithSpan(html, properties = {}) {
11039
+ const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
11040
+ return `<span ${attributes}>${html}</span>`;
11041
+ }
11042
+ function hasProperty(object2, propertyName) {
11043
+ return Object.prototype.hasOwnProperty.call(object2, propertyName);
11044
+ }
11045
+
11046
+ // src/checkIfConditionMatches.js
11047
+ function checkIfConditionMatches(node, formValues, formFields) {
11048
+ return Object.keys(node.if.properties).every((name) => {
11049
+ const currentProperty = node.if.properties[name];
11050
+ const value = formValues[name];
11051
+ const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
11052
+ value === null;
11053
+ const hasIfExplicit = node.if.required?.includes(name);
11054
+ if (hasEmptyValue && !hasIfExplicit) {
11055
+ return true;
11056
+ }
11057
+ if (hasProperty(currentProperty, "const")) {
11058
+ return compareFormValueWithSchemaValue(value, currentProperty.const);
11059
+ }
11060
+ if (currentProperty.contains?.pattern) {
11061
+ const formValue = value || [];
11062
+ if (Array.isArray(formValue)) {
11063
+ const pattern = new RegExp(currentProperty.contains.pattern);
11064
+ return (value || []).some((item) => pattern.test(item));
11065
+ }
11066
+ }
11067
+ if (currentProperty.enum) {
11068
+ return currentProperty.enum.includes(value);
11069
+ }
11070
+ if (currentProperty.properties) {
11071
+ return checkIfConditionMatches(
11072
+ { if: currentProperty },
11073
+ formValues[name],
11074
+ getField(name, formFields).fields
11075
+ );
11076
+ }
11077
+ const field = getField(name, formFields);
11078
+ return validateFieldSchema(
11079
+ {
11080
+ options: field.options,
11081
+ // @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
11082
+ ...currentProperty,
11083
+ inputType: field.inputType,
11084
+ required: true
11085
+ },
11086
+ value
11087
+ );
11088
+ });
11089
+ }
11090
+
11028
11091
  // src/internals/helpers.js
11029
11092
  var import_merge = __toESM(require_merge2());
11030
11093
  var import_get2 = __toESM(require_get());
@@ -11284,24 +11347,6 @@ function _composeFieldCustomClosure(defaultComposeFn) {
11284
11347
  };
11285
11348
  }
11286
11349
 
11287
- // src/utils.js
11288
- function convertDiskSizeFromTo(from2, to) {
11289
- const units = ["bytes", "kb", "mb"];
11290
- return function convert(value) {
11291
- return value * Math.pow(1024, units.indexOf(from2.toLowerCase())) / Math.pow(1024, units.indexOf(to.toLowerCase()));
11292
- };
11293
- }
11294
- function containsHTML(str = "") {
11295
- return /<[a-z][\s\S]*>/i.test(str);
11296
- }
11297
- function wrapWithSpan(html, properties = {}) {
11298
- const attributes = Object.entries(properties).reduce((acc, [key, value]) => `${acc}${key}="${value}" `, "").trim();
11299
- return `<span ${attributes}>${html}</span>`;
11300
- }
11301
- function hasProperty(object2, propertyName) {
11302
- return Object.prototype.hasOwnProperty.call(object2, propertyName);
11303
- }
11304
-
11305
11350
  // src/yupSchema.js
11306
11351
  var import_flow = __toESM(require_flow());
11307
11352
  var import_noop = __toESM(require_noop());
@@ -11615,42 +11660,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
11615
11660
  const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
11616
11661
  return String(formValue) === String(currentPropertyValue);
11617
11662
  }
11618
- function checkIfConditionMatches(node, formValues, formFields) {
11619
- return Object.keys(node.if.properties).every((name) => {
11620
- const currentProperty = node.if.properties[name];
11621
- const value = formValues[name];
11622
- const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
11623
- value === null;
11624
- const hasIfExplicit = node.if.required?.includes(name);
11625
- if (hasEmptyValue && !hasIfExplicit) {
11626
- return true;
11627
- }
11628
- if (hasProperty(currentProperty, "const")) {
11629
- return compareFormValueWithSchemaValue(value, currentProperty.const);
11630
- }
11631
- if (currentProperty.contains?.pattern) {
11632
- const formValue = value || [];
11633
- if (Array.isArray(formValue)) {
11634
- const pattern = new RegExp(currentProperty.contains.pattern);
11635
- return (value || []).some((item) => pattern.test(item));
11636
- }
11637
- }
11638
- if (currentProperty.enum) {
11639
- return currentProperty.enum.includes(value);
11640
- }
11641
- const field = getField(name, formFields);
11642
- return validateFieldSchema(
11643
- {
11644
- options: field.options,
11645
- // @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
11646
- ...currentProperty,
11647
- inputType: field.inputType,
11648
- required: true
11649
- },
11650
- value
11651
- );
11652
- });
11653
- }
11654
11663
  function isFieldFilled(fieldValue) {
11655
11664
  return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
11656
11665
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remoteoss/json-schema-form",
3
- "version": "0.4.2-beta.0",
3
+ "version": "0.4.3-beta.0",
4
4
  "description": "Headless UI form powered by JSON Schemas",
5
5
  "author": "Remote.com <engineering@remote.com> (https://remote.com/)",
6
6
  "license": "MIT",
@@ -0,0 +1,51 @@
1
+ import { checkIfConditionMatches } from '../checkIfConditionMatches';
2
+
3
+ it('Empty if is always going to be true', () => {
4
+ expect(checkIfConditionMatches({ if: { properties: {} } })).toBe(true);
5
+ });
6
+
7
+ it('Basic if check passes with correct value', () => {
8
+ expect(
9
+ checkIfConditionMatches(
10
+ { if: { properties: { a: { const: 'hello' } } } },
11
+ {
12
+ a: 'hello',
13
+ }
14
+ )
15
+ ).toBe(true);
16
+ });
17
+
18
+ it('Basic if check fails with incorrect value', () => {
19
+ expect(
20
+ checkIfConditionMatches(
21
+ { if: { properties: { a: { const: 'hello' } } } },
22
+ {
23
+ a: 'goodbye',
24
+ }
25
+ )
26
+ ).toBe(false);
27
+ });
28
+
29
+ it('Nested properties check passes with correct value', () => {
30
+ expect(
31
+ checkIfConditionMatches(
32
+ { if: { properties: { parent: { properties: { child: { const: 'hello from child' } } } } } },
33
+ {
34
+ parent: { child: 'hello from child' },
35
+ },
36
+ [{ name: 'parent', fields: [] }]
37
+ )
38
+ ).toBe(true);
39
+ });
40
+
41
+ it('Nested properties check passes with correct value', () => {
42
+ expect(
43
+ checkIfConditionMatches(
44
+ { if: { properties: { parent: { properties: { child: { const: 'hello from child' } } } } } },
45
+ {
46
+ parent: { child: 'goodbye from child' },
47
+ },
48
+ [{ name: 'parent', fields: [] }]
49
+ )
50
+ ).toBe(false);
51
+ });
@@ -0,0 +1,58 @@
1
+ import { createHeadlessForm } from '../createHeadlessForm';
2
+
3
+ it('Should allow check of a nested property in a conditional', () => {
4
+ const { handleValidation } = createHeadlessForm(
5
+ {
6
+ additionalProperties: false,
7
+ allOf: [
8
+ {
9
+ if: {
10
+ properties: {
11
+ parent: {
12
+ properties: {
13
+ child: {
14
+ const: 'yes',
15
+ },
16
+ },
17
+ required: ['child'],
18
+ },
19
+ },
20
+ required: ['parent'],
21
+ },
22
+ then: { required: ['parent_sibling'] },
23
+ },
24
+ ],
25
+ properties: {
26
+ parent: {
27
+ additionalProperties: false,
28
+ properties: {
29
+ child: {
30
+ oneOf: [
31
+ {
32
+ const: 'yes',
33
+ },
34
+ { const: 'no' },
35
+ ],
36
+ type: 'string',
37
+ },
38
+ },
39
+ required: ['child'],
40
+ type: 'object',
41
+ },
42
+ parent_sibling: {
43
+ type: 'integer',
44
+ },
45
+ },
46
+ required: ['parent'],
47
+ type: 'object',
48
+ },
49
+ { strictInputType: false }
50
+ );
51
+ expect(handleValidation({ parent: { child: 'no' } }).formErrors).toEqual(undefined);
52
+ expect(handleValidation({ parent: { child: 'yes' } }).formErrors).toEqual({
53
+ parent_sibling: 'Required field',
54
+ });
55
+ expect(handleValidation({ parent: { child: 'yes' }, parent_sibling: 1 }).formErrors).toEqual(
56
+ undefined
57
+ );
58
+ });