Skip to content

Commit fd35cbf

Browse files
lencioniyannickcr
authored andcommitted
Add jsx-filename-extension rule (fixes jsx-eslint#495)
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.
1 parent 8cbbe4d commit fd35cbf

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](docs/rules/jsx-indent.md): Validate JSX indentation

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
@@ -44,7 +44,8 @@ module.exports = {
4444
'prefer-stateless-function': require('./lib/rules/prefer-stateless-function'),
4545
'require-render-return': require('./lib/rules/require-render-return'),
4646
'jsx-first-prop-new-line': require('./lib/rules/jsx-first-prop-new-line'),
47-
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank')
47+
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
48+
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension')
4849
},
4950
configs: {
5051
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)