Skip to content

Commit 3a42979

Browse files
authored
feat(top-level-function): support function expression (#37)
1 parent b439efd commit 3a42979

File tree

3 files changed

+48
-10
lines changed

3 files changed

+48
-10
lines changed

src/rules/top-level-function.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# top-level-function
22

3-
Enforce top-level function to be declared using `function` instead of arrow function. With auto-fix.
3+
Enforce top-level function to be declared using `function` instead of arrow function or function expression. With auto-fix.
44

55
## Rule Details
66

@@ -14,6 +14,16 @@ export const square = (a: number, b: number): number => {
1414
}
1515
```
1616

17+
<!-- eslint-skip -->
18+
```ts
19+
// 👎 bad
20+
export const square = function (a: number, b: number): number {
21+
const a2 = a * a
22+
const b2 = b * b
23+
return a2 + b2 + 2 * a * b
24+
}
25+
```
26+
1727
<!-- eslint-skip -->
1828
```js
1929
// 👍 good

src/rules/top-level-function.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,30 @@ const invalids = [
4848
'export const foo = async () => \n({})',
4949
'export async function foo () {\n return {}\n}',
5050
],
51+
[
52+
'const foo = function () {}',
53+
'function foo () {}',
54+
],
55+
[
56+
'const foo = function (as: string, bar: number) { return as + bar }',
57+
'function foo (as: string, bar: number) { return as + bar }',
58+
],
59+
[
60+
'const foo = function <K, T extends Boolean>(as: string, bar: number): Omit<T, K> { return as + bar }',
61+
'function foo <K, T extends Boolean>(as: string, bar: number): Omit<T, K> { return as + bar }',
62+
],
63+
[
64+
'export const foo = function () {}',
65+
'export function foo () {}',
66+
],
67+
[
68+
'export const foo = function () { \nreturn {} }',
69+
'export function foo () { \nreturn {} }',
70+
],
71+
[
72+
'export const foo = async function () { \nreturn {}\n }',
73+
'export async function foo () { \nreturn {}\n }',
74+
],
5175
]
5276

5377
run({

src/rules/top-level-function.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ export default createEslintRule<Options, MessageIds>({
3333

3434
const declaration = node.declarations[0]
3535

36-
if (declaration.init?.type !== 'ArrowFunctionExpression')
36+
if (
37+
declaration.init?.type !== 'ArrowFunctionExpression'
38+
&& declaration.init?.type !== 'FunctionExpression'
39+
) {
3740
return
41+
}
3842
if (declaration.id?.type !== 'Identifier')
3943
return
4044
if (declaration.id.typeAnnotation)
@@ -46,7 +50,7 @@ export default createEslintRule<Options, MessageIds>({
4650
return
4751
}
4852

49-
const arrowFn = declaration.init
53+
const fnExpression = declaration.init
5054
const body = declaration.init.body
5155
const id = declaration.id
5256

@@ -60,19 +64,19 @@ export default createEslintRule<Options, MessageIds>({
6064
fix(fixer) {
6165
const code = context.getSourceCode().text
6266
const textName = code.slice(id.range[0], id.range[1])
63-
const textArgs = arrowFn.params.length
64-
? code.slice(arrowFn.params[0].range[0], arrowFn.params[arrowFn.params.length - 1].range[1])
67+
const textArgs = fnExpression.params.length
68+
? code.slice(fnExpression.params[0].range[0], fnExpression.params[fnExpression.params.length - 1].range[1])
6569
: ''
6670
const textBody = body.type === 'BlockStatement'
6771
? code.slice(body.range[0], body.range[1])
6872
: `{\n return ${code.slice(body.range[0], body.range[1])}\n}`
69-
const textGeneric = arrowFn.typeParameters
70-
? code.slice(arrowFn.typeParameters.range[0], arrowFn.typeParameters.range[1])
73+
const textGeneric = fnExpression.typeParameters
74+
? code.slice(fnExpression.typeParameters.range[0], fnExpression.typeParameters.range[1])
7175
: ''
72-
const textTypeReturn = arrowFn.returnType
73-
? code.slice(arrowFn.returnType.range[0], arrowFn.returnType.range[1])
76+
const textTypeReturn = fnExpression.returnType
77+
? code.slice(fnExpression.returnType.range[0], fnExpression.returnType.range[1])
7478
: ''
75-
const textAsync = arrowFn.async ? 'async ' : ''
79+
const textAsync = fnExpression.async ? 'async ' : ''
7680

7781
const final = `${textAsync}function ${textName} ${textGeneric}(${textArgs})${textTypeReturn} ${textBody}`
7882
// console.log({

0 commit comments

Comments
 (0)