@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.cjs +164 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +164 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 [
|
|
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 [
|
|
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 [
|
|
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 [
|
|
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
|
|
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.
|
|
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",
|