diff --git a/CHANGELOG.md b/CHANGELOG.md index e856eeecae..1866e352d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,13 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel ### Added * [`button-has-type`]: support trivial ternary expressions ([#2748][] @Hypnosphi) +* [`jsx-handler-names`]: add `checkInlineFunction` option ([#2761][] @dididy) ### Fixed * [`function-component-definition`]: ignore object properties ([#2771][] @stefan-wullems) [#2771]: https://github.com/yannickcr/eslint-plugin-react/pull/2771 +[#2761]: https://github.com/yannickcr/eslint-plugin-react/pull/2761 [#2748]: https://github.com/yannickcr/eslint-plugin-react/pull/2748 ## [7.20.6] - 2020.08.12 diff --git a/docs/rules/jsx-handler-names.md b/docs/rules/jsx-handler-names.md index 42d285ae99..ff54d3efab 100644 --- a/docs/rules/jsx-handler-names.md +++ b/docs/rules/jsx-handler-names.md @@ -31,7 +31,8 @@ The following patterns are **not** considered warnings: "react/jsx-handler-names": [, { "eventHandlerPrefix": , "eventHandlerPropPrefix": , - "checkLocalVariables": + "checkLocalVariables": , + "checkInlineFunction": }] ... ``` @@ -39,6 +40,7 @@ The following patterns are **not** considered warnings: * `eventHandlerPrefix`: Prefix for component methods used as event handlers. Defaults to `handle` * `eventHandlerPropPrefix`: Prefix for props that are used as event handlers. Defaults to `on` * `checkLocalVariables`: Determines whether event handlers stored as local variables are checked. Defaults to `false` +* `checkInlineFunction`: Determines whether event handlers set as inline functions are checked. Defaults to `false` ## When Not To Use It diff --git a/lib/rules/jsx-handler-names.js b/lib/rules/jsx-handler-names.js index fa1afdb68e..52879ef9c4 100644 --- a/lib/rules/jsx-handler-names.js +++ b/lib/rules/jsx-handler-names.js @@ -27,7 +27,8 @@ module.exports = { properties: { eventHandlerPrefix: {type: 'string'}, eventHandlerPropPrefix: {type: 'string'}, - checkLocalVariables: {type: 'boolean'} + checkLocalVariables: {type: 'boolean'}, + checkInlineFunction: {type: 'boolean'} }, additionalProperties: false }, { @@ -38,7 +39,8 @@ module.exports = { type: 'boolean', enum: [false] }, - checkLocalVariables: {type: 'boolean'} + checkLocalVariables: {type: 'boolean'}, + checkInlineFunction: {type: 'boolean'} }, additionalProperties: false }, { @@ -49,7 +51,8 @@ module.exports = { enum: [false] }, eventHandlerPropPrefix: {type: 'string'}, - checkLocalVariables: {type: 'boolean'} + checkLocalVariables: {type: 'boolean'}, + checkInlineFunction: {type: 'boolean'} }, additionalProperties: false }, { @@ -58,6 +61,12 @@ module.exports = { checkLocalVariables: {type: 'boolean'} }, additionalProperties: false + }, { + type: 'object', + properties: { + checkInlineFunction: {type: 'boolean'} + }, + additionalProperties: false } ] }] @@ -68,6 +77,10 @@ module.exports = { return prefix === false; } + function isInlineHandler(node) { + return node.value.expression.type === 'ArrowFunctionExpression'; + } + const configuration = context.options[0] || {}; const eventHandlerPrefix = isPrefixDisabled(configuration.eventHandlerPrefix) @@ -86,14 +99,29 @@ module.exports = { const checkLocal = !!configuration.checkLocalVariables; + const checkInlineFunction = !!configuration.checkInlineFunction; + return { JSXAttribute(node) { - if (!node.value || !node.value.expression || (!checkLocal && !node.value.expression.object)) { + if ( + !node.value + || !node.value.expression + || ( + !checkLocal + && (isInlineHandler(node) + ? !node.value.expression.body.callee.object + : !node.value.expression.object + ) + ) + ) { return; } const propKey = typeof node.name === 'object' ? node.name.name : node.name; - const propValue = context.getSourceCode().getText(node.value.expression).replace(/^this\.|.*::/, ''); + const expression = node.value.expression; + const propValue = context.getSourceCode() + .getText(checkInlineFunction && isInlineHandler(node) ? expression.body.callee : expression) + .replace(/^this\.|.*::/, ''); if (propKey === 'ref') { return; diff --git a/tests/lib/rules/jsx-handler-names.js b/tests/lib/rules/jsx-handler-names.js index d3f54ac704..a167e9a11e 100644 --- a/tests/lib/rules/jsx-handler-names.js +++ b/tests/lib/rules/jsx-handler-names.js @@ -42,6 +42,17 @@ ruleTester.run('jsx-handler-names', rule, { options: [{ checkLocalVariables: false }] + }, { + code: ' handleChange()} />', + options: [{ + checkInlineFunction: true, + checkLocalVariables: true + }] + }, { + code: ' this.handleChange()} />', + options: [{ + checkInlineFunction: true + }] }, { code: '' }, { @@ -71,6 +82,24 @@ ruleTester.run('jsx-handler-names', rule, { }, { code: '', parser: parsers.BABEL_ESLINT + }, { + code: ' props::handleChange()} />', + parser: parsers.BABEL_ESLINT, + options: [{ + checkInlineFunction: true + }] + }, { + code: ' ::props.onChange()} />', + parser: parsers.BABEL_ESLINT, + options: [{ + checkInlineFunction: true + }] + }, { + code: ' props.foo::handleChange()} />', + parser: parsers.BABEL_ESLINT, + options: [{ + checkInlineFunction: true + }] }, { code: '' }, { @@ -115,6 +144,12 @@ ruleTester.run('jsx-handler-names', rule, { options: [{ checkLocalVariables: true }] + }, { + code: ' this.takeCareOfChange()} />', + errors: [{message: 'Handler function for onChange prop key must begin with \'handle\''}], + options: [{ + checkInlineFunction: true + }] }, { code: '', errors: [{message: 'Prop key for handleChange must begin with \'on\''}] @@ -127,6 +162,13 @@ ruleTester.run('jsx-handler-names', rule, { options: [{ checkLocalVariables: true }] + }, { + code: ' handleChange()} />', + errors: [{message: 'Prop key for handleChange must begin with \'on\''}], + options: [{ + checkInlineFunction: true, + checkLocalVariables: true + }] }, { code: '', errors: [{message: 'Prop key for handleChange must begin with \'when\''}], @@ -135,6 +177,15 @@ ruleTester.run('jsx-handler-names', rule, { eventHandlerPrefix: 'handle', eventHandlerPropPrefix: 'when' }] + }, { + code: ' handleChange()} />', + errors: [{message: 'Prop key for handleChange must begin with \'when\''}], + options: [{ + checkInlineFunction: true, + checkLocalVariables: true, + eventHandlerPrefix: 'handle', + eventHandlerPropPrefix: 'when' + }] }, { code: '', errors: [{message: 'Handler function for onChange prop key must begin with \'handle\''}]