diff --git a/docs/rules/extensions.md b/docs/rules/extensions.md index 4fe70eea92..90353437d3 100644 --- a/docs/rules/extensions.md +++ b/docs/rules/extensions.md @@ -6,10 +6,12 @@ In order to provide a consistent use of file extensions across your code base, t ## Rule Details -This rule has one option which could be either a string or an object. If it is `"never"` (the default value) the rule forbids the use for any extension. If `"always"` then the rule enforces the use of extensions for all import statements. +This rule has one option which could be either a string, an object, or both. If it is `"never"` (the default value) the rule forbids the use for any extension. If `"always"` then the rule enforces the use of extensions for all import statements. By providing an object you can configure each extension separately, so for example `{ "js": "always", "json": "never" }` would always enforce the use of the `.js` extension but never allow the use of the `.json` extension. +By providing both a string and an object, the string will set the default setting for all extensions, and the object can be used to set granular overrides for specific extensions. For example, `[, "never", { "svg": "always" }]` would require that all extensions are omitted, except for "svg". + ### Exception When disallowing the use of certain extensions this rule makes an exception and allows the use of extension when the file would not be resolvable without extension. diff --git a/src/rules/extensions.js b/src/rules/extensions.js index f8bb86e187..3bbd68c5f1 100644 --- a/src/rules/extensions.js +++ b/src/rules/extensions.js @@ -6,13 +6,11 @@ import { isBuiltIn } from '../core/importType' module.exports = function (context) { const configuration = context.options[0] || 'never' + const defaultConfig = typeof configuration === 'string' ? configuration : null + const modifiers = typeof configuration === 'object' ? configuration : context.options[1] || {} function isUseOfExtensionEnforced(extension) { - if (typeof configuration === 'object') { - return configuration[extension] === 'always' - } - - return configuration === 'always' + return (modifiers[extension] || defaultConfig) === 'always' } function isResolvableWithoutExtension(file) { @@ -59,18 +57,31 @@ module.exports = function (context) { } } -module.exports.schema = [ - { - oneOf: [ - { - enum: [ 'always', 'never' ], - }, - { - type: 'object', - patternProperties: { - '.*': { enum: [ 'always', 'never' ] }, - }, - }, - ], - }, -] +const enumValues = { enum: [ 'always', 'never' ] } +const patternProperties = { + type: 'object', + patternProperties: { '.*': enumValues }, +} + +module.exports.schema = { + anyOf: [ + { + type: 'array', + items: [enumValues], + additionalItems: false, + }, + { + type: 'array', + items: [patternProperties], + additionalItems: false, + }, + { + type: 'array', + items: [ + enumValues, + patternProperties, + ], + additionalItems: false, + }, + ], +} diff --git a/tests/src/rules/extensions.js b/tests/src/rules/extensions.js index 74f8c1473a..486e7a7e28 100644 --- a/tests/src/rules/extensions.js +++ b/tests/src/rules/extensions.js @@ -33,6 +33,16 @@ ruleTester.run('extensions', rule, { settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json' ] } }, }), + test({ + code: [ + 'import lib from "./bar"', + 'import lib from "./bar.json"', + 'import lib from "./bar.hbs"', + ].join('\n'), + options: [ 'always', { js: 'never', jsx: 'never' } ], + settings: { 'import/resolve': { 'extensions': [ '.js', '.jsx', '.json', '.hbs' ] } }, + }), + // unresolved (#271/#295) test({ code: 'import path from "path"' }), test({ code: 'import path from "path"', options: [ 'never' ] }),