@@ -2,42 +2,48 @@ module.exports = {
22 meta : {
33 type : 'problem' ,
44 docs : {
5- description : 'Enforce top-level functions to be named functions ' ,
5+ description : 'Enforce top-level functions to be named function declarations ' ,
66 url : 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/named-functions.md' ,
77 } ,
88 fixable : 'code' ,
99 schema : [ ] ,
1010 } ,
1111
1212 create ( context ) {
13- function reportAndFix ( node , name ) {
13+ function reportAndFix ( node , varName ) {
1414 context . report ( {
1515 node,
1616 message : 'Top-level functions must be named function declarations.' ,
1717 fix ( fixer ) {
18- if ( node . type === 'FunctionExpression' && node . parent . type === 'VariableDeclarator' ) {
19- // Convert to a function declaration
20- const sourceCode = context . getSourceCode ( ) ;
21- const varName = node . parent . id . name ;
18+ const sourceCode = context . getSourceCode ( ) ;
19+
20+ if ( node . type === 'ArrowFunctionExpression' ) {
21+ // Convert arrow function to a named function declaration
2222 const functionBody = sourceCode . getText ( node . body ) ;
2323 const functionParams = sourceCode . getText ( node . params ) ;
2424 const asyncKeyword = node . async ? 'async ' : '' ;
25- const generatorKeyword = node . generator ? '*' : '' ;
2625
27- const functionDeclaration = `${ asyncKeyword } function ${ generatorKeyword } ${ varName } (${ functionParams } ) ${ functionBody } ` ;
28- return fixer . replaceText ( node . parent . parent , functionDeclaration ) ;
26+ let functionDeclaration ;
27+
28+ if ( node . body . type === 'BlockStatement' ) {
29+ functionDeclaration = `${ asyncKeyword } function ${ varName } (${ functionParams } ) ${ functionBody } ` ;
30+ } else {
31+ // For concise body (single expression)
32+ functionDeclaration = `${ asyncKeyword } function ${ varName } (${ functionParams } ) { return ${ functionBody } ; }` ;
33+ }
34+
35+ return fixer . replaceText ( node . parent , functionDeclaration ) ;
2936 }
3037
3138 if ( node . type === 'FunctionExpression' ) {
32- // Convert to a function declaration
33- const sourceCode = context . getSourceCode ( ) ;
39+ // Convert anonymous function expression to named function declaration
3440 const functionBody = sourceCode . getText ( node . body ) ;
3541 const functionParams = sourceCode . getText ( node . params ) ;
3642 const asyncKeyword = node . async ? 'async ' : '' ;
3743 const generatorKeyword = node . generator ? '*' : '' ;
3844
39- const functionDeclaration = `${ asyncKeyword } function ${ generatorKeyword } ${ name } (${ functionParams } ) ${ functionBody } ` ;
40- return fixer . replaceText ( node , functionDeclaration ) ;
45+ const functionDeclaration = `${ asyncKeyword } function ${ generatorKeyword } ${ varName } (${ functionParams } ) ${ functionBody } ` ;
46+ return fixer . replaceText ( node . parent , functionDeclaration ) ;
4147 }
4248
4349 return null ;
@@ -47,31 +53,29 @@ module.exports = {
4753
4854 return {
4955 Program ( programNode ) {
50- const topLevelNodes = programNode . body ;
51-
52- topLevelNodes . forEach ( ( node ) => {
53- if ( node . type === 'FunctionDeclaration' ) {
54- // Skip if already a named function declaration
55- return ;
56+ programNode . body . forEach ( ( node ) => {
57+ // Handle VariableDeclaration (e.g. const function_ = () => {})
58+ if ( node . type === 'VariableDeclaration' ) {
59+ node . declarations . forEach ( ( declaration ) => {
60+ // Ensure that declaration.init is defined and that it's a function expression or arrow function
61+ if (
62+ declaration . init &&
63+ ( declaration . init . type === 'ArrowFunctionExpression' || declaration . init . type === 'FunctionExpression' )
64+ ) {
65+ const varName = declaration . id . name ;
66+ reportAndFix ( declaration . init , varName ) ;
67+ }
68+ } ) ;
5669 }
5770
58- if (
59- node . type === 'FunctionExpression' ||
60- ( node . type === 'VariableDeclaration' && node . declarations [ 0 ] . init ?. type === 'FunctionExpression' )
61- ) {
62- // Force it to be a named function declaration
63- if ( node . type === 'VariableDeclaration' ) {
64- const varName = node . declarations [ 0 ] . id . name ;
65- reportAndFix ( node . declarations [ 0 ] . init , varName ) ;
66- } else {
67- reportAndFix ( node , 'Anonymous' ) ;
68- }
71+ // Handle anonymous top-level function declarations
72+ if ( node . type === 'FunctionDeclaration' && ! node . id ) {
73+ reportAndFix ( node , 'Anonymous' ) ;
6974 }
7075
76+ // Handle ExpressionStatement for top-level arrow function (though uncommon)
7177 if ( node . type === 'ExpressionStatement' && node . expression . type === 'ArrowFunctionExpression' ) {
72- // Convert arrow functions into named function declarations
73- const varName = node . expression . id ? node . expression . id . name : 'Anonymous' ;
74- reportAndFix ( node . expression , varName ) ;
78+ reportAndFix ( node . expression , 'Anonymous' ) ;
7579 }
7680 } ) ;
7781 } ,
0 commit comments