@sarj/eslint-plugin 2.4.0 → 2.5.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 +166 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +167 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -72,6 +72,9 @@ declare const rules: {
|
|
|
72
72
|
"no-secret-in-log": _typescript_eslint_utils_ts_eslint.RuleModule<"noSecretInLog", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
73
73
|
name: string;
|
|
74
74
|
};
|
|
75
|
+
"no-unsafe-cast": _typescript_eslint_utils_ts_eslint.RuleModule<"asAny" | "doubleCast", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
76
|
+
name: string;
|
|
77
|
+
};
|
|
75
78
|
"prefer-string-literal-union": _typescript_eslint_utils_ts_eslint.RuleModule<"bareChoiceField" | "comparisonCluster", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
76
79
|
name: string;
|
|
77
80
|
};
|
|
@@ -156,6 +159,9 @@ declare const plugin: {
|
|
|
156
159
|
"no-secret-in-log": _typescript_eslint_utils_ts_eslint.RuleModule<"noSecretInLog", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
157
160
|
name: string;
|
|
158
161
|
};
|
|
162
|
+
"no-unsafe-cast": _typescript_eslint_utils_ts_eslint.RuleModule<"asAny" | "doubleCast", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
163
|
+
name: string;
|
|
164
|
+
};
|
|
159
165
|
"prefer-string-literal-union": _typescript_eslint_utils_ts_eslint.RuleModule<"bareChoiceField" | "comparisonCluster", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
160
166
|
name: string;
|
|
161
167
|
};
|
|
@@ -187,6 +193,7 @@ declare const plugin: {
|
|
|
187
193
|
"@sarj/no-fat-try-blocks": string;
|
|
188
194
|
"@sarj/no-cors-wildcard-with-credentials": string;
|
|
189
195
|
"@sarj/no-secret-in-log": string;
|
|
196
|
+
"@sarj/no-unsafe-cast": string;
|
|
190
197
|
"@sarj/single-public-export": string;
|
|
191
198
|
"@sarj/prefer-string-literal-union": string;
|
|
192
199
|
};
|
|
@@ -217,6 +224,7 @@ declare const plugin: {
|
|
|
217
224
|
"@sarj/no-fat-try-blocks": string;
|
|
218
225
|
"@sarj/no-cors-wildcard-with-credentials": string;
|
|
219
226
|
"@sarj/no-secret-in-log": string;
|
|
227
|
+
"@sarj/no-unsafe-cast": string;
|
|
220
228
|
"@sarj/single-public-export": string;
|
|
221
229
|
"@sarj/prefer-string-literal-union": string;
|
|
222
230
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -72,6 +72,9 @@ declare const rules: {
|
|
|
72
72
|
"no-secret-in-log": _typescript_eslint_utils_ts_eslint.RuleModule<"noSecretInLog", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
73
73
|
name: string;
|
|
74
74
|
};
|
|
75
|
+
"no-unsafe-cast": _typescript_eslint_utils_ts_eslint.RuleModule<"asAny" | "doubleCast", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
76
|
+
name: string;
|
|
77
|
+
};
|
|
75
78
|
"prefer-string-literal-union": _typescript_eslint_utils_ts_eslint.RuleModule<"bareChoiceField" | "comparisonCluster", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
76
79
|
name: string;
|
|
77
80
|
};
|
|
@@ -156,6 +159,9 @@ declare const plugin: {
|
|
|
156
159
|
"no-secret-in-log": _typescript_eslint_utils_ts_eslint.RuleModule<"noSecretInLog", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
157
160
|
name: string;
|
|
158
161
|
};
|
|
162
|
+
"no-unsafe-cast": _typescript_eslint_utils_ts_eslint.RuleModule<"asAny" | "doubleCast", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
163
|
+
name: string;
|
|
164
|
+
};
|
|
159
165
|
"prefer-string-literal-union": _typescript_eslint_utils_ts_eslint.RuleModule<"bareChoiceField" | "comparisonCluster", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|
|
160
166
|
name: string;
|
|
161
167
|
};
|
|
@@ -187,6 +193,7 @@ declare const plugin: {
|
|
|
187
193
|
"@sarj/no-fat-try-blocks": string;
|
|
188
194
|
"@sarj/no-cors-wildcard-with-credentials": string;
|
|
189
195
|
"@sarj/no-secret-in-log": string;
|
|
196
|
+
"@sarj/no-unsafe-cast": string;
|
|
190
197
|
"@sarj/single-public-export": string;
|
|
191
198
|
"@sarj/prefer-string-literal-union": string;
|
|
192
199
|
};
|
|
@@ -217,6 +224,7 @@ declare const plugin: {
|
|
|
217
224
|
"@sarj/no-fat-try-blocks": string;
|
|
218
225
|
"@sarj/no-cors-wildcard-with-credentials": string;
|
|
219
226
|
"@sarj/no-secret-in-log": string;
|
|
227
|
+
"@sarj/no-unsafe-cast": string;
|
|
220
228
|
"@sarj/single-public-export": string;
|
|
221
229
|
"@sarj/prefer-string-literal-union": string;
|
|
222
230
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/rules/enforce-file-structure.ts
|
|
2
2
|
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
3
|
-
var SERVER_ACTION_FILE_RE = /(?:^|\/)actions\/|\.action\.[jt]sx?$|(?:^|\/)actions\.[jt]sx?$/;
|
|
4
3
|
var classifyStatement = (statement) => {
|
|
5
4
|
switch (statement.type) {
|
|
6
5
|
case AST_NODE_TYPES.ImportDeclaration:
|
|
@@ -15,7 +14,6 @@ var classifyStatement = (statement) => {
|
|
|
15
14
|
};
|
|
16
15
|
var isStringDirective = (statement) => statement.type === AST_NODE_TYPES.ExpressionStatement && statement.expression.type === AST_NODE_TYPES.Literal && typeof statement.expression.value === "string" && statement.expression.value.startsWith("use ");
|
|
17
16
|
var isUseServerDirective = (statement) => {
|
|
18
|
-
if (statement === void 0) return false;
|
|
19
17
|
if (statement.type !== AST_NODE_TYPES.ExpressionStatement) return false;
|
|
20
18
|
const expr = statement.expression;
|
|
21
19
|
if (expr.type !== AST_NODE_TYPES.Literal) return false;
|
|
@@ -28,23 +26,25 @@ var enforce_file_structure_default = ESLintUtils.RuleCreator(
|
|
|
28
26
|
meta: {
|
|
29
27
|
type: "suggestion",
|
|
30
28
|
docs: {
|
|
31
|
-
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.
|
|
29
|
+
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. When a module contains a `use server` directive, it must be the first statement in the file."
|
|
32
30
|
},
|
|
33
31
|
schema: [],
|
|
34
32
|
messages: {
|
|
35
33
|
importsFirst: "File structure violation: import statements must come before other declarations",
|
|
36
|
-
useServerDirective: "
|
|
34
|
+
useServerDirective: "A 'use server' directive must be the first statement in the file"
|
|
37
35
|
}
|
|
38
36
|
},
|
|
39
37
|
defaultOptions: [],
|
|
40
38
|
create(context) {
|
|
41
|
-
const isServerAction = SERVER_ACTION_FILE_RE.test(context.filename);
|
|
42
39
|
return {
|
|
43
40
|
Program(node) {
|
|
44
41
|
const body = node.body;
|
|
45
|
-
|
|
42
|
+
const misplacedUseServer = body.find(
|
|
43
|
+
(statement, index) => index > 0 && isUseServerDirective(statement)
|
|
44
|
+
);
|
|
45
|
+
if (misplacedUseServer !== void 0) {
|
|
46
46
|
context.report({
|
|
47
|
-
node,
|
|
47
|
+
node: misplacedUseServer,
|
|
48
48
|
messageId: "useServerDirective"
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -629,12 +629,49 @@ function instanceofErrorSubject(test) {
|
|
|
629
629
|
}
|
|
630
630
|
return null;
|
|
631
631
|
}
|
|
632
|
+
var TYPE_GUARD_PATTERN = /^(is|has)[A-Z]/;
|
|
633
|
+
function typeGuardSubject(test) {
|
|
634
|
+
const arg = test.type === "CallExpression" ? test.arguments[0] : void 0;
|
|
635
|
+
if (test.type === "CallExpression" && test.callee.type === "Identifier" && TYPE_GUARD_PATTERN.test(test.callee.name) && test.arguments.length === 1 && arg !== void 0 && arg.type !== "SpreadElement") {
|
|
636
|
+
return arg;
|
|
637
|
+
}
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
function positiveErrorSubject(test) {
|
|
641
|
+
return instanceofErrorSubject(test) ?? typeGuardSubject(test);
|
|
642
|
+
}
|
|
632
643
|
function negatedInstanceofErrorSubject(test) {
|
|
633
644
|
if (test.type === "UnaryExpression" && test.operator === "!") {
|
|
634
|
-
return
|
|
645
|
+
return positiveErrorSubject(test.argument);
|
|
635
646
|
}
|
|
636
647
|
return null;
|
|
637
648
|
}
|
|
649
|
+
function branchTerminates(branch) {
|
|
650
|
+
const body = branch.type === "BlockStatement" ? branch.body : [branch];
|
|
651
|
+
const last = body[body.length - 1];
|
|
652
|
+
return last !== void 0 && (last.type === "ReturnStatement" || last.type === "ThrowStatement");
|
|
653
|
+
}
|
|
654
|
+
function isNarrowedByEarlyReturn(node, argExpr, sourceCode) {
|
|
655
|
+
const argText = sourceCode.getText(argExpr);
|
|
656
|
+
let current = node.parent;
|
|
657
|
+
while (current) {
|
|
658
|
+
if (current.type === "BlockStatement" || current.type === "Program") {
|
|
659
|
+
for (const stmt of current.body) {
|
|
660
|
+
if (stmt.range[0] >= node.range[0]) {
|
|
661
|
+
break;
|
|
662
|
+
}
|
|
663
|
+
if (stmt.type === "IfStatement" && stmt.alternate === null && branchTerminates(stmt.consequent)) {
|
|
664
|
+
const subject = positiveErrorSubject(stmt.test);
|
|
665
|
+
if (subject && sourceCode.getText(subject) === argText) {
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
current = current.parent;
|
|
672
|
+
}
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
638
675
|
function nodeWithin(node, container) {
|
|
639
676
|
return container !== null && node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
640
677
|
}
|
|
@@ -644,7 +681,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
|
|
|
644
681
|
let current = node.parent;
|
|
645
682
|
while (current) {
|
|
646
683
|
if (current.type === "ConditionalExpression") {
|
|
647
|
-
const subject =
|
|
684
|
+
const subject = positiveErrorSubject(current.test);
|
|
648
685
|
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
649
686
|
return true;
|
|
650
687
|
}
|
|
@@ -653,7 +690,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
|
|
|
653
690
|
return true;
|
|
654
691
|
}
|
|
655
692
|
} else if (current.type === "IfStatement") {
|
|
656
|
-
const subject =
|
|
693
|
+
const subject = positiveErrorSubject(current.test);
|
|
657
694
|
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
658
695
|
return true;
|
|
659
696
|
}
|
|
@@ -706,7 +743,7 @@ var no_json_stringify_error_default = ESLintUtils6.RuleCreator(
|
|
|
706
743
|
if (!suggestsError) {
|
|
707
744
|
return;
|
|
708
745
|
}
|
|
709
|
-
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode)) {
|
|
746
|
+
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
|
|
710
747
|
return;
|
|
711
748
|
}
|
|
712
749
|
context.report({
|
|
@@ -849,6 +886,17 @@ function isProcessEnv(node) {
|
|
|
849
886
|
function isImportMetaEnv(node) {
|
|
850
887
|
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";
|
|
851
888
|
}
|
|
889
|
+
var BUILD_TIME_CONSTANTS = /* @__PURE__ */ new Set([
|
|
890
|
+
"NODE_ENV",
|
|
891
|
+
"MODE",
|
|
892
|
+
"DEV",
|
|
893
|
+
"PROD",
|
|
894
|
+
"SSR"
|
|
895
|
+
]);
|
|
896
|
+
function isBuildTimeConstantAccess(node) {
|
|
897
|
+
const parent = node.parent;
|
|
898
|
+
return parent.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier" && BUILD_TIME_CONSTANTS.has(parent.property.name);
|
|
899
|
+
}
|
|
852
900
|
var no_raw_env_default = ESLintUtils8.RuleCreator(
|
|
853
901
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
854
902
|
)({
|
|
@@ -867,7 +915,7 @@ var no_raw_env_default = ESLintUtils8.RuleCreator(
|
|
|
867
915
|
create(context) {
|
|
868
916
|
return {
|
|
869
917
|
MemberExpression(node) {
|
|
870
|
-
if (isProcessEnv(node) || isImportMetaEnv(node)) {
|
|
918
|
+
if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isBuildTimeConstantAccess(node)) {
|
|
871
919
|
context.report({
|
|
872
920
|
node,
|
|
873
921
|
messageId: "noRawEnv"
|
|
@@ -1106,7 +1154,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils9.RuleCreator(
|
|
|
1106
1154
|
// src/rules/no-sequential-await.ts
|
|
1107
1155
|
import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
|
|
1108
1156
|
var ARRAY_ITERATION_METHODS = /* @__PURE__ */ new Set(["forEach", "map", "filter"]);
|
|
1109
|
-
var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain/i;
|
|
1157
|
+
var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain|buffer|stream|teleport|chunk|\bqueue|drain/i;
|
|
1110
1158
|
function isFunctionLike(node) {
|
|
1111
1159
|
return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
1112
1160
|
}
|
|
@@ -1149,9 +1197,29 @@ function hasEarlyExit(root) {
|
|
|
1149
1197
|
});
|
|
1150
1198
|
return found;
|
|
1151
1199
|
}
|
|
1200
|
+
var TIMER_HELPER_RE = /^(sleep|timeout|delay|wait|pause|tick)$/i;
|
|
1201
|
+
function calleeName2(callee) {
|
|
1202
|
+
if (callee.type === "Identifier") return callee.name;
|
|
1203
|
+
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier") {
|
|
1204
|
+
return callee.property.name;
|
|
1205
|
+
}
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1152
1208
|
function isTimerYield(node) {
|
|
1153
1209
|
const arg = node.argument;
|
|
1154
|
-
|
|
1210
|
+
if (arg.type === "NewExpression" && arg.callee.type === "Identifier" && arg.callee.name === "Promise") {
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1213
|
+
if (arg.type === "CallExpression") {
|
|
1214
|
+
const name = calleeName2(arg.callee);
|
|
1215
|
+
return name !== null && TIMER_HELPER_RE.test(name);
|
|
1216
|
+
}
|
|
1217
|
+
return false;
|
|
1218
|
+
}
|
|
1219
|
+
var QUEUE_DRAIN_METHODS = /^(shift|pop|dequeue|next|poll)$/;
|
|
1220
|
+
function isQueueDrain(node) {
|
|
1221
|
+
const arg = node.argument;
|
|
1222
|
+
return arg.type === "CallExpression" && arg.callee.type === "MemberExpression" && !arg.callee.computed && arg.callee.property.type === "Identifier" && QUEUE_DRAIN_METHODS.test(arg.callee.property.name);
|
|
1155
1223
|
}
|
|
1156
1224
|
function referencesName(root, name) {
|
|
1157
1225
|
let found = false;
|
|
@@ -1186,7 +1254,7 @@ function shouldReport(awaits, earlyExit, iterableText) {
|
|
|
1186
1254
|
return false;
|
|
1187
1255
|
}
|
|
1188
1256
|
return awaits.some(
|
|
1189
|
-
(node) => !isTimerYield(node) && !isThreadedAccumulator(node)
|
|
1257
|
+
(node) => !isTimerYield(node) && !isThreadedAccumulator(node) && !isQueueDrain(node)
|
|
1190
1258
|
);
|
|
1191
1259
|
}
|
|
1192
1260
|
var no_sequential_await_default = ESLintUtils10.RuleCreator(
|
|
@@ -1207,10 +1275,10 @@ var no_sequential_await_default = ESLintUtils10.RuleCreator(
|
|
|
1207
1275
|
create(context) {
|
|
1208
1276
|
function loopParts(node) {
|
|
1209
1277
|
if (node.type === "ForStatement") {
|
|
1210
|
-
return [node.body, node.
|
|
1278
|
+
return [node.body, node.test, node.update];
|
|
1211
1279
|
}
|
|
1212
1280
|
if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
|
|
1213
|
-
return [node.body
|
|
1281
|
+
return [node.body];
|
|
1214
1282
|
}
|
|
1215
1283
|
return [node.body, node.test];
|
|
1216
1284
|
}
|
|
@@ -1872,10 +1940,10 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
|
|
|
1872
1940
|
"currentcolor",
|
|
1873
1941
|
"inherit"
|
|
1874
1942
|
]);
|
|
1875
|
-
var
|
|
1943
|
+
var isInsideSvg = (node) => {
|
|
1876
1944
|
let current = node.parent;
|
|
1877
1945
|
while (current !== void 0 && current !== null) {
|
|
1878
|
-
if (current.type === AST_NODE_TYPES7.JSXElement && current.openingElement.name.type === AST_NODE_TYPES7.JSXIdentifier && SVG_DEFS_CONTAINERS.has(current.openingElement.name.name)) {
|
|
1946
|
+
if (current.type === AST_NODE_TYPES7.JSXElement && current.openingElement.name.type === AST_NODE_TYPES7.JSXIdentifier && (current.openingElement.name.name === "svg" || SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))) {
|
|
1879
1947
|
return true;
|
|
1880
1948
|
}
|
|
1881
1949
|
current = current.parent;
|
|
@@ -1985,7 +2053,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
|
|
|
1985
2053
|
if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
|
|
1986
2054
|
return;
|
|
1987
2055
|
}
|
|
1988
|
-
if (
|
|
2056
|
+
if (isInsideSvg(node)) return;
|
|
1989
2057
|
checkColorValueNode(node.value);
|
|
1990
2058
|
},
|
|
1991
2059
|
// Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
|
|
@@ -2519,7 +2587,7 @@ function propertyKeyName(prop) {
|
|
|
2519
2587
|
}
|
|
2520
2588
|
return void 0;
|
|
2521
2589
|
}
|
|
2522
|
-
function
|
|
2590
|
+
function calleeName3(node) {
|
|
2523
2591
|
const callee = node.callee;
|
|
2524
2592
|
if (callee.type === "Identifier") {
|
|
2525
2593
|
return callee.name;
|
|
@@ -2530,7 +2598,7 @@ function calleeName2(node) {
|
|
|
2530
2598
|
return void 0;
|
|
2531
2599
|
}
|
|
2532
2600
|
function isCorsWildcardCredentialsCall(node) {
|
|
2533
|
-
const name =
|
|
2601
|
+
const name = calleeName3(node);
|
|
2534
2602
|
if (name === void 0 || name.toLowerCase() !== "cors") {
|
|
2535
2603
|
return false;
|
|
2536
2604
|
}
|
|
@@ -3162,10 +3230,56 @@ var no_secret_in_log_default = ESLintUtils23.RuleCreator(
|
|
|
3162
3230
|
}
|
|
3163
3231
|
});
|
|
3164
3232
|
|
|
3233
|
+
// src/rules/no-unsafe-cast.ts
|
|
3234
|
+
import { ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
|
|
3235
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
|
|
3236
|
+
function isAnyAnnotation(node) {
|
|
3237
|
+
return node.type === AST_NODE_TYPES13.TSAnyKeyword;
|
|
3238
|
+
}
|
|
3239
|
+
function isConstAssertion(typeAnnotation) {
|
|
3240
|
+
return typeAnnotation.type === AST_NODE_TYPES13.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES13.Identifier && typeAnnotation.typeName.name === "const";
|
|
3241
|
+
}
|
|
3242
|
+
var no_unsafe_cast_default = ESLintUtils24.RuleCreator(
|
|
3243
|
+
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3244
|
+
)({
|
|
3245
|
+
name: "no-unsafe-cast",
|
|
3246
|
+
meta: {
|
|
3247
|
+
type: "problem",
|
|
3248
|
+
docs: {
|
|
3249
|
+
description: "Disallow `as any`/`<any>` casts and `as unknown as T` double-casts, which fully disable type checking."
|
|
3250
|
+
},
|
|
3251
|
+
schema: [],
|
|
3252
|
+
messages: {
|
|
3253
|
+
asAny: "`as any` disables type checking on this value. Narrow with a type guard, model the shape, or cast to a specific type instead.",
|
|
3254
|
+
doubleCast: "`as unknown as T` double-cast bypasses the compiler's structural check. Prefer a runtime validator (e.g. a zod schema) or an accurate type at the boundary."
|
|
3255
|
+
}
|
|
3256
|
+
},
|
|
3257
|
+
defaultOptions: [],
|
|
3258
|
+
create(context) {
|
|
3259
|
+
function checkAssertion(node) {
|
|
3260
|
+
if (isConstAssertion(node.typeAnnotation)) {
|
|
3261
|
+
return;
|
|
3262
|
+
}
|
|
3263
|
+
if (isAnyAnnotation(node.typeAnnotation)) {
|
|
3264
|
+
context.report({ node, messageId: "asAny" });
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
const inner = node.expression;
|
|
3268
|
+
if (inner.type === AST_NODE_TYPES13.TSAsExpression || inner.type === AST_NODE_TYPES13.TSTypeAssertion) {
|
|
3269
|
+
context.report({ node, messageId: "doubleCast" });
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
return {
|
|
3273
|
+
TSAsExpression: checkAssertion,
|
|
3274
|
+
TSTypeAssertion: checkAssertion
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
});
|
|
3278
|
+
|
|
3165
3279
|
// src/rules/prefer-string-literal-union.ts
|
|
3166
3280
|
import {
|
|
3167
|
-
ESLintUtils as
|
|
3168
|
-
AST_NODE_TYPES as
|
|
3281
|
+
ESLintUtils as ESLintUtils25,
|
|
3282
|
+
AST_NODE_TYPES as AST_NODE_TYPES14
|
|
3169
3283
|
} from "@typescript-eslint/utils";
|
|
3170
3284
|
import * as ts from "typescript";
|
|
3171
3285
|
var CHOICE_TOKENS = /* @__PURE__ */ new Set([
|
|
@@ -3209,19 +3323,19 @@ function isChoiceLikeName(name) {
|
|
|
3209
3323
|
return CHOICE_TOKENS.has(lastWord(name));
|
|
3210
3324
|
}
|
|
3211
3325
|
function keyName(key) {
|
|
3212
|
-
if (key.type ===
|
|
3326
|
+
if (key.type === AST_NODE_TYPES14.Identifier) {
|
|
3213
3327
|
return key.name;
|
|
3214
3328
|
}
|
|
3215
|
-
if (key.type ===
|
|
3329
|
+
if (key.type === AST_NODE_TYPES14.Literal && typeof key.value === "string") {
|
|
3216
3330
|
return key.value;
|
|
3217
3331
|
}
|
|
3218
3332
|
return null;
|
|
3219
3333
|
}
|
|
3220
3334
|
function isStringLiteralMember(t) {
|
|
3221
|
-
return t.type ===
|
|
3335
|
+
return t.type === AST_NODE_TYPES14.TSLiteralType && t.literal.type === AST_NODE_TYPES14.Literal && typeof t.literal.value === "string";
|
|
3222
3336
|
}
|
|
3223
3337
|
function isStringLiteralUnion(node) {
|
|
3224
|
-
if (node?.type !==
|
|
3338
|
+
if (node?.type !== AST_NODE_TYPES14.TSUnionType) {
|
|
3225
3339
|
return false;
|
|
3226
3340
|
}
|
|
3227
3341
|
return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
|
|
@@ -3250,12 +3364,12 @@ function bindingSourceExpression(decl) {
|
|
|
3250
3364
|
return ts.isForOfStatement(node) ? node.expression : node.initializer;
|
|
3251
3365
|
}
|
|
3252
3366
|
function refKey(node) {
|
|
3253
|
-
if (node.type ===
|
|
3367
|
+
if (node.type === AST_NODE_TYPES14.Identifier) {
|
|
3254
3368
|
return node.name;
|
|
3255
3369
|
}
|
|
3256
|
-
if (node.type ===
|
|
3370
|
+
if (node.type === AST_NODE_TYPES14.MemberExpression && !node.computed) {
|
|
3257
3371
|
const inner = refKey(node.object);
|
|
3258
|
-
if (inner === null || node.property.type !==
|
|
3372
|
+
if (inner === null || node.property.type !== AST_NODE_TYPES14.Identifier) {
|
|
3259
3373
|
return null;
|
|
3260
3374
|
}
|
|
3261
3375
|
return `${inner}.${node.property.name}`;
|
|
@@ -3263,12 +3377,12 @@ function refKey(node) {
|
|
|
3263
3377
|
return null;
|
|
3264
3378
|
}
|
|
3265
3379
|
function strLiteral(node) {
|
|
3266
|
-
if (node.type ===
|
|
3380
|
+
if (node.type === AST_NODE_TYPES14.Literal && typeof node.value === "string") {
|
|
3267
3381
|
return node.value;
|
|
3268
3382
|
}
|
|
3269
3383
|
return null;
|
|
3270
3384
|
}
|
|
3271
|
-
var prefer_string_literal_union_default =
|
|
3385
|
+
var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
|
|
3272
3386
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3273
3387
|
)({
|
|
3274
3388
|
name: "prefer-string-literal-union",
|
|
@@ -3292,7 +3406,7 @@ var prefer_string_literal_union_default = ESLintUtils24.RuleCreator(
|
|
|
3292
3406
|
}
|
|
3293
3407
|
let services;
|
|
3294
3408
|
try {
|
|
3295
|
-
services =
|
|
3409
|
+
services = ESLintUtils25.getParserServices(context);
|
|
3296
3410
|
} catch {
|
|
3297
3411
|
services = null;
|
|
3298
3412
|
}
|
|
@@ -3376,7 +3490,7 @@ var prefer_string_literal_union_default = ESLintUtils24.RuleCreator(
|
|
|
3376
3490
|
containersWithUnion.add(container);
|
|
3377
3491
|
return;
|
|
3378
3492
|
}
|
|
3379
|
-
if (typeNode?.type !==
|
|
3493
|
+
if (typeNode?.type !== AST_NODE_TYPES14.TSStringKeyword) {
|
|
3380
3494
|
return;
|
|
3381
3495
|
}
|
|
3382
3496
|
const name = keyName(key);
|
|
@@ -3464,10 +3578,10 @@ var prefer_string_literal_union_default = ESLintUtils24.RuleCreator(
|
|
|
3464
3578
|
}
|
|
3465
3579
|
};
|
|
3466
3580
|
function refKeyText(node) {
|
|
3467
|
-
if (node.type ===
|
|
3581
|
+
if (node.type === AST_NODE_TYPES14.BinaryExpression) {
|
|
3468
3582
|
return refKey(node.left) ?? refKey(node.right) ?? "value";
|
|
3469
3583
|
}
|
|
3470
|
-
if (node.type ===
|
|
3584
|
+
if (node.type === AST_NODE_TYPES14.SwitchStatement) {
|
|
3471
3585
|
return refKey(node.discriminant) ?? "value";
|
|
3472
3586
|
}
|
|
3473
3587
|
return "value";
|
|
@@ -3476,7 +3590,7 @@ var prefer_string_literal_union_default = ESLintUtils24.RuleCreator(
|
|
|
3476
3590
|
});
|
|
3477
3591
|
|
|
3478
3592
|
// src/rules/single-public-export.ts
|
|
3479
|
-
import { ESLintUtils as
|
|
3593
|
+
import { ESLintUtils as ESLintUtils26, AST_NODE_TYPES as AST_NODE_TYPES15 } from "@typescript-eslint/utils";
|
|
3480
3594
|
var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
|
|
3481
3595
|
"util",
|
|
3482
3596
|
"utils",
|
|
@@ -3510,12 +3624,12 @@ var kebabCase2 = (name) => {
|
|
|
3510
3624
|
}
|
|
3511
3625
|
return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
|
|
3512
3626
|
};
|
|
3513
|
-
var isFunctionExpression = (node) => node !== null && (node.type ===
|
|
3627
|
+
var isFunctionExpression = (node) => node !== null && (node.type === AST_NODE_TYPES15.ArrowFunctionExpression || node.type === AST_NODE_TYPES15.FunctionExpression);
|
|
3514
3628
|
var functionConstName = (decl) => {
|
|
3515
3629
|
if (decl.declarations.length !== 1) return null;
|
|
3516
3630
|
const [declarator] = decl.declarations;
|
|
3517
3631
|
if (declarator === void 0) return null;
|
|
3518
|
-
if (declarator.id.type !==
|
|
3632
|
+
if (declarator.id.type !== AST_NODE_TYPES15.Identifier) return null;
|
|
3519
3633
|
if (!isFunctionExpression(declarator.init)) return null;
|
|
3520
3634
|
return declarator.id.name;
|
|
3521
3635
|
};
|
|
@@ -3529,20 +3643,20 @@ var summarizeExports = (body) => {
|
|
|
3529
3643
|
};
|
|
3530
3644
|
for (const statement of body) {
|
|
3531
3645
|
switch (statement.type) {
|
|
3532
|
-
case
|
|
3646
|
+
case AST_NODE_TYPES15.ExportAllDeclaration:
|
|
3533
3647
|
hasReExport = true;
|
|
3534
3648
|
break;
|
|
3535
|
-
case
|
|
3649
|
+
case AST_NODE_TYPES15.ExportDefaultDeclaration: {
|
|
3536
3650
|
names += 1;
|
|
3537
3651
|
const decl = statement.declaration;
|
|
3538
|
-
if (decl.type ===
|
|
3652
|
+
if (decl.type === AST_NODE_TYPES15.FunctionDeclaration && decl.id !== null) {
|
|
3539
3653
|
candidate = { name: decl.id.name, node: statement };
|
|
3540
|
-
} else if (decl.type ===
|
|
3654
|
+
} else if (decl.type === AST_NODE_TYPES15.ClassDeclaration && decl.id !== null) {
|
|
3541
3655
|
candidate = { name: decl.id.name, node: statement };
|
|
3542
3656
|
}
|
|
3543
3657
|
break;
|
|
3544
3658
|
}
|
|
3545
|
-
case
|
|
3659
|
+
case AST_NODE_TYPES15.ExportNamedDeclaration: {
|
|
3546
3660
|
if (statement.source !== null) {
|
|
3547
3661
|
hasReExport = true;
|
|
3548
3662
|
break;
|
|
@@ -3553,15 +3667,15 @@ var summarizeExports = (body) => {
|
|
|
3553
3667
|
break;
|
|
3554
3668
|
}
|
|
3555
3669
|
switch (decl.type) {
|
|
3556
|
-
case
|
|
3670
|
+
case AST_NODE_TYPES15.FunctionDeclaration:
|
|
3557
3671
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3558
3672
|
else names += 1;
|
|
3559
3673
|
break;
|
|
3560
|
-
case
|
|
3674
|
+
case AST_NODE_TYPES15.ClassDeclaration:
|
|
3561
3675
|
if (decl.id !== null) addCandidate(decl.id.name, statement);
|
|
3562
3676
|
else names += 1;
|
|
3563
3677
|
break;
|
|
3564
|
-
case
|
|
3678
|
+
case AST_NODE_TYPES15.VariableDeclaration: {
|
|
3565
3679
|
const fnName = functionConstName(decl);
|
|
3566
3680
|
if (fnName !== null && decl.declarations.length === 1) {
|
|
3567
3681
|
addCandidate(fnName, statement);
|
|
@@ -3581,7 +3695,7 @@ var summarizeExports = (body) => {
|
|
|
3581
3695
|
}
|
|
3582
3696
|
return { names, hasReExport, candidate };
|
|
3583
3697
|
};
|
|
3584
|
-
var single_public_export_default =
|
|
3698
|
+
var single_public_export_default = ESLintUtils26.RuleCreator(
|
|
3585
3699
|
(name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
3586
3700
|
)({
|
|
3587
3701
|
name: "single-public-export",
|
|
@@ -3645,13 +3759,14 @@ var rules = {
|
|
|
3645
3759
|
"no-cors-wildcard-with-credentials": no_cors_wildcard_with_credentials_default,
|
|
3646
3760
|
"no-fat-try-blocks": no_fat_try_blocks_default,
|
|
3647
3761
|
"no-secret-in-log": no_secret_in_log_default,
|
|
3762
|
+
"no-unsafe-cast": no_unsafe_cast_default,
|
|
3648
3763
|
"prefer-string-literal-union": prefer_string_literal_union_default,
|
|
3649
3764
|
"single-public-export": single_public_export_default
|
|
3650
3765
|
};
|
|
3651
3766
|
var plugin = {
|
|
3652
3767
|
meta: {
|
|
3653
3768
|
name: "@sarj/eslint-plugin",
|
|
3654
|
-
version: "2.
|
|
3769
|
+
version: "2.5.0"
|
|
3655
3770
|
},
|
|
3656
3771
|
rules,
|
|
3657
3772
|
configs: {
|
|
@@ -3681,6 +3796,7 @@ var plugin = {
|
|
|
3681
3796
|
"@sarj/no-fat-try-blocks": "warn",
|
|
3682
3797
|
"@sarj/no-cors-wildcard-with-credentials": "warn",
|
|
3683
3798
|
"@sarj/no-secret-in-log": "warn",
|
|
3799
|
+
"@sarj/no-unsafe-cast": "warn",
|
|
3684
3800
|
"@sarj/single-public-export": "warn",
|
|
3685
3801
|
"@sarj/prefer-string-literal-union": "warn"
|
|
3686
3802
|
}
|
|
@@ -3715,6 +3831,7 @@ var plugin = {
|
|
|
3715
3831
|
"@sarj/no-fat-try-blocks": "error",
|
|
3716
3832
|
"@sarj/no-cors-wildcard-with-credentials": "error",
|
|
3717
3833
|
"@sarj/no-secret-in-log": "error",
|
|
3834
|
+
"@sarj/no-unsafe-cast": "warn",
|
|
3718
3835
|
"@sarj/single-public-export": "error",
|
|
3719
3836
|
// High-volume/stylistic — warn until rollout proves FP rate.
|
|
3720
3837
|
"@sarj/prefer-string-literal-union": "warn"
|