1- import { ESLintUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
2- import { getDocsUrl , ASYNC_UTILS , LIBRARY_MODULES } from '../utils ' ;
1+ import { ASTUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
2+ import { createTestingLibraryRule } from '../create-testing-library-rule ' ;
33import {
44 findClosestCallExpressionNode ,
55 isMemberExpression ,
@@ -9,10 +9,9 @@ export const RULE_NAME = 'no-wait-for-snapshot';
99export type MessageIds = 'noWaitForSnapshot' ;
1010type Options = [ ] ;
1111
12- const ASYNC_UTILS_REGEXP = new RegExp ( `^(${ ASYNC_UTILS . join ( '|' ) } )$` ) ;
1312const SNAPSHOT_REGEXP = / ^ ( t o M a t c h S n a p s h o t | t o M a t c h I n l i n e S n a p s h o t ) $ / ;
1413
15- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
14+ export default createTestingLibraryRule < Options , MessageIds > ( {
1615 name : RULE_NAME ,
1716 meta : {
1817 type : 'problem' ,
@@ -31,102 +30,40 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
3130 } ,
3231 defaultOptions : [ ] ,
3332
34- create ( context ) {
35- const asyncUtilsUsage : Array < {
36- node : TSESTree . Identifier | TSESTree . MemberExpression ;
37- name : string ;
38- } > = [ ] ;
39- const importedAsyncUtils : string [ ] = [ ] ;
40- const snapshotUsage : TSESTree . Identifier [ ] = [ ] ;
41-
42- return {
43- 'ImportDeclaration > ImportSpecifier,ImportNamespaceSpecifier' (
44- node : TSESTree . Node
45- ) {
46- const parent = node . parent as TSESTree . ImportDeclaration ;
47-
48- if ( ! LIBRARY_MODULES . includes ( parent . source . value . toString ( ) ) ) {
49- return ;
50- }
51-
52- let name ;
53- if ( node . type === 'ImportSpecifier' ) {
54- name = node . imported . name ;
33+ create ( context , _ , helpers ) {
34+ function getClosestAsyncUtil ( node : TSESTree . Node ) {
35+ let n = node ;
36+ do {
37+ const callExpression = findClosestCallExpressionNode ( n ) ;
38+ if (
39+ ASTUtils . isIdentifier ( callExpression . callee ) &&
40+ helpers . isNodeComingFromTestingLibrary ( callExpression . callee ) &&
41+ helpers . isAsyncUtil ( callExpression . callee )
42+ ) {
43+ return callExpression . callee ;
5544 }
56-
57- if ( node . type === 'ImportNamespaceSpecifier' ) {
58- name = node . local . name ;
45+ if (
46+ isMemberExpression ( callExpression . callee ) &&
47+ ASTUtils . isIdentifier ( callExpression . callee . property ) &&
48+ helpers . isNodeComingFromTestingLibrary ( callExpression . callee )
49+ ) {
50+ return callExpression . callee . property ;
5951 }
52+ n = findClosestCallExpressionNode ( callExpression . parent ) ;
53+ } while ( n !== null ) ;
54+ return null ;
55+ }
6056
61- importedAsyncUtils . push ( name ) ;
62- } ,
63- [ `CallExpression > Identifier[name=${ ASYNC_UTILS_REGEXP } ]` ] (
64- node : TSESTree . Identifier
65- ) {
66- asyncUtilsUsage . push ( { node, name : node . name } ) ;
67- } ,
68- [ `CallExpression > MemberExpression > Identifier[name=${ ASYNC_UTILS_REGEXP } ]` ] (
69- node : TSESTree . Identifier
70- ) {
71- const memberExpression = node . parent as TSESTree . MemberExpression ;
72- const identifier = memberExpression . object as TSESTree . Identifier ;
73- const memberExpressionName = identifier . name ;
74-
75- asyncUtilsUsage . push ( {
76- node : memberExpression ,
77- name : memberExpressionName ,
78- } ) ;
79- } ,
57+ return {
8058 [ `Identifier[name=${ SNAPSHOT_REGEXP } ]` ] ( node : TSESTree . Identifier ) {
81- snapshotUsage . push ( node ) ;
82- } ,
83- 'Program:exit' ( ) {
84- const testingLibraryUtilUsage = asyncUtilsUsage . filter ( ( usage ) => {
85- if ( isMemberExpression ( usage . node ) ) {
86- const object = usage . node . object as TSESTree . Identifier ;
87-
88- return importedAsyncUtils . includes ( object . name ) ;
89- }
90-
91- return importedAsyncUtils . includes ( usage . name ) ;
92- } ) ;
93-
94- function getClosestAsyncUtil (
95- asyncUtilUsage : {
96- node : TSESTree . Identifier | TSESTree . MemberExpression ;
97- name : string ;
98- } ,
99- node : TSESTree . Node
100- ) {
101- let callExpression = findClosestCallExpressionNode ( node ) ;
102- while ( callExpression != null ) {
103- if ( callExpression . callee === asyncUtilUsage . node )
104- return asyncUtilUsage ;
105- callExpression = findClosestCallExpressionNode (
106- callExpression . parent
107- ) ;
108- }
109- return null ;
59+ const closestAsyncUtil = getClosestAsyncUtil ( node ) ;
60+ if ( closestAsyncUtil === null ) {
61+ return ;
11062 }
111-
112- snapshotUsage . forEach ( ( node ) => {
113- testingLibraryUtilUsage . forEach ( ( asyncUtilUsage ) => {
114- const closestAsyncUtil = getClosestAsyncUtil ( asyncUtilUsage , node ) ;
115- if ( closestAsyncUtil != null ) {
116- let name ;
117- if ( isMemberExpression ( closestAsyncUtil . node ) ) {
118- name = ( closestAsyncUtil . node . property as TSESTree . Identifier )
119- . name ;
120- } else {
121- name = closestAsyncUtil . name ;
122- }
123- context . report ( {
124- node,
125- messageId : 'noWaitForSnapshot' ,
126- data : { name } ,
127- } ) ;
128- }
129- } ) ;
63+ context . report ( {
64+ node,
65+ messageId : 'noWaitForSnapshot' ,
66+ data : { name : closestAsyncUtil . name } ,
13067 } ) ;
13168 } ,
13269 } ;
0 commit comments