Skip to content

Commit 9dbb834

Browse files
authored
Merge pull request #1914 from alexzherdev/is-function-helper
Add a helper function for determining function-like expressions
2 parents efe0c0c + 7edc982 commit 9dbb834

File tree

7 files changed

+129
-127
lines changed

7 files changed

+129
-127
lines changed

lib/rules/display-name.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
const has = require('has');
88
const Components = require('../util/Components');
9+
const astUtil = require('../util/ast');
910
const docsUrl = require('../util/docsUrl');
1011

1112
// ------------------------------------------------------------------------------
@@ -116,7 +117,7 @@ module.exports = {
116117
);
117118

118119
const namedFunctionExpression = (
119-
(node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') &&
120+
astUtil.isFunctionLikeExpression(node) &&
120121
node.parent &&
121122
(node.parent.type === 'VariableDeclarator' || node.parent.method === true) &&
122123
(!node.parent.parent || !utils.isES5Component(node.parent.parent))

lib/rules/no-array-index-key.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
'use strict';
66

77
const has = require('has');
8+
const astUtil = require('../util/ast');
89
const docsUrl = require('../util/docsUrl');
910

1011
// ------------------------------------------------------------------------------
@@ -63,11 +64,7 @@ module.exports = {
6364
return null;
6465
}
6566

66-
const isFunction = [
67-
'ArrowFunctionExpression',
68-
'FunctionExpression'
69-
].indexOf(firstArg.type) !== -1;
70-
if (!isFunction) {
67+
if (!astUtil.isFunctionLikeExpression(firstArg)) {
7168
return null;
7269
}
7370

lib/rules/no-unused-prop-types.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const has = require('has');
1111
const Components = require('../util/Components');
1212
const variable = require('../util/variable');
1313
const annotations = require('../util/annotations');
14+
const astUtil = require('../util/ast');
1415
const versionUtil = require('../util/version');
1516
const propsUtil = require('../util/props');
1617
const docsUrl = require('../util/docsUrl');
@@ -835,10 +836,7 @@ module.exports = {
835836
types.node = value;
836837
declaredPropTypes.push(types);
837838
// Handle custom prop validators using props inside
838-
if (
839-
value.type === 'ArrowFunctionExpression'
840-
|| value.type === 'FunctionExpression'
841-
) {
839+
if (astUtil.isFunctionLikeExpression(value)) {
842840
markPropTypesAsUsed(value);
843841
}
844842
});

lib/rules/require-render-return.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports = {
4646
if (astUtil.getPropertyName(properties[i]) !== 'render' || !properties[i].value) {
4747
continue;
4848
}
49-
return /FunctionExpression$/.test(properties[i].value.type);
49+
return astUtil.isFunctionLikeExpression(properties[i].value);
5050
}
5151
return false;
5252
}

lib/rules/sort-comp.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -393,13 +393,11 @@ module.exports = {
393393
instanceVariable: !node.static &&
394394
node.type === 'ClassProperty' &&
395395
node.value &&
396-
node.value.type !== 'ArrowFunctionExpression' &&
397-
node.value.type !== 'FunctionExpression',
396+
!astUtil.isFunctionLikeExpression(node.value),
398397
instanceMethod: !node.static &&
399398
node.type === 'ClassProperty' &&
400399
node.value &&
401-
(node.value.type === 'ArrowFunctionExpression' ||
402-
node.value.type === 'FunctionExpression'),
400+
(astUtil.isFunctionLikeExpression(node.value)),
403401
typeAnnotation: !!node.typeAnnotation && node.value === null
404402
}));
405403

lib/util/ast.js

+15-7
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,18 @@ function getComponentProperties(node) {
6262
case 'ClassExpression':
6363
return node.body.body;
6464
case 'ObjectExpression':
65-
// return node.properties;
6665
return node.properties;
6766
default:
6867
return [];
6968
}
7069
}
7170

