@remoteoss/json-schema-form 0.4.1-dev.20230703203242 → 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 +19 -0
- package/dist/index.cjs +114 -60
- package/dist/index.js +114 -60
- package/dist/standalone.js +114 -60
- package/package.json +1 -1
- package/src/tests/checkIfConditionMatches.test.js +51 -0
- package/src/tests/conditions.test.js +58 -0
- package/src/tests/createHeadlessForm.test.js +108 -31
- package/src/tests/helpers.js +13 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
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
|
+
|
|
7
|
+
#### 0.4.2-beta.0 (2023-07-20)
|
|
8
|
+
|
|
9
|
+
##### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **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))
|
|
12
|
+
|
|
13
|
+
#### 0.4.1-beta.0 (2023-07-03)
|
|
14
|
+
|
|
15
|
+
##### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* **fieldset:** support root conditionals for fieldsets ([#23](https://github.com/remoteoss/json-schema-form/pull/23)) ([65d87b3a](https://github.com/remoteoss/json-schema-form/commit/65d87b3a93018f0729aed565000eb2a2ce1f2ce7))
|
|
18
|
+
* **select/radio:** Accept just the values in options (plus `''` and `null` for backward-compatibility) ([#18](https://github.com/remoteoss/json-schema-form/pull/18)) ([37501d2d](https://github.com/remoteoss/json-schema-form/commit/37501d2ddafdd5e207b34d2ca3f6b7b7a1006e9d))
|
|
19
|
+
|
|
1
20
|
#### 0.4.0-beta.0 (2023-06-22)
|
|
2
21
|
|
|
3
22
|
##### New Features
|
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.
|
|
5
|
-
Generated:
|
|
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"));
|
|
@@ -381,6 +426,25 @@ var validateOnlyStrings = (0, import_yup.string)().trim().nullable().test(
|
|
|
381
426
|
return true;
|
|
382
427
|
}
|
|
383
428
|
);
|
|
429
|
+
var compareDates = (d1, d2) => {
|
|
430
|
+
let date1 = new Date(d1).getTime();
|
|
431
|
+
let date2 = new Date(d2).getTime();
|
|
432
|
+
if (date1 < date2) {
|
|
433
|
+
return "LESSER";
|
|
434
|
+
} else if (date1 > date2) {
|
|
435
|
+
return "GREATER";
|
|
436
|
+
} else {
|
|
437
|
+
return "EQUAL";
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
var validateMinDate = (value, minDate) => {
|
|
441
|
+
const compare = compareDates(value, minDate);
|
|
442
|
+
return compare === "GREATER" || compare === "EQUAL" ? true : false;
|
|
443
|
+
};
|
|
444
|
+
var validateMaxDate = (value, minDate) => {
|
|
445
|
+
const compare = compareDates(value, minDate);
|
|
446
|
+
return compare === "LESSER" || compare === "EQUAL" ? true : false;
|
|
447
|
+
};
|
|
384
448
|
var yupSchemas = {
|
|
385
449
|
text: validateOnlyStrings,
|
|
386
450
|
radioOrSelect: (options) => (0, import_yup.string)().nullable().transform((value) => {
|
|
@@ -394,10 +458,32 @@ var yupSchemas = {
|
|
|
394
458
|
}).oneOf(options, ({ value }) => {
|
|
395
459
|
return `The option ${JSON.stringify(value)} is not valid.`;
|
|
396
460
|
}),
|
|
397
|
-
date: (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
461
|
+
date: ({ minDate, maxDate }) => {
|
|
462
|
+
let dateString = (0, import_yup.string)().nullable().transform((value) => {
|
|
463
|
+
if (value === "") {
|
|
464
|
+
return void 0;
|
|
465
|
+
}
|
|
466
|
+
return value === null ? void 0 : value;
|
|
467
|
+
}).trim().matches(
|
|
468
|
+
/(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
|
|
469
|
+
`Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
|
|
470
|
+
);
|
|
471
|
+
if (minDate) {
|
|
472
|
+
dateString = dateString.test(
|
|
473
|
+
"minDate",
|
|
474
|
+
`The date must be ${minDate} or after.`,
|
|
475
|
+
(value) => validateMinDate(value, minDate)
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
if (maxDate) {
|
|
479
|
+
dateString = dateString.test(
|
|
480
|
+
"maxDate",
|
|
481
|
+
`The date must be ${maxDate} or before.`,
|
|
482
|
+
(value) => validateMaxDate(value, maxDate)
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
return dateString;
|
|
486
|
+
},
|
|
401
487
|
number: (0, import_yup.number)().typeError("The value must be a number").nullable(),
|
|
402
488
|
file: (0, import_yup.array)().nullable(),
|
|
403
489
|
email: (0, import_yup.string)().trim().email("Please enter a valid email address").nullable(),
|
|
@@ -442,6 +528,9 @@ var getYupSchema = ({ inputType, ...field }) => {
|
|
|
442
528
|
const optionValues = getOptions(field);
|
|
443
529
|
return yupSchemas.radioOrSelect(optionValues);
|
|
444
530
|
}
|
|
531
|
+
if (field.format === "date") {
|
|
532
|
+
return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
|
|
533
|
+
}
|
|
445
534
|
return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
|
|
446
535
|
};
|
|
447
536
|
function buildYupSchema(field, config) {
|
|
@@ -631,42 +720,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
|
|
|
631
720
|
const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
|
|
632
721
|
return String(formValue) === String(currentPropertyValue);
|
|
633
722
|
}
|
|
634
|
-
function checkIfConditionMatches(node, formValues, formFields) {
|
|
635
|
-
return Object.keys(node.if.properties).every((name) => {
|
|
636
|
-
const currentProperty = node.if.properties[name];
|
|
637
|
-
const value = formValues[name];
|
|
638
|
-
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
639
|
-
value === null;
|
|
640
|
-
const hasIfExplicit = node.if.required?.includes(name);
|
|
641
|
-
if (hasEmptyValue && !hasIfExplicit) {
|
|
642
|
-
return true;
|
|
643
|
-
}
|
|
644
|
-
if (hasProperty(currentProperty, "const")) {
|
|
645
|
-
return compareFormValueWithSchemaValue(value, currentProperty.const);
|
|
646
|
-
}
|
|
647
|
-
if (currentProperty.contains?.pattern) {
|
|
648
|
-
const formValue = value || [];
|
|
649
|
-
if (Array.isArray(formValue)) {
|
|
650
|
-
const pattern = new RegExp(currentProperty.contains.pattern);
|
|
651
|
-
return (value || []).some((item) => pattern.test(item));
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
if (currentProperty.enum) {
|
|
655
|
-
return currentProperty.enum.includes(value);
|
|
656
|
-
}
|
|
657
|
-
const field = getField(name, formFields);
|
|
658
|
-
return validateFieldSchema(
|
|
659
|
-
{
|
|
660
|
-
options: field.options,
|
|
661
|
-
// @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
|
|
662
|
-
...currentProperty,
|
|
663
|
-
inputType: field.inputType,
|
|
664
|
-
required: true
|
|
665
|
-
},
|
|
666
|
-
value
|
|
667
|
-
);
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
723
|
function isFieldFilled(fieldValue) {
|
|
671
724
|
return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
|
|
672
725
|
}
|
|
@@ -901,6 +954,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
901
954
|
maxFileSize: node.maxFileSize,
|
|
902
955
|
// @deprecated in favor of presentation.maxFileSize
|
|
903
956
|
default: node.default,
|
|
957
|
+
format: node.format,
|
|
904
958
|
// Checkboxes conditions
|
|
905
959
|
// — For checkboxes that only accept one value (string)
|
|
906
960
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
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.
|
|
5
|
-
Generated:
|
|
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";
|
|
@@ -345,6 +390,25 @@ var validateOnlyStrings = string().trim().nullable().test(
|
|
|
345
390
|
return true;
|
|
346
391
|
}
|
|
347
392
|
);
|
|
393
|
+
var compareDates = (d1, d2) => {
|
|
394
|
+
let date1 = new Date(d1).getTime();
|
|
395
|
+
let date2 = new Date(d2).getTime();
|
|
396
|
+
if (date1 < date2) {
|
|
397
|
+
return "LESSER";
|
|
398
|
+
} else if (date1 > date2) {
|
|
399
|
+
return "GREATER";
|
|
400
|
+
} else {
|
|
401
|
+
return "EQUAL";
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var validateMinDate = (value, minDate) => {
|
|
405
|
+
const compare = compareDates(value, minDate);
|
|
406
|
+
return compare === "GREATER" || compare === "EQUAL" ? true : false;
|
|
407
|
+
};
|
|
408
|
+
var validateMaxDate = (value, minDate) => {
|
|
409
|
+
const compare = compareDates(value, minDate);
|
|
410
|
+
return compare === "LESSER" || compare === "EQUAL" ? true : false;
|
|
411
|
+
};
|
|
348
412
|
var yupSchemas = {
|
|
349
413
|
text: validateOnlyStrings,
|
|
350
414
|
radioOrSelect: (options) => string().nullable().transform((value) => {
|
|
@@ -358,10 +422,32 @@ var yupSchemas = {
|
|
|
358
422
|
}).oneOf(options, ({ value }) => {
|
|
359
423
|
return `The option ${JSON.stringify(value)} is not valid.`;
|
|
360
424
|
}),
|
|
361
|
-
date:
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
425
|
+
date: ({ minDate, maxDate }) => {
|
|
426
|
+
let dateString = string().nullable().transform((value) => {
|
|
427
|
+
if (value === "") {
|
|
428
|
+
return void 0;
|
|
429
|
+
}
|
|
430
|
+
return value === null ? void 0 : value;
|
|
431
|
+
}).trim().matches(
|
|
432
|
+
/(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
|
|
433
|
+
`Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
|
|
434
|
+
);
|
|
435
|
+
if (minDate) {
|
|
436
|
+
dateString = dateString.test(
|
|
437
|
+
"minDate",
|
|
438
|
+
`The date must be ${minDate} or after.`,
|
|
439
|
+
(value) => validateMinDate(value, minDate)
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
if (maxDate) {
|
|
443
|
+
dateString = dateString.test(
|
|
444
|
+
"maxDate",
|
|
445
|
+
`The date must be ${maxDate} or before.`,
|
|
446
|
+
(value) => validateMaxDate(value, maxDate)
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
return dateString;
|
|
450
|
+
},
|
|
365
451
|
number: number().typeError("The value must be a number").nullable(),
|
|
366
452
|
file: array().nullable(),
|
|
367
453
|
email: string().trim().email("Please enter a valid email address").nullable(),
|
|
@@ -406,6 +492,9 @@ var getYupSchema = ({ inputType, ...field }) => {
|
|
|
406
492
|
const optionValues = getOptions(field);
|
|
407
493
|
return yupSchemas.radioOrSelect(optionValues);
|
|
408
494
|
}
|
|
495
|
+
if (field.format === "date") {
|
|
496
|
+
return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
|
|
497
|
+
}
|
|
409
498
|
return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
|
|
410
499
|
};
|
|
411
500
|
function buildYupSchema(field, config) {
|
|
@@ -595,42 +684,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
|
|
|
595
684
|
const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
|
|
596
685
|
return String(formValue) === String(currentPropertyValue);
|
|
597
686
|
}
|
|
598
|
-
function checkIfConditionMatches(node, formValues, formFields) {
|
|
599
|
-
return Object.keys(node.if.properties).every((name) => {
|
|
600
|
-
const currentProperty = node.if.properties[name];
|
|
601
|
-
const value = formValues[name];
|
|
602
|
-
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
603
|
-
value === null;
|
|
604
|
-
const hasIfExplicit = node.if.required?.includes(name);
|
|
605
|
-
if (hasEmptyValue && !hasIfExplicit) {
|
|
606
|
-
return true;
|
|
607
|
-
}
|
|
608
|
-
if (hasProperty(currentProperty, "const")) {
|
|
609
|
-
return compareFormValueWithSchemaValue(value, currentProperty.const);
|
|
610
|
-
}
|
|
611
|
-
if (currentProperty.contains?.pattern) {
|
|
612
|
-
const formValue = value || [];
|
|
613
|
-
if (Array.isArray(formValue)) {
|
|
614
|
-
const pattern = new RegExp(currentProperty.contains.pattern);
|
|
615
|
-
return (value || []).some((item) => pattern.test(item));
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
if (currentProperty.enum) {
|
|
619
|
-
return currentProperty.enum.includes(value);
|
|
620
|
-
}
|
|
621
|
-
const field = getField(name, formFields);
|
|
622
|
-
return validateFieldSchema(
|
|
623
|
-
{
|
|
624
|
-
options: field.options,
|
|
625
|
-
// @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
|
|
626
|
-
...currentProperty,
|
|
627
|
-
inputType: field.inputType,
|
|
628
|
-
required: true
|
|
629
|
-
},
|
|
630
|
-
value
|
|
631
|
-
);
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
687
|
function isFieldFilled(fieldValue) {
|
|
635
688
|
return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
|
|
636
689
|
}
|
|
@@ -865,6 +918,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
865
918
|
maxFileSize: node.maxFileSize,
|
|
866
919
|
// @deprecated in favor of presentation.maxFileSize
|
|
867
920
|
default: node.default,
|
|
921
|
+
format: node.format,
|
|
868
922
|
// Checkboxes conditions
|
|
869
923
|
// — For checkboxes that only accept one value (string)
|
|
870
924
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
package/dist/standalone.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.
|
|
5
|
-
Generated:
|
|
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());
|
|
@@ -11321,6 +11366,25 @@ var validateOnlyStrings = StringSchema().trim().nullable().test(
|
|
|
11321
11366
|
return true;
|
|
11322
11367
|
}
|
|
11323
11368
|
);
|
|
11369
|
+
var compareDates = (d1, d2) => {
|
|
11370
|
+
let date1 = new Date(d1).getTime();
|
|
11371
|
+
let date2 = new Date(d2).getTime();
|
|
11372
|
+
if (date1 < date2) {
|
|
11373
|
+
return "LESSER";
|
|
11374
|
+
} else if (date1 > date2) {
|
|
11375
|
+
return "GREATER";
|
|
11376
|
+
} else {
|
|
11377
|
+
return "EQUAL";
|
|
11378
|
+
}
|
|
11379
|
+
};
|
|
11380
|
+
var validateMinDate = (value, minDate) => {
|
|
11381
|
+
const compare = compareDates(value, minDate);
|
|
11382
|
+
return compare === "GREATER" || compare === "EQUAL" ? true : false;
|
|
11383
|
+
};
|
|
11384
|
+
var validateMaxDate = (value, minDate) => {
|
|
11385
|
+
const compare = compareDates(value, minDate);
|
|
11386
|
+
return compare === "LESSER" || compare === "EQUAL" ? true : false;
|
|
11387
|
+
};
|
|
11324
11388
|
var yupSchemas = {
|
|
11325
11389
|
text: validateOnlyStrings,
|
|
11326
11390
|
radioOrSelect: (options) => StringSchema().nullable().transform((value) => {
|
|
@@ -11334,10 +11398,32 @@ var yupSchemas = {
|
|
|
11334
11398
|
}).oneOf(options, ({ value }) => {
|
|
11335
11399
|
return `The option ${JSON.stringify(value)} is not valid.`;
|
|
11336
11400
|
}),
|
|
11337
|
-
date:
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11401
|
+
date: ({ minDate, maxDate }) => {
|
|
11402
|
+
let dateString = StringSchema().nullable().transform((value) => {
|
|
11403
|
+
if (value === "") {
|
|
11404
|
+
return void 0;
|
|
11405
|
+
}
|
|
11406
|
+
return value === null ? void 0 : value;
|
|
11407
|
+
}).trim().matches(
|
|
11408
|
+
/(?:\d){4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9]|3[0-1])/,
|
|
11409
|
+
`Must be a valid date in ${DEFAULT_DATE_FORMAT.toLocaleLowerCase()} format. e.g. ${todayDateHint}`
|
|
11410
|
+
);
|
|
11411
|
+
if (minDate) {
|
|
11412
|
+
dateString = dateString.test(
|
|
11413
|
+
"minDate",
|
|
11414
|
+
`The date must be ${minDate} or after.`,
|
|
11415
|
+
(value) => validateMinDate(value, minDate)
|
|
11416
|
+
);
|
|
11417
|
+
}
|
|
11418
|
+
if (maxDate) {
|
|
11419
|
+
dateString = dateString.test(
|
|
11420
|
+
"maxDate",
|
|
11421
|
+
`The date must be ${maxDate} or before.`,
|
|
11422
|
+
(value) => validateMaxDate(value, maxDate)
|
|
11423
|
+
);
|
|
11424
|
+
}
|
|
11425
|
+
return dateString;
|
|
11426
|
+
},
|
|
11341
11427
|
number: NumberSchema().typeError("The value must be a number").nullable(),
|
|
11342
11428
|
file: array_default().nullable(),
|
|
11343
11429
|
email: StringSchema().trim().email("Please enter a valid email address").nullable(),
|
|
@@ -11382,6 +11468,9 @@ var getYupSchema = ({ inputType, ...field }) => {
|
|
|
11382
11468
|
const optionValues = getOptions(field);
|
|
11383
11469
|
return yupSchemas.radioOrSelect(optionValues);
|
|
11384
11470
|
}
|
|
11471
|
+
if (field.format === "date") {
|
|
11472
|
+
return yupSchemas.date({ minDate: field.minDate, maxDate: field.maxDate });
|
|
11473
|
+
}
|
|
11385
11474
|
return yupSchemas[inputType] || yupSchemasToJsonTypes[jsonType];
|
|
11386
11475
|
};
|
|
11387
11476
|
function buildYupSchema(field, config) {
|
|
@@ -11571,42 +11660,6 @@ function compareFormValueWithSchemaValue(formValue, schemaValue) {
|
|
|
11571
11660
|
const currentPropertyValue = typeof schemaValue === "number" ? schemaValue : schemaValue || void 0;
|
|
11572
11661
|
return String(formValue) === String(currentPropertyValue);
|
|
11573
11662
|
}
|
|
11574
|
-
function checkIfConditionMatches(node, formValues, formFields) {
|
|
11575
|
-
return Object.keys(node.if.properties).every((name) => {
|
|
11576
|
-
const currentProperty = node.if.properties[name];
|
|
11577
|
-
const value = formValues[name];
|
|
11578
|
-
const hasEmptyValue = typeof value === "undefined" || // NOTE: This is a "Remote API" dependency, as empty fields are sent as "null".
|
|
11579
|
-
value === null;
|
|
11580
|
-
const hasIfExplicit = node.if.required?.includes(name);
|
|
11581
|
-
if (hasEmptyValue && !hasIfExplicit) {
|
|
11582
|
-
return true;
|
|
11583
|
-
}
|
|
11584
|
-
if (hasProperty(currentProperty, "const")) {
|
|
11585
|
-
return compareFormValueWithSchemaValue(value, currentProperty.const);
|
|
11586
|
-
}
|
|
11587
|
-
if (currentProperty.contains?.pattern) {
|
|
11588
|
-
const formValue = value || [];
|
|
11589
|
-
if (Array.isArray(formValue)) {
|
|
11590
|
-
const pattern = new RegExp(currentProperty.contains.pattern);
|
|
11591
|
-
return (value || []).some((item) => pattern.test(item));
|
|
11592
|
-
}
|
|
11593
|
-
}
|
|
11594
|
-
if (currentProperty.enum) {
|
|
11595
|
-
return currentProperty.enum.includes(value);
|
|
11596
|
-
}
|
|
11597
|
-
const field = getField(name, formFields);
|
|
11598
|
-
return validateFieldSchema(
|
|
11599
|
-
{
|
|
11600
|
-
options: field.options,
|
|
11601
|
-
// @TODO/CODE SMELL. We are passing the property (raw field), but buildYupSchema() expected the output field.
|
|
11602
|
-
...currentProperty,
|
|
11603
|
-
inputType: field.inputType,
|
|
11604
|
-
required: true
|
|
11605
|
-
},
|
|
11606
|
-
value
|
|
11607
|
-
);
|
|
11608
|
-
});
|
|
11609
|
-
}
|
|
11610
11663
|
function isFieldFilled(fieldValue) {
|
|
11611
11664
|
return Array.isArray(fieldValue) ? fieldValue.length > 0 : !!fieldValue;
|
|
11612
11665
|
}
|
|
@@ -11841,6 +11894,7 @@ function extractParametersFromNode(schemaNode) {
|
|
|
11841
11894
|
maxFileSize: node.maxFileSize,
|
|
11842
11895
|
// @deprecated in favor of presentation.maxFileSize
|
|
11843
11896
|
default: node.default,
|
|
11897
|
+
format: node.format,
|
|
11844
11898
|
// Checkboxes conditions
|
|
11845
11899
|
// — For checkboxes that only accept one value (string)
|
|
11846
11900
|
...presentation?.inputType === "checkbox" && { checkboxValue: node.const },
|
package/package.json
CHANGED
|
@@ -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
|
+
});
|
|
@@ -439,23 +439,15 @@ describe('createHeadlessForm', () => {
|
|
|
439
439
|
|
|
440
440
|
// All allowed options are valid
|
|
441
441
|
validOptions.forEach((value) => {
|
|
442
|
-
expect(
|
|
443
|
-
validateForm({
|
|
444
|
-
[fieldName]: value,
|
|
445
|
-
})
|
|
446
|
-
).toBeUndefined();
|
|
442
|
+
expect(validateForm({ [fieldName]: value })).toBeUndefined();
|
|
447
443
|
});
|
|
448
444
|
|
|
449
445
|
// Any other arbitrary value is not valid.
|
|
450
|
-
expect(
|
|
451
|
-
validateForm({
|
|
452
|
-
[fieldName]: 'blah-blah',
|
|
453
|
-
})
|
|
454
|
-
).toEqual({
|
|
446
|
+
expect(validateForm({ [fieldName]: 'blah-blah' })).toEqual({
|
|
455
447
|
[fieldName]: 'The option "blah-blah" is not valid.',
|
|
456
448
|
});
|
|
457
449
|
|
|
458
|
-
//
|
|
450
|
+
// Given undefined, it says it's a required field.
|
|
459
451
|
expect(validateForm({})).toEqual({
|
|
460
452
|
[fieldName]: 'Required field',
|
|
461
453
|
});
|
|
@@ -831,6 +823,9 @@ describe('createHeadlessForm', () => {
|
|
|
831
823
|
|
|
832
824
|
describe('support "radio" optional field - more examples @BUG RMT-518', () => {
|
|
833
825
|
function assertCommonBehavior(validateForm) {
|
|
826
|
+
// Note: Very similar to assertOptionsAllowed()
|
|
827
|
+
// We could reuse it in a next iteration.
|
|
828
|
+
|
|
834
829
|
// Happy path
|
|
835
830
|
expect(validateForm({ has_car: 'yes' })).toBeUndefined();
|
|
836
831
|
|
|
@@ -1014,30 +1009,112 @@ describe('createHeadlessForm', () => {
|
|
|
1014
1009
|
});
|
|
1015
1010
|
|
|
1016
1011
|
it('support "date" field type', () => {
|
|
1017
|
-
const
|
|
1012
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
|
|
1018
1013
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
maxDate: '2022-03-01',
|
|
1030
|
-
},
|
|
1031
|
-
],
|
|
1014
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1015
|
+
|
|
1016
|
+
expect(fields[0]).toMatchObject({
|
|
1017
|
+
label: 'Birthdate',
|
|
1018
|
+
name: 'birthdate',
|
|
1019
|
+
required: true,
|
|
1020
|
+
schema: expect.any(Object),
|
|
1021
|
+
type: 'date',
|
|
1022
|
+
minDate: '1922-03-01',
|
|
1023
|
+
maxDate: '2022-03-17',
|
|
1032
1024
|
});
|
|
1033
1025
|
|
|
1034
|
-
const fieldValidator = result.fields[0].schema;
|
|
1035
1026
|
const todayDateHint = new Date().toISOString().substring(0, 10);
|
|
1036
|
-
|
|
1037
|
-
expect(
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1027
|
+
|
|
1028
|
+
expect(validateForm({})).toEqual({
|
|
1029
|
+
birthdate: 'Required field',
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
expect(validateForm({ birthdate: '2020-10-10' })).toBeUndefined();
|
|
1033
|
+
expect(validateForm({ birthdate: '2020-13-10' })).toEqual({
|
|
1034
|
+
birthdate: `Must be a valid date in yyyy-mm-dd format. e.g. ${todayDateHint}`,
|
|
1035
|
+
});
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
it('support "date" field type with a minDate', () => {
|
|
1039
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
|
|
1040
|
+
|
|
1041
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1042
|
+
|
|
1043
|
+
expect(fields[0]).toMatchObject({
|
|
1044
|
+
label: 'Birthdate',
|
|
1045
|
+
name: 'birthdate',
|
|
1046
|
+
required: true,
|
|
1047
|
+
schema: expect.any(Object),
|
|
1048
|
+
type: 'date',
|
|
1049
|
+
minDate: '1922-03-01',
|
|
1050
|
+
maxDate: '2022-03-17',
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
expect(validateForm({})).toEqual({
|
|
1054
|
+
birthdate: 'Required field',
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
expect(validateForm({ birthdate: '' })).toEqual({
|
|
1058
|
+
birthdate: `Required field`,
|
|
1059
|
+
});
|
|
1060
|
+
|
|
1061
|
+
expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
|
|
1062
|
+
birthdate: 'The date must be 1922-03-01 or after.',
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
expect(validateForm({ birthdate: '1922-03-01' })).toBeUndefined();
|
|
1066
|
+
|
|
1067
|
+
expect(validateForm({ birthdate: '2021-03-01' })).toBeUndefined();
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
it('support "date" field type with a maxDate', () => {
|
|
1071
|
+
const { fields, handleValidation } = createHeadlessForm(schemaInputTypeDate);
|
|
1072
|
+
|
|
1073
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1074
|
+
|
|
1075
|
+
expect(fields[0]).toMatchObject({
|
|
1076
|
+
label: 'Birthdate',
|
|
1077
|
+
name: 'birthdate',
|
|
1078
|
+
required: true,
|
|
1079
|
+
schema: expect.any(Object),
|
|
1080
|
+
type: 'date',
|
|
1081
|
+
minDate: '1922-03-01',
|
|
1082
|
+
maxDate: '2022-03-17',
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
expect(validateForm({ birthdate: '' })).toEqual({
|
|
1086
|
+
birthdate: `Required field`,
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
expect(validateForm({ birthdate: '2022-02-01' })).toBeUndefined();
|
|
1090
|
+
expect(validateForm({ birthdate: '2022-03-01' })).toBeUndefined();
|
|
1091
|
+
expect(validateForm({ birthdate: '2022-04-01' })).toEqual({
|
|
1092
|
+
birthdate: 'The date must be 2022-03-17 or before.',
|
|
1093
|
+
});
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
it('support format date with minDate and maxDate', () => {
|
|
1097
|
+
const schemaFormatDate = {
|
|
1098
|
+
properties: {
|
|
1099
|
+
birthdate: {
|
|
1100
|
+
title: 'Birthdate',
|
|
1101
|
+
type: 'string',
|
|
1102
|
+
format: 'date',
|
|
1103
|
+
'x-jsf-presentation': {
|
|
1104
|
+
inputType: 'myDateType',
|
|
1105
|
+
maxDate: '2022-03-01',
|
|
1106
|
+
minDate: '1922-03-01',
|
|
1107
|
+
},
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
1110
|
+
};
|
|
1111
|
+
|
|
1112
|
+
const { handleValidation } = createHeadlessForm(schemaFormatDate);
|
|
1113
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1114
|
+
|
|
1115
|
+
expect(validateForm({ birthdate: '1922-02-01' })).toEqual({
|
|
1116
|
+
birthdate: 'The date must be 1922-03-01 or after.',
|
|
1117
|
+
});
|
|
1041
1118
|
});
|
|
1042
1119
|
|
|
1043
1120
|
it('supports "file" field type', () => {
|
package/src/tests/helpers.js
CHANGED
|
@@ -272,18 +272,6 @@ export const mockSelectInputMultipleOptional = {
|
|
|
272
272
|
type: ['array', 'null'],
|
|
273
273
|
};
|
|
274
274
|
|
|
275
|
-
export const mockDateInput = {
|
|
276
|
-
'x-jsf-presentation': {
|
|
277
|
-
inputType: 'date',
|
|
278
|
-
maxDate: '2022-03-01',
|
|
279
|
-
minDate: '1922-03-01',
|
|
280
|
-
},
|
|
281
|
-
title: 'Birthdate',
|
|
282
|
-
type: 'string',
|
|
283
|
-
format: 'date',
|
|
284
|
-
maxLength: 10,
|
|
285
|
-
};
|
|
286
|
-
|
|
287
275
|
export const mockFileInput = {
|
|
288
276
|
description: 'File Input Description',
|
|
289
277
|
'x-jsf-presentation': {
|
|
@@ -998,12 +986,19 @@ export const schemaInputTypeNumberWithPercentage = JSONSchemaBuilder()
|
|
|
998
986
|
.setRequiredFields(['shares'])
|
|
999
987
|
.build();
|
|
1000
988
|
|
|
1001
|
-
export const schemaInputTypeDate =
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
989
|
+
export const schemaInputTypeDate = {
|
|
990
|
+
type: 'object',
|
|
991
|
+
additionalProperties: false,
|
|
992
|
+
properties: {
|
|
993
|
+
birthdate: {
|
|
994
|
+
'x-jsf-presentation': { inputType: 'date', maxDate: '2022-03-17', minDate: '1922-03-01' },
|
|
995
|
+
title: 'Birthdate',
|
|
996
|
+
type: 'string',
|
|
997
|
+
format: 'date',
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
required: ['birthdate'],
|
|
1001
|
+
};
|
|
1007
1002
|
|
|
1008
1003
|
export const schemaInputTypeEmail = JSONSchemaBuilder()
|
|
1009
1004
|
.addInput({
|