@@ -15,14 +15,16 @@ const reportC = require('../util/report');
15
15
// ------------------------------------------------------------------------------
16
16
17
17
function buildFunction ( template , parts ) {
18
- return Object . keys ( parts )
19
- . reduce ( ( acc , key ) => acc . replace ( `{${ key } }` , ( ) => ( parts [ key ] || '' ) ) , template ) ;
18
+ return Object . keys ( parts ) . reduce (
19
+ ( acc , key ) => acc . replace ( `{${ key } }` , ( ) => parts [ key ] || '' ) ,
20
+ template
21
+ ) ;
20
22
}
21
23
22
24
const NAMED_FUNCTION_TEMPLATES = {
23
25
'function-declaration' : 'function {name}{typeParams}({params}){returnType} {body}' ,
24
- 'arrow-function' : 'var {name}{typeAnnotation} = {typeParams}({params}){returnType} => {body}' ,
25
- 'function-expression' : 'var {name}{typeAnnotation} = function{typeParams}({params}){returnType} {body}' ,
26
+ 'arrow-function' : '{varType} {name}{typeAnnotation} = {typeParams}({params}){returnType} => {body}' ,
27
+ 'function-expression' : '{varType} {name}{typeAnnotation} = function{typeParams}({params}){returnType} {body}' ,
26
28
} ;
27
29
28
30
const UNNAMED_FUNCTION_TEMPLATES = {
@@ -32,14 +34,20 @@ const UNNAMED_FUNCTION_TEMPLATES = {
32
34
33
35
function hasOneUnconstrainedTypeParam ( node ) {
34
36
if ( node . typeParameters ) {
35
- return node . typeParameters . params . length === 1 && ! node . typeParameters . params [ 0 ] . constraint ;
37
+ return (
38
+ node . typeParameters . params . length === 1
39
+ && ! node . typeParameters . params [ 0 ] . constraint
40
+ ) ;
36
41
}
37
42
38
43
return false ;
39
44
}
40
45
41
46
function hasName ( node ) {
42
- return node . type === 'FunctionDeclaration' || node . parent . type === 'VariableDeclarator' ;
47
+ return (
48
+ node . type === 'FunctionDeclaration'
49
+ || node . parent . type === 'VariableDeclarator'
50
+ ) ;
43
51
}
44
52
45
53
function getNodeText ( prop , source ) {
@@ -52,25 +60,27 @@ function getName(node) {
52
60
return node . id . name ;
53
61
}
54
62
55
- if ( node . type === 'ArrowFunctionExpression' || node . type === 'FunctionExpression' ) {
63
+ if (
64
+ node . type === 'ArrowFunctionExpression'
65
+ || node . type === 'FunctionExpression'
66
+ ) {
56
67
return hasName ( node ) && node . parent . id . name ;
57
68
}
58
69
}
59
70
60
71
function getParams ( node , source ) {
61
72
if ( node . params . length === 0 ) return null ;
62
- return source . slice ( node . params [ 0 ] . range [ 0 ] , node . params [ node . params . length - 1 ] . range [ 1 ] ) ;
73
+ return source . slice (
74
+ node . params [ 0 ] . range [ 0 ] ,
75
+ node . params [ node . params . length - 1 ] . range [ 1 ]
76
+ ) ;
63
77
}
64
78
65
79
function getBody ( node , source ) {
66
80
const range = node . body . range ;
67
81
68
82
if ( node . body . type !== 'BlockStatement' ) {
69
- return [
70
- '{' ,
71
- ` return ${ source . slice ( range [ 0 ] , range [ 1 ] ) } ` ,
72
- '}' ,
73
- ] . join ( '\n' ) ;
83
+ return [ '{' , ` return ${ source . slice ( range [ 0 ] , range [ 1 ] ) } ` , '}' ] . join ( '\n' ) ;
74
84
}
75
85
76
86
return source . slice ( range [ 0 ] , range [ 1 ] ) ;
@@ -79,13 +89,20 @@ function getBody(node, source) {
79
89
function getTypeAnnotation ( node , source ) {
80
90
if ( ! hasName ( node ) || node . type === 'FunctionDeclaration' ) return ;
81
91
82
- if ( node . type === 'ArrowFunctionExpression' || node . type === 'FunctionExpression' ) {
92
+ if (
93
+ node . type === 'ArrowFunctionExpression'
94
+ || node . type === 'FunctionExpression'
95
+ ) {
83
96
return getNodeText ( node . parent . id . typeAnnotation , source ) ;
84
97
}
85
98
}
86
99
87
100
function isUnfixableBecauseOfExport ( node ) {
88
- return node . type === 'FunctionDeclaration' && node . parent && node . parent . type === 'ExportDefaultDeclaration' ;
101
+ return (
102
+ node . type === 'FunctionDeclaration'
103
+ && node . parent
104
+ && node . parent . type === 'ExportDefaultDeclaration'
105
+ ) ;
89
106
}
90
107
91
108
function isFunctionExpressionWithName ( node ) {
@@ -116,12 +133,22 @@ module.exports = {
116
133
properties : {
117
134
namedComponents : {
118
135
oneOf : [
119
- { enum : [ 'function-declaration' , 'arrow-function' , 'function-expression' ] } ,
136
+ {
137
+ enum : [
138
+ 'function-declaration' ,
139
+ 'arrow-function' ,
140
+ 'function-expression' ,
141
+ ] ,
142
+ } ,
120
143
{
121
144
type : 'array' ,
122
145
items : {
123
146
type : 'string' ,
124
- enum : [ 'function-declaration' , 'arrow-function' , 'function-expression' ] ,
147
+ enum : [
148
+ 'function-declaration' ,
149
+ 'arrow-function' ,
150
+ 'function-expression' ,
151
+ ] ,
125
152
} ,
126
153
} ,
127
154
] ,
@@ -145,29 +172,49 @@ module.exports = {
145
172
146
173
create : Components . detect ( ( context , components ) => {
147
174
const configuration = context . options [ 0 ] || { } ;
175
+ let fileVarType = 'var' ;
148
176
149
- const namedConfig = [ ] . concat ( configuration . namedComponents || 'function-declaration' ) ;
150
- const unnamedConfig = [ ] . concat ( configuration . unnamedComponents || 'function-expression' ) ;
177
+ const namedConfig = [ ] . concat (
178
+ configuration . namedComponents || 'function-declaration'
179
+ ) ;
180
+ const unnamedConfig = [ ] . concat (
181
+ configuration . unnamedComponents || 'function-expression'
182
+ ) ;
151
183
152
184
function getFixer ( node , options ) {
153
185
const sourceCode = context . getSourceCode ( ) ;
154
186
const source = sourceCode . getText ( ) ;
155
187
156
188
const typeAnnotation = getTypeAnnotation ( node , source ) ;
157
189
158
- if ( options . type === 'function-declaration' && typeAnnotation ) return ;
159
- if ( options . type === 'arrow-function' && hasOneUnconstrainedTypeParam ( node ) ) return ;
190
+ if ( options . type === 'function-declaration' && typeAnnotation ) {
191
+ return ;
192
+ }
193
+ if ( options . type === 'arrow-function' && hasOneUnconstrainedTypeParam ( node ) ) {
194
+ return ;
195
+ }
160
196
if ( isUnfixableBecauseOfExport ( node ) ) return ;
161
197
if ( isFunctionExpressionWithName ( node ) ) return ;
198
+ let varType = fileVarType ;
199
+ if (
200
+ ( node . type === 'FunctionExpression' || node . type === 'ArrowFunctionExpression' )
201
+ && node . parent . type === 'VariableDeclarator'
202
+ ) {
203
+ varType = node . parent . parent . kind ;
204
+ }
162
205
163
- return ( fixer ) => fixer . replaceTextRange ( options . range , buildFunction ( options . template , {
164
- typeAnnotation,
165
- typeParams : getNodeText ( node . typeParameters , source ) ,
166
- params : getParams ( node , source ) ,
167
- returnType : getNodeText ( node . returnType , source ) ,
168
- body : getBody ( node , source ) ,
169
- name : getName ( node ) ,
170
- } ) ) ;
206
+ return ( fixer ) => fixer . replaceTextRange (
207
+ options . range ,
208
+ buildFunction ( options . template , {
209
+ typeAnnotation,
210
+ typeParams : getNodeText ( node . typeParameters , source ) ,
211
+ params : getParams ( node , source ) ,
212
+ returnType : getNodeText ( node . returnType , source ) ,
213
+ body : getBody ( node , source ) ,
214
+ name : getName ( node ) ,
215
+ varType,
216
+ } )
217
+ ) ;
171
218
}
172
219
173
220
function report ( node , options ) {
@@ -188,9 +235,10 @@ module.exports = {
188
235
fixerOptions : {
189
236
type : namedConfig [ 0 ] ,
190
237
template : NAMED_FUNCTION_TEMPLATES [ namedConfig [ 0 ] ] ,
191
- range : node . type === 'FunctionDeclaration'
192
- ? node . range
193
- : node . parent . parent . range ,
238
+ range :
239
+ node . type === 'FunctionDeclaration'
240
+ ? node . range
241
+ : node . parent . parent . range ,
194
242
} ,
195
243
} ) ;
196
244
}
@@ -209,11 +257,28 @@ module.exports = {
209
257
// --------------------------------------------------------------------------
210
258
// Public
211
259
// --------------------------------------------------------------------------
212
-
260
+ const validatePairs = [ ] ;
261
+ let hasES6OrJsx = false ;
213
262
return {
214
- FunctionDeclaration ( node ) { validate ( node , 'function-declaration' ) ; } ,
215
- ArrowFunctionExpression ( node ) { validate ( node , 'arrow-function' ) ; } ,
216
- FunctionExpression ( node ) { validate ( node , 'function-expression' ) ; } ,
263
+ FunctionDeclaration ( node ) {
264
+ validatePairs . push ( [ node , 'function-declaration' ] ) ;
265
+ } ,
266
+ ArrowFunctionExpression ( node ) {
267
+ validatePairs . push ( [ node , 'arrow-function' ] ) ;
268
+ } ,
269
+ FunctionExpression ( node ) {
270
+ validatePairs . push ( [ node , 'function-expression' ] ) ;
271
+ } ,
272
+ VariableDeclaration ( node ) {
273
+ hasES6OrJsx = hasES6OrJsx || node . kind === 'const' || node . kind === 'let' ;
274
+ } ,
275
+ 'Program:exit' ( ) {
276
+ if ( hasES6OrJsx ) fileVarType = 'const' ;
277
+ validatePairs . forEach ( ( pair ) => validate ( pair [ 0 ] , pair [ 1 ] ) ) ;
278
+ } ,
279
+ 'ImportDeclaration, ExportNamedDeclaration, ExportDefaultDeclaration, ExportAllDeclaration, ExportSpecifier, ExportDefaultSpecifier, JSXElement, TSExportAssignment, TSImportEqualsDeclaration' ( ) {
280
+ hasES6OrJsx = true ;
281
+ } ,
217
282
} ;
218
283
} ) ,
219
284
} ;
0 commit comments