Skip to content

Commit cd12d91

Browse files
dragidaviddenatys
authored andcommitted
Fix handleValidation for undefined fieldsets
1 parent 07434e3 commit cd12d91

File tree

15 files changed

+461
-127
lines changed

15 files changed

+461
-127
lines changed

next/src/field/object.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function buildFieldObject(schema: JsfObjectSchema, name: string, required
3131
name: schema.title || name,
3232
required,
3333
fields: orderedFields,
34+
isVisible: true,
3435
}
3536

3637
if (schema.title !== undefined) {

next/src/field/schema.ts

Lines changed: 107 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,6 @@ import type { JsfObjectSchema, JsfSchema, NonBooleanJsfSchema } from '../types'
22
import type { Field } from './type'
33
import { buildFieldObject } from './object'
44

5-
/**
6-
* Get the input type for a field
7-
* @param schema - The schema of the field
8-
* @returns The input type for the field, based schema type. Default to 'text'
9-
*/
10-
function getInputType(schema: NonBooleanJsfSchema): string {
11-
if (schema.type === 'string') {
12-
return 'text'
13-
}
14-
15-
return 'text'
16-
}
17-
185
/**
196
* Get the JSON type for a field
207
* @param schema - The non boolean schema of the field
@@ -32,12 +19,82 @@ function getJsonType(schema: NonBooleanJsfSchema): string {
3219
return 'text'
3320
}
3421

22+
/**
23+
* Convert options to the required format
24+
* This is used when we have a oneOf or anyOf schema property
25+
*/
26+
function convertToOptions(nodeOptions: JsfSchema[]): Array<{
27+
label: string
28+
value: unknown
29+
[key: string]: unknown
30+
}> {
31+
return nodeOptions
32+
.filter((option): option is NonBooleanJsfSchema =>
33+
option !== null && typeof option === 'object')
34+
.map((schemaOption) => {
35+
const title = schemaOption.title
36+
const value = schemaOption.const
37+
const presentation = schemaOption['x-jsf-presentation']
38+
const meta = presentation?.meta
39+
40+
const result: {
41+
label: string
42+
value: unknown
43+
[key: string]: unknown
44+
} = {
45+
label: title || '',
46+
value,
47+
}
48+
49+
// Add meta if it exists
50+
if (meta) {
51+
result.meta = meta
52+
}
53+
54+
// Add other properties, without known ones we already handled above
55+
const { title: _, const: __, 'x-jsf-presentation': ___, ...rest } = schemaOption
56+
57+
return { ...result, ...rest }
58+
})
59+
}
60+
61+
/**
62+
* Get field options from schema
63+
*/
64+
function getFieldOptions(schema: NonBooleanJsfSchema) {
65+
// Handle oneOf or radio input type
66+
if (schema.oneOf) {
67+
return convertToOptions(schema.oneOf || [])
68+
}
69+
70+
// Handle items.anyOf (for multiple select)
71+
if (schema.items?.anyOf) {
72+
return convertToOptions(schema.items.anyOf)
73+
}
74+
75+
// Handle anyOf
76+
if (schema.anyOf) {
77+
return convertToOptions(schema.anyOf)
78+
}
79+
80+
return null
81+
}
82+
83+
/**
84+
* List of schema properties that should be excluded from the final field or handled specially
85+
*/
86+
const excludedSchemaProps = [
87+
'title', // Transformed to 'label'
88+
'type', // Handled separately
89+
'x-jsf-errorMessage', // Handled separately
90+
'x-jsf-presentation', // Handled separately
91+
'oneOf', // Transformed to 'options'
92+
'anyOf', // Transformed to 'options'
93+
'items', // Handled specially for arrays
94+
]
95+
3596
/**
3697
* Build a field from any schema
37-
* @param schema - The schema of the field
38-
* @param name - The name of the field, used if the schema has no title
39-
* @param required - Whether the field is required
40-
* @returns The field
4198
*/
4299
export function buildFieldSchema(
43100
schema: JsfSchema,
@@ -53,27 +110,52 @@ export function buildFieldSchema(
53110
return buildFieldObject(objectSchema, name, required)
54111
}
55112

56-
if (Array.isArray(schema.type)) {
113+
if (schema.type === 'array') {
57114
throw new TypeError('Array type is not yet supported')
58115
}
59116

60-
const inputType = getInputType(schema)
117+
const presentation = schema['x-jsf-presentation'] || {}
118+
const errorMessage = schema['x-jsf-errorMessage']
61119

62-
const { title: _title, ...spreadSchema } = schema
120+
// Get input type from presentation or fallback to schema type
121+
const inputType = presentation.inputType || 'text'
63122

123+
// Build field with all schema properties by default, excluding ones that need special handling
64124
const field: Field = {
65-
...spreadSchema,
66-
...schema['x-jsf-presentation'],
67-
inputType,
125+
// Spread all schema properties except excluded ones
126+
...Object.entries(schema)
127+
.filter(([key]) => !excludedSchemaProps.includes(key))
128+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
129+
130+
// Add required field properties
68131
type: inputType,
69-
jsonType: getJsonType(schema),
70132
name,
133+
inputType,
134+
jsonType: getJsonType(schema),
71135
required,
136+
isVisible: true,
137+
...(errorMessage && { errorMessage }),
72138
}
73139

74-
if (schema.title !== undefined) {
140+
if (schema.title) {
75141
field.label = schema.title
76142
}
77143

144+
// Spread presentation properties to the root level
145+
if (Object.keys(presentation).length > 0) {
146+
Object.entries(presentation).forEach(([key, value]) => {
147+
// inputType is already handled above
148+
if (key !== 'inputType') {
149+
field[key] = value
150+
}
151+
})
152+
}
153+
154+
// Handle options
155+
const options = getFieldOptions(schema)
156+
if (options) {
157+
field.options = options
158+
}
159+
78160
return field
79161
}

next/src/field/type.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
/**
22
* WIP type for UI field output that allows for all `x-jsf-presentation` properties to be splatted
3+
* TODO/QUESTION: what are the required fields for a field? what are the things we want to deprecate, if any?
34
*/
4-
export type Field = {
5+
export interface Field {
56
name: string
67
label?: string
8+
description?: string
79
fields?: Field[]
810
type: string
911
inputType: string
1012
required: boolean
1113
jsonType: string
14+
isVisible: boolean
1215
accept?: string
13-
description?: string
14-
maxFileSize?: number
16+
errorMessage?: Record<string, string>
17+
computedAttributes?: Record<string, unknown>
1518
minDate?: string
1619
maxDate?: string
17-
} & {
20+
maxLength?: number
21+
maxFileSize?: number
22+
format?: string
23+
anyOf?: unknown[]
24+
options?: unknown[]
25+
26+
// Allow additional properties from x-jsf-presentation (e.g. meta from oneOf/anyOf)
1827
[key: string]: unknown
1928
}

0 commit comments

Comments
 (0)