@@ -2,19 +2,6 @@ import type { JsfObjectSchema, JsfSchema, NonBooleanJsfSchema } from '../types'
2
2
import type { Field } from './type'
3
3
import { buildFieldObject } from './object'
4
4
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
-
18
5
/**
19
6
* Get the JSON type for a field
20
7
* @param schema - The non boolean schema of the field
@@ -32,12 +19,82 @@ function getJsonType(schema: NonBooleanJsfSchema): string {
32
19
return 'text'
33
20
}
34
21
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
+
35
96
/**
36
97
* 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
41
98
*/
42
99
export function buildFieldSchema (
43
100
schema : JsfSchema ,
@@ -53,27 +110,52 @@ export function buildFieldSchema(
53
110
return buildFieldObject ( objectSchema , name , required )
54
111
}
55
112
56
- if ( Array . isArray ( schema . type ) ) {
113
+ if ( schema . type === 'array' ) {
57
114
throw new TypeError ( 'Array type is not yet supported' )
58
115
}
59
116
60
- const inputType = getInputType ( schema )
117
+ const presentation = schema [ 'x-jsf-presentation' ] || { }
118
+ const errorMessage = schema [ 'x-jsf-errorMessage' ]
61
119
62
- const { title : _title , ...spreadSchema } = schema
120
+ // Get input type from presentation or fallback to schema type
121
+ const inputType = presentation . inputType || 'text'
63
122
123
+ // Build field with all schema properties by default, excluding ones that need special handling
64
124
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
68
131
type : inputType ,
69
- jsonType : getJsonType ( schema ) ,
70
132
name,
133
+ inputType,
134
+ jsonType : getJsonType ( schema ) ,
71
135
required,
136
+ isVisible : true ,
137
+ ...( errorMessage && { errorMessage } ) ,
72
138
}
73
139
74
- if ( schema . title !== undefined ) {
140
+ if ( schema . title ) {
75
141
field . label = schema . title
76
142
}
77
143
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
+
78
160
return field
79
161
}
0 commit comments