From 345aef44e97061ed5ae02dea00e90fe92782f27e Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Fri, 19 May 2017 13:09:39 +0300 Subject: [PATCH 01/22] Add no-static-typos rule --- docs/rules/no-static-typos.md | 57 +++++++++++ index.js | 3 +- lib/rules/no-static-typos.js | 52 ++++++++++ tests/lib/rules/no-static-typos.js | 155 +++++++++++++++++++++++++++++ 4 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 docs/rules/no-static-typos.md create mode 100644 lib/rules/no-static-typos.js create mode 100644 tests/lib/rules/no-static-typos.js diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md new file mode 100644 index 0000000000..81047eb8ef --- /dev/null +++ b/docs/rules/no-static-typos.md @@ -0,0 +1,57 @@ +# Prevent casing typos when declaring static propTypes, contextType and defaultProps + +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 +* 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 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 defaultProps = {} +} +... diff --git a/index.js b/index.js index 3cb6f72f26..81b056e9f0 100644 --- a/index.js +++ b/index.js @@ -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-static-typos': require('./lib/rules/no-static-typos') }; function filterRules(rules, predicate) { diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js new file mode 100644 index 0000000000..3c3e7a6c25 --- /dev/null +++ b/lib/rules/no-static-typos.js @@ -0,0 +1,52 @@ +/** + * @fileoverview Prevent casing typos when declaring propTypes, contextTypes and defaultProps + */ +'use strict'; + +var Components = require('../util/Components'); + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +var STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'defaultProps']; + +module.exports = { + meta: { + docs: { + description: 'Prevent casing typos when declaring static class properties', + category: 'Stylistic Issues', + recommended: false + }, + schema: [] + }, + + create: Components.detect(function(context, components, utils) { + + function reportError(node) { + context.report({ + node: node, + message: 'Typo in static class property declaration' + }); + } + + return { + ClassProperty: function(node) { + if (!node.static || !utils.isES6Component(node.parent.parent)) { + return; + } + + var tokens = context.getFirstTokens(node, 2); + + var propertyName = tokens[1].value; + var propertyNameLowerCase = propertyName.toLowerCase(); + + STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { + if (CLASS_PROP.toLowerCase() === propertyNameLowerCase && CLASS_PROP !== propertyName) { + reportError(node); + } + }); + } + }; + }) +}; diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js new file mode 100644 index 0000000000..f4576f7c55 --- /dev/null +++ b/tests/lib/rules/no-static-typos.js @@ -0,0 +1,155 @@ +/** + * @fileoverview Tests for no-static-typos + */ +'use strict'; + +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- + +var rule = require('../../../lib/rules/no-static-typos'); +var RuleTester = require('eslint').RuleTester; + +var parserOptions = { + ecmaVersion: 6 +}; + +require('babel-eslint'); + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +var ERROR_MESSAGE = 'Typo in static class property declaration'; + +var ruleTester = new RuleTester(); +ruleTester.run('no-static-typos', rule, { + + valid: [{ + code: [ + 'class First {', + ' static PropTypes = {key: "myValue"};', + ' static ContextTypes = {key: "myValue"};', + ' static DefaultProps = {key: "myValue"};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class First extends React.Component {', + ' static propTypes = {key: "myValue"};', + ' static contextTypes = {key: "myValue"};', + ' static defaultProps = {key: "myValue"};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {', + ' propTypes = {key: "myValue"};', + ' contextTypes = {key: "myValue"};', + ' defaultProps = {key: "myValue"};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {', + ' PropTypes = {key: "myValue"};', + ' ContextTypes = {key: "myValue"};', + ' DefaultProps = {key: "myValue"};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {', + ' proptypes = {key: "myValue"};', + ' contexttypes = {key: "myValue"};', + ' defaultprops = {key: "myValue"};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {', + ' static PropTypes() {};', + ' static ContextTypes() {};', + ' static DefaultProps() {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {', + ' static proptypes() {};', + ' static contexttypes() {};', + ' static defaultprops() {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions + }], + + invalid: [{ + code: [ + 'class Component extends React.Component {', + ' static PropTypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static proptypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static ContextTypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static contexttypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static DefaultProps = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static defaultprops = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }] +}); From 860d7f3d07a176a4a0adf494145e6bc82a9fe4ae Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Fri, 19 May 2017 15:04:45 +0300 Subject: [PATCH 02/22] Add fix for no-static-typos --- lib/rules/no-static-typos.js | 10 +++++++--- tests/lib/rules/no-static-typos.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 3c3e7a6c25..de349563c0 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -18,15 +18,19 @@ module.exports = { category: 'Stylistic Issues', recommended: false }, + fixable: 'code', schema: [] }, create: Components.detect(function(context, components, utils) { - function reportError(node) { + function reportError(node, classPropertyName) { context.report({ node: node, - message: 'Typo in static class property declaration' + message: 'Typo in static class property declaration', + fix: function(fixer) { + return fixer.replaceText(context.getFirstTokens(node, 2)[1], classPropertyName); + } }); } @@ -43,7 +47,7 @@ module.exports = { STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { if (CLASS_PROP.toLowerCase() === propertyNameLowerCase && CLASS_PROP !== propertyName) { - reportError(node); + reportError(node, CLASS_PROP); } }); } diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index f4576f7c55..6a4cb2dbc3 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -103,6 +103,11 @@ ruleTester.run('no-static-typos', rule, { ' static PropTypes = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static propTypes = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -112,6 +117,11 @@ ruleTester.run('no-static-typos', rule, { ' static proptypes = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static propTypes = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -121,6 +131,11 @@ ruleTester.run('no-static-typos', rule, { ' static ContextTypes = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static contextTypes = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -130,6 +145,11 @@ ruleTester.run('no-static-typos', rule, { ' static contexttypes = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static contextTypes = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -139,6 +159,11 @@ ruleTester.run('no-static-typos', rule, { ' static DefaultProps = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static defaultProps = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -148,6 +173,11 @@ ruleTester.run('no-static-typos', rule, { ' static defaultprops = {};', '}' ].join('\n'), + output: [ + 'class Component extends React.Component {', + ' static defaultProps = {};', + '}' + ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] From 6a0a61478b4ed62b0a9fddaf4bcd1e9479e0a042 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Fri, 19 May 2017 16:04:20 +0300 Subject: [PATCH 03/22] Fix documentation: Fix an error with closing the code tag Add "fixable" to the documentation Add link to the main README --- README.md | 1 + docs/rules/no-static-typos.md | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2109a9a16e..8ba32cf890 100644 --- a/README.md +++ b/README.md @@ -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-static-typos](docs/rules/no-static-typos.md): Prevent casing typos when declaring static class properties. * [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) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md index 81047eb8ef..56991e46d8 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-static-typos.md @@ -2,6 +2,8 @@ Ensure no casing typos were made declaring static class properties +**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line. + ## Rule Details This rule checks whether the declared static class properties related to React components @@ -38,7 +40,7 @@ class MyComponent extends React.Component { class MyComponent extends React.Component { static defaultprops = {} } -... +``` The following patterns are not considered warnings: From 692a94ffb227a153d11204f5ad6d76658c27cf8d Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Fri, 19 May 2017 16:08:42 +0300 Subject: [PATCH 04/22] Another minor documentation fix --- docs/rules/no-static-typos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md index 56991e46d8..e54c59d9e1 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-static-typos.md @@ -56,4 +56,4 @@ class MyComponent extends React.Component { class MyComponent extends React.Component { static defaultProps = {} } -... +``` From 89f340cc36c5797f9b9cb98742d845b87d4892d0 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sun, 21 May 2017 11:34:45 +0300 Subject: [PATCH 05/22] Remove fixer from no-static-typos --- docs/rules/no-static-typos.md | 2 -- lib/rules/no-static-typos.js | 10 +++------- tests/lib/rules/no-static-typos.js | 30 ------------------------------ 3 files changed, 3 insertions(+), 39 deletions(-) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md index e54c59d9e1..4f675d26da 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-static-typos.md @@ -2,8 +2,6 @@ Ensure no casing typos were made declaring static class properties -**Fixable:** This rule is automatically fixable using the `--fix` flag on the command line. - ## Rule Details This rule checks whether the declared static class properties related to React components diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index de349563c0..3c3e7a6c25 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -18,19 +18,15 @@ module.exports = { category: 'Stylistic Issues', recommended: false }, - fixable: 'code', schema: [] }, create: Components.detect(function(context, components, utils) { - function reportError(node, classPropertyName) { + function reportError(node) { context.report({ node: node, - message: 'Typo in static class property declaration', - fix: function(fixer) { - return fixer.replaceText(context.getFirstTokens(node, 2)[1], classPropertyName); - } + message: 'Typo in static class property declaration' }); } @@ -47,7 +43,7 @@ module.exports = { STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { if (CLASS_PROP.toLowerCase() === propertyNameLowerCase && CLASS_PROP !== propertyName) { - reportError(node, CLASS_PROP); + reportError(node); } }); } diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index 6a4cb2dbc3..f4576f7c55 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -103,11 +103,6 @@ ruleTester.run('no-static-typos', rule, { ' static PropTypes = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static propTypes = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -117,11 +112,6 @@ ruleTester.run('no-static-typos', rule, { ' static proptypes = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static propTypes = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -131,11 +121,6 @@ ruleTester.run('no-static-typos', rule, { ' static ContextTypes = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static contextTypes = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -145,11 +130,6 @@ ruleTester.run('no-static-typos', rule, { ' static contexttypes = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static contextTypes = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -159,11 +139,6 @@ ruleTester.run('no-static-typos', rule, { ' static DefaultProps = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static defaultProps = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] @@ -173,11 +148,6 @@ ruleTester.run('no-static-typos', rule, { ' static defaultprops = {};', '}' ].join('\n'), - output: [ - 'class Component extends React.Component {', - ' static defaultProps = {};', - '}' - ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] From 36fae242032b58501057edc2c77cab2cc2368118 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sun, 21 May 2017 11:36:57 +0300 Subject: [PATCH 06/22] Update the title for the readme for the file Added the rule name Decided to not mention all the possible properties that we check for in the title, as adding childContextTypes in the next commit may end up making this title too long. --- docs/rules/no-static-typos.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md index 4f675d26da..3856f37754 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-static-typos.md @@ -1,4 +1,4 @@ -# Prevent casing typos when declaring static propTypes, contextType and defaultProps +# Prevent casing typos when declaring static class properties (react/no-static-typos) Ensure no casing typos were made declaring static class properties From 4a596ba9c77bedee193a8b789bd51429be38b8c8 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sun, 21 May 2017 11:41:24 +0300 Subject: [PATCH 07/22] Add support for childContextTypes --- docs/rules/no-static-typos.md | 13 +++++++++++++ lib/rules/no-static-typos.js | 2 +- tests/lib/rules/no-static-typos.js | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-static-typos.md index 3856f37754..15c69aefa6 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-static-typos.md @@ -10,6 +10,7 @@ no casing typos: * propTypes * contextTypes +* childContextTypes * defaultProps The following patterns are considered warnings: @@ -31,6 +32,14 @@ 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 = {} } @@ -51,6 +60,10 @@ class MyComponent extends React.Component { static contextTypes = {} } +class MyComponent extends React.Component { + static childContextTypes = {} +} + class MyComponent extends React.Component { static defaultProps = {} } diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 3c3e7a6c25..362de965d3 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -9,7 +9,7 @@ var Components = require('../util/Components'); // Rule Definition // ------------------------------------------------------------------------------ -var STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'defaultProps']; +var STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps']; module.exports = { meta: { diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index f4576f7c55..432645c194 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -30,6 +30,7 @@ ruleTester.run('no-static-typos', rule, { 'class First {', ' static PropTypes = {key: "myValue"};', ' static ContextTypes = {key: "myValue"};', + ' static ChildContextTypes = {key: "myValue"};', ' static DefaultProps = {key: "myValue"};', '}' ].join('\n'), @@ -40,6 +41,7 @@ ruleTester.run('no-static-typos', rule, { 'class First extends React.Component {', ' static propTypes = {key: "myValue"};', ' static contextTypes = {key: "myValue"};', + ' static childContextTypes = {key: "myValue"};', ' static defaultProps = {key: "myValue"};', '}' ].join('\n'), @@ -50,6 +52,7 @@ ruleTester.run('no-static-typos', rule, { 'class MyClass {', ' propTypes = {key: "myValue"};', ' contextTypes = {key: "myValue"};', + ' childContextTypes = {key: "myValue"};', ' defaultProps = {key: "myValue"};', '}' ].join('\n'), @@ -60,6 +63,7 @@ ruleTester.run('no-static-typos', rule, { 'class MyClass {', ' PropTypes = {key: "myValue"};', ' ContextTypes = {key: "myValue"};', + ' ChildContextTypes = {key: "myValue"};', ' DefaultProps = {key: "myValue"};', '}' ].join('\n'), @@ -70,6 +74,7 @@ ruleTester.run('no-static-typos', rule, { 'class MyClass {', ' proptypes = {key: "myValue"};', ' contexttypes = {key: "myValue"};', + ' childcontextypes = {key: "myValue"};', ' defaultprops = {key: "myValue"};', '}' ].join('\n'), @@ -80,6 +85,7 @@ ruleTester.run('no-static-typos', rule, { 'class MyClass {', ' static PropTypes() {};', ' static ContextTypes() {};', + ' static ChildContextTypes() {};', ' static DefaultProps() {};', '}' ].join('\n'), @@ -90,6 +96,7 @@ ruleTester.run('no-static-typos', rule, { 'class MyClass {', ' static proptypes() {};', ' static contexttypes() {};', + ' static childcontexttypes() {};', ' static defaultprops() {};', '}' ].join('\n'), @@ -133,6 +140,24 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static ChildContextTypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {', + ' static childcontexttypes = {};', + '}' + ].join('\n'), + parser: 'babel-eslint', + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', From 01d4338cd8f7e9089ae380275e9bc754e1c02e34 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Wed, 31 May 2017 07:55:45 +0300 Subject: [PATCH 08/22] Remove requiring babel-eslint in the test --- tests/lib/rules/no-static-typos.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index 432645c194..dec4d5ab65 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -14,8 +14,6 @@ var parserOptions = { ecmaVersion: 6 }; -require('babel-eslint'); - // ----------------------------------------------------------------------------- // Tests // ----------------------------------------------------------------------------- From 394b4d53b0df2f48b985124b782db665447cf0a6 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Mon, 5 Jun 2017 07:37:08 +0300 Subject: [PATCH 09/22] Also handle cases where we declare propTypes outside of the class --- lib/rules/no-static-typos.js | 28 +++++---- tests/lib/rules/no-static-typos.js | 98 +++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 12 deletions(-) diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 362de965d3..0fe48494fe 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -23,10 +23,14 @@ module.exports = { create: Components.detect(function(context, components, utils) { - function reportError(node) { - context.report({ - node: node, - message: 'Typo in static class property declaration' + function reportErrorIfCasingTypo(node, propertyName) { + STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { + if (CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) { + context.report({ + node: node, + message: 'Typo in static class property declaration' + }); + } }); } @@ -37,15 +41,17 @@ module.exports = { } var tokens = context.getFirstTokens(node, 2); - var propertyName = tokens[1].value; - var propertyNameLowerCase = propertyName.toLowerCase(); + reportErrorIfCasingTypo(node, propertyName); + }, - STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { - if (CLASS_PROP.toLowerCase() === propertyNameLowerCase && CLASS_PROP !== propertyName) { - reportError(node); - } - }); + MemberExpression: function(node) { + const relatedComponent = utils.getRelatedComponent(node); + + if (relatedComponent && utils.isES6Component(relatedComponent.node)) { + var propertyName = node.property.name; + reportErrorIfCasingTypo(node, propertyName); + } } }; }) diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index dec4d5ab65..0293e18dc8 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -11,7 +11,10 @@ var rule = require('../../../lib/rules/no-static-typos'); var RuleTester = require('eslint').RuleTester; var parserOptions = { - ecmaVersion: 6 + ecmaVersion: 6, + ecmaFeatures: { + jsx: true + } }; // ----------------------------------------------------------------------------- @@ -34,6 +37,16 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions + }, + { + code: [ + 'class First {}', + 'First.PropTypes = {key: "myValue"};', + 'First.ContextTypes = {key: "myValue"};', + 'First.ChildContextTypes = {key: "myValue"};', + 'First.DefaultProps = {key: "myValue"};' + ].join('\n'), + parserOptions: parserOptions }, { code: [ 'class First extends React.Component {', @@ -45,6 +58,15 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions + }, { + code: [ + 'class First extends React.Component {}', + 'First.propTypes = {key: "myValue"};', + 'First.contextTypes = {key: "myValue"};', + 'First.childContextTypes = {key: "myValue"};', + 'First.defaultProps = {key: "myValue"};' + ].join('\n'), + parserOptions: parserOptions }, { code: [ 'class MyClass {', @@ -100,6 +122,24 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parser: 'babel-eslint', parserOptions: parserOptions + }, { + code: [ + 'class MyClass {}', + 'MyClass.prototype.PropTypes = function() {};', + 'MyClass.prototype.ContextTypes = function() {};', + 'MyClass.prototype.ChildContextTypes = function() {};', + 'MyClass.prototype.DefaultProps = function() {};' + ].join('\n'), + parserOptions: parserOptions + }, { + code: [ + 'class MyClass {}', + 'MyClass.PropTypes = function() {};', + 'MyClass.ContextTypes = function() {};', + 'MyClass.ChildContextTypes = function() {};', + 'MyClass.DefaultProps = function() {};' + ].join('\n'), + parserOptions: parserOptions }], invalid: [{ @@ -111,6 +151,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.PropTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -120,6 +167,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.proptypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -129,6 +183,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.ContextTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -138,6 +199,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.contexttypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -147,6 +215,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.ChildContextTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -156,6 +231,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.childcontexttypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -165,6 +247,13 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.DefaultProps = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -174,5 +263,12 @@ ruleTester.run('no-static-typos', rule, { parser: 'babel-eslint', parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'class Component extends React.Component {}', + 'Component.defaultprops = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }] }); From 5ac830ecdbc6abb593a6c57a602b535756ca1e81 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Tue, 13 Jun 2017 08:11:45 +0300 Subject: [PATCH 10/22] Add test cases for function components --- tests/lib/rules/no-static-typos.js | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index 0293e18dc8..99e4f8c569 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -140,6 +140,15 @@ ruleTester.run('no-static-typos', rule, { 'MyClass.DefaultProps = function() {};' ].join('\n'), parserOptions: parserOptions + }, { + code: [ + 'function MyRandomFunction() {}', + 'MyRandomFunction.PropTypes = {};', + 'MyRandomFunction.ContextTypes = {};', + 'MyRandomFunction.ChildContextTypes = {};', + 'MyRandomFunction.DefaultProps = {};' + ].join('\n'), + parserOptions: parserOptions }], invalid: [{ @@ -158,6 +167,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.PropTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -174,6 +190,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.proptypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -190,6 +213,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.ContextTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -206,6 +236,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.contexttypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -222,6 +259,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.ChildContextTypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -238,6 +282,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.childcontexttypes = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -254,6 +305,13 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.DefaultProps = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }, { code: [ 'class Component extends React.Component {', @@ -270,5 +328,12 @@ ruleTester.run('no-static-typos', rule, { ].join('\n'), parserOptions: parserOptions, errors: [{message: ERROR_MESSAGE}] + }, { + code: [ + 'function MyComponent() { return (
{this.props.myProp
) }', + 'MyComponent.defaultprops = {}' + ].join('\n'), + parserOptions: parserOptions, + errors: [{message: ERROR_MESSAGE}] }] }); From ccff8ea64bcdc8763195a53ae46df08b4d34d0df Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:36:24 +0200 Subject: [PATCH 11/22] Fix syntax errors in tests --- tests/lib/rules/no-static-typos.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-static-typos.js index 99e4f8c569..0d01bf8124 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-static-typos.js @@ -169,7 +169,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.PropTypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -192,7 +192,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.proptypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -215,7 +215,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.ContextTypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -238,7 +238,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.contexttypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -261,7 +261,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.ChildContextTypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -284,7 +284,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.childcontexttypes = {}' ].join('\n'), parserOptions: parserOptions, @@ -307,7 +307,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.DefaultProps = {}' ].join('\n'), parserOptions: parserOptions, @@ -330,7 +330,7 @@ ruleTester.run('no-static-typos', rule, { errors: [{message: ERROR_MESSAGE}] }, { code: [ - 'function MyComponent() { return (
{this.props.myProp
) }', + 'function MyComponent() { return (
{this.props.myProp}
) }', 'MyComponent.defaultprops = {}' ].join('\n'), parserOptions: parserOptions, From faea2af90ac6c3afbd31cd721fa426e118ae15c5 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:37:16 +0200 Subject: [PATCH 12/22] Add suport for FunctionDeclaration to findReturnStatement findReturnStatement expect "node.value.body.body" to exist, but for FunctionDeclarations the correct path to the ReturnStatement is "node.body.body" --- lib/util/Components.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/util/Components.js b/lib/util/Components.js index 31f634ea3e..91bb330690 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -319,13 +319,18 @@ 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); + const 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; From 49a7dfa3f0cb17f9c6b1f21490575b281fb9fafb Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:37:40 +0200 Subject: [PATCH 13/22] Properly detect ES6 components and Stateless functional components --- lib/rules/no-static-typos.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 0fe48494fe..07da2f6b01 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -48,7 +48,10 @@ module.exports = { MemberExpression: function(node) { const relatedComponent = utils.getRelatedComponent(node); - if (relatedComponent && utils.isES6Component(relatedComponent.node)) { + if ( + relatedComponent && + (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node)) + ) { var propertyName = node.property.name; reportErrorIfCasingTypo(node, propertyName); } From 3e6892927f2318fa33b1e18f372900929b1ac298 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:42:39 +0200 Subject: [PATCH 14/22] const to let --- lib/util/Components.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/util/Components.js b/lib/util/Components.js index 91bb330690..3eba46760d 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -327,7 +327,8 @@ function componentRule(rule, context) { } const bodyNodes = (node.value ? node.value.body.body : node.body.body); - const i = bodyNodes.length - 1; + + let i = bodyNodes.length - 1; for (; i >= 0; i--) { if (bodyNodes[i].type === 'ReturnStatement') { return bodyNodes[i]; From ebd423102d9c734aec047d3f539a9529a1ff4e74 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:45:09 +0200 Subject: [PATCH 15/22] Fix linting errors that popped up after rebase on master --- lib/rules/no-static-typos.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 07da2f6b01..923a739038 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -22,7 +22,6 @@ module.exports = { }, create: Components.detect(function(context, components, utils) { - function reportErrorIfCasingTypo(node, propertyName) { STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { if (CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) { From 3c3baef8757c965557bc6bf7264beeac64b96ee5 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 24 Jun 2017 18:51:20 +0200 Subject: [PATCH 16/22] Fix another lint error that doesn't show up locally, only on travis :o --- lib/util/Components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/Components.js b/lib/util/Components.js index 3eba46760d..1346fb9ef1 100644 --- a/lib/util/Components.js +++ b/lib/util/Components.js @@ -321,7 +321,7 @@ function componentRule(rule, context) { findReturnStatement: function(node) { if ( (!node.value || !node.value.body || !node.value.body.body) && - (!node.body || !node.body.body) + (!node.body || !node.body.body) ) { return false; } From 7620d478bcc472315cb69131091281dd8719a95c Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Wed, 28 Jun 2017 09:17:59 +0200 Subject: [PATCH 17/22] var to const --- lib/rules/no-static-typos.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-static-typos.js index 923a739038..5cb1ba14af 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-static-typos.js @@ -3,7 +3,7 @@ */ 'use strict'; -var Components = require('../util/Components'); +const Components = require('../util/Components'); // ------------------------------------------------------------------------------ // Rule Definition @@ -39,8 +39,8 @@ module.exports = { return; } - var tokens = context.getFirstTokens(node, 2); - var propertyName = tokens[1].value; + const tokens = context.getFirstTokens(node, 2); + const propertyName = tokens[1].value; reportErrorIfCasingTypo(node, propertyName); }, @@ -51,7 +51,7 @@ module.exports = { relatedComponent && (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node)) ) { - var propertyName = node.property.name; + const propertyName = node.property.name; reportErrorIfCasingTypo(node, propertyName); } } From efb73661b8aed29764487b4bdd12718fde644c41 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Wed, 28 Jun 2017 09:22:48 +0200 Subject: [PATCH 18/22] Rename no-static-typos to no-typos --- README.md | 2 +- docs/rules/{no-static-typos.md => no-typos.md} | 2 +- index.js | 2 +- lib/rules/{no-static-typos.js => no-typos.js} | 4 ++-- tests/lib/rules/{no-static-typos.js => no-typos.js} | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) rename docs/rules/{no-static-typos.md => no-typos.md} (94%) rename lib/rules/{no-static-typos.js => no-typos.js} (90%) rename tests/lib/rules/{no-static-typos.js => no-typos.js} (98%) diff --git a/README.md b/README.md index 8ba32cf890..2dd2cddb5a 100644 --- a/README.md +++ b/README.md @@ -102,7 +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-static-typos](docs/rules/no-static-typos.md): Prevent casing typos when declaring static class properties. +* [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) diff --git a/docs/rules/no-static-typos.md b/docs/rules/no-typos.md similarity index 94% rename from docs/rules/no-static-typos.md rename to docs/rules/no-typos.md index 15c69aefa6..a7dd2b9287 100644 --- a/docs/rules/no-static-typos.md +++ b/docs/rules/no-typos.md @@ -1,4 +1,4 @@ -# Prevent casing typos when declaring static class properties (react/no-static-typos) +# Prevents common casing typos (react/no-typos) Ensure no casing typos were made declaring static class properties diff --git a/index.js b/index.js index 81b056e9f0..7bd88043e0 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,7 @@ const allRules = { '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'), - 'no-static-typos': require('./lib/rules/no-static-typos') + 'no-typos': require('./lib/rules/no-typos') }; function filterRules(rules, predicate) { diff --git a/lib/rules/no-static-typos.js b/lib/rules/no-typos.js similarity index 90% rename from lib/rules/no-static-typos.js rename to lib/rules/no-typos.js index 5cb1ba14af..538a4c8230 100644 --- a/lib/rules/no-static-typos.js +++ b/lib/rules/no-typos.js @@ -1,5 +1,5 @@ /** - * @fileoverview Prevent casing typos when declaring propTypes, contextTypes and defaultProps + * @fileoverview Prevent common casing typos */ 'use strict'; @@ -14,7 +14,7 @@ var STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', module.exports = { meta: { docs: { - description: 'Prevent casing typos when declaring static class properties', + description: 'Prevent common casing typos', category: 'Stylistic Issues', recommended: false }, diff --git a/tests/lib/rules/no-static-typos.js b/tests/lib/rules/no-typos.js similarity index 98% rename from tests/lib/rules/no-static-typos.js rename to tests/lib/rules/no-typos.js index 0d01bf8124..bdf104ad19 100644 --- a/tests/lib/rules/no-static-typos.js +++ b/tests/lib/rules/no-typos.js @@ -1,5 +1,5 @@ /** - * @fileoverview Tests for no-static-typos + * @fileoverview Tests for no-typos */ 'use strict'; @@ -7,7 +7,7 @@ // Requirements // ----------------------------------------------------------------------------- -var rule = require('../../../lib/rules/no-static-typos'); +var rule = require('../../../lib/rules/no-typos'); var RuleTester = require('eslint').RuleTester; var parserOptions = { @@ -24,7 +24,7 @@ var parserOptions = { var ERROR_MESSAGE = 'Typo in static class property declaration'; var ruleTester = new RuleTester(); -ruleTester.run('no-static-typos', rule, { +ruleTester.run('no-typos', rule, { valid: [{ code: [ From 84bd23526bfc52fdae48032ae5702c041399b585 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Wed, 28 Jun 2017 09:31:54 +0200 Subject: [PATCH 19/22] Fix linting errors from the var -> const/let PR --- lib/rules/no-typos.js | 2 +- tests/lib/rules/no-typos.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/rules/no-typos.js b/lib/rules/no-typos.js index 538a4c8230..fd61e584a1 100644 --- a/lib/rules/no-typos.js +++ b/lib/rules/no-typos.js @@ -9,7 +9,7 @@ const Components = require('../util/Components'); // Rule Definition // ------------------------------------------------------------------------------ -var STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps']; +const STATIC_CLASS_PROPERTIES = ['propTypes', 'contextTypes', 'childContextTypes', 'defaultProps']; module.exports = { meta: { diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js index bdf104ad19..d1dc48234e 100644 --- a/tests/lib/rules/no-typos.js +++ b/tests/lib/rules/no-typos.js @@ -7,10 +7,10 @@ // Requirements // ----------------------------------------------------------------------------- -var rule = require('../../../lib/rules/no-typos'); -var RuleTester = require('eslint').RuleTester; +const rule = require('../../../lib/rules/no-typos'); +const RuleTester = require('eslint').RuleTester; -var parserOptions = { +const parserOptions = { ecmaVersion: 6, ecmaFeatures: { jsx: true @@ -21,9 +21,9 @@ var parserOptions = { // Tests // ----------------------------------------------------------------------------- -var ERROR_MESSAGE = 'Typo in static class property declaration'; +const ERROR_MESSAGE = 'Typo in static class property declaration'; -var ruleTester = new RuleTester(); +const ruleTester = new RuleTester(); ruleTester.run('no-typos', rule, { valid: [{ From 73d4941cea01773614469b0603edb091fb54b5b3 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Thu, 29 Jun 2017 09:21:31 +0200 Subject: [PATCH 20/22] Add test case that was causing a crash --- lib/rules/no-typos.js | 2 +- tests/lib/rules/no-typos.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/rules/no-typos.js b/lib/rules/no-typos.js index fd61e584a1..d3cce13714 100644 --- a/lib/rules/no-typos.js +++ b/lib/rules/no-typos.js @@ -24,7 +24,7 @@ module.exports = { create: Components.detect(function(context, components, utils) { function reportErrorIfCasingTypo(node, propertyName) { STATIC_CLASS_PROPERTIES.forEach(function(CLASS_PROP) { - if (CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) { + if (propertyName && CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) { context.report({ node: node, message: 'Typo in static class property declaration' diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js index d1dc48234e..b9f699d5e0 100644 --- a/tests/lib/rules/no-typos.js +++ b/tests/lib/rules/no-typos.js @@ -149,6 +149,15 @@ ruleTester.run('no-typos', rule, { 'MyRandomFunction.DefaultProps = {};' ].join('\n'), parserOptions: parserOptions + }, { + code: [ + 'class First extends React.Component {}', + 'First["prop" + "Types"] = {};', + 'First["context" + "Types"] = {};', + 'First["childContext" + "Types"] = {};', + 'First["default" + "Props"] = {};' + ].join('\n'), + parserOptions: parserOptions }], invalid: [{ From 82facc84492179be073afa4f26b1ea97c369d775 Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 1 Jul 2017 09:27:58 +0200 Subject: [PATCH 21/22] Add another valid test case --- tests/lib/rules/no-typos.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js index b9f699d5e0..de29f92a92 100644 --- a/tests/lib/rules/no-typos.js +++ b/tests/lib/rules/no-typos.js @@ -158,6 +158,15 @@ ruleTester.run('no-typos', rule, { 'First["default" + "Props"] = {};' ].join('\n'), parserOptions: parserOptions + }, { + code: [ // This case is currently not supported + 'class First extends React.Component {}', + 'First["PROP" + "TYPES"] = {};', + 'First["CONTEXT" + "TYPES"] = {};', + 'First["CHILDCONTEXT" + "TYPES"] = {};', + 'First["DEFAULT" + "PROPS"] = {};' + ].join('\n'), + parserOptions: parserOptions }], invalid: [{ From afd6ea0d18cdd3b70ee4e1087bce74b2143c762b Mon Sep 17 00:00:00 2001 From: Joachim Seminck Date: Sat, 1 Jul 2017 09:33:22 +0200 Subject: [PATCH 22/22] Add another valid test case --- tests/lib/rules/no-typos.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js index de29f92a92..7883352453 100644 --- a/tests/lib/rules/no-typos.js +++ b/tests/lib/rules/no-typos.js @@ -167,6 +167,20 @@ ruleTester.run('no-typos', rule, { 'First["DEFAULT" + "PROPS"] = {};' ].join('\n'), parserOptions: parserOptions + }, { + code: [ // This case is currently not supported + 'const propTypes = "PROPTYPES"', + 'const contextTypes = "CONTEXTTYPES"', + 'const childContextTypes = "CHILDCONTEXTTYPES"', + 'const defautProps = "DEFAULTPROPS"', + '', + 'class First extends React.Component {}', + 'First[propTypes] = {};', + 'First[contextTypes] = {};', + 'First[childContextTypes] = {};', + 'First[defautProps] = {};' + ].join('\n'), + parserOptions: parserOptions }], invalid: [{