@@ -15,14 +15,16 @@ const reportC = require('../util/report');
1515// ------------------------------------------------------------------------------
1616
1717function 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+ ) ;
2022}
2123
2224const NAMED_FUNCTION_TEMPLATES = {
2325 '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}' ,
2628} ;
2729
2830const UNNAMED_FUNCTION_TEMPLATES = {
@@ -32,14 +34,20 @@ const UNNAMED_FUNCTION_TEMPLATES = {
3234
3335function hasOneUnconstrainedTypeParam ( node ) {
3436 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+ ) ;
3641 }
3742
3843 return false ;
3944}
4045
4146function hasName ( node ) {
42- return node . type === 'FunctionDeclaration' || node . parent . type === 'VariableDeclarator' ;
47+ return (
48+ node . type === 'FunctionDeclaration'
49+ || node . parent . type === 'VariableDeclarator'
50+ ) ;
4351}
4452
4553function getNodeText ( prop , source ) {
@@ -52,25 +60,27 @@ function getName(node) {
5260 return node . id . name ;
5361 }
5462
55- if ( node . type === 'ArrowFunctionExpression' || node . type === 'FunctionExpression' ) {
63+ if (
64+ node . type === 'ArrowFunctionExpression'
65+ || node . type === 'FunctionExpression'
66+ ) {
5667 return hasName ( node ) && node . parent . id . name ;
5768 }
5869}
5970
6071function getParams ( node , source ) {
6172 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+ ) ;
6377}
6478
6579function getBody ( node , source ) {
6680 const range = node . body . range ;
6781
6882 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' ) ;
7484 }
7585
7686 return source . slice ( range [ 0 ] , range [ 1 ] ) ;
@@ -79,13 +89,20 @@ function getBody(node, source) {
7989function getTypeAnnotation ( node , source ) {
8090 if ( ! hasName ( node ) || node . type === 'FunctionDeclaration' ) return ;
8191
82- if ( node . type === 'ArrowFunctionExpression' || node . type === 'FunctionExpression' ) {
92+ if (
93+ node . type === 'ArrowFunctionExpression'
94+ || node . type === 'FunctionExpression'
95+ ) {
8396 return getNodeText ( node . parent . id . typeAnnotation , source ) ;
8497 }
8598}
8699
87100function 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+ ) ;
89106}
90107
91108function isFunctionExpressionWithName ( node ) {
@@ -116,12 +133,22 @@ module.exports = {
116133 properties : {
117134 namedComponents : {
118135 oneOf : [
119- { enum : [ 'function-declaration' , 'arrow-function' , 'function-expression' ] } ,
136+ {
137+ enum : [
138+ 'function-declaration' ,
139+ 'arrow-function' ,
140+ 'function-expression' ,
141+ ] ,
142+ } ,
120143 {
121144 type : 'array' ,
122145 items : {
123146 type : 'string' ,
124- enum : [ 'function-declaration' , 'arrow-function' , 'function-expression' ] ,
147+ enum : [
148+ 'function-declaration' ,
149+ 'arrow-function' ,
150+ 'function-expression' ,
151+ ] ,
125152 } ,
126153 } ,
127154 ] ,
@@ -145,29 +172,49 @@ module.exports = {
145172
146173 create : Components . detect ( ( context , components ) => {
147174 const configuration = context . options [ 0 ] || { } ;
175+ let fileVarType = 'var' ;
148176
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+ ) ;
151183
152184 function getFixer ( node , options ) {
153185 const sourceCode = context . getSourceCode ( ) ;
154186 const source = sourceCode . getText ( ) ;
155187
156188 const typeAnnotation = getTypeAnnotation ( node , source ) ;
157189
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+ }
160196 if ( isUnfixableBecauseOfExport ( node ) ) return ;
161197 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+ }
162205
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+ ) ;
171218 }
172219
173220 function report ( node , options ) {
@@ -188,9 +235,10 @@ module.exports = {
188235 fixerOptions : {
189236 type : namedConfig [ 0 ] ,
190237 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 ,
194242 } ,
195243 } ) ;
196244 }
@@ -209,11 +257,28 @@ module.exports = {
209257 // --------------------------------------------------------------------------
210258 // Public
211259 // --------------------------------------------------------------------------
212-
260+ const validatePairs = [ ] ;
261+ let hasES6OrJsx = false ;
213262 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+ } ,
217282 } ;
218283 } ) ,
219284} ;
0 commit comments