Skip to content

Commit 5187508

Browse files
committed
import/extensions setting (#297)
* import/extensions setting: parser whitelist. fixes #267 * default to all extensions valid to avoid breaking change until semver-next
1 parent 7dac733 commit 5187508

File tree

10 files changed

+75
-4
lines changed

10 files changed

+75
-4
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
99
- Added an `optionalDependencies` option to [`no-extraneous-dependencies`] to allow/forbid optional dependencies ([#266], thanks [@jfmengels]).
1010
- Added `newlines-between` option to [`order`] rule ([#298], thanks [@singles])
1111
- add [`no-mutable-exports`] rule ([#290], thanks [@josh])
12+
- [`import/extensions` setting]: a whitelist of file extensions to parse as modules
13+
and search for `export`s. If unspecified, all extensions are considered valid (for now).
14+
In v2, this will likely default to `['.js', MODULE_EXT]`,. ([#297], to fix [#267])
1215

1316
### Fixed
1417
- [`extensions`]: fallback to source path for extension enforcement if imported
@@ -180,6 +183,7 @@ for info on changes for earlier releases.
180183

181184
[`import/cache` setting]: ./README.md#importcache
182185
[`import/ignore` setting]: ./README.md#importignore
186+
[`import/extensions` setting]: ./README.md#importextensions
183187

184188
[`no-unresolved`]: ./docs/rules/no-unresolved.md
185189
[`no-deprecated`]: ./docs/rules/no-deprecated.md
@@ -198,6 +202,10 @@ for info on changes for earlier releases.
198202
[`no-mutable-exports`]: ./docs/rules/no-mutable-exports.md
199203

200204
[#298]: https://github.com/benmosher/eslint-plugin-import/pull/298
205+
<<<<<<< 7775f344b90aa44c446d596e4e137d6a725bf5e8
206+
=======
207+
[#297]: https://github.com/benmosher/eslint-plugin-import/pull/297
208+
>>>>>>> default to all extensions valid to avoid breaking change until semver-next
201209
[#296]: https://github.com/benmosher/eslint-plugin-import/pull/296
202210
[#290]: https://github.com/benmosher/eslint-plugin-import/pull/290
203211
[#289]: https://github.com/benmosher/eslint-plugin-import/pull/289
@@ -221,6 +229,7 @@ for info on changes for earlier releases.
221229
[#286]: https://github.com/benmosher/eslint-plugin-import/issues/286
222230
[#281]: https://github.com/benmosher/eslint-plugin-import/issues/281
223231
[#272]: https://github.com/benmosher/eslint-plugin-import/issues/272
232+
[#267]: https://github.com/benmosher/eslint-plugin-import/issues/267
224233
[#266]: https://github.com/benmosher/eslint-plugin-import/issues/266
225234
[#216]: https://github.com/benmosher/eslint-plugin-import/issues/216
226235
[#214]: https://github.com/benmosher/eslint-plugin-import/issues/214

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ If you are interesting in writing a resolver, see the [spec](./resolvers/README.
148148

149149
You may set the following settings in your `.eslintrc`:
150150

151+
#### `import/extensions`
152+
153+
A whitelist of file extensions that will be parsed as modules and inspected for
154+
`export`s.
155+
156+
This will default to `['.js']` in the next major revision of this plugin, unless
157+
you are using the `react` shared config, in which case it is specified as `['.js', '.jsx']`.
158+
159+
Note that this is different from (and likely a subset of) any `import/resolver`
160+
extensions settings, which may include `.json`, `.coffee`, etc. which will still
161+
factor into the `no-unresolved` rule.
162+
163+
Also, `import/ignore` patterns will overrule this whitelist, so `node_modules` that
164+
end in `.js` will still be ignored by default.
165+
151166
#### `import/ignore`
152167

153168
A list of regex strings that, if matched by a path, will

config/react.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* - adds `.jsx` as an extension
3+
*/
4+
module.exports = {
5+
settings: {
6+
'import/extensions': ['.js', '.jsx'],
7+
},
8+
}

src/core/ignore.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,33 @@
1+
import { extname } from 'path'
2+
import Set from 'es6-set'
3+
4+
// one-shot memoized
5+
let cachedSet, lastSettings
6+
function validExtensions({ settings }) {
7+
if (cachedSet && settings === lastSettings) {
8+
return cachedSet
9+
}
10+
11+
// todo: add 'mjs'?
12+
lastSettings = settings
13+
// breaking: default to '.js'
14+
// cachedSet = new Set(settings['import/extensions'] || [ '.js' ])
15+
cachedSet = 'import/extensions' in settings
16+
? new Set(settings['import/extensions'])
17+
: { has: () => true } // the set of all elements
18+
19+
return cachedSet
20+
}
21+
122
export default function ignore(path, context) {
223
// ignore node_modules by default
3-
var ignoreStrings = context.settings['import/ignore']
24+
const ignoreStrings = context.settings['import/ignore']
425
? [].concat(context.settings['import/ignore'])
526
: ['node_modules']
627

28+
// check extension whitelist first (cheap)
29+
if (!validExtensions(context).has(extname(path))) return true
30+
731
if (ignoreStrings.length === 0) return false
832

933
for (var i = 0; i < ignoreStrings.length; i++) {

src/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export const configs = {
2828
'errors': require('../config/errors'),
2929
'warnings': require('../config/warnings'),
3030

31+
// useful stuff for folks using React
32+
'react': require('../config/react'),
33+
3134
// shhhh... work in progress "secret" rules
3235
'stage-0': require('../config/stage-0'),
3336
}

tests/files/data.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "foo": "bar" }

tests/src/rules/named.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test } from '../utils'
1+
import { test, SYNTAX_CASES } from '../utils'
22
import { RuleTester } from 'eslint'
33

44
var ruleTester = new RuleTester()
@@ -96,6 +96,7 @@ ruleTester.run('named', rule, {
9696
settings: { 'import/ignore': ['common'] },
9797
}),
9898

99+
...SYNTAX_CASES,
99100
],
100101

101102
invalid: [
@@ -166,6 +167,7 @@ ruleTester.run('named', rule, {
166167
// parse errors
167168
test({
168169
code: "import { a } from './test.coffee';",
170+
settings: { 'import/extensions': ['.js', '.coffee'] },
169171
errors: [{
170172
message: "Parse errors in imported module './test.coffee': Unexpected token > (1:20)",
171173
type: 'Literal',

tests/src/rules/namespace.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var test = require('../utils').test
1+
import { test, SYNTAX_CASES } from '../utils'
22
import { RuleTester } from 'eslint'
33

44
var ruleTester = new RuleTester({ env: { es6: true }})
@@ -86,6 +86,7 @@ const valid = [
8686
parser: 'babel-eslint',
8787
}),
8888

89+
...SYNTAX_CASES,
8990
]
9091

9192
const invalid = [

tests/src/rules/no-named-as-default.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test } from '../utils'
1+
import { test, SYNTAX_CASES } from '../utils'
22
import { RuleTester } from 'eslint'
33

44
const ruleTester = new RuleTester()
@@ -16,6 +16,8 @@ ruleTester.run('no-named-as-default', rule, {
1616
, parser: 'babel-eslint' }),
1717
test({ code: 'export bar from "./bar";'
1818
, parser: 'babel-eslint' }),
19+
20+
...SYNTAX_CASES,
1921
],
2022

2123
invalid: [

tests/src/utils.js

+6
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,10 @@ export const SYNTAX_CASES = [
5757
test({ code: 'export default x' }),
5858
test({ code: 'export default class x {}' }),
5959

60+
// issue #267: parser whitelist
61+
test({
62+
code: 'import json from "./data.json"',
63+
settings: { 'import/extensions': ['.js'] }, // breaking: remove for v2
64+
}),
65+
6066
]

0 commit comments

Comments
 (0)