diff --git a/packages/eslint-plugin/docs/rules/naming-convention.md b/packages/eslint-plugin/docs/rules/naming-convention.md index ec21837594f..0cd4d9324be 100644 --- a/packages/eslint-plugin/docs/rules/naming-convention.md +++ b/packages/eslint-plugin/docs/rules/naming-convention.md @@ -192,7 +192,7 @@ There are two types of selectors, individual selectors, and grouped selectors. Individual Selectors match specific, well-defined sets. There is no overlap between each of the individual selectors. - `variable` - matches any `var` / `let` / `const` variable name. - - Allowed `modifiers`: none. + - Allowed `modifiers`: `const`. - Allowed `types`: `boolean`, `string`, `number`, `function`, `array`. - `function` - matches any named function declaration or named function expression. - Allowed `modifiers`: none. @@ -309,6 +309,21 @@ Group Selectors are provided for convenience, and essentially bundle up sets of } ``` +### Enforce that all const variables are in UPPER_CASE + +```json +{ + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variable", + "modifiers": ["const"], + "format": ["UPPER_CASE"] + } + ] +} +``` + ### Enforce that type parameters (generics) are prefixed with `T` This allows you to emulate the old `generic-type-naming` rule. diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index f28454916ad..fdf1f061788 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -80,12 +80,13 @@ type MetaSelectorsString = keyof typeof MetaSelectors; type IndividualAndMetaSelectorsString = SelectorsString | MetaSelectorsString; enum Modifiers { - readonly = 1 << 0, - static = 1 << 1, - public = 1 << 2, - protected = 1 << 3, - private = 1 << 4, - abstract = 1 << 5, + const = 1 << 0, + readonly = 1 << 1, + static = 1 << 2, + public = 1 << 3, + protected = 1 << 4, + private = 1 << 5, + abstract = 1 << 6, } type ModifiersString = keyof typeof Modifiers; @@ -255,7 +256,7 @@ const SCHEMA: JSONSchema.JSONSchema4 = { ...selectorSchema('default', false, util.getEnumNames(Modifiers)), ...selectorSchema('variableLike', false), - ...selectorSchema('variable', true), + ...selectorSchema('variable', true, ['const']), ...selectorSchema('function', false), ...selectorSchema('parameter', true), @@ -439,8 +440,18 @@ export default util.createRule({ const identifiers: TSESTree.Identifier[] = []; getIdentifiersFromPattern(node.id, identifiers); + const modifiers = new Set(); + const parent = node.parent; + if ( + parent && + parent.type === AST_NODE_TYPES.VariableDeclaration && + parent.kind === 'const' + ) { + modifiers.add(Modifiers.const); + } + identifiers.forEach(i => { - validator(i); + validator(i, modifiers); }); }, diff --git a/packages/eslint-plugin/tests/rules/naming-convention.test.ts b/packages/eslint-plugin/tests/rules/naming-convention.test.ts index 206979dcb5a..84e48af1a58 100644 --- a/packages/eslint-plugin/tests/rules/naming-convention.test.ts +++ b/packages/eslint-plugin/tests/rules/naming-convention.test.ts @@ -626,6 +626,10 @@ ruleTester.run('naming-convention', rule, { }, { code: ` + declare const ANY_UPPER_CASE: any; + declare const ANY_UPPER_CASE: any | null; + declare const ANY_UPPER_CASE: any | null | undefined; + declare const string_camelCase: string; declare const string_camelCase: string | null; declare const string_camelCase: string | null | undefined; @@ -647,6 +651,12 @@ ruleTester.run('naming-convention', rule, { `, parserOptions, options: [ + { + selector: 'variable', + modifiers: ['const'], + format: ['UPPER_CASE'], + prefix: ['ANY_'], + }, { selector: 'variable', types: ['string'], @@ -824,6 +834,10 @@ ruleTester.run('naming-convention', rule, { }, { code: ` + declare const any_camelCase01: any; + declare const any_camelCase02: any | null; + declare const any_camelCase03: any | null | undefined; + declare const string_camelCase01: string; declare const string_camelCase02: string | null; declare const string_camelCase03: string | null | undefined; @@ -844,6 +858,12 @@ ruleTester.run('naming-convention', rule, { declare const boolean_camelCase16: true | false | null | undefined; `, options: [ + { + selector: 'variable', + modifiers: ['const'], + format: ['UPPER_CASE'], + prefix: ['any_'], + }, { selector: 'variable', types: ['string'], @@ -864,7 +884,7 @@ ruleTester.run('naming-convention', rule, { }, ], parserOptions, - errors: Array(16).fill({ messageId: 'doesNotMatchFormatTrimmed' }), + errors: Array(19).fill({ messageId: 'doesNotMatchFormatTrimmed' }), }, { code: `