diff --git a/packages/eslint-plugin/docs/rules/naming-convention.md b/packages/eslint-plugin/docs/rules/naming-convention.md index 53c381c9e74f..25c3a5c12bf1 100644 --- a/packages/eslint-plugin/docs/rules/naming-convention.md +++ b/packages/eslint-plugin/docs/rules/naming-convention.md @@ -216,6 +216,9 @@ Individual Selectors match specific, well-defined sets. There is no overlap betw - `function` - matches any named function declaration or named function expression. - Allowed `modifiers`: `async`, `exported`, `global`, `unused`. - Allowed `types`: none. +- `import` - matches namespace imports and default imports (i.e. does not match named imports). + - Allowed `modifiers`: `default`, `namespace`. + - Allowed `types`: none. - `interface` - matches any interface declaration. - Allowed `modifiers`: `exported`, `unused`. - Allowed `types`: none. diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/enums.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/enums.ts index 1b26c18ecb22..b92928b86477 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/enums.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/enums.ts @@ -43,6 +43,9 @@ enum Selectors { typeAlias = 1 << 14, enum = 1 << 15, typeParameter = 1 << 17, + + // other + import = 1 << 18, } type SelectorsString = keyof typeof Selectors; @@ -107,17 +110,21 @@ enum Modifiers { override = 1 << 13, // class methods, object function properties, or functions that are async via the `async` keyword async = 1 << 14, + // default imports + default = 1 << 15, + // namespace imports + namespace = 1 << 16, // make sure TypeModifiers starts at Modifiers + 1 or else sorting won't work } type ModifiersString = keyof typeof Modifiers; enum TypeModifiers { - boolean = 1 << 15, - string = 1 << 16, - number = 1 << 17, - function = 1 << 18, - array = 1 << 19, + boolean = 1 << 17, + string = 1 << 18, + number = 1 << 19, + function = 1 << 20, + array = 1 << 21, } type TypeModifiersString = keyof typeof TypeModifiers; diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts index 2cb6d9fed62b..fdbbd5821ad2 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts @@ -310,6 +310,7 @@ const SCHEMA: JSONSchema.JSONSchema4 = { ...selectorSchema('typeAlias', false, ['exported', 'unused']), ...selectorSchema('enum', false, ['exported', 'unused']), ...selectorSchema('typeParameter', false, ['unused']), + ...selectorSchema('import', false, ['default', 'namespace']), ], }, additionalItems: false, diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index d3e52d377cf2..0a8aab5e976e 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -221,6 +221,41 @@ export default util.createRule({ ) => void; }>; } = { + // #region import + + 'ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier': { + validator: validators.import, + handler: ( + node: + | TSESTree.ImportDefaultSpecifier + | TSESTree.ImportNamespaceSpecifier + | TSESTree.ImportSpecifier, + validator, + ): void => { + const modifiers = new Set(); + + switch (node.type) { + case AST_NODE_TYPES.ImportDefaultSpecifier: + modifiers.add(Modifiers.default); + break; + case AST_NODE_TYPES.ImportNamespaceSpecifier: + modifiers.add(Modifiers.namespace); + break; + case AST_NODE_TYPES.ImportSpecifier: + // Handle `import { default as Foo }` + if (node.imported.name !== 'default') { + return; + } + modifiers.add(Modifiers.default); + break; + } + + validator(node.local, modifiers); + }, + }, + + // #endregion + // #region variable VariableDeclarator: { diff --git a/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts b/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts index 75156ebb2ce7..731fc22d9c42 100644 --- a/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts +++ b/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts @@ -932,6 +932,66 @@ ruleTester.run('naming-convention', rule, { }, ], }, + { + code: "import * as FooBar from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['PascalCase'], + }, + { + selector: ['import'], + modifiers: ['default'], + format: ['camelCase'], + }, + ], + }, + { + code: "import fooBar from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['PascalCase'], + }, + { + selector: ['import'], + modifiers: ['default'], + format: ['camelCase'], + }, + ], + }, + { + code: "import { default as fooBar } from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['PascalCase'], + }, + { + selector: ['import'], + modifiers: ['default'], + format: ['camelCase'], + }, + ], + }, + { + code: "import { foo_bar } from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['PascalCase'], + }, + { + selector: ['import'], + modifiers: ['default'], + format: ['camelCase'], + }, + ], + }, ], invalid: [ { @@ -2121,5 +2181,80 @@ ruleTester.run('naming-convention', rule, { }, ], }, + { + code: "import * as fooBar from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['camelCase'], + }, + { + selector: ['import'], + modifiers: ['namespace'], + format: ['PascalCase'], + }, + ], + errors: [ + { + messageId: 'doesNotMatchFormat', + data: { + type: 'Import', + name: 'fooBar', + formats: 'PascalCase', + }, + }, + ], + }, + { + code: "import FooBar from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['camelCase'], + }, + { + selector: ['import'], + modifiers: ['namespace'], + format: ['PascalCase'], + }, + ], + errors: [ + { + messageId: 'doesNotMatchFormat', + data: { + type: 'Import', + name: 'FooBar', + formats: 'camelCase', + }, + }, + ], + }, + { + code: "import { default as foo_bar } from 'foo_bar';", + parserOptions, + options: [ + { + selector: ['import'], + format: ['camelCase'], + }, + { + selector: ['import'], + modifiers: ['namespace'], + format: ['PascalCase'], + }, + ], + errors: [ + { + messageId: 'doesNotMatchFormat', + data: { + type: 'Import', + name: 'foo_bar', + formats: 'camelCase', + }, + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/schema-snapshots/naming-convention.shot b/packages/eslint-plugin/tests/schema-snapshots/naming-convention.shot index 1f360bc55c29..8ae5a4a339d9 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/naming-convention.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/naming-convention.shot @@ -106,9 +106,11 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "abstract", "async", "const", + "default", "destructured", "exported", "global", + "namespace", "override", "private", "protected", @@ -137,6 +139,7 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "enum", "enumMember", "function", + "import", "interface", "memberLike", "method", @@ -209,9 +212,11 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "abstract", "async", "const", + "default", "destructured", "exported", "global", + "namespace", "override", "private", "protected", @@ -1508,6 +1513,58 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos }, "required": ["selector", "format"], "type": "object" + }, + { + "additionalProperties": false, + "description": "Selector 'import'", + "properties": { + "custom": { + "$ref": "#/$defs/matchRegexConfig" + }, + "failureMessage": { + "type": "string" + }, + "filter": { + "oneOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "$ref": "#/$defs/matchRegexConfig" + } + ] + }, + "format": { + "$ref": "#/$defs/formatOptionsConfig" + }, + "leadingUnderscore": { + "$ref": "#/$defs/underscoreOptions" + }, + "modifiers": { + "additionalItems": false, + "items": { + "enum": ["default", "namespace"], + "type": "string" + }, + "type": "array" + }, + "prefix": { + "$ref": "#/$defs/prefixSuffixConfig" + }, + "selector": { + "enum": ["import"], + "type": "string" + }, + "suffix": { + "$ref": "#/$defs/prefixSuffixConfig" + }, + "trailingUnderscore": { + "$ref": "#/$defs/underscoreOptions" + } + }, + "required": ["selector", "format"], + "type": "object" } ] }, @@ -1556,9 +1613,11 @@ type Options = /** Multiple selectors in one config */ | 'abstract' | 'async' | 'const' + | 'default' | 'destructured' | 'exported' | 'global' + | 'namespace' | 'override' | 'private' | 'protected' @@ -1578,6 +1637,7 @@ type Options = /** Multiple selectors in one config */ | 'enum' | 'enumMember' | 'function' + | 'import' | 'interface' | 'memberLike' | 'method' @@ -1692,9 +1752,11 @@ type Options = /** Multiple selectors in one config */ | 'abstract' | 'async' | 'const' + | 'default' | 'destructured' | 'exported' | 'global' + | 'namespace' | 'override' | 'private' | 'protected' @@ -1748,6 +1810,19 @@ type Options = /** Multiple selectors in one config */ suffix?: PrefixSuffixConfig; trailingUnderscore?: UnderscoreOptions; } + /** Selector 'import' */ + | { + custom?: MatchRegexConfig; + failureMessage?: string; + filter?: MatchRegexConfig | string; + format: FormatOptionsConfig; + leadingUnderscore?: UnderscoreOptions; + modifiers?: ('default' | 'namespace')[]; + prefix?: PrefixSuffixConfig; + selector: 'import'; + suffix?: PrefixSuffixConfig; + trailingUnderscore?: UnderscoreOptions; + } /** Selector 'interface' */ | { custom?: MatchRegexConfig; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy