source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/jsx-handler-names.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: 6.3 KB
RevLine 
[d565449]1/**
2 * @fileoverview Enforce event handler naming conventions in JSX
3 * @author Jake Marsh
4 */
5
6'use strict';
7
8const minimatch = require('minimatch');
9const docsUrl = require('../util/docsUrl');
10const getText = require('../util/eslint').getText;
11const report = require('../util/report');
12
13// ------------------------------------------------------------------------------
14// Rule Definition
15// ------------------------------------------------------------------------------
16
17const messages = {
18 badHandlerName: 'Handler function for {{propKey}} prop key must be a camelCase name beginning with \'{{handlerPrefix}}\' only',
19 badPropKey: 'Prop key for {{propValue}} must begin with \'{{handlerPropPrefix}}\'',
20};
21
22/** @type {import('eslint').Rule.RuleModule} */
23module.exports = {
24 meta: {
25 docs: {
26 description: 'Enforce event handler naming conventions in JSX',
27 category: 'Stylistic Issues',
28 recommended: false,
29 url: docsUrl('jsx-handler-names'),
30 },
31
32 messages,
33
34 schema: [{
35 anyOf: [
36 {
37 type: 'object',
38 properties: {
39 eventHandlerPrefix: { type: 'string' },
40 eventHandlerPropPrefix: { type: 'string' },
41 checkLocalVariables: { type: 'boolean' },
42 checkInlineFunction: { type: 'boolean' },
43 ignoreComponentNames: {
44 type: 'array',
45 uniqueItems: true,
46 items: { type: 'string' },
47 },
48 },
49 additionalProperties: false,
50 }, {
51 type: 'object',
52 properties: {
53 eventHandlerPrefix: { type: 'string' },
54 eventHandlerPropPrefix: {
55 type: 'boolean',
56 enum: [false],
57 },
58 checkLocalVariables: { type: 'boolean' },
59 checkInlineFunction: { type: 'boolean' },
60 ignoreComponentNames: {
61 type: 'array',
62 uniqueItems: true,
63 items: { type: 'string' },
64 },
65 },
66 additionalProperties: false,
67 }, {
68 type: 'object',
69 properties: {
70 eventHandlerPrefix: {
71 type: 'boolean',
72 enum: [false],
73 },
74 eventHandlerPropPrefix: { type: 'string' },
75 checkLocalVariables: { type: 'boolean' },
76 checkInlineFunction: { type: 'boolean' },
77 ignoreComponentNames: {
78 type: 'array',
79 uniqueItems: true,
80 items: { type: 'string' },
81 },
82 },
83 additionalProperties: false,
84 }, {
85 type: 'object',
86 properties: {
87 checkLocalVariables: { type: 'boolean' },
88 },
89 additionalProperties: false,
90 }, {
91 type: 'object',
92 properties: {
93 checkInlineFunction: { type: 'boolean' },
94 },
95 additionalProperties: false,
96 },
97 {
98 type: 'object',
99 properties: {
100 ignoreComponentNames: {
101 type: 'array',
102 uniqueItems: true,
103 items: { type: 'string' },
104 },
105 },
106 },
107 ],
108 }],
109 },
110
111 create(context) {
112 function isPrefixDisabled(prefix) {
113 return prefix === false;
114 }
115
116 function isInlineHandler(node) {
117 return node.value.expression.type === 'ArrowFunctionExpression';
118 }
119
120 const configuration = context.options[0] || {};
121
122 const eventHandlerPrefix = isPrefixDisabled(configuration.eventHandlerPrefix)
123 ? null
124 : configuration.eventHandlerPrefix || 'handle';
125 const eventHandlerPropPrefix = isPrefixDisabled(configuration.eventHandlerPropPrefix)
126 ? null
127 : configuration.eventHandlerPropPrefix || 'on';
128
129 const EVENT_HANDLER_REGEX = !eventHandlerPrefix
130 ? null
131 : new RegExp(`^((props\\.${eventHandlerPropPrefix || ''})|((.*\\.)?${eventHandlerPrefix}))[0-9]*[A-Z].*$`);
132 const PROP_EVENT_HANDLER_REGEX = !eventHandlerPropPrefix
133 ? null
134 : new RegExp(`^(${eventHandlerPropPrefix}[A-Z].*|ref)$`);
135
136 const checkLocal = !!configuration.checkLocalVariables;
137
138 const checkInlineFunction = !!configuration.checkInlineFunction;
139
140 const ignoreComponentNames = configuration.ignoreComponentNames || [];
141
142 return {
143 JSXAttribute(node) {
144 const componentName = node.parent.name.name;
145
146 const isComponentNameIgnored = ignoreComponentNames.some((ignoredComponentNamePattern) => {
147 const isIgnored = minimatch(componentName, ignoredComponentNamePattern);
148 return isIgnored;
149 });
150
151 if (
152 !node.value
153 || !node.value.expression
154 || (!checkInlineFunction && isInlineHandler(node))
155 || (
156 !checkLocal
157 && (isInlineHandler(node)
158 ? !node.value.expression.body.callee || !node.value.expression.body.callee.object
159 : !node.value.expression.object
160 )
161 )
162 || isComponentNameIgnored
163 ) {
164 return;
165 }
166
167 const propKey = typeof node.name === 'object' ? node.name.name : node.name;
168 const expression = node.value.expression;
169 const propValue = getText(
170 context,
171 checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression
172 ).replace(/\s*/g, '').replace(/^this\.|.*::/, '');
173
174 if (propKey === 'ref') {
175 return;
176 }
177
178 const propIsEventHandler = PROP_EVENT_HANDLER_REGEX && PROP_EVENT_HANDLER_REGEX.test(propKey);
179 const propFnIsNamedCorrectly = EVENT_HANDLER_REGEX && EVENT_HANDLER_REGEX.test(propValue);
180
181 if (
182 propIsEventHandler
183 && propFnIsNamedCorrectly !== null
184 && !propFnIsNamedCorrectly
185 ) {
186 report(context, messages.badHandlerName, 'badHandlerName', {
187 node,
188 data: {
189 propKey,
190 handlerPrefix: eventHandlerPrefix,
191 },
192 });
193 } else if (
194 propFnIsNamedCorrectly
195 && propIsEventHandler !== null
196 && !propIsEventHandler
197 ) {
198 report(context, messages.badPropKey, 'badPropKey', {
199 node,
200 data: {
201 propValue,
202 handlerPropPrefix: eventHandlerPropPrefix,
203 },
204 });
205 }
206 },
207 };
208 },
209};
Note: See TracBrowser for help on using the repository browser.