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 rule no static typos #1209

Merged
merged 22 commits into from
Jul 1, 2017
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
* [react/no-redundant-should-component-update](docs/rules/no-redundant-should-component-update.md): Prevent usage of `shouldComponentUpdate` when extending React.PureComponent
* [react/no-render-return-value](docs/rules/no-render-return-value.md): Prevent usage of the return value of `React.render`
* [react/no-set-state](docs/rules/no-set-state.md): Prevent usage of `setState`
* [react/no-typos](docs/rules/no-typos.md): Prevent common casing typos
* [react/no-string-refs](docs/rules/no-string-refs.md): Prevent using string references in `ref` attribute.
* [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md): Prevent invalid characters from appearing in markup
* [react/no-unknown-property](docs/rules/no-unknown-property.md): Prevent usage of unknown DOM property (fixable)
Expand Down
70 changes: 70 additions & 0 deletions docs/rules/no-typos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Prevents common casing typos (react/no-typos)

Ensure no casing typos were made declaring static class properties

## Rule Details

This rule checks whether the declared static class properties related to React components
do not contain any typos. It currently makes sure that the following class properties have
no casing typos:

* propTypes
* contextTypes
* childContextTypes
* defaultProps

The following patterns are considered warnings:

```js
class MyComponent extends React.Component {
static PropTypes = {}
}

class MyComponent extends React.Component {
static proptypes = {}
}

class MyComponent extends React.Component {
static ContextTypes = {}
}

class MyComponent extends React.Component {
static contexttypes = {}
}

class MyComponent extends React.Component {
static ChildContextTypes = {}
}

class MyComponent extends React.Component {
static childcontexttypes = {}
}

class MyComponent extends React.Component {
static DefaultProps = {}
}

class MyComponent extends React.Component {
static defaultprops = {}
}
```

The following patterns are not considered warnings:

```js
class MyComponent extends React.Component {
static propTypes = {}
}

class MyComponent extends React.Component {
static contextTypes = {}
}

class MyComponent extends React.Component {
static childContextTypes = {}
}

class MyComponent extends React.Component {
static defaultProps = {}
}
```
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ const allRules = {
'void-dom-elements-no-children': require('./lib/rules/void-dom-elements-no-children'),
'jsx-tag-spacing': require('./lib/rules/jsx-tag-spacing'),
'no-redundant-should-component-update': require('./lib/rules/no-redundant-should-component-update'),
'boolean-prop-naming': require('./lib/rules/boolean-prop-naming')
'boolean-prop-naming': require('./lib/rules/boolean-prop-naming'),
'no-typos': require('./lib/rules/no-typos')
};

function filterRules(rules, predicate) {
Expand Down
60 changes: 60 additions & 0 deletions lib/rules/no-typos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @fileoverview Prevent common casing typos
*/
'use strict';

const Components = require('../util/Components');

// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------

const STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps'];

module.exports = {
meta: {
docs: {
description: 'Prevent common casing typos',
category: 'Stylistic Issues',
recommended: false
},
schema: []
},

create: Components.detect(function(context, components, utils) {
function reportErrorIfCasingTypo(node, propertyName) {
STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) {
if (propertyName && CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) {
context.report({
node: node,
message: 'Typo in static class property declaration'
});
}
});
}

return {
ClassProperty: function(node) {
if (!node.static || !utils.isES6Component(node.parent.parent)) {
return;
}

const tokens = context.getFirstTokens(node, 2);
const propertyName = tokens[1].value;
reportErrorIfCasingTypo(node, propertyName);
},

MemberExpression: function(node) {
const relatedComponent = utils.getRelatedComponent(node);

if (
relatedComponent &&
(utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node))
) {
const propertyName = node.property.name;
reportErrorIfCasingTypo(node, propertyName);
}
}
};
})
};
14 changes: 10 additions & 4 deletions lib/util/Components.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,19 @@ function componentRule(rule, context) {
* @param {ASTNode} ASTnode The AST node being checked
*/
findReturnStatement: function(node) {
if (!node.value || !node.value.body || !node.value.body.body) {
if (
(!node.value || !node.value.body || !node.value.body.body) &&
(!node.body || !node.body.body)
) {
return false;
}
let i = node.value.body.body.length - 1;

const bodyNodes = (node.value ? node.value.body.body : node.body.body);

let i = bodyNodes.length - 1;
for (; i >= 0; i--) {
if (node.value.body.body[i].type === 'ReturnStatement') {
return node.value.body.body[i];
if (bodyNodes[i].type === 'ReturnStatement') {
return bodyNodes[i];
}
}
return false;
Expand Down