@sarj/eslint-plugin 16.2.4 → 16.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -349,69 +349,34 @@ function commentLineEnd(sourceText, start) {
349
349
  // src/rules/require-explicit-contract-implementation.ts
350
350
  var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
351
351
  defaultLevel: "warning",
352
- summary: "Require owned classes supplied as typed collaborators to explicitly implement their contract.",
353
- rationale: "Structural assignment checks a fake only at the use site; an implements clause keeps its obligations visible at the class declaration.",
354
- remediation: "Add an implements clause for the actual injected interface, or inherit an abstract class that declares it.",
352
+ summary: "Require nominal inheritance when an injected abstract class is rejected by an instanceof guard.",
353
+ rationale: "A structurally assignable fake can still fail a constructor's nominal runtime guard. Pure structural interfaces do not require an implements clause.",
354
+ remediation: "Use an implementation inheriting the existing abstract class, or remove the nominal guard if the boundary is intentionally structural.",
355
355
  category: "architecture",
356
356
  autofix: "none",
357
357
  limitations: [
358
- "Only class instances whose concrete class and selected constructor parameter resolve through the TypeScript checker are checked.",
359
- "Object literals, casts, any, callback-valued data properties, unresolved heritage, dynamic factories, and third-party classes are excluded."
358
+ "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.",
359
+ "The contract must resolve to an abstract class without decorators, unresolved ancestors, or custom computed static members in its resolved hierarchy.",
360
+ "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."
360
361
  ],
361
362
  examples: [
362
363
  {
363
- id: "structural-fake-at-injection",
364
- title: "A fake reaches a typed collaborator without implementing its interface",
364
+ id: "runtime-nominal-guard-with-structural-fake",
365
+ title: "A structurally compatible fake fails the constructor's runtime guard",
365
366
  outcome: "match",
366
- files: [{ path: "src/service.ts", source: "interface Publisher { publish(): void } class Consumer { constructor(readonly publisher: Publisher) {} } class FakePublisher { publish() {} } new Consumer(new FakePublisher());" }],
367
+ files: [{ path: "src/service.ts", source: "abstract class Publisher { abstract publish(): void } class Consumer { constructor(readonly publisher: Publisher) { if (!(publisher instanceof Publisher)) throw new TypeError('Nominal publisher required'); } } class FakePublisher { publish() {} } new Consumer(new FakePublisher());" }],
367
368
  focusPath: "src/service.ts",
368
369
  expectedCount: 1,
369
370
  public: true
370
371
  },
371
372
  {
372
- id: "explicit-fake-at-injection",
373
- title: "The fake names its actual interface",
373
+ id: "runtime-nominal-guard-with-inherited-fake",
374
+ title: "The fake satisfies the existing nominal runtime contract",
374
375
  outcome: "no-match",
375
- files: [{ path: "src/service.ts", source: "interface Publisher { publish(): void } class Consumer { constructor(readonly publisher: Publisher) {} } class FakePublisher implements Publisher { publish() {} } new Consumer(new FakePublisher());" }],
376
+ files: [{ path: "src/service.ts", source: "abstract class Publisher { abstract publish(): void } class Consumer { constructor(readonly publisher: Publisher) { if (!(publisher instanceof Publisher)) throw new TypeError('Nominal publisher required'); } } class FakePublisher extends Publisher { publish() {} } new Consumer(new FakePublisher());" }],
376
377
  focusPath: "src/service.ts",
377
378
  expectedCount: 0,
378
379
  public: true
379
- },
380
- {
381
- id: "inherited-implementation",
382
- title: "The fake inherits an implementation of the port",
383
- outcome: "no-match",
384
- files: [{ path: "src/service.ts", source: "interface Publisher { publish(): void } class Consumer { constructor(readonly publisher: Publisher) {} } class BasePublisher implements Publisher { publish() {} } class FakePublisher extends BasePublisher {} new Consumer(new FakePublisher());" }],
385
- focusPath: "src/service.ts",
386
- expectedCount: 0,
387
- public: false
388
- },
389
- {
390
- id: "non-contract-data-argument",
391
- title: "A data object is not a service port",
392
- outcome: "no-match",
393
- files: [{ path: "src/service.ts", source: "interface Options { name: string } class Consumer { constructor(readonly options: Options) {} } class FakeOptions { name = 'test' } new Consumer(new FakeOptions());" }],
394
- focusPath: "src/service.ts",
395
- expectedCount: 0,
396
- public: false
397
- },
398
- {
399
- id: "explicit-cast-origin-unknown",
400
- title: "A cast hides the concrete source",
401
- outcome: "no-match",
402
- files: [{ path: "src/service.ts", source: "interface Publisher { publish(): void } class Consumer { constructor(readonly publisher: Publisher) {} } class FakePublisher { publish() {} } new Consumer(new FakePublisher() as Publisher);" }],
403
- focusPath: "src/service.ts",
404
- expectedCount: 0,
405
- public: false
406
- },
407
- {
408
- id: "unrelated-interface",
409
- title: "Implementing another interface does not declare the supplied port",
410
- outcome: "match",
411
- files: [{ path: "src/service.ts", source: "interface Publisher { publish(): void } interface Other { publish(): void } class Consumer { constructor(readonly publisher: Publisher) {} } class FakePublisher implements Other { publish() {} } new Consumer(new FakePublisher());" }],
412
- focusPath: "src/service.ts",
413
- expectedCount: 1,
414
- public: false
415
380
  }
416
381
  ]
417
382
  };
@@ -422,7 +387,7 @@ function behavioralContract(checker, type) {
422
387
  return behavioralContract(checker, substantive[0]);
423
388
  }
424
389
  if ((type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) return null;
425
- const declaration = type.getSymbol()?.declarations?.find((item) => ts.isInterfaceDeclaration(item) || ts.isTypeAliasDeclaration(item) || ts.isClassDeclaration(item) && item.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AbstractKeyword));
390
+ const declaration = type.getSymbol()?.declarations?.find((item) => ts.isClassDeclaration(item) && item.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AbstractKeyword));
426
391
  if (declaration === void 0) return null;
427
392
  return checker.getPropertiesOfType(type).some((property) => {
428
393
  if (!property.declarations?.some((member) => ts.isMethodSignature(member) || ts.isMethodDeclaration(member))) return false;
@@ -430,43 +395,86 @@ function behavioralContract(checker, type) {
430
395
  return propertyType.getCallSignatures().length > 0;
431
396
  }) ? type : null;
432
397
  }
