@sarj/eslint-plugin 2.4.0 → 2.4.1
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 +91 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +91 -23
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
}
|
|
@@ -3651,7 +3719,7 @@ var rules = {
|
|
|
3651
3719
|
var plugin = {
|
|
3652
3720
|
meta: {
|
|
3653
3721
|
name: "@sarj/eslint-plugin",
|
|
3654
|
-
version: "2.4.
|
|
3722
|
+
version: "2.4.1"
|
|
3655
3723
|
},
|
|
3656
3724
|
rules,
|
|
3657
3725
|
configs: {
|