Skip to content

Commit 2d96bd3

Browse files
committed
Add jsx-filename-extension rule
Some projects want to require that any file that uses JSX to end in .jsx, and others prefer to use .js. This rule can be used to enforce this. I see this as complimentary to require-extension. Fixes #495
1 parent ffc2b9e commit 2d96bd3

File tree

5 files changed

+172
-1
lines changed

5 files changed

+172
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ The plugin has a [recommended configuration](#user-content-recommended-configura
103103
* [jsx-closing-bracket-location](docs/rules/jsx-closing-bracket-location.md): Validate closing bracket location in JSX (fixable)
104104
* [jsx-curly-spacing](docs/rules/jsx-curly-spacing.md): Enforce or disallow spaces inside of curly braces in JSX attributes (fixable)
105105
* [jsx-equals-spacing](docs/rules/jsx-equals-spacing.md): Enforce or disallow spaces around equal signs in JSX attributes (fixable)
106+
* [jsx-filename-extension](docs/rules/jsx-filename-extension.md): Restrict file extensions that may contain JSX
106107
* [jsx-first-prop-new-line](docs/rules/jsx-first-prop-new-line.md): Enforce position of the first prop in JSX
107108
* [jsx-handler-names](docs/rules/jsx-handler-names.md): Enforce event handler naming conventions in JSX
108109
* [jsx-indent-props](docs/rules/jsx-indent-props.md): Validate props indentation in JSX (fixable)

docs/rules/jsx-filename-extension.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Restrict file extensions that may contain JSX (jsx-filename-extension)
2+
3+
## Rule Details
4+
5+
The following pattern is considered a warning:
6+
7+
```jsx
8+
// filename: MyComponent.js
9+
function MyComponent() {
10+
return <div />;
11+
}
12+
```
13+
14+
The following pattern is not considered a warning:
15+
16+
```jsx
17+
// filename: MyComponent.jsx
18+
function MyComponent() {
19+
return <div />;
20+
}
21+
```
22+
23+
## Rule Options
24+
25+
The set of allowed extensions is configurable. By default '.jsx' is allowed. If you wanted to allow both '.jsx' and '.js', the configuration would be:
26+
27+
```js
28+
"rules": {
29+
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
30+
}
31+
```
32+
33+
## When Not To Use It
34+
35+
If you don't care about restricting the file extensions that may contain JSX.

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ module.exports = {
4343
'no-string-refs': require('./lib/rules/no-string-refs'),
4444
'prefer-stateless-function': require('./lib/rules/prefer-stateless-function'),
4545
'require-render-return': require('./lib/rules/require-render-return'),
46-
'jsx-first-prop-new-line': require('./lib/rules/jsx-first-prop-new-line')
46+
'jsx-first-prop-new-line': require('./lib/rules/jsx-first-prop-new-line'),
47+
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension')
4748
},
4849
configs: {
4950
recommended: {

lib/rules/jsx-filename-extension.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* @fileoverview Restrict file extensions that may contain JSX
3+
* @author Joe Lencioni
4+
*/
5+
'use strict';
6+
7+
var path = require('path');
8+
9+
// ------------------------------------------------------------------------------
10+
// Constants
11+
// ------------------------------------------------------------------------------
12+
13+
var DEFAULTS = {
14+
extensions: ['.jsx']
15+
};
16+
17+
// ------------------------------------------------------------------------------
18+
// Rule Definition
19+
// ------------------------------------------------------------------------------
20+
21+
module.exports = function(context) {
22+
23+
24+
function getExtensionsConfig() {
25+
return context.options[0] && context.options[0].extensions || DEFAULTS.extensions;
26+
}
27+
28+
// --------------------------------------------------------------------------
29+
// Public
30+
// --------------------------------------------------------------------------
31+
32+
return {
33+
34+
JSXElement: function(node) {
35+
var allowedExtensions = getExtensionsConfig();
36+
var filename = context.getFilename();
37+
38+
var isAllowedExtension = allowedExtensions.some(function (extension) {
39+
return filename.slice(-extension.length) === extension;
40+
});
41+
42+
if (isAllowedExtension) {
43+
return;
44+
}
45+
46+
var extension = path.extname(filename);
47+
48+
context.report({
49+
node: node,
50+
message: 'JSX not allowed in files with extension \'' + extension + '\''
51+
});
52+
}
53+
};
54+
55+
};
56+
57+
module.exports.schema = [{
58+
type: 'object',
59+
properties: {
60+
extensions: {
61+
type: 'array',
62+
items: {
63+
type: 'string'
64+
}
65+
}
66+
},
67+
additionalProperties: false
68+
}];
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @fileoverview Restrict file extensions that may contain JSX
3+
* @author Joe Lencioni
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../../../lib/rules/jsx-filename-extension');
12+
var RuleTester = require('eslint').RuleTester;
13+
14+
var parserOptions = {
15+
ecmaVersion: 6,
16+
ecmaFeatures: {
17+
jsx: true
18+
}
19+
};
20+
21+
// ------------------------------------------------------------------------------
22+
// Code Snippets
23+
// ------------------------------------------------------------------------------
24+
25+
var withJSX = 'module.exports = function MyComponent() { return <div />; }';
26+
var withoutJSX = 'module.exports = {}';
27+
28+
// ------------------------------------------------------------------------------
29+
// Tests
30+
// ------------------------------------------------------------------------------
31+
32+
var ruleTester = new RuleTester();
33+
ruleTester.run('jsx-filename-extension', rule, {
34+
35+
valid: [
36+
{
37+
filename: 'MyComponent.jsx',
38+
code: withJSX,
39+
parserOptions: parserOptions
40+
}, {
41+
filename: 'MyComponent.js',
42+
options: [{extensions: ['.js', '.jsx']}],
43+
code: withJSX,
44+
parserOptions: parserOptions
45+
}, {
46+
filename: 'notAComponent.js',
47+
code: withoutJSX
48+
}
49+
],
50+
51+
invalid: [
52+
{
53+
filename: 'MyComponent.js',
54+
code: withJSX,
55+
parserOptions: parserOptions,
56+
errors: [{message: 'JSX not allowed in files with extension \'.js\''}]
57+
}, {
58+
filename: 'MyComponent.jsx',
59+
code: withJSX,
60+
parserOptions: parserOptions,
61+
options: [{extensions: ['.js']}],
62+
errors: [{message: 'JSX not allowed in files with extension \'.jsx\''}]
63+
}
64+
]
65+
66+
});

0 commit comments

Comments
 (0)