433
- function ownedClass(type) {
398
+ function ownedClass(checker, expression) {
399
+ if (!ts.isNewExpression(expression)) return null;
400
+ const type = checker.getTypeAtLocation(expression);
434
401
  if ((type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) return null;
435
402
  const declaration = type.getSymbol()?.declarations?.find(ts.isClassDeclaration);
436
- if (declaration === void 0 || declaration.getSourceFile().isDeclarationFile || /(?:^|[/\\])(?:node_modules|vendor|generated)(?:[/\\])/u.test(declaration.getSourceFile().fileName)) return null;
403
+ const constructed = canonicalSymbol(checker, expression.expression)?.declarations?.find(ts.isClassDeclaration);
404
+ if (declaration === void 0 || declaration !== constructed || declaration.getSourceFile().isDeclarationFile || /(?:^|[/\\])(?:node_modules|vendor|generated)(?:[/\\])/u.test(declaration.getSourceFile().fileName)) return null;
437
405
  return declaration;
438
406
  }
439
- function explicitlyImplements(checker, declaration, target, seen) {
407
+ function memberName(node) {
408
+ if (ts.isPropertyAccessExpression(node)) return node.name.text;
409
+ if (ts.isElementAccessExpression(node) && ts.isStringLiteralLike(node.argumentExpression)) return node.argumentExpression.text;
410
+ return null;
411
+ }
412
+ function hasPrototypeMutation(source) {
413
+ function visit(node) {
414
+ const member = memberName(node);
415
+ if (member === "setPrototypeOf" || member === "__proto__" || member === "hasInstance") return true;
416
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && memberName(node.left) === "prototype") return true;
417
+ return ts.forEachChild(node, visit);
418
+ }
419
+ return visit(source) === true;
420
+ }
421
+ function nominallyInherits(checker, declaration, target, seen) {
422
+ if (ts.canHaveDecorators(declaration) && ts.getDecorators(declaration)?.length) return null;
423
+ if (hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some((member) => ts.isConstructorDeclaration(member) || ts.isPropertyDeclaration(member) && member.initializer !== void 0)) return null;
440
424
  const symbol = declaration.name === void 0 ? void 0 : canonicalSymbol(checker, declaration.name);
441
425
  if (symbol !== void 0) {
442
426
  if (seen.has(symbol)) return null;
443
427
  seen.add(symbol);
444
428
  }
445
- let unknown = false;
446
- for (const clause of declaration.heritageClauses ?? []) {
447
- for (const parent of clause.types) {
448
- const parentSymbol = canonicalSymbol(checker, parent.expression);
449
- if (parentSymbol === void 0) {
450
- unknown = true;
451
- continue;
452
- }
453
- if (parentSymbol === target) return true;
454
- const inherited = parentSymbol.declarations?.find((item) => ts.isClassDeclaration(item) || ts.isInterfaceDeclaration(item));
455
- if (inherited === void 0) {
456
- unknown = true;
457
- continue;
458
- }
459
- const relationship = explicitlyImplements(checker, inherited, target, new Set(seen));
460
- if (relationship === true) return true;
461
- unknown ||= relationship === null;
462
- }
463
- }
464
- return unknown ? null : false;
429
+ const parents = declaration.heritageClauses?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types;
430
+ if (parents === void 0) return false;
431
+ if (parents.length !== 1) return null;
432
+ const parentSymbol = canonicalSymbol(checker, parents[0].expression);
433
+ if (parentSymbol === void 0) return null;
434
+ if (parentSymbol === target) return true;
435
+ const inherited = parentSymbol.declarations?.find(ts.isClassDeclaration);
436
+ return inherited === void 0 ? null : nominallyInherits(checker, inherited, target, new Set(seen));
465
437
  }
466
438
  function canonicalSymbol(checker, node) {
467
439
  const symbol = checker.getSymbolAtLocation(node);
468
440
  return symbol === void 0 ? void 0 : (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
469
441
  }
442
+ function hasNominalRejectionGuard(checker, signature, parameter, contract) {
443
+ const declaration = signature.getDeclaration();
444
+ if (declaration === void 0 || !ts.isConstructorDeclaration(declaration)) return false;
445
+ if (ts.canHaveDecorators(declaration.parent) && ts.getDecorators(declaration.parent)?.length) return false;
446
+ if (hasPrototypeMutation(declaration.getSourceFile())) return false;
447
+ const first = declaration.body?.statements[0];
448
+ if (first === void 0 || !ts.isIfStatement(first) || !alwaysThrows(first.thenStatement)) return false;
449
+ const condition = unparenthesized(first.expression);
450
+ if (!ts.isPrefixUnaryExpression(condition) || condition.operator !== ts.SyntaxKind.ExclamationToken) return false;
451
+ const comparison = unparenthesized(condition.operand);
452
+ if (!ts.isBinaryExpression(comparison) || comparison.operatorToken.kind !== ts.SyntaxKind.InstanceOfKeyword) return false;
453
+ if (canonicalSymbol(checker, comparison.left) !== parameter || canonicalSymbol(checker, comparison.right) !== contract) return false;
454
+ const target = contract.declarations?.find(ts.isClassDeclaration);
455
+ return target !== void 0 && hasOrdinaryInstanceCheck(checker, target, /* @__PURE__ */ new Set());
456
+ }
457
+ function unparenthesized(expression) {
458
+ let current = expression;
459
+ while (ts.isParenthesizedExpression(current)) current = current.expression;
460
+ return current;
461
+ }
462
+ function alwaysThrows(statement) {
463
+ return ts.isThrowStatement(statement) || ts.isBlock(statement) && statement.statements.length === 1 && ts.isThrowStatement(statement.statements[0]);
464
+ }
465
+ function hasOrdinaryInstanceCheck(checker, declaration, seen) {
466
+ if (seen.has(declaration) || ts.getDecorators(declaration)?.length || hasPrototypeMutation(declaration.getSourceFile())) return false;
467
+ seen.add(declaration);
468
+ 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;
469
+ for (const clause of declaration.heritageClauses ?? []) {
470
+ if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue;
471
+ for (const parent of clause.types) {
472
+ const ancestor = canonicalSymbol(checker, parent.expression)?.declarations?.find(ts.isClassDeclaration);
473
+ if (ancestor === void 0 || !hasOrdinaryInstanceCheck(checker, ancestor, seen)) return false;
474
+ }
475
+ }
476
+ return true;
477
+ }
470
478
  var require_explicit_contract_implementation_default = createRule({
471
479
  name: "require-explicit-contract-implementation",
472
480
  documentation: REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION,
@@ -475,7 +483,7 @@ var require_explicit_contract_implementation_default = createRule({
475
483
  docs: { description: REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION.summary },
476
484
  schema: [],
477
485
  messages: {
478
- declareActualContract: "`{{implementation}}` is supplied as `{{contract}}` without explicitly implementing that contract."
486
+ declareActualContract: "`{{implementation}}` structurally matches `{{contract}}` but fails the rejecting instanceof guard; use nominal inheritance or make the boundary structural."
479
487
  }
480
488
  },
481
489
  defaultOptions: [],
@@ -486,25 +494,27 @@ var require_explicit_contract_implementation_default = createRule({
486
494
  const checker = services.program.getTypeChecker();
487
495
  function inspect(node) {
488
496
  const tsNode = services.esTreeNodeToTSNodeMap.get(node);
489
- if (!ts.isCallExpression(tsNode) && !ts.isNewExpression(tsNode)) return;
497
+ if (!ts.isNewExpression(tsNode)) return;
498
+ const consumer = canonicalSymbol(checker, tsNode.expression)?.declarations?.find(ts.isClassDeclaration);
499
+ if (consumer === void 0) return;
490
500
  const signature = checker.getResolvedSignature(tsNode);
491
- if (signature === void 0) return;
501
+ if (signature === void 0 || signature.getDeclaration()?.parent !== consumer) return;
492
502
  const parameters = signature.getParameters();
493
503
  for (const [index, argument] of node.arguments.entries()) {
494
- if (argument.type === import_utils2.AST_NODE_TYPES.SpreadElement || argument.type === import_utils2.AST_NODE_TYPES.TSAsExpression || argument.type === import_utils2.AST_NODE_TYPES.TSTypeAssertion || argument.type === import_utils2.AST_NODE_TYPES.TSSatisfiesExpression) continue;
504
+ if (argument.type !== import_utils2.AST_NODE_TYPES.NewExpression) continue;
495
505
  const parameter = parameters[index];
496
506
  if (parameter === void 0) continue;
497
507
  const parameterType = checker.getTypeOfSymbolAtLocation(parameter, tsNode);
498
508
  const contractType = behavioralContract(checker, parameterType);
499
509
  if (contractType === null) continue;
500
510
  const contractSymbol = contractType.getSymbol();
501
- if (contractSymbol === void 0) continue;
511
+ if (contractSymbol === void 0 || !hasNominalRejectionGuard(checker, signature, parameter, contractSymbol)) continue;
502
512
  const tsArgument = services.esTreeNodeToTSNodeMap.get(argument);
503
513
  const actualType = checker.getTypeAtLocation(tsArgument);
504
514
  if (!checker.isTypeAssignableTo(actualType, contractType)) continue;
505
- const implementation = ownedClass(actualType);
515
+ const implementation = ownedClass(checker, tsArgument);
506
516
  if (implementation === null) continue;
507
- const relationship = explicitlyImplements(checker, implementation, contractSymbol, /* @__PURE__ */ new Set());
517
+ const relationship = nominallyInherits(checker, implementation, contractSymbol, /* @__PURE__ */ new Set());
508
518
  if (relationship !== false) continue;
509
519
  context.report({
510
520
  node: argument,
@@ -514,7 +524,6 @@ var require_explicit_contract_implementation_default = createRule({
514
524
  }
515
525
  }
516
526
  return {
517
- CallExpression: inspect,
518
527
  NewExpression: inspect
519
528
  };
520
529
  }
@@ -632,7 +641,7 @@ var propertySignatureTypes = (members) => {
632
641
  };
633
642
  var fileTypeIndex = (program) => {
634
643
  const objects = /* @__PURE__ */ new Map();
635
- const functionAliases = /* @__PURE__ */ new Set();
644
+ const functionAliases = localFunctionAliases(program);
636
645
  function collectDeclaredType(statement) {
637
646
  const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
638
647
  if (declaration?.type === import_utils3.AST_NODE_TYPES.TSInterfaceDeclaration) {
@@ -641,10 +650,6 @@ var fileTypeIndex = (program) => {
641
650
  }
642
651
  if (declaration?.type !== import_utils3.AST_NODE_TYPES.TSTypeAliasDeclaration) return;
643
652
  const aliased = declaration.typeAnnotation;
644
- if (aliased.type === import_utils3.AST_NODE_TYPES.TSFunctionType || aliased.type === import_utils3.AST_NODE_TYPES.TSConstructorType) {
645
- functionAliases.add(declaration.id.name);
646
- return;
647
- }
648
653
  const literals = aliased.type === import_utils3.AST_NODE_TYPES.TSTypeLiteral ? [aliased] : aliased.type === import_utils3.AST_NODE_TYPES.TSIntersectionType ? aliased.types.filter((part) => part.type === import_utils3.AST_NODE_TYPES.TSTypeLiteral) : [];
649
654
  if (literals.length === 0) return;
650
655
  const merged = /* @__PURE__ */ new Map();
@@ -660,6 +665,28 @@ var fileTypeIndex = (program) => {
660
665
  }
661
666
  return { objects, functionAliases };
662
667
  };
668
+ function localFunctionAliases(program) {
669
+ const names = /* @__PURE__ */ new Set();
670
+ const parents = /* @__PURE__ */ new Map();
671
+ for (const statement of program.body) {
672
+ const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
673
+ if (declaration?.type !== import_utils3.AST_NODE_TYPES.TSTypeAliasDeclaration) continue;
674
+ const annotation = declaration.typeAnnotation;
675
+ if (annotation.type === import_utils3.AST_NODE_TYPES.TSFunctionType || annotation.type === import_utils3.AST_NODE_TYPES.TSConstructorType) names.add(declaration.id.name);
676
+ if (annotation.type === import_utils3.AST_NODE_TYPES.TSTypeReference && annotation.typeName.type === import_utils3.AST_NODE_TYPES.Identifier) parents.set(declaration.id.name, annotation.typeName.name);
677
+ }
678
+ for (let pass = 0; pass < parents.size; pass += 1) {
679
+ let changed = false;
680
+ for (const [name, parent] of parents) {
681
+ if (names.has(parent) && !names.has(name)) {
682
+ names.add(name);
683
+ changed = true;
684
+ }
685
+ }
686
+ if (!changed) break;
687
+ }
688
+ return names;
689
+ }
663
690
  var typeParameterNames = (...declarations) => {
664
691
  const names = /* @__PURE__ */ new Set();
665
692
  for (const declaration of declarations) {
@@ -671,12 +698,15 @@ var readConstructor = (ctor, declared, typeParameters) => {
671
698
  const body2 = ctor.value.body;
672
699
  const storedFieldsFrom = /* @__PURE__ */ new Map();
673
700
  const storedMemberFieldsFrom = /* @__PURE__ */ new Map();
701
+ const constructedFieldNames = /* @__PURE__ */ new Set();
702
+ const localBindings2 = /* @__PURE__ */ new Set();
674
703
  let constructedFields = 0;
675
704
  if (body2 !== null && body2 !== void 0) scanStoredFields(body2);
676
705
  function scanStoredFields(body3) {
677
706
  const pending = [...body3.body];
678
707
  function recordStoredField(current) {
679
708
  if (current.type === import_utils3.AST_NODE_TYPES.ArrowFunctionExpression || current.type === import_utils3.AST_NODE_TYPES.FunctionExpression || current.type === import_utils3.AST_NODE_TYPES.FunctionDeclaration || current.type === import_utils3.AST_NODE_TYPES.ClassExpression || current.type === import_utils3.AST_NODE_TYPES.ClassDeclaration) return;
709
+ if (current.type === import_utils3.AST_NODE_TYPES.VariableDeclarator && current.id.type === import_utils3.AST_NODE_TYPES.Identifier) localBindings2.add(current.id.name);
680
710
  const expression = current.type === import_utils3.AST_NODE_TYPES.ExpressionStatement ? current.expression : null;
681
711
  const storedField = expression?.type === import_utils3.AST_NODE_TYPES.AssignmentExpression && expression.left.type === import_utils3.AST_NODE_TYPES.MemberExpression && expression.left.object.type === import_utils3.AST_NODE_TYPES.ThisExpression ? staticMemberName(expression.left) : null;
682
712
  if (expression?.type !== import_utils3.AST_NODE_TYPES.AssignmentExpression || !STORAGE_ASSIGNMENT_OPERATORS.has(expression.operator) || expression.left.type !== import_utils3.AST_NODE_TYPES.MemberExpression || expression.left.object.type !== import_utils3.AST_NODE_TYPES.ThisExpression || storedField === null) {
@@ -687,6 +717,7 @@ var readConstructor = (ctor, declared, typeParameters) => {
687
717
  while (source.type === import_utils3.AST_NODE_TYPES.TSNonNullExpression || source.type === import_utils3.AST_NODE_TYPES.TSAsExpression || source.type === import_utils3.AST_NODE_TYPES.TSSatisfiesExpression || source.type === import_utils3.AST_NODE_TYPES.TSTypeAssertion) source = source.expression;
688
718
  if (source.type === import_utils3.AST_NODE_TYPES.NewExpression) {
689
719
  constructedFields += 1;
720
+ constructedFieldNames.add(storedField);
690
721
  } else if (source.type === import_utils3.AST_NODE_TYPES.Identifier) {
691
722
  const fields = storedFieldsFrom.get(source.name) ?? /* @__PURE__ */ new Set();
692
723
  fields.add(storedField);
@@ -719,15 +750,19 @@ var readConstructor = (ctor, declared, typeParameters) => {
719
750
  const collaborators = [];
720
751
  function collectCollaborators(parameter) {
721
752
  for (const reference of parameterCollaborators(parameter, declared, storedMemberFieldsFrom)) {
722
- const fields = parameter.type === import_utils3.AST_NODE_TYPES.TSParameterProperty ? [reference.name] : reference.fields.length > 0 ? reference.fields : [...storedFieldsFrom.get(reference.name) ?? []];
723
- if (fields.length === 0) continue;
753
+ if (localBindings2.has(reference.name)) continue;
754
+ let fields = reference.fields;
755
+ if (parameter.type === import_utils3.AST_NODE_TYPES.TSParameterProperty) fields = [reference.name];
756
+ else if (fields.length === 0) fields = [...storedFieldsFrom.get(reference.name) ?? []];
757
+ const injectedFields = fields.filter((field) => !constructedFieldNames.has(field));
758
+ if (injectedFields.length === 0) continue;
724
759
  if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
725
760
  if (CONFIGISH_NAME_RE.test(reference.name)) continue;
726
761
  if (typeParameters.has(reference.typeName)) continue;
727
762
  if (BUILTIN_CONTAINER_TYPE_RE.test(reference.typeName)) continue;
728
763
  if (VALUE_TYPE_RE.test(reference.typeName)) continue;
729
764
  if (declared().functionAliases.has(reference.typeName)) continue;
730
- collaborators.push({ ...reference, fields });
765
+ collaborators.push({ ...reference, fields: injectedFields });
731
766
  }
732
767
  }
733
768
  for (const parameter of ctor.value.params) {
@@ -946,11 +981,7 @@ function declaredMemberName(member) {
946
981
  function localInterfaceSurfaces(program) {
947
982
  const interfaces = /* @__PURE__ */ new Map();
948
983
  const parents = /* @__PURE__ */ new Map();
949
- const functionAliases = /* @__PURE__ */ new Set();
950
- for (const statement of program.body) {
951
- const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
952
- if (declaration?.type === import_utils3.AST_NODE_TYPES.TSTypeAliasDeclaration && (declaration.typeAnnotation.type === import_utils3.AST_NODE_TYPES.TSFunctionType || declaration.typeAnnotation.type === import_utils3.AST_NODE_TYPES.TSConstructorType)) functionAliases.add(declaration.id.name);
953
- }
984
+ const functionAliases = localFunctionAliases(program);
954
985
  function collectInterfaceSurface(statement) {
955
986
  const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
956
987
  if (declaration?.type === import_utils3.AST_NODE_TYPES.TSTypeAliasDeclaration) {
@@ -962,6 +993,10 @@ function localInterfaceSurfaces(program) {
962
993
  inherited.push(part.typeName.name);
963
994
  continue;
964
995
  }
996
+ if (part.type === import_utils3.AST_NODE_TYPES.TSTypeReference) {
997
+ inherited.push("*");
998
+ continue;
999
+ }
965
1000
  if (part.type !== import_utils3.AST_NODE_TYPES.TSTypeLiteral) continue;
966
1001
  addCallableMembers(part.members, callables2);
967
1002
  }
@@ -1125,30 +1160,18 @@ function createServiceOperationResolver(program) {
1125
1160
  if (retained.size === 0) return [];
1126
1161
  const callers = /* @__PURE__ */ new Map();
1127
1162
  const active = /* @__PURE__ */ new Set();
1128
- for (const member of node.body.body) {
1129
- if (member.type !== import_utils3.AST_NODE_TYPES.MethodDefinition || member.kind !== "method" || member.value.body === null) continue;
1130
- const name = declaredMemberName(member);
1131
- if (name === null) continue;
1132
- const visit = (current) => {
1133
- if (current.type === import_utils3.AST_NODE_TYPES.FunctionDeclaration || current.type === import_utils3.AST_NODE_TYPES.FunctionExpression || current.type === import_utils3.AST_NODE_TYPES.ClassDeclaration || current.type === import_utils3.AST_NODE_TYPES.ClassExpression) return;
1134
- if (current.type === import_utils3.AST_NODE_TYPES.IfStatement && current.test.type === import_utils3.AST_NODE_TYPES.Literal && typeof current.test.value === "boolean") {
1135
- visit(current.test.value ? current.consequent : current.alternate ?? current.test);
1136
- return;
1137
- }
1138
- if (current.type === import_utils3.AST_NODE_TYPES.CallExpression) {
1139
- if (retained.has(invokedInstanceField(current) ?? "")) active.add(name);
1140
- if (current.callee.type === import_utils3.AST_NODE_TYPES.MemberExpression && current.callee.object.type === import_utils3.AST_NODE_TYPES.ThisExpression) {
1141
- const callee = staticMemberName(current.callee);
1142
- if (callee !== null) {
1143
- const linked = callers.get(callee) ?? /* @__PURE__ */ new Set();
1144
- linked.add(name);
1145
- callers.set(callee, linked);
1146
- }
1163
+ for (const [name, body2] of serviceOperationBodies(node)) {
1164
+ forEachServiceCall(body2, (call) => {
1165
+ if (retained.has(invokedInstanceField(call) ?? "")) active.add(name);
1166
+ if (call.callee.type === import_utils3.AST_NODE_TYPES.MemberExpression && call.callee.object.type === import_utils3.AST_NODE_TYPES.ThisExpression) {
1167
+ const callee = staticMemberName(call.callee);
1168
+ if (callee !== null) {
1169
+ const linked = callers.get(callee) ?? /* @__PURE__ */ new Set();
1170
+ linked.add(name);
1171
+ callers.set(callee, linked);
1147
1172
  }
1148
1173
  }
1149
- forEachOwnAstChild(current, visit);
1150
- };
1151
- for (const statement of member.value.body.body) visit(statement);
1174
+ });
1152
1175
  }
1153
1176
  const pending = [...active];
1154
1177
  while (pending.length > 0) {
@@ -1163,38 +1186,127 @@ function createServiceOperationResolver(program) {
1163
1186
  return publicMethodNames(node.body, declared().functionAliases).filter((name) => active.has(name));
1164
1187
  };
1165
1188
  }
1189
+ function serviceOperationBodies(node) {
1190
+ const bodies = /* @__PURE__ */ new Map();
1191
+ for (const member of node.body.body) {
1192
+ if (member.type !== import_utils3.AST_NODE_TYPES.MethodDefinition && member.type !== import_utils3.AST_NODE_TYPES.PropertyDefinition) continue;
1193
+ if (member.static || member.decorators.length > 0) continue;
1194
+ if (member.type === import_utils3.AST_NODE_TYPES.MethodDefinition && member.kind !== "method") continue;
1195
+ if (member.value?.type !== import_utils3.AST_NODE_TYPES.FunctionExpression && member.value?.type !== import_utils3.AST_NODE_TYPES.ArrowFunctionExpression) continue;
1196
+ const name = declaredMemberName(member);
1197
+ if (name !== null && member.value.body !== null) bodies.set(name, member.value.body);
1198
+ }
1199
+ return bodies;
1200
+ }
1201
+ function forEachServiceCall(node, onCall) {
1202
+ if (node.type === import_utils3.AST_NODE_TYPES.FunctionDeclaration || node.type === import_utils3.AST_NODE_TYPES.FunctionExpression || node.type === import_utils3.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils3.AST_NODE_TYPES.ClassDeclaration || node.type === import_utils3.AST_NODE_TYPES.ClassExpression) return;
1203
+ if (node.type === import_utils3.AST_NODE_TYPES.BlockStatement) {
1204
+ for (const statement of node.body) {
1205
+ forEachServiceCall(statement, onCall);
1206
+ if (terminatesOperation(statement)) break;
1207
+ }
1208
+ return;
1209
+ }
1210
+ const branch = literalExecutionBranch(node);
1211
+ if (branch !== null) {
1212
+ forEachServiceCall(branch, onCall);
1213
+ return;
1214
+ }
1215
+ if (node.type === import_utils3.AST_NODE_TYPES.CallExpression) onCall(node);
1216
+ forEachOwnAstChild(node, (child) => {
1217
+ forEachServiceCall(child, onCall);
1218
+ });
1219
+ }
1220
+ function literalExecutionBranch(node) {
1221
+ if (node.type === import_utils3.AST_NODE_TYPES.WhileStatement && node.test.type === import_utils3.AST_NODE_TYPES.Literal && node.test.value === false) return node.test;
1222
+ if ((node.type === import_utils3.AST_NODE_TYPES.IfStatement || node.type === import_utils3.AST_NODE_TYPES.ConditionalExpression) && node.test.type === import_utils3.AST_NODE_TYPES.Literal && typeof node.test.value === "boolean") {
1223
+ return node.test.value ? node.consequent : node.alternate ?? node.test;
1224
+ }
1225
+ if (node.type !== import_utils3.AST_NODE_TYPES.LogicalExpression || node.left.type !== import_utils3.AST_NODE_TYPES.Literal || typeof node.left.value !== "boolean") return null;
1226
+ if (node.operator === "&&") return node.left.value ? node.right : node.left;
1227
+ if (node.operator === "||") return node.left.value ? node.left : node.right;
1228
+ return node.left;
1229
+ }
1230
+ function terminatesOperation(node) {
1231
+ if (node.type === import_utils3.AST_NODE_TYPES.ReturnStatement || node.type === import_utils3.AST_NODE_TYPES.ThrowStatement) return true;
1232
+ if (node.type === import_utils3.AST_NODE_TYPES.BlockStatement) return node.body.some(terminatesOperation);
1233
+ if (node.type !== import_utils3.AST_NODE_TYPES.IfStatement) return false;
1234
+ const branch = literalExecutionBranch(node);
1235
+ if (branch !== null) return terminatesOperation(branch);
1236
+ return node.alternate !== null && terminatesOperation(node.consequent) && terminatesOperation(node.alternate);
1237
+ }
1166
1238
  function hasDeclaredServiceContract(node, operations, program) {
1167
- const classes = localClassAbstractness(program);
1168
1239
  const interfaces = localInterfaceSurfaces(program);
1169
- if (node.implements.length > 0) return implementedSurfaceCovers(node, operations, classes, interfaces);
1170
- if (node.superClass === null) return false;
1171
- if (node.superClass.type !== import_utils3.AST_NODE_TYPES.Identifier) return null;
1172
- const baseName = node.superClass.name;
1173
- const isAbstract = classes.get(baseName);
1174
- if (isAbstract === void 0) return null;
1175
- if (!isAbstract) return false;
1176
- const base = program.body.flatMap((statement) => {
1177
- const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration ? statement.declaration : statement;
1178
- return declaration?.type === import_utils3.AST_NODE_TYPES.ClassDeclaration && declaration.id?.name === baseName ? [declaration] : [];
1179
- })[0];
1180
- if (base === void 0) return null;
1181
- const abstractOperations = new Set(base.body.body.flatMap(
1182
- (member) => member.type === import_utils3.AST_NODE_TYPES.TSAbstractMethodDefinition && member.accessibility !== "private" && member.accessibility !== "protected" && !member.static ? [declaredMemberName(member)] : []
1183
- ));
1184
- return operations.every((name) => abstractOperations.has(name) || publicMethodNames(base.body, /* @__PURE__ */ new Set()).includes(name));
1240
+ const classes = localClassDeclarations(program);
1241
+ const functionAliases = fileTypeIndex(program).functionAliases;
1242
+ const covered2 = /* @__PURE__ */ new Set();
1243
+ const pending = [node];
1244
+ const seen = /* @__PURE__ */ new Set();
1245
+ function addImplementedContracts(current) {
1246
+ for (const implementation of current.implements) {
1247
+ if (implementation.expression.type !== import_utils3.AST_NODE_TYPES.Identifier) return false;
1248
+ const name = implementation.expression.name;
1249
+ const surface = interfaces.get(name);
1250
+ const base = classes.get(name);
1251
+ if (surface === void 0 && base === void 0) return false;
1252
+ if (surface?.has("*")) return false;
1253
+ for (const method of surface ?? []) covered2.add(method);
1254
+ if (base?.abstract) pending.push(base);
1255
+ }
1256
+ return true;
1257
+ }
1258
+ while (pending.length > 0) {
1259
+ const current = pending.pop();
1260
+ if (current === void 0 || seen.has(current)) continue;
1261
+ seen.add(current);
1262
+ if (current.decorators.length > 0) return null;
1263
+ if (current.abstract) {
1264
+ for (const method of abstractContractOperations(current, functionAliases)) covered2.add(method);
1265
+ }
1266
+ if (!addImplementedContracts(current)) return null;
1267
+ if (current.superClass === null) continue;
1268
+ if (current.superClass.type !== import_utils3.AST_NODE_TYPES.Identifier) return null;
1269
+ const base = classes.get(current.superClass.name);
1270
+ if (base === void 0) return null;
1271
+ pending.push(base);
1272
+ }
1273
+ return operations.every((name) => covered2.has(name));
1274
+ }
1275
+ function localClassDeclarations(program) {
1276
+ const classes = /* @__PURE__ */ new Map();
1277
+ for (const statement of program.body) {
1278
+ const declaration = statement.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration || statement.type === import_utils3.AST_NODE_TYPES.ExportDefaultDeclaration ? statement.declaration : statement;
1279
+ if (declaration?.type === import_utils3.AST_NODE_TYPES.ClassDeclaration && declaration.id !== null) classes.set(declaration.id.name, declaration);
1280
+ }
1281
+ return classes;
1282
+ }
1283
+ function abstractContractOperations(node, functionAliases) {
1284
+ const methods = new Set(publicMethodNames(node.body, functionAliases));
1285
+ for (const member of node.body.body) {
1286
+ if (member.type !== import_utils3.AST_NODE_TYPES.TSAbstractMethodDefinition && member.type !== import_utils3.AST_NODE_TYPES.TSAbstractPropertyDefinition) continue;
1287
+ if (member.static || member.accessibility === "private" || member.accessibility === "protected") continue;
1288
+ if (member.type === import_utils3.AST_NODE_TYPES.TSAbstractPropertyDefinition) {
1289
+ const annotation = member.typeAnnotation?.typeAnnotation;
1290
+ if (annotation?.type !== import_utils3.AST_NODE_TYPES.TSFunctionType && !(annotation?.type === import_utils3.AST_NODE_TYPES.TSTypeReference && annotation.typeName.type === import_utils3.AST_NODE_TYPES.Identifier && functionAliases.has(annotation.typeName.name))) continue;
1291
+ }
1292
+ const name = declaredMemberName(member);
1293
+ if (name !== null) methods.add(name);
1294
+ }
1295
+ return methods;
1185
1296
  }
1186
1297
 
1187
1298
  // src/rules/require-explicit-service-contract.ts
1188
1299
  var REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION = {
1189
1300
  defaultLevel: "warning",
1190
1301
  summary: "Require explicit contracts for classes that invoke retained collaborators.",
1191
- rationale: "A one-operation service can orchestrate a collaborator without declaring the contract that its callers and fakes must implement.",
1192
- remediation: "Export a focused interface or abstract class and explicitly implement or extend it.",
1302
+ rationale: "A one-operation service can orchestrate a collaborator without declaring the contract that callers consume and implementations and fakes satisfy.",
1303
+ remediation: "Explicitly implement a focused interface or extend an abstract class covering the service operations. Export the contract only when its consumers need it.",
1193
1304
  category: "architecture",
1194
1305
  autofix: "none",
1195
1306
  limitations: [
1196
1307
  "The rule checks service, store, and provider class declarations whose constructor stores a typed behavioral collaborator and whose public method reaches that collaborator.",
1197
- "Imported or dynamic base classes with unavailable declarations are unresolved and do not produce a finding.",
1308
+ "Existing local interfaces, type aliases, and inherited contracts can cover the operations; the compiler owns signature compatibility.",
1309
+ "Imported or dynamic base classes with unavailable declarations and decorated classes or operations are unresolved and do not produce a finding.",
1198
1310
  "Generated files and JavaScript without implements syntax are excluded."
1199
1311
  ],
1200
1312
  examples: [
@@ -1216,7 +1328,7 @@ var REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION = {
1216
1328
  outcome: "no-match",
1217
1329
  files: [{
1218
1330
  path: "src/service.ts",
1219
- source: "export interface Runner { run(): void } class OrchestratorService implements Runner { constructor(private readonly worker: Worker) {} run(): void { this.worker.run(); } }"
1331
+ source: "interface Runner { run(): void } class OrchestratorService implements Runner { constructor(private readonly worker: Worker) {} run(): void { this.worker.run(); } }"
1220
1332
  }],
1221
1333
  focusPath: "src/service.ts",
1222
1334
  expectedCount: 0,
@@ -1232,7 +1344,7 @@ var require_explicit_service_contract_default = createRule({
1232
1344
  docs: { description: REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION.summary },
1233
1345
  schema: [],
1234
1346
  messages: {
1235
- requireExplicitServiceContract: "`{{name}}` invokes a retained collaborator from {{operations}} without explicitly implementing a public contract for those operations."
1347
+ requireExplicitServiceContract: "`{{name}}` invokes a retained collaborator from {{operations}} without a declared interface or abstract-class contract covering those operations. Implement a focused contract; it can remain local."
1236
1348
  }
1237
1349
  },
1238
1350
  defaultOptions: [],
@@ -1243,7 +1355,7 @@ var require_explicit_service_contract_default = createRule({
1243
1355
  const isExportedServiceClass = createExportedServiceClassResolver(program);
1244
1356
  return {
1245
1357
  ClassDeclaration(node) {
1246
- if (node.id === null || node.abstract || !isServiceRole(node.id.name, context.filename)) return;
1358
+ if (node.id === null || node.abstract || node.decorators.length > 0 || !isServiceRole(node.id.name, context.filename)) return;
1247
1359
  if (isExportedServiceClass(node) && !isTestFile(context.filename) && !isStoryFile(context.filename) && !isScriptFile(context.filename)) return;
1248
1360
  const operations = operationsFor(node);
1249
1361
  if (operations.length === 0 || hasDeclaredServiceContract(node, operations, program) !== false) return;
@@ -7058,7 +7170,7 @@ var RESHAPING_METHODS = /* @__PURE__ */ new Set([
7058
7170
  function importedName2(specifier) {
7059
7171
  return specifier.imported.type === import_utils40.AST_NODE_TYPES.Identifier ? specifier.imported.name : typeof specifier.imported.value === "string" ? specifier.imported.value : null;
7060
7172
  }
7061
- function memberName(node) {
7173
+ function memberName2(node) {
7062
7174
  if (!node.computed && node.property.type === import_utils40.AST_NODE_TYPES.Identifier) {
7063
7175
  return node.property.name;
7064
7176
  }
@@ -7143,7 +7255,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
7143
7255
  if (callee.type !== import_utils40.AST_NODE_TYPES.MemberExpression || callee.object.type !== import_utils40.AST_NODE_TYPES.CallExpression) {
7144
7256
  return null;
7145
7257
  }
7146
- const method = memberName(callee);
7258
+ const method = memberName2(callee);
7147
7259
  if (method === null) return null;
7148
7260
  calls.push({ method, node: current });
7149
7261
  current = callee.object;
@@ -7157,7 +7269,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
7157
7269
  if (callee.type !== import_utils40.AST_NODE_TYPES.MemberExpression || callee.object.type !== import_utils40.AST_NODE_TYPES.Identifier || !namespaces.has(callee.object.name) || !resolvesToTrackedImport(callee.object)) {
7158
7270
  return null;
7159
7271
  }
7160
- const name = memberName(callee);
7272
+ const name = memberName2(callee);
7161
7273
  return name !== null && KINDS.has(name) ? name : null;
7162
7274
  }
7163
7275
  function isInsideReshapingCall(node) {
@@ -7166,7 +7278,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
7166
7278
  while (parent !== void 0 && parent.type !== import_utils40.AST_NODE_TYPES.Program) {
7167
7279
  if (parent.type === import_utils40.AST_NODE_TYPES.CallExpression) {
7168
7280
  const callee = parent.callee;
7169
- if (callee.type === import_utils40.AST_NODE_TYPES.MemberExpression && RESHAPING_METHODS.has(memberName(callee) ?? "") && (callee.object.type === import_utils40.AST_NODE_TYPES.CallExpression || callee.object.type === import_utils40.AST_NODE_TYPES.Identifier && namespaces.has(callee.object.name) && resolvesToTrackedImport(callee.object))) {
7281
+ if (callee.type === import_utils40.AST_NODE_TYPES.MemberExpression && RESHAPING_METHODS.has(memberName2(callee) ?? "") && (callee.object.type === import_utils40.AST_NODE_TYPES.CallExpression || callee.object.type === import_utils40.AST_NODE_TYPES.Identifier && namespaces.has(callee.object.name) && resolvesToTrackedImport(callee.object))) {
7170
7282
  return true;
7171
7283
  }
7172
7284
  if (callee.type === import_utils40.AST_NODE_TYPES.Identifier && preprocessors.has(callee.name) && resolvesToTrackedImport(callee)) {
@@ -7428,7 +7540,7 @@ var NO_REDUNDANT_OPTIONAL_ARRAY_DEFAULT_DOCUMENTATION = {
7428
7540
  function importedName3(specifier) {
7429
7541
  return specifier.imported.type === import_utils42.AST_NODE_TYPES.Identifier ? specifier.imported.name : typeof specifier.imported.value === "string" ? specifier.imported.value : null;
7430
7542
  }
7431
- function memberName2(node) {
7543
+ function memberName3(node) {
7432
7544
  if (!node.computed && node.property.type === import_utils42.AST_NODE_TYPES.Identifier) {
7433
7545
  return node.property.name;
7434
7546
  }
@@ -7480,7 +7592,7 @@ var no_redundant_optional_array_default_default = createRule({
7480
7592
  return arrayConstructors.has(callee.name) && resolvesToTrackedImport(callee);
7481
7593
  }
7482
7594
  if (callee.type !== import_utils42.AST_NODE_TYPES.MemberExpression) return false;
7483
- const method = memberName2(callee);
7595
+ const method = memberName3(callee);
7484
7596
  if (method === "array" && (callee.object.type === import_utils42.AST_NODE_TYPES.Identifier ? namespaces.has(callee.object.name) && resolvesToTrackedImport(callee.object) : isZodSchemaExpression(callee.object))) {
7485
7597
  return true;
7486
7598
  }
@@ -7521,12 +7633,12 @@ var no_redundant_optional_array_default_default = createRule({
7521
7633
  },
7522
7634
  CallExpression(node) {
7523
7635
  const defaultCallee = node.callee;
7524
- if (defaultCallee.type !== import_utils42.AST_NODE_TYPES.MemberExpression || memberName2(defaultCallee) !== "default" || defaultCallee.object.type !== import_utils42.AST_NODE_TYPES.CallExpression) {
7636
+ if (defaultCallee.type !== import_utils42.AST_NODE_TYPES.MemberExpression || memberName3(defaultCallee) !== "default" || defaultCallee.object.type !== import_utils42.AST_NODE_TYPES.CallExpression) {
7525
7637
  return;
7526
7638
  }
7527
7639
  const optionalCall = defaultCallee.object;
7528
7640
  const optionalCallee = optionalCall.callee;
7529
- if (optionalCallee.type !== import_utils42.AST_NODE_TYPES.MemberExpression || memberName2(optionalCallee) !== "optional" || optionalCall.arguments.length !== 0 || !isArraySchemaExpression(optionalCallee.object) || sourceCode.getCommentsInside(optionalCall).length > 0) {
7641
+ if (optionalCallee.type !== import_utils42.AST_NODE_TYPES.MemberExpression || memberName3(optionalCallee) !== "optional" || optionalCall.arguments.length !== 0 || !isArraySchemaExpression(optionalCallee.object) || sourceCode.getCommentsInside(optionalCall).length > 0) {
7530
7642
  return;
7531
7643
  }
7532
7644
  context.report({
@@ -7545,12 +7657,12 @@ var ts8 = __toESM(require("typescript"), 1);
7545
7657
 
7546
7658
  // src/rules/_class-private.ts
7547
7659
  var import_utils43 = require("@typescript-eslint/utils");
7548
- function memberName3(member) {
7660
+ function memberName4(member) {
7549
7661
  return !member.computed && member.key.type === import_utils43.AST_NODE_TYPES.Identifier ? member.key.name : null;
7550
7662
  }
7551
7663
  function convertibleMemberName(member) {
7552
7664
  if (member.type !== import_utils43.AST_NODE_TYPES.MethodDefinition && member.type !== import_utils43.AST_NODE_TYPES.PropertyDefinition && member.type !== import_utils43.AST_NODE_TYPES.AccessorProperty) return null;
7553
- return memberName3(member);
7665
+ return memberName4(member);
7554
7666
  }
7555
7667
 
7556
7668
  // src/rules/interface-contract-members-private.ts
@@ -8152,7 +8264,7 @@ var LOWER_CAMEL_CASE_RE = /^[a-z][A-Za-z0-9]*$/;
8152
8264
  function propertyName2(node) {
8153
8265
  return node.type === import_utils48.AST_NODE_TYPES.Identifier ? node.name : null;
8154
8266
  }
8155
- function memberName4(node) {
8267
+ function memberName5(node) {
8156
8268
  let current = node;
8157
8269
  while (current.type === import_utils48.AST_NODE_TYPES.TSAsExpression || current.type === import_utils48.AST_NODE_TYPES.TSNonNullExpression || current.type === import_utils48.AST_NODE_TYPES.TSTypeAssertion) {
8158
8270
  current = current.expression;
@@ -8216,7 +8328,7 @@ var no_bespoke_api_case_conversion_default = createRule({
8216
8328
  Property(node) {
8217
8329
  if (node.computed || node.method || node.shorthand) return;
8218
8330
  const key = propertyName2(node.key);
8219
- const value = memberName4(node.value);
8331
+ const value = memberName5(node.value);
8220
8332
  if (key === null || value === null || !isDirectCaseTranslation(key, value)) return;
8221
8333
  if (!hasApiReceiver(node.value)) return;
8222
8334
  const wireName = SNAKE_CASE_RE2.test(key) ? key : value;
@@ -8989,9 +9101,9 @@ var no_positional_tuple_return_default = createRule({
8989
9101
  TSMethodSignature(node) {
8990
9102
  const owner = owningInterface(node);
8991
9103
  const alias = owningTypeAlias(node);
8992
- const memberName8 = staticMemberName4(node.key);
8993
- if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || node.returnType === void 0 || memberName8 === null) return;
8994
- report2(node.returnType.typeAnnotation, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName8}`);
9104
+ const memberName9 = staticMemberName4(node.key);
9105
+ if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || node.returnType === void 0 || memberName9 === null) return;
9106
+ report2(node.returnType.typeAnnotation, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName9}`);
8995
9107
  },
8996
9108
  TSTypeAliasDeclaration(node) {
8997
9109
  if (!typeExports.has(node.id.name)) return;
@@ -9002,11 +9114,11 @@ var no_positional_tuple_return_default = createRule({
9002
9114
  const owner = owningInterface(node);
9003
9115
  const alias = owningTypeAlias(node);
9004
9116
  const annotation = node.typeAnnotation?.typeAnnotation;
9005
- const memberName8 = staticMemberName4(node.key);
9006
- if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || memberName8 === null || annotation === void 0) return;
9117
+ const memberName9 = staticMemberName4(node.key);
9118
+ if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || memberName9 === null || annotation === void 0) return;
9007
9119
  const returnType = callableReturnType(annotation, aliases);
9008
9120
  if (returnType !== null) {
9009
- report2(returnType, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName8}`);
9121
+ report2(returnType, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName9}`);
9010
9122
  }
9011
9123
  },
9012
9124
  PropertyDefinition(node) {
@@ -16974,7 +17086,7 @@ var PREFER_NODE_CRYPTO_HASH_DOCUMENTATION = {
16974
17086
  { id: "mutable-one-shot-chain", title: "Avoid mutable state for one value", outcome: "match", files: [{ path: "case.ts", source: "import { createHash } from 'node:crypto'; export const digest = createHash('sha256').update('value').digest('hex');" }], focusPath: "case.ts", expectedCount: 1, public: true }
16975
17087
  ]
16976
17088
  };
16977
- function memberName5(node) {
17089
+ function memberName6(node) {
16978
17090
  if (!node.computed && node.property.type === import_utils99.AST_NODE_TYPES.Identifier) return node.property.name;
16979
17091
  if (node.computed && node.property.type === import_utils99.AST_NODE_TYPES.Literal && typeof node.property.value === "string") {
16980
17092
  return node.property.value;
@@ -16990,7 +17102,7 @@ function isCryptoLoader(node, resolve2) {
16990
17102
  if (node.callee.type === import_utils99.AST_NODE_TYPES.Identifier) {
16991
17103
  return node.callee.name === "require" && isUnshadowedBuiltinIdentifier(node.callee, resolve2);
16992
17104
  }
16993
- return node.callee.type === import_utils99.AST_NODE_TYPES.MemberExpression && node.callee.object.type === import_utils99.AST_NODE_TYPES.Identifier && node.callee.object.name === "process" && isUnshadowedBuiltinIdentifier(node.callee.object, resolve2) && memberName5(node.callee) === "getBuiltinModule";
17105
+ return node.callee.type === import_utils99.AST_NODE_TYPES.MemberExpression && node.callee.object.type === import_utils99.AST_NODE_TYPES.Identifier && node.callee.object.name === "process" && isUnshadowedBuiltinIdentifier(node.callee.object, resolve2) && memberName6(node.callee) === "getBuiltinModule";
16994
17106
  }
16995
17107
  function isCryptoSpecifier(node) {
16996
17108
  return node.type === import_utils99.AST_NODE_TYPES.Literal && (node.value === "crypto" || node.value === "node:crypto");
@@ -17072,14 +17184,14 @@ function importedName6(node) {
17072
17184
  return node.type === import_utils99.AST_NODE_TYPES.Identifier ? node.name : node.value;
17073
17185
  }
17074
17186
  function isMemberCall(node, name) {
17075
- return node.callee.type === import_utils99.AST_NODE_TYPES.MemberExpression && memberName5(node.callee) === name;
17187
+ return node.callee.type === import_utils99.AST_NODE_TYPES.MemberExpression && memberName6(node.callee) === name;
17076
17188
  }
17077
17189
  function isCreateHashCall(node, directBindings, namespaceBindings, resolve2) {
17078
17190
  if (node.callee.type === import_utils99.AST_NODE_TYPES.Identifier) {
17079
17191
  const variable2 = resolve2(node.callee);
17080
17192
  return variable2 !== null && directBindings.has(variable2);
17081
17193
  }
17082
- if (node.callee.type !== import_utils99.AST_NODE_TYPES.MemberExpression || memberName5(node.callee) !== "createHash") {
17194
+ if (node.callee.type !== import_utils99.AST_NODE_TYPES.MemberExpression || memberName6(node.callee) !== "createHash") {
17083
17195
  return false;
17084
17196
  }
17085
17197
  if (isCryptoLoader(node.callee.object, resolve2)) return true;
@@ -17107,7 +17219,7 @@ var PREFER_NODE_FS_PROMISES_DOCUMENTATION = {
17107
17219
  { id: "sync-read", title: "Do not block on a synchronous read", outcome: "match", files: [{ path: "src/store.ts", source: "import { readFileSync } from 'node:fs'; export function load(path: string) { return readFileSync(path, 'utf8'); }" }], focusPath: "src/store.ts", expectedCount: 1, public: true }
17108
17220
  ]
17109
17221
  };
17110
- function memberName6(node) {
17222
+ function memberName7(node) {
17111
17223
  if (!node.computed && node.property.type === import_utils100.AST_NODE_TYPES.Identifier) return node.property.name;
17112
17224
  if (node.computed && node.property.type === import_utils100.AST_NODE_TYPES.Literal && typeof node.property.value === "string") {
17113
17225
  return node.property.value;
@@ -17124,7 +17236,7 @@ function isFsLoader(node, isGlobal) {
17124
17236
  const [argument] = expression.arguments;
17125
17237
  if (argument === void 0 || argument.type === import_utils100.AST_NODE_TYPES.SpreadElement || !isFsSpecifier(argument)) return false;
17126
17238
  if (expression.callee.type === import_utils100.AST_NODE_TYPES.Identifier) return expression.callee.name === "require" && isGlobal(expression.callee);
17127
- return expression.callee.type === import_utils100.AST_NODE_TYPES.MemberExpression && expression.callee.object.type === import_utils100.AST_NODE_TYPES.Identifier && expression.callee.object.name === "process" && isGlobal(expression.callee.object) && memberName6(expression.callee) === "getBuiltinModule";
17239
+ return expression.callee.type === import_utils100.AST_NODE_TYPES.MemberExpression && expression.callee.object.type === import_utils100.AST_NODE_TYPES.Identifier && expression.callee.object.name === "process" && isGlobal(expression.callee.object) && memberName7(expression.callee) === "getBuiltinModule";
17128
17240
  }
17129
17241
  function isFsSpecifier(node) {
17130
17242
  return node.type === import_utils100.AST_NODE_TYPES.Literal && (node.value === "node:fs" || node.value === "fs");
@@ -17205,7 +17317,7 @@ var prefer_node_fs_promises_default = createRule({
17205
17317
  }
17206
17318
  },
17207
17319
  MemberExpression(node) {
17208
- const name = memberName6(node);
17320
+ const name = memberName7(node);
17209
17321
  if (name?.endsWith("Sync") !== true) return;
17210
17322
  const object = unwrapAwait2(node.object);
17211
17323
  if (object.type === import_utils100.AST_NODE_TYPES.Identifier && isNamespace(object) || isFsLoader(object, isGlobal)) {
@@ -17622,15 +17734,16 @@ var prefer_nullish_filter_predicate_default = createRule({
17622
17734
  var import_utils103 = require("@typescript-eslint/utils");
17623
17735
  var ts11 = __toESM(require("typescript"), 1);
17624
17736
  var PREFER_AWAIT_IN_ASYNC_RETURN_DOCUMENTATION = {
17625
- summary: "Prefer explicit `await` when an async function directly returns one typed Promise `.then` transform.",
17626
- rationale: "Mixing a directly returned Promise callback into otherwise async control flow makes sequencing and failures harder to read.",
17737
+ summary: "Prefer explicit `await` for proven Promise `.then` calls; the default scope checks direct async returns.",
17738
+ rationale: "Promise callback chains mix explicit async control flow with nested callbacks, making sequencing and failure handling harder to read.",
17627
17739
  remediation: "Consider awaiting the Promise and returning the transformed value with ordinary async statements. Preserve catch boundaries, callback behavior, and observable scheduling when rewriting manually.",
17628
17740
  category: "maintainability",
17629
17741
  since: "15.6.3",
17630
17742
  limitations: [
17631
- "Only a single directly returned `.then` call with an inline callback is checked.",
17632
- "The receiver must be proven Promise-like by TypeScript; an earlier chain can still produce that receiver. Untyped receivers, rejection handlers and named callbacks are excluded. This is not the upstream return-await policy and no scheduling equivalence is promised.",
17633
- "Direct loader callbacks passed to resolved `React.lazy` and `next/dynamic` imports are excluded because returning the module Promise is their framework contract."
17743
+ "The default async-return scope checks one directly returned `.then` call with an inline callback. The all-promise-calls scope checks direct calls to built-in Promise/PromiseLike.then, including optional and literal-computed calls, without automatic rewrites.",
17744
+ "The receiver must be proven Promise-like by TypeScript; an earlier chain can still produce that receiver. The default async-return scope excludes rejection handlers and named callbacks. This is not the upstream return-await policy and no scheduling equivalence is promised.",
17745
+ "The default async-return scope excludes direct loader callbacks passed to resolved `React.lazy` and `next/dynamic` imports because returning the module Promise is their framework contract.",
17746
+ "All-promise-calls requires type information and excludes unproven/custom thenables, dynamic property names, property reads, destructuring, and extracted method aliases. Catch and finally remain available. Framework callback exclusions apply only to the default async-return scope."
17634
17747
  ],
17635
17748
  examples: [
17636
17749
  {
@@ -17687,15 +17800,28 @@ function promiseThenReceiver(node) {
17687
17800
  }
17688
17801
  return callee.object;
17689
17802
  }
17803
+ function directThenReceiver(node) {
17804
+ const callee = node.callee;
17805
+ if (callee.type !== import_utils103.AST_NODE_TYPES.MemberExpression) return null;
17806
+ const property = callee.property;
17807
+ const isThen = callee.computed ? property.type === import_utils103.AST_NODE_TYPES.Literal && property.value === "then" || property.type === import_utils103.AST_NODE_TYPES.TemplateLiteral && property.expressions.length === 0 && property.quasis[0]?.value.cooked === "then" : property.type === import_utils103.AST_NODE_TYPES.Identifier && property.name === "then";
17808
+ return isThen ? callee.object : null;
17809
+ }
17690
17810
  function isProvenPromiseLike(node, services) {
17691
17811
  const checker = services.program.getTypeChecker();
17692
17812
  const tsNode = services.esTreeNodeToTSNodeMap.get(node);
17693
- const receiverType = checker.getTypeAtLocation(tsNode);
17694
- if ((receiverType.flags & (ts11.TypeFlags.Any | ts11.TypeFlags.Unknown | ts11.TypeFlags.Never)) !== 0) {
17813
+ const receiverType = checker.getNonNullableType(checker.getTypeAtLocation(tsNode));
17814
+ const members = receiverType.isUnion() ? receiverType.types : [receiverType];
17815
+ return members.every((member) => isBuiltInPromiseType(member, services));
17816
+ }
17817
+ function isBuiltInPromiseType(type, services) {
17818
+ if ((type.flags & (ts11.TypeFlags.Any | ts11.TypeFlags.Unknown | ts11.TypeFlags.Never)) !== 0) {
17695
17819
  return false;
17696
17820
  }
17697
- const thenSymbol = checker.getPropertyOfType(receiverType, "then");
17698
- const hasBuiltInPromiseDeclaration = thenSymbol?.declarations?.some(
17821
+ const thenSymbol = services.program.getTypeChecker().getPropertyOfType(type, "then");
17822
+ const declarations = thenSymbol?.declarations;
17823
+ if (declarations === void 0 || declarations.length === 0) return false;
17824
+ return declarations.every(
17699
17825
  (declaration) => {
17700
17826
  let owner = declaration.parent;
17701
17827
  while (owner !== void 0 && !ts11.isInterfaceDeclaration(owner)) {
@@ -17703,8 +17829,7 @@ function isProvenPromiseLike(node, services) {
17703
17829
  }
17704
17830
  return owner !== void 0 && (owner.name.text === "Promise" || owner.name.text === "PromiseLike") && services.program.isSourceFileDefaultLibrary(owner.getSourceFile());
17705
17831
  }
17706
- ) ?? false;
17707
- return hasBuiltInPromiseDeclaration;
17832
+ );
17708
17833
  }
17709
17834
  var prefer_await_in_async_return_default = createRule({
17710
17835
  name: "prefer-await-in-async-return",
@@ -17712,15 +17837,20 @@ var prefer_await_in_async_return_default = createRule({
17712
17837
  meta: {
17713
17838
  type: "suggestion",
17714
17839
  docs: {
17715
- description: "Prefer explicit `await` when an async function directly returns one typed Promise `.then` transform."
17840
+ description: "Prefer explicit `await` for proven Promise `.then` calls; the default scope checks direct async returns."
17716
17841
  },
17717
- schema: [],
17842
+ schema: [{
17843
+ type: "object",
17844
+ properties: { scope: { type: "string", enum: ["async-return", "all-promise-calls"] } },
17845
+ additionalProperties: false
17846
+ }],
17718
17847
  messages: {
17719
- preferAwait: "This async function directly returns a Promise `.then` transform. Await the Promise, then return the transformed value with explicit async control flow."
17848
+ preferAwait: "This async function directly returns a Promise `.then` transform. Await the Promise, then return the transformed value with explicit async control flow.",
17849
+ preferAwaitCall: "This call uses built-in Promise.then(). Use async/await, preserving rejection handling and observable scheduling when rewriting."
17720
17850
  }
17721
17851
  },
17722
- defaultOptions: [],
17723
- create(context) {
17852
+ defaultOptions: [{ scope: "async-return" }],
17853
+ create(context, [options]) {
17724
17854
  let services;
17725
17855
  try {
17726
17856
  services = import_utils103.ESLintUtils.getParserServices(context);
@@ -17753,6 +17883,13 @@ var prefer_await_in_async_return_default = createRule({
17753
17883
  }
17754
17884
  },
17755
17885
  CallExpression(node) {
17886
+ if (options.scope === "all-promise-calls") {
17887
+ const receiver2 = directThenReceiver(node);
17888
+ if (receiver2 !== null && isProvenPromiseLike(receiver2, services)) {
17889
+ context.report({ node, messageId: "preferAwaitCall" });
17890
+ }
17891
+ return;
17892
+ }
17756
17893
  const owner = directAsyncReturnOwner(node);
17757
17894
  if (owner === null || isFrameworkLoaderCallback(owner)) return;
17758
17895
  const receiver = promiseThenReceiver(node);
@@ -21365,7 +21502,7 @@ var REQUIRE_SQL_ACCESS_CLASS_DOCUMENTATION = {
21365
21502
  }
21366
21503
  ]
21367
21504
  };
21368
- function memberName7(node) {
21505
+ function memberName8(node) {
21369
21506
  if (!node.computed && node.property.type === import_utils116.AST_NODE_TYPES.Identifier)
21370
21507
  return node.property.name;
21371
21508
  if (node.computed && node.property.type === import_utils116.AST_NODE_TYPES.Literal && typeof node.property.value === "string")
@@ -21383,7 +21520,7 @@ function databaseReceiver(node) {
21383
21520
  if (node.type === import_utils116.AST_NODE_TYPES.Identifier)
21384
21521
  return DATABASE_NAMES.test(node.name);
21385
21522
  if (node.type !== import_utils116.AST_NODE_TYPES.MemberExpression) return false;
21386
- const name = memberName7(node);
21523
+ const name = memberName8(node);
21387
21524
  return name === "DB" || name !== null && DATABASE_NAMES.test(name);
21388
21525
  }
21389
21526
  function databaseRootMember(node) {
@@ -21404,7 +21541,7 @@ function databaseRootMember(node) {
21404
21541
  }
21405
21542
  if (current.type === import_utils116.AST_NODE_TYPES.MemberExpression) {
21406
21543
  if (current.object.type === import_utils116.AST_NODE_TYPES.ThisExpression)
21407
- return memberName7(current);
21544
+ return memberName8(current);
21408
21545
  current = current.object;
21409
21546
  continue;
21410
21547
  }
@@ -21428,7 +21565,7 @@ function expressionHasDatabaseMarker(node) {
21428
21565
  continue;
21429
21566
  }
21430
21567
  if (current.type === import_utils116.AST_NODE_TYPES.MemberExpression) {
21431
- const name = memberName7(current);
21568
+ const name = memberName8(current);
21432
21569
  if (name === "DB" || name !== null && DATABASE_NAMES.test(name))
21433
21570
  return true;
21434
21571
  current = current.object;
@@ -21450,7 +21587,7 @@ function expressionCallsBuilder(node) {
21450
21587
  }
21451
21588
  if (current.type === import_utils116.AST_NODE_TYPES.CallExpression) {
21452
21589
  if (current.callee.type !== import_utils116.AST_NODE_TYPES.MemberExpression) return false;
21453
- const name = memberName7(current.callee);
21590
+ const name = memberName8(current.callee);
21454
21591
  if (name !== null && BUILDER_METHODS.has(name)) return true;
21455
21592
  current = current.callee.object;
21456
21593
  continue;
@@ -21501,7 +21638,7 @@ function thisRootMember(node) {
21501
21638
  let current = node;
21502
21639
  let root = null;
21503
21640
  while (current.type === import_utils116.AST_NODE_TYPES.MemberExpression) {
21504
- const name = memberName7(current);
21641
+ const name = memberName8(current);
21505
21642
  if (name === null) return null;
21506
21643
  root = name;
21507
21644
  current = current.object;
@@ -21555,7 +21692,7 @@ var require_sql_access_class_default = createRule({
21555
21692
  CallExpression(node) {
21556
21693
  if (node.callee.type !== import_utils116.AST_NODE_TYPES.MemberExpression)
21557
21694
  return;
21558
- const method = memberName7(node.callee);
21695
+ const method = memberName8(node.callee);
21559
21696
  if (knownNonDatabase(node.callee.object)) return;
21560
21697
  if (method === null || !isDatabaseOperation(method, node.callee.object))
21561
21698
  return;
@@ -23185,10 +23322,11 @@ var import_node_fs2 = require("fs");
23185
23322
  var import_node_path2 = require("path");
23186
23323
  var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]);
23187
23324
  var NEXT_COMPONENT = /^(?:src\/)?app\/(?:.*\/)?(?:page|layout|loading|not-found|template|error|global-error|default|forbidden|unauthorized)\.[jt]sx?$/u;
23325
+ var NEXT_METADATA = /^(?:src\/)?app\/(?:.*\/)?(?:(?:opengraph-image|twitter-image|icon|apple-icon)\.[jt]sx?|(?:robots|sitemap|manifest)\.[jt]s)$/u;
23188
23326
  var NEXT_ROUTE = /^(?:src\/)?app\/(?:.*\/)?route\.[jt]s$/u;
23189
23327
  function isFrameworkEntrypoint(filename, exportKey) {
23190
23328
  const normalized = filename.replaceAll("\\", "/");
23191
- if (!/(?:^|\/)(?:app|pages)\/|(?:^|\/)(?:middleware|proxy)\.[jt]s$/u.test(normalized)) return false;
23329
+ if (!/(?:^|\/)(?:app|pages)\/|(?:^|\/)(?:middleware|proxy|instrumentation)\.[jt]s$/u.test(normalized)) return false;
23192
23330
  const owner = packageOwner(normalized);
23193
23331
  if (owner === null) return false;
23194
23332
  const path = (0, import_node_path2.relative)(owner.root, normalized).replaceAll("\\", "/");
@@ -23197,9 +23335,12 @@ function isFrameworkEntrypoint(filename, exportKey) {
23197
23335
  }
23198
23336
  function isNextEntrypoint(path, exportKey) {
23199
23337
  const privateAppFolder = /^(?:src\/)?app\/(?:.*\/)?_[^/]+\//u.test(path);
23200
- if (!privateAppFolder && NEXT_COMPONENT.test(path) && exportKey === "default") return true;
23338
+ if (!privateAppFolder && (NEXT_COMPONENT.test(path) || NEXT_METADATA.test(path)) && exportKey === "default") return true;
23201
23339
  if (!privateAppFolder && NEXT_ROUTE.test(path) && HTTP_METHODS.has(exportKey)) return true;
23202
23340
  if (/^(?:src\/)?pages\/.*\.[jt]sx?$/u.test(path) && exportKey === "default") return true;
23341
+ if (/^(?:src\/)?instrumentation\.[jt]s$/u.test(path)) {
23342
+ return exportKey === "register" || exportKey === "onRequestError";
23343
+ }
23203
23344
  const middleware = /^(?:src\/)?(middleware|proxy)\.[jt]s$/u.exec(path);
23204
23345
  return middleware !== null && (exportKey === "default" || exportKey === middleware[1]);
23205
23346
  }
@@ -23242,7 +23383,7 @@ var SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION = {
23242
23383
  "Framework entrypoints, generic stems covered by no-generic-single-export-module, tests, generated files, anonymous defaults, CommonJS, unresolved re-exports, and emission-dependent exports are excluded.",
23243
23384
  "The rule compares the primary filename stem and preserves a single private underscore prefix and conventional suffixes such as .server or .worker. Supporting types do not exempt a sole runtime export; public runtime aliases count as distinct exports.",
23244
23385
  "Exported destructuring patterns are excluded rather than undercounted as public exports.",
23245
- "Next.js and Astro routing exemptions require the nearest package.json to declare the framework, a conventional entrypoint path, and its expected runtime export. Custom routing roots and pageExtensions are not inferred."
23386
+ "Next.js metadata routes, instrumentation, and other Next.js and Astro entrypoint exemptions require the nearest package.json to declare the framework, a conventional entrypoint path, and its expected runtime export. Custom routing roots and pageExtensions are not inferred."
23246
23387
  ],
23247
23388
  examples: [
23248
23389
  { id: "matching-class", title: "Match a class and module", outcome: "no-match", files: [{ path: "src/artifact-store.ts", source: "export class ArtifactStore {}" }], focusPath: "src/artifact-store.ts", expectedCount: 0, public: true },
@@ -23808,7 +23949,7 @@ var RULES = {
23808
23949
  };
23809
23950
  var meta = {
23810
23951
  name: "@sarj/eslint-plugin",
23811
- version: "16.2.4"
23952
+ version: "16.2.6"
23812
23953
  };
23813
23954
  var APPLICATION_ONLY_RULES = [];
23814
23955
  var LIBRARY_IMPORT_POLICY = ["error", {