Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ updates:
schedule:
interval: 'weekly'
open-pull-requests-limit: 10
ignore:
- dependency-name: '@types/node'
update-types:
- 'version-update:semver-major'

- package-ecosystem: 'github-actions'
directory: '/'
Expand Down
10 changes: 8 additions & 2 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@
},

"rules": {
"complexity/max-cyclomatic": ["warn", { "max": 10 }],
"complexity/max-cognitive": ["warn", { "max": 15, "enableExtraction": true }],
"complexity/complexity": [
"warn",
{
"cyclomatic": 10,
"cognitive": 15,
"enableExtraction": true
}
],

"no-console": "warn",
"no-debugger": "error",
Expand Down
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Performance optimization: `minLines` option to skip complexity analysis for small functions. Default: 10 lines.

## [1.0.0-rc.1] - 2026-02-08

### Added

- **New `complexity/complexity` rule** - Optimized rule that checks both cyclomatic and cognitive complexity in a single AST walk (17% faster than separate rules)
- Export extraction analysis types and functions from public API
- Test fixtures for Svelte (`.svelte`) and Astro (`.astro`) files
- Documented framework support: React, Vue, Angular, Svelte, Astro, Solid, Qwik

### Changed

- Clean up unused parameters left over from v0.3.2 refactoring across internal APIs

### Deprecated

- `complexity/max-cyclomatic` - Use `complexity/complexity` instead
- `complexity/max-cognitive` - Use `complexity/complexity` instead

### Fixed

- Detect `this` references in extraction candidates and flag as medium-confidence issue.
- Detect mutating method calls (`push`, `sort`, `set`, `delete`, etc.) as variable mutations in extraction analysis.
- Strengthen extraction tests: replace weak/guarded assertions with exact values and rewrite inline fixtures that produced zero candidates.
- Fix `hasEarlyReturn` to use AST-based detection.
- Fix `suggestFunctionName` producing incorrect names; replaced with `"extracted"` placeholder.
- Fix exported `MaxCognitiveOptions` type missing extraction and tip-threshold options added in v0.3.0.

## [0.3.2] - 2026-02-01

Expand Down Expand Up @@ -91,7 +107,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- GitHub Actions CI pipeline
- Pre-commit hooks with Husky

[Unreleased]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v0.3.2...HEAD
[Unreleased]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v1.0.0-rc.1...HEAD
[1.0.0-rc.1]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v0.3.2...v1.0.0-rc.1
[0.3.2]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/itaymendel/oxlint-plugin-complexity/compare/v0.2.0...v0.3.0
Expand Down
10 changes: 5 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
## Development Setup

```bash
npm install
npm run build
pnpm install
pnpm run build
```

## Testing

Run the test suite:

```bash
npm test # Watch mode
npm run test:run # Single run
npm run lint # Dogfood: lint this plugin with itself
pnpm test # Watch mode
pnpm run test:run # Single run
pnpm run lint # Dogfood: lint this plugin with itself
```

### Fixture-Based Testing
Expand Down
121 changes: 78 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Cyclomatic and cognitive complexity rules for [oxlint](https://oxc.rs/docs/guide
- **Framework support:** React, Vue, Angular, Svelte, Astro, Solid, Qwik
- **File types:** `.js` `.mjs` `.cjs` `.ts` `.tsx` `.jsx` `.vue` `.svelte` `.astro`

> **Note:** Only cognitive complexity tracks nesting depth, which enables more actionable suggestions, so refactoring tips available only there.
> **Note:** Refactoring tips require cognitive complexity (only it tracks nesting depth).

## Quick Start

Expand All @@ -23,18 +23,23 @@ npm install oxlint-plugin-complexity --save-dev
{
"jsPlugins": ["oxlint-plugin-complexity"],
"rules": {
"complexity/max-cyclomatic": ["error", { "max": 20 }],
"complexity/max-cognitive": ["error", { "max": 15 }]
"complexity/complexity": [
"error",
{
"cyclomatic": 20,
"cognitive": 15
}
]
}
}
```

## Actionable Error Messages

Error messages include a summary and detailed line-by-line breakdown with the top offender highlighted. When deep nesting is detected, a refactoring tip is shown:
Error messages show a summary, line-by-line breakdown, and refactoring tips for deep nesting:

```
complexity(max-cognitive): Function 'processData' has Cognitive Complexity of 15.
complexity(complexity): Function 'processData' has Cognitive Complexity of 15.
Maximum allowed is 10. [if: +14, for: +1]

Breakdown:
Expand Down Expand Up @@ -66,58 +71,58 @@ function processData(items, mode, config) {
}
```

## Rules
## Rule Configuration

### `complexity/max-cyclomatic`
```jsonc
{
"complexity/complexity": [
"error",
{
// Complexity thresholds
"cyclomatic": 20, // Default: 20
"cognitive": 15, // Default: 15

// Performance optimization (optional)
"minLines": 10, // Default: 10 (skip functions <10 lines like getters; 0 = analyze all; counts comments/blanks)

// Extraction suggestions (optional)
"enableExtraction": true, // Default: false
"extractionMultiplier": 1.5, // Default: 1.5 (triggers at 1.5× cognitive threshold)
"minExtractionPercentage": 30, // Default: 30 (min % of total complexity to suggest)

// Refactoring tip thresholds (optional, set to 0 to disable)
"nestingTipThreshold": 3, // Default: 3
"elseIfChainThreshold": 4, // Default: 4
"logicalOperatorThreshold": 3, // Default: 3
},
],
}
```

Enforces maximum [cyclomatic complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity) (default: 20).
### Cyclomatic Complexity

Counts decision points in code. [Learn more](https://en.wikipedia.org/wiki/Cyclomatic_complexity)

**+1 for:** `if`, `for`, `for...in`, `for...of`, `while`, `do...while`, `case`, `catch`, `? :`, `&&`, `||`, `??`

### `complexity/max-cognitive`
### Cognitive Complexity

Enforces maximum [cognitive complexity](https://www.sonarsource.com/resources/cognitive-complexity/) (default: 15).
Measures how difficult code is to understand by penalizing nesting. [Learn more](https://www.sonarsource.com/resources/cognitive-complexity/)

- **+1 for:** `if`/`for`/`while`/`switch`/`catch`/`? :` (+nesting), `else`, logical sequence changes, nested functions, recursion
- **Excluded:** React components (PascalCase + returns JSX), default value patterns (`a || []`)

#### Refactoring Tips
### Refactoring Tips

The plugin detects common complexity patterns and provides actionable tips. All thresholds are configurable (set to `0` to disable):
Detects common complexity patterns and provides actionable tips:

```jsonc
{
"complexity/max-cognitive": [
"error",
{
"max": 15,
"nestingTipThreshold": 3,
"elseIfChainThreshold": 4,
"logicalOperatorThreshold": 3,
},
],
}
```
- **Deep nesting** (`nestingTipThreshold`): Suggests extracting inner loops/conditions
- **Long else-if chains** (`elseIfChainThreshold`): Recommends lookup tables or strategy pattern
- **Logical operator sequences** (`logicalOperatorThreshold`): Suggests extracting boolean expressions

#### Extraction Suggestions (Experimental)
### Extraction Suggestions

Enable `enableExtraction` to get refactoring suggestions for complex functions. Analyzes variable flow to identify extractable code blocks and potential issues.

```jsonc
{
"complexity/max-cognitive": [
"error",
{
"max": 15,
"enableExtraction": true,
// Only suggest extractions when complexity exceeds 1.5× of max-cognitive threshold
"extractionMultiplier": 1.5,
// Only suggest blocks containing at least this % of total complexity
"minExtractionPercentage": 30,
},
],
}
```
When `enableExtraction: true`, analyzes variable flow to identify extractable code blocks:

**Example output:**

Expand All @@ -143,6 +148,36 @@ Inputs: config: Config, results: number[]
Suggested: processBlock(config: Config, results: number[]): void
```

#### Known Limitations

Extraction suggestions use static analysis heuristics and may miss:

- **Globals/module variables** (not tracked by variable flow analysis)
- **Complex flows** (closures, dynamic properties, indirect mutations)

Always review suggestions before applying, even when marked "high confidence".

---

## Migration from v0.x to v1.0

**v1.0:** Combined rule for better performance. Separate rules deprecated:

```diff
// .oxlintrc.json
{
"jsPlugins": ["oxlint-plugin-complexity"],
"rules": {
- "complexity/max-cyclomatic": ["error", { "max": 20 }],
- "complexity/max-cognitive": ["error", { "max": 15 }]
+ "complexity/complexity": ["error", {
+ "cyclomatic": 20,
+ "cognitive": 15
+ }]
}
}
```

---

## Attribution
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oxlint-plugin-complexity",
"version": "0.3.2",
"version": "1.0.0-rc.2",
"description": "Cyclomatic and cognitive complexity rules for oxlint",
"keywords": [
"oxlint",
Expand Down Expand Up @@ -55,6 +55,7 @@
"oxc-parser": "^0.112.0",
"oxlint": "^1.39.0",
"prettier": "3.8.1",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"vitest": "^4.0.17"
},
Expand Down
Loading