@blumintinc/eslint-plugin-blumint 1.20.94 → 1.20.95
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/lib/index.js +1 -1
- package/lib/rules/no-redundant-param-types.js +69 -37
- package/package.json +1 -1
- package/release-manifest.json +14 -0
package/lib/index.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.noRedundantParamTypes = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const disableDirectives_1 = require("../utils/disableDirectives");
|
|
6
7
|
const importRemoval_1 = require("../utils/importRemoval");
|
|
7
8
|
/**
|
|
8
9
|
* The annotation a parameter carries, or `undefined` when it has none. A
|
|
@@ -68,57 +69,88 @@ exports.noRedundantParamTypes = (0, createRule_1.createRule)({
|
|
|
68
69
|
create(context) {
|
|
69
70
|
const sourceCode = context.getSourceCode();
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
+
* An annotation is stripped together with any import it was the only
|
|
72
73
|
* consumer of. The two are one fix: applying either half alone leaves the
|
|
73
74
|
* file worse than applying neither — a stripped annotation with its import
|
|
74
75
|
* left behind fails `no-unused-vars`, and since this rule's own report is
|
|
75
76
|
* resolved by the fix, nothing re-reports the debt.
|
|
76
77
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
* Reporting is therefore deferred to `Program:exit`: an import is unbound
|
|
79
|
+
* only once no reference to it survives the fix, and a file where two
|
|
80
|
+
* annotations name the same imported type strips both in a single pass.
|
|
81
|
+
* Judging each removal alone sees the sibling annotation still standing,
|
|
82
|
+
* concludes the binding is alive, and leaves the import stranded with no
|
|
83
|
+
* later pass to notice.
|
|
84
|
+
*/
|
|
85
|
+
const sites = [];
|
|
86
|
+
/**
|
|
87
|
+
* Suppression is applied to reports after a rule emits them, so a suppressed
|
|
88
|
+
* site keeps its annotation while losing its fix. Counting its removal
|
|
89
|
+
* toward orphanhood would unbind an import the surviving text still spells,
|
|
90
|
+
* trading an unused import for a dangling type.
|
|
91
|
+
*/
|
|
92
|
+
const isReportSuppressed = (0, disableDirectives_1.createSuppressionChecker)(context);
|
|
93
|
+
/**
|
|
94
|
+
* The strips that actually ship. A site is excluded when its report will be
|
|
95
|
+
* suppressed, or when its own removal orphans something the helper cannot
|
|
96
|
+
* rewrite — a local alias, an interface, a type parameter. Deleting a
|
|
97
|
+
* declaration is a materially riskier edit than dropping an import
|
|
98
|
+
* specifier, and the author is better placed to decide whether the type
|
|
99
|
+
* should go or be used elsewhere.
|
|
86
100
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* the import.
|
|
101
|
+
* Screening individually before batching keeps one unfixable site from
|
|
102
|
+
* vetoing the rest: orphanhood grows monotonically with the removed set, so
|
|
103
|
+
* a site that cannot be planned alone can only ever poison the batch.
|
|
91
104
|
*/
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
context.report({
|
|
96
|
-
node: param,
|
|
97
|
-
messageId: 'redundantParamType',
|
|
98
|
-
data: {
|
|
99
|
-
paramText: sourceCode.getText(param).replace(/\s+/g, ' ').trim(),
|
|
100
|
-
},
|
|
101
|
-
// No plan means no binding can be unbound safely, so the annotation
|
|
102
|
-
// stays too: the report without a fixer is the lesser damage.
|
|
103
|
-
...(importRanges
|
|
104
|
-
? {
|
|
105
|
-
fix: (fixer) => [
|
|
106
|
-
fixer.removeRange([removal[0], removal[1]]),
|
|
107
|
-
...importRanges.map((range) => fixer.removeRange([range[0], range[1]])),
|
|
108
|
-
],
|
|
109
|
-
}
|
|
110
|
-
: {}),
|
|
111
|
-
});
|
|
105
|
+
function selectFixableSites() {
|
|
106
|
+
return sites.filter((site) => !isReportSuppressed(site.param) &&
|
|
107
|
+
(0, importRemoval_1.planOrphanedImportRemoval)(sourceCode, [site.removal]) !== null);
|
|
112
108
|
}
|
|
113
109
|
return {
|
|
110
|
+
'Program:exit'() {
|
|
111
|
+
if (sites.length === 0)
|
|
112
|
+
return;
|
|
113
|
+
const fixable = selectFixableSites();
|
|
114
|
+
const removals = fixable.map((site) => site.removal);
|
|
115
|
+
// One plan over every surviving strip: an import referenced solely by
|
|
116
|
+
// annotations that all go in this pass is orphaned by their union, even
|
|
117
|
+
// though no single one of them orphans it.
|
|
118
|
+
const importRanges = removals.length > 0
|
|
119
|
+
? (0, importRemoval_1.planOrphanedImportRemoval)(sourceCode, removals)
|
|
120
|
+
: null;
|
|
121
|
+
// The whole batch ships as one fix, so no strip can land without the
|
|
122
|
+
// others that the import's orphanhood was judged against. The rest
|
|
123
|
+
// report without a fixer; the carrier's pass already resolves them.
|
|
124
|
+
//
|
|
125
|
+
// No plan at all means no binding can be unbound safely, so every
|
|
126
|
+
// annotation stays: reports without a fixer are the lesser damage.
|
|
127
|
+
const carrier = importRanges ? fixable[0] : undefined;
|
|
128
|
+
for (const site of sites) {
|
|
129
|
+
context.report({
|
|
130
|
+
node: site.param,
|
|
131
|
+
messageId: 'redundantParamType',
|
|
132
|
+
data: { paramText: site.paramText },
|
|
133
|
+
fix: site === carrier && importRanges
|
|
134
|
+
? (fixer) => [
|
|
135
|
+
...removals.map((range) => fixer.removeRange([range[0], range[1]])),
|
|
136
|
+
...importRanges.map((range) => fixer.removeRange([range[0], range[1]])),
|
|
137
|
+
]
|
|
138
|
+
: null,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
},
|
|
114
142
|
ArrowFunctionExpression(node) {
|
|
115
143
|
if (!hasRedundantTypeAnnotation(node))
|
|
116
144
|
return;
|
|
117
145
|
node.params.forEach((param) => {
|
|
118
146
|
const typeAnnotation = annotationOf(param);
|
|
119
|
-
if (typeAnnotation)
|
|
120
|
-
|
|
121
|
-
|
|
147
|
+
if (!typeAnnotation)
|
|
148
|
+
return;
|
|
149
|
+
sites.push({
|
|
150
|
+
param,
|
|
151
|
+
removal: annotationRemovalRange(typeAnnotation, sourceCode),
|
|
152
|
+
paramText: sourceCode.getText(param).replace(/\s+/g, ' ').trim(),
|
|
153
|
+
});
|
|
122
154
|
});
|
|
123
155
|
},
|
|
124
156
|
};
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.20.95",
|
|
4
|
+
"date": "2026-08-03T23:44:33.733Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "no-redundant-param-types",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
1670
|
|
11
|
+
],
|
|
12
|
+
"summary": "unbind the import two annotations share (closes #1670)"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"version": "1.20.94",
|
|
4
18
|
"date": "2026-08-03T22:57:52.839Z",
|