1+ module . exports = {
2+ meta : {
3+ type : 'problem' ,
4+ docs : {
5+ description : 'Enforce top-level functions to be named functions' ,
6+ url : 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/named-functions.md' ,
7+ } ,
8+ fixable : 'code' ,
9+ schema : [ ] ,
10+ } ,
11+
12+ create ( context ) {
13+ function reportAndFix ( node , name ) {
14+ context . report ( {
15+ node,
16+ message : 'Top-level functions must be named function declarations.' ,
17+ 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 ;
22+ const functionBody = sourceCode . getText ( node . body ) ;
23+ const functionParams = sourceCode . getText ( node . params ) ;
24+ const asyncKeyword = node . async ? 'async ' : '' ;
25+ const generatorKeyword = node . generator ? '*' : '' ;
26+
27+ const functionDeclaration = `${ asyncKeyword } function ${ generatorKeyword } ${ varName } (${ functionParams } ) ${ functionBody } ` ;
28+ return fixer . replaceText ( node . parent . parent , functionDeclaration ) ;
29+ }
30+
31+ if ( node . type === 'FunctionExpression' ) {
32+ // Convert to a function declaration
33+ const sourceCode = context . getSourceCode ( ) ;
34+ const functionBody = sourceCode . getText ( node . body ) ;
35+ const functionParams = sourceCode . getText ( node . params ) ;
36+ const asyncKeyword = node . async ? 'async ' : '' ;
37+ const generatorKeyword = node . generator ? '*' : '' ;
38+
39+ const functionDeclaration = `${ asyncKeyword } function ${ generatorKeyword } ${ name } (${ functionParams } ) ${ functionBody } ` ;
40+ return fixer . replaceText ( node , functionDeclaration ) ;
41+ }
42+
43+ return null ;
44+ } ,
45+ } ) ;
46+ }
47+
48+ return {
49+ 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+ }
57+
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+ }
69+ }
70+
71+ 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 ) ;
75+ }
76+ } ) ;
77+ } ,
78+ } ;
79+ } ,
80+ } ;
0 commit comments