@@ -67,6 +67,10 @@ export class SourceTypedParser extends SourceParser {
67
67
}
68
68
69
69
const typedProgram : TypedES . Program = ast . program as TypedES . Program
70
+ if ( context . prelude !== programStr ) {
71
+ // Check for any declaration only if the program is not the prelude
72
+ checkForAnyDeclaration ( typedProgram , context )
73
+ }
70
74
const typedCheckedProgram : Program = checkForTypeErrors ( typedProgram , context )
71
75
transformBabelASTToESTreeCompliantAST ( typedCheckedProgram )
72
76
@@ -77,3 +81,175 @@ export class SourceTypedParser extends SourceParser {
77
81
return 'SourceTypedParser'
78
82
}
79
83
}
84
+
85
+ function checkForAnyDeclaration ( program : TypedES . Program , context : Context ) {
86
+ function parseConfigOption ( option : string | undefined ) {
87
+ return option === 'true' || option === undefined
88
+ }
89
+
90
+ const config = {
91
+ allowAnyInVariables : parseConfigOption ( context . languageOptions [ 'typedAllowAnyInVariables' ] ) ,
92
+ allowAnyInParameters : parseConfigOption ( context . languageOptions [ 'typedAllowAnyInParameters' ] ) ,
93
+ allowAnyInReturnType : parseConfigOption ( context . languageOptions [ 'typedAllowAnyInReturnType' ] ) ,
94
+ allowAnyInTypeAnnotationParameters : parseConfigOption (
95
+ context . languageOptions [ 'typedAllowAnyInTypeAnnotationParameters' ]
96
+ ) ,
97
+ allowAnyInTypeAnnotationReturnType : parseConfigOption (
98
+ context . languageOptions [ 'typedAllowAnyInTypeAnnotationReturnType' ]
99
+ )
100
+ }
101
+
102
+ function pushAnyUsageError ( message : string , node : TypedES . Node ) {
103
+ if ( node . loc ) {
104
+ context . errors . push ( new FatalSyntaxError ( node . loc , message ) )
105
+ }
106
+ }
107
+
108
+ function isAnyType ( node : TypedES . TSTypeAnnotation | undefined ) {
109
+ return node ?. typeAnnotation ?. type === 'TSAnyKeyword' || node ?. typeAnnotation === undefined
110
+ }
111
+
112
+ function checkNode ( node : TypedES . Node ) {
113
+ switch ( node . type ) {
114
+ case 'VariableDeclaration' : {
115
+ node . declarations . forEach ( decl => {
116
+ const tsType = ( decl as any ) . id ?. typeAnnotation
117
+ if ( ! config . allowAnyInVariables && isAnyType ( tsType ) ) {
118
+ pushAnyUsageError ( 'Usage of "any" in variable declaration is not allowed.' , node )
119
+ }
120
+ if ( decl . init ) {
121
+ // check for lambdas
122
+ checkNode ( decl . init )
123
+ }
124
+ } )
125
+ break
126
+ }
127
+ case 'FunctionDeclaration' : {
128
+ if ( ! config . allowAnyInParameters || ! config . allowAnyInReturnType ) {
129
+ const func = node as any
130
+ // Check parameters
131
+ func . params ?. forEach ( ( param : any ) => {
132
+ if ( ! config . allowAnyInParameters && isAnyType ( param . typeAnnotation ) ) {
133
+ pushAnyUsageError ( 'Usage of "any" in function parameter is not allowed.' , param )
134
+ }
135
+ } )
136
+ // Check return type
137
+ if ( ! config . allowAnyInReturnType && isAnyType ( func . returnType ) ) {
138
+ pushAnyUsageError ( 'Usage of "any" in function return type is not allowed.' , node )
139
+ }
140
+ checkNode ( node . body )
141
+ }
142
+ break
143
+ }
144
+ case 'ArrowFunctionExpression' : {
145
+ if ( ! config . allowAnyInParameters || ! config . allowAnyInReturnType ) {
146
+ const arrow = node as any
147
+ // Check parameters
148
+ arrow . params ?. forEach ( ( param : any ) => {
149
+ if ( ! config . allowAnyInParameters && isAnyType ( param . typeAnnotation ) ) {
150
+ pushAnyUsageError ( 'Usage of "any" in arrow function parameter is not allowed.' , param )
151
+ }
152
+ } )
153
+ // Recursively check return type if present
154
+ if ( ! config . allowAnyInReturnType && isAnyType ( arrow . returnType ) ) {
155
+ pushAnyUsageError ( 'Usage of "any" in arrow function return type is not allowed.' , arrow )
156
+ }
157
+ if (
158
+ ! config . allowAnyInReturnType &&
159
+ arrow . params ?. some ( ( param : any ) => isAnyType ( param . typeAnnotation ) )
160
+ ) {
161
+ pushAnyUsageError ( 'Usage of "any" in arrow function return type is not allowed.' , arrow )
162
+ }
163
+ checkNode ( node . body )
164
+ }
165
+ break
166
+ }
167
+ case 'ReturnStatement' : {
168
+ if ( node . argument ) {
169
+ checkNode ( node . argument )
170
+ }
171
+ break
172
+ }
173
+ case 'BlockStatement' :
174
+ node . body . forEach ( checkNode )
175
+ break
176
+ default :
177
+ break
178
+ }
179
+ }
180
+
181
+ function checkTSNode ( node : TypedES . Node ) {
182
+ if ( ! node ) {
183
+ // Happens when there is no type annotation
184
+ // This should have been caught by checkNode function
185
+ return
186
+ }
187
+ switch ( node . type ) {
188
+ case 'VariableDeclaration' : {
189
+ node . declarations . forEach ( decl => {
190
+ const tsType = ( decl as any ) . id ?. typeAnnotation
191
+ checkTSNode ( tsType )
192
+ } )
193
+ break
194
+ }
195
+ case 'TSTypeAnnotation' : {
196
+ const annotation = node as TypedES . TSTypeAnnotation
197
+ // If it's a function type annotation, check params and return
198
+ if ( annotation . typeAnnotation ?. type === 'TSFunctionType' ) {
199
+ annotation . typeAnnotation . parameters ?. forEach ( param => {
200
+ // Recursively check nested TSTypeAnnotations in parameters
201
+ if ( ! config . allowAnyInTypeAnnotationParameters && isAnyType ( param . typeAnnotation ) ) {
202
+ pushAnyUsageError (
203
+ 'Usage of "any" in type annotation\'s function parameter is not allowed.' ,
204
+ param
205
+ )
206
+ }
207
+ if ( param . typeAnnotation ) {
208
+ checkTSNode ( param . typeAnnotation )
209
+ }
210
+ } )
211
+ const returnAnno = ( annotation . typeAnnotation as TypedES . TSFunctionType ) . typeAnnotation
212
+ if ( ! config . allowAnyInTypeAnnotationReturnType && isAnyType ( returnAnno ) ) {
213
+ pushAnyUsageError (
214
+ 'Usage of "any" in type annotation\'s function return type is not allowed.' ,
215
+ annotation
216
+ )
217
+ }
218
+ // Recursively check nested TSTypeAnnotations in return type
219
+ checkTSNode ( returnAnno )
220
+ }
221
+ break
222
+ }
223
+ case 'FunctionDeclaration' : {
224
+ // Here we also check param type annotations + return type via config
225
+ if (
226
+ ! config . allowAnyInTypeAnnotationParameters ||
227
+ ! config . allowAnyInTypeAnnotationReturnType
228
+ ) {
229
+ const func = node as any
230
+ // Check parameters
231
+ if ( ! config . allowAnyInTypeAnnotationParameters ) {
232
+ func . params ?. forEach ( ( param : any ) => {
233
+ checkTSNode ( param . typeAnnotation )
234
+ } )
235
+ }
236
+ // Recursively check the function return type annotation
237
+ checkTSNode ( func . returnType )
238
+ }
239
+ break
240
+ }
241
+ case 'BlockStatement' :
242
+ node . body . forEach ( checkTSNode )
243
+ break
244
+ default :
245
+ break
246
+ }
247
+ }
248
+
249
+ if ( ! config . allowAnyInVariables || ! config . allowAnyInParameters || ! config . allowAnyInReturnType ) {
250
+ program . body . forEach ( checkNode )
251
+ }
252
+ if ( ! config . allowAnyInTypeAnnotationParameters || ! config . allowAnyInTypeAnnotationReturnType ) {
253
+ program . body . forEach ( checkTSNode )
254
+ }
255
+ }
0 commit comments