123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /**
- * @fileoverview Enforce event handler naming conventions in JSX
- * @author Jake Marsh
- */
- 'use strict';
- const docsUrl = require('../util/docsUrl');
- // ------------------------------------------------------------------------------
- // Rule Definition
- // ------------------------------------------------------------------------------
- module.exports = {
- meta: {
- docs: {
- description: 'Enforce event handler naming conventions in JSX',
- category: 'Stylistic Issues',
- recommended: false,
- url: docsUrl('jsx-handler-names')
- },
- messages: {
- badHandlerName: 'Handler function for {{propKey}} prop key must be a camelCase name beginning with \'{{handlerPrefix}}\' only',
- badPropKey: 'Prop key for {{propValue}} must begin with \'{{handlerPropPrefix}}\''
- },
- schema: [{
- anyOf: [
- {
- type: 'object',
- properties: {
- eventHandlerPrefix: {type: 'string'},
- eventHandlerPropPrefix: {type: 'string'},
- checkLocalVariables: {type: 'boolean'},
- checkInlineFunction: {type: 'boolean'}
- },
- additionalProperties: false
- }, {
- type: 'object',
- properties: {
- eventHandlerPrefix: {type: 'string'},
- eventHandlerPropPrefix: {
- type: 'boolean',
- enum: [false]
- },
- checkLocalVariables: {type: 'boolean'},
- checkInlineFunction: {type: 'boolean'}
- },
- additionalProperties: false
- }, {
- type: 'object',
- properties: {
- eventHandlerPrefix: {
- type: 'boolean',
- enum: [false]
- },
- eventHandlerPropPrefix: {type: 'string'},
- checkLocalVariables: {type: 'boolean'},
- checkInlineFunction: {type: 'boolean'}
- },
- additionalProperties: false
- }, {
- type: 'object',
- properties: {
- checkLocalVariables: {type: 'boolean'}
- },
- additionalProperties: false
- }, {
- type: 'object',
- properties: {
- checkInlineFunction: {type: 'boolean'}
- },
- additionalProperties: false
- }
- ]
- }]
- },
- create(context) {
- function isPrefixDisabled(prefix) {
- return prefix === false;
- }
- function isInlineHandler(node) {
- return node.value.expression.type === 'ArrowFunctionExpression';
- }
- const configuration = context.options[0] || {};
- const eventHandlerPrefix = isPrefixDisabled(configuration.eventHandlerPrefix)
- ? null
- : configuration.eventHandlerPrefix || 'handle';
- const eventHandlerPropPrefix = isPrefixDisabled(configuration.eventHandlerPropPrefix)
- ? null
- : configuration.eventHandlerPropPrefix || 'on';
- const EVENT_HANDLER_REGEX = !eventHandlerPrefix
- ? null
- : new RegExp(`^((props\\.${eventHandlerPropPrefix || ''})|((.*\\.)?${eventHandlerPrefix}))[0-9]*[A-Z].*$`);
- const PROP_EVENT_HANDLER_REGEX = !eventHandlerPropPrefix
- ? null
- : new RegExp(`^(${eventHandlerPropPrefix}[A-Z].*|ref)$`);
- const checkLocal = !!configuration.checkLocalVariables;
- const checkInlineFunction = !!configuration.checkInlineFunction;
- return {
- JSXAttribute(node) {
- if (
- !node.value
- || !node.value.expression
- || (!checkInlineFunction && isInlineHandler(node))
- || (
- !checkLocal
- && (isInlineHandler(node)
- ? !node.value.expression.body.callee || !node.value.expression.body.callee.object
- : !node.value.expression.object
- )
- )
- ) {
- return;
- }
- const propKey = typeof node.name === 'object' ? node.name.name : node.name;
- const expression = node.value.expression;
- const propValue = context.getSourceCode()
- .getText(checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression)
- .replace(/\s*/g, '')
- .replace(/^this\.|.*::/, '');
- if (propKey === 'ref') {
- return;
- }
- const propIsEventHandler = PROP_EVENT_HANDLER_REGEX && PROP_EVENT_HANDLER_REGEX.test(propKey);
- const propFnIsNamedCorrectly = EVENT_HANDLER_REGEX && EVENT_HANDLER_REGEX.test(propValue);
- if (
- propIsEventHandler
- && propFnIsNamedCorrectly !== null
- && !propFnIsNamedCorrectly
- ) {
- context.report({
- node,
- messageId: 'badHandlerName',
- data: {
- propKey,
- handlerPrefix: eventHandlerPrefix
- }
- });
- } else if (
- propFnIsNamedCorrectly
- && propIsEventHandler !== null
- && !propIsEventHandler
- ) {
- context.report({
- node,
- messageId: 'badPropKey',
- data: {
- propValue,
- handlerPropPrefix: eventHandlerPropPrefix
- }
- });
- }
- }
- };
- }
- };
|