source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/no-direct-mutation-state.js@ d565449

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

Update repo after prototype presentation

  • Property mode set to 100644
File size: 4.5 KB
Line 
1/**
2 * @fileoverview Prevent direct mutation of this.state
3 * @author David Petersen
4 * @author Nicolas Fernandez <@burabure>
5 */
6
7'use strict';
8
9const values = require('object.values');
10
11const Components = require('../util/Components');
12const componentUtil = require('../util/componentUtil');
13const docsUrl = require('../util/docsUrl');
14const report = require('../util/report');
15
16// ------------------------------------------------------------------------------
17// Rule Definition
18// ------------------------------------------------------------------------------
19
20const messages = {
21 noDirectMutation: 'Do not mutate state directly. Use setState().',
22};
23
24/** @type {import('eslint').Rule.RuleModule} */
25module.exports = {
26 meta: {
27 docs: {
28 description: 'Disallow direct mutation of this.state',
29 category: 'Possible Errors',
30 recommended: true,
31 url: docsUrl('no-direct-mutation-state'),
32 },
33
34 messages,
35 },
36
37 create: Components.detect((context, components, utils) => {
38 /**
39 * Checks if the component is valid
40 * @param {Object} component The component to process
41 * @returns {Boolean} True if the component is valid, false if not.
42 */
43 function isValid(component) {
44 return Boolean(component && !component.mutateSetState);
45 }
46
47 /**
48 * Reports undeclared proptypes for a given component
49 * @param {Object} component The component to process
50 */
51 function reportMutations(component) {
52 let mutation;
53 for (let i = 0, j = component.mutations.length; i < j; i++) {
54 mutation = component.mutations[i];
55 report(context, messages.noDirectMutation, 'noDirectMutation', {
56 node: mutation,
57 });
58 }
59 }
60
61 /**
62 * Walks through the MemberExpression to the top-most property.
63 * @param {Object} node The node to process
64 * @returns {Object} The outer-most MemberExpression
65 */
66 function getOuterMemberExpression(node) {
67 while (node.object && node.object.property) {
68 node = node.object;
69 }
70 return node;
71 }
72
73 /**
74 * Determine if we should currently ignore assignments in this component.
75 * @param {?Object} component The component to process
76 * @returns {Boolean} True if we should skip assignment checks.
77 */
78 function shouldIgnoreComponent(component) {
79 return !component || (component.inConstructor && !component.inCallExpression);
80 }
81
82 // --------------------------------------------------------------------------
83 // Public
84 // --------------------------------------------------------------------------
85 return {
86 MethodDefinition(node) {
87 if (node.kind === 'constructor') {
88 components.set(node, {
89 inConstructor: true,
90 });
91 }
92 },
93
94 CallExpression(node) {
95 components.set(node, {
96 inCallExpression: true,
97 });
98 },
99
100 AssignmentExpression(node) {
101 const component = components.get(utils.getParentComponent(node));
102 if (shouldIgnoreComponent(component) || !node.left || !node.left.object) {
103 return;
104 }
105 const item = getOuterMemberExpression(node.left);
106 if (componentUtil.isStateMemberExpression(item)) {
107 const mutations = (component && component.mutations) || [];
108 mutations.push(node.left.object);
109 components.set(node, {
110 mutateSetState: true,
111 mutations,
112 });
113 }
114 },
115
116 UpdateExpression(node) {
117 const component = components.get(utils.getParentComponent(node));
118 if (shouldIgnoreComponent(component) || node.argument.type !== 'MemberExpression') {
119 return;
120 }
121 const item = getOuterMemberExpression(node.argument);
122 if (componentUtil.isStateMemberExpression(item)) {
123 const mutations = (component && component.mutations) || [];
124 mutations.push(item);
125 components.set(node, {
126 mutateSetState: true,
127 mutations,
128 });
129 }
130 },
131
132 'CallExpression:exit'(node) {
133 components.set(node, {
134 inCallExpression: false,
135 });
136 },
137
138 'MethodDefinition:exit'(node) {
139 if (node.kind === 'constructor') {
140 components.set(node, {
141 inConstructor: false,
142 });
143 }
144 },
145
146 'Program:exit'() {
147 values(components.list())
148 .filter((component) => !isValid(component))
149 .forEach((component) => {
150 reportMutations(component);
151 });
152 },
153 };
154 }),
155};
Note: See TracBrowser for help on using the repository browser.