Skip to content

Commit 1f15939

Browse files
committed
Merge remote-tracking branch 'origin/inline-rule-handling' into conditionals-json-logic
1 parent 42cf4ab commit 1f15939

File tree

8 files changed

+97
-16
lines changed

8 files changed

+97
-16
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
#### 0.6.1-beta.0 (2023-09-13)
2+
3+
##### Changes
4+
5+
6+
7+
- Computed string based values for json-logic ([#37](https://github.com/remoteoss/json-schema-form/pull/37)) ([6e042ea5](https://github.com/remoteoss/json-schema-form/commit/6e042ea579497ea573710c307a6ff7ee2f19b931))
8+
9+
#### 0.5.0-beta.0 (2023-09-12)
10+
11+
##### Changes
12+
13+
- Computed Attributes ([#36](https://github.com/remoteoss/json-schema-form/pull/36)) ([80c29589](https://github.com/remoteoss/json-schema-form/commit/80c29589ac0972e0f33add70a59df15a46db1b43))
14+
- JSON Logic Skeleton ([#35](https://github.com/remoteoss/json-schema-form/pull/35)) ([63149ae8](https://github.com/remoteoss/json-schema-form/commit/63149ae863cf1b5ad76a3b2a49c7f343e55ce07b))
15+
116
#### 0.4.5-beta.0 (2023-08-31)
217

318
##### Changes

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@remoteoss/json-schema-form",
3-
"version": "0.4.5-beta.0",
3+
"version": "0.6.1-beta.0",
44
"description": "Headless UI form powered by JSON Schemas",
55
"author": "Remote.com <[email protected]> (https://remote.com/)",
66
"license": "MIT",

src/helpers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ export function extractParametersFromNode(schemaNode) {
497497
return omitBy(
498498
{
499499
const: node.const,
500+
...(node.const && node.default ? { value: node.const } : {}),
500501
label: node.title,
501502
readOnly: node.readOnly,
502503
...(node.deprecated && {

src/jsonLogic.js

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ import { buildYupSchema } from './yupSchema';
1616
* @returns {Object} An object containing:
1717
* - scopes {Map} - A Map of the validation scopes (with IDs as keys)
1818
* - getScope {Function} - Function to retrieve a scope by name/ID
19-
* - validate {Function} - Function to evaluate a validation rule
20-
* - applyValidationRuleInCondition {Function} - Evaluate a validation rule used in a condition
21-
* - applyComputedValueInField {Function} - Evaluate a computed value rule for a field
22-
* - applyComputedValueRuleInCondition {Function} - Evaluate a computed value rule used in a condition
2319
*/
2420
export function createValidationChecker(schema) {
2521
const scopes = new Map();
@@ -50,6 +46,21 @@ export function createValidationChecker(schema) {
5046
};
5147
}
5248

49+
/**
50+
* Creates a validation scope object for a schema.
51+
*
52+
* Builds maps of validations and computed values defined in the schema's
53+
* x-jsf-logic section. Includes functions to evaluate the rules.
54+
*
55+
* @param {Object} schema - The JSON schema
56+
* @returns {Object} The validation scope object containing:
57+
* - validationMap - Map of validation rules
58+
* - computedValuesMap - Map of computed value rules
59+
* - validate {Function} - Function to evaluate a validation rule
60+
* - applyValidationRuleInCondition {Function} - Evaluate a validation rule used in a condition
61+
* - applyComputedValueInField {Function} - Evaluate a computed value rule for a field
62+
* - applyComputedValueRuleInCondition {Function} - Evaluate a computed value rule used in a condition
63+
*/
5364
function createValidationsScope(schema) {
5465
const validationMap = new Map();
5566
const computedValuesMap = new Map();
@@ -162,6 +173,20 @@ export function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
162173

163174
const HANDLEBARS_REGEX = /\{\{([^{}]+)\}\}/g;
164175

176+
/**
177+
* Replaces Handlebars templates in a value with computed values.
178+
*
179+
* Handles recursively replacing Handlebars templates "{{var}}" in strings
180+
* with computed values looked up from the validation logic.
181+
*
182+
* @param {Object} options - Options object
183+
* @param {*} options.value - The value to replace templates in
184+
* @param {Object} options.logic - The validation logic object
185+
* @param {Object} options.formValues - The current form values
186+
* @param {string} options.parentID - The ID of the validation scope
187+
* @param {string} options.name - The name of the field
188+
* @returns {*} The value with templates replaced with computed values
189+
*/
165190
function replaceHandlebarsTemplates({
166191
value: toReplace,
167192
logic,
@@ -397,8 +422,18 @@ function throwIfUnknownOperator(operator, subRule, id) {
397422
}
398423
}
399424

425+
const regexToGetIndices = /\.\d+\./g; // eg. .0., .10.
426+
427+
/**
428+
* Removes array indices from a json schema path string.
429+
* Converts paths like "foo.0.bar" to "foo.bar".
430+
* This allows checking if a variable exists in an array item schema without needing the specific index.
431+
*
432+
* @param {string} path - The json schema path potentially containing array indices
433+
* @returns {string} The path with array indices removed
434+
*/
400435
function removeIndicesFromPath(path) {
401-
const intermediatePath = path.replace(/\.\d+\./g, '.');
436+
const intermediatePath = path.replace(regexToGetIndices, '.');
402437
return intermediatePath.replace(/\.\d+$/, '');
403438
}
404439

src/tests/const.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,16 @@ describe('validations: const', () => {
8383
});
8484
expect(handleValidation({ string: 'hello' }).formErrors).toEqual(undefined);
8585
});
86+
87+
it('Should have value attribute for when const & default is present', () => {
88+
const { fields } = createHeadlessForm(
89+
{
90+
properties: {
91+
ten_only: { type: 'number', const: 10, default: 10 },
92+
},
93+
},
94+
{ strictInputType: false }
95+
);
96+
expect(fields[0]).toMatchObject({ value: 10, const: 10, default: 10 });
97+
});
8698
});

src/tests/jsonLogic.fixtures.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,24 @@ export const schemaWithComputedAttributes = {
227227
},
228228
};
229229

230+
export const schemaWithInlineRuleForComputedAttributeWithoutCopy = {
231+
properties: {
232+
field_a: {
233+
type: 'number',
234+
},
235+
field_b: {
236+
type: 'number',
237+
'x-jsf-logic-computedAttrs': {
238+
title: {
239+
rule: {
240+
'+': [{ var: 'field_a' }, 10],
241+
},
242+
},
243+
},
244+
},
245+
},
246+
};
247+
230248
export const schemaWithComputedAttributeThatDoesntExist = {
231249
properties: {
232250
field_a: {
@@ -463,7 +481,7 @@ export const schemaWithInlineMultipleRulesForComputedAttributes = {
463481
},
464482
};
465483

466-
export const schemaSelfContainedValueForTitle = {
484+
export const schemaInlineComputedAttrForTitle = {
467485
properties: {
468486
field_a: {
469487
type: 'number',
@@ -482,7 +500,7 @@ export const schemaSelfContainedValueForTitle = {
482500
},
483501
};
484502

485-
export const schemaSelfContainedValueForMaximumMinimumValues = {
503+
export const schemaInlineComputedAttrForMaximumMinimumValues = {
486504
properties: {
487505
field_a: {
488506
type: 'number',

src/tests/jsonLogic.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import {
44
createSchemaWithRulesOnFieldA,
55
createSchemaWithThreePropertiesWithRuleOnFieldA,
66
multiRuleSchema,
7-
schemaSelfContainedValueForMaximumMinimumValues,
8-
schemaSelfContainedValueForTitle,
97
schemaWhereValidationAndComputedValueIsAppliedOnNormalThenStatement,
8+
schemaInlineComputedAttrForMaximumMinimumValues,
9+
schemaInlineComputedAttrForTitle,
1010
schemaWithBadOperation,
1111
schemaWithChecksAndThenValidationsOnThen,
1212
schemaWithComputedAttributeThatDoesntExist,
@@ -384,18 +384,18 @@ describe('jsonLogic: cross-values validations', () => {
384384
expect(fieldB.description).toEqual('Must be between 5 and 20.');
385385
});
386386

387-
it('Use a self contained rule in a schema for a title but it just uses the value', () => {
388-
const { fields, handleValidation } = createHeadlessForm(schemaSelfContainedValueForTitle, {
387+
it('Use an inline rule in a schema for a title but it just uses the value', () => {
388+
const { fields, handleValidation } = createHeadlessForm(schemaInlineComputedAttrForTitle, {
389389
strictInputType: false,
390390
});
391391
const [, fieldB] = fields;
392392
expect(handleValidation({ field_a: 10, field_b: null }).formErrors).toEqual(undefined);
393393
expect(fieldB.label).toEqual('20');
394394
});
395395

396-
it('Use a self contained rule for a minimum, maximum value', () => {
396+
it('Use an inline rule for a minimum, maximum value', () => {
397397
const { fields, handleValidation } = createHeadlessForm(
398-
schemaSelfContainedValueForMaximumMinimumValues,
398+
schemaInlineComputedAttrForMaximumMinimumValues,
399399
{
400400
strictInputType: false,
401401
}

0 commit comments

Comments
 (0)