eslint-plugin-reliability 3.1.4 → 3.1.6
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 +15 -0
- package/README.md +9 -3
- package/package.json +1 -1
- package/src/index.js +1 -1
- 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 -0
- package/src/rules/reliability/no-missing-null-checks.d.ts +10 -1
- package/src/rules/reliability/no-missing-null-checks.js +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
## [3.1.3] - 2026-05-03
|
|
2
2
|
|
|
3
|
+
## 3.1.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#269](https://github.com/ofri-peretz/eslint/pull/269) [`7028fe2`](https://github.com/ofri-peretz/eslint/commit/7028fe2668a42266d831014184dcef70e73101ad) Thanks [@ofri-peretz](https://github.com/ofri-peretz)! - docs: dual-logo README header (Interlace mark + ESLint mark side by side) and closing Interlace footer — refreshes the README rendered on npmjs.com. No runtime changes.
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`7028fe2`](https://github.com/ofri-peretz/eslint/commit/7028fe2668a42266d831014184dcef70e73101ad)]:
|
|
10
|
+
- @interlace/eslint-devkit@1.4.2
|
|
11
|
+
|
|
12
|
+
## 3.1.5
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#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
|
|
17
|
+
|
|
3
18
|
## 3.1.4
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
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/
|
|
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/icon-light.svg" alt="Interlace" height="90" /></a>
|
|
3
|
+
|
|
4
|
+
<a href="https://eslint.org" target="_blank"><img src="https://eslint.interlace.tools/eslint-logo.svg" alt="ESLint" height="90" /></a>
|
|
3
5
|
</p>
|
|
4
6
|
|
|
5
7
|
<p align="center">
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
<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
13
|
<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
14
|
<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>
|
|
15
|
+
<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
16
|
<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
17
|
</p>
|
|
16
18
|
|
|
@@ -196,4 +198,8 @@ MIT © [Ofri Peretz](https://github.com/ofri-peretz)
|
|
|
196
198
|
|
|
197
199
|
<p align="center">
|
|
198
200
|
<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>
|
|
199
|
-
</p>
|
|
201
|
+
</p>
|
|
202
|
+
|
|
203
|
+
<p align="center">
|
|
204
|
+
<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/icon-light.svg" alt="Interlace" height="70" /></a>
|
|
205
|
+
</p>
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -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');
|
|
@@ -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
|
|
@@ -445,7 +451,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
445
451
|
},
|
|
446
452
|
],
|
|
447
453
|
});
|
|
448
|
-
/* c8 ignore next 4 -- defensive error handling, hard to trigger in tests */
|
|
449
454
|
}
|
|
450
455
|
catch {
|
|
451
456
|
// Silently skip if there's an error
|
|
@@ -458,7 +463,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
458
463
|
* Only check if it's an actual method call, not just a property access
|
|
459
464
|
*/
|
|
460
465
|
function checkCallExpression(node) {
|
|
461
|
-
/* c8 ignore next 4 -- defensive type check, always true when called by ESLint visitor */
|
|
462
466
|
// Ensure this is actually a CallExpression (not just a MemberExpression)
|
|
463
467
|
if (node.type !== 'CallExpression') {
|
|
464
468
|
return;
|
|
@@ -526,7 +530,6 @@ exports.noMissingNullChecks = (0, eslint_devkit_2.createRule)({
|
|
|
526
530
|
},
|
|
527
531
|
],
|
|
528
532
|
});
|
|
529
|
-
/* c8 ignore next 4 -- defensive error handling, hard to trigger in tests */
|
|
530
533
|
}
|
|
531
534
|
catch {
|
|
532
535
|
// Silently skip if there's an error
|