@sarj/eslint-plugin 16.6.0 → 16.7.0
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 +151 -63
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +226 -138
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -52,7 +52,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
52
52
|
// package.json
|
|
53
53
|
var package_default = {
|
|
54
54
|
name: "@sarj/eslint-plugin",
|
|
55
|
-
version: "16.
|
|
55
|
+
version: "16.7.0",
|
|
56
56
|
packageManager: "npm@12.1.0",
|
|
57
57
|
description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
58
58
|
type: "module",
|
|
@@ -470,8 +470,9 @@ function commentLineEnd(sourceText, start) {
|
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
// src/rules/require-explicit-contract-implementation.ts
|
|
473
|
+
var ESCAPED_CLASSES = /* @__PURE__ */ new WeakMap();
|
|
473
474
|
var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
|
|
474
|
-
defaultLevel: "
|
|
475
|
+
defaultLevel: "error",
|
|
475
476
|
summary: "Require nominal inheritance when an injected abstract class is rejected by an instanceof guard.",
|
|
476
477
|
rationale: "A structurally assignable fake can still fail a constructor's nominal runtime guard. Pure structural interfaces do not require an implements clause.",
|
|
477
478
|
remediation: "Use an implementation inheriting the existing abstract class, or remove the nominal guard if the boundary is intentionally structural.",
|
|
@@ -479,8 +480,8 @@ var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
|
|
|
479
480
|
autofix: "none",
|
|
480
481
|
limitations: [
|
|
481
482
|
"Requires direct construction of both owned consumer and collaborator classes, with a first-statement consumer constructor guard rejecting the exact parameter with if (!(parameter instanceof Contract)) throw.",
|
|
482
|
-
"The contract must resolve to an abstract class without decorators, unresolved ancestors, or custom computed static members in its resolved hierarchy.",
|
|
483
|
-
"Structural interfaces, non-rejecting branches, reassignment before the guard, casts, unresolved heritage, dynamic factories, explicit implementation constructors or initializers, modules referencing prototype-mutator members or assigning prototypes, and third-party classes are excluded."
|
|
483
|
+
"The contract must resolve to an abstract class without decorators, static blocks, unresolved ancestors, or custom computed static members in its resolved hierarchy. Escaped class constructors are checked across every owned module in the typed program.",
|
|
484
|
+
"Structural interfaces, non-rejecting branches, reassignment before the guard, casts, unresolved heritage, dynamic factories, implementation static blocks, explicit implementation constructors or initializers, involved modules referencing prototype-mutator members or assigning prototypes, escaped class constructors, and third-party classes are excluded."
|
|
484
485
|
],
|
|
485
486
|
examples: [
|
|
486
487
|
{
|
|
@@ -503,6 +504,115 @@ var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
|
|
|
503
504
|
}
|
|
504
505
|
]
|
|
505
506
|
};
|
|
507
|
+
function hasPrototypeMutation(source) {
|
|
508
|
+
function visit(node) {
|
|
509
|
+
const member = memberName(node);
|
|
510
|
+
if (member === "setPrototypeOf" || member === "__proto__" || member === "hasInstance") return true;
|
|
511
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && memberName(node.left) === "prototype") return true;
|
|
512
|
+
return ts.forEachChild(node, visit);
|
|
513
|
+
}
|
|
514
|
+
return visit(source) === true;
|
|
515
|
+
}
|
|
516
|
+
function memberName(node) {
|
|
517
|
+
if (ts.isPropertyAccessExpression(node)) return node.name.text;
|
|
518
|
+
if (ts.isElementAccessExpression(node) && ts.isStringLiteralLike(node.argumentExpression)) return node.argumentExpression.text;
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
function ownedSource(source) {
|
|
522
|
+
return !source.isDeclarationFile && !/(?:^|[/\\])(?:node_modules|vendor|vendored|generated|dist)(?:[/\\])/u.test(source.fileName) && !isGeneratedFile(source.fileName, source.text);
|
|
523
|
+
}
|
|
524
|
+
function escapedClasses(program, checker) {
|
|
525
|
+
const cached = ESCAPED_CLASSES.get(program);
|
|
526
|
+
if (cached !== void 0) return cached;
|
|
527
|
+
const escaped = /* @__PURE__ */ new Set();
|
|
528
|
+
const namespaceValues = /* @__PURE__ */ new Map();
|
|
529
|
+
function visit(node) {
|
|
530
|
+
if (ts.isTypeNode(node) || ts.isImportDeclaration(node)) return;
|
|
531
|
+
if (ts.isIdentifier(node) || ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
|
|
532
|
+
recordEscapedReference(checker, node, escaped, namespaceValues);
|
|
533
|
+
}
|
|
534
|
+
ts.forEachChild(node, visit);
|
|
535
|
+
}
|
|
536
|
+
for (const source of program.getSourceFiles()) if (ownedSource(source)) visit(source);
|
|
537
|
+
ESCAPED_CLASSES.set(program, escaped);
|
|
538
|
+
return escaped;
|
|
539
|
+
}
|
|
540
|
+
function recordEscapedReference(checker, node, escaped, namespaceValues) {
|
|
541
|
+
const symbol = canonicalSymbol(checker, node);
|
|
542
|
+
if (symbol !== void 0) {
|
|
543
|
+
let values = namespaceValues.get(symbol);
|
|
544
|
+
if (values === void 0) {
|
|
545
|
+
values = ownedClassValues(checker, symbol);
|
|
546
|
+
namespaceValues.set(symbol, values);
|
|
547
|
+
}
|
|
548
|
+
if (!namespacePrefix(symbol, node) && !safeClassReference(node)) for (const value of values) escaped.add(value);
|
|
549
|
+
}
|
|
550
|
+
if (ts.isElementAccessExpression(node) && !safeClassReference(node)) {
|
|
551
|
+
const receiver = canonicalSymbol(checker, node.expression) ?? checker.getTypeAtLocation(node.expression).getSymbol();
|
|
552
|
+
if (receiver !== void 0) for (const value of ownedClassValues(checker, receiver)) escaped.add(value);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function ownedClassValues(checker, original, seen = /* @__PURE__ */ new Set()) {
|
|
556
|
+
const symbol = original.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(original) : original;
|
|
557
|
+
const values = /* @__PURE__ */ new Set();
|
|
558
|
+
if (seen.has(symbol)) return values;
|
|
559
|
+
seen.add(symbol);
|
|
560
|
+
if (symbol.declarations?.some((declaration) => ts.isClassDeclaration(declaration) && ownedSource(declaration.getSourceFile()))) values.add(symbol);
|
|
561
|
+
if (symbol.declarations?.some((declaration) => (ts.isSourceFile(declaration) || ts.isModuleDeclaration(declaration)) && ownedSource(declaration.getSourceFile()))) {
|
|
562
|
+
for (const exported of checker.getExportsOfModule(symbol)) {
|
|
563
|
+
for (const value of ownedClassValues(checker, exported, seen)) values.add(value);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return values;
|
|
567
|
+
}
|
|
568
|
+
function safeClassReference(node) {
|
|
569
|
+
let reference = ts.isPropertyAccessExpression(node.parent) && node.parent.name === node ? node.parent : node;
|
|
570
|
+
while (ts.isParenthesizedExpression(reference.parent)) reference = reference.parent;
|
|
571
|
+
const parent = reference.parent;
|
|
572
|
+
return ts.isClassDeclaration(parent) && parent.name === reference || ts.isNewExpression(parent) && parent.expression === reference || ts.isExpressionWithTypeArguments(parent) && parent.expression === reference || ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword && parent.right === reference;
|
|
573
|
+
}
|
|
574
|
+
function namespacePrefix(symbol, node) {
|
|
575
|
+
const parent = node.parent;
|
|
576
|
+
const memberCall = (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && ts.isCallExpression(parent.parent) && parent.parent.expression === parent;
|
|
577
|
+
return !symbol.declarations?.some(ts.isClassDeclaration) && (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && parent.expression === node && !memberCall;
|
|
578
|
+
}
|
|
579
|
+
function closedNominalBoundary(program, checker, call, consumer, missing) {
|
|
580
|
+
const { implementation, contractSymbol } = missing;
|
|
581
|
+
const implementationSymbol = implementation.name === void 0 ? void 0 : canonicalSymbol(checker, implementation.name);
|
|
582
|
+
const consumerSymbol = consumer.name === void 0 ? void 0 : canonicalSymbol(checker, consumer.name);
|
|
583
|
+
if (implementationSymbol === void 0 || consumerSymbol === void 0) return false;
|
|
584
|
+
const contract = contractSymbol.declarations?.find(ts.isClassDeclaration);
|
|
585
|
+
if (contract === void 0) return false;
|
|
586
|
+
const targets = /* @__PURE__ */ new Set([consumerSymbol, ...classHierarchySymbols(checker, contract), ...classHierarchySymbols(checker, implementation)]);
|
|
587
|
+
const sources = /* @__PURE__ */ new Set([call.getSourceFile(), consumer.getSourceFile(), implementation.getSourceFile(), ...contractSymbol.declarations?.map((item) => item.getSourceFile()) ?? []]);
|
|
588
|
+
return ![...sources].some(hasPrototypeMutation) && ![...targets].some((target) => escapedClasses(program, checker).has(target));
|
|
589
|
+
}
|
|
590
|
+
function classHierarchySymbols(checker, declaration, seen = /* @__PURE__ */ new Set()) {
|
|
591
|
+
const symbol = declaration.name === void 0 ? void 0 : canonicalSymbol(checker, declaration.name);
|
|
592
|
+
if (symbol === void 0 || seen.has(symbol)) return seen;
|
|
593
|
+
seen.add(symbol);
|
|
594
|
+
for (const clause of declaration.heritageClauses ?? []) {
|
|
595
|
+
if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue;
|
|
596
|
+
for (const parent of clause.types) {
|
|
597
|
+
const ancestor = canonicalSymbol(checker, parent.expression)?.declarations?.find(ts.isClassDeclaration);
|
|
598
|
+
if (ancestor !== void 0) classHierarchySymbols(checker, ancestor, seen);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return seen;
|
|
602
|
+
}
|
|
603
|
+
function missingImplementation(checker, signature, parameter, call, argument) {
|
|
604
|
+
const parameterType = checker.getTypeOfSymbolAtLocation(parameter, call);
|
|
605
|
+
const contractType = behavioralContract(checker, parameterType);
|
|
606
|
+
if (contractType === null) return null;
|
|
607
|
+
const contractSymbol = contractType.getSymbol();
|
|
608
|
+
if (contractSymbol === void 0 || !hasNominalRejectionGuard(checker, signature, parameter, contractSymbol)) return null;
|
|
609
|
+
const actualType = checker.getTypeAtLocation(argument);
|
|
610
|
+
if (!checker.isTypeAssignableTo(actualType, contractType)) return null;
|
|
611
|
+
const implementation = ownedClass(checker, argument);
|
|
612
|
+
if (implementation === null) return null;
|
|
613
|
+
if (nominallyInherits(checker, implementation, contractSymbol, /* @__PURE__ */ new Set()) !== false) return null;
|
|
614
|
+
return { implementation, contractSymbol };
|
|
615
|
+
}
|
|
506
616
|
function behavioralContract(checker, type) {
|
|
507
617
|
if (type.isUnion()) {
|
|
508
618
|
const substantive = type.types.filter((member) => (member.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) === 0);
|
|
@@ -527,23 +637,9 @@ function ownedClass(checker, expression) {
|
|
|
527
637
|
if (declaration === void 0 || declaration !== constructed || declaration.getSourceFile().isDeclarationFile || /(?:^|[/\\])(?:node_modules|vendor|generated)(?:[/\\])/u.test(declaration.getSourceFile().fileName)) return null;
|
|
528
638
|
return declaration;
|
|
529
639
|
}
|
|
530
|
-
function memberName(node) {
|
|
531
|
-
if (ts.isPropertyAccessExpression(node)) return node.name.text;
|
|
532
|
-
if (ts.isElementAccessExpression(node) && ts.isStringLiteralLike(node.argumentExpression)) return node.argumentExpression.text;
|
|
533
|
-
return null;
|
|
534
|
-
}
|
|
535
|
-
function hasPrototypeMutation(source) {
|
|
536
|
-
function visit(node) {
|
|
537
|
-
const member = memberName(node);
|
|
538
|
-
if (member === "setPrototypeOf" || member === "__proto__" || member === "hasInstance") return true;
|
|
539
|
-
if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && memberName(node.left) === "prototype") return true;
|
|
540
|
-
return ts.forEachChild(node, visit);
|
|
541
|
-
}
|
|
542
|
-
return visit(source) === true;
|
|
543
|
-
}
|
|
544
640
|
function nominallyInherits(checker, declaration, target, seen) {
|
|
545
641
|
if (ts.canHaveDecorators(declaration) && ts.getDecorators(declaration)?.length) return null;
|
|
546
|
-
if (hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some((member) => ts.isConstructorDeclaration(member) || ts.isPropertyDeclaration(member) && member.initializer !== void 0)) return null;
|
|
642
|
+
if (hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some((member) => ts.isConstructorDeclaration(member) || ts.isClassStaticBlockDeclaration(member) || ts.isPropertyDeclaration(member) && member.initializer !== void 0)) return null;
|
|
547
643
|
const symbol = declaration.name === void 0 ? void 0 : canonicalSymbol(checker, declaration.name);
|
|
548
644
|
if (symbol !== void 0) {
|
|
549
645
|
if (seen.has(symbol)) return null;
|
|
@@ -558,10 +654,6 @@ function nominallyInherits(checker, declaration, target, seen) {
|
|
|
558
654
|
const inherited = parentSymbol.declarations?.find(ts.isClassDeclaration);
|
|
559
655
|
return inherited === void 0 ? null : nominallyInherits(checker, inherited, target, new Set(seen));
|
|
560
656
|
}
|
|
561
|
-
function canonicalSymbol(checker, node) {
|
|
562
|
-
const symbol = checker.getSymbolAtLocation(node);
|
|
563
|
-
return symbol === void 0 ? void 0 : (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
|
|
564
|
-
}
|
|
565
657
|
function hasNominalRejectionGuard(checker, signature, parameter, contract) {
|
|
566
658
|
const declaration = signature.getDeclaration();
|
|
567
659
|
if (declaration === void 0 || !ts.isConstructorDeclaration(declaration)) return false;
|
|
@@ -586,7 +678,7 @@ function alwaysThrows(statement) {
|
|
|
586
678
|
return ts.isThrowStatement(statement) || ts.isBlock(statement) && statement.statements.length === 1 && ts.isThrowStatement(statement.statements[0]);
|
|
587
679
|
}
|
|
588
680
|
function hasOrdinaryInstanceCheck(checker, declaration, seen) {
|
|
589
|
-
if (seen.has(declaration) || ts.getDecorators(declaration)?.length || hasPrototypeMutation(declaration.getSourceFile())) return false;
|
|
681
|
+
if (seen.has(declaration) || ts.getDecorators(declaration)?.length || hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some(ts.isClassStaticBlockDeclaration)) return false;
|
|
590
682
|
seen.add(declaration);
|
|
591
683
|
if (declaration.members.some((member) => member.name !== void 0 && ts.isComputedPropertyName(member.name) && ts.canHaveModifiers(member) && ts.getModifiers(member)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword))) return false;
|
|
592
684
|
for (const clause of declaration.heritageClauses ?? []) {
|
|
@@ -598,6 +690,10 @@ function hasOrdinaryInstanceCheck(checker, declaration, seen) {
|
|
|
598
690
|
}
|
|
599
691
|
return true;
|
|
600
692
|
}
|
|
693
|
+
function canonicalSymbol(checker, node) {
|
|
694
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
695
|
+
return symbol === void 0 ? void 0 : (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
|
|
696
|
+
}
|
|
601
697
|
var require_explicit_contract_implementation_default = createRule({
|
|
602
698
|
name: "require-explicit-contract-implementation",
|
|
603
699
|
documentation: REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION,
|
|
@@ -627,22 +723,13 @@ var require_explicit_contract_implementation_default = createRule({
|
|
|
627
723
|
if (argument.type !== import_utils2.AST_NODE_TYPES.NewExpression) continue;
|
|
628
724
|
const parameter = parameters[index];
|
|
629
725
|
if (parameter === void 0) continue;
|
|
630
|
-
const parameterType = checker.getTypeOfSymbolAtLocation(parameter, tsNode);
|
|
631
|
-
const contractType = behavioralContract(checker, parameterType);
|
|
632
|
-
if (contractType === null) continue;
|
|
633
|
-
const contractSymbol = contractType.getSymbol();
|
|
634
|
-
if (contractSymbol === void 0 || !hasNominalRejectionGuard(checker, signature, parameter, contractSymbol)) continue;
|
|
635
726
|
const tsArgument = services.esTreeNodeToTSNodeMap.get(argument);
|
|
636
|
-
const
|
|
637
|
-
if (!
|
|
638
|
-
const implementation = ownedClass(checker, tsArgument);
|
|
639
|
-
if (implementation === null) continue;
|
|
640
|
-
const relationship = nominallyInherits(checker, implementation, contractSymbol, /* @__PURE__ */ new Set());
|
|
641
|
-
if (relationship !== false) continue;
|
|
727
|
+
const missing = missingImplementation(checker, signature, parameter, tsNode, tsArgument);
|
|
728
|
+
if (missing === null || !closedNominalBoundary(services.program, checker, tsNode, consumer, missing)) continue;
|
|
642
729
|
context.report({
|
|
643
730
|
node: argument,
|
|
644
731
|
messageId: "declareActualContract",
|
|
645
|
-
data: { implementation: implementation.name?.text ?? "class", contract: contractSymbol.getName() }
|
|
732
|
+
data: { implementation: missing.implementation.name?.text ?? "class", contract: missing.contractSymbol.getName() }
|
|
646
733
|
});
|
|
647
734
|
}
|
|
648
735
|
}
|
|
@@ -17714,14 +17801,14 @@ var prefer_named_callback_domain_default = createRule({
|
|
|
17714
17801
|
// src/rules/prefer-named-complex-return-type.ts
|
|
17715
17802
|
var import_utils101 = require("@typescript-eslint/utils");
|
|
17716
17803
|
var PREFER_NAMED_COMPLEX_RETURN_TYPE_DOCUMENTATION = {
|
|
17717
|
-
defaultLevel: "
|
|
17804
|
+
defaultLevel: "error",
|
|
17718
17805
|
summary: "Prefer a named contract for structurally complex function return types.",
|
|
17719
17806
|
rationale: "A large inline return annotation hides a reusable domain concept and makes signatures difficult to scan.",
|
|
17720
17807
|
remediation: "Name the complex nested shape while preserving its generic wrappers and type parameters; reference the named contract from the return annotation.",
|
|
17721
17808
|
category: "maintainability",
|
|
17722
17809
|
limitations: [
|
|
17723
17810
|
"Only explicit object types with at least three members and unions with at least three object variants are reported.",
|
|
17724
|
-
"Any single-argument generic wrapper is traversed to find nested shapes, not assumed semantically transparent. Inferred return types are outside this rule; extraction is manual and must preserve locally bound type parameters."
|
|
17811
|
+
"Any single-argument generic wrapper is traversed to find nested shapes, not assumed semantically transparent. Inferred return types are outside this rule; extraction is manual and must preserve locally bound type parameters with generic named contracts. Types depending on polymorphic this or a local value query are excluded."
|
|
17725
17812
|
],
|
|
17726
17813
|
examples: [
|
|
17727
17814
|
{ id: "named-result", title: "Name a multi-state result", outcome: "no-match", files: [{ path: "src/queue.ts", source: "type ClaimResult = { state: 'idle' } | { state: 'waiting'; retryAt: number } | { state: 'claimed'; id: string }; export function claim(): ClaimResult { return { state: 'idle' }; }" }], focusPath: "src/queue.ts", expectedCount: 0, public: true },
|
|
@@ -17737,10 +17824,13 @@ function unwrap4(node) {
|
|
|
17737
17824
|
}
|
|
17738
17825
|
function report(context, node) {
|
|
17739
17826
|
const annotation = node.returnType?.typeAnnotation;
|
|
17740
|
-
if (annotation !== void 0 && isComplex(annotation)) {
|
|
17827
|
+
if (annotation !== void 0 && isComplex(annotation) && !hasValueDependency(annotation)) {
|
|
17741
17828
|
context.report({ node: annotation, messageId: "nameComplexReturnType" });
|
|
17742
17829
|
}
|
|
17743
17830
|
}
|
|
17831
|
+
function hasValueDependency(node) {
|
|
17832
|
+
return node.type === import_utils101.AST_NODE_TYPES.TSThisType || node.type === import_utils101.AST_NODE_TYPES.TSTypeQuery || forEachOwnAstChild(node, hasValueDependency);
|
|
17833
|
+
}
|
|
17744
17834
|
function isComplex(node) {
|
|
17745
17835
|
const type = unwrap4(node);
|
|
17746
17836
|
if (type.type === import_utils101.AST_NODE_TYPES.TSTypeLiteral) return type.members.length >= 3;
|
|
@@ -19388,20 +19478,20 @@ var prefer_shared_zod_enum_default = createRule({
|
|
|
19388
19478
|
// src/rules/prefer-switch-for-repeated-equality.ts
|
|
19389
19479
|
var import_utils110 = require("@typescript-eslint/utils");
|
|
19390
19480
|
var PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION = {
|
|
19391
|
-
defaultLevel: "
|
|
19481
|
+
defaultLevel: "error",
|
|
19392
19482
|
summary: "Prefer switch over long if/else-if chains that compare one value for strict equality.",
|
|
19393
19483
|
rationale: "A switch makes finite dispatch cases visually uniform and easier to extend without duplicating the discriminant.",
|
|
19394
19484
|
remediation: "Replace three or more strict-equality branches over the same discriminant with a switch; keep if statements for ranges, guards, and heterogeneous predicates.",
|
|
19395
19485
|
category: "maintainability",
|
|
19396
19486
|
limitations: [
|
|
19397
19487
|
"Only direct if/else-if chains with at least three strict-equality tests are reported.",
|
|
19398
|
-
"The discriminant must be a
|
|
19399
|
-
"Case values
|
|
19488
|
+
"The discriminant must be a resolved lexical variable or parameter; unresolved globals, calls, getters, and indexed reads are excluded. Preserve branch scopes and break/continue targets when converting manually; no autofix is offered.",
|
|
19489
|
+
"Case values must be primitive literals. Member references and named constants are excluded because evaluating them can observe getters or mutate the selector. Generated sources are excluded.",
|
|
19400
19490
|
"The rule deliberately ignores compound predicates, loose equality, ranges, and chains that compare different discriminants."
|
|
19401
19491
|
],
|
|
19402
19492
|
examples: [
|
|
19403
19493
|
{ id: "switch-dispatch", title: "Make finite dispatch explicit", outcome: "no-match", files: [{ path: "src/render.ts", source: "switch (kind) { case 'a': return a(); case 'b': return b(); case 'c': return c(); default: return fallback(); }" }], focusPath: "src/render.ts", expectedCount: 0, public: true },
|
|
19404
|
-
{ id: "repeated-equality", title: "Avoid repeating the discriminant", outcome: "match", files: [{ path: "src/render.ts", source: "if (kind === 'a') return a(); else if (kind === 'b') return b(); else if (kind === 'c') return c();" }], focusPath: "src/render.ts", expectedCount: 1, public: true },
|
|
19494
|
+
{ id: "repeated-equality", title: "Avoid repeating the discriminant", outcome: "match", files: [{ path: "src/render.ts", source: "function render(kind: string) { if (kind === 'a') return a(); else if (kind === 'b') return b(); else if (kind === 'c') return c(); }" }], focusPath: "src/render.ts", expectedCount: 1, public: true },
|
|
19405
19495
|
{ id: "escaped-middle", scenarioId: "native-discriminant", title: "Use native identifier identity", outcome: "match", files: [{ path: "src/dispatch.ts", source: `function probe(kind){if(kind==='a')return 1;else if(\\u006bind==='b')return 2;else if(kind==='c')return 3;return 0;}
|
|
19406
19496
|
console.log(JSON.stringify(["a","b","c","d"].map(probe)));` }], focusPath: "src/dispatch.ts", expectedCount: 1, public: true },
|
|
19407
19497
|
{ id: "different-discriminants", scenarioId: "native-discriminant", title: "Use native identifier identity", outcome: "no-match", files: [{ path: "src/dispatch.ts", source: `function probe(kind){const other="other";if(kind==='a')return 1;else if(other==='b')return 2;else if(kind==='c')return 3;return 0;}
|
|
@@ -19417,10 +19507,7 @@ function discriminantName(test) {
|
|
|
19417
19507
|
return discriminant.type === import_utils110.AST_NODE_TYPES.Identifier ? discriminant.name : null;
|
|
19418
19508
|
}
|
|
19419
19509
|
function isCaseValue(node) {
|
|
19420
|
-
|
|
19421
|
-
if (node.type === import_utils110.AST_NODE_TYPES.Identifier) return /^[A-Z][A-Z0-9_]*$/u.test(node.name);
|
|
19422
|
-
if (node.type !== import_utils110.AST_NODE_TYPES.MemberExpression || node.computed) return false;
|
|
19423
|
-
return node.property.type === import_utils110.AST_NODE_TYPES.Identifier && (node.object.type === import_utils110.AST_NODE_TYPES.Identifier || isCaseValue(node.object));
|
|
19510
|
+
return node.type === import_utils110.AST_NODE_TYPES.Literal && !("regex" in node);
|
|
19424
19511
|
}
|
|
19425
19512
|
var prefer_switch_for_repeated_equality_default = createRule({
|
|
19426
19513
|
name: "prefer-switch-for-repeated-equality",
|
|
@@ -19435,11 +19522,16 @@ var prefer_switch_for_repeated_equality_default = createRule({
|
|
|
19435
19522
|
},
|
|
19436
19523
|
defaultOptions: [],
|
|
19437
19524
|
create(context) {
|
|
19525
|
+
if (isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
19438
19526
|
return {
|
|
19439
19527
|
IfStatement(node) {
|
|
19440
19528
|
if (node.parent.type === import_utils110.AST_NODE_TYPES.IfStatement && node.parent.alternate === node) return;
|
|
19441
19529
|
const first = discriminantName(node.test);
|
|
19442
19530
|
if (first === null) return;
|
|
19531
|
+
const binding = import_utils110.ASTUtils.findVariable(context.sourceCode.getScope(node), first);
|
|
19532
|
+
if (binding === null || binding.defs.length !== 1 || binding.scope.type === "global") return;
|
|
19533
|
+
const [definition] = binding.defs;
|
|
19534
|
+
if (definition?.type !== "Parameter" && definition?.type !== "Variable") return;
|
|
19443
19535
|
let count = 1;
|
|
19444
19536
|
let current = node.alternate;
|
|
19445
19537
|
while (current?.type === import_utils110.AST_NODE_TYPES.IfStatement) {
|
|
@@ -21446,17 +21538,17 @@ var UNRESOLVED_TYPE_NODES = /* @__PURE__ */ new Set([
|
|
|
21446
21538
|
import_utils116.AST_NODE_TYPES.TSUnknownKeyword
|
|
21447
21539
|
]);
|
|
21448
21540
|
var NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION = {
|
|
21449
|
-
defaultLevel: "
|
|
21541
|
+
defaultLevel: "error",
|
|
21450
21542
|
summary: "Reference a named Zod record child's complete schema type instead of repeating its explicit annotation.",
|
|
21451
21543
|
rationale: "Repeating a child schema's generic contract creates a second maintained declaration even though the record already uses that child at runtime.",
|
|
21452
|
-
remediation: "Replace only the matching record type argument with `typeof ChildSchema
|
|
21544
|
+
remediation: "Replace only the matching record type argument with `typeof ChildSchema`, or share one explicit named schema type alias between child and record to retain an independently named public contract. Keep the outer annotation required by isolatedDeclarations and every runtime schema operation.",
|
|
21453
21545
|
category: "maintainability",
|
|
21454
21546
|
autofix: "none",
|
|
21455
21547
|
limitations: [
|
|
21456
21548
|
"Only direct module-level const z.record calls with two arguments, a ZodRecord annotation, and an earlier local const child with a complete explicit Zod type are inspected.",
|
|
21457
21549
|
"The entire generic child annotation must match token for token; input/output, defaults, transforms, readonly modifiers and brands are never compared by output shape alone.",
|
|
21458
21550
|
"Bare leaf types, broad ZodType constraints, type queries, imported or unqualified type references, annotation cycles, comments on the repeated argument, mutable bindings and generated files are excluded.",
|
|
21459
|
-
"Import aliases and namespace imports resolve through scope bindings. Independent public contract pins
|
|
21551
|
+
"Import aliases and namespace imports resolve through scope bindings. Independent public contract pins can use one shared named type alias or an exact reasoned suppression; runtime validation and outer annotations are preserved."
|
|
21460
21552
|
],
|
|
21461
21553
|
examples: [
|
|
21462
21554
|
{ id: "named-child", title: "Reference the named child contract", outcome: "no-match", files: [{ path: "src/record.ts", source: 'import { z } from "zod"; const KeySchema: z.ZodEnum<{ a: "a"; b: "b" }> = z.enum(["a", "b"]); export const RecordSchema: z.ZodRecord<typeof KeySchema, z.ZodString> = z.record(KeySchema, z.string());' }], focusPath: "src/record.ts", expectedCount: 0, public: true },
|
|
@@ -21475,7 +21567,7 @@ var named_child_schema_type_default = createRule({
|
|
|
21475
21567
|
type: "suggestion",
|
|
21476
21568
|
docs: { description: NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION.summary },
|
|
21477
21569
|
schema: [],
|
|
21478
|
-
messages: { namedChildType: "Use `typeof {{name}}` for this exact child contract; keep the outer schema annotation and runtime operations." }
|
|
21570
|
+
messages: { namedChildType: "Use `typeof {{name}}` or one shared named type alias for this exact child contract; keep the outer schema annotation and runtime operations." }
|
|
21479
21571
|
},
|
|
21480
21572
|
defaultOptions: [],
|
|
21481
21573
|
create(context) {
|
|
@@ -24875,7 +24967,6 @@ var LIBRARY_IMPORT_POLICY = ["error", {
|
|
|
24875
24967
|
}];
|
|
24876
24968
|
var ADVISORY_RULES = [
|
|
24877
24969
|
"@sarj/excessive-commentary",
|
|
24878
|
-
"@sarj/named-child-schema-type",
|
|
24879
24970
|
"@sarj/no-bespoke-api-case-conversion",
|
|
24880
24971
|
"@sarj/no-duplicate-test-case",
|
|
24881
24972
|
"@sarj/no-json-stringify-object-equality",
|
|
@@ -24884,21 +24975,18 @@ var ADVISORY_RULES = [
|
|
|
24884
24975
|
"@sarj/prefer-millisecond-control-duration-schema",
|
|
24885
24976
|
"@sarj/prefer-module-level-refined-schema",
|
|
24886
24977
|
"@sarj/prefer-multi-value-zod-literal",
|
|
24887
|
-
"@sarj/prefer-named-complex-return-type",
|
|
24888
24978
|
"@sarj/prefer-node-crypto-hash",
|
|
24889
24979
|
"@sarj/prefer-node-fs-promises",
|
|
24890
24980
|
"@sarj/prefer-nominal-id-types",
|
|
24891
24981
|
"@sarj/prefer-shared-zod-enum",
|
|
24892
|
-
"@sarj/prefer-switch-for-repeated-equality",
|
|
24893
24982
|
"@sarj/prefer-whole-object-assertion",
|
|
24894
24983
|
"@sarj/require-camelcase-properties",
|
|
24895
|
-
"@sarj/require-explicit-contract-implementation",
|
|
24896
24984
|
"@sarj/require-explicit-service-contract",
|
|
24897
24985
|
"@sarj/require-interface-for-exported-class",
|
|
24898
24986
|
"@sarj/require-sql-access-class"
|
|
24899
24987
|
];
|
|
24900
24988
|
var RECOMMENDED_RULES = {
|
|
24901
|
-
"@sarj/named-child-schema-type": "
|
|
24989
|
+
"@sarj/named-child-schema-type": "error",
|
|
24902
24990
|
"@sarj/no-conditional-empty-object-spread": "error",
|
|
24903
24991
|
"@sarj/prefer-typed-reflection": "error",
|
|
24904
24992
|
"@sarj/no-broad-return-type": "error",
|
|
@@ -24982,7 +25070,7 @@ var RECOMMENDED_RULES = {
|
|
|
24982
25070
|
"@sarj/prefer-multi-value-zod-literal": ["warn", { zodMajorVersion: 4 }],
|
|
24983
25071
|
"@sarj/prefer-named-callback-domain": "error",
|
|
24984
25072
|
"@sarj/prefer-nominal-id-types": "warn",
|
|
24985
|
-
"@sarj/prefer-named-complex-return-type": "
|
|
25073
|
+
"@sarj/prefer-named-complex-return-type": "error",
|
|
24986
25074
|
"@sarj/prefer-node-crypto-hash": "warn",
|
|
24987
25075
|
"@sarj/prefer-node-fs-promises": "warn",
|
|
24988
25076
|
"@sarj/prefer-non-nullable-collection": "error",
|
|
@@ -24990,7 +25078,7 @@ var RECOMMENDED_RULES = {
|
|
|
24990
25078
|
"@sarj/prefer-await-in-async-return": "error",
|
|
24991
25079
|
"@sarj/prefer-schema-for-api-payload": "error",
|
|
24992
25080
|
"@sarj/prefer-shared-zod-enum": "warn",
|
|
24993
|
-
"@sarj/prefer-switch-for-repeated-equality": "
|
|
25081
|
+
"@sarj/prefer-switch-for-repeated-equality": "error",
|
|
24994
25082
|
"@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
|
|
24995
25083
|
"@sarj/prefer-server-actions": "error",
|
|
24996
25084
|
"@sarj/prefer-whole-object-assertion": "warn",
|
|
@@ -24999,7 +25087,7 @@ var RECOMMENDED_RULES = {
|
|
|
24999
25087
|
"@sarj/prefer-zod-parse-output-type": "error",
|
|
25000
25088
|
"@sarj/require-assert-never": "error",
|
|
25001
25089
|
"@sarj/require-fetch-timeout": "error",
|
|
25002
|
-
"@sarj/require-explicit-contract-implementation": "
|
|
25090
|
+
"@sarj/require-explicit-contract-implementation": "error",
|
|
25003
25091
|
"@sarj/require-explicit-service-contract": "warn",
|
|
25004
25092
|
"@sarj/require-interface-for-exported-class": "warn",
|
|
25005
25093
|
"@sarj/require-port-for-service": "error",
|
|
@@ -25016,7 +25104,7 @@ var RECOMMENDED_RULES = {
|
|
|
25016
25104
|
"@sarj/require-pascal-case-zod-schema-name": "error"
|
|
25017
25105
|
};
|
|
25018
25106
|
var STRICT_RULES = {
|
|
25019
|
-
"@sarj/named-child-schema-type": "
|
|
25107
|
+
"@sarj/named-child-schema-type": "error",
|
|
25020
25108
|
"@sarj/no-conditional-empty-object-spread": "error",
|
|
25021
25109
|
"@sarj/prefer-typed-reflection": "error",
|
|
25022
25110
|
"@sarj/no-broad-return-type": "error",
|
|
@@ -25104,7 +25192,7 @@ var STRICT_RULES = {
|
|
|
25104
25192
|
"@sarj/prefer-multi-value-zod-literal": ["warn", { zodMajorVersion: 4 }],
|
|
25105
25193
|
"@sarj/prefer-named-callback-domain": "error",
|
|
25106
25194
|
"@sarj/prefer-nominal-id-types": "warn",
|
|
25107
|
-
"@sarj/prefer-named-complex-return-type": "
|
|
25195
|
+
"@sarj/prefer-named-complex-return-type": "error",
|
|
25108
25196
|
"@sarj/prefer-node-crypto-hash": "warn",
|
|
25109
25197
|
"@sarj/prefer-node-fs-promises": "warn",
|
|
25110
25198
|
"@sarj/prefer-non-nullable-collection": "error",
|
|
@@ -25112,7 +25200,7 @@ var STRICT_RULES = {
|
|
|
25112
25200
|
"@sarj/prefer-await-in-async-return": "error",
|
|
25113
25201
|
"@sarj/prefer-schema-for-api-payload": "error",
|
|
25114
25202
|
"@sarj/prefer-shared-zod-enum": "warn",
|
|
25115
|
-
"@sarj/prefer-switch-for-repeated-equality": "
|
|
25203
|
+
"@sarj/prefer-switch-for-repeated-equality": "error",
|
|
25116
25204
|
"@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
|
|
25117
25205
|
"@sarj/prefer-server-actions": "error",
|
|
25118
25206
|
"@sarj/prefer-whole-object-assertion": "warn",
|
|
@@ -25121,7 +25209,7 @@ var STRICT_RULES = {
|
|
|
25121
25209
|
"@sarj/prefer-zod-parse-output-type": "error",
|
|
25122
25210
|
"@sarj/require-assert-never": "error",
|
|
25123
25211
|
"@sarj/require-fetch-timeout": "error",
|
|
25124
|
-
"@sarj/require-explicit-contract-implementation": "
|
|
25212
|
+
"@sarj/require-explicit-contract-implementation": "error",
|
|
25125
25213
|
"@sarj/require-explicit-service-contract": "warn",
|
|
25126
25214
|
"@sarj/require-interface-for-exported-class": "warn",
|
|
25127
25215
|
"@sarj/require-port-for-service": "error",
|
package/dist/index.d.cts
CHANGED
|
@@ -291,9 +291,9 @@ declare const RULES: {
|
|
|
291
291
|
/** @deprecated All repositories use one policy; retained for import compatibility. */
|
|
292
292
|
declare const APPLICATION_ONLY_RULES: readonly [];
|
|
293
293
|
/** Rules staged as non-blocking warnings while corpus adoption evidence accumulates. */
|
|
294
|
-
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/
|
|
294
|
+
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/no-duplicate-test-case", "@sarj/no-json-stringify-object-equality", "@sarj/no-restated-comment", "@sarj/no-restated-jsdoc", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nominal-id-types", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-whole-object-assertion", "@sarj/require-camelcase-properties", "@sarj/require-explicit-service-contract", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class"];
|
|
295
295
|
declare const RECOMMENDED_RULES: {
|
|
296
|
-
readonly "@sarj/named-child-schema-type": "
|
|
296
|
+
readonly "@sarj/named-child-schema-type": "error";
|
|
297
297
|
readonly "@sarj/no-conditional-empty-object-spread": "error";
|
|
298
298
|
readonly "@sarj/prefer-typed-reflection": "error";
|
|
299
299
|
readonly "@sarj/no-broad-return-type": "error";
|
|
@@ -570,7 +570,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
570
570
|
}];
|
|
571
571
|
readonly "@sarj/prefer-named-callback-domain": "error";
|
|
572
572
|
readonly "@sarj/prefer-nominal-id-types": "warn";
|
|
573
|
-
readonly "@sarj/prefer-named-complex-return-type": "
|
|
573
|
+
readonly "@sarj/prefer-named-complex-return-type": "error";
|
|
574
574
|
readonly "@sarj/prefer-node-crypto-hash": "warn";
|
|
575
575
|
readonly "@sarj/prefer-node-fs-promises": "warn";
|
|
576
576
|
readonly "@sarj/prefer-non-nullable-collection": "error";
|
|
@@ -578,7 +578,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
578
578
|
readonly "@sarj/prefer-await-in-async-return": "error";
|
|
579
579
|
readonly "@sarj/prefer-schema-for-api-payload": "error";
|
|
580
580
|
readonly "@sarj/prefer-shared-zod-enum": "warn";
|
|
581
|
-
readonly "@sarj/prefer-switch-for-repeated-equality": "
|
|
581
|
+
readonly "@sarj/prefer-switch-for-repeated-equality": "error";
|
|
582
582
|
readonly "@sarj/prefer-semantic-colors": readonly ["error", {
|
|
583
583
|
readonly requireSemanticTokens: true;
|
|
584
584
|
}];
|
|
@@ -589,7 +589,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
589
589
|
readonly "@sarj/prefer-zod-parse-output-type": "error";
|
|
590
590
|
readonly "@sarj/require-assert-never": "error";
|
|
591
591
|
readonly "@sarj/require-fetch-timeout": "error";
|
|
592
|
-
readonly "@sarj/require-explicit-contract-implementation": "
|
|
592
|
+
readonly "@sarj/require-explicit-contract-implementation": "error";
|
|
593
593
|
readonly "@sarj/require-explicit-service-contract": "warn";
|
|
594
594
|
readonly "@sarj/require-interface-for-exported-class": "warn";
|
|
595
595
|
readonly "@sarj/require-port-for-service": "error";
|
|
@@ -606,7 +606,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
606
606
|
readonly "@sarj/require-pascal-case-zod-schema-name": "error";
|
|
607
607
|
};
|
|
608
608
|
declare const STRICT_RULES: {
|
|
609
|
-
readonly "@sarj/named-child-schema-type": "
|
|
609
|
+
readonly "@sarj/named-child-schema-type": "error";
|
|
610
610
|
readonly "@sarj/no-conditional-empty-object-spread": "error";
|
|
611
611
|
readonly "@sarj/prefer-typed-reflection": "error";
|
|
612
612
|
readonly "@sarj/no-broad-return-type": "error";
|
|
@@ -887,7 +887,7 @@ declare const STRICT_RULES: {
|
|
|
887
887
|
}];
|
|
888
888
|
readonly "@sarj/prefer-named-callback-domain": "error";
|
|
889
889
|
readonly "@sarj/prefer-nominal-id-types": "warn";
|
|
890
|
-
readonly "@sarj/prefer-named-complex-return-type": "
|
|
890
|
+
readonly "@sarj/prefer-named-complex-return-type": "error";
|
|
891
891
|
readonly "@sarj/prefer-node-crypto-hash": "warn";
|
|
892
892
|
readonly "@sarj/prefer-node-fs-promises": "warn";
|
|
893
893
|
readonly "@sarj/prefer-non-nullable-collection": "error";
|
|
@@ -895,7 +895,7 @@ declare const STRICT_RULES: {
|
|
|
895
895
|
readonly "@sarj/prefer-await-in-async-return": "error";
|
|
896
896
|
readonly "@sarj/prefer-schema-for-api-payload": "error";
|
|
897
897
|
readonly "@sarj/prefer-shared-zod-enum": "warn";
|
|
898
|
-
readonly "@sarj/prefer-switch-for-repeated-equality": "
|
|
898
|
+
readonly "@sarj/prefer-switch-for-repeated-equality": "error";
|
|
899
899
|
readonly "@sarj/prefer-semantic-colors": readonly ["error", {
|
|
900
900
|
readonly requireSemanticTokens: true;
|
|
901
901
|
}];
|
|
@@ -906,7 +906,7 @@ declare const STRICT_RULES: {
|
|
|
906
906
|
readonly "@sarj/prefer-zod-parse-output-type": "error";
|
|
907
907
|
readonly "@sarj/require-assert-never": "error";
|
|
908
908
|
readonly "@sarj/require-fetch-timeout": "error";
|
|
909
|
-
readonly "@sarj/require-explicit-contract-implementation": "
|
|
909
|
+
readonly "@sarj/require-explicit-contract-implementation": "error";
|
|
910
910
|
readonly "@sarj/require-explicit-service-contract": "warn";
|
|
911
911
|
readonly "@sarj/require-interface-for-exported-class": "warn";
|
|
912
912
|
readonly "@sarj/require-port-for-service": "error";
|
package/dist/index.d.ts
CHANGED
|
@@ -291,9 +291,9 @@ declare const RULES: {
|
|
|
291
291
|
/** @deprecated All repositories use one policy; retained for import compatibility. */
|
|
292
292
|
declare const APPLICATION_ONLY_RULES: readonly [];
|
|
293
293
|
/** Rules staged as non-blocking warnings while corpus adoption evidence accumulates. */
|
|
294
|
-
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/
|
|
294
|
+
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/no-duplicate-test-case", "@sarj/no-json-stringify-object-equality", "@sarj/no-restated-comment", "@sarj/no-restated-jsdoc", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nominal-id-types", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-whole-object-assertion", "@sarj/require-camelcase-properties", "@sarj/require-explicit-service-contract", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class"];
|
|
295
295
|
declare const RECOMMENDED_RULES: {
|
|
296
|
-
readonly "@sarj/named-child-schema-type": "
|
|
296
|
+
readonly "@sarj/named-child-schema-type": "error";
|
|
297
297
|
readonly "@sarj/no-conditional-empty-object-spread": "error";
|
|
298
298
|
readonly "@sarj/prefer-typed-reflection": "error";
|
|
299
299
|
readonly "@sarj/no-broad-return-type": "error";
|
|
@@ -570,7 +570,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
570
570
|
}];
|
|
571
571
|
readonly "@sarj/prefer-named-callback-domain": "error";
|
|
572
572
|
readonly "@sarj/prefer-nominal-id-types": "warn";
|
|
573
|
-
readonly "@sarj/prefer-named-complex-return-type": "
|
|
573
|
+
readonly "@sarj/prefer-named-complex-return-type": "error";
|
|
574
574
|
readonly "@sarj/prefer-node-crypto-hash": "warn";
|
|
575
575
|
readonly "@sarj/prefer-node-fs-promises": "warn";
|
|
576
576
|
readonly "@sarj/prefer-non-nullable-collection": "error";
|
|
@@ -578,7 +578,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
578
578
|
readonly "@sarj/prefer-await-in-async-return": "error";
|
|
579
579
|
readonly "@sarj/prefer-schema-for-api-payload": "error";
|
|
580
580
|
readonly "@sarj/prefer-shared-zod-enum": "warn";
|
|
581
|
-
readonly "@sarj/prefer-switch-for-repeated-equality": "
|
|
581
|
+
readonly "@sarj/prefer-switch-for-repeated-equality": "error";
|
|
582
582
|
readonly "@sarj/prefer-semantic-colors": readonly ["error", {
|
|
583
583
|
readonly requireSemanticTokens: true;
|
|
584
584
|
}];
|
|
@@ -589,7 +589,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
589
589
|
readonly "@sarj/prefer-zod-parse-output-type": "error";
|
|
590
590
|
readonly "@sarj/require-assert-never": "error";
|
|
591
591
|
readonly "@sarj/require-fetch-timeout": "error";
|
|
592
|
-
readonly "@sarj/require-explicit-contract-implementation": "
|
|
592
|
+
readonly "@sarj/require-explicit-contract-implementation": "error";
|
|
593
593
|
readonly "@sarj/require-explicit-service-contract": "warn";
|
|
594
594
|
readonly "@sarj/require-interface-for-exported-class": "warn";
|
|
595
595
|
readonly "@sarj/require-port-for-service": "error";
|
|
@@ -606,7 +606,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
606
606
|
readonly "@sarj/require-pascal-case-zod-schema-name": "error";
|
|
607
607
|
};
|
|
608
608
|
declare const STRICT_RULES: {
|
|
609
|
-
readonly "@sarj/named-child-schema-type": "
|
|
609
|
+
readonly "@sarj/named-child-schema-type": "error";
|
|
610
610
|
readonly "@sarj/no-conditional-empty-object-spread": "error";
|
|
611
611
|
readonly "@sarj/prefer-typed-reflection": "error";
|
|
612
612
|
readonly "@sarj/no-broad-return-type": "error";
|
|
@@ -887,7 +887,7 @@ declare const STRICT_RULES: {
|
|
|
887
887
|
}];
|
|
888
888
|
readonly "@sarj/prefer-named-callback-domain": "error";
|
|
889
889
|
readonly "@sarj/prefer-nominal-id-types": "warn";
|
|
890
|
-
readonly "@sarj/prefer-named-complex-return-type": "
|
|
890
|
+
readonly "@sarj/prefer-named-complex-return-type": "error";
|
|
891
891
|
readonly "@sarj/prefer-node-crypto-hash": "warn";
|
|
892
892
|
readonly "@sarj/prefer-node-fs-promises": "warn";
|
|
893
893
|
readonly "@sarj/prefer-non-nullable-collection": "error";
|
|
@@ -895,7 +895,7 @@ declare const STRICT_RULES: {
|
|
|
895
895
|
readonly "@sarj/prefer-await-in-async-return": "error";
|
|
896
896
|
readonly "@sarj/prefer-schema-for-api-payload": "error";
|
|
897
897
|
readonly "@sarj/prefer-shared-zod-enum": "warn";
|
|
898
|
-
readonly "@sarj/prefer-switch-for-repeated-equality": "
|
|
898
|
+
readonly "@sarj/prefer-switch-for-repeated-equality": "error";
|
|
899
899
|
readonly "@sarj/prefer-semantic-colors": readonly ["error", {
|
|
900
900
|
readonly requireSemanticTokens: true;
|
|
901
901
|
}];
|
|
@@ -906,7 +906,7 @@ declare const STRICT_RULES: {
|
|
|
906
906
|
readonly "@sarj/prefer-zod-parse-output-type": "error";
|
|
907
907
|
readonly "@sarj/require-assert-never": "error";
|
|
908
908
|
readonly "@sarj/require-fetch-timeout": "error";
|
|
909
|
-
readonly "@sarj/require-explicit-contract-implementation": "
|
|
909
|
+
readonly "@sarj/require-explicit-contract-implementation": "error";
|
|
910
910
|
readonly "@sarj/require-explicit-service-contract": "warn";
|
|
911
911
|
readonly "@sarj/require-interface-for-exported-class": "warn";
|
|
912
912
|
readonly "@sarj/require-port-for-service": "error";
|