Skip to content

Commit

Permalink
[New] jsx-filename-extension: Add allow option
Browse files Browse the repository at this point in the history
  • Loading branch information
remcohaszing authored and ljharb committed Aug 8, 2020
1 parent 97ac0fa commit 6612375
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 27 deletions.
14 changes: 14 additions & 0 deletions docs/rules/jsx-filename-extension.md
Expand Up @@ -20,8 +20,22 @@ function MyComponent() {
}
```

Beware this rule **only** reports JSX syntax, **not** other non-standard syntax such as experimental features or type annotations.

## Rule Options

### `allow` (default: `"always"`)

When to allow a JSX filename extension. By default all files may have a JSX extension. Set this to `as-needed` to only allow JSX file extensions in files that contain JSX syntax.

```js
"rules": {
"react/jsx-filename-extension": [1, { "allow": "as-needed" }]
}
```

### `extensions` (default: `[".jsx"]`)

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:

```js
Expand Down
57 changes: 30 additions & 27 deletions lib/rules/jsx-filename-extension.js
Expand Up @@ -13,6 +13,7 @@ const docsUrl = require('../util/docsUrl');
// ------------------------------------------------------------------------------

const DEFAULTS = {
allow: 'always',
extensions: ['.jsx']
};

Expand All @@ -32,6 +33,9 @@ module.exports = {
schema: [{
type: 'object',
properties: {
allow: {
enum: ['always', 'as-needed']
},
extensions: {
type: 'array',
items: {
Expand All @@ -44,32 +48,23 @@ module.exports = {
},

create(context) {
let invalidExtension;
let invalidNode;
const filename = context.getFilename();

function getExtensionsConfig() {
return context.options[0] && context.options[0].extensions || DEFAULTS.extensions;
}
let jsxNode;

function handleJSX(node) {
const filename = context.getFilename();
if (filename === '<text>') {
return;
}

if (invalidNode) {
return;
}
if (filename === '<text>') {
// No need to traverse any nodes.
return {};
}

const allowedExtensions = getExtensionsConfig();
const isAllowedExtension = allowedExtensions.some((extension) => filename.slice(-extension.length) === extension);
const allow = (context.options[0] && context.options[0].allow) || DEFAULTS.allow;
const allowedExtensions = (context.options[0] && context.options[0].extensions) || DEFAULTS.extensions;
const isAllowedExtension = allowedExtensions.some((extension) => filename.slice(-extension.length) === extension);

if (isAllowedExtension) {
return;
function handleJSX(node) {
if (!jsxNode) {
jsxNode = node;
}

invalidNode = node;
invalidExtension = path.extname(filename);
}

// --------------------------------------------------------------------------
Expand All @@ -80,15 +75,23 @@ module.exports = {
JSXElement: handleJSX,
JSXFragment: handleJSX,

'Program:exit'() {
if (!invalidNode) {
'Program:exit'(node) {
if (jsxNode) {
if (!isAllowedExtension) {
context.report({
node: jsxNode,
message: `JSX not allowed in files with extension '${path.extname(filename)}'`
});
}
return;
}

context.report({
node: invalidNode,
message: `JSX not allowed in files with extension '${invalidExtension}'`
});
if (isAllowedExtension && allow === 'as-needed') {
context.report({
node,
message: `Only files containing JSX may use the extension '${path.extname(filename)}'`
});
}
}
};
}
Expand Down
18 changes: 18 additions & 0 deletions tests/lib/rules/jsx-filename-extension.js
Expand Up @@ -45,6 +45,14 @@ ruleTester.run('jsx-filename-extension', rule, {
{
filename: 'MyComponent.jsx',
code: withJSXElement
}, {
filename: 'MyComponent.js',
code: withoutJSX,
options: [{allow: 'as-needed'}]
}, {
filename: 'MyComponent.jsx',
code: withJSXElement,
options: [{allow: 'as-needed'}]
}, {
filename: 'MyComponent.js',
options: [{extensions: ['.js', '.jsx']}],
Expand Down Expand Up @@ -74,6 +82,16 @@ ruleTester.run('jsx-filename-extension', rule, {
filename: 'MyComponent.js',
code: withJSXElement,
errors: [{message: 'JSX not allowed in files with extension \'.js\''}]
}, {
filename: 'MyComponent.jsx',
code: withoutJSX,
options: [{allow: 'as-needed'}],
errors: [{message: 'Only files containing JSX may use the extension \'.jsx\''}]
}, {
filename: 'notAComponent.js',
code: withJSXElement,
options: [{allow: 'as-needed'}],
errors: [{message: 'JSX not allowed in files with extension \'.js\''}]
}, {
filename: 'MyComponent.jsx',
code: withJSXElement,
Expand Down

0 comments on commit 6612375

Please sign in to comment.