Skip to content

Commit

Permalink
[new] support namedComponents option being an array
Browse files Browse the repository at this point in the history
This adds support to the `function-component-definition`  rule to have the
`namedComponents` rule be an array.
  • Loading branch information
petersendidit committed Nov 11, 2021
1 parent 21e01b6 commit f19a402
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 20 deletions.
5 changes: 3 additions & 2 deletions docs/rules/function-component-definition.md
Expand Up @@ -31,12 +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"`, `"arrow-function"`, or an array
containing any of those 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",
"namedComponents": "function-declaration" | "function-expression" | "arrow-function" | Array<string>,
"unnamedComponents": "function-expression" | "arrow-function"
}]
...
Expand Down
49 changes: 35 additions & 14 deletions lib/rules/function-component-definition.js
Expand Up @@ -109,23 +109,44 @@ module.exports = {

messages,

schema: [{
type: 'object',
properties: {
namedComponents: {
enum: ['function-declaration', 'arrow-function', 'function-expression'],
},
unnamedComponents: {
enum: ['arrow-function', 'function-expression'],
schema: [
{
type: 'object',
properties: {
namedComponents: {
oneOf: [
{
enum: [
'function-declaration',
'arrow-function',
'function-expression',
],
},
{
type: 'array',
items: {
type: 'string',
enum: [
'function-declaration',
'arrow-function',
'function-expression',
],
},
},
],
},
unnamedComponents: {
enum: ['arrow-function', 'function-expression'],
},
},
},
}],
],
},

create: Components.detect((context, components) => {
const configuration = context.options[0] || {};

const namedConfig = configuration.namedComponents || 'function-declaration';
const namedConfig = Array.isArray(configuration.namedComponents) ? configuration.namedComponents : [configuration.namedComponents] || ['function-declaration'];
const unnamedConfig = configuration.unnamedComponents || 'function-expression';

function getFixer(node, options) {
Expand Down Expand Up @@ -161,12 +182,12 @@ module.exports = {

if (node.parent && node.parent.type === 'Property') return;

if (hasName(node) && namedConfig !== functionType) {
if (hasName(node) && !namedConfig.includes(functionType)) {
report(node, {
messageId: namedConfig,
messageId: namedConfig[0],
fixerOptions: {
type: namedConfig,
template: NAMED_FUNCTION_TEMPLATES[namedConfig],
type: namedConfig[0],
template: NAMED_FUNCTION_TEMPLATES[namedConfig[0]],
range: node.type === 'FunctionDeclaration'
? node.range
: node.parent.parent.range,
Expand Down
78 changes: 74 additions & 4 deletions tests/lib/rules/function-component-definition.js
Expand Up @@ -78,8 +78,8 @@ ruleTester.run('function-component-definition', rule, {
options: [{ namedComponents: 'function-declaration' }],
},
{
// shouldn't trigger this rule since functions stating with a lowercase
// letter are not considered components
// shouldn't trigger this rule since functions stating with a lowercase
// letter are not considered components
code: `
const selectAvatarByUserId = (state, id) => {
const user = selectUserById(state, id)
Expand All @@ -89,8 +89,8 @@ ruleTester.run('function-component-definition', rule, {
options: [{ namedComponents: 'function-declaration' }],
},
{
// shouldn't trigger this rule since functions stating with a lowercase
// letter are not considered components
// shouldn't trigger this rule since functions stating with a lowercase
// letter are not considered components
code: `
function ensureValidSourceType(sourceType: string) {
switch (sourceType) {
Expand Down Expand Up @@ -346,6 +346,34 @@ ruleTester.run('function-component-definition', rule, {
`,
options: [{ unnamedComponents: 'function-expression' }],
},

{
code: 'function Hello(props) { return <div/> }',
options: [{ namedComponents: ['function-declaration', 'function-expression'] }],
},
{
code: 'var Hello = function(props) { return <div/> }',
options: [{ namedComponents: ['function-declaration', 'function-expression'] }],
},
{
code: 'var Foo = React.memo(function Foo() { return <p/> })',
options: [{ namedComponents: ['function-declaration', 'function-expression'] }],
},
{
code: 'function Hello(props: Test) { return <p/> }',
options: [{ namedComponents: ['function-declaration', 'function-expression'] }],
features: ['types'],
},
{
code: 'var Hello = function(props: Test) { return <p/> }',
options: [{ namedComponents: ['function-expression', 'function-expression'] }],
features: ['types'],
},
{
code: 'var Hello = (props: Test) => { return <p/> }',
options: [{ namedComponents: ['arrow-function', 'function-expression'] }],
features: ['types'],
},
]),

invalid: parsers.all([
Expand Down Expand Up @@ -879,5 +907,47 @@ ruleTester.run('function-component-definition', rule, {
options: [{ unnamedComponents: 'arrow-function' }],
errors: [{ messageId: 'arrow-function' }],
},
{
code: `
function Hello(props) {
return <div/>;
}
`,
output: `
var Hello = (props) => {
return <div/>;
}
`,
options: [{ namedComponents: ['arrow-function', 'function-expression'] }],
errors: [{ messageId: 'arrow-function' }],
},
{
code: `
var Hello = (props) => {
return <div/>;
};
`,
output: `
function Hello(props) {
return <div/>;
}
`,
options: [{ namedComponents: ['function-declaration', 'function-expression'] }],
errors: [{ messageId: 'function-declaration' }],
},
{
code: `
var Hello = (props) => {
return <div/>;
};
`,
output: `
var Hello = function(props) {
return <div/>;
}
`,
options: [{ namedComponents: ['function-expression', 'function-declaration'] }],
errors: [{ messageId: 'function-expression' }],
},
]),
});

0 comments on commit f19a402

Please sign in to comment.