Skip to content

Commit

Permalink
add jsx-pascal-case rule
Browse files Browse the repository at this point in the history
  • Loading branch information
jakemmarsh committed Nov 17, 2015
1 parent 218e9fc commit 9d07f1d
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Finally, enable all of the rules that you would like to use.
* [jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX
* [jsx-no-literals](docs/rules/jsx-no-literals.md): Prevent usage of unwrapped JSX strings
* [jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
* [jsx-pascal-case](docs/rules/jsx-pascal-case.md): Enforce PascalCase for user-defined JSX components
* [jsx-quotes](docs/rules/jsx-quotes.md): Enforce quote style for JSX attributes
* [jsx-sort-prop-types](docs/rules/jsx-sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
* [jsx-sort-props](docs/rules/jsx-sort-props.md): Enforce props alphabetical sorting
Expand Down
37 changes: 37 additions & 0 deletions docs/rules/jsx-pascal-case.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Enforce PasalCase for user-defined JSX components (jsx-pascal-case)

Enforces coding style that user-defined JSX components are defined and referenced in PascalCase.

## Rule Details

The following patterns are considered warnings:

```js
<testComponent />
```

```js
<testComponent>
<div />
</testComponent>
```

```js
<test_component />
```

The following patterns are not considered warnings:

```js
<TestComponent />
```

```js
<TestComponent>
<div />
</TestComponent>
```

## When Not To Use It

If you are not using JSX.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = {
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state'),
'react-in-jsx-scope': require('./lib/rules/react-in-jsx-scope'),
'jsx-uses-vars': require('./lib/rules/jsx-uses-vars'),
'jsx-pascal-case': require('./lib/rules/jsx-pascal-case'),
'jsx-no-bind': require('./lib/rules/jsx-no-bind'),
'jsx-no-undef': require('./lib/rules/jsx-no-undef'),
'jsx-quotes': require('./lib/rules/jsx-quotes'),
Expand Down Expand Up @@ -46,6 +47,7 @@ module.exports = {
'no-did-update-set-state': 0,
'react-in-jsx-scope': 0,
'jsx-uses-vars': 1,
'jsx-pascal-case': 0,
'jsx-no-bind': 0,
'jsx-no-undef': 0,
'jsx-quotes': 0,
Expand Down
49 changes: 49 additions & 0 deletions lib/rules/jsx-pascal-case.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* @fileoverview Enforce PasalCase for user-defined JSX components
* @author Jake Marsh
*/

'use strict';

var variableUtil = require('../util/variable');

// ------------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------------

var PASCAL_CASE_REGEX = /^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/;

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

module.exports = function(context) {

return {
JSXOpeningElement: function(node) {
var variables = variableUtil.variablesInScope(context);

switch (node.name.type) {
case 'JSXIdentifier':
node = node.name;
break;
case 'JSXMemberExpression':
node = node.name.object;
break;
case 'JSXNamespacedName':
node = node.name.namespace;
break;
default:
break;
}

var isImportedVariable = variableUtil.findVariable(variables, node.name);
var isPascalCase = PASCAL_CASE_REGEX.test(node.name);

if (isImportedVariable && !isPascalCase) {
context.report(node, 'Imported JSX component ' + node.name + ' must be in PascalCase');
}
}
};

};
70 changes: 70 additions & 0 deletions tests/lib/rules/jsx-pascal-case.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @fileoverview Tests for jsx-pascal-case
* @author Jake Marsh
*/
'use strict';

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

var rule = require('../../../lib/rules/jsx-pascal-case');
var RuleTester = require('eslint').RuleTester;

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

var ruleTester = new RuleTester();
ruleTester.run('jsx-pascal-case', rule, {
valid: [{
code: [
'var TestComponent;',
'<TestComponent />'
].join('\n'),
ecmaFeatures: {
jsx: true
}
}, {
code: [
'var TestComponent;',
'<TestComponent>',
' <div />',
'</TestComponent>'
].join('\n'),
ecmaFeatures: {
jsx: true
}
}],

invalid: [{
code: [
'var testComponent;',
'<testComponent />'
].join('\n'),
ecmaFeatures: {
jsx: true
},
errors: [{message: 'Imported JSX component testComponent must be in PascalCase'}]
}, {
code: [
'var test_component;',
'<test_component />'
].join('\n'),
ecmaFeatures: {
jsx: true
},
errors: [{message: 'Imported JSX component test_component must be in PascalCase'}]
}, {
code: [
'var testComponent;',
'<testComponent>',
' <div />',
'</testComponent>'
].join('\n'),
ecmaFeatures: {
jsx: true
},
errors: [{message: 'Imported JSX component testComponent must be in PascalCase'}]
}]
});

0 comments on commit 9d07f1d

Please sign in to comment.