source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/no-arrow-function-lifecycle.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: 5.0 KB
Line 
1/**
2 * @fileoverview Lifecycle methods should be methods on the prototype, not class fields
3 * @author Tan Nguyen
4 */
5
6'use strict';
7
8const values = require('object.values');
9
10const Components = require('../util/Components');
11const astUtil = require('../util/ast');
12const componentUtil = require('../util/componentUtil');
13const docsUrl = require('../util/docsUrl');
14const lifecycleMethods = require('../util/lifecycleMethods');
15const report = require('../util/report');
16const eslintUtil = require('../util/eslint');
17
18const getSourceCode = eslintUtil.getSourceCode;
19const getText = eslintUtil.getText;
20
21function getRuleText(node) {
22 const params = node.value.params.map((p) => p.name);
23
24 if (node.type === 'Property') {
25 return `: function(${params.join(', ')}) `;
26 }
27
28 if (node.type === 'ClassProperty' || node.type === 'PropertyDefinition') {
29 return `(${params.join(', ')}) `;
30 }
31
32 return null;
33}
34
35const messages = {
36 lifecycle: '{{propertyName}} is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.',
37};
38
39/** @type {import('eslint').Rule.RuleModule} */
40module.exports = {
41 meta: {
42 docs: {
43 description: 'Lifecycle methods should be methods on the prototype, not class fields',
44 category: 'Best Practices',
45 recommended: false,
46 url: docsUrl('no-arrow-function-lifecycle'),
47 },
48 messages,
49 schema: [],
50 fixable: 'code',
51 },
52
53 create: Components.detect((context, components) => {
54 /**
55 * @param {Array} properties list of component properties
56 */
57 function reportNoArrowFunctionLifecycle(properties) {
58 properties.forEach((node) => {
59 if (!node || !node.value) {
60 return;
61 }
62
63 const propertyName = astUtil.getPropertyName(node);
64 const nodeType = node.value.type;
65 const isLifecycleMethod = (
66 node.static && !componentUtil.isES5Component(node, context)
67 ? lifecycleMethods.static
68 : lifecycleMethods.instance
69 ).indexOf(propertyName) > -1;
70
71 if (nodeType === 'ArrowFunctionExpression' && isLifecycleMethod) {
72 const body = node.value.body;
73 const isBlockBody = body.type === 'BlockStatement';
74 const sourceCode = getSourceCode(context);
75
76 let nextComment = [];
77 let previousComment = [];
78 let bodyRange;
79 if (!isBlockBody) {
80 const previousToken = sourceCode.getTokenBefore(body);
81
82 if (sourceCode.getCommentsBefore) {
83 // eslint >=4.x
84 previousComment = sourceCode.getCommentsBefore(body);
85 } else {
86 // eslint 3.x
87 const potentialComment = sourceCode.getTokenBefore(body, { includeComments: true });
88 previousComment = previousToken === potentialComment ? [] : [potentialComment];
89 }
90
91 if (sourceCode.getCommentsAfter) {
92 // eslint >=4.x
93 nextComment = sourceCode.getCommentsAfter(body);
94 } else {
95 // eslint 3.x
96 const potentialComment = sourceCode.getTokenAfter(body, { includeComments: true });
97 const nextToken = sourceCode.getTokenAfter(body);
98 nextComment = nextToken === potentialComment ? [] : [potentialComment];
99 }
100 bodyRange = [
101 (previousComment.length > 0 ? previousComment[0] : body).range[0],
102 (nextComment.length > 0 ? nextComment[nextComment.length - 1] : body).range[1]
103 + (node.value.body.type === 'ObjectExpression' ? 1 : 0), // to account for a wrapped end paren
104 ];
105 }
106 const headRange = [
107 node.key.range[1],
108 (previousComment.length > 0 ? previousComment[0] : body).range[0],
109 ];
110 const hasSemi = node.value.expression && getText(context, node).slice(node.value.range[1] - node.range[0]) === ';';
111
112 report(
113 context,
114 messages.lifecycle,
115 'lifecycle',
116 {
117 node,
118 data: {
119 propertyName,
120 },
121 fix(fixer) {
122 if (!sourceCode.getCommentsAfter) {
123 // eslint 3.x
124 return isBlockBody && fixer.replaceTextRange(headRange, getRuleText(node));
125 }
126 return [].concat(
127 fixer.replaceTextRange(headRange, getRuleText(node)),
128 isBlockBody ? [] : fixer.replaceTextRange(
129 [bodyRange[0], bodyRange[1] + (hasSemi ? 1 : 0)],
130 `{ return ${previousComment.map((x) => getText(context, x)).join('')}${getText(context, body)}${nextComment.map((x) => getText(context, x)).join('')}; }`
131 )
132 );
133 },
134 }
135 );
136 }
137 });
138 }
139
140 return {
141 'Program:exit'() {
142 values(components.list()).forEach((component) => {
143 const properties = astUtil.getComponentProperties(component.node);
144 reportNoArrowFunctionLifecycle(properties);
145 });
146 },
147 };
148 }),
149};
Note: See TracBrowser for help on using the repository browser.