@@ -53,13 +53,13 @@ function getTemplateFilename(instrumentInternal: AnyUnilingualFormInstrument['in
5353namespace Zod3 {
5454 type ZodTypeName = Extract < `${z3 . ZodFirstPartyTypeKind } `, ( typeof ZOD_TYPE_NAMES ) [ number ] > ;
5555
56- type RequiredZodTypeName = Exclude < ZodTypeName , 'ZodEffects' | 'ZodOptional' > ;
56+ export type RequiredZodTypeName = Exclude < ZodTypeName , 'ZodEffects' | 'ZodOptional' > ;
5757
5858 type AnyZodTypeDef = z3 . ZodTypeDef & { typeName : ZodTypeName } ;
5959
6060 type ZodObjectArrayDef = z3 . ZodArrayDef & { type : z3 . AnyZodObject } ;
6161
62- type ZodTypeNameResult = {
62+ export type ZodTypeNameResult = {
6363 enumValues ?: readonly string [ ] ;
6464 isOptional : boolean ;
6565 multiKeys ?: string [ ] ;
@@ -178,7 +178,7 @@ namespace Zod3 {
178178 return isOptional ? `${ s } (optional)` : s ;
179179 }
180180
181- function generateSampleData ( {
181+ export function generateSampleData ( {
182182 enumValues,
183183 isOptional,
184184 multiKeys,
@@ -286,6 +286,112 @@ namespace Zod3 {
286286}
287287
288288namespace Zod4 {
289+ function jsonToZod ( givenType : unknown ) : Zod3 . RequiredZodTypeName {
290+ if ( typeof givenType === 'string' ) {
291+ switch ( givenType ) {
292+ case 'array' :
293+ return 'ZodArray' ;
294+ case 'boolean' :
295+ return 'ZodBoolean' ;
296+ case 'date' :
297+ return 'ZodDate' ;
298+ case 'enum' :
299+ return 'ZodEnum' ;
300+ case 'number' :
301+ return 'ZodNumber' ;
302+ case 'set' :
303+ return 'ZodSet' ;
304+ case 'string' :
305+ return 'ZodString' ;
306+ default :
307+ }
308+ }
309+ throw new Error ( "Failed to interpret json value / Échec de l'interprétation de la valeur json" ) ;
310+ }
311+
312+ function parseJSONSchema ( jsonInstrumentSchema : z4 . core . JSONSchema . ObjectSchema ) {
313+ // TODO - these could actually not exist
314+ // prettier-ignore
315+ if ( ! ( jsonInstrumentSchema . properties && jsonInstrumentSchema . required && Array . isArray ( jsonInstrumentSchema . required ) ) ) {
316+ throw new UploadError ( {
317+ en : "Failed to interpret JSON schema" ,
318+ fr : "Échec de l'interprétation du schéma JSON"
319+ } ) ;
320+ }
321+
322+ const jsonColumnNames = Object . keys ( jsonInstrumentSchema . properties ) ;
323+
324+ const jsonCSVColumns = INTERNAL_HEADERS . concat ( jsonColumnNames ) ;
325+ const jsonSampleData = [ ...INTERNAL_HEADERS_SAMPLE_DATA ] ;
326+
327+ for ( const col of jsonColumnNames ) {
328+ let optional = true ;
329+ // let data: ZodTypeNameResult;
330+ if ( jsonInstrumentSchema . required . includes ( col ) ) {
331+ optional = false ;
332+ }
333+
334+ let data : Zod3 . ZodTypeNameResult ;
335+ const propertySchema = jsonInstrumentSchema . properties [ col ] as z4 . core . JSONSchema . Schema ;
336+
337+ if ( propertySchema . type === 'array' ) {
338+ if ( ! propertySchema . items ) {
339+ throw new UploadError ( {
340+ en : "Property 'items' must be defined for array schema"
341+ } ) ;
342+ } else if ( Array . isArray ( propertySchema . items ) ) {
343+ throw new UploadError ( {
344+ en : "Property 'items' must not be array: only JSON schema 2020 or later is supported"
345+ } ) ;
346+ }
347+ const itemsSchema = propertySchema . items as z4 . core . JSONSchema . ObjectSchema ;
348+ const keys = Object . keys ( itemsSchema . properties ! ) ;
349+ const values = Object . values ( itemsSchema . properties ! ) ;
350+ const multiVals : Zod3 . ZodTypeNameResult [ ] = [ ] ;
351+
352+ let i = 0 ;
353+
354+ for ( const val of values ) {
355+ if ( val . type && Array . isArray ( itemsSchema . required ) && keys [ i ] ) {
356+ // optional is false if the key is included in the required items
357+ multiVals . push ( {
358+ isOptional : ! itemsSchema . required . includes ( keys [ i ] ! ) ,
359+ typeName : jsonToZod ( val . type )
360+ } ) ;
361+ i ++ ;
362+ }
363+ }
364+ data = {
365+ isOptional : optional ,
366+ multiKeys : keys ,
367+ multiValues : multiVals ,
368+ typeName : 'ZodObject'
369+ } ;
370+ } else if ( propertySchema . enum ) {
371+ data = {
372+ enumValues : propertySchema . enum as readonly string [ ] ,
373+ isOptional : optional ,
374+ typeName : 'ZodEnum'
375+ } ;
376+ } else if ( jsonToZod ( propertySchema . type ) ) {
377+ data = {
378+ isOptional : optional ,
379+ typeName : jsonToZod ( propertySchema . type )
380+ } ;
381+ } else {
382+ throw new UploadError ( {
383+ en : 'Failed to interpret JSON value from schema' ,
384+ fr : "Échec de l'interprétation de la valeur JSON du schéma"
385+ } ) ;
386+ }
387+ jsonSampleData . push ( Zod3 . generateSampleData ( data ) ) ;
388+ }
389+
390+ const zod4TemplateData = unparse ( [ jsonCSVColumns , jsonSampleData ] ) ;
391+
392+ return zod4TemplateData ;
393+ }
394+
289395 export function createUploadTemplateCSV (
290396 instrumentSchema : z4 . ZodType < FormTypes . Data > ,
291397 instrumentInternal : AnyUnilingualFormInstrument [ 'internal' ]
@@ -296,9 +402,9 @@ namespace Zod4 {
296402 en : `Expected form validation schema to be of type object, got ${ jsonInstrumentSchema . type } `
297403 } ) ;
298404 }
299- const zod4TemplateData = '' ; // zod4Helper(jsonInstrumentSchema);
405+
300406 return {
301- content : zod4TemplateData ,
407+ content : parseJSONSchema ( jsonInstrumentSchema ) ,
302408 filename : getTemplateFilename ( instrumentInternal )
303409 } ;
304410 }
0 commit comments