Skip to content

Commit d3f26e2

Browse files
committed
parent 80c2958
author brennj <[email protected]> 1694505093 +0200 committer brennj <[email protected]> 1694508319 +0200 Release 0.5.0-beta.0 chore: support barebones computedAttrs chore: fix errors chore: fix mess ups from rebase chore: feedback from PR chore: pass logic down at updateFieldsProperties to prevent bugs feat: JSON Logic skeleton and plumbing setup chore: clean up conditional additions chore: remove const tests chore: remove dupe file chore: remove group array stuff chore: clean up yupschema chore: clean up helpers a small bit chore: remove all error handling for now chore: clean up package-lock chore: more removing stuff chore: clean more chore: support barebones computedAttrs chore: computed string attributes chore: fix tests chore: consistency for curly braces chore: remove unneeded code for now
1 parent 80c2958 commit d3f26e2

File tree

7 files changed

+134
-6
lines changed

7 files changed

+134
-6
lines changed

.eslintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"rules": {
1313
"jest/no-focused-tests": "error",
14+
"curly": ["error", "multi-line"],
1415
"arrow-body-style": 0,
1516
"default-case": 0,
1617
"import/order": [

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#### 0.5.0-beta.0 (2023-09-12)
2+
3+
##### Changes
4+
5+
- Computed Attributes ([#36](https://github.com/remoteoss/json-schema-form/pull/36)) ([80c29589](https://github.com/remoteoss/json-schema-form/commit/80c29589ac0972e0f33add70a59df15a46db1b43))
6+
- JSON Logic Skeleton ([#35](https://github.com/remoteoss/json-schema-form/pull/35)) ([63149ae8](https://github.com/remoteoss/json-schema-form/commit/63149ae863cf1b5ad76a3b2a49c7f343e55ce07b))
7+
18
#### 0.4.5-beta.0 (2023-08-31)
29

310
##### 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.5.0-beta.0",
44
"description": "Headless UI form powered by JSON Schemas",
55
"author": "Remote.com <[email protected]> (https://remote.com/)",
66
"license": "MIT",

src/jsonLogic.js

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import jsonLogic from 'json-logic-js';
22

3+
import { buildYupSchema } from './yupSchema';
4+
35
/**
46
* Parses the JSON schema to extract the json-logic rules and returns an object
57
* containing the validation scopes, functions to retrieve the scopes, and evaluate the
@@ -123,26 +125,81 @@ export function yupSchemaWithCustomJSONLogic({ field, logic, config, id }) {
123125
);
124126
}
125127

128+
const HANDLEBARS_REGEX = /\{\{([^{}]+)\}\}/g;
129+
130+
function replaceHandlebarsTemplates({
131+
value: toReplace,
132+
logic,
133+
formValues,
134+
parentID,
135+
name: fieldName,
136+
}) {
137+
if (typeof toReplace === 'string') {
138+
return toReplace.replace(HANDLEBARS_REGEX, (match, key) => {
139+
return logic.getScope(parentID).applyComputedValueInField(key.trim(), formValues, fieldName);
140+
});
141+
}
142+
return toReplace;
143+
}
144+
126145
export function calculateComputedAttributes(fieldParams, { parentID = 'root' } = {}) {
127-
return ({ logic, formValues }) => {
146+
return ({ logic, isRequired, config, formValues }) => {
128147
const { computedAttributes } = fieldParams;
129148
const attributes = Object.fromEntries(
130149
Object.entries(computedAttributes)
131150
.map(handleComputedAttribute(logic, formValues, parentID))
132151
.filter(([, value]) => value !== null)
133152
);
134153

135-
return attributes;
154+
return {
155+
...attributes,
156+
schema: buildYupSchema(
157+
{ ...fieldParams, ...attributes, required: isRequired },
158+
config,
159+
logic
160+
),
161+
};
136162
};
137163
}
138164

139165
function handleComputedAttribute(logic, formValues, parentID) {
140166
return ([key, value]) => {
141-
if (key === 'const')
167+
if (key === 'description') {
168+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
169+
}
170+
171+
if (key === 'title') {
172+
return ['label', replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
173+
}
174+
175+
if (key === 'const') {
142176
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
177+
}
178+
179+
if (key === 'x-jsf-errorMessage') {
180+
return [
181+
'errorMessage',
182+
handleNestedObjectForComputedValues(value, formValues, parentID, logic, name),
183+
];
184+
}
143185

144186
if (typeof value === 'string') {
145187
return [key, logic.getScope(parentID).applyComputedValueInField(value, formValues)];
146188
}
189+
190+
if (key === 'x-jsf-presentation' && value.statement) {
191+
return [
192+
'statement',
193+
handleNestedObjectForComputedValues(value.statement, formValues, parentID, logic, name),
194+
];
195+
}
147196
};
148197
}
198+
199+
function handleNestedObjectForComputedValues(values, formValues, parentID, logic, name) {
200+
return Object.fromEntries(
201+
Object.entries(values).map(([key, value]) => {
202+
return [key, replaceHandlebarsTemplates({ value, logic, formValues, parentID, name })];
203+
})
204+
);
205+
}

src/tests/jsonLogic.fixtures.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,10 @@ export const schemaWithComputedAttributes = {
144144
field_b: {
145145
type: 'number',
146146
'x-jsf-logic-computedAttrs': {
147+
title: 'This is {{a_times_two}}!',
147148
const: 'a_times_two',
148149
default: 'a_times_two',
150+
description: 'This field is 2 times bigger than field_a with value of {{a_times_two}}.',
149151
},
150152
},
151153
},
@@ -160,3 +162,42 @@ export const schemaWithComputedAttributes = {
160162
},
161163
},
162164
};
165+
166+
export const schemaWithComputedAttributesAndErrorMessages = {
167+
properties: {
168+
field_a: {
169+
type: 'number',
170+
},
171+
field_b: {
172+
type: 'number',
173+
'x-jsf-logic-computedAttrs': {
174+
minimum: 'a_times_two',
175+
maximum: 'a_times_four',
176+
'x-jsf-errorMessage': {
177+
minimum: 'Must be bigger than {{a_times_two}}',
178+
maximum: 'Must be smaller than {{a_times_four}}',
179+
},
180+
'x-jsf-presentation': {
181+
statement: {
182+
description: 'Must be bigger than {{a_times_two}} and smaller than {{a_times_four}}',
183+
},
184+
},
185+
},
186+
},
187+
},
188+
required: ['field_a', 'field_b'],
189+
'x-jsf-logic': {
190+
computedValues: {
191+
a_times_two: {
192+
rule: {
193+
'*': [{ var: 'field_a' }, 2],
194+
},
195+
},
196+
a_times_four: {
197+
rule: {
198+
'*': [{ var: 'field_a' }, 4],
199+
},
200+
},
201+
},
202+
},
203+
};

src/tests/jsonLogic.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
createSchemaWithThreePropertiesWithRuleOnFieldA,
66
multiRuleSchema,
77
schemaWithComputedAttributes,
8+
schemaWithComputedAttributesAndErrorMessages,
89
schemaWithNativeAndJSONLogicChecks,
910
schemaWithNonRequiredField,
1011
schemaWithTwoRules,
@@ -221,10 +222,31 @@ describe('jsonLogic: cross-values validations', () => {
221222
initialValues: { field_a: 2 },
222223
});
223224
const fieldB = fields.find((i) => i.name === 'field_b');
225+
expect(fieldB.description).toEqual(
226+
'This field is 2 times bigger than field_a with value of 4.'
227+
);
224228
expect(fieldB.default).toEqual(4);
225229
expect(fieldB.value).toEqual(4);
226230
handleValidation({ field_a: 4 });
227231
expect(fieldB.default).toEqual(8);
232+
expect(fieldB.label).toEqual('This is 8!');
233+
});
234+
235+
it('Derived errorMessages and statements work', () => {
236+
const { fields, handleValidation } = createHeadlessForm(
237+
schemaWithComputedAttributesAndErrorMessages,
238+
{ strictInputType: false }
239+
);
240+
const fieldB = fields.find((i) => i.name === 'field_b');
241+
expect(handleValidation({ field_a: 2, field_b: 0 }).formErrors).toEqual({
242+
field_b: 'Must be bigger than 4',
243+
});
244+
expect(handleValidation({ field_a: 2, field_b: 100 }).formErrors).toEqual({
245+
field_b: 'Must be smaller than 8',
246+
});
247+
expect(fieldB.minimum).toEqual(4);
248+
expect(fieldB.maximum).toEqual(8);
249+
expect(fieldB.statement).toEqual({ description: 'Must be bigger than 4 and smaller than 8' });
228250
});
229251
});
230252
});

0 commit comments

Comments
 (0)