Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a helper function for determining function-like expressions #1914

Merged
merged 2 commits into from Aug 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/rules/display-name.js
Expand Up @@ -6,6 +6,7 @@

const has = require('has');
const Components = require('../util/Components');
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -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))
Expand Down
7 changes: 2 additions & 5 deletions lib/rules/no-array-index-key.js
Expand Up @@ -5,6 +5,7 @@
'use strict';

const has = require('has');
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -63,11 +64,7 @@ module.exports = {
return null;
}

const isFunction = [
'ArrowFunctionExpression',
'FunctionExpression'
].indexOf(firstArg.type) !== -1;
if (!isFunction) {
if (!astUtil.isFunctionLikeExpression(firstArg)) {
return null;
}

Expand Down
6 changes: 2 additions & 4 deletions lib/rules/no-unused-prop-types.js
Expand Up @@ -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');
Expand Down Expand Up @@ -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);
}
});
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/require-render-return.js
Expand Up @@ -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;
}
Expand Down
6 changes: 2 additions & 4 deletions lib/rules/sort-comp.js
Expand Up @@ -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
}));

Expand Down
22 changes: 15 additions & 7 deletions lib/util/ast.js
Expand Up @@ -62,19 +62,18 @@ function getComponentProperties(node) {
case 'ClassExpression':
return node.body.body;
case 'ObjectExpression':
// return node.properties;
return node.properties;
default:
return [];
}
}

/**
* 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;
Expand All @@ -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
};
210 changes: 105 additions & 105 deletions tests/lib/rules/no-typos.js
Expand Up @@ -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
*/
});