forked from jsx-eslint/eslint-plugin-react
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathforward-ref-uses-ref.js
100 lines (90 loc) · 3.06 KB
/
forward-ref-uses-ref.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/**
* @fileoverview Require all forwardRef components include a ref parameter
*/
'use strict';
const isParenthesized = require('../util/ast').isParenthesized;
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
const getMessageData = require('../util/message');
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
/**
* @param {ASTNode} node
* @returns {boolean} If the node represents the identifier `forwardRef`.
*/
function isForwardRefIdentifier(node) {
return node.type === 'Identifier' && node.name === 'forwardRef';
}
/**
* @param {ASTNode} node
* @returns {boolean} If the node represents a function call `forwardRef()` or `React.forwardRef()`.
*/
function isForwardRefCall(node) {
return (
node.type === 'CallExpression'
&& (
isForwardRefIdentifier(node.callee)
|| (node.callee.type === 'MemberExpression' && isForwardRefIdentifier(node.callee.property))
)
);
}
const messages = {
missingRefParameter: 'forwardRef is used with this component but no ref parameter is set',
addRefParameter: 'Add a ref parameter',
removeForwardRef: 'Remove forwardRef wrapper',
};
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
docs: {
description: 'Require all forwardRef components include a ref parameter',
category: 'Possible Errors',
recommended: false,
url: docsUrl('forward-ref-uses-ref'),
},
messages,
schema: [],
type: 'suggestion',
hasSuggestions: true,
},
create(context) {
const sourceCode = context.getSourceCode();
return {
'FunctionExpression, ArrowFunctionExpression'(node) {
if (!isForwardRefCall(node.parent)) {
return;
}
if (node.params.length === 1) {
report(context, messages.missingRefParameter, 'missingRefParameter', {
node,
suggest: [
Object.assign(
getMessageData('addRefParameter', messages.addRefParameter),
{
fix(fixer) {
const param = node.params[0];
// If using shorthand arrow function syntax, add parentheses around the new parameter pair
const shouldAddParentheses = node.type === 'ArrowFunctionExpression' && !isParenthesized(context, param);
return [].concat(
shouldAddParentheses ? fixer.insertTextBefore(param, '(') : [],
fixer.insertTextAfter(param, `, ref${shouldAddParentheses ? ')' : ''}`)
);
},
}
),
Object.assign(
getMessageData('removeForwardRef', messages.removeForwardRef),
{
fix(fixer) {
return fixer.replaceText(node.parent, sourceCode.getText(node));
},
}
),
],
});
}
},
};
},
};