@sarj/eslint-plugin 2.3.3 → 2.4.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 +923 -330
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +849 -250
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,41 +37,20 @@ module.exports = __toCommonJS(index_exports);
|
|
|
37
37
|
|
|
38
38
|
// src/rules/enforce-file-structure.ts
|
|
39
39
|
var import_utils = require("@typescript-eslint/utils");
|
|
40
|
-
var SECTION = {
|
|
41
|
-
declarations: 0,
|
|
42
|
-
functions: 1,
|
|
43
|
-
exports: 2
|
|
44
|
-
};
|
|
45
|
-
var SECTION_NAMES = ["declarations", "functions", "exports"];
|
|
46
|
-
var sectionName = (ordinal) => {
|
|
47
|
-
const name = SECTION_NAMES[ordinal];
|
|
48
|
-
return name ?? "unknown";
|
|
49
|
-
};
|
|
50
40
|
var SERVER_ACTION_FILE_RE = /(?:^|\/)actions\/|\.action\.[jt]sx?$|(?:^|\/)actions\.[jt]sx?$/;
|
|
51
|
-
var
|
|
52
|
-
var isFunctionLikeVariable = (statement) => statement.declarations.length > 0 && statement.declarations.every(
|
|
53
|
-
(decl) => decl.init !== null && isFunctionExpression(decl.init)
|
|
54
|
-
);
|
|
55
|
-
var getStatementSection = (statement) => {
|
|
41
|
+
var classifyStatement = (statement) => {
|
|
56
42
|
switch (statement.type) {
|
|
57
43
|
case import_utils.AST_NODE_TYPES.ImportDeclaration:
|
|
58
|
-
|
|
59
|
-
case import_utils.AST_NODE_TYPES.TSInterfaceDeclaration:
|
|
60
|
-
case import_utils.AST_NODE_TYPES.TSEnumDeclaration:
|
|
61
|
-
case import_utils.AST_NODE_TYPES.ClassDeclaration:
|
|
62
|
-
return SECTION.declarations;
|
|
63
|
-
case import_utils.AST_NODE_TYPES.VariableDeclaration:
|
|
64
|
-
return isFunctionLikeVariable(statement) ? SECTION.functions : SECTION.declarations;
|
|
65
|
-
case import_utils.AST_NODE_TYPES.FunctionDeclaration:
|
|
66
|
-
return SECTION.functions;
|
|
67
|
-
case import_utils.AST_NODE_TYPES.ExportNamedDeclaration:
|
|
68
|
-
case import_utils.AST_NODE_TYPES.ExportDefaultDeclaration:
|
|
44
|
+
return "import";
|
|
69
45
|
case import_utils.AST_NODE_TYPES.ExportAllDeclaration:
|
|
70
|
-
return
|
|
46
|
+
return "reexport";
|
|
47
|
+
case import_utils.AST_NODE_TYPES.ExportNamedDeclaration:
|
|
48
|
+
return statement.declaration === null ? "reexport" : "body";
|
|
71
49
|
default:
|
|
72
|
-
return
|
|
50
|
+
return "body";
|
|
73
51
|
}
|
|
74
52
|
};
|
|
53
|
+
var isStringDirective = (statement) => 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 ");
|
|
75
54
|
var isUseServerDirective = (statement) => {
|
|
76
55
|
if (statement === void 0) return false;
|
|
77
56
|
if (statement.type !== import_utils.AST_NODE_TYPES.ExpressionStatement) return false;
|
|
@@ -86,47 +65,43 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
|
|
|
86
65
|
meta: {
|
|
87
66
|
type: "suggestion",
|
|
88
67
|
docs: {
|
|
89
|
-
description: "
|
|
68
|
+
description: "Require `import` statements to come first, then allow step-down ordering (public API first, private helpers below) for the rest of the file. Exported statements are classified by WHAT they export \u2014 an exported interface is a declaration, an exported function is a function \u2014 so a public exported function followed by a private helper, or an exported interface among declarations, is allowed. Re-exports (`export { \u2026 } from`, `export *`, `export { \u2026 }`) are a neutral group, so generated namespace barrels pass. Server-action files (under `/actions/`, named `*.action.ts`, or `actions.ts`) must also begin with a `use server` directive."
|
|
90
69
|
},
|
|
91
70
|
schema: [],
|
|
92
71
|
messages: {
|
|
93
|
-
|
|
72
|
+
importsFirst: "File structure violation: import statements must come before other declarations",
|
|
94
73
|
useServerDirective: "Server action files must start with 'use server' directive"
|
|
95
74
|
}
|
|
96
75
|
},
|
|
97
76
|
defaultOptions: [],
|
|
98
77
|
create(context) {
|
|
99
|
-
const
|
|
100
|
-
const isServerAction = SERVER_ACTION_FILE_RE.test(filename);
|
|
78
|
+
const isServerAction = SERVER_ACTION_FILE_RE.test(context.filename);
|
|
101
79
|
return {
|
|
102
80
|
Program(node) {
|
|
103
81
|
const body = node.body;
|
|
104
|
-
if (isServerAction) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
messageId: "useServerDirective"
|
|
110
|
-
});
|
|
111
|
-
}
|
|
82
|
+
if (isServerAction && !isUseServerDirective(body[0])) {
|
|
83
|
+
context.report({
|
|
84
|
+
node,
|
|
85
|
+
messageId: "useServerDirective"
|
|
86
|
+
});
|
|
112
87
|
}
|
|
113
|
-
let
|
|
88
|
+
let seenBody = false;
|
|
114
89
|
for (const statement of body) {
|
|
115
|
-
if (statement
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
90
|
+
if (isStringDirective(statement)) continue;
|
|
91
|
+
switch (classifyStatement(statement)) {
|
|
92
|
+
case "reexport":
|
|
93
|
+
continue;
|
|
94
|
+
case "body":
|
|
95
|
+
seenBody = true;
|
|
96
|
+
continue;
|
|
97
|
+
case "import":
|
|
98
|
+
if (seenBody) {
|
|
99
|
+
context.report({
|
|
100
|
+
node: statement,
|
|
101
|
+
messageId: "importsFirst"
|
|
102
|
+
});
|
|
126
103
|
}
|
|
127
|
-
|
|
128
|
-
} else if (statementSection > currentSection) {
|
|
129
|
-
currentSection = statementSection;
|
|
104
|
+
continue;
|
|
130
105
|
}
|
|
131
106
|
}
|
|
132
107
|
}
|
|
@@ -272,7 +247,7 @@ var no_client_side_data_fetching_default = import_utils2.ESLintUtils.RuleCreator
|
|
|
272
247
|
// src/rules/no-comment-cruft.ts
|
|
273
248
|
var import_utils3 = require("@typescript-eslint/utils");
|
|
274
249
|
var LEADING_PREAMBLE_MIN = 4;
|
|
275
|
-
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;
|
|
250
|
+
var DIRECTIVE_RE = /^(eslint\b|eslint-|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|todo\b|fixme\b|hack\b|xxx\b)/i;
|
|
276
251
|
var LICENSE_RE = /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;
|
|
277
252
|
var BANNER_FULL_RE = /^[\s\-=*#~_+.]{4,}$/;
|
|
278
253
|
var BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\*{4,}|~{4,}/;
|
|
@@ -280,8 +255,9 @@ var REGION_RE = /^#?(?:end)?region\b/i;
|
|
|
280
255
|
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\.)/;
|
|
281
256
|
var CODE_TAIL_RE = /[;{}()]\s*$|=>\s*$|,\s*$/;
|
|
282
257
|
var CALL_OR_ASSIGN_RE = /^[A-Za-z_$][\w.$[\]]*\s*(?:=(?![=>])|\+=|-=|\*=)\s*\S.*[;)}\]]\s*$|^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
|
|
258
|
+
var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|…|\.\.\./;
|
|
283
259
|
function stripCommentMarker(line) {
|
|
284
|
-
return line.replace(/^\s
|
|
260
|
+
return line.replace(/^\s*\/{1,2}/, "").replace(/^\s*\*+/, "").trim();
|
|
285
261
|
}
|
|
286
262
|
function isDirective(text) {
|
|
287
263
|
return DIRECTIVE_RE.test(text.trim());
|
|
@@ -297,6 +273,30 @@ function looksLikeCode(text) {
|
|
|
297
273
|
if (CODE_KEYWORD_RE.test(t) && CODE_TAIL_RE.test(t)) return true;
|
|
298
274
|
return CALL_OR_ASSIGN_RE.test(t);
|
|
299
275
|
}
|
|
276
|
+
function hasPseudocode(text) {
|
|
277
|
+
return PSEUDOCODE_RE.test(text);
|
|
278
|
+
}
|
|
279
|
+
function isProse(text) {
|
|
280
|
+
const t = text.trim();
|
|
281
|
+
if (!t) return false;
|
|
282
|
+
if (t.endsWith(":")) return true;
|
|
283
|
+
if (/[.!?]$/.test(t) && /\s/.test(t) && /[a-z]/.test(t) && !looksLikeCode(t) && t.split(/\s+/).length >= 3) {
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function hasCommentedOutCode(texts, precedingProse) {
|
|
289
|
+
for (let i = 0; i < texts.length; i++) {
|
|
290
|
+
const line = texts[i];
|
|
291
|
+
if (line === void 0 || !looksLikeCode(line) || hasPseudocode(line)) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
const prev = i > 0 ? texts[i - 1] : void 0;
|
|
295
|
+
if (prev !== void 0 ? isProse(prev) : precedingProse) continue;
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
300
|
var no_comment_cruft_default = import_utils3.ESLintUtils.RuleCreator(
|
|
301
301
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
302
302
|
)({
|
|
@@ -351,12 +351,19 @@ var no_comment_cruft_default = import_utils3.ESLintUtils.RuleCreator(
|
|
|
351
351
|
Program() {
|
|
352
352
|
const comments = sourceCode.getAllComments();
|
|
353
353
|
const firstCodeLine = sourceCode.ast.tokens[0]?.loc.start.line ?? Number.MAX_SAFE_INTEGER;
|
|
354
|
-
for (
|
|
354
|
+
for (let i = 0; i < comments.length; i++) {
|
|
355
|
+
const comment = comments[i];
|
|
356
|
+
if (comment === void 0) continue;
|
|
355
357
|
if (isJsDoc(comment) || !isStandalone(comment)) continue;
|
|
358
|
+
if (LICENSE_RE.test(comment.value)) continue;
|
|
356
359
|
const texts = comment.value.split("\n").map(stripCommentMarker).filter((l) => l.length > 0 && !isDirective(l));
|
|
357
360
|
if (texts.some(isBanner)) {
|
|
358
361
|
context.report({ node: comment, messageId: "sectionBanner" });
|
|
359
|
-
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const prev = comments[i - 1];
|
|
365
|
+
const precedingProse = prev !== void 0 && prev.type === "Line" && prev.loc.end.line === comment.loc.start.line - 1 && isProse(stripCommentMarker(prev.value));
|
|
366
|
+
if (hasCommentedOutCode(texts, precedingProse)) {
|
|
360
367
|
context.report({ node: comment, messageId: "commentedOutCode" });
|
|
361
368
|
}
|
|
362
369
|
}
|
|
@@ -438,7 +445,9 @@ var no_enum_default = import_utils4.ESLintUtils.RuleCreator(
|
|
|
438
445
|
|
|
439
446
|
// src/rules/no-insecure-random-id.ts
|
|
440
447
|
var import_utils5 = require("@typescript-eslint/utils");
|
|
441
|
-
var
|
|
448
|
+
var STRONG_SECURITY_PATTERN = /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;
|
|
449
|
+
var NON_SECURITY_ID_PATTERN = /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;
|
|
450
|
+
var PATH_OR_DOM_MARKER = /[\\/#]|\.[A-Za-z0-9]/;
|
|
442
451
|
function isMathRandomCall(node) {
|
|
443
452
|
if (node.type !== "CallExpression") {
|
|
444
453
|
return false;
|
|
@@ -450,6 +459,24 @@ function isMathRandomCall(node) {
|
|
|
450
459
|
const { object, property } = callee;
|
|
451
460
|
return object.type === "Identifier" && object.name === "Math" && property.type === "Identifier" && property.name === "random";
|
|
452
461
|
}
|
|
462
|
+
function climbValueChain(node) {
|
|
463
|
+
let current = node;
|
|
464
|
+
let parent = current.parent;
|
|
465
|
+
while (parent) {
|
|
466
|
+
if (parent.type === "MemberExpression" && parent.object === current && !parent.computed) {
|
|
467
|
+
current = parent;
|
|
468
|
+
parent = current.parent;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
if (parent.type === "CallExpression" && parent.callee === current) {
|
|
472
|
+
current = parent;
|
|
473
|
+
parent = current.parent;
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
return current;
|
|
479
|
+
}
|
|
453
480
|
function isPartOfToString36Chain(node) {
|
|
454
481
|
let current = node;
|
|
455
482
|
let parent = current.parent;
|
|
@@ -515,6 +542,49 @@ function findEnclosingName(node) {
|
|
|
515
542
|
}
|
|
516
543
|
return void 0;
|
|
517
544
|
}
|
|
545
|
+
function collectStaticStringParts(node, out) {
|
|
546
|
+
if (node.type === "Literal" && typeof node.value === "string") {
|
|
547
|
+
out.push(node.value);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
if (node.type === "TemplateLiteral") {
|
|
551
|
+
for (const quasi of node.quasis) {
|
|
552
|
+
out.push(quasi.value.cooked ?? quasi.value.raw);
|
|
553
|
+
}
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (node.type === "BinaryExpression" && node.operator === "+") {
|
|
557
|
+
collectStaticStringParts(node.left, out);
|
|
558
|
+
collectStaticStringParts(node.right, out);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function isConcatenatedIntoPathOrDomId(node) {
|
|
562
|
+
const valueNode = climbValueChain(node);
|
|
563
|
+
let current = valueNode;
|
|
564
|
+
let parent = current.parent;
|
|
565
|
+
let top;
|
|
566
|
+
while (parent) {
|
|
567
|
+
if (parent.type === "BinaryExpression" && parent.operator === "+" && (parent.left === current || parent.right === current)) {
|
|
568
|
+
top = parent;
|
|
569
|
+
current = parent;
|
|
570
|
+
parent = current.parent;
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
if (parent.type === "TemplateLiteral") {
|
|
574
|
+
top = parent;
|
|
575
|
+
current = parent;
|
|
576
|
+
parent = current.parent;
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
if (!top) {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
const parts = [];
|
|
585
|
+
collectStaticStringParts(top, parts);
|
|
586
|
+
return parts.some((part) => PATH_OR_DOM_MARKER.test(part));
|
|
587
|
+
}
|
|
518
588
|
var no_insecure_random_id_default = import_utils5.ESLintUtils.RuleCreator(
|
|
519
589
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
520
590
|
)({
|
|
@@ -536,12 +606,18 @@ var no_insecure_random_id_default = import_utils5.ESLintUtils.RuleCreator(
|
|
|
536
606
|
if (!isMathRandomCall(node)) {
|
|
537
607
|
return;
|
|
538
608
|
}
|
|
539
|
-
|
|
609
|
+
const name = findEnclosingName(node);
|
|
610
|
+
if (name !== void 0 && STRONG_SECURITY_PATTERN.test(name)) {
|
|
540
611
|
context.report({ node, messageId: "insecureRandomId" });
|
|
541
612
|
return;
|
|
542
613
|
}
|
|
543
|
-
|
|
544
|
-
|
|
614
|
+
if (name !== void 0 && NON_SECURITY_ID_PATTERN.test(name)) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (isConcatenatedIntoPathOrDomId(node)) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (isPartOfToString36Chain(node)) {
|
|
545
621
|
context.report({ node, messageId: "insecureRandomId" });
|
|
546
622
|
}
|
|
547
623
|
}
|
|
@@ -552,6 +628,8 @@ var no_insecure_random_id_default = import_utils5.ESLintUtils.RuleCreator(
|
|
|
552
628
|
// src/rules/no-json-stringify-error.ts
|
|
553
629
|
var import_utils6 = require("@typescript-eslint/utils");
|
|
554
630
|
var ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;
|
|
631
|
+
var ERROR_PROP_PATTERN = /^(cause|lastError|error|err|exception|originalError|innerError)$/i;
|
|
632
|
+
var SAFE_STRING_PROPS = /* @__PURE__ */ new Set(["message", "stack", "name"]);
|
|
555
633
|
function isCatchBinding(scope, name) {
|
|
556
634
|
let current = scope;
|
|
557
635
|
while (current) {
|
|
@@ -567,6 +645,61 @@ function isCatchBinding(scope, name) {
|
|
|
567
645
|
}
|
|
568
646
|
return false;
|
|
569
647
|
}
|
|
648
|
+
function memberSuggestsError(member, scope) {
|
|
649
|
+
const propName2 = !member.computed && member.property.type === "Identifier" ? member.property.name : null;
|
|
650
|
+
if (propName2 !== null && ERROR_PROP_PATTERN.test(propName2)) {
|
|
651
|
+
return true;
|
|
652
|
+
}
|
|
653
|
+
const base = member.object;
|
|
654
|
+
const baseSuggestsError = base.type === "Identifier" && (ERROR_NAME_PATTERN.test(base.name) || isCatchBinding(scope, base.name));
|
|
655
|
+
if (baseSuggestsError) {
|
|
656
|
+
return propName2 === null || !SAFE_STRING_PROPS.has(propName2.toLowerCase());
|
|
657
|
+
}
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
function instanceofErrorSubject(test) {
|
|
661
|
+
if (test.type === "BinaryExpression" && test.operator === "instanceof" && test.right.type === "Identifier" && test.right.name === "Error") {
|
|
662
|
+
return test.left;
|
|
663
|
+
}
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
function negatedInstanceofErrorSubject(test) {
|
|
667
|
+
if (test.type === "UnaryExpression" && test.operator === "!") {
|
|
668
|
+
return instanceofErrorSubject(test.argument);
|
|
669
|
+
}
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
function nodeWithin(node, container) {
|
|
673
|
+
return container !== null && node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
674
|
+
}
|
|
675
|
+
function isGuardedByInstanceofError(node, argExpr, sourceCode) {
|
|
676
|
+
const argText = sourceCode.getText(argExpr);
|
|
677
|
+
const sameSubject = (subject) => sourceCode.getText(subject) === argText;
|
|
678
|
+
let current = node.parent;
|
|
679
|
+
while (current) {
|
|
680
|
+
if (current.type === "ConditionalExpression") {
|
|
681
|
+
const subject = instanceofErrorSubject(current.test);
|
|
682
|
+
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
683
|
+
return true;
|
|
684
|
+
}
|
|
685
|
+
const negated = negatedInstanceofErrorSubject(current.test);
|
|
686
|
+
if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
} else if (current.type === "IfStatement") {
|
|
690
|
+
const subject = instanceofErrorSubject(current.test);
|
|
691
|
+
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
const negated = negatedInstanceofErrorSubject(current.test);
|
|
695
|
+
if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
current = current.parent;
|
|
700
|
+
}
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
570
703
|
function isJsonStringify(callee) {
|
|
571
704
|
return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
|
|
572
705
|
}
|
|
@@ -592,72 +725,124 @@ var no_json_stringify_error_default = import_utils6.ESLintUtils.RuleCreator(
|
|
|
592
725
|
return;
|
|
593
726
|
}
|
|
594
727
|
const firstArg = node.arguments[0];
|
|
595
|
-
if (!firstArg
|
|
728
|
+
if (!firstArg) {
|
|
596
729
|
return;
|
|
597
730
|
}
|
|
598
|
-
const name = firstArg.name;
|
|
599
731
|
const scope = context.sourceCode.getScope(firstArg);
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
732
|
+
let suggestsError;
|
|
733
|
+
if (firstArg.type === "Identifier") {
|
|
734
|
+
suggestsError = ERROR_NAME_PATTERN.test(firstArg.name) || isCatchBinding(scope, firstArg.name);
|
|
735
|
+
} else if (firstArg.type === "MemberExpression") {
|
|
736
|
+
suggestsError = memberSuggestsError(firstArg, scope);
|
|
737
|
+
} else {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
if (!suggestsError) {
|
|
741
|
+
return;
|
|
605
742
|
}
|
|
743
|
+
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode)) {
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
context.report({
|
|
747
|
+
node,
|
|
748
|
+
messageId: "noJsonStringifyError"
|
|
749
|
+
});
|
|
606
750
|
}
|
|
607
751
|
};
|
|
608
752
|
}
|
|
609
753
|
});
|
|
610
754
|
|
|
611
755
|
// src/rules/no-log-only-catch.ts
|
|
756
|
+
var import_utils8 = require("@typescript-eslint/utils");
|
|
757
|
+
|
|
758
|
+
// src/rules/_logging.ts
|
|
612
759
|
var import_utils7 = require("@typescript-eslint/utils");
|
|
613
|
-
var
|
|
614
|
-
|
|
615
|
-
/\.spec\./,
|
|
616
|
-
/[\\/]__tests__[\\/]/
|
|
617
|
-
];
|
|
618
|
-
var CONSOLE_METHODS = /* @__PURE__ */ new Set([
|
|
619
|
-
"log",
|
|
620
|
-
"error",
|
|
621
|
-
"warn",
|
|
760
|
+
var LOG_METHODS = /* @__PURE__ */ new Set([
|
|
761
|
+
"debug",
|
|
622
762
|
"info",
|
|
623
|
-
"
|
|
763
|
+
"warn",
|
|
764
|
+
"warning",
|
|
765
|
+
"error",
|
|
766
|
+
"exception",
|
|
767
|
+
"critical",
|
|
768
|
+
"trace",
|
|
769
|
+
"log",
|
|
770
|
+
"fatal",
|
|
771
|
+
"success"
|
|
624
772
|
]);
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
773
|
+
var LOGGER_NAMES = /* @__PURE__ */ new Set([
|
|
774
|
+
"logger",
|
|
775
|
+
"log",
|
|
776
|
+
"logging",
|
|
777
|
+
"loguru",
|
|
778
|
+
"console",
|
|
779
|
+
"_logger",
|
|
780
|
+
"_log"
|
|
781
|
+
]);
|
|
782
|
+
var REPORT_NAME_RE = /error|report|capture|log|trace|warn/i;
|
|
783
|
+
function isLoggerReceiver(expr) {
|
|
784
|
+
switch (expr.type) {
|
|
785
|
+
case "Identifier":
|
|
786
|
+
return LOGGER_NAMES.has(expr.name.toLowerCase());
|
|
787
|
+
case "MemberExpression": {
|
|
788
|
+
const { property, object } = expr;
|
|
789
|
+
if (!expr.computed && property.type === "Identifier" && LOGGER_NAMES.has(property.name.toLowerCase())) {
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
return isLoggerReceiver(object);
|
|
793
|
+
}
|
|
794
|
+
default:
|
|
795
|
+
return false;
|
|
628
796
|
}
|
|
629
|
-
|
|
797
|
+
}
|
|
798
|
+
function isLoggingCall(expr) {
|
|
630
799
|
if (expr.type !== "CallExpression") {
|
|
631
800
|
return false;
|
|
632
801
|
}
|
|
633
802
|
const callee = expr.callee;
|
|
634
|
-
if (callee.type !== "MemberExpression") {
|
|
803
|
+
if (callee.type !== "MemberExpression" || callee.computed || callee.property.type !== "Identifier") {
|
|
635
804
|
return false;
|
|
636
805
|
}
|
|
637
|
-
|
|
638
|
-
if (object.type !== "Identifier" || object.name !== "console") {
|
|
806
|
+
if (!LOG_METHODS.has(callee.property.name.toLowerCase())) {
|
|
639
807
|
return false;
|
|
640
808
|
}
|
|
641
|
-
|
|
642
|
-
|
|
809
|
+
return isLoggerReceiver(callee.object);
|
|
810
|
+
}
|
|
811
|
+
function calleeName(callee) {
|
|
812
|
+
if (callee.type === "Identifier") {
|
|
813
|
+
return callee.name;
|
|
643
814
|
}
|
|
644
|
-
if (property.type
|
|
815
|
+
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier") {
|
|
816
|
+
return callee.property.name;
|
|
817
|
+
}
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// src/rules/no-log-only-catch.ts
|
|
822
|
+
var DEFAULT_IGNORE_PATTERNS2 = [
|
|
823
|
+
/\.test\./,
|
|
824
|
+
/\.spec\./,
|
|
825
|
+
/[\\/]__tests__[\\/]/
|
|
826
|
+
];
|
|
827
|
+
function isLoggingCallStatement(statement) {
|
|
828
|
+
if (statement.type !== "ExpressionStatement") {
|
|
645
829
|
return false;
|
|
646
830
|
}
|
|
647
|
-
return
|
|
831
|
+
return isLoggingCall(statement.expression);
|
|
648
832
|
}
|
|
649
|
-
var no_log_only_catch_default =
|
|
833
|
+
var no_log_only_catch_default = import_utils8.ESLintUtils.RuleCreator(
|
|
650
834
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
651
835
|
)({
|
|
652
836
|
name: "no-log-only-catch",
|
|
653
837
|
meta: {
|
|
654
838
|
type: "problem",
|
|
655
839
|
docs: {
|
|
656
|
-
description: "Disallow `catch` clauses that only log (or do nothing) and then swallow the error; rethrow or handle it instead."
|
|
840
|
+
description: "Disallow `catch` clauses that only log (or silently do nothing) and then swallow the error; rethrow or handle it instead."
|
|
657
841
|
},
|
|
658
842
|
schema: [],
|
|
659
843
|
messages: {
|
|
660
|
-
noLogOnlyCatch: "Logging then swallowing the error hides failures. Rethrow the error or handle it for real."
|
|
844
|
+
noLogOnlyCatch: "Logging then swallowing the error hides failures. Rethrow the error or handle it for real.",
|
|
845
|
+
emptyCatch: "Empty catch silently swallows the error. Rethrow it, handle it, or add a comment explaining why it is safe to ignore."
|
|
661
846
|
}
|
|
662
847
|
},
|
|
663
848
|
defaultOptions: [],
|
|
@@ -673,13 +858,16 @@ var no_log_only_catch_default = import_utils7.ESLintUtils.RuleCreator(
|
|
|
673
858
|
CatchClause(node) {
|
|
674
859
|
const statements = node.body.body;
|
|
675
860
|
if (statements.length === 0) {
|
|
676
|
-
context.
|
|
861
|
+
if (context.sourceCode.getCommentsInside(node.body).length > 0) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
context.report({ node, messageId: "emptyCatch" });
|
|
677
865
|
return;
|
|
678
866
|
}
|
|
679
|
-
const
|
|
680
|
-
(statement) =>
|
|
867
|
+
const everyStatementIsLogging = statements.every(
|
|
868
|
+
(statement) => isLoggingCallStatement(statement)
|
|
681
869
|
);
|
|
682
|
-
if (
|
|
870
|
+
if (everyStatementIsLogging) {
|
|
683
871
|
context.report({ node, messageId: "noLogOnlyCatch" });
|
|
684
872
|
}
|
|
685
873
|
}
|
|
@@ -688,8 +876,14 @@ var no_log_only_catch_default = import_utils7.ESLintUtils.RuleCreator(
|
|
|
688
876
|
});
|
|
689
877
|
|
|
690
878
|
// src/rules/no-raw-env.ts
|
|
691
|
-
var
|
|
692
|
-
|
|
879
|
+
var import_utils9 = require("@typescript-eslint/utils");
|
|
880
|
+
function isProcessEnv(node) {
|
|
881
|
+
return !node.computed && node.object.type === "Identifier" && node.object.name === "process" && node.property.type === "Identifier" && node.property.name === "env";
|
|
882
|
+
}
|
|
883
|
+
function isImportMetaEnv(node) {
|
|
884
|
+
return !node.computed && node.property.type === "Identifier" && node.property.name === "env" && node.object.type === "MetaProperty" && node.object.meta.name === "import" && node.object.property.name === "meta";
|
|
885
|
+
}
|
|
886
|
+
var no_raw_env_default = import_utils9.ESLintUtils.RuleCreator(
|
|
693
887
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
694
888
|
)({
|
|
695
889
|
name: "no-raw-env",
|
|
@@ -707,10 +901,7 @@ var no_raw_env_default = import_utils8.ESLintUtils.RuleCreator(
|
|
|
707
901
|
create(context) {
|
|
708
902
|
return {
|
|
709
903
|
MemberExpression(node) {
|
|
710
|
-
if (node
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
if (node.object.type === "Identifier" && node.object.name === "process" && node.property.type === "Identifier" && node.property.name === "env") {
|
|
904
|
+
if (isProcessEnv(node) || isImportMetaEnv(node)) {
|
|
714
905
|
context.report({
|
|
715
906
|
node,
|
|
716
907
|
messageId: "noRawEnv"
|
|
@@ -722,39 +913,72 @@ var no_raw_env_default = import_utils8.ESLintUtils.RuleCreator(
|
|
|
722
913
|
});
|
|
723
914
|
|
|
724
915
|
// src/rules/no-sentinel-return-on-catch.ts
|
|
725
|
-
var
|
|
916
|
+
var import_utils10 = require("@typescript-eslint/utils");
|
|
917
|
+
function sentinelKind(arg) {
|
|
918
|
+
if (arg === null) {
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.Literal) {
|
|
922
|
+
if (arg.value === null) {
|
|
923
|
+
return "nullish";
|
|
924
|
+
}
|
|
925
|
+
if (typeof arg.value === "boolean") {
|
|
926
|
+
return "boolean";
|
|
927
|
+
}
|
|
928
|
+
if (typeof arg.value === "string") {
|
|
929
|
+
return "string";
|
|
930
|
+
}
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.Identifier && arg.name === "undefined") {
|
|
934
|
+
return "nullish";
|
|
935
|
+
}
|
|
936
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.ArrayExpression) {
|
|
937
|
+
return "array";
|
|
938
|
+
}
|
|
939
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.ObjectExpression) {
|
|
940
|
+
return "object";
|
|
941
|
+
}
|
|
942
|
+
return null;
|
|
943
|
+
}
|
|
726
944
|
function isSentinelArgument(arg) {
|
|
727
945
|
if (arg === null) {
|
|
728
946
|
return false;
|
|
729
947
|
}
|
|
730
|
-
if (arg.type ===
|
|
948
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.Literal && arg.value === null) {
|
|
731
949
|
return true;
|
|
732
950
|
}
|
|
733
|
-
if (arg.type ===
|
|
951
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.Literal && arg.value === false) {
|
|
734
952
|
return true;
|
|
735
953
|
}
|
|
736
|
-
if (arg.type ===
|
|
954
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.Identifier && arg.name === "undefined") {
|
|
737
955
|
return true;
|
|
738
956
|
}
|
|
739
|
-
if (arg.type ===
|
|
957
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.ArrayExpression && arg.elements.length === 0) {
|
|
740
958
|
return true;
|
|
741
959
|
}
|
|
742
|
-
if (arg.type ===
|
|
960
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.ObjectExpression && arg.properties.length === 0) {
|
|
743
961
|
return true;
|
|
744
962
|
}
|
|
745
963
|
return false;
|
|
746
964
|
}
|
|
747
|
-
function
|
|
965
|
+
function isFunctionNode(node) {
|
|
966
|
+
return node.type === import_utils10.AST_NODE_TYPES.FunctionDeclaration || node.type === import_utils10.AST_NODE_TYPES.FunctionExpression || node.type === import_utils10.AST_NODE_TYPES.ArrowFunctionExpression;
|
|
967
|
+
}
|
|
968
|
+
function isNode(value) {
|
|
969
|
+
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
970
|
+
}
|
|
971
|
+
function walkWithinScope(node, visit) {
|
|
748
972
|
let found = false;
|
|
749
|
-
const
|
|
973
|
+
const recurse = (current) => {
|
|
750
974
|
if (found) {
|
|
751
975
|
return;
|
|
752
976
|
}
|
|
753
|
-
if (current
|
|
977
|
+
if (visit(current)) {
|
|
754
978
|
found = true;
|
|
755
979
|
return;
|
|
756
980
|
}
|
|
757
|
-
if (current
|
|
981
|
+
if (isFunctionNode(current)) {
|
|
758
982
|
return;
|
|
759
983
|
}
|
|
760
984
|
for (const key of Object.keys(current)) {
|
|
@@ -765,32 +989,111 @@ function containsThrow(node) {
|
|
|
765
989
|
if (Array.isArray(value)) {
|
|
766
990
|
for (const child of value) {
|
|
767
991
|
if (isNode(child)) {
|
|
768
|
-
|
|
992
|
+
recurse(child);
|
|
769
993
|
}
|
|
770
994
|
}
|
|
771
995
|
} else if (isNode(value)) {
|
|
772
|
-
|
|
996
|
+
recurse(value);
|
|
773
997
|
}
|
|
774
998
|
}
|
|
775
999
|
};
|
|
776
|
-
|
|
1000
|
+
recurse(node);
|
|
777
1001
|
return found;
|
|
778
1002
|
}
|
|
779
|
-
function
|
|
780
|
-
return
|
|
1003
|
+
function containsThrow(node) {
|
|
1004
|
+
return walkWithinScope(
|
|
1005
|
+
node,
|
|
1006
|
+
(current) => current.type === import_utils10.AST_NODE_TYPES.ThrowStatement
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
function argsIncludeBinding(args, caughtName) {
|
|
1010
|
+
if (caughtName === null) {
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
return args.some(
|
|
1014
|
+
(arg) => arg.type === import_utils10.AST_NODE_TYPES.Identifier && arg.name === caughtName
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
function logsOrReportsError(catchBody, caughtName) {
|
|
1018
|
+
return walkWithinScope(catchBody, (current) => {
|
|
1019
|
+
if (current.type !== import_utils10.AST_NODE_TYPES.CallExpression) {
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
if (isLoggingCall(current)) {
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
const name = calleeName(current.callee);
|
|
1026
|
+
return name !== null && REPORT_NAME_RE.test(name) && argsIncludeBinding(current.arguments, caughtName);
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
function tryBlockOf(catchNode) {
|
|
1030
|
+
return catchNode.parent.block;
|
|
1031
|
+
}
|
|
1032
|
+
function isSafeParseExpression(arg) {
|
|
1033
|
+
if (arg === null) {
|
|
1034
|
+
return false;
|
|
1035
|
+
}
|
|
1036
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.CallExpression && arg.callee.type === import_utils10.AST_NODE_TYPES.MemberExpression && !arg.callee.computed && arg.callee.property.type === import_utils10.AST_NODE_TYPES.Identifier && arg.callee.property.name === "parse") {
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
if (arg.type === import_utils10.AST_NODE_TYPES.NewExpression && arg.callee.type === import_utils10.AST_NODE_TYPES.Identifier) {
|
|
1040
|
+
return arg.callee.name === "RegExp" || arg.callee.name === "URL";
|
|
1041
|
+
}
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
function tryReturnsSafeParse(catchNode) {
|
|
1045
|
+
return walkWithinScope(
|
|
1046
|
+
tryBlockOf(catchNode),
|
|
1047
|
+
(current) => current.type === import_utils10.AST_NODE_TYPES.ReturnStatement && isSafeParseExpression(current.argument)
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
function enclosingFunctionBody(node) {
|
|
1051
|
+
let current = node.parent;
|
|
1052
|
+
while (current !== void 0 && current !== null) {
|
|
1053
|
+
if (isFunctionNode(current) && "body" in current && isNode(current.body) && current.body.type === import_utils10.AST_NODE_TYPES.BlockStatement) {
|
|
1054
|
+
return current.body;
|
|
1055
|
+
}
|
|
1056
|
+
current = current.parent;
|
|
1057
|
+
}
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
function functionReturnsSameSentinelKindElsewhere(catchNode, kind) {
|
|
1061
|
+
const functionBody = enclosingFunctionBody(catchNode);
|
|
1062
|
+
if (functionBody === null) {
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
return walkWithinScope(functionBody, (current) => {
|
|
1066
|
+
if (current.type !== import_utils10.AST_NODE_TYPES.ReturnStatement) {
|
|
1067
|
+
return false;
|
|
1068
|
+
}
|
|
1069
|
+
if (isWithin(current, catchNode.body)) {
|
|
1070
|
+
return false;
|
|
1071
|
+
}
|
|
1072
|
+
return sentinelKind(current.argument) === kind;
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
function isWithin(node, ancestor) {
|
|
1076
|
+
let current = node;
|
|
1077
|
+
while (current !== void 0 && current !== null) {
|
|
1078
|
+
if (current === ancestor) {
|
|
1079
|
+
return true;
|
|
1080
|
+
}
|
|
1081
|
+
current = current.parent;
|
|
1082
|
+
}
|
|
1083
|
+
return false;
|
|
781
1084
|
}
|
|
782
|
-
var no_sentinel_return_on_catch_default =
|
|
1085
|
+
var no_sentinel_return_on_catch_default = import_utils10.ESLintUtils.RuleCreator(
|
|
783
1086
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
784
1087
|
)({
|
|
785
1088
|
name: "no-sentinel-return-on-catch",
|
|
786
1089
|
meta: {
|
|
787
1090
|
type: "problem",
|
|
788
1091
|
docs: {
|
|
789
|
-
description: "Disallow swallowing a caught error by returning an empty sentinel (`null`, `undefined`, `false`, `[]`, `{}`) as the final statement of a `catch` block."
|
|
1092
|
+
description: "Disallow swallowing a caught error by returning an empty sentinel (`null`, `undefined`, `false`, `[]`, `{}`) as the final statement of a `catch` block, unless the error is logged/reported or the sentinel is the declared safe-parse/predicate contract."
|
|
790
1093
|
},
|
|
791
1094
|
schema: [],
|
|
792
1095
|
messages: {
|
|
793
|
-
noSentinelReturn: "This `catch` block swallows the error by returning an empty sentinel. Rethrow it,
|
|
1096
|
+
noSentinelReturn: "This `catch` block swallows the error by returning an empty sentinel without logging it. Rethrow it, log/report it, or return a typed Result."
|
|
794
1097
|
}
|
|
795
1098
|
},
|
|
796
1099
|
defaultOptions: [],
|
|
@@ -802,7 +1105,7 @@ var no_sentinel_return_on_catch_default = import_utils9.ESLintUtils.RuleCreator(
|
|
|
802
1105
|
return;
|
|
803
1106
|
}
|
|
804
1107
|
const last = body[body.length - 1];
|
|
805
|
-
if (last === void 0 || last.type !==
|
|
1108
|
+
if (last === void 0 || last.type !== import_utils10.AST_NODE_TYPES.ReturnStatement) {
|
|
806
1109
|
return;
|
|
807
1110
|
}
|
|
808
1111
|
if (!isSentinelArgument(last.argument)) {
|
|
@@ -811,6 +1114,17 @@ var no_sentinel_return_on_catch_default = import_utils9.ESLintUtils.RuleCreator(
|
|
|
811
1114
|
if (containsThrow(node.body)) {
|
|
812
1115
|
return;
|
|
813
1116
|
}
|
|
1117
|
+
const caughtName = node.param?.type === import_utils10.AST_NODE_TYPES.Identifier ? node.param.name : null;
|
|
1118
|
+
if (logsOrReportsError(node.body, caughtName)) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
if (tryReturnsSafeParse(node)) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
const kind = sentinelKind(last.argument);
|
|
1125
|
+
if (kind !== null && functionReturnsSameSentinelKindElsewhere(node, kind)) {
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
814
1128
|
context.report({
|
|
815
1129
|
node: last,
|
|
816
1130
|
messageId: "noSentinelReturn"
|
|
@@ -821,14 +1135,92 @@ var no_sentinel_return_on_catch_default = import_utils9.ESLintUtils.RuleCreator(
|
|
|
821
1135
|
});
|
|
822
1136
|
|
|
823
1137
|
// src/rules/no-sequential-await.ts
|
|
824
|
-
var
|
|
1138
|
+
var import_utils11 = require("@typescript-eslint/utils");
|
|
1139
|
+
var ARRAY_ITERATION_METHODS = /* @__PURE__ */ new Set(["forEach", "map", "filter"]);
|
|
1140
|
+
var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain/i;
|
|
825
1141
|
function isFunctionLike(node) {
|
|
826
1142
|
return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
827
1143
|
}
|
|
828
1144
|
function isLoop(node) {
|
|
829
1145
|
return node.type === "ForStatement" || node.type === "ForOfStatement" || node.type === "ForInStatement" || node.type === "WhileStatement" || node.type === "DoWhileStatement";
|
|
830
1146
|
}
|
|
831
|
-
|
|
1147
|
+
function isNode2(value) {
|
|
1148
|
+
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
1149
|
+
}
|
|
1150
|
+
function visitScope(root, visit) {
|
|
1151
|
+
visit(root);
|
|
1152
|
+
for (const key of Object.keys(root)) {
|
|
1153
|
+
if (key === "parent") {
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
const value = root[key];
|
|
1157
|
+
const children = Array.isArray(value) ? value : [value];
|
|
1158
|
+
for (const child of children) {
|
|
1159
|
+
if (isNode2(child) && !isFunctionLike(child) && !isLoop(child)) {
|
|
1160
|
+
visitScope(child, visit);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
function collectAwaits(root) {
|
|
1166
|
+
const awaits = [];
|
|
1167
|
+
visitScope(root, (node) => {
|
|
1168
|
+
if (node.type === "AwaitExpression") {
|
|
1169
|
+
awaits.push(node);
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
return awaits;
|
|
1173
|
+
}
|
|
1174
|
+
function hasEarlyExit(root) {
|
|
1175
|
+
let found = false;
|
|
1176
|
+
visitScope(root, (node) => {
|
|
1177
|
+
if (node.type === "ReturnStatement" || node.type === "BreakStatement" || node.type === "ContinueStatement") {
|
|
1178
|
+
found = true;
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
return found;
|
|
1182
|
+
}
|
|
1183
|
+
function isTimerYield(node) {
|
|
1184
|
+
const arg = node.argument;
|
|
1185
|
+
return arg.type === "NewExpression" && arg.callee.type === "Identifier" && arg.callee.name === "Promise";
|
|
1186
|
+
}
|
|
1187
|
+
function referencesName(root, name) {
|
|
1188
|
+
let found = false;
|
|
1189
|
+
visitScope(root, (node) => {
|
|
1190
|
+
if (node.type === "Identifier" && node.name === name) {
|
|
1191
|
+
found = true;
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
return found;
|
|
1195
|
+
}
|
|
1196
|
+
function isThreadedAccumulator(node) {
|
|
1197
|
+
const parent = node.parent;
|
|
1198
|
+
let target = null;
|
|
1199
|
+
if (parent.type === "AssignmentExpression" && parent.operator === "=" && parent.right === node && parent.left.type === "Identifier") {
|
|
1200
|
+
target = parent.left.name;
|
|
1201
|
+
} else if (parent.type === "VariableDeclarator" && parent.init === node && parent.id.type === "Identifier") {
|
|
1202
|
+
target = parent.id.name;
|
|
1203
|
+
}
|
|
1204
|
+
if (target === null) {
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
return referencesName(node.argument, target);
|
|
1208
|
+
}
|
|
1209
|
+
function shouldReport(awaits, earlyExit, iterableText) {
|
|
1210
|
+
if (awaits.length === 0) {
|
|
1211
|
+
return false;
|
|
1212
|
+
}
|
|
1213
|
+
if (earlyExit) {
|
|
1214
|
+
return false;
|
|
1215
|
+
}
|
|
1216
|
+
if (iterableText !== null && SEQUENTIAL_ITERABLE_HINT.test(iterableText)) {
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
return awaits.some(
|
|
1220
|
+
(node) => !isTimerYield(node) && !isThreadedAccumulator(node)
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
var no_sequential_await_default = import_utils11.ESLintUtils.RuleCreator(
|
|
832
1224
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
833
1225
|
)({
|
|
834
1226
|
name: "no-sequential-await",
|
|
@@ -844,54 +1236,36 @@ var no_sequential_await_default = import_utils10.ESLintUtils.RuleCreator(
|
|
|
844
1236
|
},
|
|
845
1237
|
defaultOptions: [],
|
|
846
1238
|
create(context) {
|
|
847
|
-
function
|
|
848
|
-
if (node.type === "
|
|
849
|
-
return node;
|
|
1239
|
+
function loopParts(node) {
|
|
1240
|
+
if (node.type === "ForStatement") {
|
|
1241
|
+
return [node.body, node.init, node.test, node.update];
|
|
850
1242
|
}
|
|
851
|
-
if (
|
|
852
|
-
return
|
|
1243
|
+
if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
|
|
1244
|
+
return [node.body, node.right];
|
|
853
1245
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
if (Array.isArray(value)) {
|
|
860
|
-
for (const child of value) {
|
|
861
|
-
if (isNode4(child) && !isLoop(child)) {
|
|
862
|
-
const found = findAwaitInScope(child);
|
|
863
|
-
if (found) {
|
|
864
|
-
return found;
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
} else if (isNode4(value) && !isLoop(value)) {
|
|
869
|
-
const found = findAwaitInScope(value);
|
|
870
|
-
if (found) {
|
|
871
|
-
return found;
|
|
872
|
-
}
|
|
873
|
-
}
|
|
1246
|
+
return [node.body, node.test];
|
|
1247
|
+
}
|
|
1248
|
+
function iterableTextOf(node) {
|
|
1249
|
+
if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
|
|
1250
|
+
return context.sourceCode.getText(node.right);
|
|
874
1251
|
}
|
|
875
1252
|
return null;
|
|
876
1253
|
}
|
|
877
|
-
function isNode4(value) {
|
|
878
|
-
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
879
|
-
}
|
|
880
1254
|
function checkLoop(node) {
|
|
881
|
-
const
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
if (part && !isLoop(part) && findAwaitInScope(part)) {
|
|
891
|
-
context.report({ node, messageId: "noSequentialAwait" });
|
|
892
|
-
return;
|
|
1255
|
+
const awaits = [];
|
|
1256
|
+
let earlyExit = false;
|
|
1257
|
+
for (const part of loopParts(node)) {
|
|
1258
|
+
if (part === null || isLoop(part)) {
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
awaits.push(...collectAwaits(part));
|
|
1262
|
+
if (!earlyExit && hasEarlyExit(part)) {
|
|
1263
|
+
earlyExit = true;
|
|
893
1264
|
}
|
|
894
1265
|
}
|
|
1266
|
+
if (shouldReport(awaits, earlyExit, iterableTextOf(node))) {
|
|
1267
|
+
context.report({ node, messageId: "noSequentialAwait" });
|
|
1268
|
+
}
|
|
895
1269
|
}
|
|
896
1270
|
return {
|
|
897
1271
|
ForStatement: checkLoop,
|
|
@@ -903,13 +1277,35 @@ var no_sequential_await_default = import_utils10.ESLintUtils.RuleCreator(
|
|
|
903
1277
|
return;
|
|
904
1278
|
}
|
|
905
1279
|
checkLoop(node);
|
|
1280
|
+
},
|
|
1281
|
+
CallExpression(node) {
|
|
1282
|
+
const callee = node.callee;
|
|
1283
|
+
if (callee.type !== "MemberExpression" || callee.computed) {
|
|
1284
|
+
return;
|
|
1285
|
+
}
|
|
1286
|
+
if (callee.property.type !== "Identifier" || !ARRAY_ITERATION_METHODS.has(callee.property.name)) {
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
const callback = node.arguments[0];
|
|
1290
|
+
if (callback === void 0 || !isFunctionLike(callback) || !("async" in callback && callback.async)) {
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
if (callee.property.name !== "forEach" && node.parent.type !== "ExpressionStatement") {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
const awaits = collectAwaits(callback.body);
|
|
1297
|
+
const earlyExit = hasEarlyExit(callback.body);
|
|
1298
|
+
const iterableText = context.sourceCode.getText(callee.object);
|
|
1299
|
+
if (shouldReport(awaits, earlyExit, iterableText)) {
|
|
1300
|
+
context.report({ node, messageId: "noSequentialAwait" });
|
|
1301
|
+
}
|
|
906
1302
|
}
|
|
907
1303
|
};
|
|
908
1304
|
}
|
|
909
1305
|
});
|
|
910
1306
|
|
|
911
1307
|
// src/rules/no-string-concat-in-loop.ts
|
|
912
|
-
var
|
|
1308
|
+
var import_utils12 = require("@typescript-eslint/utils");
|
|
913
1309
|
var LOOP_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
914
1310
|
"ForStatement",
|
|
915
1311
|
"ForOfStatement",
|
|
@@ -954,6 +1350,21 @@ function isStringInitializedVariable(variable) {
|
|
|
954
1350
|
}
|
|
955
1351
|
return isStringLiteralInit(declarator.init);
|
|
956
1352
|
}
|
|
1353
|
+
function isConcatOperand(node, target) {
|
|
1354
|
+
if (node.type === "Identifier") {
|
|
1355
|
+
return node.name === target;
|
|
1356
|
+
}
|
|
1357
|
+
if (node.type === "BinaryExpression" && node.operator === "+") {
|
|
1358
|
+
return isConcatOperand(node.left, target) || isConcatOperand(node.right, target);
|
|
1359
|
+
}
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
function isConcatOntoTarget(rhs, target) {
|
|
1363
|
+
if (rhs.type !== "BinaryExpression" || rhs.operator !== "+") {
|
|
1364
|
+
return false;
|
|
1365
|
+
}
|
|
1366
|
+
return isConcatOperand(rhs.left, target) || isConcatOperand(rhs.right, target);
|
|
1367
|
+
}
|
|
957
1368
|
function isInsideLoopBody(node) {
|
|
958
1369
|
let child = node;
|
|
959
1370
|
let parent = node.parent;
|
|
@@ -969,7 +1380,7 @@ function isInsideLoopBody(node) {
|
|
|
969
1380
|
}
|
|
970
1381
|
return false;
|
|
971
1382
|
}
|
|
972
|
-
var no_string_concat_in_loop_default =
|
|
1383
|
+
var no_string_concat_in_loop_default = import_utils12.ESLintUtils.RuleCreator(
|
|
973
1384
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
974
1385
|
)({
|
|
975
1386
|
name: "no-string-concat-in-loop",
|
|
@@ -987,10 +1398,11 @@ var no_string_concat_in_loop_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
987
1398
|
create(context) {
|
|
988
1399
|
return {
|
|
989
1400
|
AssignmentExpression(node) {
|
|
990
|
-
if (node.
|
|
1401
|
+
if (node.left.type !== "Identifier") {
|
|
991
1402
|
return;
|
|
992
1403
|
}
|
|
993
|
-
|
|
1404
|
+
const isAccumulation = node.operator === "+=" || node.operator === "=" && isConcatOntoTarget(node.right, node.left.name);
|
|
1405
|
+
if (!isAccumulation) {
|
|
994
1406
|
return;
|
|
995
1407
|
}
|
|
996
1408
|
if (!isInsideLoopBody(node)) {
|
|
@@ -1014,7 +1426,7 @@ var no_string_concat_in_loop_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
1014
1426
|
});
|
|
1015
1427
|
|
|
1016
1428
|
// src/rules/no-unnecessary-use-client.ts
|
|
1017
|
-
var
|
|
1429
|
+
var import_utils13 = require("@typescript-eslint/utils");
|
|
1018
1430
|
var HOOK_REGEX = /^use([A-Z]|$)/;
|
|
1019
1431
|
var EVENT_PROP_REGEX = /^on[A-Z]/;
|
|
1020
1432
|
var ERROR_FILE_REGEX = /\b(?:global-)?error\.[jt]sx?$/;
|
|
@@ -1037,16 +1449,16 @@ var BROWSER_GLOBALS = /* @__PURE__ */ new Set([
|
|
|
1037
1449
|
]);
|
|
1038
1450
|
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\/)/;
|
|
1039
1451
|
var isUseClientDirective = (node) => {
|
|
1040
|
-
return node.type ===
|
|
1452
|
+
return node.type === import_utils13.AST_NODE_TYPES.ExpressionStatement && node.expression.type === import_utils13.AST_NODE_TYPES.Literal && node.expression.value === "use client";
|
|
1041
1453
|
};
|
|
1042
1454
|
var isGlobalReference = (node, context) => {
|
|
1043
1455
|
if (!BROWSER_GLOBALS.has(node.name)) return false;
|
|
1044
1456
|
const parent = node.parent;
|
|
1045
1457
|
if (parent !== void 0) {
|
|
1046
|
-
if (parent.type ===
|
|
1458
|
+
if (parent.type === import_utils13.AST_NODE_TYPES.MemberExpression && parent.property === node && !parent.computed) {
|
|
1047
1459
|
return false;
|
|
1048
1460
|
}
|
|
1049
|
-
if (parent.type ===
|
|
1461
|
+
if (parent.type === import_utils13.AST_NODE_TYPES.Property && parent.key === node && !parent.computed) {
|
|
1050
1462
|
return false;
|
|
1051
1463
|
}
|
|
1052
1464
|
if (parent.type.startsWith("TS")) {
|
|
@@ -1063,7 +1475,7 @@ var isGlobalReference = (node, context) => {
|
|
|
1063
1475
|
}
|
|
1064
1476
|
return true;
|
|
1065
1477
|
};
|
|
1066
|
-
var no_unnecessary_use_client_default =
|
|
1478
|
+
var no_unnecessary_use_client_default = import_utils13.ESLintUtils.RuleCreator(
|
|
1067
1479
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1068
1480
|
)({
|
|
1069
1481
|
name: "no-unnecessary-use-client",
|
|
@@ -1086,13 +1498,13 @@ var no_unnecessary_use_client_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1086
1498
|
let directiveNode = null;
|
|
1087
1499
|
let hasClientIndicator = false;
|
|
1088
1500
|
const markIfHookOrContext = (callee) => {
|
|
1089
|
-
if (callee.type ===
|
|
1501
|
+
if (callee.type === import_utils13.AST_NODE_TYPES.Identifier) {
|
|
1090
1502
|
if (HOOK_REGEX.test(callee.name) || callee.name === "createContext") {
|
|
1091
1503
|
hasClientIndicator = true;
|
|
1092
1504
|
}
|
|
1093
1505
|
return;
|
|
1094
1506
|
}
|
|
1095
|
-
if (callee.type ===
|
|
1507
|
+
if (callee.type === import_utils13.AST_NODE_TYPES.MemberExpression && callee.property.type === import_utils13.AST_NODE_TYPES.Identifier) {
|
|
1096
1508
|
const name = callee.property.name;
|
|
1097
1509
|
if (HOOK_REGEX.test(name) || name === "createContext") {
|
|
1098
1510
|
hasClientIndicator = true;
|
|
@@ -1102,7 +1514,7 @@ var no_unnecessary_use_client_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1102
1514
|
return {
|
|
1103
1515
|
Program(node) {
|
|
1104
1516
|
for (const stmt of node.body) {
|
|
1105
|
-
if (stmt.type !==
|
|
1517
|
+
if (stmt.type !== import_utils13.AST_NODE_TYPES.ExpressionStatement) break;
|
|
1106
1518
|
if (isUseClientDirective(stmt)) {
|
|
1107
1519
|
directiveNode = stmt;
|
|
1108
1520
|
break;
|
|
@@ -1115,7 +1527,7 @@ var no_unnecessary_use_client_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1115
1527
|
},
|
|
1116
1528
|
JSXAttribute(node) {
|
|
1117
1529
|
if (directiveNode === null) return;
|
|
1118
|
-
if (node.name.type ===
|
|
1530
|
+
if (node.name.type === import_utils13.AST_NODE_TYPES.JSXIdentifier && EVENT_PROP_REGEX.test(node.name.name)) {
|
|
1119
1531
|
hasClientIndicator = true;
|
|
1120
1532
|
}
|
|
1121
1533
|
},
|
|
@@ -1164,8 +1576,8 @@ var no_unnecessary_use_client_default = import_utils12.ESLintUtils.RuleCreator(
|
|
|
1164
1576
|
});
|
|
1165
1577
|
|
|
1166
1578
|
// src/rules/prefer-discriminated-union.ts
|
|
1167
|
-
var import_utils13 = require("@typescript-eslint/utils");
|
|
1168
1579
|
var import_utils14 = require("@typescript-eslint/utils");
|
|
1580
|
+
var import_utils15 = require("@typescript-eslint/utils");
|
|
1169
1581
|
var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
1170
1582
|
"success",
|
|
1171
1583
|
"ok",
|
|
@@ -1175,26 +1587,26 @@ var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
|
1175
1587
|
]);
|
|
1176
1588
|
var MIN_OPTIONAL_MEMBERS = 2;
|
|
1177
1589
|
function getMemberName(member) {
|
|
1178
|
-
if (member.type !==
|
|
1590
|
+
if (member.type !== import_utils15.AST_NODE_TYPES.TSPropertySignature) {
|
|
1179
1591
|
return null;
|
|
1180
1592
|
}
|
|
1181
1593
|
const { key } = member;
|
|
1182
|
-
if (key.type ===
|
|
1594
|
+
if (key.type === import_utils15.AST_NODE_TYPES.Identifier) {
|
|
1183
1595
|
return key.name;
|
|
1184
1596
|
}
|
|
1185
|
-
if (key.type ===
|
|
1597
|
+
if (key.type === import_utils15.AST_NODE_TYPES.Literal && typeof key.value === "string") {
|
|
1186
1598
|
return key.value;
|
|
1187
1599
|
}
|
|
1188
1600
|
return null;
|
|
1189
1601
|
}
|
|
1190
1602
|
function isBooleanTyped(member) {
|
|
1191
|
-
return member.typeAnnotation?.typeAnnotation.type ===
|
|
1603
|
+
return member.typeAnnotation?.typeAnnotation.type === import_utils15.AST_NODE_TYPES.TSBooleanKeyword;
|
|
1192
1604
|
}
|
|
1193
1605
|
function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
1194
1606
|
let hasStatusBoolean = false;
|
|
1195
1607
|
let optionalCount = 0;
|
|
1196
1608
|
for (const member of typeLiteral.members) {
|
|
1197
|
-
if (member.type !==
|
|
1609
|
+
if (member.type !== import_utils15.AST_NODE_TYPES.TSPropertySignature) {
|
|
1198
1610
|
continue;
|
|
1199
1611
|
}
|
|
1200
1612
|
if (member.optional) {
|
|
@@ -1207,7 +1619,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
|
1207
1619
|
}
|
|
1208
1620
|
return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS;
|
|
1209
1621
|
}
|
|
1210
|
-
var prefer_discriminated_union_default =
|
|
1622
|
+
var prefer_discriminated_union_default = import_utils14.ESLintUtils.RuleCreator(
|
|
1211
1623
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1212
1624
|
)({
|
|
1213
1625
|
name: "prefer-discriminated-union",
|
|
@@ -1235,7 +1647,7 @@ var prefer_discriminated_union_default = import_utils13.ESLintUtils.RuleCreator(
|
|
|
1235
1647
|
TSInterfaceDeclaration(node) {
|
|
1236
1648
|
const synthetic = {
|
|
1237
1649
|
...node.body,
|
|
1238
|
-
type:
|
|
1650
|
+
type: import_utils15.AST_NODE_TYPES.TSTypeLiteral,
|
|
1239
1651
|
members: node.body.body
|
|
1240
1652
|
};
|
|
1241
1653
|
checkTypeLiteral(synthetic, node);
|
|
@@ -1248,13 +1660,13 @@ var prefer_discriminated_union_default = import_utils13.ESLintUtils.RuleCreator(
|
|
|
1248
1660
|
});
|
|
1249
1661
|
|
|
1250
1662
|
// src/rules/prefer-schema-for-api-payload.ts
|
|
1251
|
-
var
|
|
1663
|
+
var import_utils16 = require("@typescript-eslint/utils");
|
|
1252
1664
|
var unwrap = (node) => {
|
|
1253
1665
|
let current = node;
|
|
1254
1666
|
while (current !== null && current !== void 0) {
|
|
1255
|
-
if (current.type ===
|
|
1667
|
+
if (current.type === import_utils16.AST_NODE_TYPES.TSAsExpression || current.type === import_utils16.AST_NODE_TYPES.TSTypeAssertion || current.type === import_utils16.AST_NODE_TYPES.TSNonNullExpression || current.type === import_utils16.AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
1256
1668
|
current = current.expression;
|
|
1257
|
-
} else if (current.type ===
|
|
1669
|
+
} else if (current.type === import_utils16.AST_NODE_TYPES.ChainExpression) {
|
|
1258
1670
|
current = current.expression;
|
|
1259
1671
|
} else {
|
|
1260
1672
|
break;
|
|
@@ -1265,18 +1677,18 @@ var unwrap = (node) => {
|
|
|
1265
1677
|
var isJsonCall = (node) => {
|
|
1266
1678
|
let current = unwrap(node);
|
|
1267
1679
|
if (current === null) return false;
|
|
1268
|
-
if (current.type ===
|
|
1680
|
+
if (current.type === import_utils16.AST_NODE_TYPES.AwaitExpression) {
|
|
1269
1681
|
current = unwrap(current.argument);
|
|
1270
1682
|
}
|
|
1271
|
-
if (current === null || current.type !==
|
|
1683
|
+
if (current === null || current.type !== import_utils16.AST_NODE_TYPES.CallExpression) {
|
|
1272
1684
|
return false;
|
|
1273
1685
|
}
|
|
1274
1686
|
const callee = unwrap(current.callee);
|
|
1275
|
-
if (callee === null || callee.type !==
|
|
1687
|
+
if (callee === null || callee.type !== import_utils16.AST_NODE_TYPES.MemberExpression) {
|
|
1276
1688
|
return false;
|
|
1277
1689
|
}
|
|
1278
1690
|
const property = unwrap(callee.property);
|
|
1279
|
-
return property !== null && property.type ===
|
|
1691
|
+
return property !== null && property.type === import_utils16.AST_NODE_TYPES.Identifier && property.name === "json";
|
|
1280
1692
|
};
|
|
1281
1693
|
var findVariable2 = (scope, name) => {
|
|
1282
1694
|
let current = scope;
|
|
@@ -1287,15 +1699,39 @@ var findVariable2 = (scope, name) => {
|
|
|
1287
1699
|
}
|
|
1288
1700
|
return null;
|
|
1289
1701
|
};
|
|
1702
|
+
var GUARD_NAME_RE = /^is[A-Z]/;
|
|
1703
|
+
var isGuardTestPosition = (node) => {
|
|
1704
|
+
let current = node;
|
|
1705
|
+
let parent = current.parent;
|
|
1706
|
+
while (parent !== void 0 && parent !== null) {
|
|
1707
|
+
switch (parent.type) {
|
|
1708
|
+
case import_utils16.AST_NODE_TYPES.UnaryExpression:
|
|
1709
|
+
case import_utils16.AST_NODE_TYPES.LogicalExpression:
|
|
1710
|
+
case import_utils16.AST_NODE_TYPES.ChainExpression:
|
|
1711
|
+
current = parent;
|
|
1712
|
+
parent = parent.parent;
|
|
1713
|
+
continue;
|
|
1714
|
+
case import_utils16.AST_NODE_TYPES.IfStatement:
|
|
1715
|
+
case import_utils16.AST_NODE_TYPES.ConditionalExpression:
|
|
1716
|
+
case import_utils16.AST_NODE_TYPES.WhileStatement:
|
|
1717
|
+
case import_utils16.AST_NODE_TYPES.DoWhileStatement:
|
|
1718
|
+
case import_utils16.AST_NODE_TYPES.ForStatement:
|
|
1719
|
+
return parent.test === current;
|
|
1720
|
+
default:
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
return false;
|
|
1725
|
+
};
|
|
1290
1726
|
var isUnvalidatedVariableRef = (node, scope, tracked) => {
|
|
1291
1727
|
const unwrapped = unwrap(node);
|
|
1292
|
-
if (unwrapped === null || unwrapped.type !==
|
|
1728
|
+
if (unwrapped === null || unwrapped.type !== import_utils16.AST_NODE_TYPES.Identifier) {
|
|
1293
1729
|
return false;
|
|
1294
1730
|
}
|
|
1295
1731
|
const variable = findVariable2(scope, unwrapped.name);
|
|
1296
1732
|
return variable !== null && tracked.has(variable);
|
|
1297
1733
|
};
|
|
1298
|
-
var prefer_schema_for_api_payload_default =
|
|
1734
|
+
var prefer_schema_for_api_payload_default = import_utils16.ESLintUtils.RuleCreator(
|
|
1299
1735
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1300
1736
|
)({
|
|
1301
1737
|
name: "prefer-schema-for-api-payload",
|
|
@@ -1323,11 +1759,11 @@ var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreat
|
|
|
1323
1759
|
return {
|
|
1324
1760
|
VariableDeclarator(node) {
|
|
1325
1761
|
const scope = context.sourceCode.getScope(node);
|
|
1326
|
-
if (node.id.type ===
|
|
1762
|
+
if (node.id.type === import_utils16.AST_NODE_TYPES.Identifier) {
|
|
1327
1763
|
trackInitializer(node);
|
|
1328
1764
|
return;
|
|
1329
1765
|
}
|
|
1330
|
-
if (node.id.type ===
|
|
1766
|
+
if (node.id.type === import_utils16.AST_NODE_TYPES.ObjectPattern || node.id.type === import_utils16.AST_NODE_TYPES.ArrayPattern) {
|
|
1331
1767
|
if (isJsonCall(node.init)) {
|
|
1332
1768
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
1333
1769
|
return;
|
|
@@ -1339,7 +1775,7 @@ var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreat
|
|
|
1339
1775
|
},
|
|
1340
1776
|
AssignmentExpression(node) {
|
|
1341
1777
|
const scope = context.sourceCode.getScope(node);
|
|
1342
|
-
if (node.left.type ===
|
|
1778
|
+
if (node.left.type === import_utils16.AST_NODE_TYPES.Identifier) {
|
|
1343
1779
|
const variable = findVariable2(scope, node.left.name);
|
|
1344
1780
|
if (variable === null) return;
|
|
1345
1781
|
if (isJsonCall(node.right)) {
|
|
@@ -1349,7 +1785,7 @@ var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreat
|
|
|
1349
1785
|
}
|
|
1350
1786
|
return;
|
|
1351
1787
|
}
|
|
1352
|
-
if (node.left.type ===
|
|
1788
|
+
if (node.left.type === import_utils16.AST_NODE_TYPES.ObjectPattern || node.left.type === import_utils16.AST_NODE_TYPES.ArrayPattern) {
|
|
1353
1789
|
if (isJsonCall(node.right)) {
|
|
1354
1790
|
context.report({
|
|
1355
1791
|
node: node.left,
|
|
@@ -1365,18 +1801,34 @@ var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreat
|
|
|
1365
1801
|
}
|
|
1366
1802
|
}
|
|
1367
1803
|
},
|
|
1804
|
+
CallExpression(node) {
|
|
1805
|
+
if (node.callee.type !== import_utils16.AST_NODE_TYPES.Identifier) return;
|
|
1806
|
+
if (!GUARD_NAME_RE.test(node.callee.name) && !isGuardTestPosition(node)) {
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
const scope = context.sourceCode.getScope(node);
|
|
1810
|
+
for (const arg of node.arguments) {
|
|
1811
|
+
if (arg.type === import_utils16.AST_NODE_TYPES.SpreadElement) continue;
|
|
1812
|
+
const unwrapped = unwrap(arg);
|
|
1813
|
+
if (unwrapped === null || unwrapped.type !== import_utils16.AST_NODE_TYPES.Identifier) {
|
|
1814
|
+
continue;
|
|
1815
|
+
}
|
|
1816
|
+
const variable = findVariable2(scope, unwrapped.name);
|
|
1817
|
+
if (variable !== null) unvalidatedVariables.delete(variable);
|
|
1818
|
+
}
|
|
1819
|
+
},
|
|
1368
1820
|
MemberExpression(node) {
|
|
1369
1821
|
const scope = context.sourceCode.getScope(node);
|
|
1370
1822
|
const obj = unwrap(node.object);
|
|
1371
1823
|
if (isJsonCall(obj)) {
|
|
1372
1824
|
const parent = node.parent;
|
|
1373
|
-
if (parent.type ===
|
|
1825
|
+
if (parent.type === import_utils16.AST_NODE_TYPES.CallExpression && parent.callee === node && node.property.type === import_utils16.AST_NODE_TYPES.Identifier && (node.property.name === "parse" || node.property.name === "safeParse")) {
|
|
1374
1826
|
return;
|
|
1375
1827
|
}
|
|
1376
1828
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
1377
1829
|
return;
|
|
1378
1830
|
}
|
|
1379
|
-
if (obj !== null && obj.type ===
|
|
1831
|
+
if (obj !== null && obj.type === import_utils16.AST_NODE_TYPES.Identifier && isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)) {
|
|
1380
1832
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
1381
1833
|
const variable = findVariable2(scope, obj.name);
|
|
1382
1834
|
if (variable !== null) {
|
|
@@ -1389,7 +1841,7 @@ var prefer_schema_for_api_payload_default = import_utils15.ESLintUtils.RuleCreat
|
|
|
1389
1841
|
});
|
|
1390
1842
|
|
|
1391
1843
|
// src/rules/prefer-semantic-colors.ts
|
|
1392
|
-
var
|
|
1844
|
+
var import_utils17 = require("@typescript-eslint/utils");
|
|
1393
1845
|
|
|
1394
1846
|
// src/rules/_tailwind.ts
|
|
1395
1847
|
var tailwindBase = (token) => token.replace(/^(?:[a-z0-9-]+:)+/i, "").replace(/^!/, "");
|
|
@@ -1426,12 +1878,41 @@ var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
|
|
|
1426
1878
|
"lightingColor"
|
|
1427
1879
|
]);
|
|
1428
1880
|
var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
|
|
1881
|
+
var STORIES_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
|
|
1882
|
+
var SVG_DEFS_CONTAINERS = /* @__PURE__ */ new Set([
|
|
1883
|
+
"mask",
|
|
1884
|
+
"clipPath",
|
|
1885
|
+
"defs",
|
|
1886
|
+
"pattern",
|
|
1887
|
+
"linearGradient",
|
|
1888
|
+
"radialGradient"
|
|
1889
|
+
]);
|
|
1890
|
+
var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
|
|
1891
|
+
"#fff",
|
|
1892
|
+
"#ffffff",
|
|
1893
|
+
"#000",
|
|
1894
|
+
"#000000",
|
|
1895
|
+
"transparent",
|
|
1896
|
+
"none",
|
|
1897
|
+
"currentcolor",
|
|
1898
|
+
"inherit"
|
|
1899
|
+
]);
|
|
1900
|
+
var isInsideSvgDefsContainer = (node) => {
|
|
1901
|
+
let current = node.parent;
|
|
1902
|
+
while (current !== void 0 && current !== null) {
|
|
1903
|
+
if (current.type === import_utils17.AST_NODE_TYPES.JSXElement && current.openingElement.name.type === import_utils17.AST_NODE_TYPES.JSXIdentifier && SVG_DEFS_CONTAINERS.has(current.openingElement.name.name)) {
|
|
1904
|
+
return true;
|
|
1905
|
+
}
|
|
1906
|
+
current = current.parent;
|
|
1907
|
+
}
|
|
1908
|
+
return false;
|
|
1909
|
+
};
|
|
1429
1910
|
var propName = (key) => {
|
|
1430
|
-
if (key.type ===
|
|
1431
|
-
if (key.type ===
|
|
1911
|
+
if (key.type === import_utils17.AST_NODE_TYPES.Identifier) return key.name;
|
|
1912
|
+
if (key.type === import_utils17.AST_NODE_TYPES.Literal && typeof key.value === "string") return key.value;
|
|
1432
1913
|
return null;
|
|
1433
1914
|
};
|
|
1434
|
-
var prefer_semantic_colors_default =
|
|
1915
|
+
var prefer_semantic_colors_default = import_utils17.ESLintUtils.RuleCreator(
|
|
1435
1916
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1436
1917
|
)({
|
|
1437
1918
|
name: "prefer-semantic-colors",
|
|
@@ -1449,6 +1930,7 @@ var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1449
1930
|
},
|
|
1450
1931
|
defaultOptions: [],
|
|
1451
1932
|
create(context) {
|
|
1933
|
+
if (STORIES_FILE_RE.test(context.filename)) return {};
|
|
1452
1934
|
const reportClasses = (value, node) => {
|
|
1453
1935
|
for (const token of classTokens(value)) {
|
|
1454
1936
|
const base = tailwindBase(token);
|
|
@@ -1462,27 +1944,27 @@ var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1462
1944
|
const checkClassNode = (node) => {
|
|
1463
1945
|
if (node === null) return;
|
|
1464
1946
|
switch (node.type) {
|
|
1465
|
-
case
|
|
1947
|
+
case import_utils17.AST_NODE_TYPES.Literal:
|
|
1466
1948
|
if (typeof node.value === "string") reportClasses(node.value, node);
|
|
1467
1949
|
break;
|
|
1468
|
-
case
|
|
1950
|
+
case import_utils17.AST_NODE_TYPES.TemplateLiteral:
|
|
1469
1951
|
for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? "", quasi);
|
|
1470
1952
|
break;
|
|
1471
|
-
case
|
|
1953
|
+
case import_utils17.AST_NODE_TYPES.ArrayExpression:
|
|
1472
1954
|
for (const element of node.elements) {
|
|
1473
|
-
if (element !== null && element.type !==
|
|
1955
|
+
if (element !== null && element.type !== import_utils17.AST_NODE_TYPES.SpreadElement) checkClassNode(element);
|
|
1474
1956
|
}
|
|
1475
1957
|
break;
|
|
1476
|
-
case
|
|
1958
|
+
case import_utils17.AST_NODE_TYPES.ObjectExpression:
|
|
1477
1959
|
for (const property of node.properties) {
|
|
1478
|
-
if (property.type ===
|
|
1960
|
+
if (property.type === import_utils17.AST_NODE_TYPES.Property) checkClassNode(property.value);
|
|
1479
1961
|
}
|
|
1480
1962
|
break;
|
|
1481
|
-
case
|
|
1963
|
+
case import_utils17.AST_NODE_TYPES.ConditionalExpression:
|
|
1482
1964
|
checkClassNode(node.consequent);
|
|
1483
1965
|
checkClassNode(node.alternate);
|
|
1484
1966
|
break;
|
|
1485
|
-
case
|
|
1967
|
+
case import_utils17.AST_NODE_TYPES.LogicalExpression:
|
|
1486
1968
|
checkClassNode(node.right);
|
|
1487
1969
|
break;
|
|
1488
1970
|
default:
|
|
@@ -1490,29 +1972,29 @@ var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1490
1972
|
}
|
|
1491
1973
|
};
|
|
1492
1974
|
const checkColorValueNode = (node) => {
|
|
1493
|
-
if (node.type ===
|
|
1975
|
+
if (node.type === import_utils17.AST_NODE_TYPES.Literal && typeof node.value === "string" && RAW_COLOR_VALUE_RE.test(node.value)) {
|
|
1494
1976
|
context.report({ node, messageId: "inlineColor", data: { value: node.value } });
|
|
1495
1977
|
}
|
|
1496
1978
|
};
|
|
1497
1979
|
return {
|
|
1498
1980
|
"JSXAttribute[name.name='className']"(node) {
|
|
1499
1981
|
if (node.value === null) return;
|
|
1500
|
-
if (node.value.type ===
|
|
1501
|
-
else if (node.value.type ===
|
|
1502
|
-
if (node.value.expression.type !==
|
|
1982
|
+
if (node.value.type === import_utils17.AST_NODE_TYPES.Literal) checkClassNode(node.value);
|
|
1983
|
+
else if (node.value.type === import_utils17.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
1984
|
+
if (node.value.expression.type !== import_utils17.AST_NODE_TYPES.JSXEmptyExpression) {
|
|
1503
1985
|
checkClassNode(node.value.expression);
|
|
1504
1986
|
}
|
|
1505
1987
|
}
|
|
1506
1988
|
},
|
|
1507
1989
|
CallExpression(node) {
|
|
1508
|
-
if (node.callee.type ===
|
|
1990
|
+
if (node.callee.type === import_utils17.AST_NODE_TYPES.Identifier && CLASS_FNS.has(node.callee.name)) {
|
|
1509
1991
|
for (const arg of node.arguments) {
|
|
1510
|
-
if (arg.type !==
|
|
1992
|
+
if (arg.type !== import_utils17.AST_NODE_TYPES.SpreadElement) checkClassNode(arg);
|
|
1511
1993
|
}
|
|
1512
1994
|
}
|
|
1513
1995
|
},
|
|
1514
1996
|
VariableDeclarator(node) {
|
|
1515
|
-
if (node.id.type ===
|
|
1997
|
+
if (node.id.type === import_utils17.AST_NODE_TYPES.Identifier && CLASS_NAME_RE.test(node.id.name)) {
|
|
1516
1998
|
checkClassNode(node.init);
|
|
1517
1999
|
}
|
|
1518
2000
|
},
|
|
@@ -1520,9 +2002,16 @@ var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1520
2002
|
const name = propName(node.key);
|
|
1521
2003
|
if (name !== null && CLASS_NAME_RE.test(name)) checkClassNode(node.value);
|
|
1522
2004
|
},
|
|
1523
|
-
// SVG presentation attributes: <path fill="#
|
|
2005
|
+
// SVG presentation attributes: <path fill="#7c3aed" stroke="#7c3aed" />.
|
|
2006
|
+
// Neutral drawing literals and anything inside an SVG defs container are
|
|
2007
|
+
// structural, not UI tokens, so they never fire.
|
|
1524
2008
|
"JSXAttribute[name.name=/^(fill|stroke|color)$/]"(node) {
|
|
1525
|
-
if (node.value?.type
|
|
2009
|
+
if (node.value?.type !== import_utils17.AST_NODE_TYPES.Literal) return;
|
|
2010
|
+
if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
if (isInsideSvgDefsContainer(node)) return;
|
|
2014
|
+
checkColorValueNode(node.value);
|
|
1526
2015
|
},
|
|
1527
2016
|
// Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
|
|
1528
2017
|
"JSXAttribute[name.name='style'] ObjectExpression > Property"(node) {
|
|
@@ -1534,7 +2023,7 @@ var prefer_semantic_colors_default = import_utils16.ESLintUtils.RuleCreator(
|
|
|
1534
2023
|
});
|
|
1535
2024
|
|
|
1536
2025
|
// src/rules/prefer-server-actions.ts
|
|
1537
|
-
var
|
|
2026
|
+
var import_utils18 = require("@typescript-eslint/utils");
|
|
1538
2027
|
var MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "DELETE", "PATCH"]);
|
|
1539
2028
|
var AXIOS_MUTATION_METHODS = /* @__PURE__ */ new Set(["post", "put", "delete", "patch"]);
|
|
1540
2029
|
var SKIP_FILE_REGEX = /(?:\.test\.[jt]sx?$|\.spec\.[jt]sx?$|\/tests?\/|\/__tests__\/|\/scripts?\/|\/app\/api\/.*\/route\.[jt]sx?$|\/pages\/api\/)/;
|
|
@@ -1613,7 +2102,7 @@ function getPropertyNode(objNode, propName2) {
|
|
|
1613
2102
|
}
|
|
1614
2103
|
return null;
|
|
1615
2104
|
}
|
|
1616
|
-
var prefer_server_actions_default =
|
|
2105
|
+
var prefer_server_actions_default = import_utils18.ESLintUtils.RuleCreator(
|
|
1617
2106
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1618
2107
|
)({
|
|
1619
2108
|
name: "prefer-server-actions",
|
|
@@ -1681,14 +2170,38 @@ var prefer_server_actions_default = import_utils17.ESLintUtils.RuleCreator(
|
|
|
1681
2170
|
});
|
|
1682
2171
|
|
|
1683
2172
|
// src/rules/prefer-shadcn.ts
|
|
1684
|
-
var
|
|
2173
|
+
var import_utils19 = require("@typescript-eslint/utils");
|
|
1685
2174
|
var REPLACEMENTS = {
|
|
1686
|
-
input: "Input",
|
|
1687
2175
|
select: "Select",
|
|
1688
2176
|
textarea: "Textarea",
|
|
1689
2177
|
dialog: "Dialog"
|
|
1690
2178
|
};
|
|
1691
|
-
var
|
|
2179
|
+
var INPUT_TYPE_REPLACEMENTS = {
|
|
2180
|
+
checkbox: "Checkbox",
|
|
2181
|
+
radio: "RadioGroup",
|
|
2182
|
+
range: "Slider"
|
|
2183
|
+
};
|
|
2184
|
+
var SKIPPED_INPUT_TYPES = /* @__PURE__ */ new Set(["hidden"]);
|
|
2185
|
+
var kebabCase = (component) => component.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
2186
|
+
var literalTypeAttr = (node) => {
|
|
2187
|
+
for (const attribute of node.attributes) {
|
|
2188
|
+
if (attribute.type !== import_utils19.AST_NODE_TYPES.JSXAttribute || attribute.name.type !== import_utils19.AST_NODE_TYPES.JSXIdentifier || attribute.name.name !== "type") {
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
if (attribute.value?.type === import_utils19.AST_NODE_TYPES.Literal && typeof attribute.value.value === "string") {
|
|
2192
|
+
return { kind: "literal", value: attribute.value.value.toLowerCase() };
|
|
2193
|
+
}
|
|
2194
|
+
return { kind: "dynamic" };
|
|
2195
|
+
}
|
|
2196
|
+
return null;
|
|
2197
|
+
};
|
|
2198
|
+
var resolveInputReplacement = (node) => {
|
|
2199
|
+
const typeAttr = literalTypeAttr(node);
|
|
2200
|
+
if (typeAttr === null || typeAttr.kind === "dynamic") return "Input";
|
|
2201
|
+
if (SKIPPED_INPUT_TYPES.has(typeAttr.value)) return null;
|
|
2202
|
+
return INPUT_TYPE_REPLACEMENTS[typeAttr.value] ?? "Input";
|
|
2203
|
+
};
|
|
2204
|
+
var prefer_shadcn_default = import_utils19.ESLintUtils.RuleCreator(
|
|
1692
2205
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1693
2206
|
)({
|
|
1694
2207
|
name: "prefer-shadcn",
|
|
@@ -1710,8 +2223,8 @@ var prefer_shadcn_default = import_utils18.ESLintUtils.RuleCreator(
|
|
|
1710
2223
|
return;
|
|
1711
2224
|
}
|
|
1712
2225
|
const elementName = node.name.name;
|
|
1713
|
-
const replacement = REPLACEMENTS[elementName];
|
|
1714
|
-
if (replacement === void 0) {
|
|
2226
|
+
const replacement = elementName === "input" ? resolveInputReplacement(node) : REPLACEMENTS[elementName];
|
|
2227
|
+
if (replacement === void 0 || replacement === null) {
|
|
1715
2228
|
return;
|
|
1716
2229
|
}
|
|
1717
2230
|
context.report({
|
|
@@ -1720,7 +2233,7 @@ var prefer_shadcn_default = import_utils18.ESLintUtils.RuleCreator(
|
|
|
1720
2233
|
data: {
|
|
1721
2234
|
element: elementName,
|
|
1722
2235
|
replacement,
|
|
1723
|
-
lowercase:
|
|
2236
|
+
lowercase: kebabCase(replacement)
|
|
1724
2237
|
}
|
|
1725
2238
|
});
|
|
1726
2239
|
}
|
|
@@ -1729,41 +2242,57 @@ var prefer_shadcn_default = import_utils18.ESLintUtils.RuleCreator(
|
|
|
1729
2242
|
});
|
|
1730
2243
|
|
|
1731
2244
|
// src/rules/require-assert-never.ts
|
|
1732
|
-
var
|
|
2245
|
+
var import_utils20 = require("@typescript-eslint/utils");
|
|
1733
2246
|
var isAssertNeverCall = (expression) => {
|
|
1734
|
-
if (expression.type !==
|
|
2247
|
+
if (expression.type !== import_utils20.AST_NODE_TYPES.CallExpression) return false;
|
|
1735
2248
|
const callee = expression.callee;
|
|
1736
|
-
if (callee.type ===
|
|
2249
|
+
if (callee.type === import_utils20.AST_NODE_TYPES.Identifier) {
|
|
1737
2250
|
return callee.name === "assertNever";
|
|
1738
2251
|
}
|
|
1739
|
-
if (callee.type ===
|
|
2252
|
+
if (callee.type === import_utils20.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils20.AST_NODE_TYPES.Identifier) {
|
|
1740
2253
|
return callee.property.name === "assertNever";
|
|
1741
2254
|
}
|
|
1742
2255
|
return false;
|
|
1743
2256
|
};
|
|
1744
2257
|
var statementContainsAssertNever = (statement) => {
|
|
1745
|
-
if (statement.type ===
|
|
2258
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.ExpressionStatement) {
|
|
1746
2259
|
return isAssertNeverCall(statement.expression);
|
|
1747
2260
|
}
|
|
1748
|
-
if (statement.type ===
|
|
2261
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.ThrowStatement) {
|
|
1749
2262
|
return isAssertNeverCall(statement.argument);
|
|
1750
2263
|
}
|
|
1751
|
-
if (statement.type ===
|
|
2264
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.ReturnStatement) {
|
|
1752
2265
|
return statement.argument !== null && isAssertNeverCall(statement.argument);
|
|
1753
2266
|
}
|
|
1754
|
-
if (statement.type ===
|
|
2267
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.BlockStatement) {
|
|
1755
2268
|
return statement.body.some(statementContainsAssertNever);
|
|
1756
2269
|
}
|
|
1757
2270
|
return false;
|
|
1758
2271
|
};
|
|
1759
2272
|
var isRuntimeHandlingStatement = (statement) => {
|
|
1760
|
-
if (statement.type ===
|
|
1761
|
-
if (statement.type ===
|
|
2273
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.EmptyStatement) return false;
|
|
2274
|
+
if (statement.type === import_utils20.AST_NODE_TYPES.BlockStatement) {
|
|
1762
2275
|
return statement.body.some(isRuntimeHandlingStatement);
|
|
1763
2276
|
}
|
|
1764
2277
|
return true;
|
|
1765
2278
|
};
|
|
1766
|
-
var
|
|
2279
|
+
var isFallthroughDefault = (node, defaultIndex) => {
|
|
2280
|
+
const defaultCase = node.cases[defaultIndex];
|
|
2281
|
+
return defaultCase !== void 0 && defaultCase.consequent.length === 0 && defaultIndex < node.cases.length - 1;
|
|
2282
|
+
};
|
|
2283
|
+
var isCommentOnlyNoopDefault = (defaultCase, sourceCode) => {
|
|
2284
|
+
if (defaultCase.consequent.length === 0) {
|
|
2285
|
+
const defaultToken = sourceCode.getFirstToken(defaultCase);
|
|
2286
|
+
const colonToken = defaultToken ? sourceCode.getTokenAfter(defaultToken) : null;
|
|
2287
|
+
return colonToken !== null && sourceCode.getCommentsAfter(colonToken).length > 0;
|
|
2288
|
+
}
|
|
2289
|
+
const only = defaultCase.consequent[0];
|
|
2290
|
+
if (only !== void 0 && defaultCase.consequent.length === 1 && only.type === import_utils20.AST_NODE_TYPES.BlockStatement && only.body.length === 0) {
|
|
2291
|
+
return sourceCode.getCommentsInside(only).length > 0;
|
|
2292
|
+
}
|
|
2293
|
+
return false;
|
|
2294
|
+
};
|
|
2295
|
+
var require_assert_never_default = import_utils20.ESLintUtils.RuleCreator(
|
|
1767
2296
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1768
2297
|
)({
|
|
1769
2298
|
name: "require-assert-never",
|
|
@@ -1781,12 +2310,16 @@ var require_assert_never_default = import_utils19.ESLintUtils.RuleCreator(
|
|
|
1781
2310
|
create(context) {
|
|
1782
2311
|
return {
|
|
1783
2312
|
SwitchStatement(node) {
|
|
1784
|
-
const
|
|
2313
|
+
const defaultIndex = node.cases.findIndex(
|
|
1785
2314
|
(caseNode) => caseNode.test === null
|
|
1786
2315
|
);
|
|
1787
|
-
if (
|
|
2316
|
+
if (defaultIndex === -1) return;
|
|
2317
|
+
const defaultCase = node.cases[defaultIndex];
|
|
2318
|
+
if (defaultCase === void 0) return;
|
|
1788
2319
|
if (defaultCase.consequent.some(statementContainsAssertNever)) return;
|
|
1789
2320
|
if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;
|
|
2321
|
+
if (isFallthroughDefault(node, defaultIndex)) return;
|
|
2322
|
+
if (isCommentOnlyNoopDefault(defaultCase, context.sourceCode)) return;
|
|
1790
2323
|
context.report({
|
|
1791
2324
|
node: defaultCase,
|
|
1792
2325
|
messageId: "missingAssertNever"
|
|
@@ -1797,19 +2330,19 @@ var require_assert_never_default = import_utils19.ESLintUtils.RuleCreator(
|
|
|
1797
2330
|
});
|
|
1798
2331
|
|
|
1799
2332
|
// src/rules/require-zod-form-validation.ts
|
|
1800
|
-
var
|
|
2333
|
+
var import_utils21 = require("@typescript-eslint/utils");
|
|
1801
2334
|
var ZOD_SCHEMA_NAME_RE = /Schema$|^Z[A-Z]/;
|
|
1802
2335
|
var looksLikeZodSchema = (node) => {
|
|
1803
2336
|
let current = node;
|
|
1804
2337
|
while (true) {
|
|
1805
|
-
if (current.type ===
|
|
2338
|
+
if (current.type === import_utils21.AST_NODE_TYPES.Identifier) {
|
|
1806
2339
|
return current.name === "z" || ZOD_SCHEMA_NAME_RE.test(current.name);
|
|
1807
2340
|
}
|
|
1808
|
-
if (current.type ===
|
|
2341
|
+
if (current.type === import_utils21.AST_NODE_TYPES.CallExpression) {
|
|
1809
2342
|
current = current.callee;
|
|
1810
2343
|
continue;
|
|
1811
2344
|
}
|
|
1812
|
-
if (current.type ===
|
|
2345
|
+
if (current.type === import_utils21.AST_NODE_TYPES.MemberExpression) {
|
|
1813
2346
|
current = current.object;
|
|
1814
2347
|
continue;
|
|
1815
2348
|
}
|
|
@@ -1817,25 +2350,25 @@ var looksLikeZodSchema = (node) => {
|
|
|
1817
2350
|
}
|
|
1818
2351
|
};
|
|
1819
2352
|
var isZodParseCall = (node) => {
|
|
1820
|
-
if (node.type !==
|
|
2353
|
+
if (node.type !== import_utils21.AST_NODE_TYPES.CallExpression) return false;
|
|
1821
2354
|
const callee = node.callee;
|
|
1822
|
-
if (callee.type !==
|
|
2355
|
+
if (callee.type !== import_utils21.AST_NODE_TYPES.MemberExpression) return false;
|
|
1823
2356
|
if (callee.computed) return false;
|
|
1824
|
-
if (callee.property.type !==
|
|
2357
|
+
if (callee.property.type !== import_utils21.AST_NODE_TYPES.Identifier) return false;
|
|
1825
2358
|
const method = callee.property.name;
|
|
1826
2359
|
if (method !== "parse" && method !== "safeParse") return false;
|
|
1827
2360
|
return looksLikeZodSchema(callee.object);
|
|
1828
2361
|
};
|
|
1829
2362
|
var isFormDataMethodCall = (node) => {
|
|
1830
2363
|
let current = node;
|
|
1831
|
-
if (current.type ===
|
|
2364
|
+
if (current.type === import_utils21.AST_NODE_TYPES.AwaitExpression) {
|
|
1832
2365
|
current = current.argument;
|
|
1833
2366
|
}
|
|
1834
|
-
if (current.type !==
|
|
2367
|
+
if (current.type !== import_utils21.AST_NODE_TYPES.CallExpression) return false;
|
|
1835
2368
|
const callee = current.callee;
|
|
1836
|
-
return callee.type ===
|
|
2369
|
+
return callee.type === import_utils21.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils21.AST_NODE_TYPES.Identifier && callee.property.name === "formData";
|
|
1837
2370
|
};
|
|
1838
|
-
var require_zod_form_validation_default =
|
|
2371
|
+
var require_zod_form_validation_default = import_utils21.ESLintUtils.RuleCreator(
|
|
1839
2372
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1840
2373
|
)({
|
|
1841
2374
|
name: "require-zod-form-validation",
|
|
@@ -1852,14 +2385,14 @@ var require_zod_form_validation_default = import_utils20.ESLintUtils.RuleCreator
|
|
|
1852
2385
|
defaultOptions: [],
|
|
1853
2386
|
create(context) {
|
|
1854
2387
|
const isFormSourceIdentifier = (node) => {
|
|
1855
|
-
if (node.type !==
|
|
2388
|
+
if (node.type !== import_utils21.AST_NODE_TYPES.Identifier) return false;
|
|
1856
2389
|
if (/formdata/i.test(node.name)) return true;
|
|
1857
2390
|
let scope = context.sourceCode.getScope(node);
|
|
1858
2391
|
while (scope !== null) {
|
|
1859
2392
|
const variable = scope.set.get(node.name);
|
|
1860
2393
|
if (variable !== void 0 && variable.defs.length === 1) {
|
|
1861
2394
|
const def = variable.defs[0];
|
|
1862
|
-
if (def !== void 0 && def.type === "Variable" && def.node.type ===
|
|
2395
|
+
if (def !== void 0 && def.type === "Variable" && def.node.type === import_utils21.AST_NODE_TYPES.VariableDeclarator && def.node.init !== null) {
|
|
1863
2396
|
return isFormDataMethodCall(def.node.init);
|
|
1864
2397
|
}
|
|
1865
2398
|
return false;
|
|
@@ -1870,8 +2403,8 @@ var require_zod_form_validation_default = import_utils20.ESLintUtils.RuleCreator
|
|
|
1870
2403
|
};
|
|
1871
2404
|
const isFormDataGetCall = (node) => {
|
|
1872
2405
|
const callee = node.callee;
|
|
1873
|
-
if (callee.type !==
|
|
1874
|
-
if (callee.property.type !==
|
|
2406
|
+
if (callee.type !== import_utils21.AST_NODE_TYPES.MemberExpression) return false;
|
|
2407
|
+
if (callee.property.type !== import_utils21.AST_NODE_TYPES.Identifier || callee.property.name !== "get") {
|
|
1875
2408
|
return false;
|
|
1876
2409
|
}
|
|
1877
2410
|
return isFormSourceIdentifier(callee.object);
|
|
@@ -1894,15 +2427,15 @@ var require_zod_form_validation_default = import_utils20.ESLintUtils.RuleCreator
|
|
|
1894
2427
|
});
|
|
1895
2428
|
|
|
1896
2429
|
// src/rules/zod-naming-convention.ts
|
|
1897
|
-
var
|
|
2430
|
+
var import_utils22 = require("@typescript-eslint/utils");
|
|
1898
2431
|
var calleeChainStartsWithZ = (node) => {
|
|
1899
2432
|
let current = node;
|
|
1900
|
-
while (current.type ===
|
|
2433
|
+
while (current.type === import_utils22.AST_NODE_TYPES.MemberExpression) {
|
|
1901
2434
|
const receiver = current.object;
|
|
1902
|
-
if (receiver.type ===
|
|
2435
|
+
if (receiver.type === import_utils22.AST_NODE_TYPES.Identifier && receiver.name === "z") {
|
|
1903
2436
|
return true;
|
|
1904
2437
|
}
|
|
1905
|
-
if (receiver.type ===
|
|
2438
|
+
if (receiver.type === import_utils22.AST_NODE_TYPES.CallExpression) {
|
|
1906
2439
|
current = receiver.callee;
|
|
1907
2440
|
continue;
|
|
1908
2441
|
}
|
|
@@ -1910,7 +2443,7 @@ var calleeChainStartsWithZ = (node) => {
|
|
|
1910
2443
|
}
|
|
1911
2444
|
return false;
|
|
1912
2445
|
};
|
|
1913
|
-
var zod_naming_convention_default =
|
|
2446
|
+
var zod_naming_convention_default = import_utils22.ESLintUtils.RuleCreator(
|
|
1914
2447
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
1915
2448
|
)({
|
|
1916
2449
|
name: "zod-naming-convention",
|
|
@@ -1930,11 +2463,11 @@ var zod_naming_convention_default = import_utils21.ESLintUtils.RuleCreator(
|
|
|
1930
2463
|
VariableDeclarator(node) {
|
|
1931
2464
|
const init = node.init;
|
|
1932
2465
|
if (init === null || init === void 0) return;
|
|
1933
|
-
if (init.type !==
|
|
2466
|
+
if (init.type !== import_utils22.AST_NODE_TYPES.CallExpression) return;
|
|
1934
2467
|
const callee = init.callee;
|
|
1935
|
-
if (callee.type !==
|
|
2468
|
+
if (callee.type !== import_utils22.AST_NODE_TYPES.MemberExpression) return;
|
|
1936
2469
|
if (!calleeChainStartsWithZ(callee)) return;
|
|
1937
|
-
if (node.id.type !==
|
|
2470
|
+
if (node.id.type !== import_utils22.AST_NODE_TYPES.Identifier) return;
|
|
1938
2471
|
const variableName = node.id.name;
|
|
1939
2472
|
if (variableName.startsWith("Z")) return;
|
|
1940
2473
|
context.report({
|
|
@@ -1947,7 +2480,7 @@ var zod_naming_convention_default = import_utils21.ESLintUtils.RuleCreator(
|
|
|
1947
2480
|
});
|
|
1948
2481
|
|
|
1949
2482
|
// src/rules/no-cors-wildcard-with-credentials.ts
|
|
1950
|
-
var
|
|
2483
|
+
var import_utils23 = require("@typescript-eslint/utils");
|
|
1951
2484
|
var ACAO_HEADER = "access-control-allow-origin";
|
|
1952
2485
|
var ACAC_HEADER = "access-control-allow-credentials";
|
|
1953
2486
|
var HEADER_SET_METHODS = /* @__PURE__ */ new Set(["setheader", "set", "append"]);
|
|
@@ -1979,17 +2512,17 @@ function subtreeContainsStarLiteral(node) {
|
|
|
1979
2512
|
const value = node[key];
|
|
1980
2513
|
if (Array.isArray(value)) {
|
|
1981
2514
|
for (const child of value) {
|
|
1982
|
-
if (
|
|
2515
|
+
if (isNode3(child) && subtreeContainsStarLiteral(child)) {
|
|
1983
2516
|
return true;
|
|
1984
2517
|
}
|
|
1985
2518
|
}
|
|
1986
|
-
} else if (
|
|
2519
|
+
} else if (isNode3(value) && subtreeContainsStarLiteral(value)) {
|
|
1987
2520
|
return true;
|
|
1988
2521
|
}
|
|
1989
2522
|
}
|
|
1990
2523
|
return false;
|
|
1991
2524
|
}
|
|
1992
|
-
function
|
|
2525
|
+
function isNode3(value) {
|
|
1993
2526
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
1994
2527
|
}
|
|
1995
2528
|
function propertyKeyName(prop) {
|
|
@@ -2005,7 +2538,7 @@ function propertyKeyName(prop) {
|
|
|
2005
2538
|
}
|
|
2006
2539
|
return void 0;
|
|
2007
2540
|
}
|
|
2008
|
-
function
|
|
2541
|
+
function calleeName2(node) {
|
|
2009
2542
|
const callee = node.callee;
|
|
2010
2543
|
if (callee.type === "Identifier") {
|
|
2011
2544
|
return callee.name;
|
|
@@ -2016,7 +2549,7 @@ function calleeName(node) {
|
|
|
2016
2549
|
return void 0;
|
|
2017
2550
|
}
|
|
2018
2551
|
function isCorsWildcardCredentialsCall(node) {
|
|
2019
|
-
const name =
|
|
2552
|
+
const name = calleeName2(node);
|
|
2020
2553
|
if (name === void 0 || name.toLowerCase() !== "cors") {
|
|
2021
2554
|
return false;
|
|
2022
2555
|
}
|
|
@@ -2089,7 +2622,7 @@ function enclosingScope(node) {
|
|
|
2089
2622
|
}
|
|
2090
2623
|
return void 0;
|
|
2091
2624
|
}
|
|
2092
|
-
var no_cors_wildcard_with_credentials_default =
|
|
2625
|
+
var no_cors_wildcard_with_credentials_default = import_utils23.ESLintUtils.RuleCreator(
|
|
2093
2626
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2094
2627
|
)({
|
|
2095
2628
|
name: "no-cors-wildcard-with-credentials",
|
|
@@ -2157,12 +2690,12 @@ var no_cors_wildcard_with_credentials_default = import_utils22.ESLintUtils.RuleC
|
|
|
2157
2690
|
});
|
|
2158
2691
|
|
|
2159
2692
|
// src/rules/no-fat-try-blocks.ts
|
|
2160
|
-
var
|
|
2693
|
+
var import_utils24 = require("@typescript-eslint/utils");
|
|
2161
2694
|
var MAX_TRY_BODY_STATEMENTS = 3;
|
|
2162
2695
|
var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set([
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2696
|
+
import_utils24.AST_NODE_TYPES.FunctionDeclaration,
|
|
2697
|
+
import_utils24.AST_NODE_TYPES.FunctionExpression,
|
|
2698
|
+
import_utils24.AST_NODE_TYPES.ArrowFunctionExpression
|
|
2166
2699
|
]);
|
|
2167
2700
|
var PURE_METHODS = /* @__PURE__ */ new Set([
|
|
2168
2701
|
"map",
|
|
@@ -2255,25 +2788,25 @@ var PURE_CONSTRUCTORS = /* @__PURE__ */ new Set([
|
|
|
2255
2788
|
"Response",
|
|
2256
2789
|
"AbortController"
|
|
2257
2790
|
]);
|
|
2258
|
-
function
|
|
2791
|
+
function isNode4(value) {
|
|
2259
2792
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
2260
2793
|
}
|
|
2261
2794
|
function isPureCall(node) {
|
|
2262
2795
|
const callee = node.callee;
|
|
2263
|
-
if (callee.type !==
|
|
2796
|
+
if (callee.type !== import_utils24.AST_NODE_TYPES.MemberExpression) {
|
|
2264
2797
|
return false;
|
|
2265
2798
|
}
|
|
2266
2799
|
const property = callee.property;
|
|
2267
|
-
if (property.type !==
|
|
2800
|
+
if (property.type !== import_utils24.AST_NODE_TYPES.Identifier) {
|
|
2268
2801
|
return false;
|
|
2269
2802
|
}
|
|
2270
|
-
if (callee.object.type ===
|
|
2803
|
+
if (callee.object.type === import_utils24.AST_NODE_TYPES.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
|
|
2271
2804
|
return true;
|
|
2272
2805
|
}
|
|
2273
2806
|
return PURE_METHODS.has(property.name);
|
|
2274
2807
|
}
|
|
2275
2808
|
function isPureNew(node) {
|
|
2276
|
-
return node.callee.type ===
|
|
2809
|
+
return node.callee.type === import_utils24.AST_NODE_TYPES.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
|
|
2277
2810
|
}
|
|
2278
2811
|
function subtreeMatches(stmt, predicate) {
|
|
2279
2812
|
let found = false;
|
|
@@ -2295,11 +2828,11 @@ function subtreeMatches(stmt, predicate) {
|
|
|
2295
2828
|
const value = current[key];
|
|
2296
2829
|
if (Array.isArray(value)) {
|
|
2297
2830
|
for (const child of value) {
|
|
2298
|
-
if (
|
|
2831
|
+
if (isNode4(child)) {
|
|
2299
2832
|
visit(child);
|
|
2300
2833
|
}
|
|
2301
2834
|
}
|
|
2302
|
-
} else if (
|
|
2835
|
+
} else if (isNode4(value)) {
|
|
2303
2836
|
visit(value);
|
|
2304
2837
|
}
|
|
2305
2838
|
if (found) {
|
|
@@ -2310,14 +2843,14 @@ function subtreeMatches(stmt, predicate) {
|
|
|
2310
2843
|
visit(stmt);
|
|
2311
2844
|
return found;
|
|
2312
2845
|
}
|
|
2313
|
-
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type ===
|
|
2846
|
+
var hasAwait = (stmt) => subtreeMatches(stmt, (n) => n.type === import_utils24.AST_NODE_TYPES.AwaitExpression);
|
|
2314
2847
|
var hasThrowingCallOrNew = (stmt) => subtreeMatches(
|
|
2315
2848
|
stmt,
|
|
2316
|
-
(n) => n.type ===
|
|
2849
|
+
(n) => n.type === import_utils24.AST_NODE_TYPES.CallExpression && !isPureCall(n) || n.type === import_utils24.AST_NODE_TYPES.NewExpression && !isPureNew(n)
|
|
2317
2850
|
);
|
|
2318
2851
|
function unwrap2(expr) {
|
|
2319
2852
|
let current = expr;
|
|
2320
|
-
while (current.type ===
|
|
2853
|
+
while (current.type === import_utils24.AST_NODE_TYPES.ChainExpression || current.type === import_utils24.AST_NODE_TYPES.TSNonNullExpression) {
|
|
2321
2854
|
current = current.expression;
|
|
2322
2855
|
}
|
|
2323
2856
|
return current;
|
|
@@ -2326,7 +2859,7 @@ function canThrow(stmt) {
|
|
|
2326
2859
|
if (hasAwait(stmt)) {
|
|
2327
2860
|
return true;
|
|
2328
2861
|
}
|
|
2329
|
-
if (stmt.type ===
|
|
2862
|
+
if (stmt.type === import_utils24.AST_NODE_TYPES.ExpressionStatement && unwrap2(stmt.expression).type === import_utils24.AST_NODE_TYPES.CallExpression) {
|
|
2330
2863
|
return false;
|
|
2331
2864
|
}
|
|
2332
2865
|
return hasThrowingCallOrNew(stmt);
|
|
@@ -2337,9 +2870,9 @@ function handlerRethrows(handler) {
|
|
|
2337
2870
|
}
|
|
2338
2871
|
const body = handler.body.body;
|
|
2339
2872
|
const last = body[body.length - 1];
|
|
2340
|
-
return last !== void 0 && last.type ===
|
|
2873
|
+
return last !== void 0 && last.type === import_utils24.AST_NODE_TYPES.ThrowStatement;
|
|
2341
2874
|
}
|
|
2342
|
-
var no_fat_try_blocks_default =
|
|
2875
|
+
var no_fat_try_blocks_default = import_utils24.ESLintUtils.RuleCreator(
|
|
2343
2876
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2344
2877
|
)({
|
|
2345
2878
|
name: "no-fat-try-blocks",
|
|
@@ -2380,8 +2913,8 @@ var no_fat_try_blocks_default = import_utils23.ESLintUtils.RuleCreator(
|
|
|
2380
2913
|
});
|
|
2381
2914
|
|
|
2382
2915
|
// src/rules/no-secret-in-log.ts
|
|
2383
|
-
var
|
|
2384
|
-
var
|
|
2916
|
+
var import_utils25 = require("@typescript-eslint/utils");
|
|
2917
|
+
var LOG_METHODS2 = /* @__PURE__ */ new Set([
|
|
2385
2918
|
"debug",
|
|
2386
2919
|
"info",
|
|
2387
2920
|
"warn",
|
|
@@ -2394,7 +2927,7 @@ var LOG_METHODS = /* @__PURE__ */ new Set([
|
|
|
2394
2927
|
"fatal",
|
|
2395
2928
|
"success"
|
|
2396
2929
|
]);
|
|
2397
|
-
var
|
|
2930
|
+
var LOGGER_NAMES2 = /* @__PURE__ */ new Set([
|
|
2398
2931
|
"logger",
|
|
2399
2932
|
"log",
|
|
2400
2933
|
"logging",
|
|
@@ -2535,12 +3068,12 @@ function isSecretKeyword(name) {
|
|
|
2535
3068
|
function isLoggerExpr(expr) {
|
|
2536
3069
|
switch (expr.type) {
|
|
2537
3070
|
case "Identifier":
|
|
2538
|
-
return
|
|
3071
|
+
return LOGGER_NAMES2.has(expr.name.toLowerCase());
|
|
2539
3072
|
case "MemberExpression": {
|
|
2540
3073
|
const { property, object } = expr;
|
|
2541
3074
|
if (!expr.computed && property.type === "Identifier") {
|
|
2542
3075
|
const lowered = property.name.toLowerCase();
|
|
2543
|
-
if (
|
|
3076
|
+
if (LOGGER_NAMES2.has(lowered) || LOGGER_FACTORIES.has(lowered)) {
|
|
2544
3077
|
return true;
|
|
2545
3078
|
}
|
|
2546
3079
|
}
|
|
@@ -2578,7 +3111,7 @@ function propertyKeyName2(prop) {
|
|
|
2578
3111
|
}
|
|
2579
3112
|
return null;
|
|
2580
3113
|
}
|
|
2581
|
-
var no_secret_in_log_default =
|
|
3114
|
+
var no_secret_in_log_default = import_utils25.ESLintUtils.RuleCreator(
|
|
2582
3115
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2583
3116
|
)({
|
|
2584
3117
|
name: "no-secret-in-log",
|
|
@@ -2597,7 +3130,7 @@ var no_secret_in_log_default = import_utils24.ESLintUtils.RuleCreator(
|
|
|
2597
3130
|
return {
|
|
2598
3131
|
CallExpression(node) {
|
|
2599
3132
|
const callee = node.callee;
|
|
2600
|
-
if (callee.type !== "MemberExpression" || callee.computed || callee.property.type !== "Identifier" || !
|
|
3133
|
+
if (callee.type !== "MemberExpression" || callee.computed || callee.property.type !== "Identifier" || !LOG_METHODS2.has(callee.property.name)) {
|
|
2601
3134
|
return;
|
|
2602
3135
|
}
|
|
2603
3136
|
if (!isLoggerExpr(callee.object)) {
|
|
@@ -2614,6 +3147,16 @@ var no_secret_in_log_default = import_utils24.ESLintUtils.RuleCreator(
|
|
|
2614
3147
|
}
|
|
2615
3148
|
continue;
|
|
2616
3149
|
}
|
|
3150
|
+
if (arg.type === "MemberExpression") {
|
|
3151
|
+
if (!arg.computed && arg.property.type === "Identifier" && isSecretKeyword(arg.property.name)) {
|
|
3152
|
+
context.report({
|
|
3153
|
+
node: arg,
|
|
3154
|
+
messageId: "noSecretInLog",
|
|
3155
|
+
data: { name: arg.property.name }
|
|
3156
|
+
});
|
|
3157
|
+
}
|
|
3158
|
+
continue;
|
|
3159
|
+
}
|
|
2617
3160
|
if (arg.type === "ObjectExpression") {
|
|
2618
3161
|
for (const prop of arg.properties) {
|
|
2619
3162
|
if (prop.type !== "Property") {
|
|
@@ -2636,7 +3179,7 @@ var no_secret_in_log_default = import_utils24.ESLintUtils.RuleCreator(
|
|
|
2636
3179
|
});
|
|
2637
3180
|
|
|
2638
3181
|
// src/rules/prefer-string-literal-union.ts
|
|
2639
|
-
var
|
|
3182
|
+
var import_utils26 = require("@typescript-eslint/utils");
|
|
2640
3183
|
var ts = __toESM(require("typescript"), 1);
|
|
2641
3184
|
var CHOICE_TOKENS = /* @__PURE__ */ new Set([
|
|
2642
3185
|
"status",
|
|
@@ -2679,19 +3222,19 @@ function isChoiceLikeName(name) {
|
|
|
2679
3222
|
return CHOICE_TOKENS.has(lastWord(name));
|
|
2680
3223
|
}
|
|
2681
3224
|
function keyName(key) {
|
|
2682
|
-
if (key.type ===
|
|
3225
|
+
if (key.type === import_utils26.AST_NODE_TYPES.Identifier) {
|
|
2683
3226
|
return key.name;
|
|
2684
3227
|
}
|
|
2685
|
-
if (key.type ===
|
|
3228
|
+
if (key.type === import_utils26.AST_NODE_TYPES.Literal && typeof key.value === "string") {
|
|
2686
3229
|
return key.value;
|
|
2687
3230
|
}
|
|
2688
3231
|
return null;
|
|
2689
3232
|
}
|
|
2690
3233
|
function isStringLiteralMember(t) {
|
|
2691
|
-
return t.type ===
|
|
3234
|
+
return t.type === import_utils26.AST_NODE_TYPES.TSLiteralType && t.literal.type === import_utils26.AST_NODE_TYPES.Literal && typeof t.literal.value === "string";
|
|
2692
3235
|
}
|
|
2693
3236
|
function isStringLiteralUnion(node) {
|
|
2694
|
-
if (node?.type !==
|
|
3237
|
+
if (node?.type !== import_utils26.AST_NODE_TYPES.TSUnionType) {
|
|
2695
3238
|
return false;
|
|
2696
3239
|
}
|
|
2697
3240
|
return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
|
|
@@ -2700,13 +3243,32 @@ function typeHasRawString(type) {
|
|
|
2700
3243
|
const parts = type.isUnion() ? type.types : [type];
|
|
2701
3244
|
return parts.some((t) => (t.flags & ts.TypeFlags.String) !== 0);
|
|
2702
3245
|
}
|
|
3246
|
+
function isExternalSourceFile(sf) {
|
|
3247
|
+
if (sf === void 0) {
|
|
3248
|
+
return false;
|
|
3249
|
+
}
|
|
3250
|
+
return sf.isDeclarationFile || sf.fileName.includes("/node_modules/");
|
|
3251
|
+
}
|
|
3252
|
+
function symbolIsExternallyDeclared(sym) {
|
|
3253
|
+
return sym?.declarations?.some((d) => isExternalSourceFile(d.getSourceFile())) ?? false;
|
|
3254
|
+
}
|
|
3255
|
+
function bindingSourceExpression(decl) {
|
|
3256
|
+
let node = decl.parent;
|
|
3257
|
+
while (!ts.isForOfStatement(node) && !(ts.isVariableDeclaration(node) && node.initializer !== void 0)) {
|
|
3258
|
+
if (node.parent === void 0) {
|
|
3259
|
+
return void 0;
|
|
3260
|
+
}
|
|
3261
|
+
node = node.parent;
|
|
3262
|
+
}
|
|
3263
|
+
return ts.isForOfStatement(node) ? node.expression : node.initializer;
|
|
3264
|
+
}
|
|
2703
3265
|
function refKey(node) {
|
|
2704
|
-
if (node.type ===
|
|
3266
|
+
if (node.type === import_utils26.AST_NODE_TYPES.Identifier) {
|
|
2705
3267
|
return node.name;
|
|
2706
3268
|
}
|
|
2707
|
-
if (node.type ===
|
|
3269
|
+
if (node.type === import_utils26.AST_NODE_TYPES.MemberExpression && !node.computed) {
|
|
2708
3270
|
const inner = refKey(node.object);
|
|
2709
|
-
if (inner === null || node.property.type !==
|
|
3271
|
+
if (inner === null || node.property.type !== import_utils26.AST_NODE_TYPES.Identifier) {
|
|
2710
3272
|
return null;
|
|
2711
3273
|
}
|
|
2712
3274
|
return `${inner}.${node.property.name}`;
|
|
@@ -2714,12 +3276,12 @@ function refKey(node) {
|
|
|
2714
3276
|
return null;
|
|
2715
3277
|
}
|
|
2716
3278
|
function strLiteral(node) {
|
|
2717
|
-
if (node.type ===
|
|
3279
|
+
if (node.type === import_utils26.AST_NODE_TYPES.Literal && typeof node.value === "string") {
|
|
2718
3280
|
return node.value;
|
|
2719
3281
|
}
|
|
2720
3282
|
return null;
|
|
2721
3283
|
}
|
|
2722
|
-
var prefer_string_literal_union_default =
|
|
3284
|
+
var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator(
|
|
2723
3285
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
2724
3286
|
)({
|
|
2725
3287
|
name: "prefer-string-literal-union",
|
|
@@ -2743,7 +3305,7 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2743
3305
|
}
|
|
2744
3306
|
let services;
|
|
2745
3307
|
try {
|
|
2746
|
-
services =
|
|
3308
|
+
services = import_utils26.ESLintUtils.getParserServices(context);
|
|
2747
3309
|
} catch {
|
|
2748
3310
|
services = null;
|
|
2749
3311
|
}
|
|
@@ -2757,6 +3319,37 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2757
3319
|
}
|
|
2758
3320
|
return typeHasRawString(services.getTypeAtLocation(node));
|
|
2759
3321
|
}
|
|
3322
|
+
function originIsExternal(node, depth) {
|
|
3323
|
+
if (node === void 0 || services === null || depth > 6) {
|
|
3324
|
+
return false;
|
|
3325
|
+
}
|
|
3326
|
+
const checker = services.program.getTypeChecker();
|
|
3327
|
+
if (ts.isParenthesizedExpression(node) || ts.isNonNullExpression(node) || ts.isAsExpression(node)) {
|
|
3328
|
+
return originIsExternal(node.expression, depth + 1);
|
|
3329
|
+
}
|
|
3330
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
3331
|
+
return symbolIsExternallyDeclared(checker.getSymbolAtLocation(node.name));
|
|
3332
|
+
}
|
|
3333
|
+
if (ts.isCallExpression(node)) {
|
|
3334
|
+
return originIsExternal(node.expression, depth + 1);
|
|
3335
|
+
}
|
|
3336
|
+
if (ts.isIdentifier(node)) {
|
|
3337
|
+
const decl = checker.getSymbolAtLocation(node)?.valueDeclaration;
|
|
3338
|
+
if (decl === void 0) {
|
|
3339
|
+
return false;
|
|
3340
|
+
}
|
|
3341
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer !== void 0) {
|
|
3342
|
+
return originIsExternal(decl.initializer, depth + 1);
|
|
3343
|
+
}
|
|
3344
|
+
if (ts.isBindingElement(decl)) {
|
|
3345
|
+
return originIsExternal(bindingSourceExpression(decl), depth + 1);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
return false;
|
|
3349
|
+
}
|
|
3350
|
+
function operandIsFlaggable(node) {
|
|
3351
|
+
return operandIsRawString(node) && !originIsExternal(services?.esTreeNodeToTSNodeMap.get(node), 0);
|
|
3352
|
+
}
|
|
2760
3353
|
function pushScope() {
|
|
2761
3354
|
scopeStack.push({ clusters: /* @__PURE__ */ new Map() });
|
|
2762
3355
|
}
|
|
@@ -2796,7 +3389,7 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2796
3389
|
containersWithUnion.add(container);
|
|
2797
3390
|
return;
|
|
2798
3391
|
}
|
|
2799
|
-
if (typeNode?.type !==
|
|
3392
|
+
if (typeNode?.type !== import_utils26.AST_NODE_TYPES.TSStringKeyword) {
|
|
2800
3393
|
return;
|
|
2801
3394
|
}
|
|
2802
3395
|
const name = keyName(key);
|
|
@@ -2821,18 +3414,18 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2821
3414
|
const rightKey = refKey(node.right);
|
|
2822
3415
|
const leftLit = strLiteral(node.left);
|
|
2823
3416
|
if (leftKey !== null && rightLit !== null) {
|
|
2824
|
-
if (
|
|
3417
|
+
if (operandIsFlaggable(node.left)) {
|
|
2825
3418
|
accumulate(leftKey, [rightLit], node);
|
|
2826
3419
|
}
|
|
2827
3420
|
} else if (rightKey !== null && leftLit !== null) {
|
|
2828
|
-
if (
|
|
3421
|
+
if (operandIsFlaggable(node.right)) {
|
|
2829
3422
|
accumulate(rightKey, [leftLit], node);
|
|
2830
3423
|
}
|
|
2831
3424
|
}
|
|
2832
3425
|
},
|
|
2833
3426
|
SwitchStatement(node) {
|
|
2834
3427
|
const key = refKey(node.discriminant);
|
|
2835
|
-
if (key === null || !
|
|
3428
|
+
if (key === null || !operandIsFlaggable(node.discriminant)) {
|
|
2836
3429
|
return;
|
|
2837
3430
|
}
|
|
2838
3431
|
const literals = [];
|
|
@@ -2884,10 +3477,10 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2884
3477
|
}
|
|
2885
3478
|
};
|
|
2886
3479
|
function refKeyText(node) {
|
|
2887
|
-
if (node.type ===
|
|
3480
|
+
if (node.type === import_utils26.AST_NODE_TYPES.BinaryExpression) {
|
|
2888
3481
|
return refKey(node.left) ?? refKey(node.right) ?? "value";
|
|
2889
3482
|
}
|
|
2890
|
-
if (node.type ===
|
|
3483
|
+
if (node.type === import_utils26.AST_NODE_TYPES.SwitchStatement) {
|
|
2891
3484
|
return refKey(node.discriminant) ?? "value";
|
|
2892
3485
|
}
|
|
2893
3486
|
return "value";
|
|
@@ -2896,7 +3489,7 @@ var prefer_string_literal_union_default = import_utils25.ESLintUtils.RuleCreator
|
|
|
2896
3489
|
});
|
|
2897
3490
|
|
|
2898
3491
|
// src/rules/single-public-export.ts
|
|
2899
|
-
var
|
|
3492
|
+
var import_utils27 = require("@typescript-eslint/utils");
|
|
2900
3493
|
var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
|
|
2901
3494
|
"util",
|
|
2902
3495
|
"utils",
|
|
@@ -2923,20 +3516,20 @@ var TEST_FILE_RE = /\.(test|spec)\.[cm]?[jt]sx?$/i;
|
|
|
2923
3516
|
var SCRIPT_EXT_RE = /\.[cm]?[jt]sx?$/i;
|
|
2924
3517
|
var basename = (filename) => filename.split(/[/\\]/).pop() ?? filename;
|
|
2925
3518
|
var stemOf = (base) => base.replace(SCRIPT_EXT_RE, "");
|
|
2926
|
-
var
|
|
3519
|
+
var kebabCase2 = (name) => {
|
|
2927
3520
|
let normalized = name;
|
|
2928
3521
|
for (const [pattern, replacement] of ACRONYM_OVERRIDES) {
|
|
2929
3522
|
normalized = normalized.replace(pattern, replacement);
|
|
2930
3523
|
}
|
|
2931
3524
|
return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
|
|
2932
3525
|
};
|
|
2933
|
-
var
|
|
3526
|
+
var isFunctionExpression = (node) => node !== null && (node.type === import_utils27.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils27.AST_NODE_TYPES.FunctionExpression);
|
|
2934
3527
|
var functionConstName = (decl) => {
|
|
2935
3528
|
if (decl.declarations.length !== 1) return null;
|
|
2936
3529
|
const [declarator] = decl.declarations;
|
|
2937
3530
|
if (declarator === void 0) return null;
|
|
2938
|
-
if (declarator.id.type !==
|
|
2939
|
-
if (!
|
|
3531
|
+
if (declarator.id.type !== import_utils27.AST_NODE_TYPES.Identifier) return null;
|
|
3532
|
+
if (!isFunctionExpression(declarator.init)) return null;
|
|
2940
3533
|
return declarator.id.name;
|
|
2941
3534
|
};
|
|
2942
3535
|
var summarizeExports = (body) => {
|
|
@@ -2949,20 +3542,20 @@ var summarizeExports = (body) => {
|
|
|
2949
3542
|
};
|
|
2950
3543
|
for (const statement of body) {
|
|
2951
3544
|
switch (statement.type) {
|
|
2952
|
-
case
|
|
3545
|
+
case import_utils27.AST_NODE_TYPES.ExportAllDeclaration:
|
|
2953
3546
|
hasReExport = true;
|
|
2954
3547
|
break;
|
|
2955
|
-
case
|
|
3548
|
+
case import_utils27.AST_NODE_TYPES.ExportDefaultDeclaration: {
|
|
2956
3549
|
names += 1;
|
|
2957
3550
|
const decl = statement.declaration;
|
|
2958
|
-
if (decl.type ===
|
|
3551
|
+
if (decl.type === import_utils27.AST_NODE_TYPES.FunctionDeclaration && decl.id !== null) {
|
|
2959
3552
|
candidate = { name: decl.id.name, node: statement };
|
|
2960
|
-
} else if (decl.type ===
|
|
3553
|
+
} else if (decl.type === import_utils27.AST_NODE_TYPES.ClassDeclaration && decl.id !== null) {
|
|
2961
3554
|
candidate = { name: decl.id.name, node: statement };
|
|
2962
3555
|
}
|
|
2963
3556
|
break;
|
|
2964
3557
|
}
|
|
2965
|
-
case
|
|
3558
|
+
case import_utils27.AST_NODE_TYPES.ExportNamedDeclaration: {
|
|
2966
3559
|
if (statement.source !== null) {
|
|
2967
3560
|
hasReExport = true;
|
|
2968
3561
|
break;
|
|
@@ -2973,15 +3566,15 @@ var summarizeExports = (body) => {
|
|
|
2973
3566
|
break;
|
|
2974
3567
|
}
|
|
2975
3568
|
switch (decl.type) {
|
|
2976
|
-
case
|
|
3569
|
+
case import_utils27.AST_NODE_TYPES.FunctionDeclaration:
|
|
2977
3570
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
2978
3571
|
else names += 1;
|
|
2979
3572
|
break;
|
|
2980
|
-
case
|
|
3573
|
+
case import_utils27.AST_NODE_TYPES.ClassDeclaration:
|
|
2981
3574
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
2982
3575
|
else names += 1;
|
|
2983
3576
|
break;
|
|
2984
|
-
case
|
|
3577
|
+
case import_utils27.AST_NODE_TYPES.VariableDeclaration: {
|
|
2985
3578
|
const fnName = functionConstName(decl);
|
|
2986
3579
|
if (fnName !== null && decl.declarations.length === 1) {
|
|
2987
3580
|
addCandidate(fnName, statement);
|
|
@@ -3001,7 +3594,7 @@ var summarizeExports = (body) => {
|
|
|
3001
3594
|
}
|
|
3002
3595
|
return { names, hasReExport, candidate };
|
|
3003
3596
|
};
|
|
3004
|
-
var single_public_export_default =
|
|
3597
|
+
var single_public_export_default = import_utils27.ESLintUtils.RuleCreator(
|
|
3005
3598
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3006
3599
|
)({
|
|
3007
3600
|
name: "single-public-export",
|
|
@@ -3028,7 +3621,7 @@ var single_public_export_default = import_utils26.ESLintUtils.RuleCreator(
|
|
|
3028
3621
|
if (hasReExport) return;
|
|
3029
3622
|
if (names !== 1 || candidate === null) return;
|
|
3030
3623
|
if (CONVENTIONAL_BUCKET_EXPORTS.has(candidate.name)) return;
|
|
3031
|
-
const expected =
|
|
3624
|
+
const expected = kebabCase2(candidate.name);
|
|
3032
3625
|
if (stem === expected) return;
|
|
3033
3626
|
context.report({
|
|
3034
3627
|
node: candidate.node,
|
|
@@ -3071,7 +3664,7 @@ var rules = {
|
|
|
3071
3664
|
var plugin = {
|
|
3072
3665
|
meta: {
|
|
3073
3666
|
name: "@sarj/eslint-plugin",
|
|
3074
|
-
version: "2.
|
|
3667
|
+
version: "2.4.0"
|
|
3075
3668
|
},
|
|
3076
3669
|
rules,
|
|
3077
3670
|
configs: {
|