Skip to content

Commit

Permalink
import/extensions setting (#297)
Browse files Browse the repository at this point in the history
* import/extensions setting: parser whitelist. fixes #267

* default to all extensions valid to avoid breaking change until semver-next
  • Loading branch information
benmosher committed May 5, 2016
1 parent 7dac733 commit 5187508
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 4 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,9 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
- Added an `optionalDependencies` option to [`no-extraneous-dependencies`] to allow/forbid optional dependencies ([#266], thanks [@jfmengels]).
- Added `newlines-between` option to [`order`] rule ([#298], thanks [@singles])
- add [`no-mutable-exports`] rule ([#290], thanks [@josh])
- [`import/extensions` setting]: a whitelist of file extensions to parse as modules
and search for `export`s. If unspecified, all extensions are considered valid (for now).
In v2, this will likely default to `['.js', MODULE_EXT]`,. ([#297], to fix [#267])

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

[`import/cache` setting]: ./README.md#importcache
[`import/ignore` setting]: ./README.md#importignore
[`import/extensions` setting]: ./README.md#importextensions

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

[#298]: https://github.com/benmosher/eslint-plugin-import/pull/298
<<<<<<< 7775f344b90aa44c446d596e4e137d6a725bf5e8
=======
[#297]: https://github.com/benmosher/eslint-plugin-import/pull/297
>>>>>>> default to all extensions valid to avoid breaking change until semver-next
[#296]: https://github.com/benmosher/eslint-plugin-import/pull/296
[#290]: https://github.com/benmosher/eslint-plugin-import/pull/290
[#289]: https://github.com/benmosher/eslint-plugin-import/pull/289
Expand All @@ -221,6 +229,7 @@ for info on changes for earlier releases.
[#286]: https://github.com/benmosher/eslint-plugin-import/issues/286
[#281]: https://github.com/benmosher/eslint-plugin-import/issues/281
[#272]: https://github.com/benmosher/eslint-plugin-import/issues/272
[#267]: https://github.com/benmosher/eslint-plugin-import/issues/267
[#266]: https://github.com/benmosher/eslint-plugin-import/issues/266
[#216]: https://github.com/benmosher/eslint-plugin-import/issues/216
[#214]: https://github.com/benmosher/eslint-plugin-import/issues/214
Expand Down
15 changes: 15 additions & 0 deletions README.md
Expand Up @@ -148,6 +148,21 @@ If you are interesting in writing a resolver, see the [spec](./resolvers/README.

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

#### `import/extensions`

A whitelist of file extensions that will be parsed as modules and inspected for
`export`s.

This will default to `['.js']` in the next major revision of this plugin, unless
you are using the `react` shared config, in which case it is specified as `['.js', '.jsx']`.

Note that this is different from (and likely a subset of) any `import/resolver`
extensions settings, which may include `.json`, `.coffee`, etc. which will still
factor into the `no-unresolved` rule.

Also, `import/ignore` patterns will overrule this whitelist, so `node_modules` that
end in `.js` will still be ignored by default.

#### `import/ignore`

A list of regex strings that, if matched by a path, will
Expand Down
8 changes: 8 additions & 0 deletions config/react.js
@@ -0,0 +1,8 @@
/**
* - adds `.jsx` as an extension
*/
module.exports = {
settings: {
'import/extensions': ['.js', '.jsx'],
},
}
26 changes: 25 additions & 1 deletion src/core/ignore.js
@@ -1,9 +1,33 @@
import { extname } from 'path'
import Set from 'es6-set'

// one-shot memoized
let cachedSet, lastSettings
function validExtensions({ settings }) {
if (cachedSet && settings === lastSettings) {
return cachedSet
}

// todo: add 'mjs'?
lastSettings = settings
// breaking: default to '.js'
// cachedSet = new Set(settings['import/extensions'] || [ '.js' ])
cachedSet = 'import/extensions' in settings
? new Set(settings['import/extensions'])
: { has: () => true } // the set of all elements

return cachedSet
}

export default function ignore(path, context) {
// ignore node_modules by default
var ignoreStrings = context.settings['import/ignore']
const ignoreStrings = context.settings['import/ignore']
? [].concat(context.settings['import/ignore'])
: ['node_modules']

// check extension whitelist first (cheap)
if (!validExtensions(context).has(extname(path))) return true

if (ignoreStrings.length === 0) return false

for (var i = 0; i < ignoreStrings.length; i++) {
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Expand Up @@ -28,6 +28,9 @@ export const configs = {
'errors': require('../config/errors'),
'warnings': require('../config/warnings'),

// useful stuff for folks using React
'react': require('../config/react'),

// shhhh... work in progress "secret" rules
'stage-0': require('../config/stage-0'),
}
1 change: 1 addition & 0 deletions tests/files/data.json
@@ -0,0 +1 @@
{ "foo": "bar" }
4 changes: 3 additions & 1 deletion tests/src/rules/named.js
@@ -1,4 +1,4 @@
import { test } from '../utils'
import { test, SYNTAX_CASES } from '../utils'
import { RuleTester } from 'eslint'

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

...SYNTAX_CASES,
],

invalid: [
Expand Down Expand Up @@ -166,6 +167,7 @@ ruleTester.run('named', rule, {
// parse errors
test({
code: "import { a } from './test.coffee';",
settings: { 'import/extensions': ['.js', '.coffee'] },
errors: [{
message: "Parse errors in imported module './test.coffee': Unexpected token > (1:20)",
type: 'Literal',
Expand Down
3 changes: 2 additions & 1 deletion tests/src/rules/namespace.js
@@ -1,4 +1,4 @@
var test = require('../utils').test
import { test, SYNTAX_CASES } from '../utils'
import { RuleTester } from 'eslint'

var ruleTester = new RuleTester({ env: { es6: true }})
Expand Down Expand Up @@ -86,6 +86,7 @@ const valid = [
parser: 'babel-eslint',
}),

...SYNTAX_CASES,
]

const invalid = [
Expand Down
4 changes: 3 additions & 1 deletion tests/src/rules/no-named-as-default.js
@@ -1,4 +1,4 @@
import { test } from '../utils'
import { test, SYNTAX_CASES } from '../utils'
import { RuleTester } from 'eslint'

const ruleTester = new RuleTester()
Expand All @@ -16,6 +16,8 @@ ruleTester.run('no-named-as-default', rule, {
, parser: 'babel-eslint' }),
test({ code: 'export bar from "./bar";'
, parser: 'babel-eslint' }),

...SYNTAX_CASES,
],

invalid: [
Expand Down
6 changes: 6 additions & 0 deletions tests/src/utils.js
Expand Up @@ -57,4 +57,10 @@ export const SYNTAX_CASES = [
test({ code: 'export default x' }),
test({ code: 'export default class x {}' }),

// issue #267: parser whitelist
test({
code: 'import json from "./data.json"',
settings: { 'import/extensions': ['.js'] }, // breaking: remove for v2
}),

]

0 comments on commit 5187508

Please sign in to comment.