Skip to content

Commit

Permalink
bla
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanwullems committed Jan 10, 2020
1 parent 6f07af0 commit ce1d96a
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 27 deletions.
37 changes: 31 additions & 6 deletions docs/rules/function-component-definition.md
Expand Up @@ -31,13 +31,13 @@ function getComponent() {

## Rule Options

This rule takes an options object as a second parameter where the preferred function type for components can be specified. The first property of the options object is `"namedComponents"` which can be `"function-declaration"`, `"function-expression"` or `"arrow-function"` and has `'function-declaration'` as its default. The second property is `"unnamedComponents"` that can be either `"function-expression"` or `"arrow-function"` and has `'function-expression'` as its default.
This rule takes an options object as a second parameter where the preferred function type for components can be specified. The first property of the options object is `"namedComponents"` which can be `"function-declaration"`, `"function-expression"`, or `"arrow-function"` and has `'function-declaration'` as its default. The second property is `"unnamedComponents"` that can be either `"function-expression"` or `"arrow-function"`, and has `'function-expression'` as its default.

```js
...
"react/function-component-definition": [<enabled>, {
"namedComponents": "function-declaration"|"function-expression"|"arrow-function",
"unnamedComponents": "function-expression"|"arrow-function"
"namedComponents": "function-declaration" | "function-expression" | "arrow-function",
"unnamedComponents": "function-expression" | "arrow-function"
}]
...
```
Expand Down Expand Up @@ -133,6 +133,32 @@ function getComponent () {

```

## Unfixable patterns

There is one unfixable pattern in javascript.

It has to do with the fact that this is valid syntax:

```js
export default function getComponent () {
return <div/>
}
```

While these are not.

```js
export default var getComponent = () => {
return <div/>
}

export default var getComponent = function () {
return <div/>
}
```

These patterns have to be manually fixed.

## Heads up typescript users

Note that the auto fixer is somewhat constrained for typescript users.
Expand Down Expand Up @@ -168,8 +194,7 @@ function getComponent() {
}
```

If the single type parameter either have a varraint
or if there are multiple type parameters the syntax conflicts are resolved and the component can be autofixed again
Type parameters do not produce syntax conflicts if either there are multiple type parameters or, if there is only one constrained type parameter.

The following patterns can be autofixed in typescript:

Expand Down Expand Up @@ -226,4 +251,4 @@ function getComponent() {

## When not to use

If you are not interested in consistent types of function components.
If you are not interested in consistent types of function components.
19 changes: 14 additions & 5 deletions lib/rules/function-component-definition.js
Expand Up @@ -62,23 +62,22 @@ function getName(node) {
}

function getParams(node, source) {
if (!node.params.length) return null;
if (node.params.length === 0) return null;
return source.slice(node.params[0].range[0], node.params[node.params.length - 1].range[1]);
}

function getBody(node, source) {
const range = node.body.range;
if (node.body.type === 'JSXElement') {

if (node.body.type !== 'BlockStatement') {
return [
'{',
` return ${source.slice(range[0], range[1])}`,
'}'
].join('\n');
}

if (node.body.type === 'BlockStatement') {
return source.slice(range[0], range[1]);
}
return source.slice(range[0], range[1]);
}

function getTypeAnnotation(node, source) {
Expand All @@ -89,6 +88,14 @@ function getTypeAnnotation(node, source) {
}
}

function isUnfixableBecauseOfExport(node) {
return node.type === 'FunctionDeclaration' && node.parent && node.parent.type === 'ExportDefaultDeclaration';
}

function isFunctionExpressionWithName(node) {
return node.type === 'FunctionExpression' && node.id && node.id.name;
}

module.exports = {
meta: {
docs: {
Expand Down Expand Up @@ -126,6 +133,8 @@ module.exports = {

if (options.type === 'function-declaration' && typeAnnotation) return;
if (options.type === 'arrow-function' && hasOneUnconstrainedTypeParam(node)) return;
if (isUnfixableBecauseOfExport(node)) return;
if (isFunctionExpressionWithName(node)) return;

return fixer => fixer.replaceTextRange(options.range, buildFunction(options.template, {
typeAnnotation,
Expand Down
105 changes: 89 additions & 16 deletions tests/lib/rules/function-component-definition.js
Expand Up @@ -120,6 +120,22 @@ ruleTester.run('function-component-definition', rule, {
code: 'function wrapper() { return<Test extends {}>(props: Props<Test>) => { return <p/> } } ',
options: [{unnamedComponents: 'arrow-function'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: 'var Hello = function(props): ReactNode { return <p/> }',
options: [{namedComponents: 'function-expression'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: 'var Hello = (props): ReactNode => { return <p/> }',
options: [{namedComponents: 'arrow-function'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: 'function wrapper() { return function(props): ReactNode { return <p/> } } ',
options: [{unnamedComponents: 'function-expression'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: 'function wrapper() { return (props): ReactNode => { return <p/> } } ',
options: [{unnamedComponents: 'arrow-function'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: 'function Hello(props): ReactNode { return <p/> }',
options: [{namedComponents: 'function-declaration'}],
Expand Down Expand Up @@ -413,20 +429,6 @@ ruleTester.run('function-component-definition', rule, {
options: [{namedComponents: 'function-declaration'}],
errors: [{message: 'Function component is not a function declaration'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: [
'var Hello: React.FC<Test> = (props) => {',
' return <div/>',
'}'
].join('\n'),
output: [
'var Hello: React.FC<Test> = (props) => {',
' return <div/>',
'}'
].join('\n'),
options: [{namedComponents: 'function-declaration'}],
errors: [{message: 'Function component is not a function declaration'}],
parser: parsers.TYPESCRIPT_ESLINT
}, {
code: [
'function Hello<Test extends {}>(props: Test) {',
Expand Down Expand Up @@ -629,6 +631,77 @@ ruleTester.run('function-component-definition', rule, {
errors: [{message: 'Function component is not a function expression'}],
options: [{unnamedComponents: 'function-expression'}],
parser: parsers.TYPESCRIPT_ESLINT
}
]
},
{
code: [
'export function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
output: [
'export var Hello = (props) => {',
' return <div/>',
'}'
].join('\n'),
options: [{namedComponents: 'arrow-function'}],
errors: [{message: 'Function component is not an arrow function'}],
parser: parsers.BABEL_ESLINT
}, {
code: [
'export var Hello = function(props) {',
' return <div/>',
'}'
].join('\n'),
output: [
'export var Hello = (props) => {',
' return <div/>',
'}'
].join('\n'),
options: [{namedComponents: 'arrow-function'}],
errors: [{message: 'Function component is not an arrow function'}],
parser: parsers.BABEL_ESLINT
}, {
code: [
'export var Hello = (props) => {',
' return <div/>',
'}'
].join('\n'),
output: [
'export function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
options: [{namedComponents: 'function-declaration'}],
errors: [{message: 'Function component is not a function declaration'}],
parser: parsers.BABEL_ESLINT
},
{
code: [
'export default function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
output: [
'export default function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
options: [{namedComponents: 'arrow-function'}],
errors: [{message: 'Function component is not an arrow function'}],
parser: parsers.BABEL_ESLINT
}, {
code: [
'module.exports = function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
output: [
'module.exports = function Hello(props) {',
' return <div/>',
'}'
].join('\n'),
options: [{unnamedComponents: 'arrow-function'}],
errors: [{message: 'Function component is not an arrow function'}],
parser: parsers.BABEL_ESLINT
}]
});

0 comments on commit ce1d96a

Please sign in to comment.