@sarj/eslint-plugin 2.1.1 → 2.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.cjs +444 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +410 -102
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -28,45 +28,30 @@ module.exports = __toCommonJS(index_exports);
|
|
|
28
28
|
// src/rules/enforce-file-structure.ts
|
|
29
29
|
var import_utils = require("@typescript-eslint/utils");
|
|
30
30
|
var SECTION = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
functions: 3,
|
|
35
|
-
exports: 4
|
|
31
|
+
declarations: 0,
|
|
32
|
+
functions: 1,
|
|
33
|
+
exports: 2
|
|
36
34
|
};
|
|
37
|
-
var SECTION_NAMES = [
|
|
38
|
-
"imports",
|
|
39
|
-
"types",
|
|
40
|
-
"constants",
|
|
41
|
-
"functions",
|
|
42
|
-
"exports"
|
|
43
|
-
];
|
|
35
|
+
var SECTION_NAMES = ["declarations", "functions", "exports"];
|
|
44
36
|
var sectionName = (ordinal) => {
|
|
45
37
|
const name = SECTION_NAMES[ordinal];
|
|
46
38
|
return name ?? "unknown";
|
|
47
39
|
};
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
var SERVER_ACTION_FILE_RE = /(?:^|\/)actions\/|\.action\.[jt]sx?$|(?:^|\/)actions\.[jt]sx?$/;
|
|
41
|
+
var isFunctionExpression = (node) => node.type === import_utils.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils.AST_NODE_TYPES.FunctionExpression;
|
|
42
|
+
var isFunctionLikeVariable = (statement) => statement.declarations.length > 0 && statement.declarations.every(
|
|
43
|
+
(decl) => decl.init !== null && isFunctionExpression(decl.init)
|
|
44
|
+
);
|
|
53
45
|
var getStatementSection = (statement) => {
|
|
54
46
|
switch (statement.type) {
|
|
55
47
|
case import_utils.AST_NODE_TYPES.ImportDeclaration:
|
|
56
|
-
return SECTION.imports;
|
|
57
48
|
case import_utils.AST_NODE_TYPES.TSTypeAliasDeclaration:
|
|
58
49
|
case import_utils.AST_NODE_TYPES.TSInterfaceDeclaration:
|
|
59
50
|
case import_utils.AST_NODE_TYPES.TSEnumDeclaration:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (firstDeclarator !== void 0 && isConstantNamed(firstDeclarator)) {
|
|
65
|
-
return SECTION.constants;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return SECTION.functions;
|
|
69
|
-
}
|
|
51
|
+
case import_utils.AST_NODE_TYPES.ClassDeclaration:
|
|
52
|
+
return SECTION.declarations;
|
|
53
|
+
case import_utils.AST_NODE_TYPES.VariableDeclaration:
|
|
54
|
+
return isFunctionLikeVariable(statement) ? SECTION.functions : SECTION.declarations;
|
|
70
55
|
case import_utils.AST_NODE_TYPES.FunctionDeclaration:
|
|
71
56
|
return SECTION.functions;
|
|
72
57
|
case import_utils.AST_NODE_TYPES.ExportNamedDeclaration:
|
|
@@ -91,7 +76,7 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
|
|
|
91
76
|
meta: {
|
|
92
77
|
type: "suggestion",
|
|
93
78
|
docs: {
|
|
94
|
-
description: "Enforce
|
|
79
|
+
description: "Enforce that function definitions follow the file's top-of-file declarations (imports, types, constants, classes) \u2014 the stepdown rule. Ordering among non-function declarations is not enforced. Server-action files (under `/actions/`, named `*.action.ts`, or `actions.ts`) must also begin with a `use server` directive."
|
|
95
80
|
},
|
|
96
81
|
schema: [],
|
|
97
82
|
messages: {
|
|
@@ -102,7 +87,7 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
|
|
|
102
87
|
defaultOptions: [],
|
|
103
88
|
create(context) {
|
|
104
89
|
const filename = context.filename;
|
|
105
|
-
const isServerAction =
|
|
90
|
+
const isServerAction = SERVER_ACTION_FILE_RE.test(filename);
|
|
106
91
|
return {
|
|
107
92
|
Program(node) {
|
|
108
93
|
const body = node.body;
|
|
@@ -115,9 +100,8 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
|
|
|
115
100
|
});
|
|
116
101
|
}
|
|
117
102
|
}
|
|
118
|
-
let currentSection = SECTION.
|
|
103
|
+
let currentSection = SECTION.declarations;
|
|
119
104
|
for (const statement of body) {
|
|
120
|
-
if (isUseServerDirective(statement)) continue;
|
|
121
105
|
if (statement.type === import_utils.AST_NODE_TYPES.ExpressionStatement && statement.expression.type === import_utils.AST_NODE_TYPES.Literal && typeof statement.expression.value === "string" && statement.expression.value.startsWith("use ")) {
|
|
122
106
|
continue;
|
|
123
107
|
}
|
|
@@ -153,7 +137,7 @@ var HTTP_METHOD_NAMES = /* @__PURE__ */ new Set([
|
|
|
153
137
|
"head",
|
|
154
138
|
"options"
|
|
155
139
|
]);
|
|
156
|
-
var
|
|
140
|
+
var ANALYTICS_SEGMENTS = /* @__PURE__ */ new Set([
|
|
157
141
|
"analytics",
|
|
158
142
|
"telemetry",
|
|
159
143
|
"track",
|
|
@@ -162,7 +146,7 @@ var ANALYTICS_KEYWORDS = [
|
|
|
162
146
|
"beacon",
|
|
163
147
|
"metrics",
|
|
164
148
|
"event"
|
|
165
|
-
];
|
|
149
|
+
]);
|
|
166
150
|
function isEffectHookCall(node) {
|
|
167
151
|
const callee = node.callee;
|
|
168
152
|
if (callee.type === import_utils2.AST_NODE_TYPES.Identifier) {
|
|
@@ -236,7 +220,7 @@ function extractUrlString(node) {
|
|
|
236
220
|
function isAnalyticsCall(node) {
|
|
237
221
|
const url = extractUrlString(node).toLowerCase();
|
|
238
222
|
if (url === "") return false;
|
|
239
|
-
return
|
|
223
|
+
return url.split(/[/.]/).some((segment) => ANALYTICS_SEGMENTS.has(segment));
|
|
240
224
|
}
|
|
241
225
|
var no_client_side_data_fetching_default = import_utils2.ESLintUtils.RuleCreator(
|
|
242
226
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
@@ -275,8 +259,105 @@ var no_client_side_data_fetching_default = import_utils2.ESLintUtils.RuleCreator
|
|
|
275
259
|
}
|
|
276
260
|
});
|
|
277
261
|
|
|
278
|
-
// src/rules/no-
|
|
262
|
+
// src/rules/no-comment-cruft.ts
|
|
279
263
|
var import_utils3 = require("@typescript-eslint/utils");
|
|
264
|
+
var LEADING_PREAMBLE_MIN = 4;
|
|
265
|
+
var DIRECTIVE_RE = /^(eslint\b|eslint-|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|global\b|noinspection|todo\b|fixme\b|hack\b|xxx\b)/i;
|
|
266
|
+
var LICENSE_RE = /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;
|
|
267
|
+
var BANNER_FULL_RE = /^[\s\-=*#~_+.]{4,}$/;
|
|
268
|
+
var BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\*{4,}|~{4,}/;
|
|
269
|
+
var REGION_RE = /^#?(?:end)?region\b/i;
|
|
270
|
+
var CODE_KEYWORD_RE = /^(import |export |const |let |var |function\b|class |interface |type \w|enum |return\b|throw |await |async |if\s*\(|for\s*\(|while\s*\(|switch\s*\(|new |console\.)/;
|
|
271
|
+
var CODE_TAIL_RE = /[;{}()]\s*$|=>\s*$|,\s*$/;
|
|
272
|
+
var CALL_OR_ASSIGN_RE = /^[A-Za-z_$][\w.$[\]]*\s*(?:=(?![=>])|\+=|-=|\*=)\s*\S.*[;)}\]]\s*$|^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
|
|
273
|
+
function stripCommentMarker(line) {
|
|
274
|
+
return line.replace(/^\s*\/\//, "").replace(/^\s*\*+/, "").trim();
|
|
275
|
+
}
|
|
276
|
+
function isDirective(text) {
|
|
277
|
+
return DIRECTIVE_RE.test(text.trim());
|
|
278
|
+
}
|
|
279
|
+
function isBanner(text) {
|
|
280
|
+
const t = text.trim();
|
|
281
|
+
if (!t) return false;
|
|
282
|
+
return BANNER_FULL_RE.test(t) || BANNER_RUN_RE.test(t) || REGION_RE.test(t);
|
|
283
|
+
}
|
|
284
|
+
function looksLikeCode(text) {
|
|
285
|
+
const t = text.trim();
|
|
286
|
+
if (!t) return false;
|
|
287
|
+
if (CODE_KEYWORD_RE.test(t) && CODE_TAIL_RE.test(t)) return true;
|
|
288
|
+
return CALL_OR_ASSIGN_RE.test(t);
|
|
289
|
+
}
|
|
290
|
+
var no_comment_cruft_default = import_utils3.ESLintUtils.RuleCreator(
|
|
291
|
+
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
292
|
+
)({
|
|
293
|
+
name: "no-comment-cruft",
|
|
294
|
+
meta: {
|
|
295
|
+
type: "suggestion",
|
|
296
|
+
docs: {
|
|
297
|
+
description: "Flag commented-out code, section-banner comments, and leading file-header comment preambles."
|
|
298
|
+
},
|
|
299
|
+
schema: [],
|
|
300
|
+
messages: {
|
|
301
|
+
commentedOutCode: "Commented-out code \u2014 delete it; git history remembers.",
|
|
302
|
+
sectionBanner: "Section-banner / region comment \u2014 structure code with functions, not ASCII rules.",
|
|
303
|
+
fileHeaderPreamble: "File-header comment preamble \u2014 use a brief doc comment for the why, not a block of `//` lines."
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
defaultOptions: [],
|
|
307
|
+
create(context) {
|
|
308
|
+
const sourceCode = context.sourceCode;
|
|
309
|
+
function isStandalone(comment) {
|
|
310
|
+
const before = sourceCode.getTokenBefore(comment, {
|
|
311
|
+
includeComments: false
|
|
312
|
+
});
|
|
313
|
+
return !before || before.loc.end.line < comment.loc.start.line;
|
|
314
|
+
}
|
|
315
|
+
function isJsDoc(comment) {
|
|
316
|
+
return comment.type === "Block" && /^\*/.test(comment.value);
|
|
317
|
+
}
|
|
318
|
+
function reportLeadingPreamble(comments, firstCodeLine) {
|
|
319
|
+
const leading = [];
|
|
320
|
+
let prevLine = null;
|
|
321
|
+
for (const comment of comments) {
|
|
322
|
+
if (comment.type !== "Line") break;
|
|
323
|
+
if (comment.loc.start.line >= firstCodeLine) break;
|
|
324
|
+
if (!isStandalone(comment)) break;
|
|
325
|
+
const body = stripCommentMarker(comment.value);
|
|
326
|
+
if (isDirective(body) || body.startsWith("!")) continue;
|
|
327
|
+
if (prevLine !== null && comment.loc.start.line !== prevLine + 1) break;
|
|
328
|
+
leading.push(comment);
|
|
329
|
+
prevLine = comment.loc.start.line;
|
|
330
|
+
}
|
|
331
|
+
const first = leading[0];
|
|
332
|
+
if (first === void 0 || leading.length < LEADING_PREAMBLE_MIN) return;
|
|
333
|
+
const isLicense = leading.some(
|
|
334
|
+
(c) => LICENSE_RE.test(stripCommentMarker(c.value))
|
|
335
|
+
);
|
|
336
|
+
if (!isLicense) {
|
|
337
|
+
context.report({ node: first, messageId: "fileHeaderPreamble" });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
Program() {
|
|
342
|
+
const comments = sourceCode.getAllComments();
|
|
343
|
+
const firstCodeLine = sourceCode.ast.tokens[0]?.loc.start.line ?? Number.MAX_SAFE_INTEGER;
|
|
344
|
+
for (const comment of comments) {
|
|
345
|
+
if (isJsDoc(comment) || !isStandalone(comment)) continue;
|
|
346
|
+
const texts = comment.value.split("\n").map(stripCommentMarker).filter((l) => l.length > 0 && !isDirective(l));
|
|
347
|
+
if (texts.some(isBanner)) {
|
|
348
|
+
context.report({ node: comment, messageId: "sectionBanner" });
|
|
349
|
+
} else if (texts.some(looksLikeCode)) {
|
|
350
|
+
context.report({ node: comment, messageId: "commentedOutCode" });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
reportLeadingPreamble(comments, firstCodeLine);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// src/rules/no-enum.ts
|
|
360
|
+
var import_utils4 = require("@typescript-eslint/utils");
|
|
280
361
|
var DEFAULT_IGNORE_PATTERNS = [
|
|
281
362
|
/[\\/]generated[\\/]/,
|
|
282
363
|
/\.gen\.tsx?$/,
|
|
@@ -295,7 +376,7 @@ function hasGeneratedMarker(sourceText) {
|
|
|
295
376
|
const head = sourceText.slice(0, 1024);
|
|
296
377
|
return /@generated\b/.test(head);
|
|
297
378
|
}
|
|
298
|
-
var no_enum_default =
|
|
379
|
+
var no_enum_default = import_utils4.ESLintUtils.RuleCreator(
|
|
299
380
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
300
381
|
)({
|
|
301
382
|
name: "no-enum",
|
|
@@ -346,7 +427,7 @@ var no_enum_default = import_utils3.ESLintUtils.RuleCreator(
|
|
|
346
427
|
});
|
|
347
428
|
|
|
348
429
|
// src/rules/no-insecure-random-id.ts
|
|
349
|
-
var
|
|
430
|
+
var import_utils5 = require("@typescript-eslint/utils");
|
|
350
431
|
var NAME_PATTERN = /id|token|key|secret|uuid|nonce|session|password|salt/i;
|
|
351
432
|
function isMathRandomCall(node) {
|
|
352
433
|
if (node.type !== "CallExpression") {
|
|
@@ -424,7 +505,7 @@ function findEnclosingName(node) {
|
|
|
424
505
|
}
|
|
425
506
|
return void 0;
|
|
426
507
|
}
|
|
427
|
-
var no_insecure_random_id_default =
|
|
508
|
+
var no_insecure_random_id_default = import_utils5.ESLintUtils.RuleCreator(
|
|
428
509
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
429
510
|
)({
|
|
430
511
|
name: "no-insecure-random-id",
|
|
@@ -459,7 +540,7 @@ var no_insecure_random_id_default = import_utils4.ESLintUtils.RuleCreator(
|
|
|
459
540
|
});
|
|
460
541
|
|
|
461
542
|
// src/rules/no-json-stringify-error.ts
|
|
462
|
-
var
|
|
543
|
+
var import_utils6 = require("@typescript-eslint/utils");
|
|
463
544
|
var ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;
|
|
464
545
|
function isCatchBinding(scope, name) {
|
|
465
546
|
let current = scope;
|
|
@@ -479,7 +560,7 @@ function isCatchBinding(scope, name) {
|
|
|
479
560
|
function isJsonStringify(callee) {
|
|
480
561
|
return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
|
|
481
562
|
}
|
|
482
|
-
var no_json_stringify_error_default =
|
|
563
|
+
var no_json_stringify_error_default = import_utils6.ESLintUtils.RuleCreator(
|
|
483
564
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
484
565
|
)({
|
|
485
566
|
name: "no-json-stringify-error",
|
|
@@ -518,7 +599,7 @@ var no_json_stringify_error_default = import_utils5.ESLintUtils.RuleCreator(
|
|
|
518
599
|
});
|
|
519
600
|
|
|
520
601
|
// src/rules/no-log-only-catch.ts
|
|
521
|
-
var
|
|
602
|
+
var import_utils7 = require("@typescript-eslint/utils");
|
|
522
603
|
var DEFAULT_IGNORE_PATTERNS2 = [
|
|
523
604
|
/\.test\./,
|
|
524
605
|
/\.spec\./,
|
|
@@ -555,7 +636,7 @@ function isConsoleCallStatement(statement) {
|
|
|
555
636
|
}
|
|
556
637
|
return CONSOLE_METHODS.has(property.name);
|
|
557
638
|
}
|
|
558
|
-
var no_log_only_catch_default =
|
|
639
|
+
var no_log_only_catch_default = import_utils7.ESLintUtils.RuleCreator(
|
|
559
640
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
560
641
|
)({
|
|
561
642
|
name: "no-log-only-catch",
|
|
@@ -597,8 +678,8 @@ var no_log_only_catch_default = import_utils6.ESLintUtils.RuleCreator(
|
|
|
597
678
|
});
|
|
598
679
|
|
|
599
680
|
// src/rules/no-raw-env.ts
|
|
600
|
-
var
|
|
601
|
-
var no_raw_env_default =
|
|
681
|
+
var import_utils8 = require("@typescript-eslint/utils");
|
|
682
|
+
var no_raw_env_default = import_utils8.ESLintUtils.RuleCreator(
|
|
602
683
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
603
684
|
)({
|
|
604
685
|
name: "no-raw-env",
|
|
@@ -631,24 +712,24 @@ var no_raw_env_default = import_utils7.ESLintUtils.RuleCreator(
|
|
|
631
712
|
});
|
|
632
713
|
|
|
633
714
|
// src/rules/no-sentinel-return-on-catch.ts
|
|
634
|
-
var
|
|
715
|
+
var import_utils9 = require("@typescript-eslint/utils");
|
|
635
716
|
function isSentinelArgument(arg) {
|
|
636
717
|
if (arg === null) {
|
|
637
718
|
return false;
|
|
638
719
|
}
|
|
639
|
-
if (arg.type ===
|
|
720
|
+
if (arg.type === import_utils9.AST_NODE_TYPES.Literal && arg.value === null) {
|
|
640
721
|
return true;
|
|
641
722
|
}
|
|
642
|
-
if (arg.type ===
|
|
723
|
+
if (arg.type === import_utils9.AST_NODE_TYPES.Literal && arg.value === false) {
|
|
643
724
|
return true;
|
|
644
725
|
}
|
|
645
|
-
if (arg.type ===
|
|
726
|
+
if (arg.type === import_utils9.AST_NODE_TYPES.Identifier && arg.name === "undefined") {
|
|
646
727
|
return true;
|
|
647
728
|
}
|
|
648
|
-
if (arg.type ===
|
|
729
|
+
if (arg.type === import_utils9.AST_NODE_TYPES.ArrayExpression && arg.elements.length === 0) {
|
|
649
730
|
return true;
|
|
650
731
|
}
|
|
651
|
-
if (arg.type ===
|
|
732
|
+
if (arg.type === import_utils9.AST_NODE_TYPES.ObjectExpression && arg.properties.length === 0) {
|
|
652
733
|
return true;
|
|
653
734
|
}
|
|
654
735
|
return false;
|
|
@@ -659,11 +740,11 @@ function containsThrow(node) {
|
|
|
659
740
|
if (found) {
|
|
660
741
|
return;
|
|
661
742
|
}
|
|
662
|
-
if (current.type ===
|
|
743
|
+
if (current.type === import_utils9.AST_NODE_TYPES.ThrowStatement) {
|
|
663
744
|
found = true;
|
|
664
745
|
return;
|
|
665
746
|
}
|
|
666
|
-
if (current.type ===
|
|
747
|
+
if (current.type === import_utils9.AST_NODE_TYPES.FunctionDeclaration || current.type === import_utils9.AST_NODE_TYPES.FunctionExpression || current.type === import_utils9.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
667
748
|
return;
|
|
668
749
|
}
|
|
669
750
|
for (const key of Object.keys(current)) {
|
|
@@ -688,7 +769,7 @@ function containsThrow(node) {
|
|
|
688
769
|
function isNode(value) {
|
|
689
770
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
690
771
|
}
|
|
691
|
-
var no_sentinel_return_on_catch_default =
|
|
772
|
+
var no_sentinel_return_on_catch_default = import_utils9.ESLintUtils.RuleCreator(
|
|
692
773
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
693
774
|
)({
|
|
694
775
|
name: "no-sentinel-return-on-catch",
|
|
@@ -711,7 +792,7 @@ var no_sentinel_return_on_catch_default = import_utils8.ESLintUtils.RuleCreator(
|
|
|
711
792
|
return;
|
|
712
793
|
}
|
|
713
794
|
const last = body[body.length - 1];
|
|
714
|
-
if (last === void 0 || last.type !==
|
|
795
|
+
if (last === void 0 || last.type !== import_utils9.AST_NODE_TYPES.ReturnStatement) {
|
|
715
796
|
return;
|
|
716
797
|
}
|
|
717
798
|
if (!isSentinelArgument(last.argument)) {
|
|
@@ -730,14 +811,14 @@ var no_sentinel_return_on_catch_default = import_utils8.ESLintUtils.RuleCreator(
|
|
|
730
811
|
});
|
|
731
812
|
|
|
732
813
|
// src/rules/no-sequential-await.ts
|
|
733
|
-
var
|
|
814
|
+
var import_utils10 = require("@typescript-eslint/utils");
|
|
734
815
|
function isFunctionLike(node) {
|
|
735
816
|
return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
736
817
|
}
|
|
737
818
|
function isLoop(node) {
|
|
738
819
|
return node.type === "ForStatement" || node.type === "ForOfStatement" || node.type === "ForInStatement" || node.type === "WhileStatement" || node.type === "DoWhileStatement";
|
|
739
820
|
}
|
|
740
|
-
var no_sequential_await_default =
|
|
821
|
+
var no_sequential_await_default = import_utils10.ESLintUtils.RuleCreator(
|
|
741
822
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
742
823
|
)({
|
|
743
824
|
name: "no-sequential-await",
|
|
@@ -818,7 +899,7 @@ var no_sequential_await_default = import_utils9.ESLintUtils.RuleCreator(
|
|
|
818
899
|
});
|
|
819
900
|
|
|
820
901
|
// src/rules/no-string-concat-in-loop.ts
|
|
821
|
-
var
|
|
902
|
+
var import_utils11 = require("@typescript-eslint/utils");
|
|
822
903
|
var LOOP_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
823
904
|
"ForStatement",
|
|
824
905
|
"ForOfStatement",
|
|
@@ -878,7 +959,7 @@ function isInsideLoopBody(node) {
|
|
|
878
959
|
}
|
|
879
960
|
return false;
|
|
880
961
|
}
|
|
881
|
-
var no_string_concat_in_loop_default =
|
|
962
|
+
var no_string_concat_in_loop_default = import_utils11.ESLintUtils.RuleCreator(
|
|
882
963
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
883
964
|
)({
|
|
884
965
|
name: "no-string-concat-in-loop",
|
|
@@ -923,7 +1004,7 @@ var no_string_concat_in_loop_default = import_utils10.ESLintUtils.RuleCreator(
|
|
|
923
1004
|
});
|
|
924
1005
|
|
|
925
1006
|
// src/rules/no-unnecessary-use-client.ts
|
|
926
|
-
var
|
|
1007
|
+
var import_utils12 = require("@typescript-eslint/utils");
|
|
927
1008
|
var HOOK_REGEX = /^use([A-Z]|$)/;
|
|
928
1009
|
var EVENT_PROP_REGEX = /^on[A-Z]/;
|
|
929
1010
|
var ERROR_FILE_REGEX = /\b(?:global-)?error\.[jt]sx?$/;
|
|
@@ -946,16 +1027,16 @@ var BROWSER_GLOBALS = /* @__PURE__ */ new Set([
|
|
|
946
1027
|
]);
|
|
947
1028
|
var CLIENT_ONLY_PACKAGES_REGEX = /^(?:@radix-ui\/|framer-motion|react-dom|react-day-picker|@floating-ui\/|react-select|react-toastify|react-hook-form|recharts|react-dropzone|react-slick|react-swipeable|react-resizable|react-draggable|react-beautiful-dnd|@hello-pangea\/dnd|react-virtualized|react-window|@tanstack\/react-table|@tanstack\/react-query|react-redux|recoil|jotai|zustand|@tippyjs\/react|react-color|react-datepicker|next-themes|react-helmet|react-helmet-async|styled-components|@emotion\/)/;
|
|
948
1029
|
var isUseClientDirective = (node) => {
|
|
949
|
-
return node.type ===
|
|
1030
|
+
return node.type === import_utils12.AST_NODE_TYPES.ExpressionStatement && node.expression.type === import_utils12.AST_NODE_TYPES.Literal && node.expression.value === "use client";
|
|
950
1031
|
};
|
|
951
1032
|
var isGlobalReference = (node, context) => {
|
|
952
1033
|
if (!BROWSER_GLOBALS.has(node.name)) return false;
|
|
953
1034
|
const parent = node.parent;
|
|
954
1035
|
if (parent !== void 0) {
|
|
955
|
-
if (parent.type ===
|
|
1036
|
+
if (parent.type === import_utils12.AST_NODE_TYPES.MemberExpression && parent.property === node && !parent.computed) {
|
|
956
1037
|
return false;
|
|
957
1038
|
}
|
|
958
|
-
if (parent.type ===
|
|
1039
|
+
if (parent.type === import_utils12.AST_NODE_TYPES.Property && parent.key === node && !parent.computed) {
|
|
959
1040
|
return false;
|
|
960
1041
|
}
|
|
961
1042
|
if (parent.type.startsWith("TS")) {
|
|
@@ -972,7 +1053,7 @@ var isGlobalReference = (node, context) => {
|
|
|
972
1053
|
}
|
|
973
1054
|
return true;
|
|
974
1055
|
};
|
|
975
|
-
var no_unnecessary_use_client_default =
|
|
1056
|
+
var no_unnecessary_use_client_default = import_utils12.ESLintUtils.RuleCreator(
|
|
976
1057
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
977
1058
|
)({
|
|
978
1059
|
name: "no-unnecessary-use-client",
|
|
@@ -995,13 +1076,13 @@ var no_unnecessary_use_client_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
995
1076
|
let directiveNode = null;
|
|
996
1077
|
let hasClientIndicator = false;
|
|
997
1078
|
const markIfHookOrContext = (callee) => {
|
|
998
|
-
if (callee.type ===
|
|
1079
|
+
if (callee.type === import_utils12.AST_NODE_TYPES.Identifier) {
|
|
999
1080
|
if (HOOK_REGEX.test(callee.name) || callee.name === "createContext") {
|
|
1000
1081
|
hasClientIndicator = true;
|
|
1001
1082
|
}
|
|
1002
1083
|
return;
|
|
1003
1084
|
}
|
|
1004
|
-
if (callee.type ===
|
|
1085
|
+
if (callee.type === import_utils12.AST_NODE_TYPES.MemberExpression && callee.property.type === import_utils12.AST_NODE_TYPES.Identifier) {
|
|
1005
1086
|
const name = callee.property.name;
|
|
1006
1087
|
if (HOOK_REGEX.test(name) || name === "createContext") {
|
|
1007
1088
|
hasClientIndicator = true;
|
|
@@ -1011,7 +1092,7 @@ var no_unnecessary_use_client_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
1011
1092
|
return {
|
|
1012
1093
|
Program(node) {
|
|
1013
1094
|
for (const stmt of node.body) {
|
|
1014
|
-
if (stmt.type !==
|
|
1095
|
+
if (stmt.type !== import_utils12.AST_NODE_TYPES.ExpressionStatement) break;
|
|
1015
1096
|
if (isUseClientDirective(stmt)) {
|
|
1016
1097
|
directiveNode = stmt;
|
|
1017
1098
|
break;
|
|
@@ -1019,35 +1100,43 @@ var no_unnecessary_use_client_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
1019
1100
|
}
|
|
1020
1101
|
},
|
|
1021
1102
|
CallExpression(node) {
|
|
1103
|
+
if (directiveNode === null) return;
|
|
1022
1104
|
markIfHookOrContext(node.callee);
|
|
1023
1105
|
},
|
|
1024
1106
|
JSXAttribute(node) {
|
|
1025
|
-
if (
|
|
1107
|
+
if (directiveNode === null) return;
|
|
1108
|
+
if (node.name.type === import_utils12.AST_NODE_TYPES.JSXIdentifier && EVENT_PROP_REGEX.test(node.name.name)) {
|
|
1026
1109
|
hasClientIndicator = true;
|
|
1027
1110
|
}
|
|
1028
1111
|
},
|
|
1029
1112
|
ImportDeclaration(node) {
|
|
1113
|
+
if (directiveNode === null) return;
|
|
1030
1114
|
if (typeof node.source.value === "string" && CLIENT_ONLY_PACKAGES_REGEX.test(node.source.value)) {
|
|
1031
1115
|
hasClientIndicator = true;
|
|
1032
1116
|
}
|
|
1033
1117
|
},
|
|
1034
1118
|
ExportNamedDeclaration(node) {
|
|
1119
|
+
if (directiveNode === null) return;
|
|
1035
1120
|
if (node.source !== null) {
|
|
1036
1121
|
hasClientIndicator = true;
|
|
1037
1122
|
}
|
|
1038
1123
|
},
|
|
1039
1124
|
ExportAllDeclaration(node) {
|
|
1125
|
+
if (directiveNode === null) return;
|
|
1040
1126
|
if (node.source !== null) {
|
|
1041
1127
|
hasClientIndicator = true;
|
|
1042
1128
|
}
|
|
1043
1129
|
},
|
|
1044
1130
|
ClassDeclaration() {
|
|
1131
|
+
if (directiveNode === null) return;
|
|
1045
1132
|
hasClientIndicator = true;
|
|
1046
1133
|
},
|
|
1047
1134
|
ClassExpression() {
|
|
1135
|
+
if (directiveNode === null) return;
|
|
1048
1136
|
hasClientIndicator = true;
|
|
1049
1137
|
},
|
|
1050
1138
|
Identifier(node) {
|
|
1139
|
+
if (directiveNode === null) return;
|
|
1051
1140
|
if (isGlobalReference(node, context)) {
|
|
1052
1141
|
hasClientIndicator = true;
|
|
1053
1142
|
}
|
|
@@ -1065,8 +1154,8 @@ var no_unnecessary_use_client_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
1065
1154
|
});
|
|
1066
1155
|
|
|
1067
1156
|
// src/rules/prefer-discriminated-union.ts
|
|
1068
|
-
var import_utils12 = require("@typescript-eslint/utils");
|
|
1069
1157
|
var import_utils13 = require("@typescript-eslint/utils");
|
|
1158
|
+
var import_utils14 = require("@typescript-eslint/utils");
|
|
1070
1159
|
var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
1071
1160
|
"success",
|
|
1072
1161
|
"ok",
|
|
@@ -1076,26 +1165,26 @@ var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
|
1076
1165
|
]);
|
|
1077
1166
|
var MIN_OPTIONAL_MEMBERS = 2;
|
|
1078
1167
|
function getMemberName(member) {
|
|
1079
|
-
if (member.type !==
|
|
1168
|
+
if (member.type !== import_utils14.AST_NODE_TYPES.TSPropertySignature) {
|
|
1080
1169
|
return null;
|
|
1081
1170
|
}
|
|
1082
1171
|
const { key } = member;
|
|
1083
|
-
if (key.type ===
|
|
1172
|
+
if (key.type === import_utils14.AST_NODE_TYPES.Identifier) {
|
|
1084
1173
|
return key.name;
|
|
1085
1174
|
}
|
|
1086
|
-
if (key.type ===
|
|
1175
|
+
if (key.type === import_utils14.AST_NODE_TYPES.Literal && typeof key.value === "string") {
|
|
1087
1176
|
return key.value;
|
|
1088
1177
|
}
|
|
1089
1178
|
return null;
|
|
1090
1179
|
}
|
|
1091
1180
|
function isBooleanTyped(member) {
|
|
1092
|
-
return member.typeAnnotation?.typeAnnotation.type ===
|
|
1181
|
+
return member.typeAnnotation?.typeAnnotation.type === import_utils14.AST_NODE_TYPES.TSBooleanKeyword;
|
|
1093
1182
|
}
|
|
1094
1183
|
function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
1095
1184
|
let hasStatusBoolean = false;
|
|
1096
1185
|
let optionalCount = 0;
|
|
1097
1186
|
for (const member of typeLiteral.members) {
|
|
1098
|
-
if (member.type !==
|
|
1187
|
+
if (member.type !== import_utils14.AST_NODE_TYPES.TSPropertySignature) {
|
|
1099
1188
|
continue;
|
|
1100
1189
|
}
|
|
1101
1190
|
if (member.optional) {
|
|
@@ -1108,7 +1197,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
|
1108
1197
|
}
|
|
1109
1198
|
return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS;
|
|
1110
1199
|
}
|
|
1111
|
-
var prefer_discriminated_union_default =
|
|
1200
|
+
var prefer_discriminated_union_default = import_utils13.ESLintUtils.RuleCreator(
|
|
1112
1201
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1113
1202
|
)({
|
|
1114
1203
|
name: "prefer-discriminated-union",
|
|
@@ -1136,7 +1225,7 @@ var prefer_discriminated_union_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1136
1225
|
TSInterfaceDeclaration(node) {
|
|
1137
1226
|
const synthetic = {
|
|
1138
1227
|
...node.body,
|
|
1139
|
-
type:
|
|
1228
|
+
type: import_utils14.AST_NODE_TYPES.TSTypeLiteral,
|
|
1140
1229
|
members: node.body.body
|
|
1141
1230
|
};
|
|
1142
1231
|
checkTypeLiteral(synthetic, node);
|
|
@@ -1149,13 +1238,13 @@ var prefer_discriminated_union_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1149
1238
|
});
|
|
1150
1239
|
|
|
1151
1240
|
// src/rules/prefer-schema-for-api-payload.ts
|
|
1152
|
-
var
|
|
1241
|
+
var import_utils15 = require("@typescript-eslint/utils");
|
|
1153
1242
|
var unwrap = (node) => {
|
|
1154
1243
|
let current = node;
|
|
1155
1244
|
while (current !== null && current !== void 0) {
|
|
1156
|
-
if (current.type ===
|
|
1245
|
+
if (current.type === import_utils15.AST_NODE_TYPES.TSAsExpression || current.type === import_utils15.AST_NODE_TYPES.TSTypeAssertion || current.type === import_utils15.AST_NODE_TYPES.TSNonNullExpression || current.type === import_utils15.AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
1157
1246
|
current = current.expression;
|
|
1158
|
-
} else if (current.type ===
|
|
1247
|
+
} else if (current.type === import_utils15.AST_NODE_TYPES.ChainExpression) {
|
|
1159
1248
|
current = current.expression;
|
|
1160
1249
|
} else {
|
|
1161
1250
|
break;
|
|
@@ -1166,18 +1255,18 @@ var unwrap = (node) => {
|
|
|
1166
1255
|
var isJsonCall = (node) => {
|
|
1167
1256
|
let current = unwrap(node);
|
|
1168
1257
|
if (current === null) return false;
|
|
1169
|
-
if (current.type ===
|
|
1258
|
+
if (current.type === import_utils15.AST_NODE_TYPES.AwaitExpression) {
|
|
1170
1259
|
current = unwrap(current.argument);
|
|
1171
1260
|
}
|
|
1172
|
-
if (current === null || current.type !==
|
|
1261
|
+
if (current === null || current.type !== import_utils15.AST_NODE_TYPES.CallExpression) {
|
|
1173
1262
|
return false;
|
|
1174
1263
|
}
|
|
1175
1264
|
const callee = unwrap(current.callee);
|
|
1176
|
-
if (callee === null || callee.type !==
|
|
1265
|
+
if (callee === null || callee.type !== import_utils15.AST_NODE_TYPES.MemberExpression) {
|
|
1177
1266
|
return false;
|
|
1178
1267
|
}
|
|
1179
1268
|
const property = unwrap(callee.property);
|
|
1180
|
-
return property !== null && property.type ===
|
|
1269
|
+
return property !== null && property.type === import_utils15.AST_NODE_TYPES.Identifier && property.name === "json";
|
|
1181
1270
|
};
|
|
1182
1271
|
var findVariable2 = (scope, name) => {
|
|
1183
1272
|
let current = scope;
|
|
@@ -1190,13 +1279,13 @@ var findVariable2 = (scope, name) => {
|
|
|
1190
1279
|
};
|
|
1191
1280
|
var isUnvalidatedVariableRef = (node, scope, tracked) => {
|
|
1192
1281
|
const unwrapped = unwrap(node);
|
|
1193
|
-
if (unwrapped === null || unwrapped.type !==
|
|
1282
|
+
if (unwrapped === null || unwrapped.type !== import_utils15.AST_NODE_TYPES.Identifier) {
|
|
1194
1283
|
return false;
|
|
1195
1284
|
}
|
|
1196
1285
|
const variable = findVariable2(scope, unwrapped.name);
|
|
1197
1286
|
return variable !== null && tracked.has(variable);
|
|
1198
1287
|
};
|
|
1199
|
-
var prefer_schema_for_api_payload_default =
|
|
1288
|
+
var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreator(
|
|
1200
1289
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1201
1290
|
)({
|
|
1202
1291
|
name: "prefer-schema-for-api-payload",
|
|
@@ -1224,11 +1313,11 @@ var prefer_schema_for_api_payload_default = import_utils14.ESLintUtils.RuleCreat
|
|
|
1224
1313
|
return {
|
|
1225
1314
|
VariableDeclarator(node) {
|
|
1226
1315
|
const scope = context.sourceCode.getScope(node);
|
|
1227
|
-
if (node.id.type ===
|
|
1316
|
+
if (node.id.type === import_utils15.AST_NODE_TYPES.Identifier) {
|
|
1228
1317
|
trackInitializer(node);
|
|
1229
1318
|
return;
|
|
1230
1319
|
}
|
|
1231
|
-
if (node.id.type ===
|
|
1320
|
+
if (node.id.type === import_utils15.AST_NODE_TYPES.ObjectPattern || node.id.type === import_utils15.AST_NODE_TYPES.ArrayPattern) {
|
|
1232
1321
|
if (isJsonCall(node.init)) {
|
|
1233
1322
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
1234
1323
|
return;
|
|
@@ -1240,7 +1329,7 @@ var prefer_schema_for_api_payload_default = import_utils14.ESLintUtils.RuleCreat
|
|
|
1240
1329
|
},
|
|
1241
1330
|
AssignmentExpression(node) {
|
|
1242
1331
|
const scope = context.sourceCode.getScope(node);
|
|
1243
|
-
if (node.left.type ===
|
|
1332
|
+
if (node.left.type === import_utils15.AST_NODE_TYPES.Identifier) {
|
|
1244
1333
|
const variable = findVariable2(scope, node.left.name);
|
|
1245
1334
|
if (variable === null) return;
|
|
1246
1335
|
if (isJsonCall(node.right)) {
|
|
@@ -1250,7 +1339,7 @@ var prefer_schema_for_api_payload_default = import_utils14.ESLintUtils.RuleCreat
|
|
|
1250
1339
|
}
|
|
1251
1340
|
return;
|
|
1252
1341
|
}
|
|
1253
|
-
if (node.left.type ===
|
|
1342
|
+
if (node.left.type === import_utils15.AST_NODE_TYPES.ObjectPattern || node.left.type === import_utils15.AST_NODE_TYPES.ArrayPattern) {
|
|
1254
1343
|
if (isJsonCall(node.right)) {
|
|
1255
1344
|
context.report({
|
|
1256
1345
|
node: node.left,
|
|
@@ -1271,13 +1360,13 @@ var prefer_schema_for_api_payload_default = import_utils14.ESLintUtils.RuleCreat
|
|
|
1271
1360
|
const obj = unwrap(node.object);
|
|
1272
1361
|
if (isJsonCall(obj)) {
|
|
1273
1362
|
const parent = node.parent;
|
|
1274
|
-
if (parent.type ===
|
|
1363
|
+
if (parent.type === import_utils15.AST_NODE_TYPES.CallExpression && parent.callee === node && node.property.type === import_utils15.AST_NODE_TYPES.Identifier && (node.property.name === "parse" || node.property.name === "safeParse")) {
|
|
1275
1364
|
return;
|
|
1276
1365
|
}
|
|
1277
1366
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
1278
1367
|
return;
|
|
1279
1368
|
}
|
|
1280
|
-
if (obj !== null && obj.type ===
|
|
1369
|
+
if (obj !== null && obj.type === import_utils15.AST_NODE_TYPES.Identifier && isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)) {
|
|
1281
1370
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
1282
1371
|
const variable = findVariable2(scope, obj.name);
|
|
1283
1372
|
if (variable !== null) {
|
|
@@ -1289,8 +1378,153 @@ var prefer_schema_for_api_payload_default = import_utils14.ESLintUtils.RuleCreat
|
|
|
1289
1378
|
}
|
|
1290
1379
|
});
|
|
1291
1380
|
|
|
1381
|
+
// src/rules/prefer-semantic-colors.ts
|
|
1382
|
+
var import_utils16 = require("@typescript-eslint/utils");
|
|
1383
|
+
|
|
1384
|
+
// src/rules/_tailwind.ts
|
|
1385
|
+
var tailwindBase = (token) => token.replace(/^(?:[a-z0-9-]+:)+/i, "").replace(/^!/, "");
|
|
1386
|
+
var classTokens = (value) => value.split(/\s+/).filter(Boolean);
|
|
1387
|
+
|
|
1388
|
+
// src/rules/prefer-semantic-colors.ts
|
|
1389
|
+
var COLOR_PREFIXES = "text|bg|border(?:-[trblxyse])?|ring(?:-offset)?|fill|stroke|from|via|to|divide|decoration|placeholder|accent|caret|shadow|outline";
|
|
1390
|
+
var PALETTE = "red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|slate|gray|zinc|neutral|stone";
|
|
1391
|
+
var COLOR_FN = "rgba?|hsla?|hwb|oklch|oklab|lab|lch|color";
|
|
1392
|
+
var RAW_PALETTE_RE = new RegExp(`^(?:${COLOR_PREFIXES})-(?:${PALETTE})-\\d{2,3}(?:/\\d{1,3})?$`);
|
|
1393
|
+
var ARBITRARY_COLOR_RE = new RegExp(
|
|
1394
|
+
`^(?:${COLOR_PREFIXES})-\\[(?:#[0-9a-fA-F]{3,8}|(?:${COLOR_FN})\\([^\\]]*\\))\\]$`,
|
|
1395
|
+
"i"
|
|
1396
|
+
);
|
|
1397
|
+
var CLASS_FNS = /* @__PURE__ */ new Set(["cn", "clsx", "cva", "tv", "cx", "twMerge", "classnames", "classNames"]);
|
|
1398
|
+
var CLASS_NAME_RE = /class/i;
|
|
1399
|
+
var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
|
|
1400
|
+
"color",
|
|
1401
|
+
"background",
|
|
1402
|
+
"backgroundColor",
|
|
1403
|
+
"borderColor",
|
|
1404
|
+
"borderTopColor",
|
|
1405
|
+
"borderRightColor",
|
|
1406
|
+
"borderBottomColor",
|
|
1407
|
+
"borderLeftColor",
|
|
1408
|
+
"outlineColor",
|
|
1409
|
+
"caretColor",
|
|
1410
|
+
"textDecorationColor",
|
|
1411
|
+
"columnRuleColor",
|
|
1412
|
+
"fill",
|
|
1413
|
+
"stroke",
|
|
1414
|
+
"stopColor",
|
|
1415
|
+
"floodColor",
|
|
1416
|
+
"lightingColor"
|
|
1417
|
+
]);
|
|
1418
|
+
var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
|
|
1419
|
+
var propName = (key) => {
|
|
1420
|
+
if (key.type === import_utils16.AST_NODE_TYPES.Identifier) return key.name;
|
|
1421
|
+
if (key.type === import_utils16.AST_NODE_TYPES.Literal && typeof key.value === "string") return key.value;
|
|
1422
|
+
return null;
|
|
1423
|
+
};
|
|
1424
|
+
var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
1425
|
+
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1426
|
+
)({
|
|
1427
|
+
name: "prefer-semantic-colors",
|
|
1428
|
+
meta: {
|
|
1429
|
+
type: "suggestion",
|
|
1430
|
+
docs: {
|
|
1431
|
+
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."
|
|
1432
|
+
},
|
|
1433
|
+
schema: [],
|
|
1434
|
+
messages: {
|
|
1435
|
+
rawPalette: "Raw palette class '{{class}}' \u2014 use a semantic token (e.g. text-foreground, bg-primary, text-destructive, bg-muted).",
|
|
1436
|
+
arbitraryColor: "Hardcoded color '{{class}}' \u2014 use a semantic token, or var(--\u2026). For charts/brand add an eslint-disable with a reason.",
|
|
1437
|
+
inlineColor: "Hardcoded color '{{value}}' \u2014 use a semantic token / CSS variable. For charts/standalone pages add an eslint-disable with a reason."
|
|
1438
|
+
}
|
|
1439
|
+
},
|
|
1440
|
+
defaultOptions: [],
|
|
1441
|
+
create(context) {
|
|
1442
|
+
const reportClasses = (value, node) => {
|
|
1443
|
+
for (const token of classTokens(value)) {
|
|
1444
|
+
const base = tailwindBase(token);
|
|
1445
|
+
if (RAW_PALETTE_RE.test(base)) {
|
|
1446
|
+
context.report({ node, messageId: "rawPalette", data: { class: token } });
|
|
1447
|
+
} else if (ARBITRARY_COLOR_RE.test(base)) {
|
|
1448
|
+
context.report({ node, messageId: "arbitraryColor", data: { class: token } });
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
const checkClassNode = (node) => {
|
|
1453
|
+
if (node === null) return;
|
|
1454
|
+
switch (node.type) {
|
|
1455
|
+
case import_utils16.AST_NODE_TYPES.Literal:
|
|
1456
|
+
if (typeof node.value === "string") reportClasses(node.value, node);
|
|
1457
|
+
break;
|
|
1458
|
+
case import_utils16.AST_NODE_TYPES.TemplateLiteral:
|
|
1459
|
+
for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? "", quasi);
|
|
1460
|
+
break;
|
|
1461
|
+
case import_utils16.AST_NODE_TYPES.ArrayExpression:
|
|
1462
|
+
for (const element of node.elements) {
|
|
1463
|
+
if (element !== null && element.type !== import_utils16.AST_NODE_TYPES.SpreadElement) checkClassNode(element);
|
|
1464
|
+
}
|
|
1465
|
+
break;
|
|
1466
|
+
case import_utils16.AST_NODE_TYPES.ObjectExpression:
|
|
1467
|
+
for (const property of node.properties) {
|
|
1468
|
+
if (property.type === import_utils16.AST_NODE_TYPES.Property) checkClassNode(property.value);
|
|
1469
|
+
}
|
|
1470
|
+
break;
|
|
1471
|
+
case import_utils16.AST_NODE_TYPES.ConditionalExpression:
|
|
1472
|
+
checkClassNode(node.consequent);
|
|
1473
|
+
checkClassNode(node.alternate);
|
|
1474
|
+
break;
|
|
1475
|
+
case import_utils16.AST_NODE_TYPES.LogicalExpression:
|
|
1476
|
+
checkClassNode(node.right);
|
|
1477
|
+
break;
|
|
1478
|
+
default:
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
const checkColorValueNode = (node) => {
|
|
1483
|
+
if (node.type === import_utils16.AST_NODE_TYPES.Literal && typeof node.value === "string" && RAW_COLOR_VALUE_RE.test(node.value)) {
|
|
1484
|
+
context.report({ node, messageId: "inlineColor", data: { value: node.value } });
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
return {
|
|
1488
|
+
"JSXAttribute[name.name='className']"(node) {
|
|
1489
|
+
if (node.value === null) return;
|
|
1490
|
+
if (node.value.type === import_utils16.AST_NODE_TYPES.Literal) checkClassNode(node.value);
|
|
1491
|
+
else if (node.value.type === import_utils16.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
1492
|
+
if (node.value.expression.type !== import_utils16.AST_NODE_TYPES.JSXEmptyExpression) {
|
|
1493
|
+
checkClassNode(node.value.expression);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
},
|
|
1497
|
+
CallExpression(node) {
|
|
1498
|
+
if (node.callee.type === import_utils16.AST_NODE_TYPES.Identifier && CLASS_FNS.has(node.callee.name)) {
|
|
1499
|
+
for (const arg of node.arguments) {
|
|
1500
|
+
if (arg.type !== import_utils16.AST_NODE_TYPES.SpreadElement) checkClassNode(arg);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
},
|
|
1504
|
+
VariableDeclarator(node) {
|
|
1505
|
+
if (node.id.type === import_utils16.AST_NODE_TYPES.Identifier && CLASS_NAME_RE.test(node.id.name)) {
|
|
1506
|
+
checkClassNode(node.init);
|
|
1507
|
+
}
|
|
1508
|
+
},
|
|
1509
|
+
Property(node) {
|
|
1510
|
+
const name = propName(node.key);
|
|
1511
|
+
if (name !== null && CLASS_NAME_RE.test(name)) checkClassNode(node.value);
|
|
1512
|
+
},
|
|
1513
|
+
// SVG presentation attributes: <path fill="#000" stroke="#fff" />
|
|
1514
|
+
"JSXAttribute[name.name=/^(fill|stroke|color)$/]"(node) {
|
|
1515
|
+
if (node.value?.type === import_utils16.AST_NODE_TYPES.Literal) checkColorValueNode(node.value);
|
|
1516
|
+
},
|
|
1517
|
+
// Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
|
|
1518
|
+
"JSXAttribute[name.name='style'] ObjectExpression > Property"(node) {
|
|
1519
|
+
const name = propName(node.key);
|
|
1520
|
+
if (name !== null && STYLE_COLOR_PROPS.has(name)) checkColorValueNode(node.value);
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
|
|
1292
1526
|
// src/rules/prefer-server-actions.ts
|
|
1293
|
-
var
|
|
1527
|
+
var import_utils17 = require("@typescript-eslint/utils");
|
|
1294
1528
|
var MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "DELETE", "PATCH"]);
|
|
1295
1529
|
var AXIOS_MUTATION_METHODS = /* @__PURE__ */ new Set(["post", "put", "delete", "patch"]);
|
|
1296
1530
|
var SKIP_FILE_REGEX = /(?:\.test\.[jt]sx?$|\.spec\.[jt]sx?$|\/tests?\/|\/__tests__\/|\/scripts?\/|\/app\/api\/.*\/route\.[jt]sx?$|\/pages\/api\/)/;
|
|
@@ -1350,7 +1584,7 @@ function isMutationMethod(node, context) {
|
|
|
1350
1584
|
}
|
|
1351
1585
|
return false;
|
|
1352
1586
|
}
|
|
1353
|
-
function getPropertyNode(objNode,
|
|
1587
|
+
function getPropertyNode(objNode, propName2) {
|
|
1354
1588
|
if (!objNode || objNode.type !== "ObjectExpression") return null;
|
|
1355
1589
|
for (const prop of objNode.properties) {
|
|
1356
1590
|
if (prop.type !== "Property") continue;
|
|
@@ -1360,7 +1594,7 @@ function getPropertyNode(objNode, propName) {
|
|
|
1360
1594
|
} else if (prop.key.type === "Literal" && typeof prop.key.value === "string") {
|
|
1361
1595
|
keyName = prop.key.value;
|
|
1362
1596
|
}
|
|
1363
|
-
if (keyName ===
|
|
1597
|
+
if (keyName === propName2) {
|
|
1364
1598
|
if (prop.value.type === "AssignmentPattern" || prop.value.type === "ArrayPattern" || prop.value.type === "ObjectPattern") {
|
|
1365
1599
|
return null;
|
|
1366
1600
|
}
|
|
@@ -1369,7 +1603,7 @@ function getPropertyNode(objNode, propName) {
|
|
|
1369
1603
|
}
|
|
1370
1604
|
return null;
|
|
1371
1605
|
}
|
|
1372
|
-
var prefer_server_actions_default =
|
|
1606
|
+
var prefer_server_actions_default = import_utils17.ESLintUtils.RuleCreator(
|
|
1373
1607
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1374
1608
|
)({
|
|
1375
1609
|
name: "prefer-server-actions",
|
|
@@ -1408,7 +1642,10 @@ var prefer_server_actions_default = import_utils15.ESLintUtils.RuleCreator(
|
|
|
1408
1642
|
const methodName = node.callee.property.name.toLowerCase();
|
|
1409
1643
|
if (AXIOS_MUTATION_METHODS.has(methodName)) {
|
|
1410
1644
|
const urlArg = node.arguments[0];
|
|
1411
|
-
|
|
1645
|
+
const hasHandlerArg = node.arguments.some(
|
|
1646
|
+
(arg) => arg.type === "ArrowFunctionExpression" || arg.type === "FunctionExpression"
|
|
1647
|
+
);
|
|
1648
|
+
if (urlArg && urlArg.type !== "SpreadElement" && !hasHandlerArg && isApiUrl(urlArg, context)) {
|
|
1412
1649
|
isMutation = true;
|
|
1413
1650
|
}
|
|
1414
1651
|
}
|
|
@@ -1434,14 +1671,14 @@ var prefer_server_actions_default = import_utils15.ESLintUtils.RuleCreator(
|
|
|
1434
1671
|
});
|
|
1435
1672
|
|
|
1436
1673
|
// src/rules/prefer-shadcn.ts
|
|
1437
|
-
var
|
|
1674
|
+
var import_utils18 = require("@typescript-eslint/utils");
|
|
1438
1675
|
var REPLACEMENTS = {
|
|
1439
1676
|
input: "Input",
|
|
1440
1677
|
select: "Select",
|
|
1441
1678
|
textarea: "Textarea",
|
|
1442
1679
|
dialog: "Dialog"
|
|
1443
1680
|
};
|
|
1444
|
-
var prefer_shadcn_default =
|
|
1681
|
+
var prefer_shadcn_default = import_utils18.ESLintUtils.RuleCreator(
|
|
1445
1682
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1446
1683
|
)({
|
|
1447
1684
|
name: "prefer-shadcn",
|
|
@@ -1482,36 +1719,52 @@ var prefer_shadcn_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1482
1719
|
});
|
|
1483
1720
|
|
|
1484
1721
|
// src/rules/require-assert-never.ts
|
|
1485
|
-
var
|
|
1722
|
+
var import_utils19 = require("@typescript-eslint/utils");
|
|
1486
1723
|
var isAssertNeverCall = (expression) => {
|
|
1487
|
-
if (expression.type !==
|
|
1724
|
+
if (expression.type !== import_utils19.AST_NODE_TYPES.CallExpression) return false;
|
|
1488
1725
|
const callee = expression.callee;
|
|
1489
|
-
|
|
1726
|
+
if (callee.type === import_utils19.AST_NODE_TYPES.Identifier) {
|
|
1727
|
+
return callee.name === "assertNever";
|
|
1728
|
+
}
|
|
1729
|
+
if (callee.type === import_utils19.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils19.AST_NODE_TYPES.Identifier) {
|
|
1730
|
+
return callee.property.name === "assertNever";
|
|
1731
|
+
}
|
|
1732
|
+
return false;
|
|
1490
1733
|
};
|
|
1491
1734
|
var statementContainsAssertNever = (statement) => {
|
|
1492
|
-
if (statement.type ===
|
|
1735
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.ExpressionStatement) {
|
|
1493
1736
|
return isAssertNeverCall(statement.expression);
|
|
1494
1737
|
}
|
|
1495
|
-
if (statement.type ===
|
|
1738
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.ThrowStatement) {
|
|
1496
1739
|
return isAssertNeverCall(statement.argument);
|
|
1497
1740
|
}
|
|
1498
|
-
if (statement.type ===
|
|
1741
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.ReturnStatement) {
|
|
1742
|
+
return statement.argument !== null && isAssertNeverCall(statement.argument);
|
|
1743
|
+
}
|
|
1744
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.BlockStatement) {
|
|
1499
1745
|
return statement.body.some(statementContainsAssertNever);
|
|
1500
1746
|
}
|
|
1501
1747
|
return false;
|
|
1502
1748
|
};
|
|
1503
|
-
var
|
|
1749
|
+
var isRuntimeHandlingStatement = (statement) => {
|
|
1750
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.EmptyStatement) return false;
|
|
1751
|
+
if (statement.type === import_utils19.AST_NODE_TYPES.BlockStatement) {
|
|
1752
|
+
return statement.body.some(isRuntimeHandlingStatement);
|
|
1753
|
+
}
|
|
1754
|
+
return true;
|
|
1755
|
+
};
|
|
1756
|
+
var require_assert_never_default = import_utils19.ESLintUtils.RuleCreator(
|
|
1504
1757
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1505
1758
|
)({
|
|
1506
1759
|
name: "require-assert-never",
|
|
1507
1760
|
meta: {
|
|
1508
1761
|
type: "problem",
|
|
1509
1762
|
docs: {
|
|
1510
|
-
description: "Require switch
|
|
1763
|
+
description: "Require an exhaustive-style switch whose `default` case does no runtime work to call `assertNever(_)` so that discriminated unions are exhaustively checked at compile time. Switches with a legitimate runtime default (a reducer's `return state`, an HTTP-status `return fallback()`, a `break`, a `throw`, etc.) are left alone."
|
|
1511
1764
|
},
|
|
1512
1765
|
schema: [],
|
|
1513
1766
|
messages: {
|
|
1514
|
-
missingAssertNever: "
|
|
1767
|
+
missingAssertNever: "Empty switch `default` case \u2014 add runtime handling or call `assertNever()` so the discriminated union is exhaustively checked at compile time."
|
|
1515
1768
|
}
|
|
1516
1769
|
},
|
|
1517
1770
|
defaultOptions: [],
|
|
@@ -1522,10 +1775,8 @@ var require_assert_never_default = import_utils17.ESLintUtils.RuleCreator(
|
|
|
1522
1775
|
(caseNode) => caseNode.test === null
|
|
1523
1776
|
);
|
|
1524
1777
|
if (!defaultCase) return;
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
);
|
|
1528
|
-
if (hasAssertNever) return;
|
|
1778
|
+
if (defaultCase.consequent.some(statementContainsAssertNever)) return;
|
|
1779
|
+
if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;
|
|
1529
1780
|
context.report({
|
|
1530
1781
|
node: defaultCase,
|
|
1531
1782
|
messageId: "missingAssertNever"
|
|
@@ -1536,43 +1787,91 @@ var require_assert_never_default = import_utils17.ESLintUtils.RuleCreator(
|
|
|
1536
1787
|
});
|
|
1537
1788
|
|
|
1538
1789
|
// src/rules/require-zod-form-validation.ts
|
|
1539
|
-
var
|
|
1540
|
-
var
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1790
|
+
var import_utils20 = require("@typescript-eslint/utils");
|
|
1791
|
+
var ZOD_SCHEMA_NAME_RE = /Schema$|^Z[A-Z]/;
|
|
1792
|
+
var looksLikeZodSchema = (node) => {
|
|
1793
|
+
let current = node;
|
|
1794
|
+
while (true) {
|
|
1795
|
+
if (current.type === import_utils20.AST_NODE_TYPES.Identifier) {
|
|
1796
|
+
return current.name === "z" || ZOD_SCHEMA_NAME_RE.test(current.name);
|
|
1797
|
+
}
|
|
1798
|
+
if (current.type === import_utils20.AST_NODE_TYPES.CallExpression) {
|
|
1799
|
+
current = current.callee;
|
|
1800
|
+
continue;
|
|
1801
|
+
}
|
|
1802
|
+
if (current.type === import_utils20.AST_NODE_TYPES.MemberExpression) {
|
|
1803
|
+
current = current.object;
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1544
1806
|
return false;
|
|
1545
1807
|
}
|
|
1546
|
-
return callee.object.type === import_utils18.AST_NODE_TYPES.Identifier && callee.object.name === "formData";
|
|
1547
1808
|
};
|
|
1548
|
-
var
|
|
1549
|
-
if (node.type !==
|
|
1809
|
+
var isZodParseCall = (node) => {
|
|
1810
|
+
if (node.type !== import_utils20.AST_NODE_TYPES.CallExpression) return false;
|
|
1550
1811
|
const callee = node.callee;
|
|
1551
|
-
if (callee.type !==
|
|
1552
|
-
|
|
1812
|
+
if (callee.type !== import_utils20.AST_NODE_TYPES.MemberExpression) return false;
|
|
1813
|
+
if (callee.computed) return false;
|
|
1814
|
+
if (callee.property.type !== import_utils20.AST_NODE_TYPES.Identifier) return false;
|
|
1815
|
+
const method = callee.property.name;
|
|
1816
|
+
if (method !== "parse" && method !== "safeParse") return false;
|
|
1817
|
+
return looksLikeZodSchema(callee.object);
|
|
1818
|
+
};
|
|
1819
|
+
var isFormDataMethodCall = (node) => {
|
|
1820
|
+
let current = node;
|
|
1821
|
+
if (current.type === import_utils20.AST_NODE_TYPES.AwaitExpression) {
|
|
1822
|
+
current = current.argument;
|
|
1823
|
+
}
|
|
1824
|
+
if (current.type !== import_utils20.AST_NODE_TYPES.CallExpression) return false;
|
|
1825
|
+
const callee = current.callee;
|
|
1826
|
+
return callee.type === import_utils20.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils20.AST_NODE_TYPES.Identifier && callee.property.name === "formData";
|
|
1553
1827
|
};
|
|
1554
|
-
var require_zod_form_validation_default =
|
|
1828
|
+
var require_zod_form_validation_default = import_utils20.ESLintUtils.RuleCreator(
|
|
1555
1829
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1556
1830
|
)({
|
|
1557
1831
|
name: "require-zod-form-validation",
|
|
1558
1832
|
meta: {
|
|
1559
1833
|
type: "problem",
|
|
1560
1834
|
docs: {
|
|
1561
|
-
description: "Require Zod validation (`Schema.parse(...)`) when reading values out of a `FormData` object."
|
|
1835
|
+
description: "Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object."
|
|
1562
1836
|
},
|
|
1563
1837
|
schema: [],
|
|
1564
1838
|
messages: {
|
|
1565
|
-
missingZodValidation: "FormData parsing must use Zod schema validation (e.g., Schema.parse())"
|
|
1839
|
+
missingZodValidation: "FormData parsing must use Zod schema validation (e.g., Schema.parse() / Schema.safeParse())"
|
|
1566
1840
|
}
|
|
1567
1841
|
},
|
|
1568
1842
|
defaultOptions: [],
|
|
1569
1843
|
create(context) {
|
|
1844
|
+
const isFormSourceIdentifier = (node) => {
|
|
1845
|
+
if (node.type !== import_utils20.AST_NODE_TYPES.Identifier) return false;
|
|
1846
|
+
if (/formdata/i.test(node.name)) return true;
|
|
1847
|
+
let scope = context.sourceCode.getScope(node);
|
|
1848
|
+
while (scope !== null) {
|
|
1849
|
+
const variable = scope.set.get(node.name);
|
|
1850
|
+
if (variable !== void 0 && variable.defs.length === 1) {
|
|
1851
|
+
const def = variable.defs[0];
|
|
1852
|
+
if (def !== void 0 && def.type === "Variable" && def.node.type === import_utils20.AST_NODE_TYPES.VariableDeclarator && def.node.init !== null) {
|
|
1853
|
+
return isFormDataMethodCall(def.node.init);
|
|
1854
|
+
}
|
|
1855
|
+
return false;
|
|
1856
|
+
}
|
|
1857
|
+
scope = scope.upper;
|
|
1858
|
+
}
|
|
1859
|
+
return false;
|
|
1860
|
+
};
|
|
1861
|
+
const isFormDataGetCall = (node) => {
|
|
1862
|
+
const callee = node.callee;
|
|
1863
|
+
if (callee.type !== import_utils20.AST_NODE_TYPES.MemberExpression) return false;
|
|
1864
|
+
if (callee.property.type !== import_utils20.AST_NODE_TYPES.Identifier || callee.property.name !== "get") {
|
|
1865
|
+
return false;
|
|
1866
|
+
}
|
|
1867
|
+
return isFormSourceIdentifier(callee.object);
|
|
1868
|
+
};
|
|
1570
1869
|
return {
|
|
1571
1870
|
CallExpression(node) {
|
|
1572
1871
|
if (!isFormDataGetCall(node)) return;
|
|
1573
1872
|
let parent = node.parent;
|
|
1574
1873
|
while (parent !== null && parent !== void 0) {
|
|
1575
|
-
if (
|
|
1874
|
+
if (isZodParseCall(parent)) return;
|
|
1576
1875
|
parent = parent.parent;
|
|
1577
1876
|
}
|
|
1578
1877
|
context.report({
|
|
@@ -1585,15 +1884,15 @@ var require_zod_form_validation_default = import_utils18.ESLintUtils.RuleCreator
|
|
|
1585
1884
|
});
|
|
1586
1885
|
|
|
1587
1886
|
// src/rules/zod-naming-convention.ts
|
|
1588
|
-
var
|
|
1887
|
+
var import_utils21 = require("@typescript-eslint/utils");
|
|
1589
1888
|
var calleeChainStartsWithZ = (node) => {
|
|
1590
1889
|
let current = node;
|
|
1591
|
-
while (current.type ===
|
|
1890
|
+
while (current.type === import_utils21.AST_NODE_TYPES.MemberExpression) {
|
|
1592
1891
|
const receiver = current.object;
|
|
1593
|
-
if (receiver.type ===
|
|
1892
|
+
if (receiver.type === import_utils21.AST_NODE_TYPES.Identifier && receiver.name === "z") {
|
|
1594
1893
|
return true;
|
|
1595
1894
|
}
|
|
1596
|
-
if (receiver.type ===
|
|
1895
|
+
if (receiver.type === import_utils21.AST_NODE_TYPES.CallExpression) {
|
|
1597
1896
|
current = receiver.callee;
|
|
1598
1897
|
continue;
|
|
1599
1898
|
}
|
|
@@ -1601,7 +1900,7 @@ var calleeChainStartsWithZ = (node) => {
|
|
|
1601
1900
|
}
|
|
1602
1901
|
return false;
|
|
1603
1902
|
};
|
|
1604
|
-
var zod_naming_convention_default =
|
|
1903
|
+
var zod_naming_convention_default = import_utils21.ESLintUtils.RuleCreator(
|
|
1605
1904
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1606
1905
|
)({
|
|
1607
1906
|
name: "zod-naming-convention",
|
|
@@ -1621,11 +1920,11 @@ var zod_naming_convention_default = import_utils19.ESLintUtils.RuleCreator(
|
|
|
1621
1920
|
VariableDeclarator(node) {
|
|
1622
1921
|
const init = node.init;
|
|
1623
1922
|
if (init === null || init === void 0) return;
|
|
1624
|
-
if (init.type !==
|
|
1923
|
+
if (init.type !== import_utils21.AST_NODE_TYPES.CallExpression) return;
|
|
1625
1924
|
const callee = init.callee;
|
|
1626
|
-
if (callee.type !==
|
|
1925
|
+
if (callee.type !== import_utils21.AST_NODE_TYPES.MemberExpression) return;
|
|
1627
1926
|
if (!calleeChainStartsWithZ(callee)) return;
|
|
1628
|
-
if (node.id.type !==
|
|
1927
|
+
if (node.id.type !== import_utils21.AST_NODE_TYPES.Identifier) return;
|
|
1629
1928
|
const variableName = node.id.name;
|
|
1630
1929
|
if (variableName.startsWith("Z")) return;
|
|
1631
1930
|
context.report({
|
|
@@ -1641,6 +1940,7 @@ var zod_naming_convention_default = import_utils19.ESLintUtils.RuleCreator(
|
|
|
1641
1940
|
var rules = {
|
|
1642
1941
|
"enforce-file-structure": enforce_file_structure_default,
|
|
1643
1942
|
"no-client-side-data-fetching": no_client_side_data_fetching_default,
|
|
1943
|
+
"no-comment-cruft": no_comment_cruft_default,
|
|
1644
1944
|
"no-enum": no_enum_default,
|
|
1645
1945
|
"no-insecure-random-id": no_insecure_random_id_default,
|
|
1646
1946
|
"no-json-stringify-error": no_json_stringify_error_default,
|
|
@@ -1652,6 +1952,7 @@ var rules = {
|
|
|
1652
1952
|
"no-unnecessary-use-client": no_unnecessary_use_client_default,
|
|
1653
1953
|
"prefer-discriminated-union": prefer_discriminated_union_default,
|
|
1654
1954
|
"prefer-schema-for-api-payload": prefer_schema_for_api_payload_default,
|
|
1955
|
+
"prefer-semantic-colors": prefer_semantic_colors_default,
|
|
1655
1956
|
"prefer-server-actions": prefer_server_actions_default,
|
|
1656
1957
|
"prefer-shadcn": prefer_shadcn_default,
|
|
1657
1958
|
"require-assert-never": require_assert_never_default,
|
|
@@ -1661,7 +1962,7 @@ var rules = {
|
|
|
1661
1962
|
var plugin = {
|
|
1662
1963
|
meta: {
|
|
1663
1964
|
name: "@sarj/eslint-plugin",
|
|
1664
|
-
version: "2.
|
|
1965
|
+
version: "2.2.0"
|
|
1665
1966
|
},
|
|
1666
1967
|
rules,
|
|
1667
1968
|
configs: {
|
|
@@ -1683,7 +1984,10 @@ var plugin = {
|
|
|
1683
1984
|
"@sarj/no-insecure-random-id": "warn",
|
|
1684
1985
|
"@sarj/no-json-stringify-error": "warn",
|
|
1685
1986
|
"@sarj/no-string-concat-in-loop": "warn",
|
|
1686
|
-
"@sarj/prefer-discriminated-union": "warn"
|
|
1987
|
+
"@sarj/prefer-discriminated-union": "warn",
|
|
1988
|
+
"@sarj/no-comment-cruft": "warn",
|
|
1989
|
+
// Frontend / styling — distilled from frontend PR-review mining.
|
|
1990
|
+
"@sarj/prefer-semantic-colors": "warn"
|
|
1687
1991
|
}
|
|
1688
1992
|
},
|
|
1689
1993
|
strict: {
|
|
@@ -1707,7 +2011,11 @@ var plugin = {
|
|
|
1707
2011
|
"@sarj/no-insecure-random-id": "error",
|
|
1708
2012
|
"@sarj/no-json-stringify-error": "error",
|
|
1709
2013
|
"@sarj/no-string-concat-in-loop": "error",
|
|
1710
|
-
"@sarj/prefer-discriminated-union": "error"
|
|
2014
|
+
"@sarj/prefer-discriminated-union": "error",
|
|
2015
|
+
"@sarj/no-comment-cruft": "error",
|
|
2016
|
+
// Frontend / styling — distilled from frontend PR-review mining. Stylistic,
|
|
2017
|
+
// no autofix → warn (rollout should prove the FP rate before raising it).
|
|
2018
|
+
"@sarj/prefer-semantic-colors": "warn"
|
|
1711
2019
|
}
|
|
1712
2020
|
}
|
|
1713
2021
|
}
|