@sarj/eslint-plugin 15.17.9 → 15.17.10
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/dist/index.cjs +122 -190
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +189 -257
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2454,7 +2454,7 @@ var no_duplicate_lifecycle_refresh_listeners_default = createRule({
|
|
|
2454
2454
|
VariableDeclarator(node) {
|
|
2455
2455
|
if (node.id.type !== import_utils10.AST_NODE_TYPES.Identifier) return;
|
|
2456
2456
|
const variable = import_utils10.ASTUtils.findVariable(context.sourceCode.getScope(node.id), node.id.name);
|
|
2457
|
-
if (variable === null) return;
|
|
2457
|
+
if (variable === null || variable.references.some((reference) => reference.isWrite() && !reference.init)) return;
|
|
2458
2458
|
if (node.init?.type === import_utils10.AST_NODE_TYPES.ArrowFunctionExpression || node.init?.type === import_utils10.AST_NODE_TYPES.FunctionExpression) {
|
|
2459
2459
|
functionCallbacks.set(node.init, variable);
|
|
2460
2460
|
}
|
|
@@ -2465,7 +2465,7 @@ var no_duplicate_lifecycle_refresh_listeners_default = createRule({
|
|
|
2465
2465
|
FunctionDeclaration(node) {
|
|
2466
2466
|
if (node.id === null) return;
|
|
2467
2467
|
const variable = import_utils10.ASTUtils.findVariable(context.sourceCode.getScope(node.id), node.id.name);
|
|
2468
|
-
if (variable !== null) functionCallbacks.set(node, variable);
|
|
2468
|
+
if (variable !== null && !variable.references.some((reference) => reference.isWrite() && !reference.init)) functionCallbacks.set(node, variable);
|
|
2469
2469
|
},
|
|
2470
2470
|
CallExpression(node) {
|
|
2471
2471
|
const item = registration(context.sourceCode, node);
|
|
@@ -4475,105 +4475,9 @@ var ts = __toESM(require("typescript"), 1);
|
|
|
4475
4475
|
|
|
4476
4476
|
// src/rules/_class-private.ts
|
|
4477
4477
|
var import_utils21 = require("@typescript-eslint/utils");
|
|
4478
|
-
function symbolAt(services, checker, node) {
|
|
4479
|
-
return checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(node));
|
|
4480
|
-
}
|
|
4481
|
-
function sameSymbol(left, right) {
|
|
4482
|
-
return left !== void 0 && right !== void 0 && left === right;
|
|
4483
|
-
}
|
|
4484
|
-
function enclosingClass(node) {
|
|
4485
|
-
let current = node.parent;
|
|
4486
|
-
while (current !== void 0) {
|
|
4487
|
-
if (current.type === import_utils21.AST_NODE_TYPES.ClassDeclaration || current.type === import_utils21.AST_NODE_TYPES.ClassExpression) {
|
|
4488
|
-
return current;
|
|
4489
|
-
}
|
|
4490
|
-
current = current.parent;
|
|
4491
|
-
}
|
|
4492
|
-
return null;
|
|
4493
|
-
}
|
|
4494
4478
|
function memberName2(member) {
|
|
4495
4479
|
return !member.computed && member.key.type === import_utils21.AST_NODE_TYPES.Identifier ? member.key.name : null;
|
|
4496
4480
|
}
|
|
4497
|
-
function privateMemberFixes(context, services, owner, members, removePrivateKeyword) {
|
|
4498
|
-
const first = members[0];
|
|
4499
|
-
const name = first === void 0 ? null : memberName2(first);
|
|
4500
|
-
if (first === void 0 || name === null || members.some((member) => member.static || member.decorators.length > 0)) {
|
|
4501
|
-
return void 0;
|
|
4502
|
-
}
|
|
4503
|
-
if (owner.body.body.some((member) => {
|
|
4504
|
-
if (member.type !== import_utils21.AST_NODE_TYPES.MethodDefinition && member.type !== import_utils21.AST_NODE_TYPES.PropertyDefinition && member.type !== import_utils21.AST_NODE_TYPES.AccessorProperty) return false;
|
|
4505
|
-
return member.key.type === import_utils21.AST_NODE_TYPES.PrivateIdentifier && member.key.name === name;
|
|
4506
|
-
})) return void 0;
|
|
4507
|
-
const selectedMembers = new Set(members);
|
|
4508
|
-
if (owner.body.body.some((member) => {
|
|
4509
|
-
if (member.type !== import_utils21.AST_NODE_TYPES.MethodDefinition && member.type !== import_utils21.AST_NODE_TYPES.PropertyDefinition && member.type !== import_utils21.AST_NODE_TYPES.AccessorProperty) return false;
|
|
4510
|
-
return memberName2(member) === name && !selectedMembers.has(member);
|
|
4511
|
-
})) return void 0;
|
|
4512
|
-
const checker = services.program.getTypeChecker();
|
|
4513
|
-
const symbols = members.map((member) => symbolAt(services, checker, member.key)).filter(
|
|
4514
|
-
(symbol) => symbol !== void 0
|
|
4515
|
-
);
|
|
4516
|
-
if (symbols.length === 0) return void 0;
|
|
4517
|
-
const references = [];
|
|
4518
|
-
let unsafe = false;
|
|
4519
|
-
walk(context.sourceCode.ast, context.sourceCode.visitorKeys, (node) => {
|
|
4520
|
-
if (node.type === import_utils21.AST_NODE_TYPES.Literal && node.value === name) {
|
|
4521
|
-
unsafe = true;
|
|
4522
|
-
return;
|
|
4523
|
-
}
|
|
4524
|
-
if (node.type !== import_utils21.AST_NODE_TYPES.MemberExpression) return;
|
|
4525
|
-
const propertyName6 = node.property.type === import_utils21.AST_NODE_TYPES.Identifier || node.property.type === import_utils21.AST_NODE_TYPES.PrivateIdentifier ? node.property.name : node.property.type === import_utils21.AST_NODE_TYPES.Literal && typeof node.property.value === "string" ? node.property.value : null;
|
|
4526
|
-
if (propertyName6 !== name) return;
|
|
4527
|
-
const propertySymbol = symbolAt(services, checker, node.property);
|
|
4528
|
-
if (node.computed || node.property.type !== import_utils21.AST_NODE_TYPES.Identifier || node.object.type !== import_utils21.AST_NODE_TYPES.ThisExpression || enclosingClass(node) !== owner || !symbols.some((symbol) => sameSymbol(symbol, propertySymbol))) {
|
|
4529
|
-
unsafe = true;
|
|
4530
|
-
return;
|
|
4531
|
-
}
|
|
4532
|
-
references.push(node);
|
|
4533
|
-
});
|
|
4534
|
-
if (unsafe) return void 0;
|
|
4535
|
-
const privateKeywordRanges = /* @__PURE__ */ new Map();
|
|
4536
|
-
if (removePrivateKeyword) {
|
|
4537
|
-
const comments = context.sourceCode.getAllComments();
|
|
4538
|
-
for (const member of members) {
|
|
4539
|
-
const keyword = context.sourceCode.getTokens(member).find((token) => token.value === "private");
|
|
4540
|
-
const next = keyword === void 0 ? void 0 : context.sourceCode.getTokenAfter(keyword);
|
|
4541
|
-
if (keyword === void 0 || next === null || next === void 0) return void 0;
|
|
4542
|
-
if (comments.some((comment) => comment.range[0] >= keyword.range[1] && comment.range[1] <= next.range[0])) {
|
|
4543
|
-
return void 0;
|
|
4544
|
-
}
|
|
4545
|
-
privateKeywordRanges.set(member, [keyword.range[0], next.range[0]]);
|
|
4546
|
-
}
|
|
4547
|
-
}
|
|
4548
|
-
return (fixer) => {
|
|
4549
|
-
const fixes = [];
|
|
4550
|
-
for (const member of members) {
|
|
4551
|
-
fixes.push(fixer.replaceText(member.key, `#${name}`));
|
|
4552
|
-
if (removePrivateKeyword) {
|
|
4553
|
-
const range = privateKeywordRanges.get(member);
|
|
4554
|
-
if (range === void 0) return [];
|
|
4555
|
-
fixes.push(fixer.removeRange(range));
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
for (const reference of references) fixes.push(fixer.replaceText(reference.property, `#${name}`));
|
|
4559
|
-
return fixes;
|
|
4560
|
-
};
|
|
4561
|
-
}
|
|
4562
|
-
function walk(node, visitorKeys, visit) {
|
|
4563
|
-
visit(node);
|
|
4564
|
-
for (const key of visitorKeys[node.type] ?? []) {
|
|
4565
|
-
const child = node[key];
|
|
4566
|
-
if (Array.isArray(child)) {
|
|
4567
|
-
for (const item of child) {
|
|
4568
|
-
if (typeof item === "object" && item !== null && "type" in item) {
|
|
4569
|
-
walk(item, visitorKeys, visit);
|
|
4570
|
-
}
|
|
4571
|
-
}
|
|
4572
|
-
} else if (typeof child === "object" && child !== null && "type" in child) {
|
|
4573
|
-
walk(child, visitorKeys, visit);
|
|
4574
|
-
}
|
|
4575
|
-
}
|
|
4576
|
-
}
|
|
4577
4481
|
function convertibleMemberName(member) {
|
|
4578
4482
|
if (member.type !== import_utils21.AST_NODE_TYPES.MethodDefinition && member.type !== import_utils21.AST_NODE_TYPES.PropertyDefinition && member.type !== import_utils21.AST_NODE_TYPES.AccessorProperty) return null;
|
|
4579
4483
|
return memberName2(member);
|
|
@@ -5378,9 +5282,9 @@ var NO_GENERIC_SINGLE_EXPORT_MODULE_DOCUMENTATION = {
|
|
|
5378
5282
|
rationale: "A generic filename hides the sole exported responsibility and makes navigation less descriptive.",
|
|
5379
5283
|
remediation: "Choose a responsibility-bearing module name or colocate the export with its domain.",
|
|
5380
5284
|
category: "maintainability",
|
|
5381
|
-
limitations: ["Only
|
|
5285
|
+
limitations: ["Only the fixed generic-stem vocabulary with exactly one public runtime export is checked; exported destructuring patterns are excluded rather than undercounted."],
|
|
5382
5286
|
examples: [
|
|
5383
|
-
{ id: "responsibility-named-module", title: "Name the module after its export", outcome: "no-match", files: [{ path: "src/order
|
|
5287
|
+
{ id: "responsibility-named-module", title: "Name the module after its export", outcome: "no-match", files: [{ path: "src/parse-order.ts", source: "export function parseOrder() { return {}; }" }], focusPath: "src/parse-order.ts", expectedCount: 0, public: true },
|
|
5384
5288
|
{ id: "generic-module-name", title: "Do not hide one export in a generic module", outcome: "match", files: [{ path: "src/utils.ts", source: "export function parseOrder() { return {}; }" }], focusPath: "src/utils.ts", expectedCount: 1, public: true }
|
|
5385
5289
|
]
|
|
5386
5290
|
};
|
|
@@ -5441,6 +5345,7 @@ function runtimeExports(program) {
|
|
|
5441
5345
|
}
|
|
5442
5346
|
if (statement.declaration !== null) {
|
|
5443
5347
|
const declaration = statement.declaration;
|
|
5348
|
+
if (declaration.type === import_utils28.AST_NODE_TYPES.VariableDeclaration && declaration.declarations.some((item) => item.id.type !== import_utils28.AST_NODE_TYPES.Identifier)) ambiguous = true;
|
|
5444
5349
|
exports2.push(...declaredNames(declaration).map((name) => ({ key: name, name, node: declaration })));
|
|
5445
5350
|
}
|
|
5446
5351
|
for (const specifier of statement.specifiers) {
|
|
@@ -5629,7 +5534,7 @@ function tupleReturnType(node, aliases, resolving = /* @__PURE__ */ new Set()) {
|
|
|
5629
5534
|
return argument === void 0 ? null : tupleReturnType(argument, aliases, resolving);
|
|
5630
5535
|
}
|
|
5631
5536
|
if (node.type === import_utils30.AST_NODE_TYPES.TSTypeReference && node.typeName.type === import_utils30.AST_NODE_TYPES.Identifier && !resolving.has(node.typeName.name)) {
|
|
5632
|
-
const target = aliases.get(node.typeName
|
|
5537
|
+
const target = aliases.get(node.typeName);
|
|
5633
5538
|
if (target !== void 0) return tupleReturnType(target, aliases, /* @__PURE__ */ new Set([...resolving, node.typeName.name]));
|
|
5634
5539
|
}
|
|
5635
5540
|
if (node.type === import_utils30.AST_NODE_TYPES.TSTypeOperator && node.operator === "readonly") {
|
|
@@ -5721,20 +5626,27 @@ function exportedTypeNames(program) {
|
|
|
5721
5626
|
}
|
|
5722
5627
|
return names;
|
|
5723
5628
|
}
|
|
5724
|
-
function typeAliases(
|
|
5629
|
+
function typeAliases(sourceCode) {
|
|
5725
5630
|
const aliases = /* @__PURE__ */ new Map();
|
|
5726
|
-
for (const statement of
|
|
5631
|
+
for (const statement of sourceCode.ast.body) {
|
|
5727
5632
|
const declaration = statement.type === import_utils30.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
|
|
5728
5633
|
if (declaration?.type === import_utils30.AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
|
5729
|
-
aliases.set(declaration.id.name, declaration
|
|
5634
|
+
aliases.set(declaration.id.name, declaration);
|
|
5730
5635
|
}
|
|
5731
5636
|
}
|
|
5732
|
-
return
|
|
5637
|
+
return {
|
|
5638
|
+
get(identifier) {
|
|
5639
|
+
const declaration = aliases.get(identifier.name);
|
|
5640
|
+
if (declaration === void 0) return void 0;
|
|
5641
|
+
const binding = import_utils30.ASTUtils.findVariable(sourceCode.getScope(identifier), identifier.name);
|
|
5642
|
+
return binding?.defs.length === 1 && binding.defs[0]?.node === declaration ? declaration.typeAnnotation : void 0;
|
|
5643
|
+
}
|
|
5644
|
+
};
|
|
5733
5645
|
}
|
|
5734
5646
|
function callableReturnType(node, aliases, resolving = /* @__PURE__ */ new Set()) {
|
|
5735
5647
|
if (node.type === import_utils30.AST_NODE_TYPES.TSFunctionType) return node.returnType?.typeAnnotation ?? null;
|
|
5736
5648
|
if (node.type === import_utils30.AST_NODE_TYPES.TSTypeReference && node.typeName.type === import_utils30.AST_NODE_TYPES.Identifier && !resolving.has(node.typeName.name)) {
|
|
5737
|
-
const target = aliases.get(node.typeName
|
|
5649
|
+
const target = aliases.get(node.typeName);
|
|
5738
5650
|
if (target !== void 0) {
|
|
5739
5651
|
return callableReturnType(target, aliases, /* @__PURE__ */ new Set([...resolving, node.typeName.name]));
|
|
5740
5652
|
}
|
|
@@ -5863,7 +5775,7 @@ var no_positional_tuple_return_default = createRule({
|
|
|
5863
5775
|
context.sourceCode.ast,
|
|
5864
5776
|
exportedTypeNames(context.sourceCode.ast)
|
|
5865
5777
|
);
|
|
5866
|
-
const aliases = typeAliases(context.sourceCode
|
|
5778
|
+
const aliases = typeAliases(context.sourceCode);
|
|
5867
5779
|
const reportedFunctions = /* @__PURE__ */ new WeakSet();
|
|
5868
5780
|
const functionStack = [];
|
|
5869
5781
|
const report2 = (annotation, name) => {
|
|
@@ -6403,11 +6315,11 @@ var no_raw_fetch_outside_clients_default = createRule({
|
|
|
6403
6315
|
// src/rules/no-restricted-library-load.ts
|
|
6404
6316
|
var import_utils33 = require("@typescript-eslint/utils");
|
|
6405
6317
|
var NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION = {
|
|
6406
|
-
summary: "Apply
|
|
6407
|
-
rationale: "
|
|
6408
|
-
remediation: "
|
|
6318
|
+
summary: "Apply configured library restrictions to literal runtime loads and CommonJS resolution references.",
|
|
6319
|
+
rationale: "Dynamic imports, CommonJS loads, and package resolution checks can bypass library restrictions enforced for static imports.",
|
|
6320
|
+
remediation: "Use the configured replacement for the runtime dependency reference; resolution checks do not themselves load a module.",
|
|
6409
6321
|
category: "architecture",
|
|
6410
|
-
limitations: ["Only literal dynamic imports, unshadowed CommonJS loads, and TypeScript import-equals declarations are checked."],
|
|
6322
|
+
limitations: ["Only literal dynamic imports, unshadowed CommonJS loads/resolution calls, and runtime TypeScript import-equals declarations are checked; erased type imports are excluded. A configured restriction list is required."],
|
|
6411
6323
|
examples: [
|
|
6412
6324
|
{ id: "static-import", title: "Static imports remain the static-import rule's responsibility", outcome: "no-match", files: [{ path: "src/client.ts", source: "import axios from 'axios';" }], focusPath: "src/client.ts", expectedCount: 0, public: true },
|
|
6413
6325
|
{ id: "runtime-load", title: "Do not load a restricted library at runtime", outcome: "match", files: [{ path: "src/client.ts", source: "const client = require('axios');" }], focusPath: "src/client.ts", expectedCount: 1, public: true }
|
|
@@ -6425,7 +6337,7 @@ var no_restricted_library_load_default = createRule({
|
|
|
6425
6337
|
meta: {
|
|
6426
6338
|
type: "problem",
|
|
6427
6339
|
docs: {
|
|
6428
|
-
description:
|
|
6340
|
+
description: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION.summary
|
|
6429
6341
|
},
|
|
6430
6342
|
schema: [
|
|
6431
6343
|
{
|
|
@@ -6451,7 +6363,7 @@ var no_restricted_library_load_default = createRule({
|
|
|
6451
6363
|
}
|
|
6452
6364
|
],
|
|
6453
6365
|
messages: {
|
|
6454
|
-
restrictedLibraryLoad: "{{id}}: Replace runtime
|
|
6366
|
+
restrictedLibraryLoad: "{{id}}: Replace this runtime dependency reference to {{module}} with {{replacement}}.{{note}}"
|
|
6455
6367
|
}
|
|
6456
6368
|
},
|
|
6457
6369
|
defaultOptions: [{ libraries: [] }],
|
|
@@ -6497,6 +6409,7 @@ var no_restricted_library_load_default = createRule({
|
|
|
6497
6409
|
if (source !== null) report2(node.arguments[0], source);
|
|
6498
6410
|
},
|
|
6499
6411
|
TSImportEqualsDeclaration(node) {
|
|
6412
|
+
if (node.importKind === "type") return;
|
|
6500
6413
|
if (node.moduleReference.type !== import_utils33.AST_NODE_TYPES.TSExternalModuleReference) return;
|
|
6501
6414
|
const source = literalModule(node.moduleReference.expression);
|
|
6502
6415
|
if (source !== null) report2(node.moduleReference.expression, source);
|
|
@@ -7637,7 +7550,7 @@ var NO_SENTINEL_RETURN_ON_CATCH_DOCUMENTATION = {
|
|
|
7637
7550
|
rationale: "An unreported fallback makes operational failure indistinguishable from a legitimate empty result.",
|
|
7638
7551
|
remediation: "Rethrow, report the error before returning, or model expected absence with an explicit predicate, safe-parse, or result contract.",
|
|
7639
7552
|
category: "correctness",
|
|
7640
|
-
limitations: ["Recognized predicate, safe-parse, normal-path sentinel, deliberate parse, generated-client, and configured logging patterns are excluded."],
|
|
7553
|
+
limitations: ["Recognized predicate, safe-parse, normal-path sentinel, deliberate parse, generated-client, and configured logging patterns are excluded. Locally shadowed undefined bindings are not treated as sentinels; recognized handling patterns are not a proof that every control-flow path handles the error."],
|
|
7641
7554
|
examples: [
|
|
7642
7555
|
{ id: "reported-fallback", title: "Report an error before returning a fallback", outcome: "no-match", files: [{ path: "src/load.ts", source: "function load() { try { return read(); } catch (error) { logger.warn('load failed', error); return null; } }" }], focusPath: "src/load.ts", expectedCount: 0, public: true },
|
|
7643
7556
|
{ id: "silent-fallback", title: "Do not turn an unreported error into absence", outcome: "match", files: [{ path: "src/load.ts", source: "function load() { try { return read(); } catch { return null; } }" }], focusPath: "src/load.ts", expectedCount: 1, public: true }
|
|
@@ -8052,6 +7965,8 @@ var no_sentinel_return_on_catch_default = createRule({
|
|
|
8052
7965
|
if (!isSentinelArgument(last.argument)) {
|
|
8053
7966
|
return;
|
|
8054
7967
|
}
|
|
7968
|
+
const returned = unwrapSentinelExpression(last.argument);
|
|
7969
|
+
if (returned?.type === import_utils42.AST_NODE_TYPES.Identifier && returned.name === "undefined" && (import_utils42.ASTUtils.findVariable(context.sourceCode.getScope(returned), returned.name)?.defs.length ?? 0) > 0) return;
|
|
8055
7970
|
if (containsThrow(node.body)) {
|
|
8056
7971
|
return;
|
|
8057
7972
|
}
|
|
@@ -8501,12 +8416,13 @@ var no_storage_in_stateless_modules_default = createRule({
|
|
|
8501
8416
|
// src/rules/no-string-concat-in-loop.ts
|
|
8502
8417
|
var import_utils46 = require("@typescript-eslint/utils");
|
|
8503
8418
|
var NO_STRING_CONCAT_IN_LOOP_DOCUMENTATION = {
|
|
8504
|
-
summary: "
|
|
8419
|
+
summary: "Prefer collecting string fragments over repeatedly accumulating a growing string inside a loop.",
|
|
8505
8420
|
rationale: "Repeatedly rebuilding a growing string can copy all prior content on each iteration, making total work grow quadratically.",
|
|
8506
|
-
remediation: "
|
|
8421
|
+
remediation: "Consider collecting fragments and joining once; preserve intermediate observations and coercion timing, and measure hot paths.",
|
|
8507
8422
|
category: "performance",
|
|
8508
8423
|
limitations: [
|
|
8509
|
-
"Only local identifiers initialized with a string or template literal and accumulated in a loop body are inspected."
|
|
8424
|
+
"Only local identifiers initialized with a string or template literal and accumulated in a loop body are inspected.",
|
|
8425
|
+
"Deferred function bodies are excluded except recognized direct forEach callbacks. Syntax does not establish engine-specific string allocation complexity."
|
|
8510
8426
|
],
|
|
8511
8427
|
examples: [
|
|
8512
8428
|
{
|
|
@@ -8624,6 +8540,7 @@ function enclosingLoop(node) {
|
|
|
8624
8540
|
if ((parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression") && parent.parent.type === "CallExpression" && parent.parent.arguments[0] === parent && parent.parent.callee.type === "MemberExpression" && !parent.parent.callee.computed && parent.parent.callee.property.type === "Identifier" && parent.parent.callee.property.name === "forEach") {
|
|
8625
8541
|
return parent.parent;
|
|
8626
8542
|
}
|
|
8543
|
+
if (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") return null;
|
|
8627
8544
|
if (LOOP_NODE_TYPES.has(parent.type)) {
|
|
8628
8545
|
const loop = parent;
|
|
8629
8546
|
if (loop.body === child) {
|
|
@@ -8635,6 +8552,19 @@ function enclosingLoop(node) {
|
|
|
8635
8552
|
}
|
|
8636
8553
|
return null;
|
|
8637
8554
|
}
|
|
8555
|
+
function immediatelyExitsLoop(node, loop) {
|
|
8556
|
+
if (!LOOP_NODE_TYPES.has(loop.type) || node.parent.type !== "ExpressionStatement") return false;
|
|
8557
|
+
const statement = node.parent;
|
|
8558
|
+
const block = statement.parent;
|
|
8559
|
+
if (block.type !== "BlockStatement") return false;
|
|
8560
|
+
const next = block.body[block.body.indexOf(statement) + 1];
|
|
8561
|
+
if (next?.type !== "BreakStatement" && next?.type !== "ReturnStatement" && next?.type !== "ThrowStatement") return false;
|
|
8562
|
+
if (next.type === "BreakStatement" && next.label !== null) return false;
|
|
8563
|
+
for (let current = block; current !== void 0 && current !== loop; current = current.parent) {
|
|
8564
|
+
if (current.type === "TryStatement" || next.type === "BreakStatement" && current.type === "SwitchStatement") return false;
|
|
8565
|
+
}
|
|
8566
|
+
return true;
|
|
8567
|
+
}
|
|
8638
8568
|
function isSmallStaticForLoop(node) {
|
|
8639
8569
|
if (node.type !== "ForStatement" || node.init?.type !== "VariableDeclaration" || node.init.declarations.length !== 1 || node.test?.type !== "BinaryExpression" || node.test.operator !== "<" && node.test.operator !== "<=" || node.update?.type !== "UpdateExpression" || node.update.operator !== "++") {
|
|
8640
8570
|
return false;
|
|
@@ -8673,12 +8603,12 @@ var no_string_concat_in_loop_default = createRule({
|
|
|
8673
8603
|
meta: {
|
|
8674
8604
|
type: "suggestion",
|
|
8675
8605
|
docs: {
|
|
8676
|
-
description:
|
|
8606
|
+
description: NO_STRING_CONCAT_IN_LOOP_DOCUMENTATION.summary
|
|
8677
8607
|
},
|
|
8678
8608
|
schema: [],
|
|
8679
8609
|
messages: {
|
|
8680
|
-
noStringConcatInLoop:
|
|
8681
|
-
noStringReduce: "
|
|
8610
|
+
noStringConcatInLoop: "This loop repeatedly accumulates a growing string. Consider collecting fragments and joining once; preserve coercion timing and intermediate reads, and measure performance-sensitive paths.",
|
|
8611
|
+
noStringReduce: "This reduce repeatedly accumulates a growing string. Consider mapping fragments and joining once if coercion timing and intermediate observations are unchanged."
|
|
8682
8612
|
}
|
|
8683
8613
|
},
|
|
8684
8614
|
defaultOptions: [],
|
|
@@ -8705,6 +8635,7 @@ var no_string_concat_in_loop_default = createRule({
|
|
|
8705
8635
|
if (loop === null) {
|
|
8706
8636
|
return;
|
|
8707
8637
|
}
|
|
8638
|
+
if (immediatelyExitsLoop(node, loop)) return;
|
|
8708
8639
|
if (isSmallStaticForLoop(loop)) {
|
|
8709
8640
|
return;
|
|
8710
8641
|
}
|
|
@@ -10771,13 +10702,12 @@ var import_utils59 = require("@typescript-eslint/utils");
|
|
|
10771
10702
|
var PREFER_ECMASCRIPT_PRIVATE_MEMBERS_DOCUMENTATION = {
|
|
10772
10703
|
summary: "Prefer ECMAScript `#private` class members over TypeScript-only `private` members.",
|
|
10773
10704
|
rationale: "ECMAScript private names enforce encapsulation at runtime instead of erasing the boundary during compilation.",
|
|
10774
|
-
remediation: "
|
|
10705
|
+
remediation: "Review reflection, instance escape and framework contracts before replacing TypeScript privacy with ECMAScript private names and updating references.",
|
|
10775
10706
|
category: "maintainability",
|
|
10776
|
-
autofix: "
|
|
10707
|
+
autofix: "none",
|
|
10777
10708
|
limitations: [
|
|
10778
10709
|
"Ambient, abstract, computed, decorated, override, parameter-property, and generated declarations are excluded.",
|
|
10779
|
-
"
|
|
10780
|
-
"Overloads, modifier-adjacent comments, reflection, and any potentially cross-file or escaping class remain report-only."
|
|
10710
|
+
"Migration is report-only: type information cannot prove that instances or constructors never escape through this, or that reflection and framework serialization do not observe ordinary private properties."
|
|
10781
10711
|
],
|
|
10782
10712
|
references: ["https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_elements"],
|
|
10783
10713
|
examples: [
|
|
@@ -10797,19 +10727,11 @@ var PREFER_ECMASCRIPT_PRIVATE_MEMBERS_DOCUMENTATION = {
|
|
|
10797
10727
|
files: [{ path: "src/vault.ts", source: "class Vault { private read() { return 1; } open() { return this.read(); } }" }],
|
|
10798
10728
|
focusPath: "src/vault.ts",
|
|
10799
10729
|
expectedCount: 1,
|
|
10800
|
-
public: true
|
|
10801
|
-
fixedFiles: [{ path: "src/vault.ts", source: "class Vault { #read() { return 1; } open() { return this.#read(); } }" }]
|
|
10730
|
+
public: true
|
|
10802
10731
|
}
|
|
10803
10732
|
]
|
|
10804
10733
|
};
|
|
10805
|
-
function reportClass2(context,
|
|
10806
|
-
const parent = owner.parent;
|
|
10807
|
-
const directlyExported = parent.type === import_utils59.AST_NODE_TYPES.ExportNamedDeclaration || parent.type === import_utils59.AST_NODE_TYPES.ExportDefaultDeclaration;
|
|
10808
|
-
const locallyClosed = !directlyExported && owner.decorators.length === 0 && owner.type === import_utils59.AST_NODE_TYPES.ClassDeclaration && context.sourceCode.getDeclaredVariables(owner).every(
|
|
10809
|
-
(variable) => variable.references.every(
|
|
10810
|
-
(reference) => reference.identifier.range[0] >= owner.range[0] && reference.identifier.range[1] <= owner.range[1]
|
|
10811
|
-
)
|
|
10812
|
-
);
|
|
10734
|
+
function reportClass2(context, owner) {
|
|
10813
10735
|
const groups = /* @__PURE__ */ new Map();
|
|
10814
10736
|
for (const member of owner.body.body) {
|
|
10815
10737
|
if (!isConvertible(member)) continue;
|
|
@@ -10822,18 +10744,10 @@ function reportClass2(context, services, owner) {
|
|
|
10822
10744
|
for (const [name, members] of groups) {
|
|
10823
10745
|
const first = members[0];
|
|
10824
10746
|
if (first === void 0) continue;
|
|
10825
|
-
const fix = locallyClosed ? privateMemberFixes(
|
|
10826
|
-
context,
|
|
10827
|
-
services,
|
|
10828
|
-
owner,
|
|
10829
|
-
members,
|
|
10830
|
-
true
|
|
10831
|
-
) : void 0;
|
|
10832
10747
|
context.report({
|
|
10833
10748
|
node: first.key,
|
|
10834
10749
|
messageId: "preferEcmascriptPrivate",
|
|
10835
|
-
data: { name }
|
|
10836
|
-
...fix === void 0 ? {} : { fix }
|
|
10750
|
+
data: { name }
|
|
10837
10751
|
});
|
|
10838
10752
|
}
|
|
10839
10753
|
}
|
|
@@ -10847,7 +10761,6 @@ var prefer_ecmascript_private_members_default = createRule({
|
|
|
10847
10761
|
meta: {
|
|
10848
10762
|
type: "suggestion",
|
|
10849
10763
|
docs: { description: "Prefer ECMAScript `#private` class members over TypeScript-only `private` members." },
|
|
10850
|
-
fixable: "code",
|
|
10851
10764
|
schema: [],
|
|
10852
10765
|
messages: {
|
|
10853
10766
|
preferEcmascriptPrivate: "TypeScript `private {{name}}` is erased at runtime; use the ECMAScript private name `#{{name}}`."
|
|
@@ -10864,8 +10777,8 @@ var prefer_ecmascript_private_members_default = createRule({
|
|
|
10864
10777
|
}
|
|
10865
10778
|
if (services === null) return {};
|
|
10866
10779
|
return {
|
|
10867
|
-
ClassDeclaration: (node) => reportClass2(context,
|
|
10868
|
-
ClassExpression: (node) => reportClass2(context,
|
|
10780
|
+
ClassDeclaration: (node) => reportClass2(context, node),
|
|
10781
|
+
ClassExpression: (node) => reportClass2(context, node)
|
|
10869
10782
|
};
|
|
10870
10783
|
}
|
|
10871
10784
|
});
|
|
@@ -10875,10 +10788,10 @@ var import_utils60 = require("@typescript-eslint/utils");
|
|
|
10875
10788
|
var import_utils61 = require("@typescript-eslint/utils");
|
|
10876
10789
|
var PREFER_DISCRIMINATED_UNION_DOCUMENTATION = {
|
|
10877
10790
|
summary: "Flag flat result objects with a required positive boolean status and optional success/failure payloads.",
|
|
10878
|
-
rationale: "
|
|
10879
|
-
remediation: "
|
|
10791
|
+
rationale: "When success and failure are mutually exclusive outcomes, a boolean plus optional branch data permits contradictory and incomplete states.",
|
|
10792
|
+
remediation: "If the outcomes are mutually exclusive, represent each branch as a discriminated union member with its required payload.",
|
|
10880
10793
|
category: "correctness",
|
|
10881
|
-
limitations: ["Only local object shapes with recognized
|
|
10794
|
+
limitations: ["Only local object shapes with recognized non-computed status and payload names are inspected. Names do not prove that partial-success outcomes are forbidden; review the domain before changing its representation."],
|
|
10882
10795
|
examples: [
|
|
10883
10796
|
{ id: "explicit-result-branches", title: "Use explicit result branches", outcome: "no-match", files: [{ path: "src/result.ts", source: "type Result = { ok: true; data: string } | { ok: false; error: string };" }], focusPath: "src/result.ts", expectedCount: 0, public: true },
|
|
10884
10797
|
{ id: "optional-result-payloads", title: "Do not make both result payloads optional", outcome: "match", files: [{ path: "src/result.ts", source: "type Result = { ok: boolean; data?: string; error?: string };" }], focusPath: "src/result.ts", expectedCount: 1, public: true }
|
|
@@ -10942,7 +10855,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
|
10942
10855
|
return statusMemberCount === REQUIRED_STATUS_MEMBER_COUNT && hasFailurePayload && (hasSuccessPayload || !hasUnrecognizedMember);
|
|
10943
10856
|
}
|
|
10944
10857
|
function getMemberName(member) {
|
|
10945
|
-
if (member.type !== import_utils61.AST_NODE_TYPES.TSPropertySignature) {
|
|
10858
|
+
if (member.type !== import_utils61.AST_NODE_TYPES.TSPropertySignature || member.computed) {
|
|
10946
10859
|
return null;
|
|
10947
10860
|
}
|
|
10948
10861
|
const { key } = member;
|
|
@@ -10978,7 +10891,7 @@ var prefer_discriminated_union_default = createRule({
|
|
|
10978
10891
|
},
|
|
10979
10892
|
schema: [],
|
|
10980
10893
|
messages: {
|
|
10981
|
-
preferDiscriminatedUnion: "This object type
|
|
10894
|
+
preferDiscriminatedUnion: "This object type combines a boolean status with optional payloads. If success and failure are mutually exclusive, consider a discriminated union such as `{ ok: true; data: T } | { ok: false; error: E }`."
|
|
10982
10895
|
}
|
|
10983
10896
|
},
|
|
10984
10897
|
defaultOptions: [],
|
|
@@ -13128,7 +13041,7 @@ function isLiteralUnion(node) {
|
|
|
13128
13041
|
function exportedContract(node) {
|
|
13129
13042
|
let current = node;
|
|
13130
13043
|
while (current !== void 0) {
|
|
13131
|
-
if (current.type === import_utils70.AST_NODE_TYPES.
|
|
13044
|
+
if (current.type === import_utils70.AST_NODE_TYPES.TSTypeAliasDeclaration || current.type === import_utils70.AST_NODE_TYPES.TSInterfaceDeclaration) return current.parent.type === import_utils70.AST_NODE_TYPES.ExportNamedDeclaration;
|
|
13132
13045
|
if (current.type === import_utils70.AST_NODE_TYPES.Program) return false;
|
|
13133
13046
|
current = current.parent ?? void 0;
|
|
13134
13047
|
}
|
|
@@ -13226,7 +13139,7 @@ var PREFER_NATIVE_RANDOM_UUID_DOCUMENTATION = {
|
|
|
13226
13139
|
remediation: "Call `globalThis.crypto.randomUUID()` and remove the unused `uuid` v4 import when possible.",
|
|
13227
13140
|
category: "maintainability",
|
|
13228
13141
|
autofix: "suggestion",
|
|
13229
|
-
limitations: ["Only resolved zero-argument UUID v4 calls are reported; customized and other UUID versions are excluded."],
|
|
13142
|
+
limitations: ["Only resolved zero-argument UUID v4 calls are reported; customized and other UUID versions are excluded. Suggestions require unshadowed globalThis and comment-free calls; verify native randomUUID availability in the deployment runtime."],
|
|
13230
13143
|
examples: [
|
|
13231
13144
|
{ id: "native-random-uuid", title: "Use the platform UUID generator", outcome: "no-match", files: [{ path: "src/id.ts", source: "const id = globalThis.crypto.randomUUID();" }], focusPath: "src/id.ts", expectedCount: 0, public: true },
|
|
13232
13145
|
{ id: "uuid-v4-package", title: "Do not call uuid v4 without options", outcome: "match", files: [{ path: "src/id.ts", source: "import { v4 } from 'uuid'; const id = v4();" }], focusPath: "src/id.ts", expectedCount: 1, public: true }
|
|
@@ -13246,7 +13159,7 @@ var prefer_native_random_uuid_default = createRule({
|
|
|
13246
13159
|
hasSuggestions: true,
|
|
13247
13160
|
schema: [],
|
|
13248
13161
|
messages: {
|
|
13249
|
-
preferNative: "
|
|
13162
|
+
preferNative: "Where supported by the deployment runtime, prefer native `globalThis.crypto.randomUUID()` over the `uuid` package for UUID v4.",
|
|
13250
13163
|
replaceWithNative: "Replace this UUID v4 call with the native implementation."
|
|
13251
13164
|
}
|
|
13252
13165
|
},
|
|
@@ -13262,15 +13175,17 @@ var prefer_native_random_uuid_default = createRule({
|
|
|
13262
13175
|
if (variable !== null) destination.add(variable);
|
|
13263
13176
|
}
|
|
13264
13177
|
function report2(node) {
|
|
13178
|
+
const globalBinding = import_utils72.ASTUtils.findVariable(context.sourceCode.getScope(node), "globalThis");
|
|
13179
|
+
const canSuggest = (globalBinding?.defs.length ?? 0) === 0 && context.sourceCode.getCommentsInside(node).length === 0;
|
|
13265
13180
|
context.report({
|
|
13266
13181
|
node,
|
|
13267
13182
|
messageId: "preferNative",
|
|
13268
|
-
suggest: [
|
|
13183
|
+
suggest: canSuggest ? [
|
|
13269
13184
|
{
|
|
13270
13185
|
messageId: "replaceWithNative",
|
|
13271
13186
|
fix: (fixer) => fixer.replaceText(node, "globalThis.crypto.randomUUID()")
|
|
13272
13187
|
}
|
|
13273
|
-
]
|
|
13188
|
+
] : []
|
|
13274
13189
|
});
|
|
13275
13190
|
}
|
|
13276
13191
|
return {
|
|
@@ -14705,6 +14620,7 @@ var PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION = {
|
|
|
14705
14620
|
category: "maintainability",
|
|
14706
14621
|
limitations: [
|
|
14707
14622
|
"Only direct if/else-if chains with at least three strict-equality tests are reported.",
|
|
14623
|
+
"The discriminant must be a bare identifier; calls, getters, indexed reads and other repeatedly evaluated expressions are excluded. Review case-value effects, selector mutation, branch scoping, and break/continue targets when converting manually; this is not an equivalence proof.",
|
|
14708
14624
|
"Case values may be literals, enum-like member references, or upper-case named constants; dynamic expressions are excluded.",
|
|
14709
14625
|
"The rule deliberately ignores compound predicates, loose equality, ranges, and chains that compare different discriminants."
|
|
14710
14626
|
],
|
|
@@ -14718,7 +14634,8 @@ function discriminantText(sourceCode, test) {
|
|
|
14718
14634
|
const leftIsCase = isCaseValue(test.left);
|
|
14719
14635
|
const rightIsCase = isCaseValue(test.right);
|
|
14720
14636
|
if (leftIsCase === rightIsCase) return null;
|
|
14721
|
-
|
|
14637
|
+
const discriminant = leftIsCase ? test.right : test.left;
|
|
14638
|
+
return discriminant.type === import_utils80.AST_NODE_TYPES.Identifier ? sourceCode.getText(discriminant) : null;
|
|
14722
14639
|
}
|
|
14723
14640
|
function isCaseValue(node) {
|
|
14724
14641
|
if (node.type === import_utils80.AST_NODE_TYPES.Literal) return true;
|
|
@@ -16007,6 +15924,11 @@ var PREFER_ZOD_INFER_DOCUMENTATION = {
|
|
|
16007
15924
|
rationale: "A derived type stays synchronized when the runtime schema changes.",
|
|
16008
15925
|
remediation: "Replace the hand-written twin with `z.infer<typeof Schema>`.",
|
|
16009
15926
|
category: "correctness",
|
|
15927
|
+
limitations: [
|
|
15928
|
+
"Only module-level const schemas and module-level type declarations are paired; local declarations are excluded rather than matched by spelling across scopes.",
|
|
15929
|
+
"By default every field must positively agree; collection, nested-object and referenced-schema equivalence is not inferred from outer syntax alone.",
|
|
15930
|
+
"This is a bounded syntactic comparison, not general type equivalence. Review schema input versus output, interface augmentation, and separately evolving domain contracts before replacing a declaration."
|
|
15931
|
+
],
|
|
16010
15932
|
examples: [
|
|
16011
15933
|
{ id: "inferred-type", title: "Infer the schema type", outcome: "no-match", files: [{ path: "src/user.ts", source: 'import { z } from "zod"; const UserSchema = z.object({ id: z.string() }); type User = z.infer<typeof UserSchema>;' }], focusPath: "src/user.ts", expectedCount: 0, public: true },
|
|
16012
15934
|
{ id: "handwritten-twin", title: "Do not duplicate the schema shape", outcome: "match", files: [{ path: "src/user.ts", source: 'import { z } from "zod"; const UserSchema = z.object({ id: z.string() }); interface User { id: string }' }], focusPath: "src/user.ts", expectedCount: 1, public: true }
|
|
@@ -16186,6 +16108,10 @@ function sameDomain(left, right) {
|
|
|
16186
16108
|
function isExportedDeclaration(node) {
|
|
16187
16109
|
return node.parent?.type === import_utils85.AST_NODE_TYPES.ExportNamedDeclaration;
|
|
16188
16110
|
}
|
|
16111
|
+
function isModuleLevelDeclaration(node) {
|
|
16112
|
+
const parent = node.parent;
|
|
16113
|
+
return parent?.type === import_utils85.AST_NODE_TYPES.Program || parent?.type === import_utils85.AST_NODE_TYPES.ExportNamedDeclaration && parent.parent.type === import_utils85.AST_NODE_TYPES.Program;
|
|
16114
|
+
}
|
|
16189
16115
|
function isModuleLevelConst(node) {
|
|
16190
16116
|
const declaration = node.parent;
|
|
16191
16117
|
if (declaration.type !== import_utils85.AST_NODE_TYPES.VariableDeclaration || declaration.kind !== "const") {
|
|
@@ -16236,6 +16162,9 @@ function leafAgrees(field, annotation) {
|
|
|
16236
16162
|
return annotationDomain !== null && sameDomain(field.domain, annotationDomain);
|
|
16237
16163
|
}
|
|
16238
16164
|
const { leaf } = field;
|
|
16165
|
+
if (leaf !== null && ["array", "tuple", "object", "strictObject", "looseObject", "record", "map", "set", "promise", "intersection"].includes(leaf)) {
|
|
16166
|
+
return false;
|
|
16167
|
+
}
|
|
16239
16168
|
if (leaf === null || annotation === null) {
|
|
16240
16169
|
return null;
|
|
16241
16170
|
}
|
|
@@ -16528,7 +16457,6 @@ var prefer_zod_infer_default = createRule({
|
|
|
16528
16457
|
if (fields.size !== members.size) {
|
|
16529
16458
|
return false;
|
|
16530
16459
|
}
|
|
16531
|
-
let agreements = 0;
|
|
16532
16460
|
for (const [name, field] of fields) {
|
|
16533
16461
|
const member = members.get(name);
|
|
16534
16462
|
if (member === void 0) {
|
|
@@ -16547,14 +16475,11 @@ var prefer_zod_infer_default = createRule({
|
|
|
16547
16475
|
return false;
|
|
16548
16476
|
}
|
|
16549
16477
|
const agrees = leafAgrees(field, member.annotation);
|
|
16550
|
-
if (agrees
|
|
16478
|
+
if (agrees !== true) {
|
|
16551
16479
|
return false;
|
|
16552
16480
|
}
|
|
16553
|
-
if (agrees === true) {
|
|
16554
|
-
agreements += 1;
|
|
16555
|
-
}
|
|
16556
16481
|
}
|
|
16557
|
-
return
|
|
16482
|
+
return true;
|
|
16558
16483
|
}
|
|
16559
16484
|
return {
|
|
16560
16485
|
Program(node) {
|
|
@@ -16568,7 +16493,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
16568
16493
|
recordZodImport(node);
|
|
16569
16494
|
},
|
|
16570
16495
|
VariableDeclarator(node) {
|
|
16571
|
-
if (node.id.type !== import_utils85.AST_NODE_TYPES.Identifier || node.init == null) {
|
|
16496
|
+
if (node.id.type !== import_utils85.AST_NODE_TYPES.Identifier || node.init == null || !isModuleLevelConst(node)) {
|
|
16572
16497
|
return;
|
|
16573
16498
|
}
|
|
16574
16499
|
const fields = schemaFields(node.init);
|
|
@@ -16601,6 +16526,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
16601
16526
|
}
|
|
16602
16527
|
},
|
|
16603
16528
|
TSInterfaceDeclaration(node) {
|
|
16529
|
+
if (!isModuleLevelDeclaration(node)) return;
|
|
16604
16530
|
if (node.typeParameters !== void 0 || (node.extends?.length ?? 0) > 0) {
|
|
16605
16531
|
return;
|
|
16606
16532
|
}
|
|
@@ -16616,6 +16542,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
16616
16542
|
);
|
|
16617
16543
|
},
|
|
16618
16544
|
TSTypeAliasDeclaration(node) {
|
|
16545
|
+
if (!isModuleLevelDeclaration(node)) return;
|
|
16619
16546
|
const schemaName = inferredSchemaName(node.typeAnnotation);
|
|
16620
16547
|
if (schemaName !== null) {
|
|
16621
16548
|
inferredAliases.push({
|
|
@@ -16730,6 +16657,7 @@ var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
|
|
|
16730
16657
|
rationale: "An empty default silently accepts new union members instead of making the compiler identify the missing case.",
|
|
16731
16658
|
remediation: "Call `assertNever` with the discriminant in the exhaustive switch default.",
|
|
16732
16659
|
category: "correctness",
|
|
16660
|
+
limitations: ["Requires type information and singleton case values covering the current union. The helper must accept never to provide a compile-time check; its spelling alone is not a proof of that contract. Review the desired runtime behavior for unexpected external values."],
|
|
16733
16661
|
examples: [
|
|
16734
16662
|
{ id: "assert-never-default", title: "Make the default exhaustive", outcome: "no-match", files: [{ path: "src/render.ts", source: "declare const kind: 'a' | 'b';\nswitch (kind) { case 'a': break; case 'b': break; default: assertNever(kind); }" }], focusPath: "src/render.ts", expectedCount: 0, public: true },
|
|
16735
16663
|
{ id: "empty-default", title: "Do not leave an exhaustive default empty", outcome: "match", files: [{ path: "src/render.ts", source: "declare const kind: 'a' | 'b';\nswitch (kind) { case 'a': break; case 'b': break; default: }" }], focusPath: "src/render.ts", expectedCount: 1, public: true }
|
|
@@ -16786,11 +16714,9 @@ function isExhaustiveFiniteSwitch(node, services) {
|
|
|
16786
16714
|
if (caseNode.test === null) continue;
|
|
16787
16715
|
const test = services.esTreeNodeToTSNodeMap.get(caseNode.test);
|
|
16788
16716
|
const testType = checker.getTypeAtLocation(test);
|
|
16789
|
-
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
if (key !== null) handled.add(key);
|
|
16793
|
-
}
|
|
16717
|
+
if (testType.isUnion()) continue;
|
|
16718
|
+
const key = finiteTypeKey(testType, checker);
|
|
16719
|
+
if (key !== null) handled.add(key);
|
|
16794
16720
|
}
|
|
16795
16721
|
return [...expected].every((key) => handled.has(key));
|
|
16796
16722
|
}
|
|
@@ -17445,15 +17371,14 @@ var publicMethodNames = (body2, functionAliases) => {
|
|
|
17445
17371
|
if (member.static || member.accessibility === "private" || member.accessibility === "protected") continue;
|
|
17446
17372
|
if (member.key.type === import_utils89.AST_NODE_TYPES.PrivateIdentifier) continue;
|
|
17447
17373
|
if (member.value?.type !== import_utils89.AST_NODE_TYPES.ArrowFunctionExpression && member.value?.type !== import_utils89.AST_NODE_TYPES.FunctionExpression && member.typeAnnotation?.typeAnnotation.type !== import_utils89.AST_NODE_TYPES.TSFunctionType && !(member.typeAnnotation?.typeAnnotation.type === import_utils89.AST_NODE_TYPES.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === import_utils89.AST_NODE_TYPES.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name))) continue;
|
|
17448
|
-
names.push(member
|
|
17374
|
+
names.push(declaredMemberName(member) ?? "\u2026");
|
|
17449
17375
|
continue;
|
|
17450
17376
|
}
|
|
17451
17377
|
if (member.type !== import_utils89.AST_NODE_TYPES.MethodDefinition) continue;
|
|
17452
17378
|
if (member.kind !== "method" || member.static) continue;
|
|
17453
17379
|
if (member.accessibility === "private" || member.accessibility === "protected") continue;
|
|
17454
17380
|
if (member.key.type === import_utils89.AST_NODE_TYPES.PrivateIdentifier) continue;
|
|
17455
|
-
|
|
17456
|
-
else names.push("\u2026");
|
|
17381
|
+
names.push(declaredMemberName(member) ?? "\u2026");
|
|
17457
17382
|
}
|
|
17458
17383
|
return names;
|
|
17459
17384
|
};
|
|
@@ -17494,6 +17419,11 @@ function localClassAbstractness(program) {
|
|
|
17494
17419
|
}
|
|
17495
17420
|
return classes;
|
|
17496
17421
|
}
|
|
17422
|
+
function declaredMemberName(member) {
|
|
17423
|
+
if (!member.computed && member.key.type === import_utils89.AST_NODE_TYPES.Identifier) return member.key.name;
|
|
17424
|
+
if (member.key.type === import_utils89.AST_NODE_TYPES.Literal && typeof member.key.value === "string") return member.key.value;
|
|
17425
|
+
return null;
|
|
17426
|
+
}
|
|
17497
17427
|
function localInterfaceSurfaces(program) {
|
|
17498
17428
|
const interfaces = /* @__PURE__ */ new Map();
|
|
17499
17429
|
const parents = /* @__PURE__ */ new Map();
|
|
@@ -17516,14 +17446,15 @@ function localInterfaceSurfaces(program) {
|
|
|
17516
17446
|
if (part.type !== import_utils89.AST_NODE_TYPES.TSTypeLiteral) continue;
|
|
17517
17447
|
for (const member of part.members) {
|
|
17518
17448
|
if (member.type !== import_utils89.AST_NODE_TYPES.TSMethodSignature && member.type !== import_utils89.AST_NODE_TYPES.TSPropertySignature) continue;
|
|
17519
|
-
|
|
17449
|
+
const name = declaredMemberName(member);
|
|
17450
|
+
if (name === null) continue;
|
|
17520
17451
|
if (member.type === import_utils89.AST_NODE_TYPES.TSMethodSignature) {
|
|
17521
|
-
callables2.add(
|
|
17452
|
+
callables2.add(name);
|
|
17522
17453
|
continue;
|
|
17523
17454
|
}
|
|
17524
17455
|
if (member.type !== import_utils89.AST_NODE_TYPES.TSPropertySignature) continue;
|
|
17525
17456
|
const annotation = member.typeAnnotation?.typeAnnotation;
|
|
17526
|
-
if (annotation?.type === import_utils89.AST_NODE_TYPES.TSFunctionType || annotation?.type === import_utils89.AST_NODE_TYPES.TSTypeReference && annotation.typeName.type === import_utils89.AST_NODE_TYPES.Identifier && functionAliases.has(annotation.typeName.name)) callables2.add(
|
|
17457
|
+
if (annotation?.type === import_utils89.AST_NODE_TYPES.TSFunctionType || annotation?.type === import_utils89.AST_NODE_TYPES.TSTypeReference && annotation.typeName.type === import_utils89.AST_NODE_TYPES.Identifier && functionAliases.has(annotation.typeName.name)) callables2.add(name);
|
|
17527
17458
|
}
|
|
17528
17459
|
}
|
|
17529
17460
|
interfaces.set(declaration.id.name, callables2);
|
|
@@ -17534,8 +17465,9 @@ function localInterfaceSurfaces(program) {
|
|
|
17534
17465
|
const callables = interfaces.get(declaration.id.name) ?? /* @__PURE__ */ new Set();
|
|
17535
17466
|
for (const member of declaration.body.body) {
|
|
17536
17467
|
if (member.type !== import_utils89.AST_NODE_TYPES.TSMethodSignature && member.type !== import_utils89.AST_NODE_TYPES.TSPropertySignature) continue;
|
|
17537
|
-
|
|
17538
|
-
if (
|
|
17468
|
+
const name = declaredMemberName(member);
|
|
17469
|
+
if (name === null) continue;
|
|
17470
|
+
if (member.type === import_utils89.AST_NODE_TYPES.TSMethodSignature || member.typeAnnotation?.typeAnnotation.type === import_utils89.AST_NODE_TYPES.TSFunctionType || member.typeAnnotation?.typeAnnotation.type === import_utils89.AST_NODE_TYPES.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === import_utils89.AST_NODE_TYPES.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name)) callables.add(name);
|
|
17539
17471
|
}
|
|
17540
17472
|
interfaces.set(declaration.id.name, callables);
|
|
17541
17473
|
parents.set(
|
|
@@ -18751,15 +18683,15 @@ function referencedPropertyName(node) {
|
|
|
18751
18683
|
if (!node.computed && node.property.type === import_utils96.AST_NODE_TYPES.Identifier) return node.property.name;
|
|
18752
18684
|
return node.computed && node.property.type === import_utils96.AST_NODE_TYPES.Literal && typeof node.property.value === "string" ? node.property.value : null;
|
|
18753
18685
|
}
|
|
18754
|
-
function
|
|
18686
|
+
function walk(node, visitorKeys, visit, nestedFunction = false) {
|
|
18755
18687
|
visit(node, nestedFunction);
|
|
18756
18688
|
const nested = nestedFunction || isFunction(node);
|
|
18757
18689
|
for (const key of visitorKeys[node.type] ?? []) {
|
|
18758
18690
|
const child = node[key];
|
|
18759
18691
|
if (Array.isArray(child)) {
|
|
18760
|
-
for (const item of child) if (typeof item === "object" && item !== null && "type" in item)
|
|
18692
|
+
for (const item of child) if (typeof item === "object" && item !== null && "type" in item) walk(item, visitorKeys, visit, nested);
|
|
18761
18693
|
} else if (typeof child === "object" && child !== null && "type" in child) {
|
|
18762
|
-
|
|
18694
|
+
walk(child, visitorKeys, visit, nested);
|
|
18763
18695
|
}
|
|
18764
18696
|
}
|
|
18765
18697
|
}
|
|
@@ -18807,7 +18739,7 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
18807
18739
|
const parameterDecoratorNodes = /* @__PURE__ */ new Set();
|
|
18808
18740
|
for (const parameter of method.value.params) {
|
|
18809
18741
|
for (const decorator of parameter.decorators) {
|
|
18810
|
-
|
|
18742
|
+
walk(decorator, context.sourceCode.visitorKeys, (current) => parameterDecoratorNodes.add(current));
|
|
18811
18743
|
}
|
|
18812
18744
|
}
|
|
18813
18745
|
const thisValue = (value) => {
|
|
@@ -18839,10 +18771,10 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
18839
18771
|
}
|
|
18840
18772
|
};
|
|
18841
18773
|
for (const parameter of method.value.params) {
|
|
18842
|
-
|
|
18774
|
+
walk(parameter, context.sourceCode.visitorKeys, collectAlias);
|
|
18843
18775
|
}
|
|
18844
18776
|
for (const statement of method.value.body.body) {
|
|
18845
|
-
|
|
18777
|
+
walk(statement, context.sourceCode.visitorKeys, collectAlias);
|
|
18846
18778
|
}
|
|
18847
18779
|
const visitCall = (current, nestedFunction) => {
|
|
18848
18780
|
if (current.type === import_utils96.AST_NODE_TYPES.VariableDeclarator && current.id.type === import_utils96.AST_NODE_TYPES.ObjectPattern && thisValue(current.init)) {
|
|
@@ -18876,19 +18808,19 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
18876
18808
|
calls.set(caller, callees);
|
|
18877
18809
|
};
|
|
18878
18810
|
for (const decorator of method.decorators) {
|
|
18879
|
-
|
|
18811
|
+
walk(decorator, context.sourceCode.visitorKeys, visitCall, true);
|
|
18880
18812
|
}
|
|
18881
|
-
if (method.computed)
|
|
18813
|
+
if (method.computed) walk(method.key, context.sourceCode.visitorKeys, visitCall, true);
|
|
18882
18814
|
for (const parameter of method.value.params) {
|
|
18883
|
-
|
|
18815
|
+
walk(parameter, context.sourceCode.visitorKeys, visitCall);
|
|
18884
18816
|
}
|
|
18885
18817
|
for (const statement of method.value.body.body) {
|
|
18886
|
-
|
|
18818
|
+
walk(statement, context.sourceCode.visitorKeys, visitCall);
|
|
18887
18819
|
}
|
|
18888
18820
|
}
|
|
18889
18821
|
for (const member of node.body.body) {
|
|
18890
18822
|
if (member.type === import_utils96.AST_NODE_TYPES.MethodDefinition || member.type === import_utils96.AST_NODE_TYPES.TSAbstractMethodDefinition) continue;
|
|
18891
|
-
|
|
18823
|
+
walk(member, context.sourceCode.visitorKeys, (current) => {
|
|
18892
18824
|
if (current.type !== import_utils96.AST_NODE_TYPES.MemberExpression) return;
|
|
18893
18825
|
const target = referencedMethod(context, current, classVariables);
|
|
18894
18826
|
const possibleTarget = target ?? referencedPropertyName(current);
|
|
@@ -18978,7 +18910,7 @@ var stepdown_default = createRule({
|
|
|
18978
18910
|
"Program:exit": (program) => {
|
|
18979
18911
|
moduleScope(context, program);
|
|
18980
18912
|
const computedReferenceNames = /* @__PURE__ */ new Set();
|
|
18981
|
-
|
|
18913
|
+
walk(program, context.sourceCode.visitorKeys, (node) => {
|
|
18982
18914
|
if (node.type === import_utils96.AST_NODE_TYPES.MemberExpression && node.computed && node.property.type === import_utils96.AST_NODE_TYPES.Literal && typeof node.property.value === "string") computedReferenceNames.add(node.property.value);
|
|
18983
18915
|
});
|
|
18984
18916
|
for (const node of classes) classScope(context, node, computedReferenceNames);
|
|
@@ -19892,7 +19824,7 @@ var RULES = {
|
|
|
19892
19824
|
};
|
|
19893
19825
|
var meta = {
|
|
19894
19826
|
name: "@sarj/eslint-plugin",
|
|
19895
|
-
version: "15.17.
|
|
19827
|
+
version: "15.17.10"
|
|
19896
19828
|
};
|
|
19897
19829
|
var APPLICATION_ONLY_RULES = [];
|
|
19898
19830
|
var LIBRARY_IMPORT_POLICY = ["error", {
|