diff --git a/docs/rules/function-component-definition.md b/docs/rules/function-component-definition.md
index b869373d20..9c798d17e4 100644
--- a/docs/rules/function-component-definition.md
+++ b/docs/rules/function-component-definition.md
@@ -12,12 +12,12 @@ Examples of **incorrect** code for this rule:
```jsx
// function expression for named component
-var Component = function (props) {
+const Component = function (props) {
return
{props.content}
;
};
// arrow function for named component
-var Component = (props) => {
+const Component = (props) => {
return {props.content}
;
};
@@ -49,11 +49,11 @@ Examples of **incorrect** code for this rule:
```jsx
// only function declarations for named components
// [2, { "namedComponents": "function-declaration" }]
-var Component = function (props) {
+const Component = function (props) {
return ;
};
-var Component = (props) => {
+const Component = (props) => {
return ;
};
@@ -63,7 +63,7 @@ function Component (props) {
return ;
};
-var Component = (props) => {
+const Component = (props) => {
return ;
};
@@ -73,7 +73,7 @@ function Component (props) {
return ;
};
-var Component = function (props) {
+const Component = function (props) {
return ;
};
@@ -107,13 +107,13 @@ function Component (props) {
// only function expressions for named components
// [2, { "namedComponents": "function-expression" }]
-var Component = function (props) {
+const Component = function (props) {
return ;
};
// only arrow functions for named components
// [2, { "namedComponents": "arrow-function" }]
-var Component = (props) => {
+const Component = (props) => {
return ;
};
@@ -170,11 +170,11 @@ The following patterns can **not** be autofixed in TypeScript:
```tsx
// function expressions and arrow functions that have type annotations cannot be autofixed to function declarations
// [2, { "namedComponents": "function-declaration" }]
-var Component: React.FC = function (props) {
+const Component: React.FC = function (props) {
return ;
};
-var Component: React.FC = (props) => {
+const Component: React.FC = (props) => {
return ;
};
@@ -184,7 +184,7 @@ function Component(props: Props) {
return ;
};
-var Component = function (props: Props) {
+const Component = function (props: Props) {
return ;
};
@@ -203,13 +203,13 @@ The following patterns can be autofixed in TypeScript:
```tsx
// autofix to function expression with type annotation
// [2, { "namedComponents": "function-expression" }]
-var Component: React.FC = (props) => {
+const Component: React.FC = (props) => {
return ;
};
// autofix to arrow function with type annotation
// [2, { "namedComponents": "function-expression" }]
-var Component: React.FC = function (props) {
+const Component: React.FC = function (props) {
return ;
};
@@ -219,7 +219,7 @@ function Component(props: Props) {
return ;
}
-var Component = function (props: Props) {
+const Component = function (props: Props) {
return ;
};
@@ -229,7 +229,7 @@ function Component(props: Props) {
return ;
}
-var Component = function (props: Props) {
+const Component = function (props: Props) {
return ;
};
diff --git a/lib/rules/function-component-definition.js b/lib/rules/function-component-definition.js
index 8f20e63366..f326db3c99 100644
--- a/lib/rules/function-component-definition.js
+++ b/lib/rules/function-component-definition.js
@@ -21,8 +21,8 @@ function buildFunction(template, parts) {
const NAMED_FUNCTION_TEMPLATES = {
'function-declaration': 'function {name}{typeParams}({params}){returnType} {body}',
- 'arrow-function': 'var {name}{typeAnnotation} = {typeParams}({params}){returnType} => {body}',
- 'function-expression': 'var {name}{typeAnnotation} = function{typeParams}({params}){returnType} {body}',
+ 'arrow-function': '{varType} {name}{typeAnnotation} = {typeParams}({params}){returnType} => {body}',
+ 'function-expression': '{varType} {name}{typeAnnotation} = function{typeParams}({params}){returnType} {body}',
};
const UNNAMED_FUNCTION_TEMPLATES = {
@@ -145,6 +145,7 @@ module.exports = {
create: Components.detect((context, components) => {
const configuration = context.options[0] || {};
+ let fileVarType = 'var';
const namedConfig = [].concat(configuration.namedComponents || 'function-declaration');
const unnamedConfig = [].concat(configuration.unnamedComponents || 'function-expression');
@@ -159,6 +160,10 @@ module.exports = {
if (options.type === 'arrow-function' && hasOneUnconstrainedTypeParam(node)) return;
if (isUnfixableBecauseOfExport(node)) return;
if (isFunctionExpressionWithName(node)) return;
+ let varType = fileVarType;
+ if ((node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && node.parent.type === 'VariableDeclarator') {
+ varType = node.parent.parent.kind;
+ }
return (fixer) => fixer.replaceTextRange(options.range, buildFunction(options.template, {
typeAnnotation,
@@ -167,6 +172,7 @@ module.exports = {
returnType: getNodeText(node.returnType, source),
body: getBody(node, source),
name: getName(node),
+ varType,
}));
}
@@ -209,11 +215,28 @@ module.exports = {
// --------------------------------------------------------------------------
// Public
// --------------------------------------------------------------------------
-
+ const validatePairs = [];
+ let hasEs6OrJsx = false;
return {
- FunctionDeclaration(node) { validate(node, 'function-declaration'); },
- ArrowFunctionExpression(node) { validate(node, 'arrow-function'); },
- FunctionExpression(node) { validate(node, 'function-expression'); },
+ FunctionDeclaration(node) {
+ validatePairs.push([node, 'function-declaration']);
+ },
+ ArrowFunctionExpression(node) {
+ validatePairs.push([node, 'arrow-function']);
+ },
+ FunctionExpression(node) {
+ validatePairs.push([node, 'function-expression']);
+ },
+ VariableDeclaration(node) {
+ hasEs6OrJsx = hasEs6OrJsx || node.kind === 'const' || node.kind === 'let';
+ },
+ JSXElement() {
+ hasEs6OrJsx = true;
+ },
+ 'Program:exit'() {
+ if (hasEs6OrJsx) fileVarType = 'const';
+ validatePairs.forEach((pair) => validate(pair[0], pair[1]));
+ },
};
}),
};
diff --git a/tests/lib/rules/function-component-definition.js b/tests/lib/rules/function-component-definition.js
index 2da6396a99..dc872bfed2 100644
--- a/tests/lib/rules/function-component-definition.js
+++ b/tests/lib/rules/function-component-definition.js
@@ -57,6 +57,10 @@ ruleTester.run('function-component-definition', rule, {
code: 'var Hello = (props) => { return }',
options: [{ namedComponents: 'arrow-function' }],
},
+ {
+ code: 'const Hello = (props) => { return }',
+ options: [{ namedComponents: 'arrow-function' }],
+ },
{
code: 'function Hello(props) { return }',
options: [{ namedComponents: 'function-declaration' }],
@@ -65,6 +69,10 @@ ruleTester.run('function-component-definition', rule, {
code: 'var Hello = function(props) { return }',
options: [{ namedComponents: 'function-expression' }],
},
+ {
+ code: 'const Hello = function(props) { return }',
+ options: [{ namedComponents: 'function-expression' }],
+ },
{
code: 'function Hello() { return function() { return } }',
options: [{ unnamedComponents: 'function-expression' }],
@@ -77,6 +85,10 @@ ruleTester.run('function-component-definition', rule, {
code: 'var Foo = React.memo(function Foo() { return })',
options: [{ namedComponents: 'function-declaration' }],
},
+ {
+ code: 'const Foo = React.memo(function Foo() { return })',
+ options: [{ namedComponents: 'function-declaration' }],
+ },
{
// shouldn't trigger this rule since functions stating with a lowercase
// letter are not considered components
@@ -404,7 +416,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = (props) => {
+ const Hello = (props) => {
return ;
}
`,
@@ -474,7 +486,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = function(props) {
+ const Hello = function(props) {
return ;
}
`,
@@ -554,7 +566,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = (props: Test) => {
+ const Hello = (props: Test) => {
return ;
}
`,
@@ -584,7 +596,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = function(props: Test) {
+ const Hello = function(props: Test) {
return ;
}
`,
@@ -592,6 +604,21 @@ ruleTester.run('function-component-definition', rule, {
errors: [{ messageId: 'function-expression' }],
features: ['types'],
},
+ {
+ code: `
+ function Hello(props: Test) {
+ return React.createElement('div');
+ }
+ `,
+ output: `
+ var Hello = function(props: Test) {
+ return React.createElement('div');
+ }
+ `,
+ options: [{ namedComponents: 'function-expression' }],
+ errors: [{ messageId: 'function-expression' }],
+ features: ['types'],
+ },
{
code: `
var Hello = (props: Test) => {
@@ -674,7 +701,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = (props: Test) => {
+ const Hello = (props: Test) => {
return ;
}
`,
@@ -704,7 +731,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = function(props: Test) {
+ const Hello = function(props: Test) {
return ;
}
`,
@@ -874,7 +901,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- export var Hello = (props) => {
+ export const Hello = (props) => {
return ;
}
`,
@@ -934,7 +961,7 @@ ruleTester.run('function-component-definition', rule, {
}
`,
output: `
- var Hello = (props) => {
+ const Hello = (props) => {
return ;
}
`,