GoScrobble/web/node_modules/eslint-plugin-react/lib/util/makeNoMethodSetStateRule.js

105 lines
2.7 KiB
JavaScript
Raw Permalink Normal View History

2022-04-25 02:47:15 +00:00
/**
* @fileoverview Prevent usage of setState in lifecycle methods
* @author Yannick Croissant
*/
'use strict';
const docsUrl = require('./docsUrl');
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
function mapTitle(methodName) {
const map = {
componentDidMount: 'did-mount',
componentDidUpdate: 'did-update',
componentWillUpdate: 'will-update'
};
const title = map[methodName];
if (!title) {
throw Error(`No docsUrl for '${methodName}'`);
}
return `no-${title}-set-state`;
}
function makeNoMethodSetStateRule(methodName, shouldCheckUnsafeCb) {
return {
meta: {
docs: {
description: `Prevent usage of setState in ${methodName}`,
category: 'Best Practices',
recommended: false,
url: docsUrl(mapTitle(methodName))
},
messages: {
noSetState: 'Do not use setState in {{name}}'
},
schema: [{
enum: ['disallow-in-func']
}]
},
create(context) {
const mode = context.options[0] || 'allow-in-func';
function nameMatches(name) {
if (name === methodName) {
return true;
}
if (typeof shouldCheckUnsafeCb === 'function' && shouldCheckUnsafeCb(context)) {
return name === `UNSAFE_${methodName}`;
}
return false;
}
// --------------------------------------------------------------------------
// Public
// --------------------------------------------------------------------------
return {
CallExpression(node) {
const callee = node.callee;
if (
callee.type !== 'MemberExpression'
|| callee.object.type !== 'ThisExpression'
|| callee.property.name !== 'setState'
) {
return;
}
const ancestors = context.getAncestors(callee).reverse();
let depth = 0;
ancestors.some((ancestor) => {
if (/Function(Expression|Declaration)$/.test(ancestor.type)) {
depth++;
}
if (
(ancestor.type !== 'Property' && ancestor.type !== 'MethodDefinition' && ancestor.type !== 'ClassProperty')
|| !nameMatches(ancestor.key.name)
|| (mode !== 'disallow-in-func' && depth > 1)
) {
return false;
}
context.report({
node: callee,
messageId: 'noSetState',
data: {
name: ancestor.key.name
}
});
return true;
});
}
};
}
};
}
module.exports = makeNoMethodSetStateRule;