@sarj/eslint-plugin 2.12.0 → 2.12.2

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
@@ -70,6 +70,10 @@ interface RuleOptions$2 {
70
70
  * `api.ts` / `*-api.ts` module — plus test files and codemod fixtures.
71
71
  * - A method named `fetch` on some other receiver (`cache.fetch(k)`,
72
72
  * `queryClient.fetch()`): only the global is HTTP.
73
+ * - A pre-signed upload/download URL transfer (`fetch(uploadUrl, ...)`,
74
+ * `fetch(file.downloadUrl)`). Those URLs are one-off storage handoffs,
75
+ * not calls to a first-party service API that belongs behind a client
76
+ * wrapper.
73
77
  * - `new Request(...)` / `axios(...)` and friends. This rule is about the
74
78
  * global `fetch`, not about every HTTP library.
75
79
  *
@@ -237,7 +241,9 @@ declare const rules: {
237
241
  "prefer-schema-for-api-payload": _typescript_eslint_utils_ts_eslint.RuleModule<"unparsedJsonAccess", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
238
242
  name: string;
239
243
  };
240
- "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
244
+ "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [{
245
+ requireSemanticTokens?: boolean;
246
+ }?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
241
247
  name: string;
242
248
  };
243
249
  "prefer-server-actions": _typescript_eslint_utils_ts_eslint.RuleModule<"preferServerAction", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
@@ -379,7 +385,9 @@ declare const plugin: {
379
385
  "prefer-schema-for-api-payload": _typescript_eslint_utils_ts_eslint.RuleModule<"unparsedJsonAccess", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
380
386
  name: string;
381
387
  };
382
- "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
388
+ "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [{
389
+ requireSemanticTokens?: boolean;
390
+ }?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
383
391
  name: string;
384
392
  };
385
393
  "prefer-server-actions": _typescript_eslint_utils_ts_eslint.RuleModule<"preferServerAction", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
@@ -491,7 +499,9 @@ declare const plugin: {
491
499
  "@sarj/no-string-concat-in-loop": string;
492
500
  "@sarj/prefer-discriminated-union": string;
493
501
  "@sarj/no-comment-cruft": string;
494
- "@sarj/prefer-semantic-colors": string;
502
+ "@sarj/prefer-semantic-colors": (string | {
503
+ requireSemanticTokens: boolean;
504
+ })[];
495
505
  "@sarj/no-fat-try-blocks": string;
496
506
  "@sarj/no-cors-wildcard-with-credentials": string;
497
507
  "@sarj/no-secret-in-log": string;
@@ -535,7 +545,9 @@ declare const plugin: {
535
545
  "@sarj/no-string-concat-in-loop": string;
536
546
  "@sarj/prefer-discriminated-union": string;
537
547
  "@sarj/no-comment-cruft": string;
538
- "@sarj/prefer-semantic-colors": string;
548
+ "@sarj/prefer-semantic-colors": (string | {
549
+ requireSemanticTokens: boolean;
550
+ })[];
539
551
  "@sarj/no-fat-try-blocks": string;
540
552
  "@sarj/no-cors-wildcard-with-credentials": string;
541
553
  "@sarj/no-secret-in-log": string;
package/dist/index.d.ts CHANGED
@@ -70,6 +70,10 @@ interface RuleOptions$2 {
70
70
  * `api.ts` / `*-api.ts` module — plus test files and codemod fixtures.
71
71
  * - A method named `fetch` on some other receiver (`cache.fetch(k)`,
72
72
  * `queryClient.fetch()`): only the global is HTTP.
73
+ * - A pre-signed upload/download URL transfer (`fetch(uploadUrl, ...)`,
74
+ * `fetch(file.downloadUrl)`). Those URLs are one-off storage handoffs,
75
+ * not calls to a first-party service API that belongs behind a client
76
+ * wrapper.
73
77
  * - `new Request(...)` / `axios(...)` and friends. This rule is about the
74
78
  * global `fetch`, not about every HTTP library.
75
79
  *
@@ -237,7 +241,9 @@ declare const rules: {
237
241
  "prefer-schema-for-api-payload": _typescript_eslint_utils_ts_eslint.RuleModule<"unparsedJsonAccess", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
238
242
  name: string;
239
243
  };
240
- "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
244
+ "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [{
245
+ requireSemanticTokens?: boolean;
246
+ }?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
241
247
  name: string;
242
248
  };
243
249
  "prefer-server-actions": _typescript_eslint_utils_ts_eslint.RuleModule<"preferServerAction", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
@@ -379,7 +385,9 @@ declare const plugin: {
379
385
  "prefer-schema-for-api-payload": _typescript_eslint_utils_ts_eslint.RuleModule<"unparsedJsonAccess", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
380
386
  name: string;
381
387
  };
382
- "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
388
+ "prefer-semantic-colors": _typescript_eslint_utils_ts_eslint.RuleModule<"rawPalette" | "arbitraryColor" | "inlineColor", readonly [{
389
+ requireSemanticTokens?: boolean;
390
+ }?], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
383
391
  name: string;
384
392
  };
