@@ -28,6 +28,7 @@ export default util.createRule<Options, MessageIds>({
28
28
defaultOptions : [ { } ] ,
29
29
create ( context ) {
30
30
const rules = baseRule . create ( context ) ;
31
+ const filename = context . getFilename ( ) ;
31
32
32
33
/**
33
34
* Gets a list of TS module definitions for a specified variable.
@@ -207,19 +208,93 @@ export default util.createRule<Options, MessageIds>({
207
208
}
208
209
} ,
209
210
210
- // TODO - this could probably be refined a bit
211
- '*[declare=true] Identifier' ( node : TSESTree . Identifier ) : void {
212
- context . markVariableAsUsed ( node . name ) ;
213
- const scope = context . getScope ( ) ;
214
- const { variableScope } = scope ;
215
- if ( variableScope !== scope ) {
216
- const superVar = variableScope . set . get ( node . name ) ;
211
+ // declaration file handling
212
+ [ declarationSelector ( AST_NODE_TYPES . Program , true ) ] (
213
+ node : DeclarationSelectorNode ,
214
+ ) : void {
215
+ if ( ! util . isDefinitionFile ( filename ) ) {
216
+ return ;
217
+ }
218
+ markDeclarationChildAsUsed ( node ) ;
219
+ } ,
220
+
221
+ // declared namespace handling
222
+ [ declarationSelector (
223
+ 'TSModuleDeclaration[declare = true] > TSModuleBlock' ,
224
+ false ,
225
+ ) ] ( node : DeclarationSelectorNode ) : void {
226
+ markDeclarationChildAsUsed ( node ) ;
227
+ } ,
228
+ } ;
229
+
230
+ type DeclarationSelectorNode =
231
+ | TSESTree . TSInterfaceDeclaration
232
+ | TSESTree . TSTypeAliasDeclaration
233
+ | TSESTree . ClassDeclaration
234
+ | TSESTree . FunctionDeclaration
235
+ | TSESTree . TSDeclareFunction
236
+ | TSESTree . TSEnumDeclaration
237
+ | TSESTree . TSModuleDeclaration
238
+ | TSESTree . VariableDeclaration ;
239
+ function declarationSelector (
240
+ parent : string ,
241
+ childDeclare : boolean ,
242
+ ) : string {
243
+ return [
244
+ // Types are ambiently exported
245
+ `${ parent } > :matches(${ [
246
+ AST_NODE_TYPES . TSInterfaceDeclaration ,
247
+ AST_NODE_TYPES . TSTypeAliasDeclaration ,
248
+ ] . join ( ', ' ) } )`,
249
+ // Value things are ambiently exported if they are "declare"d
250
+ `${ parent } > :matches(${ [
251
+ AST_NODE_TYPES . ClassDeclaration ,
252
+ AST_NODE_TYPES . TSDeclareFunction ,
253
+ AST_NODE_TYPES . TSEnumDeclaration ,
254
+ AST_NODE_TYPES . TSModuleDeclaration ,
255
+ AST_NODE_TYPES . VariableDeclaration ,
256
+ ] . join ( ', ' ) } )${ childDeclare ? '[declare=true]' : '' } `,
257
+ ] . join ( ', ' ) ;
258
+ }
259
+ function markDeclarationChildAsUsed ( node : DeclarationSelectorNode ) : void {
260
+ const identifiers : TSESTree . Identifier [ ] = [ ] ;
261
+ switch ( node . type ) {
262
+ case AST_NODE_TYPES . TSInterfaceDeclaration :
263
+ case AST_NODE_TYPES . TSTypeAliasDeclaration :
264
+ case AST_NODE_TYPES . ClassDeclaration :
265
+ case AST_NODE_TYPES . FunctionDeclaration :
266
+ case AST_NODE_TYPES . TSDeclareFunction :
267
+ case AST_NODE_TYPES . TSEnumDeclaration :
268
+ case AST_NODE_TYPES . TSModuleDeclaration :
269
+ if ( node . id ?. type === AST_NODE_TYPES . Identifier ) {
270
+ identifiers . push ( node . id ) ;
271
+ }
272
+ break ;
273
+
274
+ case AST_NODE_TYPES . VariableDeclaration :
275
+ for ( const declaration of node . declarations ) {
276
+ visitPattern ( declaration , pattern => {
277
+ identifiers . push ( pattern ) ;
278
+ } ) ;
279
+ }
280
+ break ;
281
+ }
282
+
283
+ const scope = context . getScope ( ) ;
284
+ const { variableScope } = scope ;
285
+ if ( variableScope !== scope ) {
286
+ for ( const id of identifiers ) {
287
+ const superVar = variableScope . set . get ( id . name ) ;
217
288
if ( superVar ) {
218
289
superVar . eslintUsed = true ;
219
290
}
220
291
}
221
- } ,
222
- } ;
292
+ } else {
293
+ for ( const id of identifiers ) {
294
+ context . markVariableAsUsed ( id . name ) ;
295
+ }
296
+ }
297
+ }
223
298
224
299
function visitPattern (
225
300
node : TSESTree . Node ,
0 commit comments