@blumintinc/eslint-plugin-blumint 1.17.1 → 1.17.3
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
CHANGED
|
@@ -241,6 +241,41 @@ function isTypeGuardFunction(node) {
|
|
|
241
241
|
}
|
|
242
242
|
return false;
|
|
243
243
|
}
|
|
244
|
+
// The names below are the built-in TypeScript read-only wrapper types. When a
|
|
245
|
+
// function is annotated with one of these, the annotation is NOT redundant:
|
|
246
|
+
// TypeScript always infers the mutable concrete type (e.g. Set<T> not
|
|
247
|
+
// ReadonlySet<T>), so stripping the annotation silently changes the public
|
|
248
|
+
// return type and lets callers mutate internal state that the author intended
|
|
249
|
+
// to protect.
|
|
250
|
+
const READONLY_TYPE_NAMES = new Set([
|
|
251
|
+
'ReadonlySet',
|
|
252
|
+
'ReadonlyMap',
|
|
253
|
+
'ReadonlyArray',
|
|
254
|
+
'Readonly',
|
|
255
|
+
]);
|
|
256
|
+
/**
|
|
257
|
+
* Returns true when `returnType` is a read-only widening annotation — i.e.
|
|
258
|
+
* one that TypeScript would NOT infer on its own and whose removal therefore
|
|
259
|
+
* changes the public API. Two forms are covered:
|
|
260
|
+
*
|
|
261
|
+
* TSTypeReference — ReadonlySet<T>, ReadonlyMap<K,V>, ReadonlyArray<T>,
|
|
262
|
+
* Readonly<T>
|
|
263
|
+
* TSTypeOperator — `readonly T[]` and `readonly [a, b]` tuples
|
|
264
|
+
*/
|
|
265
|
+
function isReadonlyWideningReturnType(returnType) {
|
|
266
|
+
const typeAnnotation = returnType.typeAnnotation;
|
|
267
|
+
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
268
|
+
const typeName = typeAnnotation.typeName;
|
|
269
|
+
return (typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
270
|
+
READONLY_TYPE_NAMES.has(typeName.name));
|
|
271
|
+
}
|
|
272
|
+
// `readonly T[]` and `readonly [a, b]` are represented as TSTypeOperator
|
|
273
|
+
// nodes with operator === 'readonly'.
|
|
274
|
+
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeOperator) {
|
|
275
|
+
return typeAnnotation.operator === 'readonly';
|
|
276
|
+
}
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
244
279
|
exports.noExplicitReturnType = (0, createRule_1.createRule)({
|
|
245
280
|
name: 'no-explicit-return-type',
|
|
246
281
|
meta: {
|
|
@@ -297,6 +332,7 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
|
|
|
297
332
|
if (!returnType)
|
|
298
333
|
return;
|
|
299
334
|
if (isTypeGuardFunction(node) ||
|
|
335
|
+
isReadonlyWideningReturnType(returnType) ||
|
|
300
336
|
(mergedOptions.allowRecursiveFunctions && isRecursiveFunction(node))) {
|
|
301
337
|
return;
|
|
302
338
|
}
|
|
@@ -320,6 +356,7 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
|
|
|
320
356
|
return;
|
|
321
357
|
}
|
|
322
358
|
if (isTypeGuardFunction(node) ||
|
|
359
|
+
isReadonlyWideningReturnType(returnType) ||
|
|
323
360
|
(mergedOptions.allowRecursiveFunctions && isRecursiveFunction(node))) {
|
|
324
361
|
return;
|
|
325
362
|
}
|
|
@@ -334,7 +371,8 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
|
|
|
334
371
|
const returnType = node.returnType;
|
|
335
372
|
if (!returnType)
|
|
336
373
|
return;
|
|
337
|
-
if (isTypeGuardFunction(node)
|
|
374
|
+
if (isTypeGuardFunction(node) ||
|
|
375
|
+
isReadonlyWideningReturnType(returnType)) {
|
|
338
376
|
return;
|
|
339
377
|
}
|
|
340
378
|
context.report({
|
|
@@ -366,6 +404,7 @@ exports.noExplicitReturnType = (0, createRule_1.createRule)({
|
|
|
366
404
|
if (!returnType)
|
|
367
405
|
return;
|
|
368
406
|
if (isTypeGuardFunction(node.value) ||
|
|
407
|
+
isReadonlyWideningReturnType(returnType) ||
|
|
369
408
|
(mergedOptions.allowAbstractMethodSignatures &&
|
|
370
409
|
isInterfaceOrAbstractMethodSignature(node))) {
|
|
371
410
|
return;
|
|
@@ -10,7 +10,12 @@ const COMMON_TYPES = [
|
|
|
10
10
|
'Boolean',
|
|
11
11
|
'Array',
|
|
12
12
|
'Object',
|
|
13
|
-
'Function',
|
|
13
|
+
// 'Function' is intentionally excluded. Unlike an incidental, rot-prone data
|
|
14
|
+
// type (String/Number/...), a value named *Function is intrinsically and
|
|
15
|
+
// permanently callable, so the marker can never become misleading. Fn/Func/
|
|
16
|
+
// Function are function-ROLE designators (like callback/handler/predicate),
|
|
17
|
+
// not Hungarian type tags — compareFn/mapFn are the ECMAScript/MDN-canonical
|
|
18
|
+
// parameter names. See the ABBREVIATION_MARKERS note and issue #1255.
|
|
14
19
|
// 'Date', too many false positives
|
|
15
20
|
'RegExp',
|
|
16
21
|
'Promise',
|
|
@@ -20,16 +25,11 @@ const COMMON_TYPES = [
|
|
|
20
25
|
// Abbreviation type markers (e.g. str, arr, obj). No English word is spelled this
|
|
21
26
|
// way, so their presence as a segment — even in the middle of a name — is
|
|
22
27
|
// unambiguously a type tag (strName, USER_STR_NAME, ConfigArrSettings).
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'arr',
|
|
29
|
-
'obj',
|
|
30
|
-
'fn',
|
|
31
|
-
'func',
|
|
32
|
-
];
|
|
28
|
+
// `fn`/`func` are deliberately excluded: they abbreviate a value's callable ROLE
|
|
29
|
+
// (like callback/handler/predicate), which is intrinsic and never rots, so
|
|
30
|
+
// checkFn/compareFn/mapFn/renderFunc are legitimate role names, not Hungarian
|
|
31
|
+
// type tags (#1255).
|
|
32
|
+
const ABBREVIATION_MARKERS = ['str', 'num', 'int', 'bool', 'arr', 'obj'];
|
|
33
33
|
// Combined type markers (former Hungarian prefixes and type suffixes)
|
|
34
34
|
const TYPE_MARKERS = [
|
|
35
35
|
...ABBREVIATION_MARKERS,
|
|
@@ -53,7 +53,7 @@ const SINGLE_LETTER_PREFIXES = new Set(['b', 'i']);
|
|
|
53
53
|
// allowed compound noun PhoneNumber. Abbreviation markers (str/arr/obj/...) are
|
|
54
54
|
// deliberately excluded: no English word is spelled that way, so their presence
|
|
55
55
|
// as a segment is unambiguously a type tag even inside a type name.
|
|
56
|
-
const FULL_TYPE_WORDS = new Set(
|
|
56
|
+
const FULL_TYPE_WORDS = new Set(COMMON_TYPES.map((word) => word.toLowerCase()));
|
|
57
57
|
// Allowed descriptive suffixes that should not be flagged as Hungarian notation
|
|
58
58
|
const ALLOWED_SUFFIXES = [
|
|
59
59
|
'Formatted',
|
|
@@ -218,7 +218,7 @@ function splitCamelSegments(name) {
|
|
|
218
218
|
// A TYPE name (alias/interface/class) is exempt from a full-type-word marker when
|
|
219
219
|
// that marker is one clean PascalCase segment among OTHER descriptive segments —
|
|
220
220
|
// i.e. the word denotes a type concept/relation, not a redundant type tag.
|
|
221
|
-
// Examples: StringToNumber, CapitalizedString, PromiseOrValue
|
|
221
|
+
// Examples: StringToNumber, CapitalizedString, PromiseOrValue.
|
|
222
222
|
// Abbreviation markers (str/arr/obj/...) never qualify, so genuine Hungarian type
|
|
223
223
|
// names like UserStrName / ConfigArrSettings / UserObjData still fire.
|
|
224
224
|
function isSemanticTypeConcept(typeName) {
|
|
@@ -177,9 +177,13 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
|
|
|
177
177
|
if (node.parent?.type === utils_1.AST_NODE_TYPES.LogicalExpression) {
|
|
178
178
|
return true;
|
|
179
179
|
}
|
|
180
|
-
// Allow type assertions
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
// Allow type assertions that are direct arguments of any call or new expression.
|
|
181
|
+
// The asserted value is an argument — TypeScript structurally checks it against the
|
|
182
|
+
// parameter type — so the returned value is the call's result, not the cast itself.
|
|
183
|
+
// This covers method calls (obj.method(x as T)), plain calls (fn(x as T)), and
|
|
184
|
+
// constructors (new Ctor(x as T)) uniformly.
|
|
185
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression ||
|
|
186
|
+
node.parent?.type === utils_1.AST_NODE_TYPES.NewExpression) {
|
|
183
187
|
return true;
|
|
184
188
|
}
|
|
185
189
|
// Allow type assertions within array includes checks
|
|
@@ -195,27 +199,6 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
|
|
|
195
199
|
if (isPropertyAccess(node) && isInsideConditionalStatement(node)) {
|
|
196
200
|
return true;
|
|
197
201
|
}
|
|
198
|
-
// Allow type assertions in object instantiations (as constructor arguments)
|
|
199
|
-
if (node.parent?.type === utils_1.AST_NODE_TYPES.ObjectExpression &&
|
|
200
|
-
node.parent.parent?.type === utils_1.AST_NODE_TYPES.NewExpression) {
|
|
201
|
-
return true;
|
|
202
|
-
}
|
|
203
|
-
// Allow type assertions as arguments to constructors
|
|
204
|
-
if (node.parent?.type === utils_1.AST_NODE_TYPES.NewExpression ||
|
|
205
|
-
(node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
206
|
-
node.parent.parent?.type === utils_1.AST_NODE_TYPES.NewExpression)) {
|
|
207
|
-
return true;
|
|
208
|
-
}
|
|
209
|
-
// Allow type assertions as arguments to constructor calls
|
|
210
|
-
if (node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
211
|
-
let current = node.parent;
|
|
212
|
-
while (current?.parent) {
|
|
213
|
-
if (current.parent.type === utils_1.AST_NODE_TYPES.NewExpression) {
|
|
214
|
-
return true;
|
|
215
|
-
}
|
|
216
|
-
current = current.parent;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
202
|
// Allow type assertions in JSX attributes/props or object properties
|
|
220
203
|
if (isInsideJSXAttributeOrObjectProperty(node)) {
|
|
221
204
|
return true;
|
|
@@ -59,9 +59,6 @@ const COMMON_PREPOSITION_SUFFIXES = new Set([
|
|
|
59
59
|
'Where',
|
|
60
60
|
'When',
|
|
61
61
|
'While',
|
|
62
|
-
// Programming-specific suffixes
|
|
63
|
-
'Async',
|
|
64
|
-
'Sync',
|
|
65
62
|
]);
|
|
66
63
|
/**
|
|
67
64
|
* Phrasal-verb particles that fuse with a preceding past participle to form an
|
|
@@ -134,6 +131,41 @@ function isPhrasalVerbEnding(name, suffix) {
|
|
|
134
131
|
const lastWord = beforeSuffix.match(/[A-Z]?[a-z]+$/)?.[0] ?? '';
|
|
135
132
|
return phrasalVerbStem(lastWord) !== null;
|
|
136
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Returns true when `node` (or its relevant ancestor for the declaration kind)
|
|
136
|
+
* is directly wrapped in an export declaration. An exported symbol must not be
|
|
137
|
+
* auto-fixed because the fixer can only rename within the current file, leaving
|
|
138
|
+
* cross-file import references broken.
|
|
139
|
+
*
|
|
140
|
+
* Call this with:
|
|
141
|
+
* - the FunctionDeclaration node for `function foo() {}`
|
|
142
|
+
* - the ArrowFunctionExpression/FunctionExpression node for `const foo = () => {}`
|
|
143
|
+
* (its parent chain: arrow → VariableDeclarator → VariableDeclaration → export?)
|
|
144
|
+
*/
|
|
145
|
+
function isExported(node) {
|
|
146
|
+
const parent = node.parent;
|
|
147
|
+
if (!parent)
|
|
148
|
+
return false;
|
|
149
|
+
// FunctionDeclaration directly inside `export function foo() {}`
|
|
150
|
+
if (parent.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
|
|
151
|
+
parent.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
// Arrow/FunctionExpression assigned to a VariableDeclarator:
|
|
155
|
+
// VariableDeclarator → VariableDeclaration → ExportNamedDeclaration
|
|
156
|
+
if (parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
157
|
+
const varDecl = parent.parent; // VariableDeclaration
|
|
158
|
+
if (!varDecl)
|
|
159
|
+
return false;
|
|
160
|
+
const varDeclParent = varDecl.parent; // possible ExportNamedDeclaration
|
|
161
|
+
if (varDeclParent &&
|
|
162
|
+
(varDeclParent.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
|
|
163
|
+
varDeclParent.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
137
169
|
exports.noUnnecessaryVerbSuffix = (0, createRule_1.createRule)({
|
|
138
170
|
name: 'no-unnecessary-verb-suffix',
|
|
139
171
|
meta: {
|
|
@@ -150,7 +182,27 @@ exports.noUnnecessaryVerbSuffix = (0, createRule_1.createRule)({
|
|
|
150
182
|
},
|
|
151
183
|
defaultOptions: [],
|
|
152
184
|
create(context) {
|
|
153
|
-
function checkFunctionName(node, name
|
|
185
|
+
function checkFunctionName(node, name,
|
|
186
|
+
/**
|
|
187
|
+
* The AST node that holds the identifier being renamed.
|
|
188
|
+
* For FunctionDeclaration this is `node.id`; for VariableDeclarator
|
|
189
|
+
* assigned arrows it is `declarator.id`; for Property/MethodDefinition
|
|
190
|
+
* it is the key node. Passing it explicitly avoids re-deriving it inside
|
|
191
|
+
* the fixer and allows the reference-rename loop to skip it cleanly.
|
|
192
|
+
*/
|
|
193
|
+
declarationIdNode,
|
|
194
|
+
/**
|
|
195
|
+
* The AST node whose declared variables the scope manager tracks.
|
|
196
|
+
* For FunctionDeclaration this is `node` itself; for a VariableDeclarator
|
|
197
|
+
* arrow it is the VariableDeclarator; for methods/properties it is null
|
|
198
|
+
* because member references are not in scope (resolved via `this.x`).
|
|
199
|
+
*/
|
|
200
|
+
scopeNode,
|
|
201
|
+
/**
|
|
202
|
+
* Whether the symbol is exported. When true, the fix is suppressed so we
|
|
203
|
+
* don't produce broken cross-file renames.
|
|
204
|
+
*/
|
|
205
|
+
exported) {
|
|
154
206
|
if (!name)
|
|
155
207
|
return;
|
|
156
208
|
for (const suffix of COMMON_PREPOSITION_SUFFIXES) {
|
|
@@ -182,25 +234,50 @@ exports.noUnnecessaryVerbSuffix = (0, createRule_1.createRule)({
|
|
|
182
234
|
suggestion,
|
|
183
235
|
},
|
|
184
236
|
fix(fixer) {
|
|
185
|
-
|
|
186
|
-
|
|
237
|
+
// An autofix here is only reference-safe when the fixer can
|
|
238
|
+
// rename EVERY use of the symbol, not just its declaration —
|
|
239
|
+
// otherwise call sites are orphaned and produce a ReferenceError
|
|
240
|
+
// (#1256). Two cases make that impossible, so the fix is
|
|
241
|
+
// suppressed (report only, no `--fix` change):
|
|
242
|
+
//
|
|
243
|
+
// 1. Exported symbols — a single-file fixer cannot reach
|
|
244
|
+
// cross-file import references.
|
|
245
|
+
// 2. Member-accessed symbols (class methods, object-literal
|
|
246
|
+
// properties, interface method signatures) — their call
|
|
247
|
+
// sites are member expressions (`this.x()`, `obj.x()`) that
|
|
248
|
+
// the scope manager does not track as variable references,
|
|
249
|
+
// so they cannot be found and renamed syntactically.
|
|
250
|
+
// `scopeNode` is null for exactly these declarations.
|
|
251
|
+
if (exported || !scopeNode || !declarationIdNode) {
|
|
252
|
+
return null;
|
|
187
253
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
254
|
+
// Scope-tracked symbols (FunctionDeclaration, VariableDeclarator
|
|
255
|
+
// arrows/functions, named FunctionExpression): rename the
|
|
256
|
+
// declaration identifier and every in-file reference together so
|
|
257
|
+
// no call site is left pointing at the old name.
|
|
258
|
+
const fixes = [
|
|
259
|
+
fixer.replaceText(declarationIdNode, suggestion),
|
|
260
|
+
];
|
|
261
|
+
// Note: context.getDeclaredVariables is the API available in the
|
|
262
|
+
// pinned @typescript-eslint version (the SourceCode-based
|
|
263
|
+
// replacement is not yet in these type definitions).
|
|
264
|
+
const declaredVars = context.getDeclaredVariables(scopeNode);
|
|
265
|
+
// getDeclaredVariables returns ALL variables the node declares
|
|
266
|
+
// (e.g. for a FunctionDeclaration it includes the function name
|
|
267
|
+
// variable AND its parameter variables). Filter to the one whose
|
|
268
|
+
// name matches the symbol being renamed so we only follow
|
|
269
|
+
// references to the name, not parameters.
|
|
270
|
+
for (const variable of declaredVars) {
|
|
271
|
+
if (variable.name !== name)
|
|
272
|
+
continue;
|
|
273
|
+
for (const ref of variable.references) {
|
|
274
|
+
// Skip the declaration identifier itself — already handled.
|
|
275
|
+
if (ref.identifier === declarationIdNode)
|
|
276
|
+
continue;
|
|
277
|
+
fixes.push(fixer.replaceText(ref.identifier, suggestion));
|
|
201
278
|
}
|
|
202
279
|
}
|
|
203
|
-
return
|
|
280
|
+
return fixes;
|
|
204
281
|
},
|
|
205
282
|
});
|
|
206
283
|
}
|
|
@@ -210,38 +287,49 @@ exports.noUnnecessaryVerbSuffix = (0, createRule_1.createRule)({
|
|
|
210
287
|
return {
|
|
211
288
|
FunctionDeclaration(node) {
|
|
212
289
|
if (node.id) {
|
|
213
|
-
checkFunctionName(node, node.id.name);
|
|
290
|
+
checkFunctionName(node, node.id.name, node.id, node, isExported(node));
|
|
214
291
|
}
|
|
215
292
|
},
|
|
216
293
|
VariableDeclarator(node) {
|
|
217
294
|
if (node.id.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
218
295
|
(node.init?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
219
296
|
node.init?.type === utils_1.AST_NODE_TYPES.FunctionExpression)) {
|
|
220
|
-
checkFunctionName(node.init, node.id.name);
|
|
297
|
+
checkFunctionName(node.init, node.id.name, node.id, node, isExported(node.init));
|
|
221
298
|
}
|
|
222
299
|
},
|
|
223
300
|
MethodDefinition(node) {
|
|
224
301
|
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
225
|
-
|
|
302
|
+
// Class methods are called via member expressions (`this.method()`,
|
|
303
|
+
// `instance.method()`) that the scope manager does not track as
|
|
304
|
+
// references. A syntactic single-file fixer therefore cannot find and
|
|
305
|
+
// rename those call sites, so renaming the method would orphan them
|
|
306
|
+
// (#1256). Pass null for both the rename target and scopeNode so the
|
|
307
|
+
// violation is still reported but no unsafe fix is offered.
|
|
308
|
+
checkFunctionName(node.value, node.key.name, null, null, false);
|
|
226
309
|
}
|
|
227
310
|
},
|
|
228
311
|
TSMethodSignature(node) {
|
|
229
|
-
//
|
|
312
|
+
// Interface method signatures have their implementations and call sites
|
|
313
|
+
// elsewhere (member accesses on implementers), unreachable from this
|
|
314
|
+
// declaration. Report only — never offer a rename fix.
|
|
230
315
|
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
231
|
-
checkFunctionName(node, node.key.name);
|
|
316
|
+
checkFunctionName(node, node.key.name, null, null, false);
|
|
232
317
|
}
|
|
233
318
|
},
|
|
234
319
|
Property(node) {
|
|
235
320
|
if (node.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
236
321
|
(node.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
237
322
|
node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression)) {
|
|
238
|
-
|
|
323
|
+
// Object-literal method properties are accessed via member expressions
|
|
324
|
+
// (`obj.method()`) the scope manager does not track. As with class
|
|
325
|
+
// methods, the fix is suppressed to avoid orphaning call sites.
|
|
326
|
+
checkFunctionName(node.value, node.key.name, null, null, false);
|
|
239
327
|
}
|
|
240
328
|
},
|
|
241
329
|
FunctionExpression(node) {
|
|
242
330
|
// Handle named function expressions
|
|
243
331
|
if (node.id) {
|
|
244
|
-
checkFunctionName(node, node.id.name);
|
|
332
|
+
checkFunctionName(node, node.id.name, node.id, node, isExported(node));
|
|
245
333
|
}
|
|
246
334
|
},
|
|
247
335
|
};
|
package/package.json
CHANGED
package/release-manifest.json
CHANGED
|
@@ -1,4 +1,56 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "1.17.3",
|
|
4
|
+
"date": "2026-07-02T16:07:25.816Z",
|
|
5
|
+
"rules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "no-unnecessary-verb-suffix",
|
|
8
|
+
"changeType": "fix",
|
|
9
|
+
"issues": [
|
|
10
|
+
1256
|
|
11
|
+
],
|
|
12
|
+
"summary": "make autofix reference-safe (closes #1256)"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "1.17.2",
|
|
18
|
+
"date": "2026-07-02T12:29:19.590Z",
|
|
19
|
+
"rules": [
|
|
20
|
+
{
|
|
21
|
+
"name": "no-explicit-return-type",
|
|
22
|
+
"changeType": "fix",
|
|
23
|
+
"issues": [
|
|
24
|
+
1253
|
|
25
|
+
],
|
|
26
|
+
"summary": "exempt read-only widening return types from removal (closes #1253)"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "no-hungarian",
|
|
30
|
+
"changeType": "fix",
|
|
31
|
+
"issues": [
|
|
32
|
+
1255
|
|
33
|
+
],
|
|
34
|
+
"summary": "treat Fn/Func/Function as function-role designators, not type tags (closes #1255)"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "no-type-assertion-returns",
|
|
38
|
+
"changeType": "fix",
|
|
39
|
+
"issues": [
|
|
40
|
+
1254
|
|
41
|
+
],
|
|
42
|
+
"summary": "allow type assertions as call/new arguments in return position (closes #1254)"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "no-unnecessary-verb-suffix",
|
|
46
|
+
"changeType": "fix",
|
|
47
|
+
"issues": [
|
|
48
|
+
1252
|
|
49
|
+
],
|
|
50
|
+
"summary": "stop flagging Async/Sync execution-model suffixes (closes #1252)"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
},
|
|
2
54
|
{
|
|
3
55
|
"version": "1.17.1",
|
|
4
56
|
"date": "2026-07-01T22:31:34.840Z",
|