@sarj/eslint-plugin 9.0.0 → 9.2.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
@@ -392,7 +392,7 @@ type FlatPreset = {
392
392
  declare const plugin: {
393
393
  meta: {
394
394
  readonly name: "@sarj/eslint-plugin";
395
- readonly version: "9.0.0";
395
+ readonly version: "9.2.0";
396
396
  };
397
397
  rules: {
398
398
  "enforce-file-structure": _typescript_eslint_utils_ts_eslint.RuleModule<"importsFirst" | "useServerDirective", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
package/dist/index.d.ts CHANGED
@@ -392,7 +392,7 @@ type FlatPreset = {
392
392
  declare const plugin: {
393
393
  meta: {
394
394
  readonly name: "@sarj/eslint-plugin";
395
- readonly version: "9.0.0";
395
+ readonly version: "9.2.0";
396
396
  };
397
397
  rules: {
398
398
  "enforce-file-structure": _typescript_eslint_utils_ts_eslint.RuleModule<"importsFirst" | "useServerDirective", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
package/dist/index.js CHANGED
@@ -1540,12 +1540,6 @@ var no_dynamic_sql_default = createRule({
1540
1540
 
1541
1541
  // src/rules/no-enum.ts
1542
1542
  import "@typescript-eslint/utils";
1543
- var DEFAULT_IGNORE_PATTERNS = [
1544
- /[\\/]generated[\\/]/,
1545
- /[\\/]openapi-gen[\\/]/,
1546
- /\.gen\.tsx?$/,
1547
- /\.generated\.tsx?$/
1548
- ];
1549
1543
  function matchesAnyPattern(filename, patterns) {
1550
1544
  for (const pattern of patterns) {
1551
1545
  const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
@@ -1555,10 +1549,6 @@ function matchesAnyPattern(filename, patterns) {
1555
1549
  }
1556
1550
  return false;
1557
1551
  }
1558
- function hasGeneratedMarker(sourceText) {
1559
- const head = sourceText.slice(0, 1024);
1560
- return /@generated\b/.test(head);
1561
- }
1562
1552
  var no_enum_default = createRule({
1563
1553
  name: "no-enum",
1564
1554
  meta: {
@@ -1588,12 +1578,8 @@ var no_enum_default = createRule({
1588
1578
  const ignoreFiles = options.ignoreFiles ?? [];
1589
1579
  const filename = context.filename;
1590
1580
  const sourceText = context.sourceCode.getText();
1591
- const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some(
1592
- (re) => re.test(filename)
1593
- );
1594
1581
  const isIgnoredByOption = ignoreFiles.length > 0 && matchesAnyPattern(filename, ignoreFiles);
1595
- const isGenerated = hasGeneratedMarker(sourceText) || isGeneratedFile(filename, sourceText);
1596
- if (isIgnoredByDefault || isIgnoredByOption || isGenerated) {
1582
+ if (isIgnoredByOption || isGeneratedFile(filename, sourceText)) {
1597
1583
  return {};
1598
1584
  }
1599
1585
  return {
@@ -3341,35 +3327,6 @@ var no_restated_comment_default = createRule({
3341
3327
 
3342
3328
  // src/rules/no-restated-jsdoc.ts
3343
3329
  import { AST_NODE_TYPES as AST_NODE_TYPES16 } from "@typescript-eslint/utils";
3344
- var VALUE_TAGS = /* @__PURE__ */ new Set([
3345
- "alpha",
3346
- "author",
3347
- "beta",
3348
- "category",
3349
- "copyright",
3350
- "default",
3351
- "defaultvalue",
3352
- "deprecated",
3353
- "example",
3354
- "experimental",
3355
- "fileoverview",
3356
- "fixme",
3357
- "group",
3358
- "inheritdoc",
3359
- "internal",
3360
- "license",
3361
- "link",
3362
- "module",
3363
- "override",
3364
- "packagedocumentation",
3365
- "remarks",
3366
- "see",
3367
- "since",
3368
- "template",
3369
- "throws",
3370
- "todo",
3371
- "typeparam"
3372
- ]);
3373
3330
  var MODELLED_TAGS = /* @__PURE__ */ new Set([
3374
3331
  "arg",
3375
3332
  "argument",
@@ -3494,7 +3451,6 @@ var no_restated_jsdoc_default = createRule({
3494
3451
  const { description, tags } = parseJsDoc(comment.value);
3495
3452
  if (DIRECTIVE_RE3.test(description)) continue;
3496
3453
  const tagNames = new Set(tags.map((tag) => tag.name));
3497
- if ([...tagNames].some((name) => VALUE_TAGS.has(name))) continue;
3498
3454
  if ([...tagNames].some((name) => !MODELLED_TAGS.has(name))) continue;
3499
3455
  if (isProtected(description)) continue;
3500
3456
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
@@ -6975,25 +6931,32 @@ var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
6975
6931
  var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
6976
6932
  var CSS_VAR_REFERENCE_RE = /var\(\s*--/;
6977
6933
  var STORIES_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
6978
- var SEMANTIC_TOKEN_RE = /@theme\b|--(?:background|foreground|primary|secondary|muted|accent|destructive|border|card|popover)\b|(?:bg|text|border)-(?:background|foreground|primary|secondary|muted|accent|destructive|border|card|popover)\b/;
6979
- var CONFIG_IS_SUFFICIENT = /* @__PURE__ */ new Set([
6980
- "components.json",
6981
- "tailwind.config.cjs",
6982
- "tailwind.config.js",
6983
- "tailwind.config.mjs",
6984
- "tailwind.config.ts"
6985
- ]);
6986
- var DETECTION_FILES = [
6934
+ var TOKEN_ROLES = "background|foreground|primary|secondary|muted|accent|destructive|danger|success|warning|info|border|card|popover|surface|content|base|subtle|default|ring|input|fg|bg";
6935
+ var SEMANTIC_TOKEN_RE = new RegExp(
6936
+ `--(?:color-)?(?:${TOKEN_ROLES})\\b|(?:bg|text|border|ring|fill|stroke)-(?:ui-)?(?:${TOKEN_ROLES})\\b`
6937
+ );
6938
+ var THEME_BLOCK_RE = /@theme\b/;
6939
+ var PRESENCE_MARKERS = [
6987
6940
  "components.json",
6988
6941
  "tailwind.config.js",
6989
6942
  "tailwind.config.cjs",
6990
6943
  "tailwind.config.mjs",
6991
6944
  "tailwind.config.ts",
6945
+ "tailwind.config.mts",
6946
+ "tailwind.config.cts"
6947
+ ];
6948
+ var CSS_DETECTION_FILES = [
6992
6949
  "app/globals.css",
6950
+ "app/global.css",
6951
+ "app/styles/globals.css",
6993
6952
  "src/app/globals.css",
6953
+ "src/app/global.css",
6954
+ "src/global.css",
6994
6955
  "src/index.css",
6995
6956
  "src/styles/globals.css",
6996
- "styles/globals.css"
6957
+ "src/styles/index.css",
6958
+ "styles/globals.css",
6959
+ "styles/index.css"
6997
6960
  ];
6998
6961
  var WORKSPACE_ROOT_FILES = [
6999
6962
  "pnpm-workspace.yaml",
@@ -7072,12 +7035,13 @@ var isInsideIconFactoryPath = (node) => {
7072
7035
  return false;
7073
7036
  };
7074
7037
  var hasMarkerAt = (dir) => {
7075
- for (const rel of DETECTION_FILES) {
7038
+ if (PRESENCE_MARKERS.some((rel) => existsSync(join(dir, rel)))) return true;
7039
+ for (const rel of CSS_DETECTION_FILES) {
7076
7040
  const candidate = join(dir, rel);
7077
7041
  if (!existsSync(candidate)) continue;
7078
- if (CONFIG_IS_SUFFICIENT.has(rel)) return true;
7079
7042
  try {
7080
- if (SEMANTIC_TOKEN_RE.test(readFileSync(candidate, "utf8"))) return true;
7043
+ const css = readFileSync(candidate, "utf8");
7044
+ if (SEMANTIC_TOKEN_RE.test(css) || THEME_BLOCK_RE.test(css)) return true;
7081
7045
  } catch {
7082
7046
  }
7083
7047
  }
@@ -8542,32 +8506,6 @@ var prefer_zod_infer_default = createRule({
8542
8506
 
8543
8507
  // src/rules/require-assert-never.ts
8544
8508
  import { AST_NODE_TYPES as AST_NODE_TYPES39 } from "@typescript-eslint/utils";
8545
- var isAssertNeverCall = (expression) => {
8546
- if (expression.type !== AST_NODE_TYPES39.CallExpression) return false;
8547
- const callee = expression.callee;
8548
- if (callee.type === AST_NODE_TYPES39.Identifier) {
8549
- return callee.name === "assertNever";
8550
- }
8551
- if (callee.type === AST_NODE_TYPES39.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES39.Identifier) {
8552
- return callee.property.name === "assertNever";
8553
- }
8554
- return false;
8555
- };
8556
- var statementContainsAssertNever = (statement) => {
8557
- if (statement.type === AST_NODE_TYPES39.ExpressionStatement) {
8558
- return isAssertNeverCall(statement.expression);
8559
- }
8560
- if (statement.type === AST_NODE_TYPES39.ThrowStatement) {
8561
- return isAssertNeverCall(statement.argument);
8562
- }
8563
- if (statement.type === AST_NODE_TYPES39.ReturnStatement) {
8564
- return statement.argument !== null && isAssertNeverCall(statement.argument);
8565
- }
8566
- if (statement.type === AST_NODE_TYPES39.BlockStatement) {
8567
- return statement.body.some(statementContainsAssertNever);
8568
- }
8569
- return false;
8570
- };
8571
8509
  var isRuntimeHandlingStatement = (statement) => {
8572
8510
  if (statement.type === AST_NODE_TYPES39.EmptyStatement) return false;
8573
8511
  if (statement.type === AST_NODE_TYPES39.BlockStatement) {
@@ -8613,7 +8551,6 @@ var require_assert_never_default = createRule({
8613
8551
  if (defaultIndex === -1) return;
8614
8552
  const defaultCase = node.cases[defaultIndex];
8615
8553
  if (defaultCase === void 0) return;
8616
- if (defaultCase.consequent.some(statementContainsAssertNever)) return;
8617
8554
  if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;
8618
8555
  if (isFallthroughDefault(node, defaultIndex)) return;
8619
8556
  if (isCommentOnlyNoopDefault(defaultCase, context.sourceCode)) return;
@@ -8628,7 +8565,6 @@ var require_assert_never_default = createRule({
8628
8565
 
8629
8566
  // src/rules/require-fetch-timeout.ts
8630
8567
  import { AST_NODE_TYPES as AST_NODE_TYPES40, ASTUtils as ASTUtils2 } from "@typescript-eslint/utils";
8631
- var CODEMOD_FIXTURE_RE = /[\\/]__testfixtures__[\\/]/;
8632
8568
  var GLOBAL_OBJECTS2 = /* @__PURE__ */ new Set([
8633
8569
  "globalThis",
8634
8570
  "window",
@@ -8689,7 +8625,7 @@ var require_fetch_timeout_default = createRule({
8689
8625
  },
8690
8626
  defaultOptions: [{}],
8691
8627
  create(context, [optionsArg]) {
8692
- if (isTestFile(context.filename) || isScriptFile(context.filename) || CODEMOD_FIXTURE_RE.test(context.filename)) {
8628
+ if (isTestFile(context.filename) || isScriptFile(context.filename)) {
8693
8629
  return {};
8694
8630
  }
8695
8631
  const allowIn = optionsArg?.allowIn ?? [];
@@ -8729,26 +8665,111 @@ import { AST_NODE_TYPES as AST_NODE_TYPES41 } from "@typescript-eslint/utils";
8729
8665
  var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Props|Args|Env|Environment|Callbacks|Flags)$/;
8730
8666
  var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
8731
8667
  var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
8668
+ 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
8669
  var TRANSPORT_WRAPPER_NAME_RE = /Client$/;
8733
8670
  var ROUTER_FACTORY_NAME = "Router";
8734
8671
  var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
8735
8672
  var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES41.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES41.ExportDefaultDeclaration;
8736
8673
  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) => {
8674
+ var readTypeReference = (annotation) => {
8675
+ if (annotation === void 0 || annotation.type !== AST_NODE_TYPES41.TSTypeReference) return null;
8676
+ const { typeName } = annotation;
8677
+ const rightmost = typeName.type === AST_NODE_TYPES41.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES41.TSQualifiedName ? typeName.right.name : null;
8678
+ if (rightmost === null) return null;
8679
+ return { typeName: rightmost, display: qualifiedName(typeName) };
8680
+ };
8681
+ var namedParameterCollaborator = (annotated) => {
8738
8682
  let target = annotated;
8739
8683
  if (target.type === AST_NODE_TYPES41.TSParameterProperty) target = target.parameter;
8740
8684
  if (target.type === AST_NODE_TYPES41.AssignmentPattern) target = target.left;
8741
8685
  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) {
8686
+ const reference = readTypeReference(target.typeAnnotation?.typeAnnotation);
8687
+ if (reference === null) return null;
8688
+ return { name: target.name, ...reference };
8689
+ };
8690
+ var propertySignatureTypes = (members) => {
8691
+ const types = /* @__PURE__ */ new Map();
8692
+ for (const member of members) {
8693
+ if (member.type !== AST_NODE_TYPES41.TSPropertySignature) continue;
8694
+ if (member.computed || member.key.type !== AST_NODE_TYPES41.Identifier) continue;
8695
+ const reference = readTypeReference(member.typeAnnotation?.typeAnnotation);
8696
+ if (reference === null) continue;
8697
+ types.set(member.key.name, reference);
8698
+ }
8699
+ return types;
8700
+ };
8701
+ var fileTypeIndex = (program) => {
8702
+ const objects = /* @__PURE__ */ new Map();
8703
+ const functionAliases = /* @__PURE__ */ new Set();
8704
+ for (const statement of program.body) {
8705
+ const declaration = statement.type === AST_NODE_TYPES41.ExportNamedDeclaration ? statement.declaration : statement;
8706
+ if (declaration?.type === AST_NODE_TYPES41.TSInterfaceDeclaration) {
8707
+ objects.set(declaration.id.name, propertySignatureTypes(declaration.body.body));
8708
+ continue;
8709
+ }
8710
+ if (declaration?.type !== AST_NODE_TYPES41.TSTypeAliasDeclaration) continue;
8711
+ const aliased = declaration.typeAnnotation;
8712
+ if (aliased.type === AST_NODE_TYPES41.TSFunctionType || aliased.type === AST_NODE_TYPES41.TSConstructorType) {
8713
+ functionAliases.add(declaration.id.name);
8714
+ continue;
8715
+ }
8716
+ 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) : [];
8717
+ if (literals.length === 0) continue;
8718
+ const merged = /* @__PURE__ */ new Map();
8719
+ for (const literal of literals) {
8720
+ for (const [name, reference] of propertySignatureTypes(literal.members)) {
8721
+ merged.set(name, reference);
8722
+ }
8723
+ }
8724
+ objects.set(declaration.id.name, merged);
8725
+ }
8726
+ return { objects, functionAliases };
8727
+ };
8728
+ var bagMemberTypes = (annotation, declared) => {
8729
+ if (annotation.type === AST_NODE_TYPES41.TSTypeLiteral) {
8730
+ return propertySignatureTypes(annotation.members);
8731
+ }
8732
+ if (annotation.type !== AST_NODE_TYPES41.TSTypeReference || annotation.typeName.type !== AST_NODE_TYPES41.Identifier) {
8744
8733
  return null;
8745
8734
  }
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) };
8735
+ return declared().objects.get(annotation.typeName.name) ?? null;
8736
+ };
8737
+ var objectPatternCollaborators = (pattern, declared) => {
8738
+ const annotation = pattern.typeAnnotation?.typeAnnotation;
8739
+ if (annotation === void 0) return [];
8740
+ const members = bagMemberTypes(annotation, declared);
8741
+ if (members === null) return [];
8742
+ const collaborators = [];
8743
+ for (const property of pattern.properties) {
8744
+ if (property.type !== AST_NODE_TYPES41.Property || property.computed) continue;
8745
+ if (property.key.type !== AST_NODE_TYPES41.Identifier) continue;
8746
+ const key = property.key.name;
8747
+ const bound = property.value.type === AST_NODE_TYPES41.AssignmentPattern ? property.value.left : property.value;
8748
+ if (bound.type !== AST_NODE_TYPES41.Identifier) continue;
8749
+ if (CONFIGISH_NAME_RE.test(key)) continue;
8750
+ const reference = members.get(key);
8751
+ if (reference === void 0) continue;
8752
+ collaborators.push({ name: bound.name, ...reference });
8753
+ }
8754
+ return collaborators;
8755
+ };
8756
+ var parameterCollaborators = (parameter, declared) => {
8757
+ let target = parameter;
8758
+ if (target.type === AST_NODE_TYPES41.AssignmentPattern) target = target.left;
8759
+ if (target.type === AST_NODE_TYPES41.ObjectPattern) {
8760
+ return objectPatternCollaborators(target, declared);
8761
+ }
8762
+ const named2 = namedParameterCollaborator(parameter);
8763
+ return named2 === null ? [] : [named2];
8750
8764
  };
8751
- var readConstructor = (ctor) => {
8765
+ var typeParameterNames = (...declarations) => {
8766
+ const names = /* @__PURE__ */ new Set();
8767
+ for (const declaration of declarations) {
8768
+ for (const parameter of declaration?.params ?? []) names.add(parameter.name.name);
8769
+ }
8770
+ return names;
8771
+ };
8772
+ var readConstructor = (ctor, declared, typeParameters) => {
8752
8773
  const body = ctor.value.body;
8753
8774
  const storedFrom = /* @__PURE__ */ new Set();
8754
8775
  let constructedFields = 0;
@@ -8771,13 +8792,16 @@ var readConstructor = (ctor) => {
8771
8792
  }
8772
8793
  const collaborators = [];
8773
8794
  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);
8795
+ for (const reference of parameterCollaborators(parameter, declared)) {
8796
+ const stored = parameter.type === AST_NODE_TYPES41.TSParameterProperty || storedFrom.has(reference.name);
8797
+ if (!stored) continue;
8798
+ if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
8799
+ if (CONFIGISH_NAME_RE.test(reference.name)) continue;
8800
+ if (typeParameters.has(reference.typeName)) continue;
8801
+ if (BUILTIN_CONTAINER_TYPE_RE.test(reference.typeName)) continue;
8802
+ if (declared().functionAliases.has(reference.typeName)) continue;
8803
+ collaborators.push(reference);
8804
+ }
8781
8805
  }
8782
8806
  return { collaborators, constructedFields };
8783
8807
  };
@@ -8859,6 +8883,8 @@ var require_interface_for_injected_service_default = createRule({
8859
8883
  const { filename } = context;
8860
8884
  if (isTestFile(filename) || isStoryFile(filename) || isScriptFile(filename)) return {};
8861
8885
  if (isGeneratedFile(filename, context.sourceCode.getText())) return {};
8886
+ let declaredTypes = null;
8887
+ const objectTypes = () => declaredTypes ??= fileTypeIndex(context.sourceCode.ast);
8862
8888
  return {
8863
8889
  ClassDeclaration(node) {
8864
8890
  if (node.id === null) return;
@@ -8871,7 +8897,11 @@ var require_interface_for_injected_service_default = createRule({
8871
8897
  (member) => member.type === AST_NODE_TYPES41.MethodDefinition && member.kind === "constructor"
8872
8898
  );
8873
8899
  if (ctor === void 0) return;
8874
- const { collaborators, constructedFields } = readConstructor(ctor);
8900
+ const { collaborators, constructedFields } = readConstructor(
8901
+ ctor,
8902
+ objectTypes,
8903
+ typeParameterNames(node.typeParameters, ctor.value.typeParameters)
8904
+ );
8875
8905
  if (collaborators.length === 0) return;
8876
8906
  if (constructedFields > collaborators.length) return;
8877
8907
  if (isFrameworkWiring(node.body)) return;
@@ -9254,7 +9284,7 @@ var rules = {
9254
9284
  };
9255
9285
  var meta = {
9256
9286
  name: "@sarj/eslint-plugin",
9257
- version: "9.0.0"
9287
+ version: "9.2.0"
9258
9288
  };
9259
9289
  var recommendedRules = {
9260
9290
  "@sarj/enforce-file-structure": "warn",