1
1
import type { Literal } from 'estree' ;
2
- import { createRule , parseJestFnCall } from './utils' ;
2
+ import { type ParsedJestFnCall , createRule , parseJestFnCall } from './utils' ;
3
3
4
4
const createFixerImports = (
5
5
usesImport : boolean ,
@@ -30,7 +30,7 @@ export default createRule({
30
30
defaultOptions : [ ] ,
31
31
create ( context ) {
32
32
const importedJestFunctions : string [ ] = [ ] ;
33
- const usedJestFunctions = new Set < string > ( ) ;
33
+ const usedJestFunctions : ParsedJestFnCall [ ] = [ ] ;
34
34
35
35
return {
36
36
CallExpression ( node ) {
@@ -44,138 +44,142 @@ export default createRule({
44
44
importedJestFunctions . push ( jestFnCall . name ) ;
45
45
}
46
46
47
- usedJestFunctions . add ( jestFnCall . name ) ;
47
+ usedJestFunctions . push ( jestFnCall ) ;
48
48
} ,
49
49
'Program:exit' ( ) {
50
- const jestFunctionsToImport = Array . from ( usedJestFunctions ) . filter (
51
- jestFunction => ! importedJestFunctions . includes ( jestFunction ) ,
50
+ const jestFunctionsToReport = usedJestFunctions . filter (
51
+ jestFunction => ! importedJestFunctions . includes ( jestFunction . name ) ,
52
52
) ;
53
53
54
- if ( jestFunctionsToImport . length > 0 ) {
55
- const node = context . getSourceCode ( ) . ast ;
56
- const jestFunctionsToImportFormatted =
57
- jestFunctionsToImport . join ( ', ' ) ;
58
-
59
- context . report ( {
60
- node,
61
- messageId : 'preferImportingJestGlobal' ,
62
- data : { jestFunctions : jestFunctionsToImportFormatted } ,
63
- fix ( fixer ) {
64
- const sourceCode = context . getSourceCode ( ) ;
65
- const usesImport = sourceCode . ast . body . some (
66
- node => node . type === 'ImportDeclaration' ,
67
- ) ;
68
- const [ firstNode ] = sourceCode . ast . body ;
69
-
70
- let firstNodeValue ;
71
-
72
- if ( firstNode . type === 'ExpressionStatement' ) {
73
- const firstExpression = firstNode . expression as Literal ;
74
- const { value } = firstExpression ;
75
-
76
- firstNodeValue = value ;
77
- }
78
-
79
- const useStrictDirectiveExists =
80
- firstNode . type === 'ExpressionStatement' &&
81
- firstNodeValue === 'use strict' ;
82
-
83
- if ( useStrictDirectiveExists ) {
84
- return fixer . insertTextAfter (
85
- firstNode ,
86
- `\n${ createFixerImports ( usesImport , jestFunctionsToImport ) } ` ,
87
- ) ;
88
- }
89
-
90
- const importNode = sourceCode . ast . body . find (
91
- node =>
92
- node . type === 'ImportDeclaration' &&
93
- node . source . value === '@jest/globals' ,
54
+ if ( ! jestFunctionsToReport . length ) {
55
+ return ;
56
+ }
57
+ const jestFunctionsToImport = jestFunctionsToReport . map (
58
+ jestFunction => jestFunction . name ,
59
+ ) ;
60
+ const reportingNode = jestFunctionsToReport [ 0 ] . head . node ;
61
+
62
+ const jestFunctionsToImportFormatted = jestFunctionsToImport . join ( ', ' ) ;
63
+
64
+ context . report ( {
65
+ node : reportingNode ,
66
+ messageId : 'preferImportingJestGlobal' ,
67
+ data : { jestFunctions : jestFunctionsToImportFormatted } ,
68
+ fix ( fixer ) {
69
+ const sourceCode = context . getSourceCode ( ) ;
70
+ const usesImport = sourceCode . ast . body . some (
71
+ node => node . type === 'ImportDeclaration' ,
72
+ ) ;
73
+ const [ firstNode ] = sourceCode . ast . body ;
74
+
75
+ let firstNodeValue ;
76
+
77
+ if ( firstNode . type === 'ExpressionStatement' ) {
78
+ const firstExpression = firstNode . expression as Literal ;
79
+ const { value } = firstExpression ;
80
+
81
+ firstNodeValue = value ;
82
+ }
83
+
84
+ const useStrictDirectiveExists =
85
+ firstNode . type === 'ExpressionStatement' &&
86
+ firstNodeValue === 'use strict' ;
87
+
88
+ if ( useStrictDirectiveExists ) {
89
+ return fixer . insertTextAfter (
90
+ firstNode ,
91
+ `\n${ createFixerImports ( usesImport , jestFunctionsToImport ) } ` ,
94
92
) ;
95
-
96
- if ( importNode && importNode . type === 'ImportDeclaration' ) {
97
- const existingImports = importNode . specifiers . map ( specifier => {
98
- /* istanbul ignore else */
99
- if ( specifier . type === 'ImportSpecifier' ) {
100
- return specifier . imported ?. name ;
101
- }
102
-
103
- // istanbul ignore next
104
- return null ;
105
- } ) ;
106
- const allImports = [
107
- ...new Set ( [
108
- ...existingImports . filter (
109
- ( imp ) : imp is string => imp !== null ,
110
- ) ,
111
- ...jestFunctionsToImport ,
112
- ] ) ,
113
- ] ;
114
-
115
- return fixer . replaceText (
116
- importNode ,
117
- createFixerImports ( usesImport , allImports ) ,
118
- ) ;
119
- }
120
-
121
- const requireNode = sourceCode . ast . body . find (
122
- node =>
123
- node . type === 'VariableDeclaration' &&
124
- node . declarations . some (
125
- declaration =>
126
- declaration . init &&
127
- ( declaration . init as any ) . callee &&
128
- ( declaration . init as any ) . callee . name === 'require' &&
129
- ( declaration . init as any ) . arguments ?. [ 0 ] ?. type ===
130
- 'Literal' &&
131
- ( declaration . init as any ) . arguments ?. [ 0 ] ?. value ===
132
- '@jest/globals' ,
93
+ }
94
+
95
+ const importNode = sourceCode . ast . body . find (
96
+ node =>
97
+ node . type === 'ImportDeclaration' &&
98
+ node . source . value === '@jest/globals' ,
99
+ ) ;
100
+
101
+ if ( importNode && importNode . type === 'ImportDeclaration' ) {
102
+ const existingImports = importNode . specifiers . map ( specifier => {
103
+ /* istanbul ignore else */
104
+ if ( specifier . type === 'ImportSpecifier' ) {
105
+ return specifier . imported ?. name ;
106
+ }
107
+
108
+ // istanbul ignore next
109
+ return null ;
110
+ } ) ;
111
+ const allImports = [
112
+ ...new Set ( [
113
+ ...existingImports . filter (
114
+ ( imp ) : imp is string => imp !== null ,
133
115
) ,
134
- ) ;
116
+ ...jestFunctionsToImport ,
117
+ ] ) ,
118
+ ] ;
135
119
136
- if ( requireNode && requireNode . type === 'VariableDeclaration' ) {
137
- const existingImports =
138
- requireNode . declarations [ 0 ] ?. id . type === 'ObjectPattern'
139
- ? requireNode . declarations [ 0 ] ?. id . properties ?. map (
140
- property => {
120
+ return fixer . replaceText (
121
+ importNode ,
122
+ createFixerImports ( usesImport , allImports ) ,
123
+ ) ;
124
+ }
125
+
126
+ const requireNode = sourceCode . ast . body . find (
127
+ node =>
128
+ node . type === 'VariableDeclaration' &&
129
+ node . declarations . some (
130
+ declaration =>
131
+ declaration . init &&
132
+ ( declaration . init as any ) . callee &&
133
+ ( declaration . init as any ) . callee . name === 'require' &&
134
+ ( declaration . init as any ) . arguments ?. [ 0 ] ?. type ===
135
+ 'Literal' &&
136
+ ( declaration . init as any ) . arguments ?. [ 0 ] ?. value ===
137
+ '@jest/globals' ,
138
+ ) ,
139
+ ) ;
140
+
141
+ if ( requireNode && requireNode . type === 'VariableDeclaration' ) {
142
+ const existingImports =
143
+ requireNode . declarations [ 0 ] ?. id . type === 'ObjectPattern'
144
+ ? requireNode . declarations [ 0 ] ?. id . properties ?. map (
145
+ property => {
146
+ /* istanbul ignore else */
147
+ if ( property . type === 'Property' ) {
141
148
/* istanbul ignore else */
142
- if ( property . type === 'Property' ) {
143
- /* istanbul ignore else */
144
- if ( property . key . type === 'Identifier' ) {
145
- return property . key . name ;
146
- }
149
+ if ( property . key . type === 'Identifier' ) {
150
+ return property . key . name ;
147
151
}
152
+ }
153
+
154
+ // istanbul ignore next
155
+ return null ;
156
+ } ,
157
+ ) ||
158
+ // istanbul ignore next
159
+ [ ]
160
+ : // istanbul ignore next
161
+ [ ] ;
162
+ const allImports = [
163
+ ...new Set ( [
164
+ ...existingImports . filter (
165
+ ( imp ) : imp is string => imp !== null ,
166
+ ) ,
167
+ ...jestFunctionsToImport ,
168
+ ] ) ,
169
+ ] ;
148
170
149
- // istanbul ignore next
150
- return null ;
151
- } ,
152
- ) ||
153
- // istanbul ignore next
154
- [ ]
155
- : // istanbul ignore next
156
- [ ] ;
157
- const allImports = [
158
- ...new Set ( [
159
- ...existingImports . filter (
160
- ( imp ) : imp is string => imp !== null ,
161
- ) ,
162
- ...jestFunctionsToImport ,
163
- ] ) ,
164
- ] ;
165
-
166
- return fixer . replaceText (
167
- requireNode ,
168
- `${ createFixerImports ( usesImport , allImports ) } ` ,
169
- ) ;
170
- }
171
-
172
- return fixer . insertTextBefore (
173
- node ,
174
- `${ createFixerImports ( usesImport , jestFunctionsToImport ) } \n` ,
171
+ return fixer . replaceText (
172
+ requireNode ,
173
+ `${ createFixerImports ( usesImport , allImports ) } ` ,
175
174
) ;
176
- } ,
177
- } ) ;
178
- }
175
+ }
176
+
177
+ return fixer . insertTextBefore (
178
+ reportingNode ,
179
+ `${ createFixerImports ( usesImport , jestFunctionsToImport ) } \n` ,
180
+ ) ;
181
+ } ,
182
+ } ) ;
179
183
} ,
180
184
} ;
181
185
} ,
0 commit comments