@sarj/eslint-plugin 8.0.0 → 9.1.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.d.cts CHANGED
@@ -76,7 +76,9 @@ interface RuleOptions {
76
76
  }
77
77
 
78
78
  /**
79
- * @fileoverview _renames — a renamed rule keeps its old name registered as a deprecated alias, because a name that simply vanishes reads as growth to a shrink-only baseline.
79
+ * @fileoverview _renames — every rule this plugin has renamed, old name to new; the old names no longer resolve, so this map is what says what to write instead.
80
+ *
81
+ * It feeds `scripts/sync-rule-ledger.py`, which turns each entry into a `renamed` row of the shipped `rule-ledger.json` that `sarj-lint-configs doctor` reads.
80
82
  *
81
83
  * Evidence: https://github.com/sarj-ai/standards/blob/main/docs/rules/_renames.md
82
84
  */
@@ -269,7 +271,6 @@ declare const rules: {
269
271
  name: string;
270
272
  };
271
273
  };
272
- type RuleModule = (typeof rules)[keyof typeof rules];
273
274
  declare const recommendedRules: {
274
275
  readonly "@sarj/enforce-file-structure": "warn";
275
276
  readonly "@sarj/no-async-callback-in-wait-for": "warn";
@@ -391,13 +392,9 @@ type FlatPreset = {
391
392
  declare const plugin: {
392
393
  meta: {
393
394
  readonly name: "@sarj/eslint-plugin";
394
- readonly version: "8.0.0";
395
+ readonly version: "9.1.0";
395
396
  };
396
397
  rules: {
397
- "jsdoc-restates-signature": RuleModule;
398
- "no-async-callback-in-waitfor": RuleModule;
399
- "strict-test-assertions": RuleModule;
400
- "trailing-value-narration": RuleModule;
401
398
  "enforce-file-structure": _typescript_eslint_utils_ts_eslint.RuleModule<"importsFirst" | "useServerDirective", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
402
399
  name: string;
403
400
  };
package/dist/index.d.ts CHANGED
@@ -76,7 +76,9 @@ interface RuleOptions {
76
76
  }
77
77
 
78
78
  /**
79
- * @fileoverview _renames — a renamed rule keeps its old name registered as a deprecated alias, because a name that simply vanishes reads as growth to a shrink-only baseline.
79
+ * @fileoverview _renames — every rule this plugin has renamed, old name to new; the old names no longer resolve, so this map is what says what to write instead.
80
+ *
81
+ * It feeds `scripts/sync-rule-ledger.py`, which turns each entry into a `renamed` row of the shipped `rule-ledger.json` that `sarj-lint-configs doctor` reads.
80
82
  *
81
83
  * Evidence: https://github.com/sarj-ai/standards/blob/main/docs/rules/_renames.md
82
84
  */
@@ -269,7 +271,6 @@ declare const rules: {
269
271
  name: string;
270
272
  };
271
273
  };
272
- type RuleModule = (typeof rules)[keyof typeof rules];
273
274
  declare const recommendedRules: {
274
275
  readonly "@sarj/enforce-file-structure": "warn";
275
276
  readonly "@sarj/no-async-callback-in-wait-for": "warn";
@@ -391,13 +392,9 @@ type FlatPreset = {
391
392
  declare const plugin: {
392
393
  meta: {
393
394
  readonly name: "@sarj/eslint-plugin";
394
- readonly version: "8.0.0";
395
+ readonly version: "9.1.0";
395
396
  };
396
397
  rules: {
397
- "jsdoc-restates-signature": RuleModule;
398
- "no-async-callback-in-waitfor": RuleModule;
399
- "strict-test-assertions": RuleModule;
400
- "trailing-value-narration": RuleModule;
401
398
  "enforce-file-structure": _typescript_eslint_utils_ts_eslint.RuleModule<"importsFirst" | "useServerDirective", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
402
399
  name: string;
403
400
  };
package/dist/index.js CHANGED
@@ -8729,26 +8729,111 @@ import { AST_NODE_TYPES as AST_NODE_TYPES41 } from "@typescript-eslint/utils";
8729
8729
  var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Props|Args|Env|Environment|Callbacks|Flags)$/;
8730
8730
  var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
8731
8731
  var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
8732
+ var BUILTIN_CONTAINER_TYPE_RE = /^(?:Record|Map|WeakMap|Set|WeakSet|Array|ReadonlyArray|ReadonlyMap|ReadonlySet|Promise|Partial|Required|Readonly|Pick|Omit|Exclude|Extract|NonNullable|Awaited|Parameters|ReturnType|InstanceType)$/;
8732
8733
  var TRANSPORT_WRAPPER_NAME_RE = /Client$/;
8733
8734
  var ROUTER_FACTORY_NAME = "Router";
8734
8735
  var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
8735
8736
  var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES41.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES41.ExportDefaultDeclaration;
8736
8737
  var qualifiedName = (name) => name.type === AST_NODE_TYPES41.Identifier ? name.name : name.type === AST_NODE_TYPES41.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
8737
- var typeReferenceName = (annotated) => {
8738
+ var readTypeReference = (annotation) => {
8739
+ if (annotation === void 0 || annotation.type !== AST_NODE_TYPES41.TSTypeReference) return null;
8740
+ const { typeName } = annotation;
8741
+ const rightmost = typeName.type === AST_NODE_TYPES41.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES41.TSQualifiedName ? typeName.right.name : null;
8742
+ if (rightmost === null) return null;
8743
+ return { typeName: rightmost, display: qualifiedName(typeName) };
8744
+ };
8745
+ var namedParameterCollaborator = (annotated) => {
8738
8746
  let target = annotated;
8739
8747
  if (target.type === AST_NODE_TYPES41.TSParameterProperty) target = target.parameter;
8740
8748
  if (target.type === AST_NODE_TYPES41.AssignmentPattern) target = target.left;
8741
8749
  if (target.type !== AST_NODE_TYPES41.Identifier) return null;
8742
- const annotation = target.typeAnnotation?.typeAnnotation;
8743
- if (annotation === void 0 || annotation.type !== AST_NODE_TYPES41.TSTypeReference) {
8750
+ const reference = readTypeReference(target.typeAnnotation?.typeAnnotation);
8751
+ if (reference === null) return null;
8752
+ return { name: target.name, ...reference };
8753
+ };
8754
+ var propertySignatureTypes = (members) => {
8755
+ const types = /* @__PURE__ */ new Map();
8756
+ for (const member of members) {
8757
+ if (member.type !== AST_NODE_TYPES41.TSPropertySignature) continue;
8758
+ if (member.computed || member.key.type !== AST_NODE_TYPES41.Identifier) continue;
8759
+ const reference = readTypeReference(member.typeAnnotation?.typeAnnotation);
8760
+ if (reference === null) continue;
8761
+ types.set(member.key.name, reference);
8762
+ }
8763
+ return types;
8764
+ };
8765
+ var fileTypeIndex = (program) => {
8766
+ const objects = /* @__PURE__ */ new Map();
8767
+ const functionAliases = /* @__PURE__ */ new Set();
8768
+ for (const statement of program.body) {
8769
+ const declaration = statement.type === AST_NODE_TYPES41.ExportNamedDeclaration ? statement.declaration : statement;
8770
+ if (declaration?.type === AST_NODE_TYPES41.TSInterfaceDeclaration) {
8771
+ objects.set(declaration.id.name, propertySignatureTypes(declaration.body.body));
8772
+ continue;
8773
+ }
8774
+ if (declaration?.type !== AST_NODE_TYPES41.TSTypeAliasDeclaration) continue;
8775
+ const aliased = declaration.typeAnnotation;
8776
+ if (aliased.type === AST_NODE_TYPES41.TSFunctionType || aliased.type === AST_NODE_TYPES41.TSConstructorType) {
8777
+ functionAliases.add(declaration.id.name);
8778
+ continue;
8779
+ }
8780
+ const literals = aliased.type === AST_NODE_TYPES41.TSTypeLiteral ? [aliased] : aliased.type === AST_NODE_TYPES41.TSIntersectionType ? aliased.types.filter((part) => part.type === AST_NODE_TYPES41.TSTypeLiteral) : [];
8781
+ if (literals.length === 0) continue;
8782
+ const merged = /* @__PURE__ */ new Map();
8783
+ for (const literal of literals) {
8784
+ for (const [name, reference] of propertySignatureTypes(literal.members)) {
8785
+ merged.set(name, reference);
8786
+ }
8787
+ }
8788
+ objects.set(declaration.id.name, merged);
8789
+ }
8790
+ return { objects, functionAliases };
8791
+ };
8792
+ var bagMemberTypes = (annotation, declared) => {
8793
+ if (annotation.type === AST_NODE_TYPES41.TSTypeLiteral) {
8794
+ return propertySignatureTypes(annotation.members);
8795
+ }
8796
+ if (annotation.type !== AST_NODE_TYPES41.TSTypeReference || annotation.typeName.type !== AST_NODE_TYPES41.Identifier) {
8744
8797
  return null;
8745
8798
  }
8746
- const { typeName } = annotation;
8747
- const rightmost = typeName.type === AST_NODE_TYPES41.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES41.TSQualifiedName ? typeName.right.name : null;
8748
- if (rightmost === null) return null;
8749
- return { name: target.name, typeName: rightmost, display: qualifiedName(typeName) };
8799
+ return declared().objects.get(annotation.typeName.name) ?? null;
8800
+ };
8801
+ var objectPatternCollaborators = (pattern, declared) => {
8802
+ const annotation = pattern.typeAnnotation?.typeAnnotation;
8803
+ if (annotation === void 0) return [];
8804
+ const members = bagMemberTypes(annotation, declared);
8805
+ if (members === null) return [];
8806
+ const collaborators = [];
8807
+ for (const property of pattern.properties) {
8808
+ if (property.type !== AST_NODE_TYPES41.Property || property.computed) continue;
8809
+ if (property.key.type !== AST_NODE_TYPES41.Identifier) continue;
8810
+ const key = property.key.name;
8811
+ const bound = property.value.type === AST_NODE_TYPES41.AssignmentPattern ? property.value.left : property.value;
8812
+ if (bound.type !== AST_NODE_TYPES41.Identifier) continue;
8813
+ if (CONFIGISH_NAME_RE.test(key)) continue;
8814
+ const reference = members.get(key);
8815
+ if (reference === void 0) continue;
8816
+ collaborators.push({ name: bound.name, ...reference });
8817
+ }
8818
+ return collaborators;
8819
+ };
8820
+ var parameterCollaborators = (parameter, declared) => {
8821
+ let target = parameter;
8822
+ if (target.type === AST_NODE_TYPES41.AssignmentPattern) target = target.left;
8823
+ if (target.type === AST_NODE_TYPES41.ObjectPattern) {
8824
+ return objectPatternCollaborators(target, declared);
8825
+ }
8826
+ const named2 = namedParameterCollaborator(parameter);
8827
+ return named2 === null ? [] : [named2];
8828
+ };
8829
+ var typeParameterNames = (...declarations) => {
8830
+ const names = /* @__PURE__ */ new Set();
8831
+ for (const declaration of declarations) {
8832
+ for (const parameter of declaration?.params ?? []) names.add(parameter.name.name);
8833
+ }
8834
+ return names;
8750
8835
  };
8751
- var readConstructor = (ctor) => {
8836
+ var readConstructor = (ctor, declared, typeParameters) => {
8752
8837
  const body = ctor.value.body;
8753
8838
  const storedFrom = /* @__PURE__ */ new Set();
8754
8839
  let constructedFields = 0;
@@ -8771,13 +8856,16 @@ var readConstructor = (ctor) => {
8771
8856
  }
8772
8857
  const collaborators = [];
8773
8858
  for (const parameter of ctor.value.params) {
8774
- const reference = typeReferenceName(parameter);
8775
- if (reference === null) continue;
8776
- const stored = parameter.type === AST_NODE_TYPES41.TSParameterProperty || storedFrom.has(reference.name);
8777
- if (!stored) continue;
8778
- if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
8779
- if (CONFIGISH_NAME_RE.test(reference.name)) continue;
8780
- collaborators.push(reference);
8859
+ for (const reference of parameterCollaborators(parameter, declared)) {
8860
+ const stored = parameter.type === AST_NODE_TYPES41.TSParameterProperty || storedFrom.has(reference.name);
8861
+ if (!stored) continue;
8862
+ if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
8863
+ if (CONFIGISH_NAME_RE.test(reference.name)) continue;
8864
+ if (typeParameters.has(reference.typeName)) continue;
8865
+ if (BUILTIN_CONTAINER_TYPE_RE.test(reference.typeName)) continue;
8866
+ if (declared().functionAliases.has(reference.typeName)) continue;
8867
+ collaborators.push(reference);
8868
+ }
8781
8869
  }
8782
8870
  return { collaborators, constructedFields };
8783
8871
  };
@@ -8859,6 +8947,8 @@ var require_interface_for_injected_service_default = createRule({
8859
8947
  const { filename } = context;
8860
8948
  if (isTestFile(filename) || isStoryFile(filename) || isScriptFile(filename)) return {};
8861
8949
  if (isGeneratedFile(filename, context.sourceCode.getText())) return {};
8950
+ let declaredTypes = null;
8951
+ const objectTypes = () => declaredTypes ??= fileTypeIndex(context.sourceCode.ast);
8862
8952
  return {
8863
8953
  ClassDeclaration(node) {
8864
8954
  if (node.id === null) return;
@@ -8871,7 +8961,11 @@ var require_interface_for_injected_service_default = createRule({
8871
8961
  (member) => member.type === AST_NODE_TYPES41.MethodDefinition && member.kind === "constructor"
8872
8962
  );
8873
8963
  if (ctor === void 0) return;
8874
- const { collaborators, constructedFields } = readConstructor(ctor);
8964
+ const { collaborators, constructedFields } = readConstructor(
8965
+ ctor,
8966
+ objectTypes,
8967
+ typeParameterNames(node.typeParameters, ctor.value.typeParameters)
8968
+ );
8875
8969
  if (collaborators.length === 0) return;
8876
8970
  if (constructedFields > collaborators.length) return;
8877
8971
  if (isFrameworkWiring(node.body)) return;
@@ -9254,29 +9348,8 @@ var rules = {
9254
9348
  };
9255
9349
  var meta = {
9256
9350
  name: "@sarj/eslint-plugin",
9257
- version: "8.0.0"
9351
+ version: "9.1.0"
9258
9352
  };
9259
- var renames = renamedRules;
9260
- var deprecatedAliases = Object.fromEntries(
9261
- Object.entries(renames).map(([from, to]) => {
9262
- const rule = rules[to];
9263
- return [
9264
- from,
9265
- {
9266
- ...rule,
9267
- meta: {
9268
- ...rule.meta,
9269
- deprecated: {
9270
- message: `Renamed to \`@sarj/${to}\`.`,
9271
- replacedBy: [{ rule: { name: `@sarj/${to}` } }],
9272
- deprecatedSince: meta.version
9273
- }
9274
- }
9275
- }
9276
- ];
9277
- })
9278
- );
9279
- var allRules = { ...rules, ...deprecatedAliases };
9280
9353
  var recommendedRules = {
9281
9354
  "@sarj/enforce-file-structure": "warn",
9282
9355
  "@sarj/no-async-callback-in-wait-for": "warn",
@@ -9383,7 +9456,7 @@ var strictRules = {
9383
9456
  };
9384
9457
  var plugin = {
9385
9458
  meta,
9386
- rules: allRules,
9459
+ rules,
9387
9460
  // Withdrawn names travel WITH the plugin so a consumer's migration script and
9388
9461
  // this repo's gates read one map, not two. See src/rules/_retired.ts.
9389
9462
  retiredRules,