source: imaps-frontend/node_modules/eslint-plugin-react/lib/util/makeNoMethodSetStateRule.js@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 3.7 KB
Line 
1/**
2 * @fileoverview Prevent usage of setState in lifecycle methods
3 * @author Yannick Croissant
4 */
5
6'use strict';
7
8const findLast = require('array.prototype.findlast');
9
10const docsUrl = require('./docsUrl');
11const report = require('./report');
12const getAncestors = require('./eslint').getAncestors;
13const testReactVersion = require('./version').testReactVersion;
14
15// ------------------------------------------------------------------------------
16// Rule Definition
17// ------------------------------------------------------------------------------
18
19function mapTitle(methodName) {
20 const map = {
21 componentDidMount: 'did-mount',
22 componentDidUpdate: 'did-update',
23 componentWillUpdate: 'will-update',
24 };
25 const title = map[methodName];
26 if (!title) {
27 throw Error(`No docsUrl for '${methodName}'`);
28 }
29 return `no-${title}-set-state`;
30}
31
32const messages = {
33 noSetState: 'Do not use setState in {{name}}',
34};
35
36const methodNoopsAsOf = {
37 componentDidMount: '>= 16.3.0',
38 componentDidUpdate: '>= 16.3.0',
39};
40
41function shouldBeNoop(context, methodName) {
42 return methodName in methodNoopsAsOf
43 && testReactVersion(context, methodNoopsAsOf[methodName])
44 && !testReactVersion(context, '999.999.999'); // for when the version is not specified
45}
46
47// eslint-disable-next-line valid-jsdoc
48/**
49 * @param {string} methodName
50 * @param {(context: import('eslint').Rule.RuleContext) => boolean} [shouldCheckUnsafeCb]
51 * @returns {import('eslint').Rule.RuleModule}
52 */
53module.exports = function makeNoMethodSetStateRule(methodName, shouldCheckUnsafeCb) {
54 return {
55 meta: {
56 docs: {
57 description: `Disallow usage of setState in ${methodName}`,
58 category: 'Best Practices',
59 recommended: false,
60 url: docsUrl(mapTitle(methodName)),
61 },
62
63 messages,
64
65 schema: [{
66 enum: ['disallow-in-func'],
67 }],
68 },
69
70 create(context) {
71 const mode = context.options[0] || 'allow-in-func';
72
73 function nameMatches(name) {
74 if (name === methodName) {
75 return true;
76 }
77
78 if (typeof shouldCheckUnsafeCb === 'function' && shouldCheckUnsafeCb(context)) {
79 return name === `UNSAFE_${methodName}`;
80 }
81
82 return false;
83 }
84
85 if (shouldBeNoop(context, methodName)) {
86 return {};
87 }
88
89 // --------------------------------------------------------------------------
90 // Public
91 // --------------------------------------------------------------------------
92
93 return {
94 CallExpression(node) {
95 const callee = node.callee;
96 if (
97 callee.type !== 'MemberExpression'
98 || callee.object.type !== 'ThisExpression'
99 || !('name' in callee.property)
100 || callee.property.name !== 'setState'
101 ) {
102 return;
103 }
104 const ancestors = getAncestors(context, node);
105 let depth = 0;
106 findLast(ancestors, (ancestor) => {
107 // ancestors.some((ancestor) => {
108 if (/Function(Expression|Declaration)$/.test(ancestor.type)) {
109 depth += 1;
110 }
111 if (
112 (ancestor.type !== 'Property' && ancestor.type !== 'MethodDefinition' && ancestor.type !== 'ClassProperty' && ancestor.type !== 'PropertyDefinition')
113 || !nameMatches(ancestor.key.name)
114 || (mode !== 'disallow-in-func' && depth > 1)
115 ) {
116 return false;
117 }
118 report(context, messages.noSetState, 'noSetState', {
119 node: callee,
120 data: {
121 name: ancestor.key.name,
122 },
123 });
124 return true;
125 });
126 },
127 };
128 },
129 };
130};
Note: See TracBrowser for help on using the repository browser.