diff --git a/.eslintrc b/.eslintrc
index 4991f200f2..d10247d296 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,82 +1,82 @@
{
- "root": true,
- "extends": ["airbnb-base", "plugin:eslint-plugin/recommended"],
- "plugins": ["eslint-plugin"],
- "env": {
- "es6": true,
- "node": true
- },
- "parserOptions": {
- "ecmaVersion": 6,
- "ecmaFeatures": {
- "jsx": true
- },
- "sourceType": "script",
- },
- "ignorePatterns": [
- "coverage/",
- ".nyc_output/",
- ],
- "rules": {
- "comma-dangle": [2, "always-multiline"],
- "object-shorthand": [2, "always", {
- "ignoreConstructors": false,
- "avoidQuotes": false, // this is the override vs airbnb
- }],
- "max-len": [2, 120, {
- "ignoreStrings": true,
- "ignoreTemplateLiterals": true,
- "ignoreComments": true,
- }],
- "consistent-return": 0,
+ "root": true,
+ "extends": ["airbnb-base", "plugin:eslint-plugin/recommended"],
+ "plugins": ["eslint-plugin"],
+ "env": {
+ "es6": true,
+ "node": true
+ },
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "sourceType": "script",
+ },
+ "ignorePatterns": [
+ "coverage/",
+ ".nyc_output/",
+ ],
+ "rules": {
+ "comma-dangle": [2, "always-multiline"],
+ "object-shorthand": [2, "always", {
+ "ignoreConstructors": false,
+ "avoidQuotes": false, // this is the override vs airbnb
+ }],
+ "max-len": [2, 120, {
+ "ignoreStrings": true,
+ "ignoreTemplateLiterals": true,
+ "ignoreComments": true,
+ }],
+ "consistent-return": 0,
- "prefer-destructuring": [2, { "array": false, "object": false }, { "enforceForRenamedProperties": false }],
- "prefer-object-spread": 0, // until node 8 is required
- "prefer-rest-params": 0, // until node 6 is required
- "prefer-spread": 0, // until node 6 is required
- "function-call-argument-newline": 1, // TODO: enable
- "function-paren-newline": 0,
- "no-plusplus": [2, {"allowForLoopAfterthoughts": true}],
- "no-param-reassign": 1,
- "no-restricted-syntax": [2, {
- "selector": "ObjectPattern",
- "message": "Object destructuring is not compatible with Node v4"
- }],
- "strict": [2, "safe"],
- "valid-jsdoc": [2, {
- "requireReturn": false,
- "requireParamDescription": false,
- "requireReturnDescription": false,
- }],
+ "prefer-destructuring": [2, { "array": false, "object": false }, { "enforceForRenamedProperties": false }],
+ "prefer-object-spread": 0, // until node 8 is required
+ "prefer-rest-params": 0, // until node 6 is required
+ "prefer-spread": 0, // until node 6 is required
+ "function-call-argument-newline": 1, // TODO: enable
+ "function-paren-newline": 0,
+ "no-plusplus": [2, {"allowForLoopAfterthoughts": true}],
+ "no-param-reassign": 1,
+ "no-restricted-syntax": [2, {
+ "selector": "ObjectPattern",
+ "message": "Object destructuring is not compatible with Node v4"
+ }],
+ "strict": [2, "safe"],
+ "valid-jsdoc": [2, {
+ "requireReturn": false,
+ "requireParamDescription": false,
+ "requireReturnDescription": false,
+ }],
- "eslint-plugin/consistent-output": 0,
- "eslint-plugin/require-meta-docs-description": [2, { "pattern": "^(Enforce|Require|Disallow)" }],
- "eslint-plugin/require-meta-schema": 0,
- "eslint-plugin/require-meta-type": 0
- },
- "overrides": [
- {
- "files": "tests/**",
- "rules": {
- "no-template-curly-in-string": 1,
- },
- },
- {
- "files": "markdown.config.js",
- "rules": {
- "no-console": 0,
- },
- },
- {
- "files": ".github/workflows/*.js",
- "parserOptions": {
- "ecmaVersion": 2019,
- },
- "rules": {
- "camelcase": 0,
- "no-console": 0,
- "no-restricted-syntax": 0,
- },
- },
- ],
-}
+ "eslint-plugin/consistent-output": 0,
+ "eslint-plugin/require-meta-docs-description": [2, { "pattern": "^(Enforce|Require|Disallow)" }],
+ "eslint-plugin/require-meta-schema": 0,
+ "eslint-plugin/require-meta-type": 0
+ },
+ "overrides": [
+ {
+ "files": "tests/**",
+ "rules": {
+ "no-template-curly-in-string": 1,
+ },
+ },
+ {
+ "files": "markdown.config.js",
+ "rules": {
+ "no-console": 0,
+ },
+ },
+ {
+ "files": ".github/workflows/*.js",
+ "parserOptions": {
+ "ecmaVersion": 2019,
+ },
+ "rules": {
+ "camelcase": 0,
+ "no-console": 0,
+ "no-restricted-syntax": 0,
+ },
+ },
+ ],
+ }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a358c59def..a2c437523f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,7 +7,12 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
### Fixed
* [`boolean-prop-naming`]: avoid a crash with a non-TSTypeReference type ([#3718][] @developer-bandi)
+* [`jsx-no-leaked-render`]: invalid report if left side is boolean ([#3746][] @akulsr0)
+* [`jsx-closing-bracket-location`]: message shows `{{details}}` when there are no details ([#3759][] @mdjermanovic)
+* [`no-invalid-html-attribute`]: ensure error messages are correct ([#3759][] @mdjermanovic, @ljharb)
+[#3759]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3759
+[#3746]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3746
[#3718]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3718
## [7.34.1] - 2024.03.15
diff --git a/lib/rules/boolean-prop-naming.js b/lib/rules/boolean-prop-naming.js
index 173b154354..f64da93242 100644
--- a/lib/rules/boolean-prop-naming.js
+++ b/lib/rules/boolean-prop-naming.js
@@ -13,6 +13,10 @@ const propsUtil = require('../util/props');
const docsUrl = require('../util/docsUrl');
const propWrapperUtil = require('../util/propWrapper');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -115,7 +119,7 @@ module.exports = {
// we can't get the name of the Flow object key name. So we have
// to hack around it for now.
if (node.type === 'ObjectTypeProperty') {
- return context.getSourceCode().getFirstToken(node).value;
+ return getSourceCode(context).getFirstToken(node).value;
}
return node.key.name;
@@ -308,7 +312,7 @@ module.exports = {
&& node.value.type === 'CallExpression'
&& propWrapperUtil.isPropWrapperFunction(
context,
- context.getSourceCode().getText(node.value.callee)
+ getText(context, node.value.callee)
)
) {
checkPropWrapperArguments(node, node.value.arguments);
@@ -334,7 +338,7 @@ module.exports = {
right.type === 'CallExpression'
&& propWrapperUtil.isPropWrapperFunction(
context,
- context.getSourceCode().getText(right.callee)
+ getText(context, right.callee)
)
) {
checkPropWrapperArguments(component.node, right.arguments);
diff --git a/lib/rules/button-has-type.js b/lib/rules/button-has-type.js
index 204a33c43e..d40596067d 100644
--- a/lib/rules/button-has-type.js
+++ b/lib/rules/button-has-type.js
@@ -135,7 +135,7 @@ module.exports = {
checkValue(node, propValue);
},
CallExpression(node) {
- if (!isCreateElement(node, context) || node.arguments.length < 1) {
+ if (!isCreateElement(context, node) || node.arguments.length < 1) {
return;
}
diff --git a/lib/rules/checked-requires-onchange-or-readonly.js b/lib/rules/checked-requires-onchange-or-readonly.js
index 420611fee5..c719644e1c 100644
--- a/lib/rules/checked-requires-onchange-or-readonly.js
+++ b/lib/rules/checked-requires-onchange-or-readonly.js
@@ -115,7 +115,7 @@ module.exports = {
checkAttributesAndReport(node, propSet);
},
CallExpression(node) {
- if (!isCreateElement(node, context)) {
+ if (!isCreateElement(context, node)) {
return;
}
diff --git a/lib/rules/destructuring-assignment.js b/lib/rules/destructuring-assignment.js
index e1a98d30a5..b4aa3da159 100644
--- a/lib/rules/destructuring-assignment.js
+++ b/lib/rules/destructuring-assignment.js
@@ -6,9 +6,13 @@
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const isAssignmentLHS = require('../util/ast').isAssignmentLHS;
const report = require('../util/report');
+const getScope = eslintUtil.getScope;
+const getText = eslintUtil.getText;
+
const DEFAULT_OPTION = 'always';
function createSFCParams() {
@@ -102,7 +106,7 @@ module.exports = {
function handleStatelessComponent(node) {
const params = evalParams(node.params);
- const SFCComponent = components.get(context.getScope(node).block);
+ const SFCComponent = components.get(getScope(context, node).block);
if (!SFCComponent) {
return;
}
@@ -120,7 +124,7 @@ module.exports = {
}
function handleStatelessComponentExit(node) {
- const SFCComponent = components.get(context.getScope(node).block);
+ const SFCComponent = components.get(getScope(context, node).block);
if (SFCComponent) {
sfcParams.pop();
}
@@ -192,7 +196,7 @@ module.exports = {
'FunctionExpression:exit': handleStatelessComponentExit,
MemberExpression(node) {
- let scope = context.getScope(node);
+ let scope = getScope(context, node);
let SFCComponent = components.get(scope.block);
while (!SFCComponent && scope.upper && scope.upper !== scope) {
SFCComponent = components.get(scope.upper.block);
@@ -210,7 +214,7 @@ module.exports = {
VariableDeclarator(node) {
const classComponent = utils.getParentComponent(node);
- const SFCComponent = components.get(context.getScope(node).block);
+ const SFCComponent = components.get(getScope(context, node).block);
const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern');
// let {foo} = props;
@@ -248,7 +252,7 @@ module.exports = {
&& destructureInSignature === 'always'
&& node.init.name === 'props'
) {
- const scopeSetProps = context.getScope().set.get('props');
+ const scopeSetProps = getScope(context, node).set.get('props');
const propsRefs = scopeSetProps && scopeSetProps.references;
if (!propsRefs) {
return;
@@ -269,7 +273,7 @@ module.exports = {
param.typeAnnotation ? param.typeAnnotation.range[0] : param.range[1],
];
return [
- fixer.replaceTextRange(replaceRange, context.getSourceCode().getText(node.id)),
+ fixer.replaceTextRange(replaceRange, getText(context, node.id)),
fixer.remove(node.parent),
];
},
diff --git a/lib/rules/forbid-elements.js b/lib/rules/forbid-elements.js
index c7f978a164..dd3ffa8f5d 100644
--- a/lib/rules/forbid-elements.js
+++ b/lib/rules/forbid-elements.js
@@ -7,6 +7,7 @@
const has = require('object.hasown/polyfill')();
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const isCreateElement = require('../util/isCreateElement');
const report = require('../util/report');
@@ -90,11 +91,11 @@ module.exports = {
return {
JSXOpeningElement(node) {
- reportIfForbidden(context.getSourceCode().getText(node.name), node.name);
+ reportIfForbidden(getText(context, node.name), node.name);
},
CallExpression(node) {
- if (!isCreateElement(node, context)) {
+ if (!isCreateElement(context, node)) {
return;
}
@@ -110,7 +111,7 @@ module.exports = {
} else if (argType === 'Literal' && /^[a-z][^.]*$/.test(argument.value)) {
reportIfForbidden(argument.value, argument);
} else if (argType === 'MemberExpression') {
- reportIfForbidden(context.getSourceCode().getText(argument), argument);
+ reportIfForbidden(getText(context, argument), argument);
}
},
};
diff --git a/lib/rules/forbid-prop-types.js b/lib/rules/forbid-prop-types.js
index 92f0f0f51f..b561b26da1 100644
--- a/lib/rules/forbid-prop-types.js
+++ b/lib/rules/forbid-prop-types.js
@@ -10,6 +10,7 @@ const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const propWrapperUtil = require('../util/propWrapper');
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Constants
@@ -162,7 +163,7 @@ module.exports = {
checkProperties(node.properties);
break;
case 'Identifier': {
- const propTypesObject = variableUtil.findVariableByName(context, node.name);
+ const propTypesObject = variableUtil.findVariableByName(context, node, node.name);
if (propTypesObject && propTypesObject.properties) {
checkProperties(propTypesObject.properties);
}
@@ -171,7 +172,7 @@ module.exports = {
case 'CallExpression': {
const innerNode = node.arguments && node.arguments[0];
if (
- propWrapperUtil.isPropWrapperFunction(context, context.getSourceCode().getText(node.callee))
+ propWrapperUtil.isPropWrapperFunction(context, getText(context, node.callee))
&& innerNode
) {
checkNode(innerNode);
diff --git a/lib/rules/function-component-definition.js b/lib/rules/function-component-definition.js
index 43e3154873..24ad3f48d7 100644
--- a/lib/rules/function-component-definition.js
+++ b/lib/rules/function-component-definition.js
@@ -9,6 +9,7 @@ const arrayIncludes = require('array-includes');
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const reportC = require('../util/report');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -181,8 +182,7 @@ module.exports = {
);
function getFixer(node, options) {
- const sourceCode = context.getSourceCode();
- const source = sourceCode.getText();
+ const source = getText(context);
const typeAnnotation = getTypeAnnotation(node, source);
diff --git a/lib/rules/hook-use-state.js b/lib/rules/hook-use-state.js
index a9deed4fd6..938802d82b 100644
--- a/lib/rules/hook-use-state.js
+++ b/lib/rules/hook-use-state.js
@@ -9,6 +9,7 @@ const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
const getMessageData = require('../util/message');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -160,14 +161,14 @@ module.exports = {
fix: (fixer) => [
// Add useMemo import, if necessary
useStateReactImportSpecifier
- && (!useMemoReactImportSpecifier || defaultReactImportName)
- && fixer.insertTextAfter(useStateReactImportSpecifier, ', useMemo'),
+ && (!useMemoReactImportSpecifier || defaultReactImportName)
+ && fixer.insertTextAfter(useStateReactImportSpecifier, ', useMemo'),
// Convert single-value destructure to simple assignment
fixer.replaceTextRange(node.parent.id.range, valueVariableName),
// Convert useState call to useMemo + arrow function + dependency array
fixer.replaceTextRange(
node.range,
- `${useMemoCode}(() => ${context.getSourceCode().getText(node.arguments[0])}, [])`
+ `${useMemoCode}(() => ${getText(context, node.arguments[0])}, [])`
),
].filter(Boolean),
}
diff --git a/lib/rules/iframe-missing-sandbox.js b/lib/rules/iframe-missing-sandbox.js
index 810e30b52b..7d8f234d97 100644
--- a/lib/rules/iframe-missing-sandbox.js
+++ b/lib/rules/iframe-missing-sandbox.js
@@ -131,7 +131,7 @@ module.exports = {
},
CallExpression(node) {
- if (isCreateElement(node, context) && node.arguments && node.arguments.length > 0) {
+ if (isCreateElement(context, node) && node.arguments && node.arguments.length > 0) {
const tag = node.arguments[0];
if (tag.type === 'Literal' && tag.value === 'iframe') {
checkProps(context, node);
diff --git a/lib/rules/jsx-closing-bracket-location.js b/lib/rules/jsx-closing-bracket-location.js
index 4816fd0068..26556d6117 100644
--- a/lib/rules/jsx-closing-bracket-location.js
+++ b/lib/rules/jsx-closing-bracket-location.js
@@ -7,6 +7,7 @@
const has = require('object.hasown/polyfill')();
const docsUrl = require('../util/docsUrl');
+const getSourceCode = require('../util/eslint').getSourceCode;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -170,11 +171,11 @@ module.exports = {
let spaces = [];
switch (expectedLocation) {
case 'props-aligned':
- indentation = /^\s*/.exec(context.getSourceCode().lines[tokens.lastProp.firstLine - 1])[0];
+ indentation = /^\s*/.exec(getSourceCode(context).lines[tokens.lastProp.firstLine - 1])[0];
break;
case 'tag-aligned':
case 'line-aligned':
- indentation = /^\s*/.exec(context.getSourceCode().lines[tokens.opening.line - 1])[0];
+ indentation = /^\s*/.exec(getSourceCode(context).lines[tokens.opening.line - 1])[0];
break;
default:
indentation = '';
@@ -194,7 +195,7 @@ module.exports = {
* prop and start of opening line.
*/
function getTokensLocations(node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const opening = sourceCode.getFirstToken(node).loc.start;
const closing = sourceCode.getLastTokens(node, node.selfClosing ? 2 : 1)[0].loc.start;
const tag = sourceCode.getFirstToken(node.name).loc.start;
@@ -266,7 +267,10 @@ module.exports = {
return;
}
- const data = { location: MESSAGE_LOCATION[expectedLocation] };
+ const data = {
+ location: MESSAGE_LOCATION[expectedLocation],
+ details: '',
+ };
const correctColumn = getCorrectColumn(tokens, expectedLocation);
if (correctColumn !== null) {
diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js
index 3eac3b47ea..083a60a0e3 100755
--- a/lib/rules/jsx-curly-brace-presence.js
+++ b/lib/rules/jsx-curly-brace-presence.js
@@ -11,6 +11,10 @@ const arrayIncludes = require('array-includes');
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Constants
@@ -176,8 +180,7 @@ module.exports = {
let textToReplace;
if (jsxUtil.isJSX(expression)) {
- const sourceCode = context.getSourceCode();
- textToReplace = sourceCode.getText(expression);
+ textToReplace = getText(context, expression);
} else {
const expressionType = expression && expression.type;
const parentType = JSXExpressionNode.parent.type;
@@ -188,9 +191,7 @@ module.exports = {
: expression.raw.slice(1, -1)
}"`;
} else if (jsxUtil.isJSX(expression)) {
- const sourceCode = context.getSourceCode();
-
- textToReplace = sourceCode.getText(expression);
+ textToReplace = getText(context, expression);
} else {
textToReplace = expressionType === 'TemplateLiteral'
? expression.quasis[0].value.cooked : expression.value;
@@ -207,7 +208,7 @@ module.exports = {
node: literalNode,
fix(fixer) {
if (jsxUtil.isJSX(literalNode)) {
- return fixer.replaceText(literalNode, `{${context.getSourceCode().getText(literalNode)}}`);
+ return fixer.replaceText(literalNode, `{${getText(context, literalNode)}}`);
}
// If a HTML entity name is found, bail out because it can be fixed
@@ -251,7 +252,7 @@ module.exports = {
const expression = JSXExpressionNode.expression;
const expressionType = expression.type;
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
// Curly braces containing comments are necessary
if (sourceCode.getCommentsInside && sourceCode.getCommentsInside(JSXExpressionNode).length > 0) {
return;
diff --git a/lib/rules/jsx-curly-newline.js b/lib/rules/jsx-curly-newline.js
index 068a7103da..046ff79582 100644
--- a/lib/rules/jsx-curly-newline.js
+++ b/lib/rules/jsx-curly-newline.js
@@ -5,8 +5,12 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const report = require('../util/report');
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
+
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
@@ -77,7 +81,7 @@ module.exports = {
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const option = getNormalizedOption(context);
// ----------------------------------------------------------------------
@@ -130,8 +134,7 @@ module.exports = {
report(context, messages.unexpectedAfter, 'unexpectedAfter', {
node: leftCurly,
fix(fixer) {
- return sourceCode
- .getText()
+ return getText(context)
.slice(leftCurly.range[1], tokenAfterLeftCurly.range[0])
.trim()
? null // If there is a comment between the { and the first element, don't do a fix.
@@ -149,8 +152,7 @@ module.exports = {
report(context, messages.unexpectedBefore, 'unexpectedBefore', {
node: rightCurly,
fix(fixer) {
- return sourceCode
- .getText()
+ return getText(context)
.slice(tokenBeforeRightCurly.range[1], rightCurly.range[0])
.trim()
? null // If there is a comment between the last element and the }, don't do a fix.
diff --git a/lib/rules/jsx-curly-spacing.js b/lib/rules/jsx-curly-spacing.js
index 094e612c7d..8d504f1d20 100644
--- a/lib/rules/jsx-curly-spacing.js
+++ b/lib/rules/jsx-curly-spacing.js
@@ -13,6 +13,7 @@
const has = require('object.hasown/polyfill')();
const docsUrl = require('../util/docsUrl');
+const getSourceCode = require('../util/eslint').getSourceCode;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -175,7 +176,7 @@ module.exports = {
* @returns {Object|*|{range, text}}
*/
function fixByTrimmingWhitespace(fixer, fromLoc, toLoc, mode, spacing) {
- let replacementText = context.getSourceCode().text.slice(fromLoc, toLoc);
+ let replacementText = getSourceCode(context).text.slice(fromLoc, toLoc);
if (mode === 'start') {
replacementText = replacementText.replace(/^\s+/gm, '');
} else {
@@ -206,7 +207,7 @@ module.exports = {
token: token.value,
},
fix(fixer) {
- const nextToken = context.getSourceCode().getTokenAfter(token);
+ const nextToken = getSourceCode(context).getTokenAfter(token);
return fixByTrimmingWhitespace(fixer, token.range[1], nextToken.range[0], 'start', spacing);
},
});
@@ -227,7 +228,7 @@ module.exports = {
token: token.value,
},
fix(fixer) {
- const previousToken = context.getSourceCode().getTokenBefore(token);
+ const previousToken = getSourceCode(context).getTokenBefore(token);
return fixByTrimmingWhitespace(fixer, previousToken.range[1], token.range[0], 'end', spacing);
},
});
@@ -247,7 +248,7 @@ module.exports = {
token: token.value,
},
fix(fixer) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const nextToken = sourceCode.getTokenAfter(token);
let nextComment;
@@ -284,7 +285,7 @@ module.exports = {
token: token.value,
},
fix(fixer) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const previousToken = sourceCode.getTokenBefore(token);
let previousComment;
@@ -370,7 +371,7 @@ module.exports = {
return;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const first = sourceCode.getFirstToken(node);
const last = sourceCode.getLastToken(node);
let second = sourceCode.getTokenAfter(first, { includeComments: true });
diff --git a/lib/rules/jsx-equals-spacing.js b/lib/rules/jsx-equals-spacing.js
index e5eefd2bb5..3424961a9d 100644
--- a/lib/rules/jsx-equals-spacing.js
+++ b/lib/rules/jsx-equals-spacing.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getSourceCode = require('../util/eslint').getSourceCode;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -59,7 +60,7 @@ module.exports = {
return;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const equalToken = sourceCode.getTokenAfter(attrNode.name);
const spacedBefore = sourceCode.isSpaceBetweenTokens(attrNode.name, equalToken);
const spacedAfter = sourceCode.isSpaceBetweenTokens(equalToken, attrNode.value);
diff --git a/lib/rules/jsx-fragments.js b/lib/rules/jsx-fragments.js
index 38b4dd8b4b..4dadb076d7 100644
--- a/lib/rules/jsx-fragments.js
+++ b/lib/rules/jsx-fragments.js
@@ -11,6 +11,7 @@ const variableUtil = require('../util/variable');
const testReactVersion = require('../util/version').testReactVersion;
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -65,36 +66,34 @@ module.exports = {
}
function getFixerToLong(jsxFragment) {
- const sourceCode = context.getSourceCode();
if (!jsxFragment.closingFragment || !jsxFragment.openingFragment) {
// the old TS parser crashes here
// TODO: FIXME: can we fake these two descriptors?
return null;
}
return function fix(fixer) {
- let source = sourceCode.getText();
+ let source = getText(context);
source = replaceNode(source, jsxFragment.closingFragment, closeFragLong);
source = replaceNode(source, jsxFragment.openingFragment, openFragLong);
- const lengthDiff = openFragLong.length - sourceCode.getText(jsxFragment.openingFragment).length
- + closeFragLong.length - sourceCode.getText(jsxFragment.closingFragment).length;
+ const lengthDiff = openFragLong.length - getText(context, jsxFragment.openingFragment).length
+ + closeFragLong.length - getText(context, jsxFragment.closingFragment).length;
const range = jsxFragment.range;
return fixer.replaceTextRange(range, source.slice(range[0], range[1] + lengthDiff));
};
}
function getFixerToShort(jsxElement) {
- const sourceCode = context.getSourceCode();
return function fix(fixer) {
- let source = sourceCode.getText();
+ let source = getText(context);
let lengthDiff;
if (jsxElement.closingElement) {
source = replaceNode(source, jsxElement.closingElement, closeFragShort);
source = replaceNode(source, jsxElement.openingElement, openFragShort);
- lengthDiff = sourceCode.getText(jsxElement.openingElement).length - openFragShort.length
- + sourceCode.getText(jsxElement.closingElement).length - closeFragShort.length;
+ lengthDiff = getText(context, jsxElement.openingElement).length - openFragShort.length
+ + getText(context, jsxElement.closingElement).length - closeFragShort.length;
} else {
source = replaceNode(source, jsxElement.openingElement, `${openFragShort}${closeFragShort}`);
- lengthDiff = sourceCode.getText(jsxElement.openingElement).length - openFragShort.length
+ lengthDiff = getText(context, jsxElement.openingElement).length - openFragShort.length
- closeFragShort.length;
}
@@ -103,8 +102,8 @@ module.exports = {
};
}
- function refersToReactFragment(name) {
- const variableInit = variableUtil.findVariableByName(context, name);
+ function refersToReactFragment(node, name) {
+ const variableInit = variableUtil.findVariableByName(context, node, name);
if (!variableInit) {
return false;
}
@@ -185,7 +184,7 @@ module.exports = {
const openingEl = node.openingElement;
const elName = elementType(openingEl);
- if (fragmentNames.has(elName) || refersToReactFragment(elName)) {
+ if (fragmentNames.has(elName) || refersToReactFragment(node, elName)) {
if (reportOnReactVersion(node)) {
return;
}
diff --git a/lib/rules/jsx-handler-names.js b/lib/rules/jsx-handler-names.js
index 8ff56fb47a..d839073a52 100644
--- a/lib/rules/jsx-handler-names.js
+++ b/lib/rules/jsx-handler-names.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -129,10 +130,10 @@ module.exports = {
const propKey = typeof node.name === 'object' ? node.name.name : node.name;
const expression = node.value.expression;
- const propValue = context.getSourceCode()
- .getText(checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression)
- .replace(/\s*/g, '')
- .replace(/^this\.|.*::/, '');
+ const propValue = getText(
+ context,
+ checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression
+ ).replace(/\s*/g, '').replace(/^this\.|.*::/, '');
if (propKey === 'ref') {
return;
diff --git a/lib/rules/jsx-indent-props.js b/lib/rules/jsx-indent-props.js
index 0d971ac7ac..050e721df3 100644
--- a/lib/rules/jsx-indent-props.js
+++ b/lib/rules/jsx-indent-props.js
@@ -32,6 +32,7 @@
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const reportC = require('../util/report');
// ------------------------------------------------------------------------------
@@ -140,7 +141,7 @@ module.exports = {
* @return {Number} Indent
*/
function getNodeIndent(node) {
- let src = context.getSourceCode().getText(node, node.loc.start.column + extraColumnStart);
+ let src = getText(context, node, node.loc.start.column + extraColumnStart);
const lines = src.split('\n');
src = lines[0];
diff --git a/lib/rules/jsx-indent.js b/lib/rules/jsx-indent.js
index 9a86e6c03a..27397172c8 100644
--- a/lib/rules/jsx-indent.js
+++ b/lib/rules/jsx-indent.js
@@ -36,6 +36,10 @@ const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const reportC = require('../util/report');
const jsxUtil = require('../util/jsx');
+const eslintUtil = require('../util/eslint');
+
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -116,7 +120,7 @@ module.exports = {
}
if (node.type === 'ReturnStatement') {
- const raw = context.getSourceCode().getText(node);
+ const raw = getText(context, node);
const lines = raw.split('\n');
if (lines.length > 1) {
return function fix(fixer) {
@@ -168,7 +172,7 @@ module.exports = {
* @return {Number} Indent
*/
function getNodeIndent(node, byLastLine, excludeCommas) {
- let src = context.getSourceCode().getText(node, node.loc.start.column + extraColumnStart);
+ let src = getText(context, node, node.loc.start.column + extraColumnStart);
const lines = src.split('\n');
if (byLastLine) {
src = lines[lines.length - 1];
@@ -215,7 +219,7 @@ module.exports = {
&& node.parent.parent
&& node.parent.parent.type === 'ConditionalExpression'
&& node.parent.parent.alternate === node.parent
- && context.getSourceCode().getTokenBefore(node).value !== '('
+ && getSourceCode(context).getTokenBefore(node).value !== '('
);
}
@@ -334,7 +338,7 @@ module.exports = {
}
function handleOpeningElement(node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
let prevToken = sourceCode.getTokenBefore(node);
if (!prevToken) {
return;
@@ -377,7 +381,7 @@ module.exports = {
return;
}
const nameIndent = getNodeIndent(node.name);
- const lastToken = context.getSourceCode().getLastToken(node.value);
+ const lastToken = getSourceCode(context).getLastToken(node.value);
const firstInLine = astUtil.getFirstNodeInLine(context, lastToken);
const indent = node.name.loc.start.line === firstInLine.loc.start.line ? 0 : nameIndent;
checkNodesIndent(firstInLine, indent);
@@ -424,7 +428,7 @@ module.exports = {
}
if (
!fn
- || !jsxUtil.isReturningJSX(node, context, true)
+ || !jsxUtil.isReturningJSX(context, node, true)
) {
return;
}
diff --git a/lib/rules/jsx-key.js b/lib/rules/jsx-key.js
index 7ea874d0ae..feee7ad5a0 100644
--- a/lib/rules/jsx-key.js
+++ b/lib/rules/jsx-key.js
@@ -12,6 +12,7 @@ const docsUrl = require('../util/docsUrl');
const pragmaUtil = require('../util/pragma');
const report = require('../util/report');
const astUtil = require('../util/ast');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -213,7 +214,7 @@ module.exports = {
}
} else {
keys.forEach((attr) => {
- const value = context.getSourceCode().getText(attr.value);
+ const value = getText(context, attr.value);
if (!map[value]) { map[value] = []; }
map[value].push(attr);
diff --git a/lib/rules/jsx-max-depth.js b/lib/rules/jsx-max-depth.js
index 01698264c7..6b1db78189 100644
--- a/lib/rules/jsx-max-depth.js
+++ b/lib/rules/jsx-max-depth.js
@@ -150,7 +150,7 @@ module.exports = {
return;
}
- const variables = variableUtil.variablesInScope(context);
+ const variables = variableUtil.variablesInScope(context, node);
const element = findJSXElementOrFragment(variables, node.expression.name, []);
if (element) {
diff --git a/lib/rules/jsx-max-props-per-line.js b/lib/rules/jsx-max-props-per-line.js
index 95d7942f9a..eebf7f0f33 100644
--- a/lib/rules/jsx-max-props-per-line.js
+++ b/lib/rules/jsx-max-props-per-line.js
@@ -6,11 +6,12 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const report = require('../util/report');
function getPropName(context, propNode) {
if (propNode.type === 'JSXSpreadAttribute') {
- return context.getSourceCode().getText(propNode.argument);
+ return getText(context, propNode.argument);
}
return propNode.name.name;
}
@@ -87,7 +88,6 @@ module.exports = {
};
function generateFixFunction(line, max) {
- const sourceCode = context.getSourceCode();
const output = [];
const front = line[0].range[0];
const back = line[line.length - 1].range[1];
@@ -96,9 +96,9 @@ module.exports = {
const nodes = line.slice(i, i + max);
output.push(nodes.reduce((prev, curr) => {
if (prev === '') {
- return sourceCode.getText(curr);
+ return getText(context, curr);
}
- return `${prev} ${sourceCode.getText(curr)}`;
+ return `${prev} ${getText(context, curr)}`;
}, ''));
}
diff --git a/lib/rules/jsx-newline.js b/lib/rules/jsx-newline.js
index 966bf6a34b..7fd395c72f 100644
--- a/lib/rules/jsx-newline.js
+++ b/lib/rules/jsx-newline.js
@@ -7,6 +7,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -71,10 +72,9 @@ module.exports = {
},
create(context) {
const jsxElementParents = new Set();
- const sourceCode = context.getSourceCode();
function isBlockCommentInCurlyBraces(element) {
- const elementRawValue = sourceCode.getText(element);
+ const elementRawValue = getText(context, element);
return /^\s*{\/\*/.test(elementRawValue);
}
@@ -122,8 +122,7 @@ module.exports = {
fix(fixer) {
return fixer.replaceText(
firstAdjacentSibling,
- sourceCode.getText(firstAdjacentSibling)
- .replace(regex, replacement)
+ getText(context, firstAdjacentSibling).replace(regex, replacement)
);
},
});
@@ -151,8 +150,7 @@ module.exports = {
return fixer.replaceText(
firstAdjacentSibling,
// double or remove the last newline
- sourceCode.getText(firstAdjacentSibling)
- .replace(regex, replacement)
+ getText(context, firstAdjacentSibling).replace(regex, replacement)
);
},
});
diff --git a/lib/rules/jsx-no-bind.js b/lib/rules/jsx-no-bind.js
index 17e56e2e04..4d6e349d25 100644
--- a/lib/rules/jsx-no-bind.js
+++ b/lib/rules/jsx-no-bind.js
@@ -11,6 +11,7 @@ const propName = require('jsx-ast-utils/propName');
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
+const getAncestors = require('../util/eslint').getAncestors;
// -----------------------------------------------------------------------------
// Rule Definition
@@ -123,7 +124,7 @@ module.exports = {
}
function getBlockStatementAncestors(node) {
- return context.getAncestors(node).filter(
+ return getAncestors(context, node).filter(
(ancestor) => ancestor.type === 'BlockStatement'
).reverse();
}
diff --git a/lib/rules/jsx-no-comment-textnodes.js b/lib/rules/jsx-no-comment-textnodes.js
index 2a90467d3f..de4d288c37 100644
--- a/lib/rules/jsx-no-comment-textnodes.js
+++ b/lib/rules/jsx-no-comment-textnodes.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -16,9 +17,14 @@ const messages = {
putCommentInBraces: 'Comments inside children section of tag should be placed inside braces',
};
-function checkText(node, context) {
+/**
+ * @param {Context} context
+ * @param {ASTNode} node
+ * @returns {void}
+ */
+function checkText(context, node) {
// since babel-eslint has the wrong node.raw, we'll get the source text
- const rawValue = context.getSourceCode().getText(node);
+ const rawValue = getText(context, node);
if (/^\s*\/(\/|\*)/m.test(rawValue)) {
// inside component, e.g.
literal
if (
@@ -55,10 +61,10 @@ module.exports = {
return {
Literal(node) {
- checkText(node, context);
+ checkText(context, node);
},
JSXText(node) {
- checkText(node, context);
+ checkText(context, node);
},
};
},
diff --git a/lib/rules/jsx-no-constructed-context-values.js b/lib/rules/jsx-no-constructed-context-values.js
index f28c51fd4a..2e9ef93422 100644
--- a/lib/rules/jsx-no-constructed-context-values.js
+++ b/lib/rules/jsx-no-constructed-context-values.js
@@ -8,6 +8,7 @@
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
+const getScope = require('../util/eslint').getScope;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -139,7 +140,7 @@ module.exports = {
url: docsUrl('jsx-no-constructed-context-values'),
},
messages,
- schema: {},
+ schema: false,
},
// eslint-disable-next-line arrow-body-style
@@ -180,7 +181,7 @@ module.exports = {
}
const valueExpression = valueNode.expression;
- const invocationScope = context.getScope();
+ const invocationScope = getScope(context, node);
// Check if the value prop is a construction
const constructInfo = isConstruction(valueExpression, invocationScope);
diff --git a/lib/rules/jsx-no-leaked-render.js b/lib/rules/jsx-no-leaked-render.js
index a6bf54b72a..f7eea1ad52 100644
--- a/lib/rules/jsx-no-leaked-render.js
+++ b/lib/rules/jsx-no-leaked-render.js
@@ -8,8 +8,10 @@
const find = require('es-iterator-helpers/Iterator.prototype.find');
const from = require('es-iterator-helpers/Iterator.from');
+const getText = require('../util/eslint').getText;
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const variableUtil = require('../util/variable');
const testReactVersion = require('../util/version').testReactVersion;
const isParenthesized = require('../util/ast').isParenthesized;
@@ -54,13 +56,12 @@ function extractExpressionBetweenLogicalAnds(node) {
}
function ruleFixer(context, fixStrategy, fixer, reportedNode, leftNode, rightNode) {
- const sourceCode = context.getSourceCode();
- const rightSideText = sourceCode.getText(rightNode);
+ const rightSideText = getText(context, rightNode);
if (fixStrategy === COERCE_STRATEGY) {
const expressions = extractExpressionBetweenLogicalAnds(leftNode);
const newText = expressions.map((node) => {
- let nodeText = sourceCode.getText(node);
+ let nodeText = getText(context, node);
if (isParenthesized(context, node)) {
nodeText = `(${nodeText})`;
}
@@ -98,7 +99,7 @@ function ruleFixer(context, fixStrategy, fixer, reportedNode, leftNode, rightNod
}
if (fixStrategy === TERNARY_STRATEGY) {
- let leftSideText = sourceCode.getText(trimLeftNode(leftNode));
+ let leftSideText = getText(context, trimLeftNode(leftNode));
if (isParenthesized(context, leftNode)) {
leftSideText = `(${leftSideText})`;
}
@@ -160,6 +161,17 @@ module.exports = {
if (isCoerceValidLeftSide || getIsCoerceValidNestedLogicalExpression(leftSide)) {
return;
}
+ const variables = variableUtil.variablesInScope(context, node);
+ const leftSideVar = variableUtil.getVariable(variables, leftSide.name);
+ if (leftSideVar) {
+ const leftSideValue = leftSideVar.defs
+ && leftSideVar.defs.length
+ && leftSideVar.defs[0].node.init
+ && leftSideVar.defs[0].node.init.value;
+ if (typeof leftSideValue === 'boolean') {
+ return;
+ }
+ }
}
if (testReactVersion(context, '>= 18') && leftSide.type === 'Literal' && leftSide.value === '') {
diff --git a/lib/rules/jsx-no-literals.js b/lib/rules/jsx-no-literals.js
index ca4f3a8d46..d7f43ab05c 100644
--- a/lib/rules/jsx-no-literals.js
+++ b/lib/rules/jsx-no-literals.js
@@ -11,6 +11,7 @@ const map = require('es-iterator-helpers/Iterator.prototype.map');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -149,7 +150,7 @@ module.exports = {
report(context, messages[messageId], messageId, {
node,
data: {
- text: context.getSourceCode().getText(node).trim(),
+ text: getText(context, node).trim(),
},
});
}
diff --git a/lib/rules/jsx-no-undef.js b/lib/rules/jsx-no-undef.js
index 3a1f4dbc5f..a15de8e854 100644
--- a/lib/rules/jsx-no-undef.js
+++ b/lib/rules/jsx-no-undef.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
@@ -50,8 +51,8 @@ module.exports = {
* @returns {void}
*/
function checkIdentifierInJSX(node) {
- let scope = context.getScope();
- const sourceCode = context.getSourceCode();
+ let scope = eslintUtil.getScope(context, node);
+ const sourceCode = eslintUtil.getSourceCode(context);
const sourceType = sourceCode.ast.sourceType;
const scopeUpperBound = !allowGlobals && sourceType === 'module' ? 'module' : 'global';
let variables = scope.variables;
diff --git a/lib/rules/jsx-no-useless-fragment.js b/lib/rules/jsx-no-useless-fragment.js
index 303b9719e5..4c2886469f 100644
--- a/lib/rules/jsx-no-useless-fragment.js
+++ b/lib/rules/jsx-no-useless-fragment.js
@@ -10,6 +10,7 @@ const pragmaUtil = require('../util/pragma');
const jsxUtil = require('../util/jsx');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
function isJSXText(node) {
return !!node && (node.type === 'JSXText' || node.type === 'Literal');
@@ -216,7 +217,7 @@ module.exports = {
const opener = node.type === 'JSXFragment' ? node.openingFragment : node.openingElement;
const closer = node.type === 'JSXFragment' ? node.closingFragment : node.closingElement;
- const childrenText = opener.selfClosing ? '' : context.getSourceCode().getText().slice(opener.range[1], closer.range[0]);
+ const childrenText = opener.selfClosing ? '' : getText(context).slice(opener.range[1], closer.range[0]);
return fixer.replaceText(node, trimLikeReact(childrenText));
};
diff --git a/lib/rules/jsx-one-expression-per-line.js b/lib/rules/jsx-one-expression-per-line.js
index f18fa919e1..3ae61e3d96 100644
--- a/lib/rules/jsx-one-expression-per-line.js
+++ b/lib/rules/jsx-one-expression-per-line.js
@@ -6,9 +6,13 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
+
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
@@ -55,8 +59,12 @@ module.exports = {
return `${node.loc.start.line},${node.loc.start.column}`;
}
+ /**
+ * @param {ASTNode} n
+ * @returns {string}
+ */
function nodeDescriptor(n) {
- return n.openingElement ? n.openingElement.name.name : context.getSourceCode().getText(n).replace(/\n/g, '');
+ return n.openingElement ? n.openingElement.name.name : getText(context, n).replace(/\n/g, '');
}
function handleJSX(node) {
@@ -163,20 +171,20 @@ module.exports = {
function spaceBetweenPrev() {
return ((prevChild.type === 'Literal' || prevChild.type === 'JSXText') && / $/.test(prevChild.raw))
|| ((child.type === 'Literal' || child.type === 'JSXText') && /^ /.test(child.raw))
- || context.getSourceCode().isSpaceBetweenTokens(prevChild, child);
+ || getSourceCode(context).isSpaceBetweenTokens(prevChild, child);
}
function spaceBetweenNext() {
return ((nextChild.type === 'Literal' || nextChild.type === 'JSXText') && /^ /.test(nextChild.raw))
|| ((child.type === 'Literal' || child.type === 'JSXText') && / $/.test(child.raw))
- || context.getSourceCode().isSpaceBetweenTokens(child, nextChild);
+ || getSourceCode(context).isSpaceBetweenTokens(child, nextChild);
}
if (!prevChild && !nextChild) {
return;
}
- const source = context.getSourceCode().getText(child);
+ const source = getText(context, child);
const leadingSpace = !!(prevChild && spaceBetweenPrev());
const trailingSpace = !!(nextChild && spaceBetweenNext());
const leadingNewLine = !!prevChild;
diff --git a/lib/rules/jsx-props-no-multi-spaces.js b/lib/rules/jsx-props-no-multi-spaces.js
index edd122c413..ce80338cd8 100644
--- a/lib/rules/jsx-props-no-multi-spaces.js
+++ b/lib/rules/jsx-props-no-multi-spaces.js
@@ -6,8 +6,12 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const report = require('../util/report');
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
+
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
@@ -34,12 +38,12 @@ module.exports = {
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
function getPropName(propNode) {
switch (propNode.type) {
case 'JSXSpreadAttribute':
- return context.getSourceCode().getText(propNode.argument);
+ return getText(context, propNode.argument);
case 'JSXIdentifier':
return propNode.name;
case 'JSXMemberExpression':
@@ -47,7 +51,7 @@ module.exports = {
default:
return propNode.name
? propNode.name.name
- : `${context.getSourceCode().getText(propNode.object)}.${propNode.property.name}`; // needed for typescript-eslint parser
+ : `${getText(context, propNode.object)}.${propNode.property.name}`; // needed for typescript-eslint parser
}
}
@@ -82,7 +86,7 @@ module.exports = {
return;
}
- const between = context.getSourceCode().text.slice(prev.range[1], node.range[0]);
+ const between = getSourceCode(context).text.slice(prev.range[1], node.range[0]);
if (between !== ' ') {
report(context, messages.onlyOneSpace, 'onlyOneSpace', {
diff --git a/lib/rules/jsx-sort-default-props.js b/lib/rules/jsx-sort-default-props.js
index f35e40dc5f..89b7bb64cc 100644
--- a/lib/rules/jsx-sort-default-props.js
+++ b/lib/rules/jsx-sort-default-props.js
@@ -10,6 +10,10 @@ const variableUtil = require('../util/variable');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
const log = require('../util/log');
+const eslintUtil = require('../util/eslint');
+
+const getFirstTokens = eslintUtil.getFirstTokens;
+const getText = eslintUtil.getText;
let isWarnedForDeprecation = false;
@@ -65,7 +69,7 @@ module.exports = {
// (babel-eslint@5 does not expose property name so we have to rely on tokens)
}
if (node.type === 'ClassProperty') {
- const tokens = context.getSourceCode().getFirstTokens(node, 2);
+ const tokens = getFirstTokens(context, node, 2);
return tokens[1] && tokens[1].type === 'Identifier' ? tokens[1].value : tokens[0].value;
}
return '';
@@ -82,16 +86,19 @@ module.exports = {
}
function getKey(node) {
- return context.getSourceCode().getText(node.key || node.argument);
+ return getText(context, node.key || node.argument);
}
/**
* Find a variable by name in the current scope.
+ * @param {ASTNode} node The node to look for.
* @param {string} name Name of the variable to look for.
* @returns {ASTNode|null} Return null if the variable could not be found, ASTNode otherwise.
*/
- function findVariableByName(name) {
- const variable = variableUtil.variablesInScope(context).find((item) => item.name === name);
+ function findVariableByName(node, name) {
+ const variable = variableUtil
+ .variablesInScope(context, node)
+ .find((item) => item.name === name);
if (!variable || !variable.defs[0] || !variable.defs[0].node) {
return null;
@@ -111,7 +118,7 @@ module.exports = {
*/
function checkSorted(declarations) {
// function fix(fixer) {
- // return propTypesSortUtil.fixPropTypesSort(fixer, context, declarations, ignoreCase);
+ // return propTypesSortUtil.fixPropTypesSort(context, fixer, declarations, ignoreCase);
// }
declarations.reduce((prev, curr, idx, decls) => {
@@ -147,7 +154,7 @@ module.exports = {
if (node.type === 'ObjectExpression') {
checkSorted(node.properties);
} else if (node.type === 'Identifier') {
- const propTypesObject = findVariableByName(node.name);
+ const propTypesObject = findVariableByName(node, node.name);
if (propTypesObject && propTypesObject.properties) {
checkSorted(propTypesObject.properties);
}
diff --git a/lib/rules/jsx-sort-props.js b/lib/rules/jsx-sort-props.js
index 3ca1724ebe..f811e16cf7 100644
--- a/lib/rules/jsx-sort-props.js
+++ b/lib/rules/jsx-sort-props.js
@@ -12,6 +12,10 @@ const toSorted = require('array.prototype.tosorted');
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getText = eslintUtil.getText;
+const getSourceCode = eslintUtil.getSourceCode;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -141,7 +145,7 @@ function contextCompare(a, b, options) {
* @return {Array>}
*/
function getGroupsOfSortableAttributes(attributes, context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const sortableAttributeGroups = [];
let groupCount = 0;
@@ -212,7 +216,6 @@ function getGroupsOfSortableAttributes(attributes, context) {
}
function generateFixerFunction(node, context, reservedList) {
- const sourceCode = context.getSourceCode();
const attributes = node.attributes.slice(0);
const configuration = context.options[0] || {};
const ignoreCase = configuration.ignoreCase || false;
@@ -245,7 +248,7 @@ function generateFixerFunction(node, context, reservedList) {
return function fixFunction(fixer) {
const fixers = [];
- let source = sourceCode.getText();
+ let source = getText(context);
sortableAttributeGroups.forEach((sortableGroup, ii) => {
sortableGroup.forEach((attr, jj) => {
diff --git a/lib/rules/jsx-space-before-closing.js b/lib/rules/jsx-space-before-closing.js
index f1e1e61d96..e923adfbd3 100644
--- a/lib/rules/jsx-space-before-closing.js
+++ b/lib/rules/jsx-space-before-closing.js
@@ -10,6 +10,7 @@ const getTokenBeforeClosingBracket = require('../util/getTokenBeforeClosingBrack
const docsUrl = require('../util/docsUrl');
const log = require('../util/log');
const report = require('../util/report');
+const getSourceCode = require('../util/eslint').getSourceCode;
let isWarnedForDeprecation = false;
@@ -54,7 +55,7 @@ module.exports = {
return;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const leftToken = getTokenBeforeClosingBracket(node);
const closingSlash = sourceCode.getTokenAfter(leftToken);
diff --git a/lib/rules/jsx-tag-spacing.js b/lib/rules/jsx-tag-spacing.js
index 9cc18e8c37..ac7c693278 100644
--- a/lib/rules/jsx-tag-spacing.js
+++ b/lib/rules/jsx-tag-spacing.js
@@ -8,6 +8,10 @@
const getTokenBeforeClosingBracket = require('../util/getTokenBeforeClosingBracket');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getFirstTokens = eslintUtil.getFirstTokens;
+const getSourceCode = eslintUtil.getSourceCode;
const messages = {
selfCloseSlashNoSpace: 'Whitespace is forbidden between `/` and `>`; write `/>`',
@@ -29,7 +33,7 @@ const messages = {
// ------------------------------------------------------------------------------
function validateClosingSlash(context, node, option) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
let adjacent;
@@ -64,7 +68,7 @@ function validateClosingSlash(context, node, option) {
});
}
} else {
- const firstTokens = sourceCode.getFirstTokens(node, 2);
+ const firstTokens = getFirstTokens(context, node, 2);
adjacent = !sourceCode.isSpaceBetweenTokens(firstTokens[0], firstTokens[1]);
@@ -97,7 +101,7 @@ function validateClosingSlash(context, node, option) {
}
function validateBeforeSelfClosing(context, node, option) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const leftToken = getTokenBeforeClosingBracket(node);
const closingSlash = sourceCode.getTokenAfter(leftToken);
@@ -141,7 +145,7 @@ function validateBeforeSelfClosing(context, node, option) {
}
function validateAfterOpening(context, node, option) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const openingToken = sourceCode.getTokenBefore(node.name);
if (option === 'allow-multiline') {
@@ -182,7 +186,7 @@ function validateAfterOpening(context, node, option) {
function validateBeforeClosing(context, node, option) {
// Don't enforce this rule for self closing tags
if (!node.selfClosing) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const leftToken = option === 'proportional-always'
? getTokenBeforeClosingBracket(node)
: sourceCode.getLastTokens(node, 2)[0];
diff --git a/lib/rules/jsx-uses-react.js b/lib/rules/jsx-uses-react.js
index bf06f508f8..5d64f76cd8 100644
--- a/lib/rules/jsx-uses-react.js
+++ b/lib/rules/jsx-uses-react.js
@@ -7,6 +7,7 @@
const pragmaUtil = require('../util/pragma');
const docsUrl = require('../util/docsUrl');
+const markVariableAsUsed = require('../util/eslint').markVariableAsUsed;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -29,8 +30,12 @@ module.exports = {
const pragma = pragmaUtil.getFromContext(context);
const fragment = pragmaUtil.getFragmentFromContext(context);
- function handleOpeningElement() {
- context.markVariableAsUsed(pragma);
+ /**
+ * @param {ASTNode} node
+ * @returns {void}
+ */
+ function handleOpeningElement(node) {
+ markVariableAsUsed(pragma, node, context);
}
// --------------------------------------------------------------------------
// Public
@@ -39,8 +44,8 @@ module.exports = {
return {
JSXOpeningElement: handleOpeningElement,
JSXOpeningFragment: handleOpeningElement,
- JSXFragment() {
- context.markVariableAsUsed(fragment);
+ JSXFragment(node) {
+ markVariableAsUsed(fragment, node, context);
},
};
},
diff --git a/lib/rules/jsx-uses-vars.js b/lib/rules/jsx-uses-vars.js
index 9ea9ab001e..6f5f4f6cc0 100644
--- a/lib/rules/jsx-uses-vars.js
+++ b/lib/rules/jsx-uses-vars.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const markVariableAsUsed = require('../util/eslint').markVariableAsUsed;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -53,7 +54,7 @@ module.exports = {
return;
}
- context.markVariableAsUsed(name);
+ markVariableAsUsed(name, node, context);
},
};
diff --git a/lib/rules/jsx-wrap-multilines.js b/lib/rules/jsx-wrap-multilines.js
index 59fa5f294b..17a9812465 100644
--- a/lib/rules/jsx-wrap-multilines.js
+++ b/lib/rules/jsx-wrap-multilines.js
@@ -7,10 +7,14 @@
const has = require('object.hasown/polyfill')();
const docsUrl = require('../util/docsUrl');
+const eslintUtil = require('../util/eslint');
const jsxUtil = require('../util/jsx');
const reportC = require('../util/report');
const isParenthesized = require('../util/ast').isParenthesized;
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
+
// ------------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------------
@@ -93,7 +97,7 @@ module.exports = {
}
function needsOpeningNewLine(node) {
- const previousToken = context.getSourceCode().getTokenBefore(node);
+ const previousToken = getSourceCode(context).getTokenBefore(node);
if (!isParenthesized(context, node)) {
return false;
@@ -107,7 +111,7 @@ module.exports = {
}
function needsClosingNewLine(node) {
- const nextToken = context.getSourceCode().getTokenAfter(node);
+ const nextToken = getSourceCode(context).getTokenAfter(node);
if (!isParenthesized(context, node)) {
return false;
@@ -143,11 +147,11 @@ module.exports = {
return;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const option = getOption(type);
if ((option === true || option === 'parens') && !isParenthesized(context, node) && isMultilines(node)) {
- report(node, 'missingParens', (fixer) => fixer.replaceText(node, `(${sourceCode.getText(node)})`));
+ report(node, 'missingParens', (fixer) => fixer.replaceText(node, `(${getText(context, node)})`));
}
if (option === 'parens-new-line' && isMultilines(node)) {
@@ -162,18 +166,18 @@ module.exports = {
'missingParens',
(fixer) => fixer.replaceTextRange(
[tokenBefore.range[0], tokenAfter && (tokenAfter.value === ';' || tokenAfter.value === '}') ? tokenAfter.range[0] : node.range[1]],
- `${trimTokenBeforeNewline(node, tokenBefore)}(\n${start.column > 0 ? ' '.repeat(start.column) : ''}${sourceCode.getText(node)}\n${start.column > 0 ? ' '.repeat(start.column - 2) : ''})`
+ `${trimTokenBeforeNewline(node, tokenBefore)}(\n${start.column > 0 ? ' '.repeat(start.column) : ''}${getText(context, node)}\n${start.column > 0 ? ' '.repeat(start.column - 2) : ''})`
)
);
} else {
- report(node, 'missingParens', (fixer) => fixer.replaceText(node, `(\n${sourceCode.getText(node)}\n)`));
+ report(node, 'missingParens', (fixer) => fixer.replaceText(node, `(\n${getText(context, node)}\n)`));
}
} else {
const needsOpening = needsOpeningNewLine(node);
const needsClosing = needsClosingNewLine(node);
if (needsOpening || needsClosing) {
report(node, 'parensOnNewLines', (fixer) => {
- const text = sourceCode.getText(node);
+ const text = getText(context, node);
let fixed = text;
if (needsOpening) {
fixed = `\n${fixed}`;
@@ -192,7 +196,7 @@ module.exports = {
const tokenAfter = sourceCode.getTokenAfter(node);
report(node, 'extraParens', (fixer) => fixer.replaceTextRange(
[tokenBefore.range[0], tokenAfter.range[1]],
- sourceCode.getText(node)
+ getText(context, node)
));
}
}
diff --git a/lib/rules/no-access-state-in-setstate.js b/lib/rules/no-access-state-in-setstate.js
index 89d4976077..be72ea42e4 100644
--- a/lib/rules/no-access-state-in-setstate.js
+++ b/lib/rules/no-access-state-in-setstate.js
@@ -8,6 +8,7 @@
const docsUrl = require('../util/docsUrl');
const componentUtil = require('../util/componentUtil');
const report = require('../util/report');
+const getScope = require('../util/eslint').getScope;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -47,8 +48,15 @@ module.exports = {
return current.arguments[0] === node;
}
- function isClassComponent() {
- return !!(componentUtil.getParentES6Component(context) || componentUtil.getParentES5Component(context));
+ /**
+ * @param {ASTNode} node
+ * @returns {boolean}
+ */
+ function isClassComponent(node) {
+ return !!(
+ componentUtil.getParentES6Component(context, node)
+ || componentUtil.getParentES5Component(context, node)
+ );
}
// The methods array contains all methods or functions that are using this.state
@@ -58,7 +66,7 @@ module.exports = {
const vars = [];
return {
CallExpression(node) {
- if (!isClassComponent()) {
+ if (!isClassComponent(node)) {
return;
}
// Appends all the methods that are calling another
@@ -103,7 +111,7 @@ module.exports = {
if (
node.property.name === 'state'
&& node.object.type === 'ThisExpression'
- && isClassComponent()
+ && isClassComponent(node)
) {
let current = node;
while (current.type !== 'Program') {
@@ -134,7 +142,7 @@ module.exports = {
if (current.type === 'VariableDeclarator') {
vars.push({
node,
- scope: context.getScope(),
+ scope: getScope(context, node),
variableName: current.id.name,
});
break;
@@ -158,7 +166,7 @@ module.exports = {
while (current.type !== 'Program') {
if (isFirstArgumentInSetStateCall(current, node)) {
vars
- .filter((v) => v.scope === context.getScope() && v.variableName === node.name)
+ .filter((v) => v.scope === getScope(context, node) && v.variableName === node.name)
.forEach((v) => {
report(context, messages.useCallback, 'useCallback', {
node: v.node,
@@ -176,7 +184,7 @@ module.exports = {
if (property && property.key && property.key.name === 'state' && isDerivedFromThis) {
vars.push({
node: property.key,
- scope: context.getScope(),
+ scope: getScope(context, node),
variableName: property.key.name,
});
}
diff --git a/lib/rules/no-adjacent-inline-elements.js b/lib/rules/no-adjacent-inline-elements.js
index 60e404ba22..5d7fdb8d6e 100644
--- a/lib/rules/no-adjacent-inline-elements.js
+++ b/lib/rules/no-adjacent-inline-elements.js
@@ -111,7 +111,7 @@ module.exports = {
validate(node, node.children);
},
CallExpression(node) {
- if (!isCreateElement(node, context)) {
+ if (!isCreateElement(context, node)) {
return;
}
if (node.arguments.length < 2 || !node.arguments[2]) {
diff --git a/lib/rules/no-array-index-key.js b/lib/rules/no-array-index-key.js
index bc8c91f9ef..c79fd56e2c 100644
--- a/lib/rules/no-array-index-key.js
+++ b/lib/rules/no-array-index-key.js
@@ -28,7 +28,7 @@ function isCreateCloneElement(node, context) {
}
if (node.type === 'Identifier') {
- const variable = variableUtil.findVariableByName(context, node.name);
+ const variable = variableUtil.findVariableByName(context, node, node.name);
if (variable && variable.type === 'ImportSpecifier') {
return variable.parent.source.value === 'react';
}
diff --git a/lib/rules/no-arrow-function-lifecycle.js b/lib/rules/no-arrow-function-lifecycle.js
index a1de789b81..e56cb78601 100644
--- a/lib/rules/no-arrow-function-lifecycle.js
+++ b/lib/rules/no-arrow-function-lifecycle.js
@@ -13,8 +13,12 @@ const componentUtil = require('../util/componentUtil');
const docsUrl = require('../util/docsUrl');
const lifecycleMethods = require('../util/lifecycleMethods');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
-function getText(node) {
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
+
+function getRuleText(node) {
const params = node.value.params.map((p) => p.name);
if (node.type === 'Property') {
@@ -67,7 +71,7 @@ module.exports = {
if (nodeType === 'ArrowFunctionExpression' && isLifecycleMethod) {
const body = node.value.body;
const isBlockBody = body.type === 'BlockStatement';
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
let nextComment = [];
let previousComment = [];
@@ -103,7 +107,7 @@ module.exports = {
node.key.range[1],
(previousComment.length > 0 ? previousComment[0] : body).range[0],
];
- const hasSemi = node.value.expression && sourceCode.getText(node).slice(node.value.range[1] - node.range[0]) === ';';
+ const hasSemi = node.value.expression && getText(context, node).slice(node.value.range[1] - node.range[0]) === ';';
report(
context,
@@ -117,13 +121,13 @@ module.exports = {
fix(fixer) {
if (!sourceCode.getCommentsAfter) {
// eslint 3.x
- return isBlockBody && fixer.replaceTextRange(headRange, getText(node));
+ return isBlockBody && fixer.replaceTextRange(headRange, getRuleText(node));
}
return [].concat(
- fixer.replaceTextRange(headRange, getText(node)),
+ fixer.replaceTextRange(headRange, getRuleText(node)),
isBlockBody ? [] : fixer.replaceTextRange(
[bodyRange[0], bodyRange[1] + (hasSemi ? 1 : 0)],
- `{ return ${previousComment.map((x) => sourceCode.getText(x)).join('')}${sourceCode.getText(body)}${nextComment.map((x) => sourceCode.getText(x)).join('')}; }`
+ `{ return ${previousComment.map((x) => getText(context, x)).join('')}${getText(context, body)}${nextComment.map((x) => getText(context, x)).join('')}; }`
)
);
},
diff --git a/lib/rules/no-children-prop.js b/lib/rules/no-children-prop.js
index 440e61e945..508488e4d9 100644
--- a/lib/rules/no-children-prop.js
+++ b/lib/rules/no-children-prop.js
@@ -21,7 +21,7 @@ const report = require('../util/report');
* object literal, False if not.
*/
function isCreateElementWithProps(node, context) {
- return isCreateElement(node, context)
+ return isCreateElement(context, node)
&& node.arguments.length > 1
&& node.arguments[1].type === 'ObjectExpression';
}
diff --git a/lib/rules/no-danger-with-children.js b/lib/rules/no-danger-with-children.js
index 17d55930ff..d3508721fe 100644
--- a/lib/rules/no-danger-with-children.js
+++ b/lib/rules/no-danger-with-children.js
@@ -31,8 +31,9 @@ module.exports = {
schema: [], // no options
},
create(context) {
- function findSpreadVariable(name) {
- return variableUtil.variablesInScope(context).find((item) => item.name === name);
+ function findSpreadVariable(node, name) {
+ return variableUtil.variablesInScope(context, node)
+ .find((item) => item.name === name);
}
/**
* Takes a ObjectExpression and returns the value of the prop if it has it
@@ -50,7 +51,7 @@ module.exports = {
return prop.key.name === propName;
}
if (prop.type === 'ExperimentalSpreadProperty' || prop.type === 'SpreadElement') {
- const variable = findSpreadVariable(prop.argument.name);
+ const variable = findSpreadVariable(node, prop.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init) {
if (seenProps.indexOf(prop.argument.name) > -1) {
return false;
@@ -73,7 +74,7 @@ module.exports = {
const attributes = node.openingElement.attributes;
return attributes.find((attribute) => {
if (attribute.type === 'JSXSpreadAttribute') {
- const variable = findSpreadVariable(attribute.argument.name);
+ const variable = findSpreadVariable(node, attribute.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init) {
return findObjectProp(variable.defs[0].node.init, propName, []);
}
@@ -127,7 +128,8 @@ module.exports = {
let props = node.arguments[1];
if (props.type === 'Identifier') {
- const variable = variableUtil.variablesInScope(context).find((item) => item.name === props.name);
+ const variable = variableUtil.variablesInScope(context, node)
+ .find((item) => item.name === props.name);
if (variable && variable.defs.length && variable.defs[0].node.init) {
props = variable.defs[0].node.init;
}
diff --git a/lib/rules/no-deprecated.js b/lib/rules/no-deprecated.js
index d37b55bbfd..462bd4c756 100644
--- a/lib/rules/no-deprecated.js
+++ b/lib/rules/no-deprecated.js
@@ -14,6 +14,7 @@ const docsUrl = require('../util/docsUrl');
const pragmaUtil = require('../util/pragma');
const testReactVersion = require('../util/version').testReactVersion;
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
// ------------------------------------------------------------------------------
// Constants
@@ -217,7 +218,7 @@ module.exports = {
return {
MemberExpression(node) {
- checkDeprecation(node, context.getSourceCode().getText(node));
+ checkDeprecation(node, getText(context, node));
},
ImportDeclaration(node) {
diff --git a/lib/rules/no-direct-mutation-state.js b/lib/rules/no-direct-mutation-state.js
index 9349a85fe5..3df0998c6e 100644
--- a/lib/rules/no-direct-mutation-state.js
+++ b/lib/rules/no-direct-mutation-state.js
@@ -98,7 +98,7 @@ module.exports = {
},
AssignmentExpression(node) {
- const component = components.get(utils.getParentComponent());
+ const component = components.get(utils.getParentComponent(node));
if (shouldIgnoreComponent(component) || !node.left || !node.left.object) {
return;
}
@@ -114,7 +114,7 @@ module.exports = {
},
UpdateExpression(node) {
- const component = components.get(utils.getParentComponent());
+ const component = components.get(utils.getParentComponent(node));
if (shouldIgnoreComponent(component) || node.argument.type !== 'MemberExpression') {
return;
}
diff --git a/lib/rules/no-invalid-html-attribute.js b/lib/rules/no-invalid-html-attribute.js
index 1dd4d0f44b..98c33fbc3f 100644
--- a/lib/rules/no-invalid-html-attribute.js
+++ b/lib/rules/no-invalid-html-attribute.js
@@ -238,8 +238,8 @@ const messages = {
suggestRemoveDefault: '"remove {{attributeName}}"',
suggestRemoveEmpty: '"remove empty attribute {{attributeName}}"',
suggestRemoveInvalid: '“remove invalid attribute {{reportingValue}}”',
- suggestRemoveWhitespaces: 'remove whitespaces in “{{reportingValue}}”',
- suggestRemoveNonString: 'remove non-string value in “{{reportingValue}}”',
+ suggestRemoveWhitespaces: 'remove whitespaces in “{{attributeName}}”',
+ suggestRemoveNonString: 'remove non-string value in “{{attributeName}}”',
};
function splitIntoRangedParts(node, regex) {
@@ -259,13 +259,18 @@ function splitIntoRangedParts(node, regex) {
function checkLiteralValueNode(context, attributeName, node, parentNode, parentNodeName) {
if (typeof node.value !== 'string') {
+ const data = { attributeName, reportingValue: node.value };
+
report(context, messages.onlyStrings, 'onlyStrings', {
node,
- data: { attributeName },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveNonString', messages.suggestRemoveNonString),
- { fix(fixer) { return fixer.remove(parentNode); } }
+ {
+ data,
+ fix(fixer) { return fixer.remove(parentNode); },
+ }
),
],
});
@@ -273,13 +278,18 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN
}
if (!node.value.trim()) {
+ const data = { attributeName, reportingValue: node.value };
+
report(context, messages.noEmpty, 'noEmpty', {
node,
- data: { attributeName },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveEmpty', messages.suggestRemoveEmpty),
- { fix(fixer) { return fixer.remove(node.parent); } }
+ {
+ data,
+ fix(fixer) { return fixer.remove(node.parent); },
+ }
),
],
});
@@ -291,32 +301,44 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN
const allowedTags = VALID_VALUES.get(attributeName).get(singlePart.value);
const reportingValue = singlePart.reportingValue;
- const suggest = [
- Object.assign(
- getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid),
- { fix(fixer) { return fixer.removeRange(singlePart.range); } }
- ),
- ];
-
if (!allowedTags) {
const data = {
attributeName,
reportingValue,
};
+
report(context, messages.neverValid, 'neverValid', {
node,
data,
- suggest,
+ suggest: [
+ Object.assign(
+ getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid),
+ {
+ data,
+ fix(fixer) { return fixer.removeRange(singlePart.range); },
+ }
+ ),
+ ],
});
} else if (!allowedTags.has(parentNodeName)) {
+ const data = {
+ attributeName,
+ reportingValue,
+ elementName: parentNodeName,
+ };
+
report(context, messages.notValidFor, 'notValidFor', {
node,
- data: {
- attributeName,
- reportingValue,
- elementName: parentNodeName,
- },
- suggest,
+ data,
+ suggest: [
+ Object.assign(
+ getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid),
+ {
+ data,
+ fix(fixer) { return fixer.removeRange(singlePart.range); },
+ }
+ ),
+ ],
});
}
}
@@ -360,7 +382,10 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN
suggest: [
Object.assign(
getMessageData('suggestRemoveWhitespaces', messages.suggestRemoveWhitespaces),
- { fix(fixer) { return fixer.removeRange(whitespacePart.range); } }
+ {
+ data: { attributeName },
+ fix(fixer) { return fixer.removeRange(whitespacePart.range); },
+ }
),
],
});
@@ -371,7 +396,10 @@ function checkLiteralValueNode(context, attributeName, node, parentNode, parentN
suggest: [
Object.assign(
getMessageData('suggestRemoveWhitespaces', messages.suggestRemoveWhitespaces),
- { fix(fixer) { return fixer.replaceTextRange(whitespacePart.range, '\u0020'); } }
+ {
+ data: { attributeName },
+ fix(fixer) { return fixer.replaceTextRange(whitespacePart.range, '\u0020'); },
+ }
),
],
});
@@ -390,16 +418,21 @@ function checkAttribute(context, node) {
COMPONENT_ATTRIBUTE_MAP.get(attribute).values(),
(tagName) => `"<${tagName}>"`
).join(', ');
+ const data = {
+ attributeName: attribute,
+ tagNames,
+ };
+
report(context, messages.onlyMeaningfulFor, 'onlyMeaningfulFor', {
node: node.name,
- data: {
- attributeName: attribute,
- tagNames,
- },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault),
- { fix(fixer) { return fixer.remove(node); } }
+ {
+ data,
+ fix(fixer) { return fixer.remove(node); },
+ }
),
],
});
@@ -409,13 +442,15 @@ function checkAttribute(context, node) {
function fix(fixer) { return fixer.remove(node); }
if (!node.value) {
+ const data = { attributeName: attribute };
+
report(context, messages.emptyIsMeaningless, 'emptyIsMeaningless', {
node: node.name,
- data: { attributeName: attribute },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveEmpty', messages.suggestRemoveEmpty),
- { fix }
+ { data, fix }
),
],
});
@@ -435,24 +470,28 @@ function checkAttribute(context, node) {
}
if (node.value.expression.type === 'ObjectExpression') {
+ const data = { attributeName: attribute };
+
report(context, messages.onlyStrings, 'onlyStrings', {
node: node.value,
- data: { attributeName: attribute },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault),
- { fix }
+ { data, fix }
),
],
});
} else if (node.value.expression.type === 'Identifier' && node.value.expression.name === 'undefined') {
+ const data = { attributeName: attribute };
+
report(context, messages.onlyStrings, 'onlyStrings', {
node: node.value,
- data: { attributeName: attribute },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveDefault', messages.suggestRemoveDefault),
- { fix }
+ { data, fix }
),
],
});
@@ -476,16 +515,21 @@ function checkPropValidValue(context, node, value, attribute) {
const validTagSet = validTags.get(value.value);
if (!validTagSet) {
+ const data = {
+ attributeName: attribute,
+ reportingValue: value.value,
+ };
+
report(context, messages.neverValid, 'neverValid', {
node: value,
- data: {
- attributeName: attribute,
- reportingValue: value.value,
- },
+ data,
suggest: [
Object.assign(
getMessageData('suggestRemoveInvalid', messages.suggestRemoveInvalid),
- { fix(fixer) { return fixer.replaceText(value, value.raw.replace(value.value, '')); } }
+ {
+ data,
+ fix(fixer) { return fixer.replaceText(value, value.raw.replace(value.value, '')); },
+ }
),
],
});
diff --git a/lib/rules/no-is-mounted.js b/lib/rules/no-is-mounted.js
index c15b6e81a4..fd99d5b683 100644
--- a/lib/rules/no-is-mounted.js
+++ b/lib/rules/no-is-mounted.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getAncestors = require('../util/eslint').getAncestors;
const report = require('../util/report');
// ------------------------------------------------------------------------------
@@ -40,7 +41,7 @@ module.exports = {
if (callee.object.type !== 'ThisExpression' || callee.property.name !== 'isMounted') {
return;
}
- const ancestors = context.getAncestors(callee);
+ const ancestors = getAncestors(context, node);
for (let i = 0, j = ancestors.length; i < j; i++) {
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') {
report(context, messages.noIsMounted, 'noIsMounted', {
diff --git a/lib/rules/no-namespace.js b/lib/rules/no-namespace.js
index d7559f5ebd..20ca5d9324 100644
--- a/lib/rules/no-namespace.js
+++ b/lib/rules/no-namespace.js
@@ -36,7 +36,7 @@ module.exports = {
create(context) {
return {
CallExpression(node) {
- if (isCreateElement(node, context) && node.arguments.length > 0 && node.arguments[0].type === 'Literal') {
+ if (isCreateElement(context, node) && node.arguments.length > 0 && node.arguments[0].type === 'Literal') {
const name = node.arguments[0].value;
if (typeof name !== 'string' || name.indexOf(':') === -1) return undefined;
report(context, messages.noNamespace, 'noNamespace', {
diff --git a/lib/rules/no-set-state.js b/lib/rules/no-set-state.js
index c88db30d7e..199e922b75 100644
--- a/lib/rules/no-set-state.js
+++ b/lib/rules/no-set-state.js
@@ -68,7 +68,7 @@ module.exports = {
) {
return;
}
- const component = components.get(utils.getParentComponent());
+ const component = components.get(utils.getParentComponent(node));
const setStateUsages = (component && component.setStateUsages) || [];
setStateUsages.push(callee);
components.set(node, {
diff --git a/lib/rules/no-string-refs.js b/lib/rules/no-string-refs.js
index 466a214579..09ce286685 100644
--- a/lib/rules/no-string-refs.js
+++ b/lib/rules/no-string-refs.js
@@ -50,7 +50,7 @@ module.exports = {
*/
function isRefsUsage(node) {
return !!(
- (componentUtil.getParentES6Component(context) || componentUtil.getParentES5Component(context))
+ (componentUtil.getParentES6Component(context, node) || componentUtil.getParentES5Component(context, node))
&& node.object.type === 'ThisExpression'
&& node.property.name === 'refs'
);
diff --git a/lib/rules/no-this-in-sfc.js b/lib/rules/no-this-in-sfc.js
index cf9eb99bd4..c520abd31c 100644
--- a/lib/rules/no-this-in-sfc.js
+++ b/lib/rules/no-this-in-sfc.js
@@ -34,7 +34,7 @@ module.exports = {
create: Components.detect((context, components, utils) => ({
MemberExpression(node) {
if (node.object.type === 'ThisExpression') {
- const component = components.get(utils.getParentStatelessComponent());
+ const component = components.get(utils.getParentStatelessComponent(node));
if (!component || (component.node && component.node.parent && component.node.parent.type === 'Property')) {
return;
}
diff --git a/lib/rules/no-unescaped-entities.js b/lib/rules/no-unescaped-entities.js
index a449ad5206..ecf1abc5e1 100644
--- a/lib/rules/no-unescaped-entities.js
+++ b/lib/rules/no-unescaped-entities.js
@@ -6,6 +6,7 @@
'use strict';
const docsUrl = require('../util/docsUrl');
+const getSourceCode = require('../util/eslint').getSourceCode;
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
@@ -83,9 +84,9 @@ module.exports = {
const entities = configuration.forbid || DEFAULTS;
// HTML entities are already escaped in node.value (as well as node.raw),
- // so pull the raw text from context.getSourceCode()
+ // so pull the raw text from getSourceCode(context)
for (let i = node.loc.start.line; i <= node.loc.end.line; i++) {
- let rawLine = context.getSourceCode().lines[i - 1];
+ let rawLine = getSourceCode(context).lines[i - 1];
let start = 0;
let end = rawLine.length;
if (i === node.loc.start.line) {
diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js
index 9491f9c658..3e8c6de111 100644
--- a/lib/rules/no-unknown-property.js
+++ b/lib/rules/no-unknown-property.js
@@ -7,6 +7,7 @@
const has = require('object.hasown/polyfill')();
const docsUrl = require('../util/docsUrl');
+const getText = require('../util/eslint').getText;
const testReactVersion = require('../util/version').testReactVersion;
const report = require('../util/report');
@@ -555,7 +556,7 @@ module.exports = {
return {
JSXAttribute(node) {
const ignoreNames = getIgnoreConfig();
- const actualName = context.getSourceCode().getText(node.name);
+ const actualName = getText(context, node.name);
if (ignoreNames.indexOf(actualName) >= 0) {
return;
}
diff --git a/lib/rules/no-unstable-nested-components.js b/lib/rules/no-unstable-nested-components.js
index 2ef635efab..c1dd606b6a 100644
--- a/lib/rules/no-unstable-nested-components.js
+++ b/lib/rules/no-unstable-nested-components.js
@@ -68,7 +68,7 @@ function isCreateElementMatcher(node, context) {
return (
node
&& node.type === 'CallExpression'
- && isCreateElement(node, context)
+ && isCreateElement(context, node)
);
}
@@ -306,7 +306,7 @@ module.exports = {
* @returns {Boolean} True if node is inside class component's render block, false if not
*/
function isInsideRenderMethod(node) {
- const parentComponent = utils.getParentComponent();
+ const parentComponent = utils.getParentComponent(node);
if (!parentComponent || parentComponent.type !== 'ClassDeclaration') {
return false;
@@ -334,8 +334,8 @@ module.exports = {
* @returns {Boolean} True if given node a function component declared inside class component, false if not
*/
function isFunctionComponentInsideClassComponent(node) {
- const parentComponent = utils.getParentComponent();
- const parentStatelessComponent = utils.getParentStatelessComponent();
+ const parentComponent = utils.getParentComponent(node);
+ const parentStatelessComponent = utils.getParentStatelessComponent(node);
return (
parentComponent
diff --git a/lib/rules/no-unused-state.js b/lib/rules/no-unused-state.js
index 73a0e52163..0ed480694d 100644
--- a/lib/rules/no-unused-state.js
+++ b/lib/rules/no-unused-state.js
@@ -13,6 +13,7 @@ const docsUrl = require('../util/docsUrl');
const ast = require('../util/ast');
const componentUtil = require('../util/componentUtil');
const report = require('../util/report');
+const getScope = require('../util/eslint').getScope;
// Descend through all wrapping TypeCastExpressions and return the expression
// that was cast.
@@ -107,7 +108,7 @@ module.exports = {
'componentDidUpdate',
];
- let scope = context.getScope();
+ let scope = getScope(context, node);
while (scope) {
const parent = scope.block && scope.block.parent;
if (
@@ -368,7 +369,7 @@ module.exports = {
return;
}
- const childScope = context.getScope().childScopes.find((x) => x.block === node.value);
+ const childScope = getScope(context, node).childScopes.find((x) => x.block === node.value);
if (!childScope) {
return;
}
diff --git a/lib/rules/prefer-exact-props.js b/lib/rules/prefer-exact-props.js
index 4ad088e9ee..6d7db27d0f 100644
--- a/lib/rules/prefer-exact-props.js
+++ b/lib/rules/prefer-exact-props.js
@@ -10,6 +10,7 @@ const propsUtil = require('../util/props');
const propWrapperUtil = require('../util/propWrapper');
const variableUtil = require('../util/variable');
const report = require('../util/report');
+const getText = require('../util/eslint').getText;
// -----------------------------------------------------------------------------
// Rule Definition
@@ -36,7 +37,6 @@ module.exports = {
create: Components.detect((context, components, utils) => {
const typeAliases = {};
const exactWrappers = propWrapperUtil.getExactPropWrapperFunctions(context);
- const sourceCode = context.getSourceCode();
function getPropTypesErrorMessage() {
const formattedWrappers = propWrapperUtil.formatPropWrapperFunctions(exactWrappers);
@@ -83,7 +83,7 @@ module.exports = {
return (
node
&& node.type === 'CallExpression'
- && !propWrapperUtil.isExactPropWrapperFunction(context, sourceCode.getText(node.callee))
+ && !propWrapperUtil.isExactPropWrapperFunction(context, getText(context, node.callee))
);
}
@@ -149,7 +149,7 @@ module.exports = {
reportPropTypesError(node);
} else if (right.type === 'Identifier') {
const identifier = right.name;
- const propsDefinition = variableUtil.findVariableByName(context, identifier);
+ const propsDefinition = variableUtil.findVariableByName(context, node, identifier);
if (isNonEmptyObjectExpression(propsDefinition)) {
reportPropTypesError(node);
} else if (isNonExactPropWrapperFunction(propsDefinition)) {
diff --git a/lib/rules/prefer-stateless-function.js b/lib/rules/prefer-stateless-function.js
index 07c435747f..bfbabe76be 100644
--- a/lib/rules/prefer-stateless-function.js
+++ b/lib/rules/prefer-stateless-function.js
@@ -15,6 +15,10 @@ const astUtil = require('../util/ast');
const componentUtil = require('../util/componentUtil');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getScope = eslintUtil.getScope;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -332,7 +336,7 @@ module.exports = {
// Mark `ref` usage
JSXAttribute(node) {
- const name = context.getSourceCode().getText(node.name);
+ const name = getText(context, node.name);
if (name !== 'ref') {
return;
}
@@ -342,7 +346,7 @@ module.exports = {
// Mark `render` that do not return some JSX
ReturnStatement(node) {
let blockNode;
- let scope = context.getScope();
+ let scope = getScope(context, node);
while (scope) {
blockNode = scope.block && scope.block.parent;
if (blockNode && (blockNode.type === 'MethodDefinition' || blockNode.type === 'Property')) {
diff --git a/lib/rules/prop-types.js b/lib/rules/prop-types.js
index 07adca104a..eb6bab1c09 100644
--- a/lib/rules/prop-types.js
+++ b/lib/rules/prop-types.js
@@ -74,11 +74,11 @@ module.exports = {
/**
* Checks if the component must be validated
* @param {Object} component The component to process
- * @returns {Boolean} True if the component must be validated, false if not.
+ * @returns {boolean} True if the component must be validated, false if not.
*/
function mustBeValidated(component) {
const isSkippedByConfig = skipUndeclared && typeof component.declaredPropTypes === 'undefined';
- return Boolean(
+ return !!(
component
&& component.usedPropTypes
&& !component.ignorePropsValidation
@@ -90,7 +90,7 @@ module.exports = {
* Internal: Checks if the prop is declared
* @param {Object} declaredPropTypes Description of propTypes declared in the current component
* @param {String[]} keyList Dot separated name of the prop to check.
- * @returns {Boolean} True if the prop is declared, false if not.
+ * @returns {boolean} True if the prop is declared, false if not.
*/
function internalIsDeclaredInComponent(declaredPropTypes, keyList) {
for (let i = 0, j = keyList.length; i < j; i++) {
diff --git a/lib/rules/react-in-jsx-scope.js b/lib/rules/react-in-jsx-scope.js
index 1af398deae..f2d8bc4837 100644
--- a/lib/rules/react-in-jsx-scope.js
+++ b/lib/rules/react-in-jsx-scope.js
@@ -37,7 +37,7 @@ module.exports = {
const pragma = pragmaUtil.getFromContext(context);
function checkIfReactIsInScope(node) {
- const variables = variableUtil.variablesInScope(context);
+ const variables = variableUtil.variablesInScope(context, node);
if (variableUtil.findVariable(variables, pragma)) {
return;
}
diff --git a/lib/rules/require-optimization.js b/lib/rules/require-optimization.js
index 9d440b19ee..dc0b60f73a 100644
--- a/lib/rules/require-optimization.js
+++ b/lib/rules/require-optimization.js
@@ -11,6 +11,7 @@ const Components = require('../util/Components');
const componentUtil = require('../util/componentUtil');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const getScope = require('../util/eslint').getScope;
const messages = {
noShouldComponentUpdate: 'Component is not optimized. Please add a shouldComponentUpdate method.',
@@ -154,11 +155,12 @@ module.exports = {
/**
* Checks if we are declaring function in class
- * @returns {Boolean} True if we are declaring function in class, false if not.
+ * @param {ASTNode} node
+ * @returns {boolean} True if we are declaring function in class, false if not.
*/
- function isFunctionInClass() {
+ function isFunctionInClass(node) {
let blockNode;
- let scope = context.getScope();
+ let scope = getScope(context, node);
while (scope) {
blockNode = scope.block;
if (blockNode && blockNode.type === 'ClassDeclaration') {
@@ -173,7 +175,7 @@ module.exports = {
return {
ArrowFunctionExpression(node) {
// Skip if the function is declared in the class
- if (isFunctionInClass()) {
+ if (isFunctionInClass(node)) {
return;
}
// Stateless Functional Components cannot be optimized (yet)
@@ -193,7 +195,7 @@ module.exports = {
FunctionDeclaration(node) {
// Skip if the function is declared in the class
- if (isFunctionInClass()) {
+ if (isFunctionInClass(node)) {
return;
}
// Stateless Functional Components cannot be optimized (yet)
@@ -202,7 +204,7 @@ module.exports = {
FunctionExpression(node) {
// Skip if the function is declared in the class
- if (isFunctionInClass()) {
+ if (isFunctionInClass(node)) {
return;
}
// Stateless Functional Components cannot be optimized (yet)
diff --git a/lib/rules/require-render-return.js b/lib/rules/require-render-return.js
index d79c9406b7..c46613e420 100644
--- a/lib/rules/require-render-return.js
+++ b/lib/rules/require-render-return.js
@@ -12,6 +12,7 @@ const astUtil = require('../util/ast');
const componentUtil = require('../util/componentUtil');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const getAncestors = require('../util/eslint').getAncestors;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -61,7 +62,7 @@ module.exports = {
return {
ReturnStatement(node) {
- const ancestors = context.getAncestors(node).reverse();
+ const ancestors = getAncestors(context, node).reverse();
let depth = 0;
ancestors.forEach((ancestor) => {
if (/Function(Expression|Declaration)$/.test(ancestor.type)) {
diff --git a/lib/rules/sort-default-props.js b/lib/rules/sort-default-props.js
index aae419ba18..aca868f95d 100644
--- a/lib/rules/sort-default-props.js
+++ b/lib/rules/sort-default-props.js
@@ -9,6 +9,10 @@
const variableUtil = require('../util/variable');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getFirstTokens = eslintUtil.getFirstTokens;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -60,7 +64,7 @@ module.exports = {
// (babel-eslint@5 does not expose property name so we have to rely on tokens)
}
if (node.type === 'ClassProperty') {
- const tokens = context.getSourceCode().getFirstTokens(node, 2);
+ const tokens = getFirstTokens(context, node, 2);
return tokens[1] && tokens[1].type === 'Identifier' ? tokens[1].value : tokens[0].value;
}
return '';
@@ -77,16 +81,18 @@ module.exports = {
}
function getKey(node) {
- return context.getSourceCode().getText(node.key || node.argument);
+ return getText(context, node.key || node.argument);
}
/**
* Find a variable by name in the current scope.
+ * @param {ASTNode} node The node to look for.
* @param {string} name Name of the variable to look for.
* @returns {ASTNode|null} Return null if the variable could not be found, ASTNode otherwise.
*/
- function findVariableByName(name) {
- const variable = variableUtil.variablesInScope(context).find((item) => item.name === name);
+ function findVariableByName(node, name) {
+ const variable = variableUtil.variablesInScope(context, node)
+ .find((item) => item.name === name);
if (!variable || !variable.defs[0] || !variable.defs[0].node) {
return null;
@@ -106,7 +112,7 @@ module.exports = {
*/
function checkSorted(declarations) {
// function fix(fixer) {
- // return propTypesSortUtil.fixPropTypesSort(fixer, context, declarations, ignoreCase);
+ // return propTypesSortUtil.fixPropTypesSort(context, fixer, declarations, ignoreCase);
// }
declarations.reduce((prev, curr, idx, decls) => {
@@ -142,7 +148,7 @@ module.exports = {
if (node.type === 'ObjectExpression') {
checkSorted(node.properties);
} else if (node.type === 'Identifier') {
- const propTypesObject = findVariableByName(node.name);
+ const propTypesObject = findVariableByName(node, node.name);
if (propTypesObject && propTypesObject.properties) {
checkSorted(propTypesObject.properties);
}
diff --git a/lib/rules/sort-prop-types.js b/lib/rules/sort-prop-types.js
index 8c3574af4a..808dd1df1f 100644
--- a/lib/rules/sort-prop-types.js
+++ b/lib/rules/sort-prop-types.js
@@ -10,6 +10,10 @@ const docsUrl = require('../util/docsUrl');
const propWrapperUtil = require('../util/propWrapper');
const propTypesSortUtil = require('../util/propTypesSort');
const report = require('../util/report');
+const eslintUtil = require('../util/eslint');
+
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
// ------------------------------------------------------------------------------
// Rule Definition
@@ -23,12 +27,12 @@ const messages = {
function getKey(context, node) {
if (node.type === 'ObjectTypeProperty') {
- return context.getSourceCode().getFirstToken(node).value;
+ return getSourceCode(context).getFirstToken(node).value;
}
if (node.key && node.key.value) {
return node.key.value;
}
- return context.getSourceCode().getText(node.key || node.argument);
+ return getText(context, node.key || node.argument);
}
function getValueName(node) {
@@ -118,8 +122,8 @@ module.exports = {
function fix(fixer) {
return propTypesSortUtil.fixPropTypesSort(
- fixer,
context,
+ fixer,
declarations,
ignoreCase,
requiredFirst,
@@ -207,7 +211,7 @@ module.exports = {
checkSorted(node.properties);
break;
case 'Identifier': {
- const propTypesObject = variableUtil.findVariableByName(context, node.name);
+ const propTypesObject = variableUtil.findVariableByName(context, node, node.name);
if (propTypesObject && propTypesObject.properties) {
checkSorted(propTypesObject.properties);
}
@@ -260,7 +264,7 @@ module.exports = {
if (firstArg.properties) {
checkSorted(firstArg.properties);
} else if (firstArg.type === 'Identifier') {
- const variable = variableUtil.findVariableByName(context, firstArg.name);
+ const variable = variableUtil.findVariableByName(context, node, firstArg.name);
if (variable && variable.properties) {
checkSorted(variable.properties);
}
diff --git a/lib/rules/state-in-constructor.js b/lib/rules/state-in-constructor.js
index c518b1713a..9dd756b4d2 100644
--- a/lib/rules/state-in-constructor.js
+++ b/lib/rules/state-in-constructor.js
@@ -44,7 +44,7 @@ module.exports = {
option === 'always'
&& !node.static
&& node.key.name === 'state'
- && componentUtil.getParentES6Component(context)
+ && componentUtil.getParentES6Component(context, node)
) {
report(context, messages.stateInitConstructor, 'stateInitConstructor', {
node,
@@ -55,8 +55,8 @@ module.exports = {
if (
option === 'never'
&& componentUtil.isStateMemberExpression(node.left)
- && astUtil.inConstructor(context)
- && componentUtil.getParentES6Component(context)
+ && astUtil.inConstructor(context, node)
+ && componentUtil.getParentES6Component(context, node)
) {
report(context, messages.stateInitClassProp, 'stateInitClassProp', {
node,
diff --git a/lib/rules/static-property-placement.js b/lib/rules/static-property-placement.js
index efc50da3bd..7baf2faeb4 100644
--- a/lib/rules/static-property-placement.js
+++ b/lib/rules/static-property-placement.js
@@ -12,6 +12,7 @@ const astUtil = require('../util/ast');
const componentUtil = require('../util/componentUtil');
const propsUtil = require('../util/props');
const report = require('../util/report');
+const getScope = require('../util/eslint').getScope;
// ------------------------------------------------------------------------------
// Positioning Options
@@ -97,11 +98,12 @@ module.exports = {
/**
* Checks if we are declaring context in class
+ * @param {ASTNode} node
* @returns {Boolean} True if we are declaring context in class, false if not.
*/
- function isContextInClass() {
+ function isContextInClass(node) {
let blockNode;
- let scope = context.getScope();
+ let scope = getScope(context, node);
while (scope) {
blockNode = scope.block;
if (blockNode && blockNode.type === 'ClassDeclaration') {
@@ -149,7 +151,7 @@ module.exports = {
// ----------------------------------------------------------------------
return {
'ClassProperty, PropertyDefinition'(node) {
- if (!componentUtil.getParentES6Component(context)) {
+ if (!componentUtil.getParentES6Component(context, node)) {
return;
}
@@ -160,7 +162,7 @@ module.exports = {
// If definition type is undefined then it must not be a defining expression or if the definition is inside a
// class body then skip this node.
const right = node.parent.right;
- if (!right || right.type === 'undefined' || isContextInClass()) {
+ if (!right || right.type === 'undefined' || isContextInClass(node)) {
return;
}
@@ -178,7 +180,11 @@ module.exports = {
MethodDefinition(node) {
// If the function is inside a class and is static getter then check if correctly positioned
- if (componentUtil.getParentES6Component(context) && node.static && node.kind === 'get') {
+ if (
+ componentUtil.getParentES6Component(context, node)
+ && node.static
+ && node.kind === 'get'
+ ) {
// Report error if needed
reportNodeIncorrectlyPositioned(node, STATIC_GETTER);
}
diff --git a/lib/rules/style-prop-object.js b/lib/rules/style-prop-object.js
index 4d6684a6f1..4f77beccb2 100644
--- a/lib/rules/style-prop-object.js
+++ b/lib/rules/style-prop-object.js
@@ -61,7 +61,8 @@ module.exports = {
* @param {object} node A Identifier node
*/
function checkIdentifiers(node) {
- const variable = variableUtil.variablesInScope(context).find((item) => item.name === node.name);
+ const variable = variableUtil.variablesInScope(context, node)
+ .find((item) => item.name === node.name);
if (!variable || !variable.defs[0] || !variable.defs[0].node.init) {
return;
@@ -77,7 +78,7 @@ module.exports = {
return {
CallExpression(node) {
if (
- isCreateElement(node, context)
+ isCreateElement(context, node)
&& node.arguments.length > 1
) {
if (node.arguments[0].name) {
diff --git a/lib/rules/void-dom-elements-no-children.js b/lib/rules/void-dom-elements-no-children.js
index 721ffae872..a8a6ba0149 100644
--- a/lib/rules/void-dom-elements-no-children.js
+++ b/lib/rules/void-dom-elements-no-children.js
@@ -108,7 +108,7 @@ module.exports = {
return;
}
- if (!isCreateElement(node, context)) {
+ if (!isCreateElement(context, node)) {
return;
}
diff --git a/lib/util/Components.js b/lib/util/Components.js
index a31989702f..67fac5afc5 100644
--- a/lib/util/Components.js
+++ b/lib/util/Components.js
@@ -21,6 +21,10 @@ const usedPropTypesUtil = require('./usedPropTypes');
const defaultPropsUtil = require('./defaultProps');
const isFirstLetterCapitalized = require('./isFirstLetterCapitalized');
const isDestructuredFromPragmaImport = require('./isDestructuredFromPragmaImport');
+const eslintUtil = require('./eslint');
+
+const getScope = eslintUtil.getScope;
+const getText = eslintUtil.getText;
function getId(node) {
return node ? `${node.range[0]}:${node.range[1]}` : '';
@@ -282,7 +286,6 @@ function mergeRules(rules) {
function componentRule(rule, context) {
const pragma = pragmaUtil.getFromContext(context);
- const sourceCode = context.getSourceCode();
const components = new Components();
const wrapperFunctions = getWrapperFunctions(context, pragma);
@@ -291,19 +294,25 @@ function componentRule(rule, context) {
/**
* Check if variable is destructured from pragma import
*
+ * @param {ASTNode} node The AST node to check
* @param {string} variable The variable name to check
- * @returns {Boolean} True if createElement is destructured from the pragma
+ * @returns {boolean} True if createElement is destructured from the pragma
*/
- isDestructuredFromPragmaImport(variable) {
- return isDestructuredFromPragmaImport(variable, context);
+ isDestructuredFromPragmaImport(node, variable) {
+ return isDestructuredFromPragmaImport(context, node, variable);
},
+ /**
+ * @param {ASTNode} ASTNode
+ * @param {boolean=} strict
+ * @returns {boolean}
+ */
isReturningJSX(ASTNode, strict) {
- return jsxUtil.isReturningJSX(ASTNode, context, strict, true);
+ return jsxUtil.isReturningJSX(context, ASTNode, strict, true);
},
isReturningJSXOrNull(ASTNode, strict) {
- return jsxUtil.isReturningJSX(ASTNode, context, strict);
+ return jsxUtil.isReturningJSX(context, ASTNode, strict);
},
isReturningOnlyNull(ASTNode) {
@@ -412,7 +421,7 @@ function componentRule(rule, context) {
return wrapperFunction.property === node.callee.name
&& (!wrapperFunction.object
// Functions coming from the current pragma need special handling
- || (wrapperFunction.object === pragma && this.isDestructuredFromPragmaImport(node.callee.name))
+ || (wrapperFunction.object === pragma && this.isDestructuredFromPragmaImport(node, node.callee.name))
);
});
},
@@ -426,14 +435,15 @@ function componentRule(rule, context) {
/**
* Get the parent component node from the current scope
+ * @param {ASTNode} node
*
* @returns {ASTNode} component node, null if we are not in a component
*/
- getParentComponent() {
+ getParentComponent(node) {
return (
- componentUtil.getParentES6Component(context)
- || componentUtil.getParentES5Component(context)
- || utils.getParentStatelessComponent()
+ componentUtil.getParentES6Component(context, node)
+ || componentUtil.getParentES5Component(context, node)
+ || utils.getParentStatelessComponent(node)
);
},
@@ -612,13 +622,13 @@ function componentRule(rule, context) {
/**
* Get the parent stateless component node from the current scope
*
+ * @param {ASTNode} node The AST node being checked
* @returns {ASTNode} component node, null if we are not in a component
*/
- getParentStatelessComponent() {
- let scope = context.getScope();
+ getParentStatelessComponent(node) {
+ let scope = getScope(context, node);
while (scope) {
- const node = scope.block;
- const statelessComponent = utils.getStatelessComponent(node);
+ const statelessComponent = utils.getStatelessComponent(scope.block);
if (statelessComponent) {
return statelessComponent;
}
@@ -641,14 +651,15 @@ function componentRule(rule, context) {
let componentNode;
// Get the component path
const componentPath = [];
- while (node) {
- if (node.property && node.property.type === 'Identifier') {
- componentPath.push(node.property.name);
+ let nodeTemp = node;
+ while (nodeTemp) {
+ if (nodeTemp.property && nodeTemp.property.type === 'Identifier') {
+ componentPath.push(nodeTemp.property.name);
}
- if (node.object && node.object.type === 'Identifier') {
- componentPath.push(node.object.name);
+ if (nodeTemp.object && nodeTemp.object.type === 'Identifier') {
+ componentPath.push(nodeTemp.object.name);
}
- node = node.object;
+ nodeTemp = nodeTemp.object;
}
componentPath.reverse();
const componentName = componentPath.slice(0, componentPath.length - 1).join('.');
@@ -659,7 +670,7 @@ function componentRule(rule, context) {
return null;
}
let variableInScope;
- const variables = variableUtil.variablesInScope(context);
+ const variables = variableUtil.variablesInScope(context, node);
for (i = 0, j = variables.length; i < j; i++) {
if (variables[i].name === variableName) {
variableInScope = variables[i];
@@ -676,7 +687,7 @@ function componentRule(rule, context) {
if (refId.parent && refId.parent.type === 'MemberExpression') {
refId = refId.parent;
}
- if (sourceCode.getText(refId) !== componentName) {
+ if (getText(context, refId) !== componentName) {
return false;
}
if (refId.type === 'MemberExpression') {
@@ -776,7 +787,7 @@ function componentRule(rule, context) {
&& node.callee.type === 'Identifier'
&& node.callee.name.match(USE_HOOK_PREFIX_REGEX);
- const scope = (isPotentialReactHookCall || isPotentialHookCall) && context.getScope();
+ const scope = (isPotentialReactHookCall || isPotentialHookCall) && getScope(context, node);
const reactResolvedDefs = isPotentialReactHookCall
&& scope.references
@@ -888,7 +899,7 @@ function componentRule(rule, context) {
},
ThisExpression(node) {
- const component = utils.getParentStatelessComponent();
+ const component = utils.getParentStatelessComponent(node);
if (!component || !/Function/.test(component.type) || !node.parent.property) {
return;
}
diff --git a/lib/util/annotations.js b/lib/util/annotations.js
index 60aaef8cd0..24b18074c0 100644
--- a/lib/util/annotations.js
+++ b/lib/util/annotations.js
@@ -6,6 +6,8 @@
'use strict';
+const getFirstTokens = require('./eslint').getFirstTokens;
+
/**
* Checks if we are declaring a `props` argument with a flow type annotation.
* @param {ASTNode} node The AST node being checked.
@@ -19,7 +21,7 @@ function isAnnotatedFunctionPropsDeclaration(node, context) {
const typeNode = node.params[0].type === 'AssignmentPattern' ? node.params[0].left : node.params[0];
- const tokens = context.getFirstTokens(typeNode, 2);
+ const tokens = getFirstTokens(context, typeNode, 2);
const isAnnotated = typeNode.typeAnnotation;
const isDestructuredProps = typeNode.type === 'ObjectPattern';
const isProps = tokens[0].value === 'props' || (tokens[1] && tokens[1].value === 'props');
diff --git a/lib/util/ast.js b/lib/util/ast.js
index fd6019a3f2..5664dcb512 100644
--- a/lib/util/ast.js
+++ b/lib/util/ast.js
@@ -5,6 +5,11 @@
'use strict';
const estraverse = require('estraverse');
+const eslintUtil = require('./eslint');
+
+const getFirstTokens = eslintUtil.getFirstTokens;
+const getScope = eslintUtil.getScope;
+const getSourceCode = eslintUtil.getSourceCode;
// const pragmaUtil = require('./pragma');
/**
@@ -186,7 +191,7 @@ function getComponentProperties(node) {
* @return {ASTNode} the first node in the line
*/
function getFirstNodeInLine(context, node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
let token = node;
let lines;
do {
@@ -253,10 +258,11 @@ function isClass(node) {
/**
* Check if we are in a class constructor
* @param {Context} context
+ * @param {ASTNode} node The AST node being checked.
* @return {boolean}
*/
-function inConstructor(context) {
- let scope = context.getScope();
+function inConstructor(context, node) {
+ let scope = getScope(context, node);
while (scope) {
// @ts-ignore
if (scope.block && scope.block.parent && scope.block.parent.kind === 'constructor') {
@@ -284,7 +290,7 @@ function stripQuotes(string) {
*/
function getKeyValue(context, node) {
if (node.type === 'ObjectTypeProperty') {
- const tokens = context.getSourceCode().getFirstTokens(node, 2);
+ const tokens = getFirstTokens(context, node, 2);
return (tokens[0].value === '+' || tokens[0].value === '-'
? tokens[1].value
: stripQuotes(tokens[0].value)
@@ -311,7 +317,7 @@ function getKeyValue(context, node) {
* @returns {boolean}
*/
function isParenthesized(context, node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const previousToken = sourceCode.getTokenBefore(node);
const nextToken = sourceCode.getTokenAfter(node);
diff --git a/lib/util/componentUtil.js b/lib/util/componentUtil.js
index 35d54edcc5..f98762a49a 100644
--- a/lib/util/componentUtil.js
+++ b/lib/util/componentUtil.js
@@ -2,6 +2,11 @@
const doctrine = require('doctrine');
const pragmaUtil = require('./pragma');
+const eslintUtil = require('./eslint');
+
+const getScope = eslintUtil.getScope;
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
// eslint-disable-next-line valid-jsdoc
/**
@@ -57,7 +62,7 @@ function isES5Component(node, context) {
* @returns {boolean}
*/
function isExplicitComponent(node, context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
let comment;
// Sometimes the passed node may not have been parsed yet by eslint, and this function call crashes.
// Can be removed when eslint sets "parent" property for all nodes on initial AST traversal: https://github.com/eslint/eslint-scope/issues/27
@@ -116,13 +121,14 @@ function isES6Component(node, context) {
/**
* Get the parent ES5 component node from the current scope
* @param {Context} context
+ * @param {ASTNode} node
* @returns {ASTNode|null}
*/
-function getParentES5Component(context) {
- let scope = context.getScope();
+function getParentES5Component(context, node) {
+ let scope = getScope(context, node);
while (scope) {
// @ts-ignore
- const node = scope.block && scope.block.parent && scope.block.parent.parent;
+ node = scope.block && scope.block.parent && scope.block.parent.parent;
if (node && isES5Component(node, context)) {
return node;
}
@@ -134,14 +140,15 @@ function getParentES5Component(context) {
/**
* Get the parent ES6 component node from the current scope
* @param {Context} context
+ * @param {ASTNode} node
* @returns {ASTNode | null}
*/
-function getParentES6Component(context) {
- let scope = context.getScope();
+function getParentES6Component(context, node) {
+ let scope = getScope(context, node);
while (scope && scope.type !== 'class') {
scope = scope.upper;
}
- const node = scope && scope.block;
+ node = scope && scope.block;
if (!node || !isES6Component(node, context)) {
return null;
}
@@ -156,9 +163,8 @@ function getParentES6Component(context) {
*/
function isPureComponent(node, context) {
const pragma = getPragma(context);
- const sourceCode = context.getSourceCode();
if (node.superClass) {
- return new RegExp(`^(${pragma}\\.)?PureComponent$`).test(sourceCode.getText(node.superClass));
+ return new RegExp(`^(${pragma}\\.)?PureComponent$`).test(getText(context, node.superClass));
}
return false;
}
diff --git a/lib/util/defaultProps.js b/lib/util/defaultProps.js
index 44b42454ce..cd14c7fa41 100644
--- a/lib/util/defaultProps.js
+++ b/lib/util/defaultProps.js
@@ -10,12 +10,11 @@ const componentUtil = require('./componentUtil');
const propsUtil = require('./props');
const variableUtil = require('./variable');
const propWrapperUtil = require('./propWrapper');
+const getText = require('./eslint').getText;
const QUOTES_REGEX = /^["']|["']$/g;
module.exports = function defaultPropsInstructions(context, components, utils) {
- const sourceCode = context.getSourceCode();
-
/**
* Try to resolve the node passed in to a variable in the current scope. If the node passed in is not
* an Identifier, then the node is simply returned.
@@ -24,7 +23,7 @@ module.exports = function defaultPropsInstructions(context, components, utils) {
*/
function resolveNodeValue(node) {
if (node.type === 'Identifier') {
- return variableUtil.findVariableByName(context, node.name);
+ return variableUtil.findVariableByName(context, node, node.name);
}
if (
node.type === 'CallExpression'
@@ -51,7 +50,7 @@ module.exports = function defaultPropsInstructions(context, components, utils) {
}
return objectExpression.properties.map((defaultProp) => ({
- name: sourceCode.getText(defaultProp.key).replace(QUOTES_REGEX, ''),
+ name: getText(context, defaultProp.key).replace(QUOTES_REGEX, ''),
node: defaultProp,
}));
}
@@ -172,7 +171,7 @@ module.exports = function defaultPropsInstructions(context, components, utils) {
}
// find component this propTypes/defaultProps belongs to
- const component = components.get(componentUtil.getParentES6Component(context));
+ const component = components.get(componentUtil.getParentES6Component(context, node));
if (!component) {
return;
}
@@ -215,7 +214,7 @@ module.exports = function defaultPropsInstructions(context, components, utils) {
}
// find component this propTypes/defaultProps belongs to
- const component = components.get(componentUtil.getParentES6Component(context));
+ const component = components.get(componentUtil.getParentES6Component(context, node));
if (!component) {
return;
}
diff --git a/lib/util/eslint.js b/lib/util/eslint.js
new file mode 100644
index 0000000000..79a0537f3b
--- /dev/null
+++ b/lib/util/eslint.js
@@ -0,0 +1,46 @@
+'use strict';
+
+function getSourceCode(context) {
+ return context.getSourceCode ? context.getSourceCode() : context.sourceCode;
+}
+
+function getAncestors(context, node) {
+ const sourceCode = getSourceCode(context);
+ return sourceCode.getAncestors ? sourceCode.getAncestors(node) : context.getAncestors();
+}
+
+function getScope(context, node) {
+ const sourceCode = getSourceCode(context);
+ if (sourceCode.getScope) {
+ return sourceCode.getScope(node);
+ }
+
+ return context.getScope();
+}
+
+function markVariableAsUsed(name, node, context) {
+ const sourceCode = getSourceCode(context);
+ return sourceCode.markVariableAsUsed
+ ? sourceCode.markVariableAsUsed(name, node)
+ : context.markVariableAsUsed(name);
+}
+
+function getFirstTokens(context, node, count) {
+ const sourceCode = getSourceCode(context);
+ return sourceCode.getFirstTokens ? sourceCode.getFirstTokens(node, count) : context.getFirstTokens(node, count);
+}
+
+function getText(context) {
+ const sourceCode = getSourceCode(context);
+ const args = Array.prototype.slice.call(arguments, 1);
+ return sourceCode.getText ? sourceCode.getText.apply(sourceCode, args) : context.getSource.apply(context, args);
+}
+
+module.exports = {
+ getAncestors,
+ getFirstTokens,
+ getScope,
+ getSourceCode,
+ getText,
+ markVariableAsUsed,
+};
diff --git a/lib/util/isCreateElement.js b/lib/util/isCreateElement.js
index c28dc563fb..9e531964fa 100644
--- a/lib/util/isCreateElement.js
+++ b/lib/util/isCreateElement.js
@@ -5,11 +5,11 @@ const isDestructuredFromPragmaImport = require('./isDestructuredFromPragmaImport
/**
* Checks if the node is a createElement call
- * @param {ASTNode} node - The AST node being checked.
* @param {Context} context - The AST node being checked.
- * @returns {Boolean} - True if node is a createElement call object literal, False if not.
+ * @param {ASTNode} node - The AST node being checked.
+ * @returns {boolean} - True if node is a createElement call object literal, False if not.
*/
-module.exports = function isCreateElement(node, context) {
+module.exports = function isCreateElement(context, node) {
if (
node.callee
&& node.callee.type === 'MemberExpression'
@@ -24,7 +24,7 @@ module.exports = function isCreateElement(node, context) {
node
&& node.callee
&& node.callee.name === 'createElement'
- && isDestructuredFromPragmaImport('createElement', context)
+ && isDestructuredFromPragmaImport(context, node, 'createElement')
) {
return true;
}
diff --git a/lib/util/isDestructuredFromPragmaImport.js b/lib/util/isDestructuredFromPragmaImport.js
index 6f8deb08bc..4d64596274 100644
--- a/lib/util/isDestructuredFromPragmaImport.js
+++ b/lib/util/isDestructuredFromPragmaImport.js
@@ -6,13 +6,14 @@ const variableUtil = require('./variable');
/**
* Check if variable is destructured from pragma import
*
- * @param {string} variable The variable name to check
* @param {Context} context eslint context
- * @returns {Boolean} True if createElement is destructured from the pragma
+ * @param {ASTNode} node The AST node to check
+ * @param {string} variable The variable name to check
+ * @returns {boolean} True if createElement is destructured from the pragma
*/
-module.exports = function isDestructuredFromPragmaImport(variable, context) {
+module.exports = function isDestructuredFromPragmaImport(context, node, variable) {
const pragma = pragmaUtil.getFromContext(context);
- const variables = variableUtil.variablesInScope(context);
+ const variables = variableUtil.variablesInScope(context, node);
const variableInScope = variableUtil.getVariable(variables, variable);
if (variableInScope) {
const latestDef = variableUtil.getLatestVariableDefinition(variableInScope);
diff --git a/lib/util/jsx.js b/lib/util/jsx.js
index 55073bfe1e..07a09a8022 100644
--- a/lib/util/jsx.js
+++ b/lib/util/jsx.js
@@ -86,13 +86,13 @@ function isWhiteSpaces(value) {
/**
* Check if the node is returning JSX or null
*
- * @param {ASTNode} ASTnode The AST node being checked
* @param {Context} context The context of `ASTNode`.
+ * @param {ASTNode} ASTnode The AST node being checked
* @param {Boolean} [strict] If true, in a ternary condition the node must return JSX in both cases
* @param {Boolean} [ignoreNull] If true, null return values will be ignored
* @returns {Boolean} True if the node is returning JSX or null, false if not
*/
-function isReturningJSX(ASTnode, context, strict, ignoreNull) {
+function isReturningJSX(context, ASTnode, strict, ignoreNull) {
const isJSXValue = (node) => {
if (!node) {
return false;
@@ -114,14 +114,14 @@ function isReturningJSX(ASTnode, context, strict, ignoreNull) {
case 'JSXFragment':
return true;
case 'CallExpression':
- return isCreateElement(node, context);
+ return isCreateElement(context, node);
case 'Literal':
if (!ignoreNull && node.value === null) {
return true;
}
return false;
case 'Identifier': {
- const variable = variableUtil.findVariableByName(context, node.name);
+ const variable = variableUtil.findVariableByName(context, node, node.name);
return isJSX(variable);
}
default:
diff --git a/lib/util/makeNoMethodSetStateRule.js b/lib/util/makeNoMethodSetStateRule.js
index 1225092802..faee6de163 100644
--- a/lib/util/makeNoMethodSetStateRule.js
+++ b/lib/util/makeNoMethodSetStateRule.js
@@ -9,6 +9,7 @@ const findLast = require('array.prototype.findlast');
const docsUrl = require('./docsUrl');
const report = require('./report');
+const getAncestors = require('./eslint').getAncestors;
const testReactVersion = require('./version').testReactVersion;
// ------------------------------------------------------------------------------
@@ -93,7 +94,7 @@ module.exports = function makeNoMethodSetStateRule(methodName, shouldCheckUnsafe
) {
return;
}
- const ancestors = context.getAncestors(callee);
+ const ancestors = getAncestors(context, node);
let depth = 0;
findLast(ancestors, (ancestor) => {
// ancestors.some((ancestor) => {
diff --git a/lib/util/pragma.js b/lib/util/pragma.js
index 2bde47fb37..4114442d05 100644
--- a/lib/util/pragma.js
+++ b/lib/util/pragma.js
@@ -5,6 +5,8 @@
'use strict';
+const getSourceCode = require('./eslint').getSourceCode;
+
const JSX_ANNOTATION_REGEX = /@jsx\s+([^\s]+)/;
// Does not check for reserved keywords or unicode characters
const JS_IDENTIFIER_REGEX = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/;
@@ -48,7 +50,7 @@ function getFragmentFromContext(context) {
function getFromContext(context) {
let pragma = 'React';
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
const pragmaNode = sourceCode.getAllComments().find((node) => JSX_ANNOTATION_REGEX.test(node.value));
if (pragmaNode) {
diff --git a/lib/util/propTypes.js b/lib/util/propTypes.js
index a189f871ca..6f879e2347 100644
--- a/lib/util/propTypes.js
+++ b/lib/util/propTypes.js
@@ -13,6 +13,12 @@ const testFlowVersion = require('./version').testFlowVersion;
const propWrapperUtil = require('./propWrapper');
const astUtil = require('./ast');
const isFirstLetterCapitalized = require('./isFirstLetterCapitalized');
+const eslintUtil = require('./eslint');
+
+const getFirstTokens = eslintUtil.getFirstTokens;
+const getScope = eslintUtil.getScope;
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
/**
* Check if node is function type.
@@ -361,14 +367,15 @@ module.exports = function propTypesInstructions(context, components, utils) {
/**
* Resolve node of type Identifier when building declaration types.
* @param {ASTNode} node
+ * @param {ASTNode} rootNode
* @param {Function} callback called with the resolved value only if resolved.
*/
- function resolveValueForIdentifierNode(node, callback) {
+ function resolveValueForIdentifierNode(node, rootNode, callback) {
if (
node
&& node.type === 'Identifier'
) {
- const scope = context.getScope();
+ const scope = getScope(context, rootNode);
const identVariable = scope.variableScope.variables.find(
(variable) => variable.name === node.name
);
@@ -384,10 +391,11 @@ module.exports = function propTypesInstructions(context, components, utils) {
* The representation is used to verify nested used properties.
* @param {ASTNode} value Node of the PropTypes for the desired property
* @param {string} parentName
+ * @param {ASTNode} rootNode
* @return {Object} The representation of the declaration, empty object means
* the property is declared without the need for further analysis.
*/
- function buildReactDeclarationTypes(value, parentName) {
+ function buildReactDeclarationTypes(value, parentName, rootNode) {
if (
value
&& value.callee
@@ -409,7 +417,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
// propTypes = {
// example: variableType
// }
- resolveValueForIdentifierNode(value, (newValue) => {
+ resolveValueForIdentifierNode(value, rootNode, (newValue) => {
identNodeResolved = true;
value = newValue;
});
@@ -431,7 +439,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
// example: variableType.isRequired
// }
if (!identNodeResolved) {
- resolveValueForIdentifierNode(value, (newValue) => {
+ resolveValueForIdentifierNode(value, rootNode, (newValue) => {
value = newValue;
});
}
@@ -462,7 +470,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
iterateProperties(context, argument.properties, (childKey, childValue, propNode) => {
if (childValue) { // skip spread propTypes
const fullName = [parentName, childKey].join('.');
- const types = buildReactDeclarationTypes(childValue, fullName);
+ const types = buildReactDeclarationTypes(childValue, fullName, rootNode);
types.fullName = fullName;
types.name = childKey;
types.node = propNode;
@@ -474,7 +482,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
case 'arrayOf':
case 'objectOf': {
const fullName = [parentName, '*'].join('.');
- const child = buildReactDeclarationTypes(argument, fullName);
+ const child = buildReactDeclarationTypes(argument, fullName, rootNode);
child.fullName = fullName;
child.name = '__ANY_KEY__';
child.node = argument;
@@ -497,7 +505,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
/** @type {UnionTypeDefinition} */
const unionTypeDefinition = {
type: 'union',
- children: argument.elements.map((element) => buildReactDeclarationTypes(element, parentName)),
+ children: argument.elements.map((element) => buildReactDeclarationTypes(element, parentName, rootNode)),
};
if (unionTypeDefinition.children.length === 0) {
// no complex type found, simply accept everything
@@ -573,13 +581,14 @@ module.exports = function propTypesInstructions(context, components, utils) {
}
class DeclarePropTypesForTSTypeAnnotation {
- constructor(propTypes, declaredPropTypes) {
+ constructor(propTypes, declaredPropTypes, rootNode) {
this.propTypes = propTypes;
this.declaredPropTypes = declaredPropTypes;
this.foundDeclaredPropertiesList = [];
this.referenceNameMap = new Set();
- this.sourceCode = context.getSourceCode();
+ this.sourceCode = getSourceCode(context);
this.shouldIgnorePropTypes = false;
+ this.rootNode = rootNode;
this.visitTSNode(this.propTypes);
this.endAndStructDeclaredPropTypes();
}
@@ -609,7 +618,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
this.visitTSNode(typeAnnotation);
} else if (astUtil.isTSTypeParameterInstantiation(node)) {
if (Array.isArray(node.params)) {
- node.params.forEach(this.visitTSNode, this);
+ node.params.forEach((x) => this.visitTSNode(x));
}
} else {
this.shouldIgnorePropTypes = true;
@@ -655,7 +664,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
return;
}
if (typeName === 'ReturnType') {
- this.convertReturnTypeToPropTypes(node);
+ this.convertReturnTypeToPropTypes(node, this.rootNode);
return;
}
// Prevent recursive inheritance will cause maximum callstack.
@@ -709,24 +718,24 @@ module.exports = function propTypesInstructions(context, components, utils) {
this.visitTSNode(typeAnnotation);
}
if (Array.isArray(node.extends)) {
- node.extends.forEach(this.visitTSNode, this);
+ node.extends.forEach((x) => this.visitTSNode(x));
// This line is trying to handle typescript-eslint-parser
// typescript-eslint-parser extension is name as heritage
} else if (Array.isArray(node.heritage)) {
- node.heritage.forEach(this.visitTSNode, this);
+ node.heritage.forEach((x) => this.visitTSNode(x));
}
}
convertIntersectionTypeToPropTypes(node) {
if (!node) return;
if (Array.isArray(node.types)) {
- node.types.forEach(this.visitTSNode, this);
+ node.types.forEach((x) => this.visitTSNode(x));
} else {
this.shouldIgnorePropTypes = true;
}
}
- convertReturnTypeToPropTypes(node) {
+ convertReturnTypeToPropTypes(node, rootNode) {
// ReturnType should always have one parameter
const nodeTypeParams = node.typeParameters;
if (nodeTypeParams) {
@@ -776,7 +785,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
this.shouldIgnorePropTypes = true;
return;
}
- const types = buildReactDeclarationTypes(value, key);
+ const types = buildReactDeclarationTypes(value, key, rootNode);
types.fullName = key;
types.name = key;
types.node = propNode;
@@ -850,8 +859,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
* Mark a prop type as declared
* @param {ASTNode} node The AST node being checked.
* @param {ASTNode} propTypes The AST node containing the proptypes
+ * @param {ASTNode} rootNode
*/
- function markPropTypesAsDeclared(node, propTypes) {
+ function markPropTypesAsDeclared(node, propTypes, rootNode) {
let componentNode = node;
while (componentNode && !components.get(componentNode)) {
componentNode = componentNode.parent;
@@ -869,7 +879,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
ignorePropsValidation = true;
return;
}
- const types = buildReactDeclarationTypes(value, key);
+ const types = buildReactDeclarationTypes(value, key, rootNode);
types.fullName = key;
types.name = key;
types.node = propNode;
@@ -903,10 +913,11 @@ module.exports = function propTypesInstructions(context, components, utils) {
ignorePropsValidation = true;
break;
}
- const parentProp = context.getSource(propTypes.parent.left.object).replace(/^.*\.propTypes\./, '');
+ const parentProp = getText(context, propTypes.parent.left.object).replace(/^.*\.propTypes\./, '');
const types = buildReactDeclarationTypes(
propTypes.parent.right,
- parentProp
+ parentProp,
+ rootNode
);
types.name = propTypes.property.name;
@@ -934,12 +945,11 @@ module.exports = function propTypesInstructions(context, components, utils) {
break;
}
case 'Identifier': {
- const variablesInScope = variableUtil.variablesInScope(context);
- const firstMatchingVariable = variablesInScope
+ const firstMatchingVariable = variableUtil.variablesInScope(context, node)
.find((variableInScope) => variableInScope.name === propTypes.name);
if (firstMatchingVariable) {
const defInScope = firstMatchingVariable.defs[firstMatchingVariable.defs.length - 1];
- markPropTypesAsDeclared(node, defInScope.node && defInScope.node.init);
+ markPropTypesAsDeclared(node, defInScope.node && defInScope.node.init, rootNode);
return;
}
ignorePropsValidation = true;
@@ -949,11 +959,11 @@ module.exports = function propTypesInstructions(context, components, utils) {
if (
propWrapperUtil.isPropWrapperFunction(
context,
- context.getSourceCode().getText(propTypes.callee)
+ getText(context, propTypes.callee)
)
&& propTypes.arguments && propTypes.arguments[0]
) {
- markPropTypesAsDeclared(node, propTypes.arguments[0]);
+ markPropTypesAsDeclared(node, propTypes.arguments[0], rootNode);
return;
}
break;
@@ -974,7 +984,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
break;
case 'TSTypeReference':
case 'TSTypeAnnotation': {
- const tsTypeAnnotation = new DeclarePropTypesForTSTypeAnnotation(propTypes, declaredPropTypes);
+ const tsTypeAnnotation = new DeclarePropTypesForTSTypeAnnotation(propTypes, declaredPropTypes, rootNode);
ignorePropsValidation = tsTypeAnnotation.shouldIgnorePropTypes;
declaredPropTypes = tsTypeAnnotation.declaredPropTypes;
}
@@ -995,8 +1005,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
/**
* @param {ASTNode} node We expect either an ArrowFunctionExpression,
* FunctionDeclaration, or FunctionExpression
+ * @param {ASTNode} rootNode
*/
- function markAnnotatedFunctionArgumentsAsDeclared(node) {
+ function markAnnotatedFunctionArgumentsAsDeclared(node, rootNode) {
if (!node.params || !node.params.length) {
return;
}
@@ -1017,7 +1028,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
) {
const propTypesParams = node.parent.typeParameters;
const declaredPropTypes = {};
- const obj = new DeclarePropTypesForTSTypeAnnotation(propTypesParams.params[1], declaredPropTypes);
+ const obj = new DeclarePropTypesForTSTypeAnnotation(propTypesParams.params[1], declaredPropTypes, rootNode);
components.set(node, {
declaredPropTypes: obj.declaredPropTypes,
ignorePropsValidation: obj.shouldIgnorePropTypes,
@@ -1048,13 +1059,13 @@ module.exports = function propTypesInstructions(context, components, utils) {
if (param.typeAnnotation && param.typeAnnotation.typeAnnotation && param.typeAnnotation.typeAnnotation.type === 'UnionTypeAnnotation') {
param.typeAnnotation.typeAnnotation.types.forEach((annotation) => {
if (annotation.type === 'GenericTypeAnnotation') {
- markPropTypesAsDeclared(node, resolveTypeAnnotation(annotation));
+ markPropTypesAsDeclared(node, resolveTypeAnnotation(annotation), rootNode);
} else {
- markPropTypesAsDeclared(node, annotation);
+ markPropTypesAsDeclared(node, annotation, rootNode);
}
});
} else {
- markPropTypesAsDeclared(node, resolveTypeAnnotation(param));
+ markPropTypesAsDeclared(node, resolveTypeAnnotation(param), rootNode);
}
} else {
// implements what's discussed here: https://github.com/jsx-eslint/eslint-plugin-react/issues/2777#issuecomment-683944481
@@ -1070,7 +1081,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
if (!isValidReactGenericTypeAnnotation(annotation)) return;
- markPropTypesAsDeclared(node, resolveTypeAnnotation(siblingIdentifier));
+ markPropTypesAsDeclared(node, resolveTypeAnnotation(siblingIdentifier), rootNode);
}
}
@@ -1109,7 +1120,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
*/
function isAnnotatedClassPropsDeclaration(node) {
if (node && (node.type === 'ClassProperty' || node.type === 'PropertyDefinition')) {
- const tokens = context.getFirstTokens(node, 2);
+ const tokens = getFirstTokens(context, node, 2);
if (
node.typeAnnotation && (
tokens[0].value === 'props'
@@ -1132,15 +1143,15 @@ module.exports = function propTypesInstructions(context, components, utils) {
ClassDeclaration(node) {
if (isSuperTypeParameterPropsDeclaration(node)) {
- markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
+ markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node), node);
}
},
'ClassProperty, PropertyDefinition'(node) {
if (isAnnotatedClassPropsDeclaration(node)) {
- markPropTypesAsDeclared(node, resolveTypeAnnotation(node));
+ markPropTypesAsDeclared(node, resolveTypeAnnotation(node), node);
} else if (propsUtil.isPropTypesDeclaration(node)) {
- markPropTypesAsDeclared(node, node.value);
+ markPropTypesAsDeclared(node, node.value, node);
}
},
@@ -1150,13 +1161,13 @@ module.exports = function propTypesInstructions(context, components, utils) {
if (!propsUtil.isPropTypesDeclaration(property)) {
return;
}
- markPropTypesAsDeclared(node, property.value);
+ markPropTypesAsDeclared(node, property.value, node);
});
},
FunctionExpression(node) {
if (node.parent.type !== 'MethodDefinition') {
- markAnnotatedFunctionArgumentsAsDeclared(node);
+ markAnnotatedFunctionArgumentsAsDeclared(node, node);
}
},
@@ -1193,7 +1204,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
return;
}
try {
- markPropTypesAsDeclared(component.node, node.parent.right || node.parent);
+ markPropTypesAsDeclared(component.node, node.parent.right || node.parent, node);
} catch (e) {
if (e.constructor !== RangeError) { throw e; }
}
@@ -1213,7 +1224,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
}
if (i >= 0) {
- markPropTypesAsDeclared(node, node.value.body.body[i].argument);
+ markPropTypesAsDeclared(node, node.value.body.body[i].argument, node);
}
},
@@ -1244,7 +1255,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
'Program:exit'() {
classExpressions.forEach((node) => {
if (isSuperTypeParameterPropsDeclaration(node)) {
- markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node));
+ markPropTypesAsDeclared(node, resolveSuperParameterPropsType(node), node);
}
});
},
diff --git a/lib/util/propTypesSort.js b/lib/util/propTypesSort.js
index 505f346a3b..12982430b3 100644
--- a/lib/util/propTypesSort.js
+++ b/lib/util/propTypesSort.js
@@ -7,6 +7,10 @@
const toSorted = require('array.prototype.tosorted');
const astUtil = require('./ast');
+const eslintUtil = require('./eslint');
+
+const getSourceCode = eslintUtil.getSourceCode;
+const getText = eslintUtil.getText;
/**
* Returns the value name of a node.
@@ -114,8 +118,8 @@ const commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start a
/**
* Fixes sort order of prop types.
*
+ * @param {Context} context the second element to compare.
* @param {Fixer} fixer the first element to compare.
- * @param {Object} context the second element to compare.
* @param {Array} declarations The context of the two nodes.
* @param {Boolean=} ignoreCase whether or not to ignore case when comparing the two elements.
* @param {Boolean=} requiredFirst whether or not to sort required elements first.
@@ -125,8 +129,8 @@ const commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start a
* @returns {Object|*|{range, text}} the sort order of the two elements.
*/
function fixPropTypesSort(
- fixer,
context,
+ fixer,
declarations,
ignoreCase,
requiredFirst,
@@ -136,7 +140,7 @@ function fixPropTypesSort(
) {
function sortInSource(allNodes, source) {
const originalSource = source;
- const sourceCode = context.getSourceCode();
+ const sourceCode = getSourceCode(context);
for (let i = 0; i < allNodes.length; i++) {
const node = allNodes[i];
let commentAfter = [];
@@ -178,9 +182,9 @@ function fixPropTypesSort(
(a, b) => sorter(a, b, context, ignoreCase, requiredFirst, callbacksLast, noSortAlphabetically)
);
+ const sourceCodeText = getText(context);
source = nodes.reduceRight((acc, attr, index) => {
const sortedAttr = sortedAttributes[index];
- const sourceCodeText = sourceCode.getText();
const commentNode = commentnodeMap.get(sortedAttr);
let sortedAttrText = sourceCodeText.slice(commentNode.start, commentNode.end);
if (sortShapeProp && isShapeProp(sortedAttr.value)) {
@@ -199,7 +203,7 @@ function fixPropTypesSort(
return source;
}
- const source = sortInSource(declarations, context.getSourceCode().getText());
+ const source = sortInSource(declarations, getText(context));
const rangeStart = commentnodeMap.get(declarations[0]).start;
const rangeEnd = commentnodeMap.get(declarations[declarations.length - 1]).end;
diff --git a/lib/util/usedPropTypes.js b/lib/util/usedPropTypes.js
index 6a0a650333..9ecef0af37 100644
--- a/lib/util/usedPropTypes.js
+++ b/lib/util/usedPropTypes.js
@@ -10,6 +10,10 @@ const astUtil = require('./ast');
const componentUtil = require('./componentUtil');
const testReactVersion = require('./version').testReactVersion;
const ast = require('./ast');
+const eslintUtil = require('./eslint');
+
+const getScope = eslintUtil.getScope;
+const getSourceCode = eslintUtil.getSourceCode;
// ------------------------------------------------------------------------------
// Constants
@@ -80,11 +84,12 @@ function mustBeValidated(component) {
/**
* Check if we are in a lifecycle method
* @param {object} context
+ * @param {ASTNode} node The AST node being checked.
* @param {boolean} checkAsyncSafeLifeCycles
* @return {boolean} true if we are in a class constructor, false if not
*/
-function inLifeCycleMethod(context, checkAsyncSafeLifeCycles) {
- let scope = context.getScope();
+function inLifeCycleMethod(context, node, checkAsyncSafeLifeCycles) {
+ let scope = getScope(context, node);
while (scope) {
if (scope.block && scope.block.parent && scope.block.parent.key) {
const name = scope.block.parent.key.name;
@@ -158,11 +163,11 @@ function isSetStateUpdater(node) {
&& node.parent.arguments[0] === node;
}
-function isPropArgumentInSetStateUpdater(context, name) {
+function isPropArgumentInSetStateUpdater(context, node, name) {
if (typeof name !== 'string') {
return;
}
- let scope = context.getScope();
+ let scope = getScope(context, node);
while (scope) {
const unwrappedParentCalleeNode = scope.block
&& scope.block.parent
@@ -186,10 +191,11 @@ function isPropArgumentInSetStateUpdater(context, name) {
/**
* @param {Context} context
+ * @param {ASTNode} node
* @returns {boolean}
*/
-function isInClassComponent(context) {
- return !!(componentUtil.getParentES6Component(context) || componentUtil.getParentES5Component(context));
+function isInClassComponent(context, node) {
+ return !!(componentUtil.getParentES6Component(context, node) || componentUtil.getParentES5Component(context, node));
}
/**
@@ -211,22 +217,22 @@ function isThisDotProps(node) {
* @returns {Boolean} True if the prop has spread operator, false if not.
*/
function hasSpreadOperator(context, node) {
- const tokens = context.getSourceCode().getTokens(node);
+ const tokens = getSourceCode(context).getTokens(node);
return tokens.length && tokens[0].value === '...';
}
/**
* Checks if the node is a propTypes usage of the form `this.props.*`, `props.*`, `prevProps.*`, or `nextProps.*`.
- * @param {ASTNode} node
* @param {Context} context
+ * @param {ASTNode} node
* @param {Object} utils
* @param {boolean} checkAsyncSafeLifeCycles
* @returns {boolean}
*/
-function isPropTypesUsageByMemberExpression(node, context, utils, checkAsyncSafeLifeCycles) {
+function isPropTypesUsageByMemberExpression(context, node, utils, checkAsyncSafeLifeCycles) {
const unwrappedObjectNode = ast.unwrapTSAsExpression(node.object);
- if (isInClassComponent(context)) {
+ if (isInClassComponent(context, node)) {
// this.props.*
if (isThisDotProps(unwrappedObjectNode)) {
return true;
@@ -234,12 +240,12 @@ function isPropTypesUsageByMemberExpression(node, context, utils, checkAsyncSafe
// props.* or prevProps.* or nextProps.*
if (
isCommonVariableNameForProps(unwrappedObjectNode.name)
- && (inLifeCycleMethod(context, checkAsyncSafeLifeCycles) || astUtil.inConstructor(context))
+ && (inLifeCycleMethod(context, node, checkAsyncSafeLifeCycles) || astUtil.inConstructor(context, node))
) {
return true;
}
// this.setState((_, props) => props.*))
- if (isPropArgumentInSetStateUpdater(context, unwrappedObjectNode.name)) {
+ if (isPropArgumentInSetStateUpdater(context, node, unwrappedObjectNode.name)) {
return true;
}
return false;
@@ -250,13 +256,13 @@ function isPropTypesUsageByMemberExpression(node, context, utils, checkAsyncSafe
/**
* Retrieve the name of a property node
- * @param {ASTNode} node The AST node with the property.
* @param {Context} context
+ * @param {ASTNode} node The AST node with the property.
* @param {Object} utils
* @param {boolean} checkAsyncSafeLifeCycles
* @return {string|undefined} the name of the property or undefined if not found
*/
-function getPropertyName(node, context, utils, checkAsyncSafeLifeCycles) {
+function getPropertyName(context, node, utils, checkAsyncSafeLifeCycles) {
const property = node.property;
if (property) {
switch (property.type) {
@@ -274,7 +280,7 @@ function getPropertyName(node, context, utils, checkAsyncSafeLifeCycles) {
}
// Accept number as well but only accept props[123]
if (typeof property.value === 'number') {
- if (isPropTypesUsageByMemberExpression(node, context, utils, checkAsyncSafeLifeCycles)) {
+ if (isPropTypesUsageByMemberExpression(context, node, utils, checkAsyncSafeLifeCycles)) {
return property.raw;
}
}
@@ -309,7 +315,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
switch (node.type) {
case 'OptionalMemberExpression':
case 'MemberExpression':
- name = getPropertyName(node, context, utils, checkAsyncSafeLifeCycles);
+ name = getPropertyName(context, node, utils, checkAsyncSafeLifeCycles);
if (name) {
allNames = parentNames.concat(name);
if (
@@ -362,7 +368,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
throw new Error(`${node.type} ASTNodes are not handled by markPropTypesAsUsed`);
}
- const component = components.get(utils.getParentComponent());
+ const component = components.get(utils.getParentComponent(node));
const usedPropTypes = (component && component.usedPropTypes) || [];
let ignoreUnusedPropTypesValidation = (component && component.ignoreUnusedPropTypesValidation) || false;
@@ -472,7 +478,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
const unwrappedInitNode = ast.unwrapTSAsExpression(node.init);
// let props = this.props
- if (isThisDotProps(unwrappedInitNode) && isInClassComponent(context) && node.id.type === 'Identifier') {
+ if (isThisDotProps(unwrappedInitNode) && isInClassComponent(context, node) && node.id.type === 'Identifier') {
propVariables.set(node.id.name, []);
}
@@ -501,14 +507,14 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
// let {firstname} = props
if (
isCommonVariableNameForProps(unwrappedInitNode.name)
- && (utils.getParentStatelessComponent() || isInLifeCycleMethod(node, checkAsyncSafeLifeCycles))
+ && (utils.getParentStatelessComponent(node) || isInLifeCycleMethod(node, checkAsyncSafeLifeCycles))
) {
markPropTypesAsUsed(node.id);
return;
}
// let {firstname} = this.props
- if (isThisDotProps(unwrappedInitNode) && isInClassComponent(context)) {
+ if (isThisDotProps(unwrappedInitNode) && isInClassComponent(context, node)) {
markPropTypesAsUsed(node.id);
return;
}
@@ -532,14 +538,14 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
'FunctionExpression:exit': popScope,
JSXSpreadAttribute(node) {
- const component = components.get(utils.getParentComponent());
+ const component = components.get(utils.getParentComponent(node));
components.set(component ? component.node : node, {
ignoreUnusedPropTypesValidation: node.argument.type !== 'ObjectExpression',
});
},
'MemberExpression, OptionalMemberExpression'(node) {
- if (isPropTypesUsageByMemberExpression(node, context, utils, checkAsyncSafeLifeCycles)) {
+ if (isPropTypesUsageByMemberExpression(context, node, utils, checkAsyncSafeLifeCycles)) {
markPropTypesAsUsed(node);
return;
}
diff --git a/lib/util/variable.js b/lib/util/variable.js
index a93cf18b5e..2903c67344 100644
--- a/lib/util/variable.js
+++ b/lib/util/variable.js
@@ -6,6 +6,7 @@
'use strict';
const toReversed = require('array.prototype.toreversed');
+const getScope = require('./eslint').getScope;
/**
* Search a particular variable in a list
@@ -33,10 +34,11 @@ function getVariable(variables, name) {
* Contain a patch for babel-eslint to avoid https://github.com/babel/babel-eslint/issues/21
*
* @param {Object} context The current rule context.
+ * @param {ASTNode} node The node to start looking from.
* @returns {Array} The variables list
*/
-function variablesInScope(context) {
- let scope = context.getScope();
+function variablesInScope(context, node) {
+ let scope = getScope(context, node);
let variables = scope.variables;
while (scope.type !== 'global') {
@@ -56,11 +58,12 @@ function variablesInScope(context) {
/**
* Find a variable by name in the current scope.
* @param {Object} context The current rule context.
+ * @param {ASTNode} node The node to check. Must be an Identifier node.
* @param {string} name Name of the variable to look for.
* @returns {ASTNode|null} Return null if the variable could not be found, ASTNode otherwise.
*/
-function findVariableByName(context, name) {
- const variable = getVariable(variablesInScope(context), name);
+function findVariableByName(context, node, name) {
+ const variable = getVariable(variablesInScope(context, node), name);
if (!variable || !variable.defs[0] || !variable.defs[0].node) {
return null;
diff --git a/tests/lib/rules/function-component-definition.js b/tests/lib/rules/function-component-definition.js
index 8f0e96ee17..f5282bf6f7 100644
--- a/tests/lib/rules/function-component-definition.js
+++ b/tests/lib/rules/function-component-definition.js
@@ -807,11 +807,7 @@ ruleTester.run('function-component-definition', rule, {
return ;
}
`,
- output: `
- var Hello: React.FC = function(props) {
- return ;
- }
- `,
+ output: null,
options: [{ namedComponents: 'function-declaration' }],
errors: [{ messageId: 'function-declaration' }],
features: ['types'],
@@ -822,11 +818,7 @@ ruleTester.run('function-component-definition', rule, {
return ;
};
`,
- output: `
- var Hello: React.FC = (props) => {
- return ;
- };
- `,
+ output: null,
options: [{ namedComponents: 'function-declaration' }],
errors: [{ messageId: 'function-declaration' }],
features: ['types'],
@@ -852,11 +844,7 @@ ruleTester.run('function-component-definition', rule, {
return ;
}
`,
- output: `
- function Hello(props: Test) {
- return ;
- }
- `,
+ output: null,
options: [{ namedComponents: 'arrow-function' }],
errors: [{ messageId: 'arrow-function' }],
features: ['types'],
@@ -963,13 +951,7 @@ ruleTester.run('function-component-definition', rule, {
}
}
`,
- output: `
- function wrap(Component) {
- return function(props) {
- return
- }
- }
- `,
+ output: null,
errors: [{ messageId: 'arrow-function' }],
options: [{ unnamedComponents: 'arrow-function' }],
features: ['types'],
diff --git a/tests/lib/rules/jsx-closing-bracket-location.js b/tests/lib/rules/jsx-closing-bracket-location.js
index c23ec1943a..120f1e3638 100644
--- a/tests/lib/rules/jsx-closing-bracket-location.js
+++ b/tests/lib/rules/jsx-closing-bracket-location.js
@@ -419,7 +419,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_TAG },
+ data: {
+ location: MESSAGE_AFTER_TAG,
+ details: '',
+ },
},
],
},
@@ -434,7 +437,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -449,7 +455,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -536,7 +545,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -578,7 +590,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -644,7 +659,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -686,7 +704,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -1098,7 +1119,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_TAG },
+ data: {
+ location: MESSAGE_AFTER_TAG,
+ details: '',
+ },
},
],
},
@@ -1216,7 +1240,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -1258,7 +1285,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -1324,7 +1354,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -1366,7 +1399,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_PROPS },
+ data: {
+ location: MESSAGE_AFTER_PROPS,
+ details: '',
+ },
},
],
},
@@ -1778,7 +1814,10 @@ ruleTester.run('jsx-closing-bracket-location', rule, {
errors: [
{
messageId: 'bracketLocation',
- data: { location: MESSAGE_AFTER_TAG },
+ data: {
+ location: MESSAGE_AFTER_TAG,
+ details: '',
+ },
},
],
},
diff --git a/tests/lib/rules/jsx-fragments.js b/tests/lib/rules/jsx-fragments.js
index 1ee6fb3fa2..2807a15f75 100644
--- a/tests/lib/rules/jsx-fragments.js
+++ b/tests/lib/rules/jsx-fragments.js
@@ -142,7 +142,7 @@ ruleTester.run('jsx-fragments', rule, {
},
{
code: '<>>',
- output: '<>>', // should get '', but the old TS parser lacks opening/closing Fragment info
+ output: null, // should get '', but the old TS parser lacks opening/closing Fragment info
features: ['fragment', 'no-babel', 'ts', 'no-ts-new'],
options: ['element'],
settings,
diff --git a/tests/lib/rules/jsx-no-leaked-render.js b/tests/lib/rules/jsx-no-leaked-render.js
index f5729bf059..a6742a29cd 100644
--- a/tests/lib/rules/jsx-no-leaked-render.js
+++ b/tests/lib/rules/jsx-no-leaked-render.js
@@ -195,6 +195,24 @@ ruleTester.run('jsx-no-leaked-render', rule, {
`,
options: [{ validStrategies: ['coerce'] }],
},
+ {
+ code: `
+ const isOpen = true;
+ const Component = () => {
+ return 0} />
+ }
+ `,
+ options: [{ validStrategies: ['coerce'] }],
+ },
+ {
+ code: `
+ const isOpen = false;
+ const Component = () => {
+ return 0} />
+ }
+ `,
+ options: [{ validStrategies: ['coerce'] }],
+ },
]) || [],
invalid: parsers.all([].concat(
@@ -972,6 +990,26 @@ ruleTester.run('jsx-no-leaked-render', rule, {
line: 5,
column: 16,
}],
- } : []
+ } : [],
+ {
+ code: `
+ const isOpen = 0;
+ const Component = () => {
+ return 0} />
+ }
+ `,
+ output: `
+ const isOpen = 0;
+ const Component = () => {
+ return 0} />
+ }
+ `,
+ options: [{ validStrategies: ['coerce'] }],
+ errors: [{
+ message: 'Potential leaked value that might cause unintentionally rendered values or rendering crashes',
+ line: 4,
+ column: 33,
+ }],
+ }
)),
});
diff --git a/tests/lib/rules/jsx-no-useless-fragment.js b/tests/lib/rules/jsx-no-useless-fragment.js
index 22594aa6bf..d1b599a8b2 100644
--- a/tests/lib/rules/jsx-no-useless-fragment.js
+++ b/tests/lib/rules/jsx-no-useless-fragment.js
@@ -194,7 +194,7 @@ ruleTester.run('jsx-no-useless-fragment', rule, {
},
{
code: '<>{"a"}{"b"}>
',
- output: '<>{"a"}{"b"}>
',
+ output: null,
errors: [{ messageId: 'ChildOfHtmlElement', type: 'JSXFragment' }],
features: ['fragment', 'ts-old', 'no-ts-new', 'no-babel', 'no-default'],
},
diff --git a/tests/lib/rules/no-invalid-html-attribute.js b/tests/lib/rules/no-invalid-html-attribute.js
index f1e20aa9a6..b171d823a4 100644
--- a/tests/lib/rules/no-invalid-html-attribute.js
+++ b/tests/lib/rules/no-invalid-html-attribute.js
@@ -247,12 +247,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'alternatex',
attributeName: 'rel',
+ reportingValue: 'alternatex',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex' },
output: '',
},
],
@@ -266,12 +267,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'alternatex',
attributeName: 'rel',
+ reportingValue: 'alternatex',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex' },
output: 'React.createElement("a", { rel: "" })',
},
],
@@ -291,6 +293,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex' },
output: 'React.createElement("a", { rel: [""] })',
},
],
@@ -304,12 +307,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'alternatex',
attributeName: 'rel',
+ reportingValue: 'alternatex',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex' },
output: '',
},
],
@@ -323,12 +327,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'alternatex alternate',
attributeName: 'rel',
+ reportingValue: 'alternatex alternate',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex alternate' },
output: 'React.createElement("a", { rel: "" })',
},
],
@@ -348,6 +353,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex alternate' },
output: 'React.createElement("a", { rel: [""] })',
},
],
@@ -367,6 +373,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternatex' },
output: '',
},
],
@@ -386,6 +393,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternate alternatex' },
output: 'React.createElement("a", { rel: "" })',
},
],
@@ -405,6 +413,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternate alternatex' },
output: 'React.createElement("a", { rel: [""] })',
},
],
@@ -424,6 +433,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveDefault',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -443,6 +453,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
// suggestions: [
// {
// messageId: 'suggestRemoveDefault',
+ // data: { attributeName: 'rel' },
// output: 'React.createElement("html", { })',
// },
// ],
@@ -460,6 +471,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveEmpty',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -508,6 +520,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveDefault',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -524,6 +537,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveNonString',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -540,6 +554,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveNonString',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -552,10 +567,11 @@ ruleTester.run('no-invalid-html-attribute', rule, {
errors: [
{
messageId: 'onlyStrings',
- data: { attributeName: 'rel' },
+ data: { attributeName: 'rel', reportingValue: 'true' },
suggestions: [
{
messageId: 'suggestRemoveNonString',
+ data: { attributeName: 'rel', reportingValue: 'true' },
output: '',
},
],
@@ -572,6 +588,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveDefault',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -588,6 +605,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveDefault',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -607,6 +625,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'foobar' },
output: '',
},
],
@@ -623,6 +642,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -639,6 +659,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -655,6 +676,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -674,6 +696,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'foobar' },
output: '',
},
],
@@ -693,6 +716,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'foobar' },
output: 'React.createElement("a", { rel: ["noreferrer", "noopener", "" ] })',
},
],
@@ -712,6 +736,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'foobar' },
output: '',
},
],
@@ -731,6 +756,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'foobar' },
output: '',
},
],
@@ -745,6 +771,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'batgo' },
output: '',
},
],
@@ -753,6 +780,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'spaceDelimited',
data: { attributeName: 'rel' },
+ suggestions: [
+ {
+ messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
+ output: '',
+ },
+ ],
},
],
},
@@ -765,6 +799,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -781,6 +816,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -800,6 +836,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'batgo' },
output: '',
},
],
@@ -808,6 +845,13 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'spaceDelimited',
data: { attributeName: 'rel' },
+ suggestions: [
+ {
+ messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
+ output: '',
+ },
+ ],
},
],
},
@@ -823,6 +867,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'batgo' },
output: '',
},
],
@@ -839,6 +884,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -859,6 +905,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'canonical' },
output: '',
},
],
@@ -879,6 +926,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'dns-prefetch' },
output: '',
},
],
@@ -899,6 +947,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'icon' },
output: '',
},
],
@@ -925,12 +974,16 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'foo',
attributeName: 'rel',
+ reportingValue: 'foo',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: {
+ attributeName: 'rel',
+ reportingValue: 'foo',
+ },
output: '',
},
],
@@ -956,6 +1009,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -969,12 +1023,16 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'neverValid',
data: {
- reportingValue: 'foo',
attributeName: 'rel',
+ reportingValue: 'foo',
},
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: {
+ attributeName: 'rel',
+ reportingValue: 'foo',
+ },
output: '',
},
],
@@ -983,6 +1041,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
{
messageId: 'notAlone',
data: {
+ attributeName: 'rel',
reportingValue: 'shortcut',
missingValue: 'icon',
},
@@ -993,6 +1052,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveWhitespaces',
+ data: { attributeName: 'rel' },
output: '',
},
],
@@ -1013,6 +1073,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'manifest' },
output: '',
},
],
@@ -1033,6 +1094,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'modulepreload' },
output: '',
},
],
@@ -1053,6 +1115,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'pingback' },
output: '',
},
],
@@ -1073,6 +1136,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preconnect' },
output: '',
},
],
@@ -1093,6 +1157,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prefetch' },
output: '',
},
],
@@ -1113,6 +1178,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preload' },
output: '',
},
],
@@ -1133,6 +1199,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prerender' },
output: '',
},
],
@@ -1153,6 +1220,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'stylesheet' },
output: '',
},
],
@@ -1173,6 +1241,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'canonical' },
output: '',
},
],
@@ -1193,6 +1262,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'dns-prefetch' },
output: '',
},
],
@@ -1213,6 +1283,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'icon' },
output: '',
},
],
@@ -1233,6 +1304,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'manifest' },
output: '',
},
],
@@ -1253,6 +1325,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'modulepreload' },
output: '',
},
],
@@ -1273,6 +1346,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'pingback' },
output: '',
},
],
@@ -1293,6 +1367,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preconnect' },
output: '',
},
],
@@ -1313,6 +1388,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prefetch' },
output: '',
},
],
@@ -1333,6 +1409,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preload' },
output: '',
},
],
@@ -1353,6 +1430,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prerender' },
output: '',
},
],
@@ -1373,6 +1451,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'stylesheet' },
output: '',
},
],
@@ -1393,6 +1472,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'bookmark' },
output: '',
},
],
@@ -1413,6 +1493,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'external' },
output: '',
},
],
@@ -1433,6 +1514,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'nofollow' },
output: '',
},
],
@@ -1453,6 +1535,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'noopener' },
output: '',
},
],
@@ -1472,6 +1555,8 @@ ruleTester.run('no-invalid-html-attribute', rule, {
},
suggestions: [
{
+ messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'noreferrer' },
output: '',
},
],
@@ -1492,6 +1577,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'opener' },
output: '',
},
],
@@ -1512,6 +1598,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'tag' },
output: '',
},
],
@@ -1532,6 +1619,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'alternate' },
output: '',
},
],
@@ -1552,6 +1640,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'author' },
output: '',
},
],
@@ -1572,6 +1661,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'bookmark' },
output: '',
},
],
@@ -1592,6 +1682,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'canonical' },
output: '',
},
],
@@ -1612,6 +1703,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'dns-prefetch' },
output: '',
},
],
@@ -1632,6 +1724,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'icon' },
output: '',
},
],
@@ -1652,6 +1745,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'manifest' },
output: '',
},
],
@@ -1672,6 +1766,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'modulepreload' },
output: '',
},
],
@@ -1692,6 +1787,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'pingback' },
output: '',
},
],
@@ -1712,6 +1808,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preconnect' },
output: '',
},
],
@@ -1732,6 +1829,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prefetch' },
output: '',
},
],
@@ -1752,6 +1850,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'preload' },
output: '',
},
],
@@ -1772,6 +1871,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'prerender' },
output: '',
},
],
@@ -1792,6 +1892,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'stylesheet' },
output: '',
},
],
@@ -1812,6 +1913,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveInvalid',
+ data: { reportingValue: 'tag' },
output: '',
},
],
@@ -1832,6 +1934,7 @@ ruleTester.run('no-invalid-html-attribute', rule, {
suggestions: [
{
messageId: 'suggestRemoveEmpty',
+ data: { attributeName: 'rel' },
output: '',
},
],
diff --git a/tests/util/jsx.js b/tests/util/jsx.js
index c8009fc005..7be16d5410 100644
--- a/tests/util/jsx.js
+++ b/tests/util/jsx.js
@@ -21,6 +21,7 @@ const parseCode = (code) => {
};
const mockContext = {
+ getSourceCode() { return { getScope: mockContext.getScope }; },
getScope() {
return {
type: 'global',
@@ -34,7 +35,7 @@ const mockContext = {
describe('jsxUtil', () => {
describe('isReturningJSX', () => {
const assertValid = (codeStr) => assert(
- isReturningJSX(parseCode(codeStr), mockContext)
+ isReturningJSX(mockContext, parseCode(codeStr))
);
it('Works when returning JSX', () => {