@@ -105,6 +105,19 @@ function validateParams(p5, fn, lifecycles) {
105
105
return { funcName, funcClass } ;
106
106
}
107
107
108
+ function validBracketNesting ( type ) {
109
+ let level = 0 ;
110
+ for ( let i = 0 ; i < type . length ; i ++ ) {
111
+ if ( type [ i ] === '[' ) {
112
+ level ++ ;
113
+ } else if ( type [ i ] === ']' ) {
114
+ level -- ;
115
+ if ( level < 0 ) return false ;
116
+ }
117
+ }
118
+ return level === 0 ;
119
+ }
120
+
108
121
/**
109
122
* This is a helper function that generates Zod schemas for a function based on
110
123
* the parameter data from `docs/parameterData.json`.
@@ -139,11 +152,8 @@ function validateParams(p5, fn, lifecycles) {
139
152
}
140
153
141
154
// Returns a schema for a single type, i.e. z.boolean() for `boolean`.
142
- const generateTypeSchema = type => {
143
- if ( ! type ) return z . any ( ) ;
144
-
145
- const isArray = type . endsWith ( '[]' ) ;
146
- const baseType = isArray ? type . slice ( 0 , - 2 ) : type ;
155
+ const generateTypeSchema = baseType => {
156
+ if ( ! baseType ) return z . any ( ) ;
147
157
148
158
let typeSchema ;
149
159
@@ -162,7 +172,7 @@ function validateParams(p5, fn, lifecycles) {
162
172
typeSchema = z . function ( ) ;
163
173
}
164
174
// All p5 objects start with `p5` in the documentation, i.e. `p5.Camera`.
165
- else if ( baseType . startsWith ( 'p5' ) ) {
175
+ else if ( / ^ p 5 \. [ a - z A - Z 0 - 9 ] + $ / . exec ( baseType ) || baseType === 'p5' ) {
166
176
const className = baseType . substring ( baseType . indexOf ( '.' ) + 1 ) ;
167
177
typeSchema = z . instanceof ( p5Constructors [ className ] ) ;
168
178
}
@@ -171,7 +181,11 @@ function validateParams(p5, fn, lifecycles) {
171
181
typeSchema = schemaMap [ baseType ] ;
172
182
}
173
183
// Tuple types
174
- else if ( baseType . startsWith ( '[' ) && baseType . endsWith ( ']' ) ) {
184
+ else if (
185
+ baseType . startsWith ( '[' ) &&
186
+ baseType . endsWith ( ']' ) &&
187
+ validBracketNesting ( baseType . slice ( 1 , - 1 ) )
188
+ ) {
175
189
typeSchema = z . tuple (
176
190
baseType
177
191
. slice ( 1 , - 1 )
@@ -182,21 +196,7 @@ function validateParams(p5, fn, lifecycles) {
182
196
// JavaScript classes, e.g. Request
183
197
else if ( baseType . match ( / ^ [ A - Z ] / ) && baseType in window ) {
184
198
typeSchema = z . instanceof ( window [ baseType ] ) ;
185
- } else {
186
- throw new Error ( `Unsupported type '${ type } ' in parameter validation. Please report this issue.` ) ;
187
199
}
188
-
189
- return isArray ? z . array ( typeSchema ) : typeSchema ;
190
- } ;
191
-
192
- // Generate a schema for a single parameter. In the case where a parameter can
193
- // be of multiple types, `generateTypeSchema` is called for each type.
194
- const generateParamSchema = param => {
195
- const isOptional = param ?. endsWith ( '?' ) ;
196
- param = param ?. replace ( / \? $ / , '' ) ;
197
-
198
- let schema ;
199
-
200
200
// Generate a schema for a single parameter that can be of multiple
201
201
// types / constants, i.e. `String|Number|Array`.
202
202
//
@@ -206,15 +206,28 @@ function validateParams(p5, fn, lifecycles) {
206
206
// our constants sometimes have numeric or non-primitive values.
207
207
// 2) In some cases, the type can be constants or strings, making z.enum()
208
208
// insufficient for the use case.
209
- if ( param ? .includes ( '|' ) ) {
210
- const types = param . split ( '|' ) ;
211
- schema = z . union ( types
209
+ else if ( baseType . includes ( '|' ) && baseType . split ( '|' ) . every ( t => validBracketNesting ( t ) ) ) {
210
+ const types = baseType . split ( '|' ) ;
211
+ typeSchema = z . union ( types
212
212
. map ( t => generateTypeSchema ( t ) )
213
213
. filter ( s => s !== undefined ) ) ;
214
+ } else if ( baseType . endsWith ( '[]' ) ) {
215
+ typeSchema = z . array ( generateTypeSchema ( baseType . slice ( 0 , - 2 ) ) ) ;
214
216
} else {
215
- schema = generateTypeSchema ( param ) ;
217
+ throw new Error ( `Unsupported type ' ${ baseType } ' in parameter validation. Please report this issue.` ) ;
216
218
}
217
219
220
+ return typeSchema ;
221
+ } ;
222
+
223
+ // Generate a schema for a single parameter. In the case where a parameter can
224
+ // be of multiple types, `generateTypeSchema` is called for each type.
225
+ const generateParamSchema = param => {
226
+ const isOptional = param ?. endsWith ( '?' ) ;
227
+ param = param ?. replace ( / \? $ / , '' ) ;
228
+
229
+ let schema = generateTypeSchema ( param ) ;
230
+
218
231
return isOptional ? schema . optional ( ) : schema ;
219
232
} ;
220
233
0 commit comments