@sarj/eslint-plugin 9.1.0 → 9.3.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.1.0";
395
+ readonly version: "9.3.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.1.0";
395
+ readonly version: "9.3.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
@@ -493,7 +493,72 @@ function restatesStatementHead(body, statement) {
493
493
  // src/rules/no-comment-cruft.ts
494
494
  var LEADING_PREAMBLE_MIN = 4;
495
495
  var STEP_NARRATION_RE = /^(?:first(?:ly)?|second(?:ly)?|third(?:ly)?|then|next|after(?:wards| that)?|finally|lastly|now)\s*[,:]\s*\S/i;
496
- var META_COMMENTARY_RE = /\b(?:for now|keeping (?:it|this) simple|could be (?:refactored|improved|cleaned up|simplified)|refactor(?:ed|ing)? (?:later|this)|not sure (?:if|whether|why|how)|quick[- ](?:and[- ]dirty|fix)|(?:a |bit of a )?hacky|is a hack|temporary (?:solution|workaround|fix|hack)|revisit (?:this|later|below)|clean (?:this|it) up|not ideal|placeholder for now)\b/i;
496
+ var META_COMMENTARY_RE = /\b(?:keeping (?:it|this) simple|could be (?:refactored|improved|cleaned up|simplified)|refactor(?:ed|ing)? (?:later|this)|not sure (?:if|whether|why|how)|quick[- ](?:and[- ]dirty|fix)|(?:a |bit of a )?hacky|is a hack|temporary (?:solution|workaround|fix|hack)|revisit (?:this|later|below)|clean (?:this|it) up|not ideal|placeholder for now)\b/i;
497
+ var FOR_NOW_RE = /\bfor now\b/i;
498
+ var DEFERRAL_STOPWORDS = /* @__PURE__ */ new Set([
499
+ "a",
500
+ "an",
501
+ "and",
502
+ "are",
503
+ "as",
504
+ "at",
505
+ "be",
506
+ "but",
507
+ "by",
508
+ "can",
509
+ "could",
510
+ "do",
511
+ "does",
512
+ "for",
513
+ "from",
514
+ "had",
515
+ "has",
516
+ "have",
517
+ "here",
518
+ "i",
519
+ "in",
520
+ "is",
521
+ "it",
522
+ "its",
523
+ "just",
524
+ "may",
525
+ "might",
526
+ "no",
527
+ "not",
528
+ "now",
529
+ "of",
530
+ "on",
531
+ "only",
532
+ "our",
533
+ "shall",
534
+ "should",
535
+ "so",
536
+ "still",
537
+ "that",
538
+ "the",
539
+ "then",
540
+ "there",
541
+ "this",
542
+ "to",
543
+ "us",
544
+ "was",
545
+ "we",
546
+ "were",
547
+ "will",
548
+ "with",
549
+ "would",
550
+ "you",
551
+ "your"
552
+ ]);
553
+ var DEFERRAL_MAX_CONTENT_WORDS = 2;
554
+ function isBareDeferral(text) {
555
+ if (!FOR_NOW_RE.test(text)) return false;
556
+ const rest = text.replace(FOR_NOW_RE, " ");
557
+ const content = (rest.match(/[A-Za-z][\w']*/g) ?? []).filter(
558
+ (word) => !DEFERRAL_STOPWORDS.has(word.toLowerCase())
559
+ );
560
+ return content.length <= DEFERRAL_MAX_CONTENT_WORDS;
561
+ }
497
562
  var DIRECTIVE_RE = /^(eslint\b|eslint-|sarj-noqa\b|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|hack\b|xxx\b)/i;
498
563
  var LICENSE_RE = /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;
499
564
  var ENUMERATED_ITEM_RE = /^(?:\d+[.):]|[-*•])\s+\S/;
@@ -614,6 +679,7 @@ function isRedundantNarration(body, statementBelow, standalone, isolatedEnumerat
614
679
  const justified = JUSTIFICATION_RE.test(t);
615
680
  if (STEP_NARRATION_RE.test(t) && !justified) return true;
616
681
  if (META_COMMENTARY_RE.test(t) && !justified) return true;
682
+ if (isBareDeferral(t) && !justified) return true;
617
683
  if (HELPER_OPENER_RE.test(t) || LETS_RE.test(t)) return true;
618
684
  const words = t.split(/\s+/);
619
685
  if (words.length > 1 && words.length <= 4 && DUMMY_TRANSLATION_RE.test(t) && !/[():=]/.test(t)) {
@@ -1540,12 +1606,6 @@ var no_dynamic_sql_default = createRule({
1540
1606
 
1541
1607
  // src/rules/no-enum.ts
1542
1608
  import "@typescript-eslint/utils";
1543
- var DEFAULT_IGNORE_PATTERNS = [
1544
- /[\\/]generated[\\/]/,
1545
- /[\\/]openapi-gen[\\/]/,
1546
- /\.gen\.tsx?$/,
1547
- /\.generated\.tsx?$/
1548
- ];
1549
1609
  function matchesAnyPattern(filename, patterns) {
1550
1610
  for (const pattern of patterns) {
1551
1611
  const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
@@ -1555,10 +1615,6 @@ function matchesAnyPattern(filename, patterns) {
1555
1615
  }
1556
1616
  return false;
1557
1617
  }
1558
- function hasGeneratedMarker(sourceText) {
1559
- const head = sourceText.slice(0, 1024);
1560
- return /@generated\b/.test(head);
1561
- }
1562
1618
  var no_enum_default = createRule({
1563
1619
  name: "no-enum",
1564
1620
  meta: {
@@ -1588,12 +1644,8 @@ var no_enum_default = createRule({
1588
1644
  const ignoreFiles = options.ignoreFiles ?? [];
1589
1645
  const filename = context.filename;
1590
1646
  const sourceText = context.sourceCode.getText();
1591
- const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some(
1592
- (re) => re.test(filename)
1593
- );
1594
1647
  const isIgnoredByOption = ignoreFiles.length > 0 && matchesAnyPattern(filename, ignoreFiles);
1595
- const isGenerated = hasGeneratedMarker(sourceText) || isGeneratedFile(filename, sourceText);
1596
- if (isIgnoredByDefault || isIgnoredByOption || isGenerated) {
1648
+ if (isIgnoredByOption || isGeneratedFile(filename, sourceText)) {
1597
1649
  return {};
1598
1650
  }
1599
1651
  return {
@@ -3341,35 +3393,6 @@ var no_restated_comment_default = createRule({
3341
3393
 
3342
3394
  // src/rules/no-restated-jsdoc.ts
3343
3395
  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
3396
  var MODELLED_TAGS = /* @__PURE__ */ new Set([
3374
3397
  "arg",
3375
3398
  "argument",
@@ -3494,7 +3517,6 @@ var no_restated_jsdoc_default = createRule({
3494
3517
  const { description, tags } = parseJsDoc(comment.value);
3495
3518
  if (DIRECTIVE_RE3.test(description)) continue;
3496
3519
  const tagNames = new Set(tags.map((tag) => tag.name));
3497
- if ([...tagNames].some((name) => VALUE_TAGS.has(name))) continue;
3498
3520
  if ([...tagNames].some((name) => !MODELLED_TAGS.has(name))) continue;
3499
3521
  if (isProtected(description)) continue;
3500
3522
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
@@ -6975,25 +6997,32 @@ var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
6975
6997
  var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
6976
6998
  var CSS_VAR_REFERENCE_RE = /var\(\s*--/;
6977
6999
  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 = [
7000
+ 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";
7001
+ var SEMANTIC_TOKEN_RE = new RegExp(
7002
+ `--(?:color-)?(?:${TOKEN_ROLES})\\b|(?:bg|text|border|ring|fill|stroke)-(?:ui-)?(?:${TOKEN_ROLES})\\b`
7003
+ );
7004
+ var THEME_BLOCK_RE = /@theme\b/;
7005
+ var PRESENCE_MARKERS = [
6987
7006
  "components.json",
6988
7007
  "tailwind.config.js",
6989
7008
  "tailwind.config.cjs",
6990
7009
  "tailwind.config.mjs",
6991
7010
  "tailwind.config.ts",
7011
+ "tailwind.config.mts",
7012
+ "tailwind.config.cts"
7013
+ ];
7014
+ var CSS_DETECTION_FILES = [
6992
7015
  "app/globals.css",
7016
+ "app/global.css",
7017
+ "app/styles/globals.css",
6993
7018
  "src/app/globals.css",
7019
+ "src/app/global.css",
7020
+ "src/global.css",
6994
7021
  "src/index.css",
6995
7022
  "src/styles/globals.css",
6996
- "styles/globals.css"
7023
+ "src/styles/index.css",
7024
+ "styles/globals.css",
7025
+ "styles/index.css"
6997
7026
  ];
6998
7027
  var WORKSPACE_ROOT_FILES = [
6999
7028
  "pnpm-workspace.yaml",
@@ -7072,12 +7101,13 @@ var isInsideIconFactoryPath = (node) => {
7072
7101
  return false;
7073
7102
  };
7074
7103
  var hasMarkerAt = (dir) => {
7075
- for (const rel of DETECTION_FILES) {
7104
+ if (PRESENCE_MARKERS.some((rel) => existsSync(join(dir, rel)))) return true;
7105
+ for (const rel of CSS_DETECTION_FILES) {
7076
7106
  const candidate = join(dir, rel);
7077
7107
  if (!existsSync(candidate)) continue;
7078
- if (CONFIG_IS_SUFFICIENT.has(rel)) return true;
7079
7108
  try {
7080
- if (SEMANTIC_TOKEN_RE.test(readFileSync(candidate, "utf8"))) return true;
7109
+ const css = readFileSync(candidate, "utf8");
7110
+ if (SEMANTIC_TOKEN_RE.test(css) || THEME_BLOCK_RE.test(css)) return true;
7081
7111
  } catch {
7082
7112
  }
7083
7113
  }
@@ -8542,32 +8572,6 @@ var prefer_zod_infer_default = createRule({
8542
8572
 
8543
8573
  // src/rules/require-assert-never.ts
8544
8574
  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
8575
  var isRuntimeHandlingStatement = (statement) => {
8572
8576
  if (statement.type === AST_NODE_TYPES39.EmptyStatement) return false;
8573
8577
  if (statement.type === AST_NODE_TYPES39.BlockStatement) {
@@ -8613,7 +8617,6 @@ var require_assert_never_default = createRule({
8613
8617
  if (defaultIndex === -1) return;
8614
8618
  const defaultCase = node.cases[defaultIndex];
8615
8619
  if (defaultCase === void 0) return;
8616
- if (defaultCase.consequent.some(statementContainsAssertNever)) return;
8617
8620
  if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;
8618
8621
  if (isFallthroughDefault(node, defaultIndex)) return;
8619
8622
  if (isCommentOnlyNoopDefault(defaultCase, context.sourceCode)) return;
@@ -8628,7 +8631,6 @@ var require_assert_never_default = createRule({
8628
8631
 
8629
8632
  // src/rules/require-fetch-timeout.ts
8630
8633
  import { AST_NODE_TYPES as AST_NODE_TYPES40, ASTUtils as ASTUtils2 } from "@typescript-eslint/utils";
8631
- var CODEMOD_FIXTURE_RE = /[\\/]__testfixtures__[\\/]/;
8632
8634
  var GLOBAL_OBJECTS2 = /* @__PURE__ */ new Set([
8633
8635
  "globalThis",
8634
8636
  "window",
@@ -8689,7 +8691,7 @@ var require_fetch_timeout_default = createRule({
8689
8691
  },
8690
8692
  defaultOptions: [{}],
8691
8693
  create(context, [optionsArg]) {
8692
- if (isTestFile(context.filename) || isScriptFile(context.filename) || CODEMOD_FIXTURE_RE.test(context.filename)) {
8694
+ if (isTestFile(context.filename) || isScriptFile(context.filename)) {
8693
8695
  return {};
8694
8696
  }
8695
8697
  const allowIn = optionsArg?.allowIn ?? [];
@@ -9348,7 +9350,7 @@ var rules = {
9348
9350
  };
9349
9351
  var meta = {
9350
9352
  name: "@sarj/eslint-plugin",
9351
- version: "9.1.0"
9353
+ version: "9.3.0"
9352
9354
  };
9353
9355
  var recommendedRules = {
9354
9356
  "@sarj/enforce-file-structure": "warn",