7271
/**
73-
* Checks if the node is the first in its line, excluding whitespace.
74-
* @param {Object} context The node to check
75-
* @param {ASTNode} node The node to check
76-
* @return {Boolean} true if its the first node in its line
77-
*/
72+
* Checks if the node is the first in its line, excluding whitespace.
73+
* @param {Object} context The node to check
74+
* @param {ASTNode} node The node to check
75+
* @return {Boolean} true if it's the first node in its line
76+
*/
7877
function isNodeFirstInLine(context, node) {
7978
const sourceCode = context.getSourceCode();
8079
let token = node;
@@ -94,11 +93,20 @@ function isNodeFirstInLine(context, node) {
9493
return startLine !== endLine;
9594
}
9695

96+
/**
97+
* Checks if the node is a function or arrow function expression.
98+
* @param {Object} context The node to check
99+
* @return {Boolean} true if it's a function-like expression
100+
*/
101+
function isFunctionLikeExpression(node) {
102+
return node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';
103+
}
97104

98105
module.exports = {
99106
findReturnStatement: findReturnStatement,
100107
getPropertyName: getPropertyName,
101108
getPropertyNameNode: getPropertyNameNode,
102109
getComponentProperties: getComponentProperties,
103-
isNodeFirstInLine: isNodeFirstInLine
110+
isNodeFirstInLine: isNodeFirstInLine,
111+
isFunctionLikeExpression: isFunctionLikeExpression
104112
};

tests/lib/rules/no-typos.js

+105-105
Original file line numberDiff line numberDiff line change
@@ -1370,110 +1370,110 @@ ruleTester.run('no-typos', rule, {
13701370
message: 'Typo in declared prop type: objectof'
13711371
}]
13721372
}]
1373-
/*
1374-
// PropTypes declared on a component that is detected through JSDoc comments and is
1375-
// declared AFTER the PropTypes assignment
1376-
// Commented out since it only works with ESLint 5.
1377-
,{
1378-
code: `
1379-
MyComponent.PROPTYPES = {}
1380-
\/** @extends React.Component *\/
1381-
class MyComponent extends BaseComponent {}
1382-
`,
1383-
parserOptions: parserOptions
1384-
},
1385-
*/
1386-
/*
1387-
// createClass tests below fail, so they're commented out
1388-
// ---------
1389-
}, {
1390-
code: `
1391-
import React from 'react';
1392-
import PropTypes from 'prop-types';
1393-
const Component = React.createClass({
1394-
propTypes: {
1395-
a: PropTypes.string.isrequired,
1396-
b: PropTypes.shape({
1397-
c: PropTypes.number
1398-
}).isrequired
1399-
}
1400-
});
1401-
`,
1402-
parser: 'babel-eslint',
1403-
parserOptions: parserOptions,
1404-
errors: [{
1405-
message: 'Typo in prop type chain qualifier: isrequired'
1406-
}, {
1407-
message: 'Typo in prop type chain qualifier: isrequired'
1408-
}]
1409-
}, {
1410-
code: `
1411-
import React from 'react';
1412-
import PropTypes from 'prop-types';
1413-
const Component = React.createClass({
1414-
childContextTypes: {
1415-
a: PropTypes.bools,
1416-
b: PropTypes.Array,
1417-
c: PropTypes.function,
1418-
d: PropTypes.objectof,
1419-
}
1420-
});
1421-
`,
1422-
parser: 'babel-eslint',
1423-
parserOptions: parserOptions,
1424-
errors: [{
1425-
message: 'Typo in declared prop type: bools'
1426-
}, {
1427-
message: 'Typo in declared prop type: Array'
1428-
}, {
1429-
message: 'Typo in declared prop type: function'
1430-
}, {
1431-
message: 'Typo in declared prop type: objectof'
1432-
}]
1433-
}, {
1434-
code: `
1435-
import React from 'react';
1436-
import PropTypes from 'prop-types';
1437-
const Component = React.createClass({
1438-
propTypes: {
1439-
a: PropTypes.string.isrequired,
1440-
b: PropTypes.shape({
1441-
c: PropTypes.number
1442-
}).isrequired
1443-
}
1444-
});
1445-
`,
1446-
parserOptions: parserOptions,
1447-
errors: [{
1448-
message: 'Typo in prop type chain qualifier: isrequired'
1449-
}, {
1450-
message: 'Typo in prop type chain qualifier: isrequired'
1451-
}]
1452-
}, {
1453-
code: `
1454-
import React from 'react';
1455-
import PropTypes from 'prop-types';
1456-
const Component = React.createClass({
1457-
childContextTypes: {
1458-
a: PropTypes.bools,
1459-
b: PropTypes.Array,
1460-
c: PropTypes.function,
1461-
d: PropTypes.objectof,
1462-
}
1463-
});
1464-
`,
1465-
parserOptions: parserOptions,
1466-
errors: [{
1467-
message: 'Typo in declared prop type: bools'
1468-
}, {
1469-
message: 'Typo in declared prop type: Array'
1470-
}, {
1471-
message: 'Typo in declared prop type: function'
1472-
}, {
1473-
message: 'Typo in declared prop type: objectof'
1373+
/*
1374+
// PropTypes declared on a component that is detected through JSDoc comments and is
1375+
// declared AFTER the PropTypes assignment
1376+
// Commented out since it only works with ESLint 5.
1377+
,{
1378+
code: `
1379+
MyComponent.PROPTYPES = {}
1380+
\/** @extends React.Component *\/
1381+
class MyComponent extends BaseComponent {}
1382+
`,
1383+
parserOptions: parserOptions
1384+
},
1385+
*/
1386+
/*
1387+
// createClass tests below fail, so they're commented out
1388+
// ---------
1389+
}, {
1390+
code: `
1391+
import React from 'react';
1392+
import PropTypes from 'prop-types';
1393+
const Component = React.createClass({
1394+
propTypes: {
1395+
a: PropTypes.string.isrequired,
1396+
b: PropTypes.shape({
1397+
c: PropTypes.number
1398+
}).isrequired
1399+
}
1400+
});
1401+
`,
1402+
parser: 'babel-eslint',
1403+
parserOptions: parserOptions,
1404+
errors: [{
1405+
message: 'Typo in prop type chain qualifier: isrequired'
1406+
}, {
1407+
message: 'Typo in prop type chain qualifier: isrequired'
1408+
}]
1409+
}, {
1410+
code: `
1411+
import React from 'react';
1412+
import PropTypes from 'prop-types';
1413+
const Component = React.createClass({
1414+
childContextTypes: {
1415+
a: PropTypes.bools,
1416+
b: PropTypes.Array,
1417+
c: PropTypes.function,
1418+
d: PropTypes.objectof,
1419+
}
1420+
});
1421+
`,
1422+
parser: 'babel-eslint',
1423+
parserOptions: parserOptions,
1424+
errors: [{
1425+
message: 'Typo in declared prop type: bools'
1426+
}, {
1427+
message: 'Typo in declared prop type: Array'
1428+
}, {
1429+
message: 'Typo in declared prop type: function'
1430+
}, {
1431+
message: 'Typo in declared prop type: objectof'
1432+
}]
1433+
}, {
1434+
code: `
1435+
import React from 'react';
1436+
import PropTypes from 'prop-types';
1437+
const Component = React.createClass({
1438+
propTypes: {
1439+
a: PropTypes.string.isrequired,
1440+
b: PropTypes.shape({
1441+
c: PropTypes.number
1442+
}).isrequired
1443+
}
1444+
});
1445+
`,
1446+
parserOptions: parserOptions,
1447+
errors: [{
1448+
message: 'Typo in prop type chain qualifier: isrequired'
1449+
}, {
1450+
message: 'Typo in prop type chain qualifier: isrequired'
1451+
}]
1452+
}, {
1453+
code: `
1454+
import React from 'react';
1455+
import PropTypes from 'prop-types';
1456+
const Component = React.createClass({
1457+
childContextTypes: {
1458+
a: PropTypes.bools,
1459+
b: PropTypes.Array,
1460+
c: PropTypes.function,
1461+
d: PropTypes.objectof,
1462+
}
1463+
});
1464+
`,
1465+
parserOptions: parserOptions,
1466+
errors: [{
1467+
message: 'Typo in declared prop type: bools'
1468+
}, {
1469+
message: 'Typo in declared prop type: Array'
1470+
}, {
1471+
message: 'Typo in declared prop type: function'
1472+
}, {
1473+
message: 'Typo in declared prop type: objectof'
1474+
}]
14741475
}]
1475-
}]
1476-
// ---------
1477-
// createClass tests above fail, so they're commented out
1478-
*/
1476+
// ---------
1477+
// createClass tests above fail, so they're commented out
1478+
*/
14791479
});

0 commit comments

Comments
 (0)