@@ -10,17 +10,47 @@ export function parse(
10
10
schema : JSONSchema ,
11
11
name ?: string ,
12
12
rootSchema : JSONSchema = schema ,
13
- isRequired = false
13
+ isRequired = false ,
14
+ processed = new Map < JSONSchema , AST > ( )
15
+ ) : AST {
16
+ log ( whiteBright . bgBlue ( 'parser' ) , schema , '<-' + typeOfSchema ( schema ) , processed . has ( schema ) ? '(CACHED)' : '' )
17
+ if ( processed . has ( schema ) ) {
18
+ return processed . get ( schema ) !
19
+ }
20
+ const ast = parseSchema ( schema , name , rootSchema , isRequired , processed )
21
+ processed . set ( schema , ast )
22
+ return ast
23
+ }
24
+
25
+ function parseSchema (
26
+ schema : JSONSchema ,
27
+ name : string | undefined ,
28
+ rootSchema : JSONSchema ,
29
+ isRequired : boolean ,
30
+ processed : Map < JSONSchema , AST >
14
31
) : AST {
15
- log ( whiteBright . bgBlue ( 'parser' ) , JSON . stringify ( schema , null , 2 ) , '<-' + typeOfSchema ( schema ) , name )
16
32
switch ( typeOfSchema ( schema ) ) {
17
33
case 'ALL_OF' :
18
34
// TODO: support schema.properties
19
- return { comment : schema . description , name, isRequired, params : schema . allOf ! . map ( _ => parse ( _ ) ) , standaloneName : schema . title , type : 'INTERSECTION' }
35
+ return {
36
+ comment : schema . description ,
37
+ isRequired,
38
+ name,
39
+ get params ( ) { return schema . allOf ! . map ( _ => parse ( _ , undefined , rootSchema , undefined , processed ) ) } ,
40
+ standaloneName : schema . title ,
41
+ type : 'INTERSECTION'
42
+ }
20
43
case 'ANY' :
21
44
return { comment : schema . description , name, isRequired, standaloneName : schema . title , type : 'ANY' }
22
45
case 'ANY_OF' :
23
- return { comment : schema . description , name, isRequired, params : schema . anyOf ! . map ( _ => parse ( _ ) ) , standaloneName : schema . title , type : 'UNION' }
46
+ return {
47
+ comment : schema . description ,
48
+ isRequired,
49
+ name,
50
+ get params ( ) { return schema . anyOf ! . map ( _ => parse ( _ , undefined , rootSchema , undefined , processed ) ) } ,
51
+ standaloneName : schema . title ,
52
+ type : 'UNION'
53
+ }
24
54
case 'BOOLEAN' :
25
55
return { comment : schema . description , name, isRequired, standaloneName : schema . title , type : 'BOOLEAN' }
26
56
case 'LITERAL' :
@@ -30,7 +60,7 @@ export function parse(
30
60
comment : schema . description ,
31
61
isRequired,
32
62
name,
33
- params : schema . enum ! . map ( ( _ , n ) => parse ( _ , schema . tsEnumNames ! [ n ] , rootSchema ) as ASTWithName ) ,
63
+ get params ( ) { return schema . enum ! . map ( ( _ , n ) => parse ( _ , schema . tsEnumNames ! [ n ] , rootSchema , undefined , processed ) as ASTWithName ) } ,
34
64
standaloneName : name ! ,
35
65
type : 'ENUM'
36
66
}
@@ -39,7 +69,7 @@ export function parse(
39
69
comment : schema . description ,
40
70
isRequired,
41
71
name,
42
- params : parseSchemaSchema ( schema as SchemaSchema , rootSchema ) ,
72
+ get params ( ) { return parseSchemaSchema ( schema as SchemaSchema , rootSchema , processed ) } ,
43
73
standaloneName : computeSchemaName ( schema as SchemaSchema , name ) ,
44
74
type : 'INTERFACE'
45
75
}
@@ -50,21 +80,35 @@ export function parse(
50
80
case 'OBJECT' :
51
81
return { comment : schema . description , name, isRequired, standaloneName : schema . title , type : 'OBJECT' }
52
82
case 'REFERENCE' :
53
- return parse ( resolveReference ( schema . $ref as string , rootSchema ) , '' , schema )
83
+ return parse ( resolveReference ( schema . $ref as string , rootSchema ) , '' , schema , undefined , processed )
54
84
case 'STRING' :
55
85
return { comment : schema . description , name, isRequired, standaloneName : schema . title , type : 'STRING' }
56
86
case 'TYPED_ARRAY' :
57
87
if ( Array . isArray ( schema . items ) ) {
58
- return { comment : schema . description , name, isRequired, params : schema . items . map ( _ => parse ( _ ) ) , standaloneName : schema . title , type : 'TUPLE' }
88
+ return {
89
+ comment : schema . description ,
90
+ name,
91
+ isRequired,
92
+ get params ( ) { return schema . items . map ( _ => parse ( _ , undefined , rootSchema , undefined , processed ) ) } ,
93
+ standaloneName : schema . title ,
94
+ type : 'TUPLE'
95
+ }
59
96
} else {
60
- return { comment : schema . description , name, isRequired, params : parse ( schema . items ! ) , standaloneName : schema . title , type : 'ARRAY' }
97
+ return {
98
+ comment : schema . description ,
99
+ name,
100
+ isRequired,
101
+ get params ( ) { return parse ( schema . items ! , undefined , rootSchema , undefined , processed ) } ,
102
+ standaloneName : schema . title ,
103
+ type : 'ARRAY'
104
+ }
61
105
}
62
106
case 'UNION' :
63
107
return {
64
108
comment : schema . description ,
65
109
name,
66
110
isRequired,
67
- params : ( schema . type as JSONSchema4TypeName [ ] ) . map ( _ => parse ( { required : [ ] , type : _ } ) ) ,
111
+ get params ( ) { return ( schema . type as JSONSchema4TypeName [ ] ) . map ( _ => parse ( { required : [ ] , type : _ } , undefined , rootSchema , undefined , processed ) ) } ,
68
112
standaloneName : schema . title ,
69
113
type : 'UNION'
70
114
}
@@ -73,7 +117,7 @@ export function parse(
73
117
comment : schema . description ,
74
118
isRequired,
75
119
name,
76
- params : schema . enum ! . map ( _ => parse ( _ ) ) ,
120
+ get params ( ) { return schema . enum ! . map ( _ => parse ( _ , undefined , rootSchema , undefined , processed ) ) } ,
77
121
standaloneName : schema . title ,
78
122
type : 'UNION'
79
123
}
@@ -82,12 +126,19 @@ export function parse(
82
126
comment : schema . description ,
83
127
isRequired,
84
128
name,
85
- params : parseSchemaSchema ( schema as SchemaSchema , rootSchema ) ,
129
+ get params ( ) { return parseSchemaSchema ( schema as SchemaSchema , rootSchema , processed ) } ,
86
130
standaloneName : computeSchemaName ( schema as SchemaSchema , name ) ,
87
131
type : 'INTERFACE'
88
132
}
89
133
case 'UNTYPED_ARRAY' :
90
- return { comment : schema . description , name, isRequired, params : T_ANY , standaloneName : schema . title , type : 'ARRAY' }
134
+ return {
135
+ comment : schema . description ,
136
+ name,
137
+ isRequired,
138
+ params : T_ANY ,
139
+ standaloneName : schema . title ,
140
+ type : 'ARRAY'
141
+ }
91
142
}
92
143
}
93
144
@@ -106,10 +157,11 @@ function computeSchemaName(
106
157
*/
107
158
function parseSchemaSchema (
108
159
schema : SchemaSchema ,
109
- rootSchema : JSONSchema
160
+ rootSchema : JSONSchema ,
161
+ processed : Map < JSONSchema , AST >
110
162
) : ASTWithName [ ] {
111
163
const asts = map ( schema . properties , ( value , key ) =>
112
- parse ( value , key , rootSchema , ( schema . required || [ ] ) . includes ( key ! ) ) as ASTWithName
164
+ parse ( value , key , rootSchema , ( schema . required || [ ] ) . includes ( key ! ) , processed ) as ASTWithName
113
165
)
114
166
// handle additionalProperties
115
167
switch ( schema . additionalProperties ) {
@@ -123,7 +175,7 @@ function parseSchemaSchema(
123
175
// pass "true" as the last param because in TS, properties
124
176
// defined via index signatures are already optional
125
177
default :
126
- return asts . concat ( parse ( schema . additionalProperties , '[k: string]' , rootSchema , true ) as ASTWithName )
178
+ return asts . concat ( parse ( schema . additionalProperties , '[k: string]' , rootSchema , true , processed ) as ASTWithName )
127
179
}
128
180
}
129
181
0 commit comments