From ef36ba9e126073b65648851d20be98fc0915004b Mon Sep 17 00:00:00 2001 From: Alex Zherdev Date: Sun, 5 Aug 2018 00:21:13 -0700 Subject: [PATCH 1/2] Add a helper function for determining function-like expressions --- lib/rules/display-name.js | 3 ++- lib/rules/no-array-index-key.js | 7 ++----- lib/rules/no-unused-prop-types.js | 6 ++---- lib/rules/require-render-return.js | 2 +- lib/rules/sort-comp.js | 6 ++---- lib/util/ast.js | 22 +++++++++++++++------- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/rules/display-name.js b/lib/rules/display-name.js index 8fa67761cb..4e40d3fcb7 100644 --- a/lib/rules/display-name.js +++ b/lib/rules/display-name.js @@ -6,6 +6,7 @@ const has = require('has'); const Components = require('../util/Components'); +const astUtil = require('../util/ast'); const docsUrl = require('../util/docsUrl'); // ------------------------------------------------------------------------------ @@ -116,7 +117,7 @@ module.exports = { ); const namedFunctionExpression = ( - (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && + astUtil.isFunctionLikeExpression(node) && node.parent && (node.parent.type === 'VariableDeclarator' || node.parent.method === true) && (!node.parent.parent || !utils.isES5Component(node.parent.parent)) diff --git a/lib/rules/no-array-index-key.js b/lib/rules/no-array-index-key.js index 37e93b04dd..c5b1fe0a32 100644 --- a/lib/rules/no-array-index-key.js +++ b/lib/rules/no-array-index-key.js @@ -5,6 +5,7 @@ 'use strict'; const has = require('has'); +const astUtil = require('../util/ast'); const docsUrl = require('../util/docsUrl'); // ------------------------------------------------------------------------------ @@ -63,11 +64,7 @@ module.exports = { return null; } - const isFunction = [ - 'ArrowFunctionExpression', - 'FunctionExpression' - ].indexOf(firstArg.type) !== -1; - if (!isFunction) { + if (!astUtil.isFunctionLikeExpression(firstArg)) { return null; } diff --git a/lib/rules/no-unused-prop-types.js b/lib/rules/no-unused-prop-types.js index b82c9049ec..590378e8a3 100644 --- a/lib/rules/no-unused-prop-types.js +++ b/lib/rules/no-unused-prop-types.js @@ -11,6 +11,7 @@ const has = require('has'); const Components = require('../util/Components'); const variable = require('../util/variable'); const annotations = require('../util/annotations'); +const astUtil = require('../util/ast'); const versionUtil = require('../util/version'); const propsUtil = require('../util/props'); const docsUrl = require('../util/docsUrl'); @@ -835,10 +836,7 @@ module.exports = { types.node = value; declaredPropTypes.push(types); // Handle custom prop validators using props inside - if ( - value.type === 'ArrowFunctionExpression' - || value.type === 'FunctionExpression' - ) { + if (astUtil.isFunctionLikeExpression(value)) { markPropTypesAsUsed(value); } }); diff --git a/lib/rules/require-render-return.js b/lib/rules/require-render-return.js index 356bb9a885..139465045e 100644 --- a/lib/rules/require-render-return.js +++ b/lib/rules/require-render-return.js @@ -46,7 +46,7 @@ module.exports = { if (astUtil.getPropertyName(properties[i]) !== 'render' || !properties[i].value) { continue; } - return /FunctionExpression$/.test(properties[i].value.type); + return astUtil.isFunctionLikeExpression(properties[i].value); } return false; } diff --git a/lib/rules/sort-comp.js b/lib/rules/sort-comp.js index ed364a8217..4e2602a74e 100644 --- a/lib/rules/sort-comp.js +++ b/lib/rules/sort-comp.js @@ -393,13 +393,11 @@ module.exports = { instanceVariable: !node.static && node.type === 'ClassProperty' && node.value && - node.value.type !== 'ArrowFunctionExpression' && - node.value.type !== 'FunctionExpression', + !astUtil.isFunctionLikeExpression(node.value), instanceMethod: !node.static && node.type === 'ClassProperty' && node.value && - (node.value.type === 'ArrowFunctionExpression' || - node.value.type === 'FunctionExpression'), + (astUtil.isFunctionLikeExpression(node.value)), typeAnnotation: !!node.typeAnnotation && node.value === null })); diff --git a/lib/util/ast.js b/lib/util/ast.js index a2c7696ea6..10fc434625 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -62,7 +62,6 @@ function getComponentProperties(node) { case 'ClassExpression': return node.body.body; case 'ObjectExpression': - // return node.properties; return node.properties; default: return []; @@ -70,11 +69,11 @@ function getComponentProperties(node) { } /** - * Checks if the node is the first in its line, excluding whitespace. - * @param {Object} context The node to check - * @param {ASTNode} node The node to check - * @return {Boolean} true if its the first node in its line - */ + * Checks if the node is the first in its line, excluding whitespace. + * @param {Object} context The node to check + * @param {ASTNode} node The node to check + * @return {Boolean} true if it's the first node in its line + */ function isNodeFirstInLine(context, node) { const sourceCode = context.getSourceCode(); let token = node; @@ -94,11 +93,20 @@ function isNodeFirstInLine(context, node) { return startLine !== endLine; } +/** + * Checks if the node is a function or arrow function expression. + * @param {Object} context The node to check + * @return {Boolean} true if it's a function-like expression + */ +function isFunctionLikeExpression(node) { + return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression'; +} module.exports = { findReturnStatement: findReturnStatement, getPropertyName: getPropertyName, getPropertyNameNode: getPropertyNameNode, getComponentProperties: getComponentProperties, - isNodeFirstInLine: isNodeFirstInLine + isNodeFirstInLine: isNodeFirstInLine, + isFunctionLikeExpression: isFunctionLikeExpression }; From 7edc98216887c31ed890acac17e05792d4aea761 Mon Sep 17 00:00:00 2001 From: Alex Zherdev Date: Sun, 5 Aug 2018 00:34:51 -0700 Subject: [PATCH 2/2] Fix lint error --- tests/lib/rules/no-typos.js | 210 ++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js index ba6b524bac..06279e786b 100644 --- a/tests/lib/rules/no-typos.js +++ b/tests/lib/rules/no-typos.js @@ -1370,110 +1370,110 @@ ruleTester.run('no-typos', rule, { message: 'Typo in declared prop type: objectof' }] }] -/* -// PropTypes declared on a component that is detected through JSDoc comments and is -// declared AFTER the PropTypes assignment -// Commented out since it only works with ESLint 5. - ,{ - code: ` - MyComponent.PROPTYPES = {} - \/** @extends React.Component *\/ - class MyComponent extends BaseComponent {} - `, - parserOptions: parserOptions - }, -*/ -/* -// createClass tests below fail, so they're commented out -// --------- - }, { - code: ` - import React from 'react'; - import PropTypes from 'prop-types'; - const Component = React.createClass({ - propTypes: { - a: PropTypes.string.isrequired, - b: PropTypes.shape({ - c: PropTypes.number - }).isrequired - } - }); - `, - parser: 'babel-eslint', - parserOptions: parserOptions, - errors: [{ - message: 'Typo in prop type chain qualifier: isrequired' - }, { - message: 'Typo in prop type chain qualifier: isrequired' - }] - }, { - code: ` - import React from 'react'; - import PropTypes from 'prop-types'; - const Component = React.createClass({ - childContextTypes: { - a: PropTypes.bools, - b: PropTypes.Array, - c: PropTypes.function, - d: PropTypes.objectof, - } - }); - `, - parser: 'babel-eslint', - parserOptions: parserOptions, - errors: [{ - message: 'Typo in declared prop type: bools' - }, { - message: 'Typo in declared prop type: Array' - }, { - message: 'Typo in declared prop type: function' - }, { - message: 'Typo in declared prop type: objectof' - }] - }, { - code: ` - import React from 'react'; - import PropTypes from 'prop-types'; - const Component = React.createClass({ - propTypes: { - a: PropTypes.string.isrequired, - b: PropTypes.shape({ - c: PropTypes.number - }).isrequired - } - }); - `, - parserOptions: parserOptions, - errors: [{ - message: 'Typo in prop type chain qualifier: isrequired' - }, { - message: 'Typo in prop type chain qualifier: isrequired' - }] - }, { - code: ` - import React from 'react'; - import PropTypes from 'prop-types'; - const Component = React.createClass({ - childContextTypes: { - a: PropTypes.bools, - b: PropTypes.Array, - c: PropTypes.function, - d: PropTypes.objectof, - } - }); - `, - parserOptions: parserOptions, - errors: [{ - message: 'Typo in declared prop type: bools' - }, { - message: 'Typo in declared prop type: Array' - }, { - message: 'Typo in declared prop type: function' - }, { - message: 'Typo in declared prop type: objectof' + /* + // PropTypes declared on a component that is detected through JSDoc comments and is + // declared AFTER the PropTypes assignment + // Commented out since it only works with ESLint 5. + ,{ + code: ` + MyComponent.PROPTYPES = {} + \/** @extends React.Component *\/ + class MyComponent extends BaseComponent {} + `, + parserOptions: parserOptions + }, + */ + /* + // createClass tests below fail, so they're commented out + // --------- + }, { + code: ` + import React from 'react'; + import PropTypes from 'prop-types'; + const Component = React.createClass({ + propTypes: { + a: PropTypes.string.isrequired, + b: PropTypes.shape({ + c: PropTypes.number + }).isrequired + } + }); + `, + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{ + message: 'Typo in prop type chain qualifier: isrequired' + }, { + message: 'Typo in prop type chain qualifier: isrequired' + }] + }, { + code: ` + import React from 'react'; + import PropTypes from 'prop-types'; + const Component = React.createClass({ + childContextTypes: { + a: PropTypes.bools, + b: PropTypes.Array, + c: PropTypes.function, + d: PropTypes.objectof, + } + }); + `, + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{ + message: 'Typo in declared prop type: bools' + }, { + message: 'Typo in declared prop type: Array' + }, { + message: 'Typo in declared prop type: function' + }, { + message: 'Typo in declared prop type: objectof' + }] + }, { + code: ` + import React from 'react'; + import PropTypes from 'prop-types'; + const Component = React.createClass({ + propTypes: { + a: PropTypes.string.isrequired, + b: PropTypes.shape({ + c: PropTypes.number + }).isrequired + } + }); + `, + parserOptions: parserOptions, + errors: [{ + message: 'Typo in prop type chain qualifier: isrequired' + }, { + message: 'Typo in prop type chain qualifier: isrequired' + }] + }, { + code: ` + import React from 'react'; + import PropTypes from 'prop-types'; + const Component = React.createClass({ + childContextTypes: { + a: PropTypes.bools, + b: PropTypes.Array, + c: PropTypes.function, + d: PropTypes.objectof, + } + }); + `, + parserOptions: parserOptions, + errors: [{ + message: 'Typo in declared prop type: bools' + }, { + message: 'Typo in declared prop type: Array' + }, { + message: 'Typo in declared prop type: function' + }, { + message: 'Typo in declared prop type: objectof' + }] }] - }] -// --------- -// createClass tests above fail, so they're commented out -*/ + // --------- + // createClass tests above fail, so they're commented out + */ });