385
393
  "prefer-server-actions": _typescript_eslint_utils_ts_eslint.RuleModule<"preferServerAction", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
@@ -491,7 +499,9 @@ declare const plugin: {
491
499
  "@sarj/no-string-concat-in-loop": string;
492
500
  "@sarj/prefer-discriminated-union": string;
493
501
  "@sarj/no-comment-cruft": string;
494
- "@sarj/prefer-semantic-colors": string;
502
+ "@sarj/prefer-semantic-colors": (string | {
503
+ requireSemanticTokens: boolean;
504
+ })[];
495
505
  "@sarj/no-fat-try-blocks": string;
496
506
  "@sarj/no-cors-wildcard-with-credentials": string;
497
507
  "@sarj/no-secret-in-log": string;
@@ -535,7 +545,9 @@ declare const plugin: {
535
545
  "@sarj/no-string-concat-in-loop": string;
536
546
  "@sarj/prefer-discriminated-union": string;
537
547
  "@sarj/no-comment-cruft": string;
538
- "@sarj/prefer-semantic-colors": string;
548
+ "@sarj/prefer-semantic-colors": (string | {
549
+ requireSemanticTokens: boolean;
550
+ })[];
539
551
  "@sarj/no-fat-try-blocks": string;
540
552
  "@sarj/no-cors-wildcard-with-credentials": string;
541
553
  "@sarj/no-secret-in-log": string;
package/dist/index.js CHANGED
@@ -1,5 +1,30 @@
1
1
  // src/rules/enforce-file-structure.ts
2
2
  import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
3
+
4
+ // src/rules/_paths.ts
5
+ var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
6
+ var STORY_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
7
+ var GENERATED_FILE_RE = /([\\/](?:generated|openapi-gen|graphql[\\/]types)[\\/])|(\.gen\.[cm]?[jt]sx?$)|(\.generated\.[cm]?[jt]sx?$)|(\.d\.[cm]?ts$)|(\.types\.[cm]?ts$)/;
8
+ var GENERATED_MARKER_RE = /(?:@generated\b|generated (?:with|by)|generated (?:graphql )?types|do not edit(?: directly| manually)?)/i;
9
+ function isTestFile(filename) {
10
+ const normalized = filename.replaceAll("\\", "/");
11
+ const base = normalized.slice(normalized.lastIndexOf("/") + 1);
12
+ if (/\.(test|spec|e2e|integration)\.[cm]?[jt]sx?$/.test(base)) {
13
+ return true;
14
+ }
15
+ return /(^|\/)(tests?|__tests__|__mocks__|fixtures|e2e|integration)\//.test(normalized);
16
+ }
17
+ function isStoryFile(filename) {
18
+ return STORY_FILE_RE.test(filename);
19
+ }
20
+ function isGeneratedFile(filename, sourceText = "") {
21
+ return GENERATED_FILE_RE.test(filename.replaceAll("\\", "/")) || GENERATED_MARKER_RE.test(sourceText.slice(0, 2048));
22
+ }
23
+ function isScriptFile(filename) {
24
+ return SCRIPT_FILE_RE.test(filename);
25
+ }
26
+
27
+ // src/rules/enforce-file-structure.ts
3
28
  var classifyStatement = (statement) => {
4
29
  switch (statement.type) {
5
30
  case AST_NODE_TYPES.ImportDeclaration:
@@ -36,6 +61,9 @@ var enforce_file_structure_default = ESLintUtils.RuleCreator(
36
61
  },
37
62
  defaultOptions: [],
38
63
  create(context) {
64
+ if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
65
+ return {};
66
+ }
39
67
  return {
40
68
  Program(node) {
41
69
  const body = node.body;
@@ -425,6 +453,9 @@ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
425
453
  },
426
454
  defaultOptions: [],
427
455
  create(context) {
456
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) {
457
+ return {};
458
+ }
428
459
  const sourceCode = context.sourceCode;
429
460
  function isStandalone(comment) {
430
461
  const before = sourceCode.getTokenBefore(comment, {
@@ -497,6 +528,7 @@ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
497
528
  import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
498
529
  var DEFAULT_IGNORE_PATTERNS = [
499
530
  /[\\/]generated[\\/]/,
531
+ /[\\/]openapi-gen[\\/]/,
500
532
  /\.gen\.tsx?$/,
501
533
  /\.generated\.tsx?$/
502
534
  ];
@@ -548,7 +580,7 @@ var no_enum_default = ESLintUtils4.RuleCreator(
548
580
  (re) => re.test(filename)
549
581
  );
550
582
  const isIgnoredByOption = ignoreFiles.length > 0 && matchesAnyPattern(filename, ignoreFiles);
551
- const isGenerated = hasGeneratedMarker(sourceText);
583
+ const isGenerated = hasGeneratedMarker(sourceText) || isGeneratedFile(filename, sourceText);
552
584
  if (isIgnoredByDefault || isIgnoredByOption || isGenerated) {
553
585
  return {};
554
586
  }
@@ -565,22 +597,6 @@ var no_enum_default = ESLintUtils4.RuleCreator(
565
597
 
566
598
  // src/rules/no-insecure-random-id.ts
567
599
  import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
568
-
569
- // src/rules/_paths.ts
570
- var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
571
- function isTestFile(filename) {
572
- const normalized = filename.replaceAll("\\", "/");
573
- const base = normalized.slice(normalized.lastIndexOf("/") + 1);
574
- if (/\.(test|spec)\.[cm]?[jt]sx?$/.test(base)) {
575
- return true;
576
- }
577
- return /(^|\/)(tests?|__tests__|__mocks__|fixtures)\//.test(normalized);
578
- }
579
- function isScriptFile(filename) {
580
- return SCRIPT_FILE_RE.test(filename);
581
- }
582
-
583
- // src/rules/no-insecure-random-id.ts
584
600
  var STRONG_SECURITY_PATTERN = /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;
585
601
  var NON_SECURITY_ID_PATTERN = /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;
586
602
  var PATH_OR_DOM_MARKER = /[\\/#]|\.[A-Za-z0-9]/;
@@ -1124,6 +1140,10 @@ var no_log_only_catch_default = ESLintUtils7.RuleCreator(
1124
1140
  // src/rules/no-raw-env.ts
1125
1141
  import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
1126
1142
  var CONFIG_FILE_RE = /(^|[\\/])[\w.-]+\.config\.[cm]?[jt]sx?$/;
1143
+ var ENV_BOUNDARY_FILE_RE = /(^|[\\/])(?:env|client-env|server-env|client-settings|server-settings)\.[cm]?[jt]sx?$/;
1144
+ function isValidatedEnvBoundary(filename, sourceText) {
1145
+ return ENV_BOUNDARY_FILE_RE.test(filename.replaceAll("\\", "/")) && /\bz\.object\s*\(/.test(sourceText) && /\.parse\s*\(/.test(sourceText);
1146
+ }
1127
1147
  function isProcessEnv(node) {
1128
1148
  return !node.computed && node.object.type === "Identifier" && node.object.name === "process" && node.property.type === "Identifier" && node.property.name === "env";
1129
1149
  }
@@ -1173,7 +1193,7 @@ var no_raw_env_default = ESLintUtils8.RuleCreator(
1173
1193
  defaultOptions: [],
1174
1194
  create(context) {
1175
1195
  const filename = context.filename;
1176
- if (isTestFile(filename) || isScriptFile(filename) || CONFIG_FILE_RE.test(filename.replaceAll("\\", "/"))) {
1196
+ if (isTestFile(filename) || isScriptFile(filename) || CONFIG_FILE_RE.test(filename.replaceAll("\\", "/")) || isValidatedEnvBoundary(filename, context.sourceCode.text)) {
1177
1197
  return {};
1178
1198
  }
1179
1199
  return {
@@ -1518,6 +1538,9 @@ var no_sentinel_return_on_catch_default = ESLintUtils9.RuleCreator(
1518
1538
  },
1519
1539
  defaultOptions: [{}],
1520
1540
  create(context, [loggingOptions]) {
1541
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) {
1542
+ return {};
1543
+ }
1521
1544
  const matcher = createLogMatcher(loggingOptions);
1522
1545
  function logsOrReportsError(catchBody, caughtName) {
1523
1546
  return walkWithinScope(catchBody, (current) => {
@@ -1924,6 +1947,9 @@ var no_string_concat_in_loop_default = ESLintUtils11.RuleCreator(
1924
1947
  },
1925
1948
  defaultOptions: [],
1926
1949
  create(context) {
1950
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) {
1951
+ return {};
1952
+ }
1927
1953
  const reported = /* @__PURE__ */ new WeakMap();
1928
1954
  return {
1929
1955
  AssignmentExpression(node) {
@@ -2394,7 +2420,7 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2394
2420
  },
2395
2421
  defaultOptions: [],
2396
2422
  create(context) {
2397
- if (isTestFile(context.filename)) {
2423
+ if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
2398
2424
  return {};
2399
2425
  }
2400
2426
  const unvalidatedVariables = /* @__PURE__ */ new Set();
@@ -2493,6 +2519,8 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2493
2519
 
2494
2520
  // src/rules/prefer-semantic-colors.ts
2495
2521
  import { AST_NODE_TYPES as AST_NODE_TYPES8, ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
2522
+ import { existsSync, readFileSync } from "fs";
2523
+ import { dirname, join, parse } from "path";
2496
2524
 
2497
2525
  // src/rules/_tailwind.ts
2498
2526
  var tailwindBase = (token) => token.replace(/^(?:[a-z0-9-]+:)+/i, "").replace(/^!/, "");
@@ -2530,6 +2558,20 @@ var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
2530
2558
  ]);
2531
2559
  var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
2532
2560
  var STORIES_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
2561
+ var SEMANTIC_TOKEN_RE = /--(?: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/;
2562
+ var DETECTION_FILES = [
2563
+ "components.json",
2564
+ "tailwind.config.js",
2565
+ "tailwind.config.cjs",
2566
+ "tailwind.config.mjs",
2567
+ "tailwind.config.ts",
2568
+ "app/globals.css",
2569
+ "src/app/globals.css",
2570
+ "src/index.css",
2571
+ "src/styles/globals.css",
2572
+ "styles/globals.css"
2573
+ ];
2574
+ var semanticTokenCache = /* @__PURE__ */ new Map();
2533
2575
  var SVG_DEFS_CONTAINERS = /* @__PURE__ */ new Set([
2534
2576
  "mask",
2535
2577
  "clipPath",
@@ -2548,16 +2590,66 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
2548
2590
  "currentcolor",
2549
2591
  "inherit"
2550
2592
  ]);
2593
+ function jsxElementName(node) {
2594
+ const name = node.openingElement.name;
2595
+ if (name.type === AST_NODE_TYPES8.JSXIdentifier) return name.name;
2596
+ if (name.type === AST_NODE_TYPES8.JSXMemberExpression && name.property.type === AST_NODE_TYPES8.JSXIdentifier) {
2597
+ return name.property.name;
2598
+ }
2599
+ return null;
2600
+ }
2601
+ function isSvgLikeElementName(name) {
2602
+ return name === "svg" || SVG_DEFS_CONTAINERS.has(name) || /svg$/i.test(name);
2603
+ }
2551
2604
  var isInsideSvg = (node) => {
2552
2605
  let current = node.parent;
2553
2606
  while (current !== void 0 && current !== null) {
2554
- if (current.type === AST_NODE_TYPES8.JSXElement && current.openingElement.name.type === AST_NODE_TYPES8.JSXIdentifier && (current.openingElement.name.name === "svg" || SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))) {
2607
+ if (current.type === AST_NODE_TYPES8.JSXElement) {
2608
+ const name = jsxElementName(current);
2609
+ if (name !== null && isSvgLikeElementName(name)) return true;
2610
+ }
2611
+ current = current.parent;
2612
+ }
2613
+ return false;
2614
+ };
2615
+ var isInsideIconFactoryPath = (node) => {
2616
+ let current = node.parent;
2617
+ while (current !== void 0 && current !== null) {
2618
+ if (current.type === AST_NODE_TYPES8.Property && propName(current.key) === "path" && current.parent.type === AST_NODE_TYPES8.ObjectExpression && current.parent.parent.type === AST_NODE_TYPES8.CallExpression && current.parent.parent.callee.type === AST_NODE_TYPES8.Identifier && current.parent.parent.callee.name === "createIcon") {
2555
2619
  return true;
2556
2620
  }
2557
2621
  current = current.parent;
2558
2622
  }
2559
2623
  return false;
2560
2624
  };
2625
+ var hasSemanticTokenSystem = (filename) => {
2626
+ let dir = dirname(filename);
2627
+ const root = parse(dir).root;
2628
+ for (let depth = 0; depth < 8; depth += 1) {
2629
+ const cached = semanticTokenCache.get(dir);
2630
+ if (cached !== void 0) return cached;
2631
+ let found = false;
2632
+ for (const rel of DETECTION_FILES) {
2633
+ const candidate = join(dir, rel);
2634
+ if (!existsSync(candidate)) continue;
2635
+ if (rel === "components.json") {
2636
+ found = true;
2637
+ break;
2638
+ }
2639
+ try {
2640
+ if (SEMANTIC_TOKEN_RE.test(readFileSync(candidate, "utf8"))) {
2641
+ found = true;
2642
+ break;
2643
+ }
2644
+ } catch {
2645
+ }
2646
+ }
2647
+ semanticTokenCache.set(dir, found);
2648
+ if (found || dir === root) return found;
2649
+ dir = dirname(dir);
2650
+ }
2651
+ return false;
2652
+ };
2561
2653
  var propName = (key) => {
2562
2654
  if (key.type === AST_NODE_TYPES8.Identifier) return key.name;
2563
2655
  if (key.type === AST_NODE_TYPES8.Literal && typeof key.value === "string") return key.value;
@@ -2572,16 +2664,27 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2572
2664
  docs: {
2573
2665
  description: "Enforce design-system semantic color tokens (bg-primary, text-destructive, \u2026) over raw Tailwind palette classes (text-red-500), arbitrary color values (bg-[#fff]), and inline color literals."
2574
2666
  },
2575
- schema: [],
2667
+ schema: [
2668
+ {
2669
+ type: "object",
2670
+ additionalProperties: false,
2671
+ properties: {
2672
+ requireSemanticTokens: { type: "boolean" }
2673
+ }
2674
+ }
2675
+ ],
2576
2676
  messages: {
2577
2677
  rawPalette: "Raw palette class '{{class}}' \u2014 use a semantic token (e.g. text-foreground, bg-primary, text-destructive, bg-muted).",
2578
2678
  arbitraryColor: "Hardcoded color '{{class}}' \u2014 use a semantic token, or var(--\u2026). For charts/brand add an eslint-disable with a reason.",
2579
2679
  inlineColor: "Hardcoded color '{{value}}' \u2014 use a semantic token / CSS variable. For charts/standalone pages add an eslint-disable with a reason."
2580
2680
  }
2581
2681
  },
2582
- defaultOptions: [],
2583
- create(context) {
2682
+ defaultOptions: [{}],
2683
+ create(context, [options]) {
2584
2684
  if (STORIES_FILE_RE.test(context.filename)) return {};
2685
+ if (options?.requireSemanticTokens === true && !hasSemanticTokenSystem(context.filename)) {
2686
+ return {};
2687
+ }
2585
2688
  const reportClasses = (value, node) => {
2586
2689
  for (const token of classTokens(value)) {
2587
2690
  const base = tailwindBase(token);
@@ -2661,7 +2764,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2661
2764
  if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
2662
2765
  return;
2663
2766
  }
2664
- if (isInsideSvg(node)) return;
2767
+ if (isInsideSvg(node) || isInsideIconFactoryPath(node)) return;
2665
2768
  checkColorValueNode(node.value);
2666
2769
  },
2667
2770
  // Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
@@ -2843,7 +2946,7 @@ var INPUT_TYPE_REPLACEMENTS = {
2843
2946
  radio: "RadioGroup",
2844
2947
  range: "Slider"
2845
2948
  };
2846
- var SKIPPED_INPUT_TYPES = /* @__PURE__ */ new Set(["hidden"]);
2949
+ var SKIPPED_INPUT_TYPES = /* @__PURE__ */ new Set(["file", "hidden"]);
2847
2950
  var kebabCase = (component) => component.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2848
2951
  var literalTypeAttr = (node) => {
2849
2952
  for (const attribute of node.attributes) {
@@ -2857,8 +2960,12 @@ var literalTypeAttr = (node) => {
2857
2960
  }
2858
2961
  return null;
2859
2962
  };
2963
+ var hasFileAcceptAttr = (node) => node.attributes.some(
2964
+ (attribute) => attribute.type === AST_NODE_TYPES9.JSXAttribute && attribute.name.type === AST_NODE_TYPES9.JSXIdentifier && attribute.name.name === "accept"
2965
+ );
2860
2966
  var resolveInputReplacement = (node) => {
2861
2967
  const typeAttr = literalTypeAttr(node);
2968
+ if (hasFileAcceptAttr(node)) return null;
2862
2969
  if (typeAttr === null || typeAttr.kind === "dynamic") return "Input";
2863
2970
  if (SKIPPED_INPUT_TYPES.has(typeAttr.value)) return null;
2864
2971
  return INPUT_TYPE_REPLACEMENTS[typeAttr.value] ?? "Input";
@@ -2879,7 +2986,7 @@ var prefer_shadcn_default = ESLintUtils17.RuleCreator(
2879
2986
  },
2880
2987
  defaultOptions: [],
2881
2988
  create(context) {
2882
- if (isTestFile(context.filename)) {
2989
+ if (isTestFile(context.filename) || isStoryFile(context.filename)) {
2883
2990
  return {};
2884
2991
  }
2885
2992
  return {
@@ -3200,7 +3307,7 @@ var zod_naming_convention_default = ESLintUtils20.RuleCreator(
3200
3307
  const convention = optionsArg?.convention ?? "either";
3201
3308
  const { test, messageId } = CONVENTIONS[convention];
3202
3309
  const acceptsSchemaWord = convention !== "prefix";
3203
- if (isTestFile(context.filename)) {
3310
+ if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
3204
3311
  return {};
3205
3312
  }
3206
3313
  return {
@@ -3958,6 +4065,9 @@ var no_fat_try_blocks_default = ESLintUtils25.RuleCreator(
3958
4065
  },
3959
4066
  defaultOptions: [],
3960
4067
  create(context) {
4068
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) {
4069
+ return {};
4070
+ }
3961
4071
  const sourceCode = context.sourceCode;
3962
4072
  return {
3963
4073
  TryStatement(node) {
@@ -4347,7 +4457,7 @@ var no_unsafe_cast_default = ESLintUtils27.RuleCreator(
4347
4457
  },
4348
4458
  defaultOptions: [],
4349
4459
  create(context) {
4350
- if (isTestFile(context.filename)) {
4460
+ if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
4351
4461
  return {};
4352
4462
  }
4353
4463
  function checkAssertion(node) {
@@ -5509,7 +5619,9 @@ var EQUALITY_OPERATORS = /* @__PURE__ */ new Set(["===", "!==", "==", "!="]);
5509
5619
  var SENTINEL_IDENTIFIERS = /* @__PURE__ */ new Set(["undefined", "NaN"]);
5510
5620
  var SENTINEL_WORDS = /(^|_)(SENTINEL|EMPTY|NONE|NULL|UNSET|MISSING|PLACEHOLDER|DUMMY|FAKE|EXAMPLE)(_|$)/;
5511
5621
  var SENTINEL_PREFIX_RE = /^(skip|sentinel|empty|none|missing|unset|placeholder|dummy|fake|example|noop)[A-Z]/;
5622
+ var AST_NODE_TYPE_RE = /^(?:TS|JSX)?[A-Z][A-Za-z]*(?:Signature|Keyword|Expression|Declaration|Element|Literal|Identifier)$/;
5512
5623
  function isConstantReference(identifier) {
5624
+ if (AST_NODE_TYPE_RE.test(identifier)) return true;
5513
5625
  if (isAuthSecretName(identifier) && !SENTINEL_WORDS.test(identifier)) return false;
5514
5626
  return identifier === identifier.toUpperCase() && /[A-Za-z]/.test(identifier);
5515
5627
  }
@@ -5776,6 +5888,7 @@ var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set([
5776
5888
  "window",
5777
5889
  "self"
5778
5890
  ]);
5891
+ var PRESIGNED_URL_NAME_RE = /(?:pre-?signed|signed|upload|download)Url$/i;
5779
5892
  function isGlobalFetchCall(node) {
5780
5893
  const callee = node.callee;
5781
5894
  if (callee.type === "Identifier") {
@@ -5786,6 +5899,23 @@ function isGlobalFetchCall(node) {
5786
5899
  }
5787
5900
  return false;
5788
5901
  }
5902
+ function identifierLikeName(node) {
5903
+ if (node.type === "Identifier") {
5904
+ return node.name;
5905
+ }
5906
+ if (node.type === "MemberExpression" && !node.computed && node.property.type === "Identifier") {
5907
+ return node.property.name;
5908
+ }
5909
+ return null;
5910
+ }
5911
+ function isPresignedUrlTransfer(node) {
5912
+ const first = node.arguments[0];
5913
+ if (first === void 0) {
5914
+ return false;
5915
+ }
5916
+ const name = identifierLikeName(first);
5917
+ return name !== null && PRESIGNED_URL_NAME_RE.test(name);
5918
+ }
5789
5919
  function compile(patterns) {
5790
5920
  const compiled = [];
5791
5921
  for (const pattern of patterns) {
@@ -5832,6 +5962,9 @@ var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
5832
5962
  }
5833
5963
  return {
5834
5964
  CallExpression(node) {
5965
+ if (isPresignedUrlTransfer(node)) {
5966
+ return;
5967
+ }
5835
5968
  if (isGlobalFetchCall(node)) {
5836
5969
  context.report({ node, messageId: "rawFetch" });
5837
5970
  }
@@ -6463,7 +6596,7 @@ var rules = {
6463
6596
  var plugin = {
6464
6597
  meta: {
6465
6598
  name: "@sarj/eslint-plugin",
6466
- version: "2.12.0"
6599
+ version: "2.12.2"
6467
6600
  },
6468
6601
  rules,
6469
6602
  configs: {
@@ -6488,7 +6621,7 @@ var plugin = {
6488
6621
  "@sarj/prefer-discriminated-union": "warn",
6489
6622
  "@sarj/no-comment-cruft": "warn",
6490
6623
  // Frontend / styling — distilled from frontend PR-review mining.
6491
- "@sarj/prefer-semantic-colors": "warn",
6624
+ "@sarj/prefer-semantic-colors": ["warn", { requireSemanticTokens: true }],
6492
6625
  // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.
6493
6626
  "@sarj/no-fat-try-blocks": "warn",
6494
6627
  "@sarj/no-cors-wildcard-with-credentials": "warn",
@@ -6547,7 +6680,7 @@ var plugin = {
6547
6680
  "@sarj/no-comment-cruft": "error",
6548
6681
  // Frontend / styling — distilled from frontend PR-review mining. Stylistic,
6549
6682
  // no autofix → warn (rollout should prove the FP rate before raising it).
6550
- "@sarj/prefer-semantic-colors": "error",
6683
+ "@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
6551
6684
  // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.
6552
6685
  "@sarj/no-fat-try-blocks": "error",
6553
6686
  "@sarj/no-cors-wildcard-with-credentials": "error",