@remoteoss/json-schema-form 0.11.11-dev.20250220174843 → 0.11.12-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 +12 -0
- package/dist/index.cjs +10 -36
- package/dist/index.js +10 -36
- package/dist/standalone.js +10 -36
- package/package.json +1 -1
- package/src/tests/conditions.test.js +48 -227
- package/src/tests/createHeadlessForm.test.js +4 -59
- package/src/tests/helpers.custom.js +7 -7
- package/src/tests/helpers.js +5 -61
- package/src/tests/jsonLogic.fixtures.js +48 -0
- package/src/tests/jsonLogic.test.js +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
#### 0.11.12-beta.0 (2025-04-15)
|
|
2
|
+
|
|
3
|
+
##### Chores
|
|
4
|
+
|
|
5
|
+
* change deprecated 'presentation' to 'x-jsf-presentation' in test helpers ([#159](https://github.com/remoteoss/json-schema-form/pull/159)) ([3f03b16d](https://github.com/remoteoss/json-schema-form/commit/3f03b16dce6acd801ff497a9c547cceb1b6347c5))
|
|
6
|
+
|
|
7
|
+
#### 0.11.11-beta.0 (2025-02-20)
|
|
8
|
+
|
|
9
|
+
##### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **conditionals:** Add support to `oneOf` ([#136](https://github.com/remoteoss/json-schema-form/pull/136)) ([966cec59](https://github.com/remoteoss/json-schema-form/commit/966cec595ed2a1ff35f9d15e22acaea16cdd5113))
|
|
12
|
+
|
|
1
13
|
#### 0.11.10-beta.0 (2025-01-22)
|
|
2
14
|
|
|
3
15
|
##### Bug Fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2025 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.11.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.11.12-beta.0
|
|
5
|
+
Generated: Tue, 15 Apr 2025 08:28:29 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -101,6 +101,11 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
|
|
|
101
101
|
if (typeof node.if === "boolean") {
|
|
102
102
|
return node.if;
|
|
103
103
|
}
|
|
104
|
+
if (node.if.anyOf) {
|
|
105
|
+
return node.if.anyOf.some(
|
|
106
|
+
(property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
104
109
|
return Object.keys(node.if.properties ?? {}).every((name) => {
|
|
105
110
|
const currentProperty = node.if.properties[name];
|
|
106
111
|
const value = formValues[name];
|
|
@@ -1164,11 +1169,7 @@ function hasType(type, typeName) {
|
|
|
1164
1169
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
1165
1170
|
}
|
|
1166
1171
|
function getField(fieldName, fields) {
|
|
1167
|
-
|
|
1168
|
-
return fields.find(({ name }) => name === fieldName);
|
|
1169
|
-
} else {
|
|
1170
|
-
return fields[fieldName];
|
|
1171
|
-
}
|
|
1172
|
+
return fields.find(({ name }) => name === fieldName);
|
|
1172
1173
|
}
|
|
1173
1174
|
function validateFieldSchema(field, value, logic) {
|
|
1174
1175
|
const validator = buildYupSchema(field, {}, logic);
|
|
@@ -1382,25 +1383,6 @@ function processNode({
|
|
|
1382
1383
|
logic
|
|
1383
1384
|
});
|
|
1384
1385
|
}
|
|
1385
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
1386
|
-
const values = formValues[name];
|
|
1387
|
-
if (Array.isArray(values)) {
|
|
1388
|
-
const newFields = [];
|
|
1389
|
-
const field = getField(name, formFields);
|
|
1390
|
-
values.forEach((value) => {
|
|
1391
|
-
const fields = field.fields();
|
|
1392
|
-
processNode({
|
|
1393
|
-
node: nestedNode.items,
|
|
1394
|
-
formValues: value,
|
|
1395
|
-
formFields: fields,
|
|
1396
|
-
parentID: name,
|
|
1397
|
-
logic
|
|
1398
|
-
});
|
|
1399
|
-
newFields.push(fields);
|
|
1400
|
-
});
|
|
1401
|
-
field.dynamicFields = newFields;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
1386
|
});
|
|
1405
1387
|
}
|
|
1406
1388
|
if (node["x-jsf-logic"]) {
|
|
@@ -1772,16 +1754,6 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
|
|
|
1772
1754
|
logic
|
|
1773
1755
|
);
|
|
1774
1756
|
}
|
|
1775
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
1776
|
-
fields = () => getFieldsFromJSONSchema(
|
|
1777
|
-
fieldProperties.items,
|
|
1778
|
-
{
|
|
1779
|
-
customProperties: (0, import_get3.default)(config, `customProperties.${name}.customProperties`, {}),
|
|
1780
|
-
parentID: name
|
|
1781
|
-
},
|
|
1782
|
-
logic
|
|
1783
|
-
);
|
|
1784
|
-
}
|
|
1785
1757
|
const result = {
|
|
1786
1758
|
name,
|
|
1787
1759
|
inputType,
|
|
@@ -1875,10 +1847,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
|
|
|
1875
1847
|
if (fieldParams.inputType === "group-array") {
|
|
1876
1848
|
const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
|
|
1877
1849
|
const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
|
|
1850
|
+
groupArrayItem.nameKey = groupArrayItem.name;
|
|
1878
1851
|
const customProperties = null;
|
|
1879
1852
|
const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
|
|
1880
1853
|
return composeFn(groupArrayItem);
|
|
1881
1854
|
});
|
|
1855
|
+
fieldParams.nameKey = fieldParams.name;
|
|
1882
1856
|
fieldParams.nthFieldGroup = {
|
|
1883
1857
|
name: fieldParams.name,
|
|
1884
1858
|
label: fieldParams.label,
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2025 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.11.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.11.12-beta.0
|
|
5
|
+
Generated: Tue, 15 Apr 2025 08:28:29 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -64,6 +64,11 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
|
|
|
64
64
|
if (typeof node.if === "boolean") {
|
|
65
65
|
return node.if;
|
|
66
66
|
}
|
|
67
|
+
if (node.if.anyOf) {
|
|
68
|
+
return node.if.anyOf.some(
|
|
69
|
+
(property) => checkIfConditionMatchesProperties({ if: property }, formValues, formFields, logic)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
67
72
|
return Object.keys(node.if.properties ?? {}).every((name) => {
|
|
68
73
|
const currentProperty = node.if.properties[name];
|
|
69
74
|
const value = formValues[name];
|
|
@@ -1127,11 +1132,7 @@ function hasType(type, typeName) {
|
|
|
1127
1132
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
1128
1133
|
}
|
|
1129
1134
|
function getField(fieldName, fields) {
|
|
1130
|
-
|
|
1131
|
-
return fields.find(({ name }) => name === fieldName);
|
|
1132
|
-
} else {
|
|
1133
|
-
return fields[fieldName];
|
|
1134
|
-
}
|
|
1135
|
+
return fields.find(({ name }) => name === fieldName);
|
|
1135
1136
|
}
|
|
1136
1137
|
function validateFieldSchema(field, value, logic) {
|
|
1137
1138
|
const validator = buildYupSchema(field, {}, logic);
|
|
@@ -1345,25 +1346,6 @@ function processNode({
|
|
|
1345
1346
|
logic
|
|
1346
1347
|
});
|
|
1347
1348
|
}
|
|
1348
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
1349
|
-
const values = formValues[name];
|
|
1350
|
-
if (Array.isArray(values)) {
|
|
1351
|
-
const newFields = [];
|
|
1352
|
-
const field = getField(name, formFields);
|
|
1353
|
-
values.forEach((value) => {
|
|
1354
|
-
const fields = field.fields();
|
|
1355
|
-
processNode({
|
|
1356
|
-
node: nestedNode.items,
|
|
1357
|
-
formValues: value,
|
|
1358
|
-
formFields: fields,
|
|
1359
|
-
parentID: name,
|
|
1360
|
-
logic
|
|
1361
|
-
});
|
|
1362
|
-
newFields.push(fields);
|
|
1363
|
-
});
|
|
1364
|
-
field.dynamicFields = newFields;
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
1349
|
});
|
|
1368
1350
|
}
|
|
1369
1351
|
if (node["x-jsf-logic"]) {
|
|
@@ -1735,16 +1717,6 @@ function buildFieldParameters(name, fieldProperties, required = [], config = {},
|
|
|
1735
1717
|
logic
|
|
1736
1718
|
);
|
|
1737
1719
|
}
|
|
1738
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
1739
|
-
fields = () => getFieldsFromJSONSchema(
|
|
1740
|
-
fieldProperties.items,
|
|
1741
|
-
{
|
|
1742
|
-
customProperties: get3(config, `customProperties.${name}.customProperties`, {}),
|
|
1743
|
-
parentID: name
|
|
1744
|
-
},
|
|
1745
|
-
logic
|
|
1746
|
-
);
|
|
1747
|
-
}
|
|
1748
1720
|
const result = {
|
|
1749
1721
|
name,
|
|
1750
1722
|
inputType,
|
|
@@ -1838,10 +1810,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
|
|
|
1838
1810
|
if (fieldParams.inputType === "group-array") {
|
|
1839
1811
|
const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
|
|
1840
1812
|
const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
|
|
1813
|
+
groupArrayItem.nameKey = groupArrayItem.name;
|
|
1841
1814
|
const customProperties = null;
|
|
1842
1815
|
const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
|
|
1843
1816
|
return composeFn(groupArrayItem);
|
|
1844
1817
|
});
|
|
1818
|
+
fieldParams.nameKey = fieldParams.name;
|
|
1845
1819
|
fieldParams.nthFieldGroup = {
|
|
1846
1820
|
name: fieldParams.name,
|
|
1847
1821
|
label: fieldParams.label,
|
package/dist/standalone.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2025 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.11.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.11.12-beta.0
|
|
5
|
+
Generated: Tue, 15 Apr 2025 08:28:29 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -11581,6 +11581,11 @@ function checkIfConditionMatchesProperties(node, formValues, formFields, logic)
|
|
|
11581
11581
|
if (typeof node.if === "boolean") {
|
|
11582
11582
|
return node.if;
|
|
11583
11583
|
}
|
|
11584
|
+
if (node.if.anyOf) {
|
|
11585
|
+
return node.if.anyOf.some(
|
|
11586
|
+
(property2) => checkIfConditionMatchesProperties({ if: property2 }, formValues, formFields, logic)
|
|
11587
|
+
);
|
|
11588
|
+
}
|
|
11584
11589
|
return Object.keys(node.if.properties ?? {}).every((name) => {
|
|
11585
11590
|
const currentProperty = node.if.properties[name];
|
|
11586
11591
|
const value = formValues[name];
|
|
@@ -12643,11 +12648,7 @@ function hasType(type, typeName) {
|
|
|
12643
12648
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
12644
12649
|
}
|
|
12645
12650
|
function getField(fieldName, fields) {
|
|
12646
|
-
|
|
12647
|
-
return fields.find(({ name }) => name === fieldName);
|
|
12648
|
-
} else {
|
|
12649
|
-
return fields[fieldName];
|
|
12650
|
-
}
|
|
12651
|
+
return fields.find(({ name }) => name === fieldName);
|
|
12651
12652
|
}
|
|
12652
12653
|
function validateFieldSchema(field, value, logic) {
|
|
12653
12654
|
const validator = buildYupSchema(field, {}, logic);
|
|
@@ -12861,25 +12862,6 @@ function processNode({
|
|
|
12861
12862
|
logic
|
|
12862
12863
|
});
|
|
12863
12864
|
}
|
|
12864
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
12865
|
-
const values2 = formValues[name];
|
|
12866
|
-
if (Array.isArray(values2)) {
|
|
12867
|
-
const newFields = [];
|
|
12868
|
-
const field = getField(name, formFields);
|
|
12869
|
-
values2.forEach((value) => {
|
|
12870
|
-
const fields = field.fields();
|
|
12871
|
-
processNode({
|
|
12872
|
-
node: nestedNode.items,
|
|
12873
|
-
formValues: value,
|
|
12874
|
-
formFields: fields,
|
|
12875
|
-
parentID: name,
|
|
12876
|
-
logic
|
|
12877
|
-
});
|
|
12878
|
-
newFields.push(fields);
|
|
12879
|
-
});
|
|
12880
|
-
field.dynamicFields = newFields;
|
|
12881
|
-
}
|
|
12882
|
-
}
|
|
12883
12865
|
});
|
|
12884
12866
|
}
|
|
12885
12867
|
if (node["x-jsf-logic"]) {
|
|
@@ -13251,16 +13233,6 @@ function buildFieldParameters(name, fieldProperties, required2 = [], config = {}
|
|
|
13251
13233
|
logic
|
|
13252
13234
|
);
|
|
13253
13235
|
}
|
|
13254
|
-
if (inputType === supportedTypes.GROUP_ARRAY) {
|
|
13255
|
-
fields = () => getFieldsFromJSONSchema(
|
|
13256
|
-
fieldProperties.items,
|
|
13257
|
-
{
|
|
13258
|
-
customProperties: (0, import_get4.default)(config, `customProperties.${name}.customProperties`, {}),
|
|
13259
|
-
parentID: name
|
|
13260
|
-
},
|
|
13261
|
-
logic
|
|
13262
|
-
);
|
|
13263
|
-
}
|
|
13264
13236
|
const result = {
|
|
13265
13237
|
name,
|
|
13266
13238
|
inputType,
|
|
@@ -13354,10 +13326,12 @@ function getFieldsFromJSONSchema(scopedJsonSchema, config, logic) {
|
|
|
13354
13326
|
if (fieldParams.inputType === "group-array") {
|
|
13355
13327
|
const groupArrayItems = convertJSONSchemaPropertiesToFieldParameters(fieldParams.items);
|
|
13356
13328
|
const groupArrayFields = groupArrayItems.map((groupArrayItem) => {
|
|
13329
|
+
groupArrayItem.nameKey = groupArrayItem.name;
|
|
13357
13330
|
const customProperties = null;
|
|
13358
13331
|
const composeFn = getComposeFunctionForField(groupArrayItem, !!customProperties);
|
|
13359
13332
|
return composeFn(groupArrayItem);
|
|
13360
13333
|
});
|
|
13334
|
+
fieldParams.nameKey = fieldParams.name;
|
|
13361
13335
|
fieldParams.nthFieldGroup = {
|
|
13362
13336
|
name: fieldParams.name,
|
|
13363
13337
|
label: fieldParams.label,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remoteoss/json-schema-form",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.12-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",
|
|
@@ -422,233 +422,6 @@ describe('Conditional attributes updated', () => {
|
|
|
422
422
|
handleValidation({ is_full_time: 'no' });
|
|
423
423
|
expect(fields[1].visibilityCondition).toEqual(expect.any(Function));
|
|
424
424
|
});
|
|
425
|
-
|
|
426
|
-
it('Group array nested condition', () => {
|
|
427
|
-
const { fields, handleValidation } = createHeadlessForm({
|
|
428
|
-
type: 'object',
|
|
429
|
-
additionalProperties: false,
|
|
430
|
-
properties: {
|
|
431
|
-
companies: {
|
|
432
|
-
type: 'array',
|
|
433
|
-
'x-jsf-presentation': {
|
|
434
|
-
inputType: 'group-array',
|
|
435
|
-
},
|
|
436
|
-
items: {
|
|
437
|
-
type: 'object',
|
|
438
|
-
properties: {
|
|
439
|
-
company: {
|
|
440
|
-
type: 'string',
|
|
441
|
-
oneOf: [
|
|
442
|
-
{
|
|
443
|
-
title: 'A',
|
|
444
|
-
const: 'A',
|
|
445
|
-
},
|
|
446
|
-
{
|
|
447
|
-
title: 'B',
|
|
448
|
-
const: 'B',
|
|
449
|
-
},
|
|
450
|
-
],
|
|
451
|
-
'x-jsf-presentation': {
|
|
452
|
-
inputType: 'select',
|
|
453
|
-
},
|
|
454
|
-
},
|
|
455
|
-
role: {
|
|
456
|
-
title: 'Role',
|
|
457
|
-
oneOf: [],
|
|
458
|
-
'x-jsf-presentation': {
|
|
459
|
-
inputType: 'select',
|
|
460
|
-
},
|
|
461
|
-
},
|
|
462
|
-
},
|
|
463
|
-
allOf: [
|
|
464
|
-
{
|
|
465
|
-
if: {
|
|
466
|
-
properties: {
|
|
467
|
-
company: {
|
|
468
|
-
const: 'A',
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
required: ['company'],
|
|
472
|
-
},
|
|
473
|
-
then: {
|
|
474
|
-
properties: {
|
|
475
|
-
role: {
|
|
476
|
-
oneOf: [
|
|
477
|
-
{
|
|
478
|
-
title: 'adminA',
|
|
479
|
-
const: 'adminA',
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
title: 'userA',
|
|
483
|
-
const: 'userA',
|
|
484
|
-
},
|
|
485
|
-
],
|
|
486
|
-
'x-jsf-presentation': {
|
|
487
|
-
inputType: 'select',
|
|
488
|
-
},
|
|
489
|
-
},
|
|
490
|
-
},
|
|
491
|
-
required: ['role'],
|
|
492
|
-
},
|
|
493
|
-
},
|
|
494
|
-
{
|
|
495
|
-
if: {
|
|
496
|
-
properties: {
|
|
497
|
-
company: {
|
|
498
|
-
const: 'B',
|
|
499
|
-
},
|
|
500
|
-
},
|
|
501
|
-
required: ['company'],
|
|
502
|
-
},
|
|
503
|
-
then: {
|
|
504
|
-
properties: {
|
|
505
|
-
role: {
|
|
506
|
-
oneOf: [
|
|
507
|
-
{
|
|
508
|
-
title: 'adminB',
|
|
509
|
-
const: 'adminB',
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
title: 'userB',
|
|
513
|
-
const: 'userB',
|
|
514
|
-
},
|
|
515
|
-
],
|
|
516
|
-
'x-jsf-presentation': {
|
|
517
|
-
inputType: 'select',
|
|
518
|
-
},
|
|
519
|
-
},
|
|
520
|
-
},
|
|
521
|
-
required: ['role'],
|
|
522
|
-
},
|
|
523
|
-
},
|
|
524
|
-
],
|
|
525
|
-
required: ['company', 'role'],
|
|
526
|
-
},
|
|
527
|
-
},
|
|
528
|
-
},
|
|
529
|
-
required: ['companies'],
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
handleValidation({ companies: [{ company: 'A' }, { company: 'B' }] });
|
|
533
|
-
expect(fields[0].dynamicFields[0][1].options).toEqual([
|
|
534
|
-
{ label: 'adminA', value: 'adminA' },
|
|
535
|
-
{ label: 'userA', value: 'userA' },
|
|
536
|
-
]);
|
|
537
|
-
expect(fields[0].dynamicFields[1][1].options).toEqual([
|
|
538
|
-
{ label: 'adminB', value: 'adminB' },
|
|
539
|
-
{ label: 'userB', value: 'userB' },
|
|
540
|
-
]);
|
|
541
|
-
handleValidation({ companies: [] });
|
|
542
|
-
expect(fields[0].dynamicFields).toEqual([]);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
it('select multiple conditions', () => {
|
|
546
|
-
const { fields, handleValidation } = createHeadlessForm({
|
|
547
|
-
type: 'object',
|
|
548
|
-
additionalProperties: false,
|
|
549
|
-
properties: {
|
|
550
|
-
company: {
|
|
551
|
-
title: 'Select Company',
|
|
552
|
-
type: 'string',
|
|
553
|
-
description: 'Choose a company',
|
|
554
|
-
oneOf: [
|
|
555
|
-
{
|
|
556
|
-
title: 'A',
|
|
557
|
-
const: 'A',
|
|
558
|
-
},
|
|
559
|
-
{
|
|
560
|
-
title: 'B',
|
|
561
|
-
const: 'B',
|
|
562
|
-
},
|
|
563
|
-
],
|
|
564
|
-
'x-jsf-presentation': {
|
|
565
|
-
inputType: 'select',
|
|
566
|
-
},
|
|
567
|
-
},
|
|
568
|
-
role: {
|
|
569
|
-
title: 'Role',
|
|
570
|
-
oneOf: [],
|
|
571
|
-
'x-jsf-presentation': {
|
|
572
|
-
inputType: 'select',
|
|
573
|
-
},
|
|
574
|
-
},
|
|
575
|
-
},
|
|
576
|
-
allOf: [
|
|
577
|
-
{
|
|
578
|
-
if: {
|
|
579
|
-
properties: {
|
|
580
|
-
company: {
|
|
581
|
-
const: 'A',
|
|
582
|
-
},
|
|
583
|
-
},
|
|
584
|
-
required: ['company'],
|
|
585
|
-
},
|
|
586
|
-
then: {
|
|
587
|
-
properties: {
|
|
588
|
-
role: {
|
|
589
|
-
oneOf: [
|
|
590
|
-
{
|
|
591
|
-
title: 'adminA',
|
|
592
|
-
const: 'adminA',
|
|
593
|
-
},
|
|
594
|
-
{
|
|
595
|
-
title: 'userA',
|
|
596
|
-
const: 'userA',
|
|
597
|
-
},
|
|
598
|
-
],
|
|
599
|
-
'x-jsf-presentation': {
|
|
600
|
-
inputType: 'select',
|
|
601
|
-
},
|
|
602
|
-
},
|
|
603
|
-
},
|
|
604
|
-
required: ['role'],
|
|
605
|
-
},
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
if: {
|
|
609
|
-
properties: {
|
|
610
|
-
company: {
|
|
611
|
-
const: 'B',
|
|
612
|
-
},
|
|
613
|
-
},
|
|
614
|
-
required: ['company'],
|
|
615
|
-
},
|
|
616
|
-
then: {
|
|
617
|
-
properties: {
|
|
618
|
-
role: {
|
|
619
|
-
oneOf: [
|
|
620
|
-
{
|
|
621
|
-
title: 'adminB',
|
|
622
|
-
const: 'adminB',
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
title: 'userB',
|
|
626
|
-
const: 'userB',
|
|
627
|
-
},
|
|
628
|
-
],
|
|
629
|
-
'x-jsf-presentation': {
|
|
630
|
-
inputType: 'select',
|
|
631
|
-
},
|
|
632
|
-
},
|
|
633
|
-
},
|
|
634
|
-
required: ['role'],
|
|
635
|
-
},
|
|
636
|
-
},
|
|
637
|
-
],
|
|
638
|
-
required: ['company', 'role'],
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
handleValidation({ company: 'A' });
|
|
642
|
-
expect(fields[1].options).toEqual([
|
|
643
|
-
{ label: 'adminA', value: 'adminA' },
|
|
644
|
-
{ label: 'userA', value: 'userA' },
|
|
645
|
-
]);
|
|
646
|
-
handleValidation({ company: 'B' });
|
|
647
|
-
expect(fields[1].options).toEqual([
|
|
648
|
-
{ label: 'adminB', value: 'adminB' },
|
|
649
|
-
{ label: 'userB', value: 'userB' },
|
|
650
|
-
]);
|
|
651
|
-
});
|
|
652
425
|
});
|
|
653
426
|
|
|
654
427
|
describe('Conditional with a minimum value check', () => {
|
|
@@ -775,6 +548,54 @@ describe('Conditional with literal booleans', () => {
|
|
|
775
548
|
});
|
|
776
549
|
});
|
|
777
550
|
|
|
551
|
+
describe('Conditional with anyOf', () => {
|
|
552
|
+
const schema = {
|
|
553
|
+
additionalProperties: false,
|
|
554
|
+
type: 'object',
|
|
555
|
+
properties: {
|
|
556
|
+
field_a: { type: 'string' },
|
|
557
|
+
field_b: { type: 'string' },
|
|
558
|
+
field_c: { type: 'string' },
|
|
559
|
+
},
|
|
560
|
+
allOf: [
|
|
561
|
+
{
|
|
562
|
+
if: {
|
|
563
|
+
anyOf: [
|
|
564
|
+
{ properties: { field_a: { const: '1' } }, required: ['field_a'] },
|
|
565
|
+
{ properties: { field_b: { const: '2' } }, required: ['field_b'] },
|
|
566
|
+
],
|
|
567
|
+
},
|
|
568
|
+
then: {
|
|
569
|
+
required: ['field_c'],
|
|
570
|
+
},
|
|
571
|
+
else: {
|
|
572
|
+
properties: {
|
|
573
|
+
field_c: false,
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
it('handles true case', () => {
|
|
581
|
+
const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
|
|
582
|
+
|
|
583
|
+
expect(fields[2].isVisible).toBe(false);
|
|
584
|
+
expect(handleValidation({ field_a: 'x', field_b: '2' }).formErrors).toEqual({
|
|
585
|
+
field_c: 'Required field',
|
|
586
|
+
});
|
|
587
|
+
expect(fields[2].isVisible).toBe(true);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
it('handles false case', () => {
|
|
591
|
+
const { fields, handleValidation } = createHeadlessForm(schema, { strictInputType: false });
|
|
592
|
+
|
|
593
|
+
expect(fields[2].isVisible).toBe(false);
|
|
594
|
+
expect(handleValidation({ field_a: 'x', field_b: 'x' }).formErrors).toBeUndefined();
|
|
595
|
+
expect(fields[2].isVisible).toBe(false);
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
|
|
778
599
|
describe('Conditionals - bugs and code-smells', () => {
|
|
779
600
|
// Why do we have these bugs?
|
|
780
601
|
// To be honest we never realized it much later later.
|
|
@@ -63,7 +63,6 @@ import {
|
|
|
63
63
|
schemaForErrorMessageSpecificity,
|
|
64
64
|
jsfConfigForErrorMessageSpecificity,
|
|
65
65
|
schemaInputTypeFile,
|
|
66
|
-
nestedGroupArrayForm,
|
|
67
66
|
} from './helpers';
|
|
68
67
|
import { mockConsole, restoreConsoleAndEnsureItWasNotCalled } from './testUtils';
|
|
69
68
|
import { createHeadlessForm } from '@/createHeadlessForm';
|
|
@@ -1605,6 +1604,7 @@ describe('createHeadlessForm', () => {
|
|
|
1605
1604
|
type: 'text',
|
|
1606
1605
|
description: 'Enter your child’s full name',
|
|
1607
1606
|
maxLength: 255,
|
|
1607
|
+
nameKey: 'full_name',
|
|
1608
1608
|
label: 'Child Full Name',
|
|
1609
1609
|
name: 'full_name',
|
|
1610
1610
|
required: true,
|
|
@@ -1616,6 +1616,7 @@ describe('createHeadlessForm', () => {
|
|
|
1616
1616
|
required: true,
|
|
1617
1617
|
description: 'Enter your child’s date of birth',
|
|
1618
1618
|
maxLength: 255,
|
|
1619
|
+
nameKey: 'birthdate',
|
|
1619
1620
|
},
|
|
1620
1621
|
{
|
|
1621
1622
|
type: 'radio',
|
|
@@ -1634,6 +1635,7 @@ describe('createHeadlessForm', () => {
|
|
|
1634
1635
|
required: true,
|
|
1635
1636
|
description:
|
|
1636
1637
|
'We know sex is non-binary but for insurance and payroll purposes, we need to collect this information.',
|
|
1638
|
+
nameKey: 'sex',
|
|
1637
1639
|
},
|
|
1638
1640
|
]);
|
|
1639
1641
|
});
|
|
@@ -1735,63 +1737,6 @@ describe('createHeadlessForm', () => {
|
|
|
1735
1737
|
});
|
|
1736
1738
|
});
|
|
1737
1739
|
|
|
1738
|
-
it('nested "group-array" fields', () => {
|
|
1739
|
-
const result = createHeadlessForm({
|
|
1740
|
-
properties: {
|
|
1741
|
-
nestedGroupArray: nestedGroupArrayForm,
|
|
1742
|
-
},
|
|
1743
|
-
});
|
|
1744
|
-
|
|
1745
|
-
expect(result.fields[0]).toMatchObject({
|
|
1746
|
-
label: 'Parent object',
|
|
1747
|
-
name: 'nestedGroupArray',
|
|
1748
|
-
required: false,
|
|
1749
|
-
type: 'group-array',
|
|
1750
|
-
inputType: 'group-array',
|
|
1751
|
-
jsonType: 'array',
|
|
1752
|
-
fields: expect.any(Function),
|
|
1753
|
-
});
|
|
1754
|
-
|
|
1755
|
-
expect(result.fields[0].fields()).toMatchObject([
|
|
1756
|
-
{
|
|
1757
|
-
type: 'text',
|
|
1758
|
-
description: 'Simple text field',
|
|
1759
|
-
maxLength: 255,
|
|
1760
|
-
label: 'Outer Field',
|
|
1761
|
-
name: 'notNested',
|
|
1762
|
-
required: true,
|
|
1763
|
-
},
|
|
1764
|
-
{
|
|
1765
|
-
label: 'Nested group-array',
|
|
1766
|
-
name: 'nested',
|
|
1767
|
-
required: true,
|
|
1768
|
-
type: 'group-array',
|
|
1769
|
-
inputType: 'group-array',
|
|
1770
|
-
jsonType: 'array',
|
|
1771
|
-
fields: expect.any(Function),
|
|
1772
|
-
},
|
|
1773
|
-
]);
|
|
1774
|
-
|
|
1775
|
-
expect(result.fields[0].fields()[1].fields()).toMatchObject([
|
|
1776
|
-
{
|
|
1777
|
-
type: 'text',
|
|
1778
|
-
description: 'First nested text field',
|
|
1779
|
-
maxLength: 255,
|
|
1780
|
-
label: 'Inner Field 1',
|
|
1781
|
-
name: 'nestedField1',
|
|
1782
|
-
required: true,
|
|
1783
|
-
},
|
|
1784
|
-
{
|
|
1785
|
-
type: 'text',
|
|
1786
|
-
description: 'Second nested text field',
|
|
1787
|
-
maxLength: 255,
|
|
1788
|
-
label: 'Inner Field 2',
|
|
1789
|
-
name: 'nestedField2',
|
|
1790
|
-
required: true,
|
|
1791
|
-
},
|
|
1792
|
-
]);
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
1740
|
it('can pass custom field attributes', () => {
|
|
1796
1741
|
const result = createHeadlessForm(
|
|
1797
1742
|
{
|
|
@@ -2576,7 +2521,7 @@ describe('createHeadlessForm', () => {
|
|
|
2576
2521
|
.addInput({
|
|
2577
2522
|
username: {
|
|
2578
2523
|
...mockTextInputDeprecated,
|
|
2579
|
-
presentation: {
|
|
2524
|
+
'x-jsf-presentation': {
|
|
2580
2525
|
inputType: 'text',
|
|
2581
2526
|
maskSecret: 2,
|
|
2582
2527
|
// should override the root level description
|
|
@@ -11,7 +11,7 @@ export const schemaInputTypeTextarea = {
|
|
|
11
11
|
properties: {
|
|
12
12
|
comment: {
|
|
13
13
|
title: 'Your comment',
|
|
14
|
-
presentation: {
|
|
14
|
+
'x-jsf-presentation': {
|
|
15
15
|
inputType: 'textarea',
|
|
16
16
|
},
|
|
17
17
|
maxLength: 250,
|
|
@@ -29,7 +29,7 @@ export const inputTypeCountriesSolo = {
|
|
|
29
29
|
{ title: 'Algeria', const: 'Algeria' },
|
|
30
30
|
],
|
|
31
31
|
type: 'string',
|
|
32
|
-
presentation: {
|
|
32
|
+
'x-jsf-presentation': {
|
|
33
33
|
inputType: 'countries',
|
|
34
34
|
},
|
|
35
35
|
};
|
|
@@ -58,7 +58,7 @@ export const schemaInputTypeCountriesMultiple = {
|
|
|
58
58
|
],
|
|
59
59
|
},
|
|
60
60
|
type: 'array',
|
|
61
|
-
presentation: {
|
|
61
|
+
'x-jsf-presentation': {
|
|
62
62
|
inputType: 'countries',
|
|
63
63
|
},
|
|
64
64
|
},
|
|
@@ -90,7 +90,7 @@ export const schemaInputTypeTel = {
|
|
|
90
90
|
type: 'string',
|
|
91
91
|
pattern: '^(\\+|00)[0-9]{6,}$',
|
|
92
92
|
maxLength: 30,
|
|
93
|
-
presentation: {
|
|
93
|
+
'x-jsf-presentation': {
|
|
94
94
|
inputType: 'tel',
|
|
95
95
|
},
|
|
96
96
|
errorMessage: {
|
|
@@ -106,7 +106,7 @@ const mockTelInput = {
|
|
|
106
106
|
title: 'Phone number',
|
|
107
107
|
description: 'Enter your telephone number',
|
|
108
108
|
maxLength: 30,
|
|
109
|
-
presentation: {
|
|
109
|
+
'x-jsf-presentation': {
|
|
110
110
|
inputType: 'tel',
|
|
111
111
|
},
|
|
112
112
|
pattern: '^(\\+|00)\\d*$',
|
|
@@ -116,7 +116,7 @@ const mockTelInput = {
|
|
|
116
116
|
export const mockMoneyInput = {
|
|
117
117
|
title: 'Weekly salary',
|
|
118
118
|
description: 'This field has a min and max values. Max has a custom error message.',
|
|
119
|
-
presentation: {
|
|
119
|
+
'x-jsf-presentation': {
|
|
120
120
|
inputType: 'money',
|
|
121
121
|
currency: 'EUR',
|
|
122
122
|
},
|
|
@@ -150,7 +150,7 @@ export const schemaCustomComponent = {
|
|
|
150
150
|
salary: {
|
|
151
151
|
title: 'Monthly gross salary',
|
|
152
152
|
description: 'This field gets represented by a custom UI Component.',
|
|
153
|
-
presentation: {
|
|
153
|
+
'x-jsf-presentation': {
|
|
154
154
|
inputType: 'money',
|
|
155
155
|
currency: 'EUR',
|
|
156
156
|
},
|
package/src/tests/helpers.js
CHANGED
|
@@ -17,7 +17,7 @@ export const mockTextInputDeprecated = {
|
|
|
17
17
|
title: 'Username',
|
|
18
18
|
description: 'Your username (max 10 characters)',
|
|
19
19
|
maxLength: 10,
|
|
20
|
-
presentation: {
|
|
20
|
+
'x-jsf-presentation': {
|
|
21
21
|
inputType: 'text',
|
|
22
22
|
maskSecret: 2,
|
|
23
23
|
},
|
|
@@ -1284,7 +1284,7 @@ export const schemaForErrorMessageSpecificity = {
|
|
|
1284
1284
|
title: 'Weekday',
|
|
1285
1285
|
description: "This text field has the traditional error message. 'Required field'",
|
|
1286
1286
|
type: 'string',
|
|
1287
|
-
presentation: { inputType: 'text' },
|
|
1287
|
+
'x-jsf-presentation': { inputType: 'text' },
|
|
1288
1288
|
},
|
|
1289
1289
|
day: {
|
|
1290
1290
|
title: 'Day',
|
|
@@ -1293,21 +1293,21 @@ export const schemaForErrorMessageSpecificity = {
|
|
|
1293
1293
|
'The remaining fields are numbers and were customized to say "This cannot be empty." instead of "Required field".',
|
|
1294
1294
|
|
|
1295
1295
|
maximum: 31,
|
|
1296
|
-
presentation: { inputType: 'number' },
|
|
1296
|
+
'x-jsf-presentation': { inputType: 'number' },
|
|
1297
1297
|
},
|
|
1298
1298
|
month: {
|
|
1299
1299
|
title: 'Month',
|
|
1300
1300
|
type: 'number',
|
|
1301
1301
|
minimum: 1,
|
|
1302
1302
|
maximum: 12,
|
|
1303
|
-
presentation: { inputType: 'number' },
|
|
1303
|
+
'x-jsf-presentation': { inputType: 'number' },
|
|
1304
1304
|
},
|
|
1305
1305
|
year: {
|
|
1306
1306
|
title: 'Year',
|
|
1307
1307
|
description:
|
|
1308
1308
|
"This number field has a custom error message declared in the json schema, which has a higher specificity than the one declared in createHeadlessForm's configuration.",
|
|
1309
1309
|
type: 'number',
|
|
1310
|
-
presentation: { inputType: 'number' },
|
|
1310
|
+
'x-jsf-presentation': { inputType: 'number' },
|
|
1311
1311
|
'x-jsf-errorMessage': {
|
|
1312
1312
|
required: 'The year is mandatory.',
|
|
1313
1313
|
},
|
|
@@ -2327,59 +2327,3 @@ export const schemaWithCustomValidationsAndConditionals = {
|
|
|
2327
2327
|
},
|
|
2328
2328
|
],
|
|
2329
2329
|
};
|
|
2330
|
-
|
|
2331
|
-
export const nestedGroupArrayForm = {
|
|
2332
|
-
items: {
|
|
2333
|
-
properties: {
|
|
2334
|
-
notNested: {
|
|
2335
|
-
description: 'Simple text field',
|
|
2336
|
-
'x-jsf-presentation': {
|
|
2337
|
-
inputType: 'text',
|
|
2338
|
-
},
|
|
2339
|
-
title: 'Outer Field',
|
|
2340
|
-
type: 'string',
|
|
2341
|
-
maxLength: 255,
|
|
2342
|
-
},
|
|
2343
|
-
nested: {
|
|
2344
|
-
items: {
|
|
2345
|
-
properties: {
|
|
2346
|
-
nestedField1: {
|
|
2347
|
-
description: 'First nested text field',
|
|
2348
|
-
'x-jsf-presentation': {
|
|
2349
|
-
inputType: 'text',
|
|
2350
|
-
},
|
|
2351
|
-
title: 'Inner Field 1',
|
|
2352
|
-
type: 'string',
|
|
2353
|
-
maxLength: 255,
|
|
2354
|
-
},
|
|
2355
|
-
nestedField2: {
|
|
2356
|
-
description: 'Second nested text field',
|
|
2357
|
-
'x-jsf-presentation': {
|
|
2358
|
-
inputType: 'text',
|
|
2359
|
-
},
|
|
2360
|
-
title: 'Inner Field 2',
|
|
2361
|
-
type: 'string',
|
|
2362
|
-
maxLength: 255,
|
|
2363
|
-
},
|
|
2364
|
-
},
|
|
2365
|
-
'x-jsf-order': ['nestedField1', 'nestedField2'],
|
|
2366
|
-
required: ['nestedField1', 'nestedField2'],
|
|
2367
|
-
type: 'object',
|
|
2368
|
-
},
|
|
2369
|
-
'x-jsf-presentation': {
|
|
2370
|
-
inputType: 'group-array',
|
|
2371
|
-
},
|
|
2372
|
-
title: 'Nested group-array',
|
|
2373
|
-
type: 'array',
|
|
2374
|
-
},
|
|
2375
|
-
},
|
|
2376
|
-
'x-jsf-order': ['notNested', 'nested'],
|
|
2377
|
-
required: ['notNested', 'nested'],
|
|
2378
|
-
type: 'object',
|
|
2379
|
-
},
|
|
2380
|
-
'x-jsf-presentation': {
|
|
2381
|
-
inputType: 'group-array',
|
|
2382
|
-
},
|
|
2383
|
-
title: 'Parent object',
|
|
2384
|
-
type: 'array',
|
|
2385
|
-
};
|
|
@@ -984,3 +984,51 @@ export const schemaWithTwoValidationsWhereOneOfThemIsAppliedConditionally = {
|
|
|
984
984
|
},
|
|
985
985
|
],
|
|
986
986
|
};
|
|
987
|
+
|
|
988
|
+
export const schemaWithReduceAccumulator = {
|
|
989
|
+
properties: {
|
|
990
|
+
work_days: {
|
|
991
|
+
items: {
|
|
992
|
+
anyOf: [
|
|
993
|
+
{ const: 'monday', title: 'Monday' },
|
|
994
|
+
{ const: 'tuesday', title: 'Tuesday' },
|
|
995
|
+
{ const: 'wednesday', title: 'Wednesday' },
|
|
996
|
+
{ const: 'thursday', title: 'Thursday' },
|
|
997
|
+
{ const: 'friday', title: 'Friday' },
|
|
998
|
+
{ const: 'saturday', title: 'Saturday' },
|
|
999
|
+
{ const: 'sunday', title: 'Sunday' },
|
|
1000
|
+
],
|
|
1001
|
+
},
|
|
1002
|
+
type: 'array',
|
|
1003
|
+
uniqueItems: true,
|
|
1004
|
+
'x-jsf-presentation': {
|
|
1005
|
+
inputType: 'select',
|
|
1006
|
+
},
|
|
1007
|
+
},
|
|
1008
|
+
working_hours_per_day: {
|
|
1009
|
+
type: 'number',
|
|
1010
|
+
},
|
|
1011
|
+
working_hours_per_week: {
|
|
1012
|
+
type: 'number',
|
|
1013
|
+
'x-jsf-logic-computedAttrs': {
|
|
1014
|
+
const: 'computed_work_hours_per_week',
|
|
1015
|
+
defaultValue: 'computed_work_hours_per_week',
|
|
1016
|
+
title: '{{computed_work_hours_per_week}} hours per week',
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
'x-jsf-logic': {
|
|
1021
|
+
computedValues: {
|
|
1022
|
+
computed_work_hours_per_week: {
|
|
1023
|
+
rule: {
|
|
1024
|
+
'*': [
|
|
1025
|
+
{ var: 'working_hours_per_day' },
|
|
1026
|
+
{
|
|
1027
|
+
reduce: [{ var: 'work_days' }, { '+': [{ var: ['accumulator', 0] }, 1] }, 0],
|
|
1028
|
+
},
|
|
1029
|
+
],
|
|
1030
|
+
},
|
|
1031
|
+
},
|
|
1032
|
+
},
|
|
1033
|
+
},
|
|
1034
|
+
};
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
schemaWithUnknownVariableInValidations,
|
|
35
35
|
schemaWithValidationThatDoesNotExistOnProperty,
|
|
36
36
|
badSchemaThatWillNotSetAForcedValue,
|
|
37
|
+
schemaWithReduceAccumulator,
|
|
37
38
|
} from './jsonLogic.fixtures';
|
|
38
39
|
import { mockConsole, restoreConsoleAndEnsureItWasNotCalled } from './testUtils';
|
|
39
40
|
import { createHeadlessForm } from '@/createHeadlessForm';
|
|
@@ -243,6 +244,23 @@ describe('jsonLogic: cross-values validations', () => {
|
|
|
243
244
|
});
|
|
244
245
|
});
|
|
245
246
|
|
|
247
|
+
// TODO: Implement this test.
|
|
248
|
+
describe.skip('Reduce', () => {
|
|
249
|
+
it('reduce: working_hours_per_day * work_days', () => {
|
|
250
|
+
const { fields, handleValidation } = createHeadlessForm(schemaWithReduceAccumulator, {
|
|
251
|
+
strictInputType: false,
|
|
252
|
+
});
|
|
253
|
+
handleValidation({
|
|
254
|
+
work_days: ['monday', 'tuesday'],
|
|
255
|
+
working_hours_per_day: 8,
|
|
256
|
+
});
|
|
257
|
+
const field = fields.find((i) => i.name === 'working_hours_per_week');
|
|
258
|
+
expect(field.const).toEqual(16);
|
|
259
|
+
expect(field.default).toEqual(16);
|
|
260
|
+
expect(field.label).toEqual('16 hours per week');
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
246
264
|
describe('Logical: ||, &&', () => {
|
|
247
265
|
it('AND: field_a > field_b && field_a > field_c (implicit with multiple rules in a single field)', () => {
|
|
248
266
|
const schema = createSchemaWithThreePropertiesWithRuleOnFieldA({
|