Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: provide compatibility with eslint v9 #3727

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/node-18+.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
matrix:
node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
eslint:
- 9
- 8
- 7
- 6
Expand All @@ -48,6 +49,7 @@ jobs:
npm install --no-save "eslint@${{ matrix.eslint }}" "@typescript-eslint/parser@5" "babel-eslint@${{ matrix.babel-eslint }}"
env:
NPM_CONFIG_LEGACY_PEER_DEPS: true
ESLINT_USE_FLAT_CONFIG: false
- run: npx ls-engines
- run: npm run unit-test
- uses: codecov/codecov-action@v3.1.5
Expand Down
12 changes: 7 additions & 5 deletions lib/rules/destructuring-assignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

'use strict';

const astUtil = require('../util/ast');
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const isAssignmentLHS = require('../util/ast').isAssignmentLHS;
Expand Down Expand Up @@ -101,7 +102,7 @@ module.exports = {
function handleStatelessComponent(node) {
const params = evalParams(node.params);

const SFCComponent = components.get(context.getScope(node).block);
const SFCComponent = components.get(astUtil.getScope(context, node).block);
if (!SFCComponent) {
return;
}
Expand All @@ -119,7 +120,7 @@ module.exports = {
}

function handleStatelessComponentExit(node) {
const SFCComponent = components.get(context.getScope(node).block);
const SFCComponent = components.get(astUtil.getScope(context, node).block);
if (SFCComponent) {
sfcParams.pop();
}
Expand Down Expand Up @@ -191,7 +192,7 @@ module.exports = {
'FunctionExpression:exit': handleStatelessComponentExit,

MemberExpression(node) {
let scope = context.getScope(node);
let scope = astUtil.getScope(context, node);
let SFCComponent = components.get(scope.block);
while (!SFCComponent && scope.upper && scope.upper !== scope) {
SFCComponent = components.get(scope.upper.block);
Expand All @@ -209,7 +210,7 @@ module.exports = {

VariableDeclarator(node) {
const classComponent = utils.getParentComponent(node);
const SFCComponent = components.get(context.getScope(node).block);
const SFCComponent = components.get(astUtil.getScope(context, node).block);

const destructuring = (node.init && node.id && node.id.type === 'ObjectPattern');
// let {foo} = props;
Expand Down Expand Up @@ -247,7 +248,8 @@ module.exports = {
&& destructureInSignature === 'always'
&& node.init.name === 'props'
) {
const scopeSetProps = context.getScope().set.get('props');
const scope = astUtil.getScope(context, node);
ljharb marked this conversation as resolved.
Show resolved Hide resolved
const scopeSetProps = scope.set.get('props');
const propsRefs = scopeSetProps && scopeSetProps.references;
if (!propsRefs) {
return;
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/forbid-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ module.exports = {
checkProperties(node.properties);
break;
case 'Identifier': {
const propTypesObject = variableUtil.findVariableByName(context, node.name);
const propTypesObject = variableUtil.findVariableByName(context, node);
ljharb marked this conversation as resolved.
Show resolved Hide resolved
if (propTypesObject && propTypesObject.properties) {
checkProperties(propTypesObject.properties);
}
Expand Down
6 changes: 3 additions & 3 deletions lib/rules/jsx-fragments.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,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;
}
Expand Down Expand Up @@ -185,7 +185,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;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/jsx-max-depth.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ module.exports = {
return;
}

const variables = variableUtil.variablesInScope(context);
const variables = variableUtil.variablesInScope(context, node);
const element = findJSXElementOrFragment(variables, node.expression.name, []);

if (element) {
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/jsx-no-bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'use strict';

const propName = require('jsx-ast-utils/propName');
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
Expand Down Expand Up @@ -123,7 +124,7 @@ module.exports = {
}

function getBlockStatementAncestors(node) {
return context.getAncestors(node).filter(
return astUtil.getAncestors(context, node).filter(
(ancestor) => ancestor.type === 'BlockStatement'
).reverse();
}
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/jsx-no-constructed-context-values.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

'use strict';

const astUtil = require('../util/ast');
const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');
Expand Down Expand Up @@ -179,7 +180,7 @@ module.exports = {
}

const valueExpression = valueNode.expression;
const invocationScope = context.getScope();
const invocationScope = astUtil.getScope(context, node);
ljharb marked this conversation as resolved.
Show resolved Hide resolved

// Check if the value prop is a construction
const constructInfo = isConstruction(valueExpression, invocationScope);
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/jsx-no-undef.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

'use strict';

const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
Expand Down Expand Up @@ -49,7 +50,7 @@ module.exports = {
* @returns {void}
*/
function checkIdentifierInJSX(node) {
let scope = context.getScope();
let scope = astUtil.getScope(context, node);
ljharb marked this conversation as resolved.
Show resolved Hide resolved
const sourceCode = context.getSourceCode();
const sourceType = sourceCode.ast.sourceType;
const scopeUpperBound = !allowGlobals && sourceType === 'module' ? 'module' : 'global';
Expand Down
9 changes: 5 additions & 4 deletions lib/rules/jsx-sort-default-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ module.exports = {

/**
* Find a variable by name in the current scope.
* @param {string} name Name of the variable to look for.
* @param {ASTNode} node The node to check.
* @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) {
const name = node.name;
const variable = variableUtil.variablesInScope(context, node).find((item) => item.name === name);
Comment on lines +94 to +95
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like variableUtil.variablesInScope(context, node, node.name) should do this logic for us. am i misreading?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

variableUtil.variablesInScope(context, node) returns a set of vars visible from the specified node, and then we pick the one by name, as I understand.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right - but providing the third argument to variablesInScope picks it by name already, doesn't it?


if (!variable || !variable.defs[0] || !variable.defs[0].node) {
return null;
Expand Down Expand Up @@ -147,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);
if (propTypesObject && propTypesObject.properties) {
checkSorted(propTypesObject.properties);
}
Expand Down
17 changes: 10 additions & 7 deletions lib/rules/no-access-state-in-setstate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

'use strict';

const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const componentUtil = require('../util/componentUtil');
const report = require('../util/report');
Expand Down Expand Up @@ -47,8 +48,9 @@ module.exports = {
return current.arguments[0] === node;
}

function isClassComponent() {
return !!(componentUtil.getParentES6Component(context) || componentUtil.getParentES5Component(context));
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
Expand All @@ -58,7 +60,7 @@ module.exports = {
const vars = [];
return {
CallExpression(node) {
if (!isClassComponent()) {
if (!isClassComponent(node)) {
return;
}
// Appends all the methods that are calling another
Expand Down Expand Up @@ -103,7 +105,7 @@ module.exports = {
if (
node.property.name === 'state'
&& node.object.type === 'ThisExpression'
&& isClassComponent()
&& isClassComponent(node)
) {
let current = node;
while (current.type !== 'Program') {
Expand Down Expand Up @@ -134,7 +136,7 @@ module.exports = {
if (current.type === 'VariableDeclarator') {
vars.push({
node,
scope: context.getScope(),
scope: astUtil.getScope(context, node),
ljharb marked this conversation as resolved.
Show resolved Hide resolved
variableName: current.id.name,
});
break;
Expand All @@ -155,10 +157,11 @@ module.exports = {
current.parent.value === current
|| current.parent.object === current
) {
const scope = astUtil.getScope(context, node);
while (current.type !== 'Program') {
if (isFirstArgumentInSetStateCall(current, node)) {
vars
.filter((v) => v.scope === context.getScope() && v.variableName === node.name)
.filter((v) => v.scope === scope && v.variableName === node.name)
ljharb marked this conversation as resolved.
Show resolved Hide resolved
.forEach((v) => {
report(context, messages.useCallback, 'useCallback', {
node: v.node,
Expand All @@ -176,7 +179,7 @@ module.exports = {
if (property && property.key && property.key.name === 'state' && isDerivedFromThis) {
vars.push({
node: property.key,
scope: context.getScope(),
scope: astUtil.getScope(context, node),
ljharb marked this conversation as resolved.
Show resolved Hide resolved
variableName: property.key.name,
});
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-array-index-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
if (variable && variable.type === 'ImportSpecifier') {
return variable.parent.source.value === 'react';
}
Expand Down
10 changes: 5 additions & 5 deletions lib/rules/no-danger-with-children.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ module.exports = {
schema: [], // no options
},
create(context) {
function findSpreadVariable(name) {
return variableUtil.variablesInScope(context).find((item) => item.name === name);
function findSpreadVariable(name, node) {
return variableUtil.variablesInScope(context, node).find((item) => item.name === name);
}
/**
* Takes a ObjectExpression and returns the value of the prop if it has it
Expand All @@ -50,7 +50,7 @@ module.exports = {
return prop.key.name === propName;
}
if (prop.type === 'ExperimentalSpreadProperty' || prop.type === 'SpreadElement') {
const variable = findSpreadVariable(prop.argument.name);
const variable = findSpreadVariable(prop.argument.name, node);
if (variable && variable.defs.length && variable.defs[0].node.init) {
if (seenProps.indexOf(prop.argument.name) > -1) {
return false;
Expand All @@ -73,7 +73,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(attribute.argument.name, node);
if (variable && variable.defs.length && variable.defs[0].node.init) {
return findObjectProp(variable.defs[0].node.init, propName, []);
}
Expand Down Expand Up @@ -127,7 +127,7 @@ 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;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/no-direct-mutation-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,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;
}
Expand All @@ -113,7 +113,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;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/rules/no-is-mounted.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

'use strict';

const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
const report = require('../util/report');

Expand Down Expand Up @@ -40,7 +41,7 @@ module.exports = {
if (callee.object.type !== 'ThisExpression' || callee.property.name !== 'isMounted') {
return;
}
const ancestors = context.getAncestors(callee);
const ancestors = astUtil.getAncestors(context, callee);
for (let i = 0, j = ancestors.length; i < j; i++) {
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') {
report(context, messages.noIsMounted, 'noIsMounted', {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-set-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,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, {
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-string-refs.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,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'
);
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-this-in-sfc.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/rules/no-unstable-nested-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,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;
Expand Down Expand Up @@ -333,8 +333,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
Expand Down