@@ -67,6 +67,10 @@ export class SourceTypedParser extends SourceParser {
6767 }
6868
6969 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+ }
7074 const typedCheckedProgram : Program = checkForTypeErrors ( typedProgram , context )
7175 transformBabelASTToESTreeCompliantAST ( typedCheckedProgram )
7276
@@ -77,3 +81,175 @@ export class SourceTypedParser extends SourceParser {
7781 return 'SourceTypedParser'
7882 }
7983}
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