@@ -14,11 +14,18 @@ export function make(schema: unknown, options?: {
1414 readonly definitions ?: Schema . JsonSchema . Definitions | undefined
1515} ) : string {
1616 const definitions = options ?. definitions ?? { }
17- return go ( schema , { definitions } )
17+ return recur ( schema , { definitions } )
1818}
1919
2020const Never = "Schema.Never"
2121const Unknown = "Schema.Unknown"
22+ const Null = "Schema.Null"
23+ const String = "Schema.String"
24+ const Number = "Schema.Number"
25+ const Int = "Schema.Int"
26+ const Boolean = "Schema.Boolean"
27+ const UnknownRecord = "Schema.Record(Schema.String, Schema.Unknown)"
28+ const UnknownArray = "Schema.Array(Schema.Unknown)"
2229
2330function Union ( members : ReadonlyArray < string > , mode : "anyOf" | "oneOf" ) : string {
2431 return `Schema.Union([${ members . join ( ", " ) } ]${ mode === "oneOf" ? ", { mode: \"oneOf\" }" : "" } )`
@@ -28,7 +35,7 @@ interface GoOptions {
2835 readonly definitions : Schema . JsonSchema . Definitions
2936}
3037
31- function go ( schema : unknown , options : GoOptions ) : string {
38+ function recur ( schema : unknown , options : GoOptions ) : string {
3239 if ( typeof schema === "boolean" ) {
3340 return schema ? Unknown : Never
3441 }
@@ -94,42 +101,97 @@ function getAnnotationsAndChecks(schema: Record<string, unknown>, options: GoOpt
94101 return out
95102}
96103
97- function baseByType ( type : unknown ) : string {
98- if ( typeof type === "string" ) {
99- switch ( type ) {
100- case "null" :
101- return "Schema.Null"
102- case "string" :
103- return "Schema.String"
104- case "number" :
105- return "Schema.Number"
106- case "integer" :
107- return "Schema.Int"
108- case "boolean" :
109- return "Schema.Boolean"
110- case "object" :
111- return "Schema.Struct({})"
112- case "array" :
104+ type Type = "null" | "string" | "number" | "integer" | "boolean" | "object" | "array"
105+
106+ type WithType = {
107+ readonly type : Type
108+ [ x : string ] : unknown
109+ }
110+
111+ function isWithType ( schema : Record < string , unknown > ) : schema is WithType {
112+ return schema . type === "null"
113+ || schema . type === "string"
114+ || schema . type === "number"
115+ || schema . type === "integer"
116+ || schema . type === "boolean"
117+ || schema . type === "object"
118+ || schema . type === "array"
119+ }
120+
121+ function byType ( type : Type ) : string {
122+ switch ( type ) {
123+ case "null" :
124+ return Null
125+ case "string" :
126+ return String
127+ case "number" :
128+ return Number
129+ case "integer" :
130+ return Int
131+ case "boolean" :
132+ return Boolean
133+ case "object" :
134+ return UnknownRecord
135+ case "array" :
136+ return UnknownArray
137+ }
138+ }
139+
140+ function byWithType ( schema : WithType , options : GoOptions ) : string {
141+ switch ( schema . type ) {
142+ case "null" :
143+ return Null
144+ case "string" :
145+ return String
146+ case "number" :
147+ return Number
148+ case "integer" :
149+ return Int
150+ case "boolean" :
151+ return Boolean
152+ case "object" : {
153+ if ( ! isObject ( schema . properties ) ) {
154+ return UnknownRecord
155+ }
156+ const required = Array . isArray ( schema . required ) ? schema . required : [ ]
157+ const properties = schema . properties
158+ return `Schema.Struct({ ${
159+ Object . entries ( properties ) . map ( ( [ k , v ] ) => {
160+ const value = recur ( v , options )
161+ if ( required . includes ( k ) ) {
162+ return `${ k } : ${ value } `
163+ } else {
164+ return `${ k } : Schema.optionalKey(${ value } )`
165+ }
166+ } ) . join ( ", " )
167+ } })`
168+ }
169+ case "array" : {
170+ if ( Object . keys ( schema ) . length === 1 ) {
171+ return UnknownArray
172+ }
173+ if ( schema . items === false ) {
113174 return "Schema.Tuple([])"
175+ }
176+ return "TODO"
114177 }
115178 }
116- return Unknown
117179}
118180
119181function base ( schema : Record < string , unknown > , options : GoOptions ) : string {
120- if ( "type" in schema ) {
121- if ( Array . isArray ( schema . type ) ) {
122- return Union ( schema . type . map ( baseByType ) , "anyOf" )
123- }
124- return baseByType ( schema . type )
182+ if ( Array . isArray ( schema . type ) ) {
183+ return Union ( schema . type . map ( byType ) , "anyOf" )
184+ }
185+ if ( isWithType ( schema ) ) {
186+ return byWithType ( schema , options )
125187 }
126188 if ( Array . isArray ( schema . anyOf ) ) {
127189 if ( schema . anyOf . length === 0 ) return Never
128- return Union ( schema . anyOf . map ( ( schema ) => go ( schema , options ) ) , "anyOf" )
190+ return Union ( schema . anyOf . map ( ( schema ) => recur ( schema , options ) ) , "anyOf" )
129191 }
130192 if ( Array . isArray ( schema . oneOf ) ) {
131193 if ( schema . oneOf . length === 0 ) return Never
132- return Union ( schema . oneOf . map ( ( schema ) => go ( schema , options ) ) , "oneOf" )
194+ return Union ( schema . oneOf . map ( ( schema ) => recur ( schema , options ) ) , "oneOf" )
133195 }
134196 if ( isObject ( schema . not ) && Object . keys ( schema . not ) . length === 0 ) {
135197 return Never
@@ -143,7 +205,7 @@ function base(schema: Record<string, unknown>, options: GoOptions): string {
143205 if ( definition === undefined ) {
144206 throw new Error ( `Definition not found for $ref: ${ schema . $ref } ` )
145207 }
146- return go ( definition , options ) + `.annotate({ identifier: "${ identifier } " })`
208+ return recur ( definition , options ) + `.annotate({ identifier: "${ identifier } " })`
147209 }
148210 return Unknown
149211}
0 commit comments