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

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 3.4 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
47module.exports = function makeNoMethodSetStateRule(methodName, shouldCheckUnsafeCb) {
48 return {
49 meta: {
50 docs: {
51 description: `Disallow usage of setState in ${methodName}`,
52 category: 'Best Practices',
53 recommended: false,
54 url: docsUrl(mapTitle(methodName)),
55 },
56
57 messages,
58
59 schema: [{
60 enum: ['disallow-in-func'],
61 }],
62 },
63
64 create(context) {
65 const mode = context.options[0] || 'allow-in-func';
66
67 function nameMatches(name) {
68 if (name === methodName) {
69 return true;
70 }
71
72 if (typeof shouldCheckUnsafeCb === 'function' && shouldCheckUnsafeCb(context)) {
73 return name === `UNSAFE_${methodName}`;
74 }
75
76 return false;
77 }
78
79 if (shouldBeNoop(context, methodName)) {
80 return {};
81 }
82
83 // --------------------------------------------------------------------------
84 // Public
85 // --------------------------------------------------------------------------
86
87 return {
88 CallExpression(node) {
89 const callee = node.callee;
90 if (
91 callee.type !== 'MemberExpression'
92 || callee.object.type !== 'ThisExpression'
93 || callee.property.name !== 'setState'
94 ) {
95 return;
96 }
97 const ancestors = getAncestors(context, node);
98 let depth = 0;
99 findLast(ancestors, (ancestor) => {
100 // ancestors.some((ancestor) => {
101 if (/Function(Expression|Declaration)$/.test(ancestor.type)) {
102 depth += 1;
103 }
104 if (
105 (ancestor.type !== 'Property' && ancestor.type !== 'MethodDefinition' && ancestor.type !== 'ClassProperty' && ancestor.type !== 'PropertyDefinition')
106 || !nameMatches(ancestor.key.name)
107 || (mode !== 'disallow-in-func' && depth > 1)
108 ) {
109 return false;
110 }
111 report(context, messages.noSetState, 'noSetState', {
112 node: callee,
113 data: {
114 name: ancestor.key.name,
115 },
116 });
117 return true;
118 });
119 },
120 };
121 },
122 };
123};
Note: See TracBrowser for help on using the repository browser.