eslint-plugin-no-consecutive-caps
Version:
An ESLint plugin to disallow consecutive uppercase letters in identifiers, often found in acronyms.
211 lines (148 loc) • 8.48 kB
Markdown
# eslint-plugin-no-consecutive-caps
[](https://www.npmjs.com/package/eslint-plugin-no-consecutive-caps)
[](https://www.npmjs.com/package/eslint-plugin-no-consecutive-caps)
[](https://github.com/lgick/eslint-plugin-no-consecutive-caps/blob/main/LICENSE)
An ESLint plugin to enforce a stricter camelCase convention by disallowing consecutive uppercase letters in identifiers within **your own code**, while intelligently ignoring external libraries and browser APIs.
---
## ✨ Key Features
- **Strict Naming Style:** Disallows acronyms like `userID` or `APIKey` in favor of `userId` and `apiKey` for improved consistency.
- **Intelligent Detection:** Uses scope and AST analysis to determine which identifiers are declared within your codebase. **It will not trigger errors** on properties from third-party libraries or built-in browser APIs.
- **Comprehensive Fixer:** Automatically renames all occurrences of an identifier—including variables, functions, classes, and their properties (`this.myProp`)—throughout its scope with a single command.
- **Flexible Exceptions:** Allows you to specify a list of permitted acronyms if needed.
- **Flat Config Ready:** Designed for the modern `eslint.config.js` format.
## 🤔 Why is this important?
The standard ESLint `camelcase` rule allows writing acronyms in uppercase (`userID`, `fetchURL`, `myAPIKey`). This often leads to team debates and inconsistencies in the codebase.
This plugin solves the problem by proposing a single, strict style.
| Identifier | Standard `camelcase` | `no-consecutive-caps` (this plugin) |
| :---------- | :------------------: | :---------------------------------: |
| `myUserID` | ✅ Ok | ❌ Error (`myUserId`) |
| `apiURL` | ✅ Ok | ❌ Error (`apiUrl`) |
| `parseHTML` | ✅ Ok | ❌ Error (`parseHtml`) |
| `userId` | ✅ Ok | ✅ Ok |
### Key Advantage: Ignoring Third-Party Code
The biggest problem with similar rules is false positives on code you don't control. This plugin uses **ESLint's scope and AST analysis** to solve this:
```javascript
// ✅ This code will not cause errors, as the plugin understands
// that these are properties of external objects.
// Third-party library
import someLibrary from 'some-library';
console.log(someLibrary.someUglyID); // OK
// Built-in browser APIs
element.innerHTML = '...'; // OK
const range = document.createRange(); // OK
```
The plugin only checks identifiers that you declare and control: variables, functions, classes, **their properties (`this.someProp`, object keys)**, and parameters.
## 💿 Installation
You'll need [ESLint](https://eslint.org/) installed.
```bash
npm install --save-dev eslint eslint-plugin-no-consecutive-caps
```
## 🚀 Usage
This plugin is designed for use with ESLint's new "flat" config format (`eslint.config.js`).
1. Import the plugin into your `eslint.config.js`.
2. Add it to a configuration object under the `plugins` key.
3. Enable and configure the rule under the `rules` key.
**Example `eslint.config.js`:**
```javascript
import js from '@eslint/js';
import noConsecutiveCapsPlugin from 'eslint-plugin-no-consecutive-caps';
export default [
// Base recommended ESLint rules
js.configs.recommended,
// Your project's configuration
{
plugins: {
'no-consecutive-caps': noConsecutiveCapsPlugin,
},
rules: {
// It's a good idea to use the standard rule alongside this one
camelcase: 'error',
// Enable the rule from our plugin
// Format: "plugin-name/rule-name"
'no-consecutive-caps/no-consecutive-caps': 'error',
},
// Optional: apply these rules only to your source files
// files: ["src/**/*.js"],
},
];
```
## 📖 Rules
### `no-consecutive-caps/no-consecutive-caps`
Disallows using two or more consecutive uppercase letters in identifiers that you declare in your code. The autofix will rename all instances of an identifier (variables, functions, classes, and user-defined properties) within the file.
**❌ Examples of incorrect code (will trigger an error):**
```javascript
const myAPIKey = '...'; // Error: 'API'
let userID = 123; // Error: 'ID'
function getNewURL() {
// Error: 'URL'
// ...
}
class HTMLParser {
// Error: 'HTML'
constructor() {
this.parserID = 'main'; // Error: 'ID'
}
}
```
**✅ Examples of correct code:**
```javascript
const myApiKey = '...';
let userId = 123;
function getNewUrl() {
// ...
}
class HtmlParser {
constructor() {
this.parserId = 'main';
}
}
```
#### Configuring Exceptions
Sometimes you need to allow specific acronyms (e.g., due to third-party API requirements or internal conventions). You can add them to the exceptions list.
Exceptions are specified as an array of strings in the rule's options. Each string must **exactly match, case-sensitively**, the group of uppercase letters you want to allow.
**Example configuration with exceptions:**
In this example, we allow `UUID` and `MS` (milliseconds) but still disallow `API`.
```javascript
// eslint.config.js
export default [
{
rules: {
'no-consecutive-caps/no-consecutive-caps': [
'error',
{
exceptions: ['UUID', 'MS'],
},
],
},
},
];
```
**✅ Code that is now considered correct (with this configuration):**
```javascript
function generateUUID() {
// Ok: 'UUID' is in the exceptions list
// ...
}
const timeoutMS = 500; // Ok: 'MS' is in the exceptions list
```
**❌ Code that will still be considered incorrect:**
```javascript
const primaryAPIKey = '...'; // Error: 'API' was not added to the exceptions
```
## 💡 How It Works (A Look Under the Hood)
The plugin's intelligence comes from a two-phase process that leverages ESLint's built-in tools:
1. **Collection Phase:** As ESLint traverses your code, the plugin inspects every `Identifier`. It uses two strategies to identify code you control:
- **Scope Analysis:** For variables, functions, and classes, it uses ESLint's scope analysis to find their original declaration and all references.
- **AST Analysis:** For properties (`this.myProp`), object keys (`{myKey: 1}`), and class methods, it analyzes the code's structure (the AST) to identify them as user-defined.
All identifiers found to have consecutive caps are collected in lists for processing at the end, instead of being reported immediately.
2. **Reporting Phase (`Program:exit`):** After the entire file has been analyzed, the plugin processes the collected lists. For each group of identifiers (e.g., all occurrences of the variable `myAPIKey` or the property `fameIDH`), it generates a single, **comprehensive fix** to rename them all at once. This ensures that an autofix corrects an identifier everywhere, maintaining code integrity and providing a seamless developer experience in your editor.
## ❤️ Contributing
Contributions are welcome! Please feel free to open an [issue](https://github.com/lgick/eslint-plugin-no-consecutive-caps/issues) or submit a [pull request](https://github.com/lgick/eslint-plugin-no-consecutive-caps/pulls).
## 📄 License
[MIT](https://github.com/lgick/eslint-plugin-no-consecutive-caps/blob/main/LICENSE)
## ❤️ Supporting the Project
If you find this plugin useful and want to support its development, starring the project on GitHub is a great way to show your appreciation!
Donations are also welcome via Bitcoin. Every contribution helps sustain the project and is greatly appreciated.
| Currency | Address | QR Code |
| :------- | :------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
| **BTC** | `bc1q0fnakv2jean57p3rjqzhq826jklygpj6gc7evu` | <img src="https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=bc1q0fnakv2jean57p3rjqzhq826jklygpj6gc7evu" alt="BTC QR Code" width="120"> |