eslint-plugin-maintainability 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -58
- package/package.json +2 -2
- package/src/index.js +1 -1
- package/src/rules/error-handling/no-missing-error-context.js +1 -1
- package/src/rules/error-handling/no-unhandled-promise.js +1 -1
- package/src/rules/maintainability/consistent-function-scoping.js +1 -1
- package/src/rules/maintainability/max-parameters.js +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability" target="blank"><img src="https://eslint.interlace.tools/logos/interlace.svg" alt="Interlace" height="90" /></a>
|
|
2
|
+
<a href="https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability" target="blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://eslint.interlace.tools/logos/interlace-dark.svg"><img src="https://eslint.interlace.tools/logos/interlace-light.svg" alt="Interlace" height="90" /></picture></a>
|
|
3
3
|
|
|
4
|
-
<a href="https://oxc.rs" target="_blank"><img src="https://eslint.interlace.tools/logos/oxlint.svg" alt="oxlint" height="90" /></a>
|
|
4
|
+
<a href="https://oxc.rs" target="_blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://eslint.interlace.tools/logos/oxlint-dark.svg"><img src="https://eslint.interlace.tools/logos/oxlint-light.svg" alt="oxlint" height="90" /></picture></a>
|
|
5
5
|
|
|
6
|
-
<a href="https://eslint.org" target="_blank"><img src="https://eslint.interlace.tools/logos/eslint.svg" alt="ESLint" height="90" /></a>
|
|
6
|
+
<a href="https://eslint.org" target="_blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://eslint.interlace.tools/logos/eslint-dark.svg"><img src="https://eslint.interlace.tools/logos/eslint-light.svg" alt="ESLint" height="90" /></picture></a>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
@@ -25,57 +25,25 @@
|
|
|
25
25
|
|
|
26
26
|
This plugin provides Maintainability rules — complexity ceilings, dead code, and readability guardrails.
|
|
27
27
|
|
|
28
|
-
## Philosophy
|
|
29
|
-
|
|
30
|
-
**Interlace** fosters **strength through integration**. Instead of stacking isolated rules, we **interlace** security directly into your workflow to create a resilient fabric of code. We believe tools should **guide rather than gatekeep**, providing educational feedback that strengthens the developer with every interaction.
|
|
31
|
-
|
|
32
28
|
<!-- AUTO-GENERATED:DOCTRINE:START - Do not edit manually -->
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
That is a trade, and it is made deliberately. It costs recall, and we measure what it
|
|
42
|
-
costs rather than assuming it is free.
|
|
43
|
-
|
|
44
|
-
## How the rules decide
|
|
45
|
-
|
|
46
|
-
**Evidence, not names.** A rule fires on what the code *does*, resolved through the
|
|
47
|
-
AST and ESLint's own scope analysis — not on an identifier that happens to contain
|
|
48
|
-
`query`, a method called `setItem`, or a file whose path contains `key`. Every one of
|
|
49
|
-
those was a real false positive in this ecosystem, found by reading our own output on
|
|
50
|
-
open-source projects and fixed with a test that fails on the unfixed rule.
|
|
51
|
-
|
|
52
|
-
Where a rule has known false-positive shapes, its page carries a **Not a finding**
|
|
53
|
-
section: what it deliberately stays quiet on, and what to check first when it fires
|
|
54
|
-
and you disagree.
|
|
55
|
-
|
|
56
|
-
## What you get
|
|
30
|
+
- **Why** — a linter nobody reads protects nothing. We would rather miss a finding
|
|
31
|
+
than spend your attention on one that was never real.
|
|
32
|
+
- **How** — evidence, not names. A rule fires on what the code *does*, resolved
|
|
33
|
+
through the AST and ESLint's own scope analysis.
|
|
34
|
+
- **What** — every finding carries its fix, in prose for a human and as structured
|
|
35
|
+
JSON for an agent. Security rules add a CWE mapping and, where assigned, a CVSS score.
|
|
57
36
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
[open an issue](https://github.com/ofri-peretz/eslint/issues) — a false positive is a
|
|
63
|
-
bug here, not a tuning exercise for you.
|
|
64
|
-
|
|
65
|
-
How that is measured, on which projects, and where it falls short:
|
|
66
|
-
[benchmark methodology](https://github.com/ofri-peretz/eslint/blob/main/BENCHMARK-METHODOLOGY.md)
|
|
67
|
-
and [results](https://github.com/ofri-peretz/eslint/blob/main/BENCHMARK-RESULTS.md).
|
|
37
|
+
That trade costs recall, and we measure it:
|
|
38
|
+
[methodology](https://github.com/ofri-peretz/eslint/blob/main/BENCHMARK-METHODOLOGY.md)
|
|
39
|
+
· [results](https://github.com/ofri-peretz/eslint/blob/main/BENCHMARK-RESULTS.md)
|
|
40
|
+
· [a false positive is a bug](https://github.com/ofri-peretz/eslint/issues).
|
|
68
41
|
|
|
69
42
|
<!-- AUTO-GENERATED:DOCTRINE:END -->
|
|
70
43
|
|
|
71
44
|
## Getting Started
|
|
72
45
|
|
|
73
46
|
- To check out the [guide](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability), visit [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability). 📚
|
|
74
|
-
- 要查看中文 [指南](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability), 请访问 [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability). 📚
|
|
75
|
-
- [가이드](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability) 문서는 [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability)에서 확인하실 수 있습니다. 📚
|
|
76
|
-
- [ガイド](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability)は [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability)でご確認ください。 📚
|
|
77
|
-
- Para ver la [guía](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability), visita [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability). 📚
|
|
78
|
-
- للاطلاع على [الدليل](https://eslint.interlace.tools/docs/quality/plugin-maintainability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability)، قم بزيارة [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability). 📚
|
|
79
47
|
|
|
80
48
|
```bash
|
|
81
49
|
npm install eslint-plugin-maintainability --save-dev
|
|
@@ -125,23 +93,52 @@ See the [ESLint Version Support Policy](../../docs/ESLINT_VERSION_SUPPORT.md)
|
|
|
125
93
|
| [no-unhandled-promise](https://eslint.interlace.tools/docs/quality/plugin-maintainability/rules/no-unhandled-promise?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability) | CWE-1024 | | | Disallow unhandled Promise rejections with LLM-optimized suggestions for proper async error handling | 🟢 | | | | 💡 | |
|
|
126
94
|
| [no-unreadable-iife](https://eslint.interlace.tools/docs/quality/plugin-maintainability/rules/no-unreadable-iife?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability) | | | | Disallow unreadable IIFE (Immediately Invoked Function Expression) patterns | 🟢 | | | | 💡 | |
|
|
127
95
|
<!-- AUTO-GENERATED:RULES_TABLE:END -->
|
|
96
|
+
<!-- AUTO-GENERATED:ECOSYSTEM_TABLE:START - Do not edit manually -->
|
|
97
|
+
|
|
128
98
|
## 🔗 Related ESLint Plugins
|
|
129
99
|
|
|
130
|
-
Part of the **Interlace ESLint
|
|
100
|
+
Part of the **Interlace ESLint ecosystem** — AI-native rules with LLM-optimized error messages:
|
|
101
|
+
|
|
102
|
+
**Security**
|
|
131
103
|
|
|
132
104
|
| Plugin | Downloads | Description |
|
|
133
105
|
| :--- | :---: | :--- |
|
|
134
|
-
| [`eslint-plugin-
|
|
135
|
-
| [`eslint-plugin-
|
|
136
|
-
| [`eslint-plugin-
|
|
137
|
-
| [`eslint-plugin-
|
|
138
|
-
| [`eslint-plugin-
|
|
139
|
-
| [`eslint-plugin-
|
|
140
|
-
| [`eslint-plugin-
|
|
141
|
-
| [`eslint-plugin-
|
|
142
|
-
| [`eslint-plugin-
|
|
143
|
-
| [`eslint-plugin-
|
|
144
|
-
| [`eslint-plugin-
|
|
106
|
+
| [`eslint-plugin-anthropic-security`](https://www.npmjs.com/package/eslint-plugin-anthropic-security) | [](https://www.npmjs.com/package/eslint-plugin-anthropic-security) | Anthropic SDK security. |
|
|
107
|
+
| [`eslint-plugin-browser-security`](https://www.npmjs.com/package/eslint-plugin-browser-security) | [](https://www.npmjs.com/package/eslint-plugin-browser-security) | XSS, DOM security. |
|
|
108
|
+
| [`eslint-plugin-drizzle-security`](https://www.npmjs.com/package/eslint-plugin-drizzle-security) | [](https://www.npmjs.com/package/eslint-plugin-drizzle-security) | Drizzle security. |
|
|
109
|
+
| [`eslint-plugin-express-security`](https://www.npmjs.com/package/eslint-plugin-express-security) | [](https://www.npmjs.com/package/eslint-plugin-express-security) | Express middleware hardening. |
|
|
110
|
+
| [`eslint-plugin-gemini-security`](https://www.npmjs.com/package/eslint-plugin-gemini-security) | [](https://www.npmjs.com/package/eslint-plugin-gemini-security) | Google Gemini SDK security. |
|
|
111
|
+
| [`eslint-plugin-jwt-security`](https://www.npmjs.com/package/eslint-plugin-jwt-security) | [](https://www.npmjs.com/package/eslint-plugin-jwt-security) | Token security. |
|
|
112
|
+
| [`eslint-plugin-knex-security`](https://www.npmjs.com/package/eslint-plugin-knex-security) | [](https://www.npmjs.com/package/eslint-plugin-knex-security) | Knex security. |
|
|
113
|
+
| [`eslint-plugin-lambda-security`](https://www.npmjs.com/package/eslint-plugin-lambda-security) | [](https://www.npmjs.com/package/eslint-plugin-lambda-security) | AWS Lambda hardening. |
|
|
114
|
+
| [`eslint-plugin-mcp-sdk-security`](https://www.npmjs.com/package/eslint-plugin-mcp-sdk-security) | [](https://www.npmjs.com/package/eslint-plugin-mcp-sdk-security) | MCP SDK security. |
|
|
115
|
+
| [`eslint-plugin-mongodb-security`](https://www.npmjs.com/package/eslint-plugin-mongodb-security) | [](https://www.npmjs.com/package/eslint-plugin-mongodb-security) | MongoDB injection. |
|
|
116
|
+
| [`eslint-plugin-mysql-security`](https://www.npmjs.com/package/eslint-plugin-mysql-security) | [](https://www.npmjs.com/package/eslint-plugin-mysql-security) | MySQL security. |
|
|
117
|
+
| [`eslint-plugin-nestjs-security`](https://www.npmjs.com/package/eslint-plugin-nestjs-security) | [](https://www.npmjs.com/package/eslint-plugin-nestjs-security) | NestJS framework hardening. |
|
|
118
|
+
| [`eslint-plugin-node-security`](https://www.npmjs.com/package/eslint-plugin-node-security) | [](https://www.npmjs.com/package/eslint-plugin-node-security) | Server-side patterns. |
|
|
119
|
+
| [`eslint-plugin-openai-security`](https://www.npmjs.com/package/eslint-plugin-openai-security) | [](https://www.npmjs.com/package/eslint-plugin-openai-security) | OpenAI SDK security. |
|
|
120
|
+
| [`eslint-plugin-postgresql-security`](https://www.npmjs.com/package/eslint-plugin-postgresql-security) | [](https://www.npmjs.com/package/eslint-plugin-postgresql-security) | PostgreSQL security. |
|
|
121
|
+
| [`eslint-plugin-prisma-security`](https://www.npmjs.com/package/eslint-plugin-prisma-security) | [](https://www.npmjs.com/package/eslint-plugin-prisma-security) | Prisma security. |
|
|
122
|
+
| [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-plugin-secure-coding) | [](https://www.npmjs.com/package/eslint-plugin-secure-coding) | Injection prevention. |
|
|
123
|
+
| [`eslint-plugin-sequelize-security`](https://www.npmjs.com/package/eslint-plugin-sequelize-security) | [](https://www.npmjs.com/package/eslint-plugin-sequelize-security) | Sequelize ORM security. |
|
|
124
|
+
| [`eslint-plugin-sqlite-security`](https://www.npmjs.com/package/eslint-plugin-sqlite-security) | [](https://www.npmjs.com/package/eslint-plugin-sqlite-security) | SQLite security. |
|
|
125
|
+
| [`eslint-plugin-typeorm-security`](https://www.npmjs.com/package/eslint-plugin-typeorm-security) | [](https://www.npmjs.com/package/eslint-plugin-typeorm-security) | TypeORM security. |
|
|
126
|
+
| [`eslint-plugin-vercel-ai-security`](https://www.npmjs.com/package/eslint-plugin-vercel-ai-security) | [](https://www.npmjs.com/package/eslint-plugin-vercel-ai-security) | AI SDK security. |
|
|
127
|
+
|
|
128
|
+
**Code quality**
|
|
129
|
+
|
|
130
|
+
| Plugin | Downloads | Description |
|
|
131
|
+
| :--- | :---: | :--- |
|
|
132
|
+
| [`eslint-plugin-conventions`](https://www.npmjs.com/package/eslint-plugin-conventions) | [](https://www.npmjs.com/package/eslint-plugin-conventions) | Team-specific habits and styles. |
|
|
133
|
+
| [`eslint-plugin-import-next`](https://www.npmjs.com/package/eslint-plugin-import-next) | [](https://www.npmjs.com/package/eslint-plugin-import-next) | Fast cycle + import-graph analysis. |
|
|
134
|
+
| [`eslint-plugin-modernization`](https://www.npmjs.com/package/eslint-plugin-modernization) | [](https://www.npmjs.com/package/eslint-plugin-modernization) | ESNext migration + syntax evolution. |
|
|
135
|
+
| [`eslint-plugin-modularity`](https://www.npmjs.com/package/eslint-plugin-modularity) | [](https://www.npmjs.com/package/eslint-plugin-modularity) | Structural integrity and DDD patterns. |
|
|
136
|
+
| [`eslint-plugin-operability`](https://www.npmjs.com/package/eslint-plugin-operability) | [](https://www.npmjs.com/package/eslint-plugin-operability) | Production readiness and resource health. |
|
|
137
|
+
| [`eslint-plugin-react-a11y`](https://www.npmjs.com/package/eslint-plugin-react-a11y) | [](https://www.npmjs.com/package/eslint-plugin-react-a11y) | React accessibility / WCAG. |
|
|
138
|
+
| [`eslint-plugin-react-features`](https://www.npmjs.com/package/eslint-plugin-react-features) | [](https://www.npmjs.com/package/eslint-plugin-react-features) | React best practices and optimization. |
|
|
139
|
+
| [`eslint-plugin-reliability`](https://www.npmjs.com/package/eslint-plugin-reliability) | [](https://www.npmjs.com/package/eslint-plugin-reliability) | Runtime stability and error safety. |
|
|
140
|
+
|
|
141
|
+
<!-- AUTO-GENERATED:ECOSYSTEM_TABLE:END -->
|
|
145
142
|
|
|
146
143
|
<!-- INTERLACE:STAR_CTA:START -->
|
|
147
144
|
## ⭐ Support & follow
|
|
@@ -161,5 +158,5 @@ MIT © [Ofri Peretz](https://github.com/ofri-peretz)
|
|
|
161
158
|
</p>
|
|
162
159
|
|
|
163
160
|
<p align="center">
|
|
164
|
-
<a href="https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability" target="blank"><img src="https://eslint.interlace.tools/
|
|
161
|
+
<a href="https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-maintainability" target="blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://eslint.interlace.tools/logos/interlace-dark.svg"><img src="https://eslint.interlace.tools/logos/interlace-light.svg" alt="Interlace" height="70" /></picture></a>
|
|
165
162
|
</p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-maintainability",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "ESLint plugin for maintainable code — limits cognitive complexity, nesting depth, parameter counts, duplicate functions, and unhandled or silent errors.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@interlace/eslint-devkit": "^1.
|
|
66
|
+
"@interlace/eslint-devkit": "^1.18.0"
|
|
67
67
|
},
|
|
68
68
|
"repository": {
|
|
69
69
|
"type": "git",
|
package/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.rules={get"cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"maintainability/cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"maintainability/nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"maintainability/identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"maintainability/max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"maintainability/no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"maintainability/no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"maintainability/consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"maintainability/no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"maintainability/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"maintainability/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"maintainability/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"maintainability/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-maintainability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-maintainability",version:"3.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.rules={get"cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"maintainability/cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"maintainability/nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"maintainability/identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"maintainability/max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"maintainability/no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"maintainability/no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"maintainability/consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"maintainability/no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"maintainability/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"maintainability/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"maintainability/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"maintainability/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-maintainability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-maintainability",version:"3.2.0"},rules:exports.rules};exports.configs={recommended:{plugins:{"maintainability":exports.plugin},rules:{"maintainability/cognitive-complexity":"warn","maintainability/identical-functions":"warn","maintainability/max-parameters":"warn"}}};exports.default=exports.plugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingErrorContext=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function hasErrorMessage(node){if(!node.argument){return false}if(node.argument.type==="NewExpression"&&node.argument.callee.type==="Identifier"&&(node.argument.callee.name==="Error"||node.argument.callee.name.endsWith("Error"))){if(node.argument.arguments.length>0){const firstArg=node.argument.arguments[0];
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingErrorContext=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function hasErrorMessage(node){if(!node.argument){return false}if(node.argument.type==="NewExpression"&&node.argument.callee.type==="Identifier"&&(node.argument.callee.name==="Error"||node.argument.callee.name.endsWith("Error"))){if(node.argument.arguments.length>0){const firstArg=node.argument.arguments[0];const staticText=(0,eslint_devkit_1.staticString)(firstArg);if(staticText!==null){return staticText.length>0}if(firstArg.type==="TemplateLiteral"){return true}}}if(node.argument.type==="Literal"&&typeof node.argument.value==="string"){return node.argument.value.length>0}if(node.argument.type==="TemplateLiteral"){return true}return false}function hasErrorStack(node){if(!node.argument){return false}if(node.argument.type==="NewExpression"&&node.argument.callee.type==="Identifier"){const calleeName=node.argument.callee.name;if(calleeName==="Error"||calleeName.endsWith("Error")){return true}}return false}exports.noMissingErrorContext=(0,eslint_devkit_2.createRule)({name:"no-missing-error-context",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/no-missing-error-context.md",description:"Detects thrown errors without context"},hasSuggestions:true,messages:{missingErrorContext:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Missing error context",description:"Thrown error missing {{missing}}",severity:"MEDIUM",fix:"Add error message and use Error class for stack trace",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1128/"}),addErrorMessage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Message",description:"Add descriptive error message",severity:"LOW",fix:'throw new Error("descriptive message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),addErrorStack:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Error Class",description:"Use Error class for stack trace",severity:"LOW",fix:"throw new Error(message) instead of throw message",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),useErrorClass:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Specific Error",description:"Use specific error class",severity:"LOW",fix:'throw new TypeError("message") or throw new RangeError("message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError"})},schema:[{type:"object",properties:{requireMessage:{type:"boolean",default:true,description:"Require error message"},requireStackTrace:{type:"boolean",default:false,description:"Require stack trace"},ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"}},additionalProperties:false}]},defaultOptions:[{requireMessage:true,requireStackTrace:false,ignoreInTests:true}],create(context,[options={}]){const{requireMessage=true,requireStackTrace=false,ignoreInTests=true}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}function checkThrowStatement(node){const missing=[];if(requireMessage&&!hasErrorMessage(node)){missing.push("message")}if(requireStackTrace&&!hasErrorStack(node)){missing.push("stack trace")}if(missing.length===0){return}context.report({node,messageId:"missingErrorContext",data:{missing:missing.join(" and ")},suggest:[{messageId:"addErrorMessage",fix:()=>null},{messageId:"addErrorStack",fix:()=>null},{messageId:"useErrorClass",fix:()=>null}]})}return{ThrowStatement:checkThrowStatement}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnhandledPromise=void 0;exports.isPromiseExpression=isPromiseExpression;exports.isInsidePromiseCallback=isInsidePromiseCallback;exports.isPromiseHandled=isPromiseHandled;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isPromiseExpression(node){if(node.type==="CallExpression"){return true}if(node.type==="AwaitExpression"){return false}return false}function isInsidePromiseCallback(node){let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(!parent)break;if(parent.type==="ArrowFunctionExpression"||parent.type==="FunctionExpression"){const funcParent=parent.parent;if(funcParent&&funcParent.type==="CallExpression"&&funcParent.callee&&funcParent.callee.type==="MemberExpression"){const memberExpr=funcParent.callee;if(memberExpr.property.type==="Identifier"){const methodName=memberExpr.property.name;if(methodName==="then"||methodName==="catch"||methodName==="finally"){return true}}}}current=parent;depth++}return false}function isPromiseHandled(node){if(node.type==="Identifier"){const parent=node.parent;if(parent&&parent.type==="MemberExpression"&&parent.object===node){if(parent.property.type==="Identifier"){const methodName=parent.property.name;if(methodName==="catch"||methodName==="then"||methodName==="finally"){const memberParent=parent.parent;if(memberParent&&memberParent.type==="CallExpression"&&memberParent.callee===parent){return true}}}}}let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(!parent)break;if(parent.type==="MemberExpression"&&parent.object===current){if(parent.property.type==="Identifier"){const methodName=parent.property.name;if(methodName==="catch"||methodName==="then"||methodName==="finally"){const memberParent=parent.parent;if(memberParent&&memberParent.type==="CallExpression"&&memberParent.callee===parent){return true}}}}if(parent.type==="TryStatement"){return true}if(parent.type==="AwaitExpression"){return true}current=parent;depth++}return false}exports.noUnhandledPromise=(0,eslint_devkit_2.createRule)({name:"no-unhandled-promise",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/no-unhandled-promise.md",description:"Detects unhandled Promise rejections",cwe:"CWE-1024",cvss:7.5},hasSuggestions:true,messages:{unhandledPromise:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Unhandled promise",cwe:"CWE-1024",description:"Unhandled Promise rejection detected",severity:"HIGH",fix:"Add .catch() handler or use try/catch with await",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-4635/"}),addCatch:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add catch handler",description:"Add .catch() handler to promise",severity:"LOW",fix:"promise.catch(error => console.error(error))",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch"}),useTryCatch:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use try/catch",description:"Use try/catch with await",severity:"LOW",fix:"try { await promise; } catch (error) { handle(error); }",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"}),useAwait:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use await",description:"Use await to handle promise",severity:"LOW",fix:"await promise;",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore promises in test files"},ignoreVoidExpressions:{type:"boolean",default:false,description:"Ignore promises in void expressions"}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,ignoreVoidExpressions:false}],create(context,[options={}]){const{ignoreInTests=true,ignoreVoidExpressions=false}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}function checkCallExpression(node){if(isInsidePromiseCallback(node)){return}if(node.callee.type==="MemberExpression"&&node.callee.property.type==="Identifier"){const methodName=node.callee.property.name;if(methodName==="
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnhandledPromise=void 0;exports.isPromiseExpression=isPromiseExpression;exports.hasPromiseEvidence=hasPromiseEvidence;exports.isInsidePromiseCallback=isInsidePromiseCallback;exports.isPromiseHandled=isPromiseHandled;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isPromiseExpression(node){if(node.type==="CallExpression"){return true}if(node.type==="AwaitExpression"){return false}return false}const PROMISE_STATICS=new Set(["all","allSettled","any","race","resolve","reject"]);function isAsyncFunctionNode(node){if(!node)return false;return(node.type==="FunctionDeclaration"||node.type==="FunctionExpression"||node.type==="ArrowFunctionExpression")&&node.async===true}function hasPromiseEvidence(node,promiseReturning,resolveBinding){if(isAsyncFunctionNode(node.callee))return true;if(node.callee.type==="MemberExpression"){const{object,property}=node.callee;if(object.type==="Identifier"&&object.name==="Promise"&&property.type==="Identifier"&&PROMISE_STATICS.has(property.name)){return true}const propertyName=property.type==="Identifier"?property.name:(0,eslint_devkit_1.staticString)(property)!==null?(0,eslint_devkit_1.staticString)(property):null;if(propertyName==="then")return true;return object.type==="Identifier"&&promiseReturning.has(object.name)}if(node.callee.type==="Identifier"){if(promiseReturning.has(node.callee.name))return true;return isAsyncFunctionNode(resolveBinding(node.callee.name))}return false}function isInsidePromiseCallback(node){let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(!parent)break;if(parent.type==="ArrowFunctionExpression"||parent.type==="FunctionExpression"){const funcParent=parent.parent;if(funcParent&&funcParent.type==="CallExpression"&&funcParent.callee&&funcParent.callee.type==="MemberExpression"){const memberExpr=funcParent.callee;if(memberExpr.property.type==="Identifier"){const methodName=memberExpr.property.name;if(methodName==="then"||methodName==="catch"||methodName==="finally"){return true}}}}current=parent;depth++}return false}function isPromiseHandled(node){if(node.type==="Identifier"){const parent=node.parent;if(parent&&parent.type==="MemberExpression"&&parent.object===node){if(parent.property.type==="Identifier"){const methodName=parent.property.name;if(methodName==="catch"||methodName==="then"||methodName==="finally"){const memberParent=parent.parent;if(memberParent&&memberParent.type==="CallExpression"&&memberParent.callee===parent){return true}}}}}let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(!parent)break;if(parent.type==="MemberExpression"&&parent.object===current){if(parent.property.type==="Identifier"){const methodName=parent.property.name;if(methodName==="catch"||methodName==="then"||methodName==="finally"){const memberParent=parent.parent;if(memberParent&&memberParent.type==="CallExpression"&&memberParent.callee===parent){return true}}}}if(parent.type==="TryStatement"){return true}if(parent.type==="AwaitExpression"){return true}current=parent;depth++}return false}exports.noUnhandledPromise=(0,eslint_devkit_2.createRule)({name:"no-unhandled-promise",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/no-unhandled-promise.md",description:"Detects unhandled Promise rejections",cwe:"CWE-1024",cvss:7.5},hasSuggestions:true,messages:{unhandledPromise:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Unhandled promise",cwe:"CWE-1024",description:"Unhandled Promise rejection detected",severity:"HIGH",fix:"Add .catch() handler or use try/catch with await",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-4635/"}),addCatch:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add catch handler",description:"Add .catch() handler to promise",severity:"LOW",fix:"promise.catch(error => console.error(error))",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch"}),useTryCatch:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use try/catch",description:"Use try/catch with await",severity:"LOW",fix:"try { await promise; } catch (error) { handle(error); }",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch"}),useAwait:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use await",description:"Use await to handle promise",severity:"LOW",fix:"await promise;",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore promises in test files"},ignoreVoidExpressions:{type:"boolean",default:false,description:"Ignore promises in void expressions"},requirePromiseEvidence:{type:"boolean",default:true,description:"Report only calls the file itself shows to be promise-producing. False restores the pre-2026-08 behaviour of treating every call as a promise."},promiseReturning:{type:"array",items:{type:"string"},default:["fetch"],description:"Names that return a promise and cannot be resolved from the file \u2014 platform APIs and project conventions."}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,ignoreVoidExpressions:false,requirePromiseEvidence:true,promiseReturning:["fetch"]}],create(context,[options={}]){const{ignoreInTests=true,ignoreVoidExpressions=false,requirePromiseEvidence=true,promiseReturning=["fetch"]}=options||{};const promiseNames=new Set(promiseReturning);function resolveBinding(name,from){let scope=context.sourceCode.getScope(from);while(scope){const variable=scope.variables.find(v=>v.name===name);if(variable){const def=variable.defs[0];if(!def)return null;if(def.node.type==="FunctionDeclaration")return def.node;if(def.node.type==="VariableDeclarator"){return def.node.init??null}return null}scope=scope.upper}return null}const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}function checkCallExpression(node){if(isInsidePromiseCallback(node)){return}if(node.callee.type==="MemberExpression"&&node.callee.property.type==="Identifier"){const methodName=node.callee.property.name;if(methodName==="catch"||methodName==="finally"){if(node.arguments.length>0&&node.arguments[0].type==="ArrowFunctionExpression"){const callback=node.arguments[0];if(callback.body.type==="BlockStatement"&&callback.body.body.length===0){}else{return}}else{return}}}if(!isPromiseExpression(node)){return}if(requirePromiseEvidence&&!hasPromiseEvidence(node,promiseNames,name=>resolveBinding(name,node))){return}if(isPromiseHandled(node)){return}if(ignoreVoidExpressions){const parent2=node.parent;if(parent2&&parent2.type==="UnaryExpression"&&parent2.operator==="void"){return}}const parent=node.parent;if(parent&&parent.type==="CallExpression"){const grandParent=parent.parent;const chainOn=grandParent?.type==="MemberExpression"&&grandParent.object===parent?grandParent:null;const outerChainMethod=chainOn===null?null:(0,eslint_devkit_1.propertyName)(chainOn);const inPromiseChain=chainOn!==null&&chainOn.property.type==="Identifier"&&outerChainMethod==="then";const isArgument=parent.arguments.some(a=>a===node);const outerIsPromise=outerChainMethod==="then"||outerChainMethod==="catch"||outerChainMethod==="finally"||hasPromiseEvidence(parent,promiseNames,name=>resolveBinding(name,parent));if(!inPromiseChain&&(!isArgument||outerIsPromise)){return}}context.report({node,messageId:"unhandledPromise",suggest:[{messageId:"addCatch",fix:()=>null},{messageId:"useTryCatch",fix:()=>null},{messageId:"useAwait",fix:()=>null}]})}function checkStatementPromise(node){const parent=node.parent;if(parent?.type!=="ExpressionStatement")return;context.report({node,messageId:"unhandledPromise"})}return{CallExpression:checkCallExpression,ImportExpression:checkStatementPromise,NewExpression(node){if(node.callee.type==="Identifier"&&node.callee.name==="Promise"){checkStatementPromise(node)}}}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.consistentFunctionScoping=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");exports.consistentFunctionScoping=(0,eslint_devkit_1.createRule)({name:"consistent-function-scoping",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/consistent-function-scoping.md",description:"Move function definitions to the highest possible scope to improve readability and performance"},hasSuggestions:true,messages:{inconsistentFunctionScoping:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Inconsistent Function Scoping",description:"Function can be moved to higher scope as it doesn't capture outer variables",severity:"MEDIUM",fix:"Move function declaration to module scope",documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"}),moveToModuleScope:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Function Scoping Optimization",description:"Function does not use variables from its containing scope and can be moved to module level",severity:"MEDIUM",fix:'Move function outside current scope: extract `function helper() { return "value"; }` to module level before the containing function/class',documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"})},schema:[{type:"object",properties:{checkArrowFunctions:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{checkArrowFunctions:true}],create(context){const[options]=context.options;const{checkArrowFunctions=true}=options||{};const scopeStack=[new Set];function enterScope(){scopeStack.push(new Set)}function exitScope(){scopeStack.pop()}function addVariableToCurrentScope(name){const currentScope=scopeStack[scopeStack.length-1];if(currentScope){currentScope.add(name)}}function getOuterScopeVariables(){const outerScopes=scopeStack.slice(0,-1);const outerVars=new Set;for(const scope of outerScopes){for(const varName of scope){outerVars.add(varName)}}return outerVars}function analyzeFunction(node){
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.consistentFunctionScoping=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");exports.consistentFunctionScoping=(0,eslint_devkit_1.createRule)({name:"consistent-function-scoping",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/consistent-function-scoping.md",description:"Move function definitions to the highest possible scope to improve readability and performance"},hasSuggestions:true,messages:{inconsistentFunctionScoping:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Inconsistent Function Scoping",description:"Function can be moved to higher scope as it doesn't capture outer variables",severity:"MEDIUM",fix:"Move function declaration to module scope",documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"}),moveToModuleScope:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Function Scoping Optimization",description:"Function does not use variables from its containing scope and can be moved to module level",severity:"MEDIUM",fix:'Move function outside current scope: extract `function helper() { return "value"; }` to module level before the containing function/class',documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"})},schema:[{type:"object",properties:{checkArrowFunctions:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{checkArrowFunctions:true}],create(context){const[options]=context.options;const{checkArrowFunctions=true}=options||{};const scopeStack=[new Set];function enterScope(){scopeStack.push(new Set)}function exitScope(){scopeStack.pop()}function addVariableToCurrentScope(name){const currentScope=scopeStack[scopeStack.length-1];if(currentScope){currentScope.add(name)}}function getOuterScopeVariables(){const outerScopes=scopeStack.slice(0,-1);const outerVars=new Set;for(const scope of outerScopes){for(const varName of scope){outerVars.add(varName)}}return outerVars}function analyzeFunction(node){let ancestor=node.parent;while(ancestor?.type==="VariableDeclarator"||ancestor?.type==="VariableDeclaration"){ancestor=ancestor.parent}if(ancestor?.type==="Program"||ancestor?.type==="ExportNamedDeclaration"||ancestor?.type==="ExportDefaultDeclaration"){return}const p=node.parent;if(p?.type==="MethodDefinition"||p?.type==="PropertyDefinition"){return}if(p?.type==="CallExpression"||p?.type==="NewExpression"){return}if(p?.type==="Property"){return}const referencedVars=new Set;function collectReferences(astNode,depth=0){if(astNode.type==="Identifier"){referencedVars.add(astNode.name)}if(depth<10){for(const key in astNode){if(key==="parent")continue;const child=astNode[key];if(child&&typeof child==="object"){if(Array.isArray(child)){child.forEach(item=>{if(item&&typeof item==="object"&&"type"in item){collectReferences(item,depth+1)}})}else if("type"in child){collectReferences(child,depth+1)}}}}}if(node.body.type==="BlockStatement"){node.body.body.forEach(stmt=>collectReferences(stmt))}else{collectReferences(node.body)}node.params.forEach(param=>{if(param.type==="Identifier"){referencedVars.add(param.name)}});const outerVars=getOuterScopeVariables();let capturesOuterVar=false;for(const ref of referencedVars){if(outerVars.has(ref)){capturesOuterVar=true;break}}if(!capturesOuterVar){const functionName=node.type==="FunctionDeclaration"?node.id?.name:void 0;const moduleScope=scopeStack[0];if(!functionName||!moduleScope.has(functionName)){context.report({node,messageId:"inconsistentFunctionScoping",data:{functionName:functionName||"anonymous function"},suggest:[{messageId:"moveToModuleScope",fix(fixer){return fixer.insertTextBefore(node,"// TODO: Move this function to module scope - it doesn't capture outer variables\n")}}]})}}}return{Program(){enterScope()},"Program:exit"(){exitScope()},FunctionDeclaration(node){enterScope();node.params.forEach(param=>{if(param.type==="Identifier"){addVariableToCurrentScope(param.name)}});analyzeFunction(node)},"FunctionDeclaration:exit"(){exitScope()},FunctionExpression(node){enterScope();node.params.forEach(param=>{if(param.type==="Identifier"){addVariableToCurrentScope(param.name)}});analyzeFunction(node)},"FunctionExpression:exit"(){exitScope()},ArrowFunctionExpression(node){enterScope();node.params.forEach(param=>{if(param.type==="Identifier"){addVariableToCurrentScope(param.name)}});if(checkArrowFunctions){analyzeFunction(node)}},"ArrowFunctionExpression:exit"(){exitScope()},VariableDeclaration(node){node.declarations.forEach(decl=>{if(decl.id.type==="Identifier"){addVariableToCurrentScope(decl.id.name)}})}}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.maxParameters=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");function countParameters(node){return node.params.length}exports.maxParameters=(0,eslint_devkit_2.createRule)({name:"max-parameters",skipGeneratedFiles:true,meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/max-parameters.md",description:"Detects functions with too many parameters"},hasSuggestions:true,messages:{tooManyParameters:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.COMPLEXITY,issueName:"Too many parameters",description:"{{functionName}}: {{count}} parameters (max: {{max}})",severity:"MEDIUM",fix:"Refactor to use object parameter or split function",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-107/"}),useObjectParameter:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Object Parameter",description:"Use object parameter pattern",severity:"LOW",fix:"function({ param1, param2, param3 })",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment"}),extractToClass:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Extract to Class",description:"Extract to class with properties",severity:"LOW",fix:"Create class to hold related parameters",documentationLink:"https://refactoring.guru/introduce-parameter-object"}),splitFunction:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Split Function",description:"Split into smaller functions",severity:"LOW",fix:"Extract logic into separate focused functions",documentationLink:"https://refactoring.guru/smells/long-parameter-list"})},schema:[{type:"object",properties:{max:{type:"number",default:4,minimum:1},ignoreConstructors:{type:"boolean",default:false},ignoreOverriddenMethods:{type:"boolean",default:false}},additionalProperties:false}]},defaultOptions:[{max:4,ignoreConstructors:false,ignoreOverriddenMethods:false}],create(context,[options={}]){const{max=4,ignoreConstructors=false}=options||{};function checkFunction(node){if(ignoreConstructors){if(node.type==="FunctionDeclaration"&&node.id&&node.id.name&&/^[A-Z]/.test(node.id.name)){return}}const paramCount=countParameters(node);if(paramCount<=max){return}const functionSignature=(0,eslint_devkit_3.extractFunctionSignature)(node);const overBy=paramCount-max;context.report({node,messageId:"tooManyParameters",data:{functionName:functionSignature,count:String(paramCount),max:String(max),overBy:String(overBy)},suggest:[{messageId:"useObjectParameter",fix:()=>null},{messageId:"extractToClass",fix:()=>null},{messageId:"splitFunction",fix:()=>null}]})}return{FunctionDeclaration:checkFunction,FunctionExpression:checkFunction,ArrowFunctionExpression:checkFunction}}});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.maxParameters=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");function countParameters(node){const[first]=node.params;const hasThisParam=first?.type==="Identifier"&&first.name==="this";return node.params.length-(hasThisParam?1:0)}exports.maxParameters=(0,eslint_devkit_2.createRule)({name:"max-parameters",skipGeneratedFiles:true,meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/max-parameters.md",description:"Detects functions with too many parameters"},hasSuggestions:true,messages:{tooManyParameters:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.COMPLEXITY,issueName:"Too many parameters",description:"{{functionName}}: {{count}} parameters (max: {{max}})",severity:"MEDIUM",fix:"Refactor to use object parameter or split function",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-107/"}),useObjectParameter:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Object Parameter",description:"Use object parameter pattern",severity:"LOW",fix:"function({ param1, param2, param3 })",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment"}),extractToClass:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Extract to Class",description:"Extract to class with properties",severity:"LOW",fix:"Create class to hold related parameters",documentationLink:"https://refactoring.guru/introduce-parameter-object"}),splitFunction:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Split Function",description:"Split into smaller functions",severity:"LOW",fix:"Extract logic into separate focused functions",documentationLink:"https://refactoring.guru/smells/long-parameter-list"})},schema:[{type:"object",properties:{max:{type:"number",default:4,minimum:1},ignoreConstructors:{type:"boolean",default:false},ignoreOverriddenMethods:{type:"boolean",default:false}},additionalProperties:false}]},defaultOptions:[{max:4,ignoreConstructors:false,ignoreOverriddenMethods:false}],create(context,[options={}]){const{max=4,ignoreConstructors=false}=options||{};function checkFunction(node){if(ignoreConstructors){if(node.type==="FunctionDeclaration"&&node.id&&node.id.name&&/^[A-Z]/.test(node.id.name)){return}}const paramCount=countParameters(node);if(paramCount<=max){return}const functionSignature=(0,eslint_devkit_3.extractFunctionSignature)(node);const overBy=paramCount-max;context.report({node,messageId:"tooManyParameters",data:{functionName:functionSignature,count:String(paramCount),max:String(max),overBy:String(overBy)},suggest:[{messageId:"useObjectParameter",fix:()=>null},{messageId:"extractToClass",fix:()=>null},{messageId:"splitFunction",fix:()=>null}]})}return{FunctionDeclaration:checkFunction,FunctionExpression:checkFunction,ArrowFunctionExpression:checkFunction}}});
|