eslint-plugin-reliability 3.1.3 → 3.1.5
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/CHANGELOG.md +32 -0
- package/README.md +29 -18
- package/package.json +6 -2
- package/src/index.d.ts +1 -1
- package/src/index.js +2 -2
- package/src/rules/error-handling/no-silent-errors.js +0 -2
- package/src/rules/error-handling/no-unhandled-promise.d.ts +24 -1
- package/src/rules/error-handling/no-unhandled-promise.js +12 -0
- package/src/rules/reliability/no-jsdoc-terminator-in-example.d.ts +10 -0
- package/src/rules/reliability/no-jsdoc-terminator-in-example.js +6 -1
- package/src/rules/reliability/no-missing-null-checks.d.ts +10 -1
- package/src/rules/reliability/no-missing-null-checks.js +54 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
## [3.1.3] - 2026-05-03
|
|
2
2
|
|
|
3
|
+
## 3.1.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#252](https://github.com/ofri-peretz/eslint/pull/252) [`d67e395`](https://github.com/ofri-peretz/eslint/commit/d67e3953c2748ad36e6aebe0f24b1d04e518b4d0) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - Fix Codecov badge showing "unknown" — switch from flag to component URL format
|
|
8
|
+
|
|
9
|
+
## 3.1.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#141](https://github.com/ofri-peretz/eslint/pull/141) [`38ab670`](https://github.com/ofri-peretz/eslint/commit/38ab670a0221684f4fd3d5dc3c05ddec7458ca2b) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - fix: remove false `meta.fixable: 'code'` declarations from 21 rules that had no `fix()` function
|
|
14
|
+
|
|
15
|
+
Rules that declared `fixable: 'code'` in their ESLint meta without an actual `fix()` implementation would show the ⚡ auto-fix icon in editors and CI formatters but apply no change when `--fix` was run. This patch removes the misleading declaration from:
|
|
16
|
+
- `browser-security/no-clickjacking`
|
|
17
|
+
- `import-next/first`, `named`, `no-barrel-import`, `no-import-module-exports`, `no-namespace`
|
|
18
|
+
- `node-security/no-buffer-overread`, `no-unsafe-dynamic-require`, `no-zip-slip`
|
|
19
|
+
- `react-features/react-no-inline-functions`
|
|
20
|
+
- `reliability/no-jsdoc-terminator-in-example` (uses `suggest`, not auto-fix; corrected to `hasSuggestions: true` only)
|
|
21
|
+
- `secure-coding/no-directive-injection`, `no-electron-security-issues`, `no-graphql-injection`, `no-improper-sanitization`, `no-improper-type-validation`, `no-ldap-injection`, `no-unchecked-loop-condition`, `no-unlimited-resource-allocation`, `no-weak-password-recovery`, `no-xpath-injection`
|
|
22
|
+
|
|
23
|
+
- [#143](https://github.com/ofri-peretz/eslint/pull/143) [`213cde1`](https://github.com/ofri-peretz/eslint/commit/213cde190ff2aea49ca7c1b533170940f879d9b4) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - fix(no-missing-null-checks): eliminate 53 false positives via three new narrowing patterns
|
|
24
|
+
|
|
25
|
+
Rules that were recognized as null guards are now correctly identified as safe:
|
|
26
|
+
1. **Truthy if guard** — `if (obj) { obj.prop }` — direct truthy check proves non-null. Also covers chains: `if (response)` protects `response.data.items`.
|
|
27
|
+
2. **Short-circuit AND** — `obj && obj.prop` — right side of `&&` only runs when left is truthy.
|
|
28
|
+
3. **Ternary consequent** — `obj ? obj.prop : fallback` — truthy test guards the consequent.
|
|
29
|
+
|
|
30
|
+
Also: bumped `beforeAll` timeout to 30 seconds in 7 compatibility test files (`__compatibility__/*.spec.ts`). Native-addon packages routinely exceed the previous 10-second default on a cold ESM load.
|
|
31
|
+
|
|
32
|
+
- Updated dependencies [[`736a5fe`](https://github.com/ofri-peretz/eslint/commit/736a5fed47e673f6157ea900b29fe2a54e4bc7df)]:
|
|
33
|
+
- @interlace/eslint-devkit@1.4.1
|
|
34
|
+
|
|
3
35
|
### Bug Fixes
|
|
4
36
|
|
|
5
37
|
- `no-missing-null-checks`: exempt provably-non-null identifiers (built-in singletons like `Math`, `JSON`, `console`, error classes; catch-clause params; constructor results; top-level imports) from the null-check requirement. Eliminates a large class of false positives without weakening real coverage.
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://eslint.interlace.tools" target="blank"><img src="https://eslint.interlace.tools/eslint-interlace-logo-light.svg" alt="ESLint Interlace Logo" width="120" /></a>
|
|
2
|
+
<a href="https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability" target="blank"><img src="https://eslint.interlace.tools/eslint-interlace-logo-light.svg" alt="ESLint Interlace Logo" width="120" /></a>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
<a href="https://www.npmjs.com/package/eslint-plugin-reliability" target="_blank"><img src="https://img.shields.io/npm/v/eslint-plugin-reliability.svg" alt="NPM Version" /></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/eslint-plugin-reliability" target="_blank"><img src="https://img.shields.io/npm/dm/eslint-plugin-reliability.svg" alt="NPM Downloads" /></a>
|
|
12
12
|
<a href="https://opensource.org/licenses/MIT" target="_blank"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="Package License" /></a>
|
|
13
|
-
<a href="https://app.codecov.io/gh/ofri-peretz/eslint/components?components%5B0%5D=reliability" target="_blank"><img src="https://codecov.io/gh/ofri-peretz/eslint/graph/badge.svg?component=reliability" alt="Codecov" /></a>
|
|
13
|
+
<a href="https://app.codecov.io/gh/ofri-peretz/eslint/components?components%5B0%5D=eslint-plugin-reliability" target="_blank"><img src="https://codecov.io/gh/ofri-peretz/eslint/graph/badge.svg?component=eslint-plugin-reliability" alt="Codecov" /></a>
|
|
14
14
|
<a href="https://github.com/ofri-peretz/eslint" target="_blank"><img src="https://img.shields.io/badge/Since-Dec_2025-blue?logo=rocket&logoColor=white" alt="Since Dec 2025" /></a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
|
+
> ⭐ If this plugin caught a real bug for you, [**star the repo**](https://github.com/ofri-peretz/eslint) — it's the signal that keeps these rules maintained.
|
|
18
|
+
|
|
17
19
|
## Description
|
|
18
20
|
|
|
19
21
|
This plugin provides Reliability rules for defensive programming, error handling, and async correctness.
|
|
@@ -24,12 +26,12 @@ This plugin provides Reliability rules for defensive programming, error handling
|
|
|
24
26
|
|
|
25
27
|
## Getting Started
|
|
26
28
|
|
|
27
|
-
- To check out the [guide](https://eslint.interlace.tools/docs/quality/plugin-reliability), visit [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
28
|
-
- 要查看中文 [指南](https://eslint.interlace.tools/docs/quality/plugin-reliability), 请访问 [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
29
|
-
- [가이드](https://eslint.interlace.tools/docs/quality/plugin-reliability) 문서는 [eslint.interlace.tools](https://eslint.interlace.tools)에서 확인하실 수 있습니다. 📚
|
|
30
|
-
- [ガイド](https://eslint.interlace.tools/docs/quality/plugin-reliability)は [eslint.interlace.tools](https://eslint.interlace.tools)でご確認ください。 📚
|
|
31
|
-
- Para ver la [guía](https://eslint.interlace.tools/docs/quality/plugin-reliability), visita [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
32
|
-
- للاطلاع على [الدليل](https://eslint.interlace.tools/docs/quality/plugin-reliability)، قم بزيارة [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
29
|
+
- To check out the [guide](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability), visit [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability). 📚
|
|
30
|
+
- 要查看中文 [指南](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability), 请访问 [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability). 📚
|
|
31
|
+
- [가이드](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) 문서는 [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability)에서 확인하실 수 있습니다. 📚
|
|
32
|
+
- [ガイド](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability)は [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability)でご確認ください。 📚
|
|
33
|
+
- Para ver la [guía](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability), visita [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability). 📚
|
|
34
|
+
- للاطلاع على [الدليل](https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability)، قم بزيارة [eslint.interlace.tools](https://eslint.interlace.tools/?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability). 📚
|
|
33
35
|
|
|
34
36
|
```bash
|
|
35
37
|
npm install eslint-plugin-reliability --save-dev
|
|
@@ -151,15 +153,15 @@ See the [ESLint Version Support Policy](../../docs/ESLINT_VERSION_SUPPORT.md)
|
|
|
151
153
|
<!-- AUTO-GENERATED:RULES_TABLE:START - Do not edit manually -->
|
|
152
154
|
| Rule | CWE | OWASP | CVSS | Description | 🧠 | 💼 | ⚠️ | 🔧 | 💡 | 🚫 |
|
|
153
155
|
| :--- | :---: | :---: | :---: | :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
154
|
-
| [error-message](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/error-message) | | | | Enforce providing a message when creating built-in Error objects for better debugging. This rule is part of… | 🟢 | | | | 💡 | |
|
|
155
|
-
| [no-await-in-loop](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-await-in-loop) | | | | Disallow await inside loops without considering concurrency implications | 🟢 | | | | 💡 | |
|
|
156
|
-
| [no-jsdoc-terminator-in-example](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-jsdoc-terminator-in-example) | | | | Detect `*/` sequences inside JSDoc `@example` blocks that prematurely close the JSDoc comment. | 🟢 | | | | 💡 | |
|
|
157
|
-
| [no-missing-error-context](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-missing-error-context) | | | | ESLint Rule: no-missing-error-context with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | | | 💡 | |
|
|
158
|
-
| [no-missing-null-checks](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-missing-null-checks) | CWE-476 | | | ESLint Rule: no-missing-null-checks with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | ⚠️ | | 💡 | |
|
|
159
|
-
| [no-silent-errors](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-silent-errors) | | | | ESLint Rule: no-silent-errors with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | ⚠️ | | 💡 | |
|
|
160
|
-
| [no-unhandled-promise](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-unhandled-promise) | CWE-1024 | | | Disallow unhandled Promise rejections with LLM-optimized suggestions for proper async error handling. This… | 🟢 | | | | 💡 | |
|
|
161
|
-
| [no-unsafe-type-narrowing](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-unsafe-type-narrowing) | | | | ESLint Rule: no-unsafe-type-narrowing with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | | | 💡 | |
|
|
162
|
-
| [require-network-timeout](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/require-network-timeout) | | | | Require timeout configuration for network requests. This rule is part of eslint-plugin-reliability and prov… | 🟢 | 💼 | | | 💡 | |
|
|
156
|
+
| [error-message](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/error-message?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | Enforce providing a message when creating built-in Error objects for better debugging. This rule is part of… | 🟢 | | | | 💡 | |
|
|
157
|
+
| [no-await-in-loop](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-await-in-loop?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | Disallow await inside loops without considering concurrency implications | 🟢 | | | | 💡 | |
|
|
158
|
+
| [no-jsdoc-terminator-in-example](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-jsdoc-terminator-in-example?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | Detect `*/` sequences inside JSDoc `@example` blocks that prematurely close the JSDoc comment. | 🟢 | | | | 💡 | |
|
|
159
|
+
| [no-missing-error-context](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-missing-error-context?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | ESLint Rule: no-missing-error-context with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | | | 💡 | |
|
|
160
|
+
| [no-missing-null-checks](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-missing-null-checks?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | CWE-476 | | | ESLint Rule: no-missing-null-checks with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | ⚠️ | | 💡 | |
|
|
161
|
+
| [no-silent-errors](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-silent-errors?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | ESLint Rule: no-silent-errors with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | ⚠️ | | 💡 | |
|
|
162
|
+
| [no-unhandled-promise](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-unhandled-promise?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | CWE-1024 | | | Disallow unhandled Promise rejections with LLM-optimized suggestions for proper async error handling. This… | 🟢 | | | | 💡 | |
|
|
163
|
+
| [no-unsafe-type-narrowing](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/no-unsafe-type-narrowing?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | ESLint Rule: no-unsafe-type-narrowing with LLM-optimized suggestions and auto-fix capabilities. | 🟢 | | | | 💡 | |
|
|
164
|
+
| [require-network-timeout](https://eslint.interlace.tools/docs/quality/plugin-reliability/rules/require-network-timeout?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability) | | | | Require timeout configuration for network requests. This rule is part of eslint-plugin-reliability and prov… | 🟢 | 💼 | | | 💡 | |
|
|
163
165
|
<!-- AUTO-GENERATED:RULES_TABLE:END -->
|
|
164
166
|
## 🔗 Related ESLint Plugins
|
|
165
167
|
|
|
@@ -179,10 +181,19 @@ Part of the **Interlace ESLint Ecosystem** — AI-native security plugins with L
|
|
|
179
181
|
| [`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) | Vercel AI SDK security hardening. |
|
|
180
182
|
| [`eslint-plugin-import-next`](https://www.npmjs.com/package/eslint-plugin-import-next) | [](https://www.npmjs.com/package/eslint-plugin-import-next) | Next-gen import sorting & architecture. |
|
|
181
183
|
|
|
184
|
+
<!-- INTERLACE:STAR_CTA:START -->
|
|
185
|
+
## ⭐ Support & follow
|
|
186
|
+
|
|
187
|
+
If this plugin caught a real bug for you, **[star the repo](https://github.com/ofri-peretz/eslint)** — stars are the signal that keeps the Interlace ESLint ecosystem maintained — and **[follow the writeups on Dev.to](https://dev.to/ofri-peretz)** for the benchmarks and security research behind these rules.
|
|
188
|
+
|
|
189
|
+
[](https://github.com/ofri-peretz/eslint)
|
|
190
|
+
|
|
191
|
+
<!-- INTERLACE:STAR_CTA:END -->
|
|
192
|
+
|
|
182
193
|
## 📄 License
|
|
183
194
|
|
|
184
195
|
MIT © [Ofri Peretz](https://github.com/ofri-peretz)
|
|
185
196
|
|
|
186
197
|
<p align="center">
|
|
187
|
-
<a href="https://eslint.interlace.tools/docs/quality/plugin-reliability"><img src="https://eslint.interlace.tools/images/og-reliability.png" alt="ESLint Interlace Plugin" width="100%" /></a>
|
|
198
|
+
<a href="https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=github&utm_medium=referral&utm_campaign=eslint-plugin-reliability"><img src="https://eslint.interlace.tools/images/og-reliability.png" alt="ESLint Interlace Plugin" width="100%" /></a>
|
|
188
199
|
</p>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-reliability",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.5",
|
|
4
4
|
"description": "ESLint rules for runtime stability, fault tolerance, and type safety.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"url": "https://github.com/ofri-peretz/eslint",
|
|
53
53
|
"directory": "packages/eslint-plugin-reliability"
|
|
54
54
|
},
|
|
55
|
-
"homepage": "https://
|
|
55
|
+
"homepage": "https://eslint.interlace.tools/docs/quality/plugin-reliability?utm_source=npm&utm_medium=referral&utm_campaign=eslint-plugin-reliability",
|
|
56
56
|
"bugs": {
|
|
57
57
|
"url": "https://github.com/ofri-peretz/eslint/issues"
|
|
58
58
|
},
|
|
@@ -64,5 +64,9 @@
|
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"eslint": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
67
|
+
},
|
|
68
|
+
"funding": {
|
|
69
|
+
"type": "github",
|
|
70
|
+
"url": "https://github.com/ofri-peretz/eslint"
|
|
67
71
|
}
|
|
68
72
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -189,7 +189,7 @@ export declare const configs: {
|
|
|
189
189
|
};
|
|
190
190
|
};
|
|
191
191
|
rules: {
|
|
192
|
-
'reliability/no-silent-errors': "
|
|
192
|
+
'reliability/no-silent-errors': "error";
|
|
193
193
|
'reliability/no-missing-null-checks': "warn";
|
|
194
194
|
'reliability/require-network-timeout': "error";
|
|
195
195
|
};
|
package/src/index.js
CHANGED
|
@@ -41,7 +41,7 @@ exports.rules = {
|
|
|
41
41
|
exports.plugin = {
|
|
42
42
|
meta: {
|
|
43
43
|
name: 'eslint-plugin-reliability',
|
|
44
|
-
version: '3.1.
|
|
44
|
+
version: '3.1.5',
|
|
45
45
|
},
|
|
46
46
|
rules: exports.rules,
|
|
47
47
|
};
|
|
@@ -51,7 +51,7 @@ exports.configs = {
|
|
|
51
51
|
reliability: exports.plugin,
|
|
52
52
|
},
|
|
53
53
|
rules: {
|
|
54
|
-
'reliability/no-silent-errors': '
|
|
54
|
+
'reliability/no-silent-errors': 'error',
|
|
55
55
|
'reliability/no-missing-null-checks': 'warn',
|
|
56
56
|
'reliability/require-network-timeout': 'error',
|
|
57
57
|
},
|
|
@@ -13,7 +13,6 @@ const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
|
13
13
|
*/
|
|
14
14
|
function isEmptyCatchBlock(catchClause) {
|
|
15
15
|
const body = catchClause.body;
|
|
16
|
-
/* v8 ignore next 3 -- defensive: catch clause body is always BlockStatement in valid JS */
|
|
17
16
|
if (!body || body.type !== 'BlockStatement') {
|
|
18
17
|
return true;
|
|
19
18
|
}
|
|
@@ -33,7 +32,6 @@ function hasExplanatoryComment(catchClause, sourceCode) {
|
|
|
33
32
|
// Check for comments before the catch clause
|
|
34
33
|
const comments = sourceCode.getAllComments();
|
|
35
34
|
const catchStart = catchClause.loc?.start;
|
|
36
|
-
/* v8 ignore next 3 -- defensive: catch clause always has location, and no comments = no match */
|
|
37
35
|
if (!catchStart || !comments.length) {
|
|
38
36
|
return false;
|
|
39
37
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @see https://cwe.mitre.org/data/definitions/1024.html
|
|
12
12
|
* @see https://rules.sonarsource.com/javascript/RSPEC-4635/
|
|
13
13
|
*/
|
|
14
|
-
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
14
|
+
import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
|
|
15
15
|
type MessageIds = 'unhandledPromise' | 'addCatch' | 'useTryCatch' | 'useAwait';
|
|
16
16
|
export interface Options {
|
|
17
17
|
/** Ignore promises in test files. Default: true */
|
|
@@ -20,6 +20,29 @@ export interface Options {
|
|
|
20
20
|
ignoreVoidExpressions?: boolean;
|
|
21
21
|
}
|
|
22
22
|
type RuleOptions = [Options?];
|
|
23
|
+
/**
|
|
24
|
+
* Returns true if the call MIGHT return a Promise (default — we want to
|
|
25
|
+
* preserve detection for unknown calls). Returns false only when the
|
|
26
|
+
* callee is a known synchronous built-in (`setTimeout`, `console.log`,
|
|
27
|
+
* `Math.floor`, etc.) — those structurally never return promises and
|
|
28
|
+
* firing on them produces FPs. Keeping the default as "could be a
|
|
29
|
+
* promise" preserves recall on user-defined async functions.
|
|
30
|
+
*
|
|
31
|
+
* Exported for direct Layer-2 unit testing: the non-CallExpression early
|
|
32
|
+
* return is only reachable when called with a non-call node (kept for the
|
|
33
|
+
* future `checkIdentifier` listener), which the current CallExpression-only
|
|
34
|
+
* listener never produces.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isLikelyPromiseExpression(node: TSESTree.Node): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if promise is handled (has .catch, .then, or is in try/catch)
|
|
39
|
+
*
|
|
40
|
+
* Exported for direct Layer-2 unit testing: the Identifier branch is only
|
|
41
|
+
* reachable when called with an Identifier node (kept for the future
|
|
42
|
+
* `checkIdentifier` listener), which the current CallExpression-only
|
|
43
|
+
* listener never produces.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isPromiseHandled(node: TSESTree.Node): boolean;
|
|
23
46
|
export declare const noUnhandledPromise: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
|
|
24
47
|
name: string;
|
|
25
48
|
};
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.noUnhandledPromise = void 0;
|
|
9
|
+
exports.isLikelyPromiseExpression = isLikelyPromiseExpression;
|
|
10
|
+
exports.isPromiseHandled = isPromiseHandled;
|
|
9
11
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
12
|
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
13
|
/**
|
|
@@ -68,6 +70,11 @@ const SYNC_NAMESPACE_OBJECTS = new Set([
|
|
|
68
70
|
* `Math.floor`, etc.) — those structurally never return promises and
|
|
69
71
|
* firing on them produces FPs. Keeping the default as "could be a
|
|
70
72
|
* promise" preserves recall on user-defined async functions.
|
|
73
|
+
*
|
|
74
|
+
* Exported for direct Layer-2 unit testing: the non-CallExpression early
|
|
75
|
+
* return is only reachable when called with a non-call node (kept for the
|
|
76
|
+
* future `checkIdentifier` listener), which the current CallExpression-only
|
|
77
|
+
* listener never produces.
|
|
71
78
|
*/
|
|
72
79
|
function isLikelyPromiseExpression(node) {
|
|
73
80
|
if (node.type !== 'CallExpression')
|
|
@@ -159,6 +166,11 @@ function isInsidePromiseCallback(node) {
|
|
|
159
166
|
}
|
|
160
167
|
/**
|
|
161
168
|
* Check if promise is handled (has .catch, .then, or is in try/catch)
|
|
169
|
+
*
|
|
170
|
+
* Exported for direct Layer-2 unit testing: the Identifier branch is only
|
|
171
|
+
* reachable when called with an Identifier node (kept for the future
|
|
172
|
+
* `checkIdentifier` listener), which the current CallExpression-only
|
|
173
|
+
* listener never produces.
|
|
162
174
|
*/
|
|
163
175
|
function isPromiseHandled(node) {
|
|
164
176
|
// For identifiers, check if they're used in a promise chain
|
|
@@ -19,6 +19,16 @@ type MessageIds = 'jsdocTerminatorInExample' | 'wrapInQuotes';
|
|
|
19
19
|
export interface Options {
|
|
20
20
|
}
|
|
21
21
|
type RuleOptions = [Options?];
|
|
22
|
+
/**
|
|
23
|
+
* Check whether a comment line is inside an @example block.
|
|
24
|
+
* We track this by scanning line-by-line for @example / next-tag boundaries.
|
|
25
|
+
*
|
|
26
|
+
* Exported for direct Layer-2 unit testing: a real parser terminates the
|
|
27
|
+
* enclosing block comment at the first star-slash sequence, so a comment
|
|
28
|
+
* value containing one can never reach this function through a
|
|
29
|
+
* normally-parsed file.
|
|
30
|
+
*/
|
|
31
|
+
export declare function findTerminatorsInExamples(commentText: string): number[];
|
|
22
32
|
export declare const noJsdocTerminatorInExample: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
|
|
23
33
|
name: string;
|
|
24
34
|
};
|
|
@@ -6,10 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.noJsdocTerminatorInExample = void 0;
|
|
9
|
+
exports.findTerminatorsInExamples = findTerminatorsInExamples;
|
|
9
10
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
11
|
/**
|
|
11
12
|
* Check whether a comment line is inside an @example block.
|
|
12
13
|
* We track this by scanning line-by-line for @example / next-tag boundaries.
|
|
14
|
+
*
|
|
15
|
+
* Exported for direct Layer-2 unit testing: a real parser terminates the
|
|
16
|
+
* enclosing block comment at the first star-slash sequence, so a comment
|
|
17
|
+
* value containing one can never reach this function through a
|
|
18
|
+
* normally-parsed file.
|
|
13
19
|
*/
|
|
14
20
|
function findTerminatorsInExamples(commentText) {
|
|
15
21
|
const lines = commentText.split('\n');
|
|
@@ -63,7 +69,6 @@ exports.noJsdocTerminatorInExample = (0, eslint_devkit_1.createRule)({
|
|
|
63
69
|
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-jsdoc-terminator-in-example.md',
|
|
64
70
|
description: 'Detects `*/` sequences inside JSDoc @example blocks that prematurely close the comment',
|
|
65
71
|
},
|
|
66
|
-
fixable: 'code',
|
|
67
72
|
hasSuggestions: true,
|
|
68
73
|
messages: {
|
|
69
74
|
jsdocTerminatorInExample: (0, eslint_devkit_1.formatLLMMessage)({
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @see https://cwe.mitre.org/data/definitions/476.html
|
|
12
12
|
* @see https://rules.sonarsource.com/javascript/RSPEC-2259/
|
|
13
13
|
*/
|
|
14
|
-
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
14
|
+
import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
|
|
15
15
|
type MessageIds = 'missingNullCheck' | 'useOptionalChaining' | 'useNullishCoalescing' | 'addExplicitCheck';
|
|
16
16
|
export interface Options {
|
|
17
17
|
/** Ignore in test files. Default: true */
|
|
@@ -20,6 +20,15 @@ export interface Options {
|
|
|
20
20
|
requireExplicitChecks?: boolean;
|
|
21
21
|
}
|
|
22
22
|
type RuleOptions = [Options?];
|
|
23
|
+
/**
|
|
24
|
+
* Check if property access has null/undefined check
|
|
25
|
+
*
|
|
26
|
+
* Exported for direct Layer-2 unit testing: the `node.optional` and
|
|
27
|
+
* ChainExpression early returns are defensive duplicates of checks both
|
|
28
|
+
* callers perform before invoking this helper, so they are unreachable
|
|
29
|
+
* through the rule's listeners.
|
|
30
|
+
*/
|
|
31
|
+
export declare function hasNullCheck(node: TSESTree.MemberExpression, sourceCode: TSESLint.SourceCode): boolean;
|
|
23
32
|
export declare const noMissingNullChecks: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
|
|
24
33
|
name: string;
|
|
25
34
|
};
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.noMissingNullChecks = void 0;
|
|
9
|
+
exports.hasNullCheck = hasNullCheck;
|
|
9
10
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
11
|
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
12
|
/**
|
|
@@ -128,6 +129,11 @@ function isProvablyNonNullableIdentifier(ident, scope) {
|
|
|
128
129
|
}
|
|
129
130
|
/**
|
|
130
131
|
* Check if property access has null/undefined check
|
|
132
|
+
*
|
|
133
|
+
* Exported for direct Layer-2 unit testing: the `node.optional` and
|
|
134
|
+
* ChainExpression early returns are defensive duplicates of checks both
|
|
135
|
+
* callers perform before invoking this helper, so they are unreachable
|
|
136
|
+
* through the rule's listeners.
|
|
131
137
|
*/
|
|
132
138
|
function hasNullCheck(node, sourceCode) {
|
|
133
139
|
// Check if node itself uses optional chaining
|
|
@@ -137,20 +143,49 @@ function hasNullCheck(node, sourceCode) {
|
|
|
137
143
|
// Check if parent is optional chaining
|
|
138
144
|
const parent = node.parent;
|
|
139
145
|
if (parent && parent.type === 'ChainExpression') {
|
|
140
|
-
return true;
|
|
146
|
+
return true;
|
|
141
147
|
}
|
|
142
148
|
// Check if used with nullish coalescing
|
|
143
149
|
if (usesNullishCoalescing(node)) {
|
|
144
150
|
return true;
|
|
145
151
|
}
|
|
146
|
-
|
|
147
|
-
//
|
|
148
|
-
//
|
|
152
|
+
const objectText = sourceCode.getText(node.object);
|
|
153
|
+
// Short-circuit AND: `obj && obj.prop` — the right side of && runs only
|
|
154
|
+
// when the left side is truthy, so obj is guaranteed non-null here.
|
|
155
|
+
// Walk up one level (CallExpression wraps MemberExpression for `obj && obj.method()`)
|
|
156
|
+
const immediateParent = parent;
|
|
157
|
+
const nodeOrCall = immediateParent?.type === 'CallExpression' &&
|
|
158
|
+
immediateParent.callee === node
|
|
159
|
+
? immediateParent
|
|
160
|
+
: node;
|
|
161
|
+
const andParent = nodeOrCall
|
|
162
|
+
.parent;
|
|
163
|
+
if (andParent?.type === 'LogicalExpression' &&
|
|
164
|
+
andParent.operator === '&&' &&
|
|
165
|
+
andParent.right === nodeOrCall) {
|
|
166
|
+
const leftText = sourceCode.getText(andParent.left);
|
|
167
|
+
if (leftText === objectText || leftText.endsWith(objectText))
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
// Ternary consequent: `obj ? obj.prop : fallback` — the test being truthy
|
|
171
|
+
// guarantees obj is non-null before the consequent evaluates.
|
|
172
|
+
let cur = node;
|
|
173
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
174
|
+
const p = cur.parent;
|
|
175
|
+
if (!p)
|
|
176
|
+
break;
|
|
177
|
+
if (p.type === 'ConditionalExpression' &&
|
|
178
|
+
p.consequent === cur) {
|
|
179
|
+
if (sourceCode.getText(p.test) === objectText) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
cur = p;
|
|
184
|
+
}
|
|
185
|
+
// Explicit null/truthy check in enclosing if statement
|
|
149
186
|
if (hasExplicitNullCheck(node, sourceCode)) {
|
|
150
187
|
return true;
|
|
151
188
|
}
|
|
152
|
-
// For more sophisticated null checking, we'd need control flow analysis
|
|
153
|
-
// This is a simplified implementation that checks for basic patterns
|
|
154
189
|
return false;
|
|
155
190
|
}
|
|
156
191
|
/**
|
|
@@ -180,7 +215,17 @@ function hasExplicitNullCheck(node, sourceCode) {
|
|
|
180
215
|
* Check if a test expression is a null check for a specific object
|
|
181
216
|
*/
|
|
182
217
|
function isNullCheckForObject(test, object, sourceCode) {
|
|
183
|
-
|
|
218
|
+
const objectText = sourceCode.getText(object);
|
|
219
|
+
// Truthy check: `if (obj)` or `if (obj.prop)` — direct truthy guard proves
|
|
220
|
+
// non-null. Also covers nested chains: `if (response) { response.data.items }`
|
|
221
|
+
// because checking the root (response) implicitly protects the full chain.
|
|
222
|
+
if (test.type === 'Identifier' || test.type === 'MemberExpression') {
|
|
223
|
+
const testText = sourceCode.getText(test);
|
|
224
|
+
if (testText === objectText || objectText.startsWith(testText + '.')) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Handle binary expressions like obj !== null, obj != undefined
|
|
184
229
|
if (test.type === 'BinaryExpression') {
|
|
185
230
|
const { left, right, operator } = test;
|
|
186
231
|
if (operator === '!==' ||
|
|
@@ -189,8 +234,6 @@ function isNullCheckForObject(test, object, sourceCode) {
|
|
|
189
234
|
operator === '==') {
|
|
190
235
|
const leftText = sourceCode.getText(left);
|
|
191
236
|
const rightText = sourceCode.getText(right);
|
|
192
|
-
const objectText = sourceCode.getText(object);
|
|
193
|
-
// Check if one side matches our object and the other is null/undefined
|
|
194
237
|
if ((leftText === objectText &&
|
|
195
238
|
(rightText === 'null' || rightText === 'undefined')) ||
|
|
196
239
|
(rightText === objectText &&
|
|
@@ -204,6 +247,8 @@ function isNullCheckForObject(test, object, sourceCode) {
|
|
|
204
247
|
return (isNullCheckForObject(test.left, object, sourceCode) ||
|
|
205
248
|
isNullCheckForObject(test.right, object, sourceCode));
|
|
206
249
|
}
|
|
250
|
+
// Unary negation: `if (!obj)` is a FALSY guard — only safe when paired
|
|
251
|
+
// with early return, which requires control-flow analysis. Skip for now.
|
|
207
252
|
return false;
|
|
208
253
|
}
|
|
209
254
|
/**
|
|
@@ -406,7 +451,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
406
451
|
},
|
|
407
452
|
],
|
|
408
453
|
});
|
|
409
|
-
/* c8 ignore next 4 -- defensive error handling, hard to trigger in tests */
|
|
410
454
|
}
|
|
411
455
|
catch {
|
|
412
456
|
// Silently skip if there's an error
|
|
@@ -419,7 +463,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
419
463
|
* Only check if it's an actual method call, not just a property access
|
|
420
464
|
*/
|
|
421
465
|
function checkCallExpression(node) {
|
|
422
|
-
/* c8 ignore next 4 -- defensive type check, always true when called by ESLint visitor */
|
|
423
466
|
// Ensure this is actually a CallExpression (not just a MemberExpression)
|
|
424
467
|
if (node.type !== 'CallExpression') {
|
|
425
468
|
return;
|
|
@@ -487,7 +530,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
487
530
|
},
|
|
488
531
|
],
|
|
489
532
|
});
|
|
490
|
-
/* c8 ignore next 4 -- defensive error handling, hard to trigger in tests */
|
|
491
533
|
}
|
|
492
534
|
catch {
|
|
493
535
|
// Silently skip if there's an error
|