Skip to content

Commit 1b6cc82

Browse files
chore: address PR comments
fix: provide empty fields for hidden fieldsets/group-arrays chore: update test feat: add 'value' fallback when const is not present for const validation fix: delete conditional branches after processing them chore: add comment
1 parent 55e3475 commit 1b6cc82

File tree

7 files changed

+89
-3
lines changed

7 files changed

+89
-3
lines changed

next/src/field/schema.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,18 @@ export function buildFieldSchema({
349349
}: BuildFieldSchemaParams): Field | null {
350350
// If schema is boolean false, return a field with isVisible=false
351351
if (schema === false) {
352-
// If the schema is false, we use the original schema to get the input type
352+
// If the schema is false (hidden field), we use the original schema to get the input type
353353
const inputType = getInputType(type, name, originalSchema, strictInputType)
354+
const inputHasInnerFields = ['fieldset', 'group-array'].includes(inputType)
355+
354356
return {
355357
type: inputType,
356358
name,
357359
inputType,
358360
jsonType: 'boolean',
359361
required,
360362
isVisible: false,
363+
...(inputHasInnerFields && { fields: [] }),
361364
}
362365
}
363366

next/src/mutations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,14 @@ function applySchemaRules(
108108
// If the rule matches, process the then branch
109109
if (matches && rule.then) {
110110
processBranch(schema, values, rule.then, options, jsonLogicContext)
111+
// Delete the then branch to avoid processing it again when validating the schema
112+
delete rule.then
111113
}
112114
// If the rule doesn't match, process the else branch
113115
else if (!matches && rule.else) {
114116
processBranch(schema, values, rule.else, options, jsonLogicContext)
117+
// Delete the else branch to avoid processing it again when validating the schema
118+
delete rule.else
115119
}
116120
}
117121

next/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export type JsfSchema = JSONSchema & {
6262
'if'?: JsfSchema
6363
'then'?: JsfSchema
6464
'else'?: JsfSchema
65+
// while value is not part of the spec, we're keeping it for v0 backwards compatibility
66+
'value'?: SchemaValue
6567
// Note: if we don't have this property here, when inspecting any recursive
6668
// schema (like an if inside another schema), the required property won't be
6769
// present in the type

next/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export function convertKBToMB(kb: number): number {
5252
return Number.parseFloat(mb.toFixed(2)) // Keep 2 decimal places
5353
}
5454

55-
// Keys to skip when merging schema objects
55+
// When merging schemas, we should skip merging the if/then/else properties as we could be creating wrong conditions
5656
const KEYS_TO_SKIP = ['if', 'then', 'else']
5757

5858
function isObject(value: any): boolean {

next/src/validation/const.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function validateConst(
1919
schema: NonBooleanJsfSchema,
2020
path: ValidationErrorPath = [],
2121
): ValidationError[] {
22-
const constValue = schema.const
22+
const constValue = typeof schema.const !== 'undefined' ? schema.const : schema.value
2323

2424
if (constValue === undefined) {
2525
return []

next/test/fields.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ describe('fields', () => {
9999
inputType: 'fieldset',
100100
type: 'fieldset',
101101
jsonType: 'boolean',
102+
fields: [],
102103
name: 'root',
103104
required: true,
104105
isVisible: false,

next/test/validation/const.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { NonBooleanJsfSchema } from '../../src/types'
2+
import { describe, expect, it } from '@jest/globals'
3+
import { validateConst } from '../../src/validation/const'
4+
5+
describe('const schema validation', () => {
6+
it('should return empty array when const value matches', () => {
7+
const schema: NonBooleanJsfSchema = { const: 42 }
8+
const value = 42
9+
expect(validateConst(value, schema)).toEqual([])
10+
})
11+
12+
it('should return error when const value does not match', () => {
13+
const schema: NonBooleanJsfSchema = { const: 42 }
14+
const value = 43
15+
const result = validateConst(value, schema)
16+
expect(result).toHaveLength(1)
17+
expect(result[0]).toEqual({
18+
path: [],
19+
validation: 'const',
20+
schema,
21+
value: 43,
22+
})
23+
})
24+
25+
it('should handle nested objects with deep equality', () => {
26+
const schema: NonBooleanJsfSchema = {
27+
const: { foo: { bar: 42 } },
28+
}
29+
const value = { foo: { bar: 42 } }
30+
expect(validateConst(value, schema)).toEqual([])
31+
})
32+
33+
it('should handle arrays with deep equality', () => {
34+
const schema: NonBooleanJsfSchema = {
35+
const: [1, 2, { foo: 'bar' }],
36+
}
37+
const value = [1, 2, { foo: 'bar' }]
38+
expect(validateConst(value, schema)).toEqual([])
39+
})
40+
41+
it('should return empty array when const is not present', () => {
42+
const schema: NonBooleanJsfSchema = {}
43+
const value = 42
44+
expect(validateConst(value, schema)).toEqual([])
45+
})
46+
47+
it('should handle schema.value as fallback for const', () => {
48+
const schema: NonBooleanJsfSchema = { value: 42 }
49+
const input = 42
50+
expect(validateConst(input, schema)).toEqual([])
51+
})
52+
53+
it('should handle different types correctly', () => {
54+
const testCases = [
55+
{ schema: { const: 'string' }, value: 'string', shouldPass: true },
56+
{ schema: { const: true }, value: false, shouldPass: false },
57+
{ schema: { const: null }, value: null, shouldPass: true },
58+
{ schema: { const: 0 }, value: '0', shouldPass: false },
59+
{ schema: { const: [] }, value: [], shouldPass: true },
60+
{ schema: { const: {} }, value: {}, shouldPass: true },
61+
]
62+
63+
testCases.forEach(({ schema, value, shouldPass }) => {
64+
const result = validateConst(value, schema as NonBooleanJsfSchema)
65+
expect(result.length).toBe(shouldPass ? 0 : 1)
66+
})
67+
})
68+
69+
it('should handle path parameter correctly', () => {
70+
const schema: NonBooleanJsfSchema = { const: 42 }
71+
const value = 43
72+
const path = ['foo', 'bar']
73+
const result = validateConst(value, schema, path)
74+
expect(result[0].path).toEqual(path)
75+
})
76+
})

0 commit comments

Comments
 (0)