@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.cjs
CHANGED
|
@@ -37,7 +37,6 @@ 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 SERVER_ACTION_FILE_RE = /(?:^|\/)actions\/|\.action\.[jt]sx?$|(?:^|\/)actions\.[jt]sx?$/;
|
|
41
40
|
var classifyStatement = (statement) => {
|
|
42
41
|
switch (statement.type) {
|
|
43
42
|
case import_utils.AST_NODE_TYPES.ImportDeclaration:
|
|
@@ -52,7 +51,6 @@ var classifyStatement = (statement) => {
|
|
|
52
51
|
};
|
|
53
52
|
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 ");
|
|
54
53
|
var isUseServerDirective = (statement) => {
|
|
55
|
-
if (statement === void 0) return false;
|
|
56
54
|
if (statement.type !== import_utils.AST_NODE_TYPES.ExpressionStatement) return false;
|
|
57
55
|
const expr = statement.expression;
|
|
58
56
|
if (expr.type !== import_utils.AST_NODE_TYPES.Literal) return false;
|
|
@@ -65,23 +63,25 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
|
|
|
65
63
|
meta: {
|
|
66
64
|
type: "suggestion",
|
|
67
65
|
docs: {
|
|
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.
|
|
66
|
+
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."
|
|
69
67
|
},
|
|
70
68
|
schema: [],
|
|
71
69
|
messages: {
|
|
72
70
|
importsFirst: "File structure violation: import statements must come before other declarations",
|
|
73
|
-
useServerDirective: "
|
|
71
|
+
useServerDirective: "A 'use server' directive must be the first statement in the file"
|
|
74
72
|
}
|
|
75
73
|
},
|
|
76
74
|
defaultOptions: [],
|
|
77
75
|
create(context) {
|
|
78
|
-
const isServerAction = SERVER_ACTION_FILE_RE.test(context.filename);
|
|
79
76
|
return {
|
|
80
77
|
Program(node) {
|
|
81
78
|
const body = node.body;
|
|
82
|
-
|
|
79
|
+
const misplacedUseServer = body.find(
|
|
80
|
+
(statement, index) => index > 0 && isUseServerDirective(statement)
|
|
81
|
+
);
|
|
82
|
+
if (misplacedUseServer !== void 0) {
|
|
83
83
|
context.report({
|
|
84
|
-
node,
|
|
84
|
+
node: misplacedUseServer,
|
|
85
85
|
messageId: "useServerDirective"
|
|
86
86
|
});
|
|
87
87
|
}
|
|
@@ -663,12 +663,49 @@ function instanceofErrorSubject(test) {
|
|
|
663
663
|
}
|
|
664
664
|
return null;
|
|
665
665
|
}
|
|
666
|
+
var TYPE_GUARD_PATTERN = /^(is|has)[A-Z]/;
|
|
667
|
+
function typeGuardSubject(test) {
|
|
668
|
+
const arg = test.type === "CallExpression" ? test.arguments[0] : void 0;
|
|
669
|
+
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") {
|
|
670
|
+
return arg;
|
|
671
|
+
}
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
function positiveErrorSubject(test) {
|
|
675
|
+
return instanceofErrorSubject(test) ?? typeGuardSubject(test);
|
|
676
|
+
}
|
|
666
677
|
function negatedInstanceofErrorSubject(test) {
|
|
667
678
|
if (test.type === "UnaryExpression" && test.operator === "!") {
|
|
668
|
-
return
|
|
679
|
+
return positiveErrorSubject(test.argument);
|
|
669
680
|
}
|
|
670
681
|
return null;
|
|
671
682
|
}
|
|
683
|
+
function branchTerminates(branch) {
|
|
684
|
+
const body = branch.type === "BlockStatement" ? branch.body : [branch];
|
|
685
|
+
const last = body[body.length - 1];
|
|
686
|
+
return last !== void 0 && (last.type === "ReturnStatement" || last.type === "ThrowStatement");
|
|
687
|
+
}
|
|
688
|
+
function isNarrowedByEarlyReturn(node, argExpr, sourceCode) {
|
|
689
|
+
const argText = sourceCode.getText(argExpr);
|
|
690
|
+
let current = node.parent;
|
|
691
|
+
while (current) {
|
|
692
|
+
if (current.type === "BlockStatement" || current.type === "Program") {
|
|
693
|
+
for (const stmt of current.body) {
|
|
694
|
+
if (stmt.range[0] >= node.range[0]) {
|
|
695
|
+
break;
|
|
696
|
+
}
|
|
697
|
+
if (stmt.type === "IfStatement" && stmt.alternate === null && branchTerminates(stmt.consequent)) {
|
|
698
|
+
const subject = positiveErrorSubject(stmt.test);
|
|
699
|
+
if (subject && sourceCode.getText(subject) === argText) {
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
current = current.parent;
|
|
706
|
+
}
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
672
709
|
function nodeWithin(node, container) {
|
|
673
710
|
return container !== null && node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
674
711
|
}
|
|
@@ -678,7 +715,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
|
|
|
678
715
|
let current = node.parent;
|
|
679
716
|
while (current) {
|
|
680
717
|
if (current.type === "ConditionalExpression") {
|
|
681
|
-
const subject =
|
|
718
|
+
const subject = positiveErrorSubject(current.test);
|
|
682
719
|
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
683
720
|
return true;
|
|
684
721
|
}
|
|
@@ -687,7 +724,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
|
|
|
687
724
|
return true;
|
|
688
725
|
}
|
|
689
726
|
} else if (current.type === "IfStatement") {
|
|
690
|
-
const subject =
|
|
727
|
+
const subject = positiveErrorSubject(current.test);
|
|
691
728
|
if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
|
|
692
729
|
return true;
|
|
693
730
|
}
|
|
@@ -740,7 +777,7 @@ var no_json_stringify_error_default = import_utils6.ESLintUtils.RuleCreator(
|
|
|
740
777
|
if (!suggestsError) {
|
|
741
778
|
return;
|
|
742
779
|
}
|
|
743
|
-
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode)) {
|
|
780
|
+
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
|
|
744
781
|
return;
|
|
745
782
|
}
|
|
746
783
|
context.report({
|
|
@@ -883,6 +920,17 @@ function isProcessEnv(node) {
|
|
|
883
920
|
function isImportMetaEnv(node) {
|
|
884
921
|
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
922
|
}
|
|
923
|
+
var BUILD_TIME_CONSTANTS = /* @__PURE__ */ new Set([
|
|
924
|
+
"NODE_ENV",
|
|
925
|
+
"MODE",
|
|
926
|
+
"DEV",
|
|
927
|
+
"PROD",
|
|
928
|
+
"SSR"
|
|
929
|
+
]);
|
|
930
|
+
function isBuildTimeConstantAccess(node) {
|
|
931
|
+
const parent = node.parent;
|
|
932
|
+
return parent.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier" && BUILD_TIME_CONSTANTS.has(parent.property.name);
|
|
933
|
+
}
|
|
886
934
|
var no_raw_env_default = import_utils9.ESLintUtils.RuleCreator(
|
|
887
935
|
(name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
|
|
888
936
|
)({
|
|
@@ -901,7 +949,7 @@ var no_raw_env_default = import_utils9.ESLintUtils.RuleCreator(
|
|
|
901
949
|
create(context) {
|
|
902
950
|
return {
|
|
903
951
|
MemberExpression(node) {
|
|
904
|
-
if (isProcessEnv(node) || isImportMetaEnv(node)) {
|
|
952
|
+
if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isBuildTimeConstantAccess(node)) {
|
|
905
953
|
context.report({
|
|
906
954
|
node,
|
|
907
955
|
messageId: "noRawEnv"
|
|
@@ -1137,7 +1185,7 @@ var no_sentinel_return_on_catch_default = import_utils10.ESLintUtils.RuleCreator
|
|
|
1137
1185
|
// src/rules/no-sequential-await.ts
|
|
1138
1186
|
var import_utils11 = require("@typescript-eslint/utils");
|
|
1139
1187
|
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;
|
|
1188
|
+
var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain|buffer|stream|teleport|chunk|\bqueue|drain/i;
|
|
1141
1189
|
function isFunctionLike(node) {
|
|
1142
1190
|
return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
1143
1191
|
}
|
|
@@ -1180,9 +1228,29 @@ function hasEarlyExit(root) {
|
|
|
1180
1228
|
});
|
|
1181
1229
|
return found;
|
|
1182
1230
|
}
|
|
1231
|
+
var TIMER_HELPER_RE = /^(sleep|timeout|delay|wait|pause|tick)$/i;
|
|
1232
|
+
function calleeName2(callee) {
|
|
1233
|
+
if (callee.type === "Identifier") return callee.name;
|
|
1234
|
+
if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier") {
|
|
1235
|
+
return callee.property.name;
|
|
1236
|
+
}
|
|
1237
|
+
return null;
|
|
1238
|
+
}
|
|
1183
1239
|
function isTimerYield(node) {
|
|
1184
1240
|
const arg = node.argument;
|
|
1185
|
-
|
|
1241
|
+
if (arg.type === "NewExpression" && arg.callee.type === "Identifier" && arg.callee.name === "Promise") {
|
|
1242
|
+
return true;
|
|
1243
|
+
}
|
|
1244
|
+
if (arg.type === "CallExpression") {
|
|
1245
|
+
const name = calleeName2(arg.callee);
|
|
1246
|
+
return name !== null && TIMER_HELPER_RE.test(name);
|
|
1247
|
+
}
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
var QUEUE_DRAIN_METHODS = /^(shift|pop|dequeue|next|poll)$/;
|
|
1251
|
+
function isQueueDrain(node) {
|
|
1252
|
+
const arg = node.argument;
|
|
1253
|
+
return arg.type === "CallExpression" && arg.callee.type === "MemberExpression" && !arg.callee.computed && arg.callee.property.type === "Identifier" && QUEUE_DRAIN_METHODS.test(arg.callee.property.name);
|
|
1186
1254
|
}
|
|
1187
1255
|
function referencesName(root, name) {
|
|
1188
1256
|
let found = false;
|
|
@@ -1217,7 +1285,7 @@ function shouldReport(awaits, earlyExit, iterableText) {
|
|
|
1217
1285
|
return false;
|
|
1218
1286
|
}
|
|
1219
1287
|
return awaits.some(
|
|
1220
|
-
(node) => !isTimerYield(node) && !isThreadedAccumulator(node)
|
|
1288
|
+
(node) => !isTimerYield(node) && !isThreadedAccumulator(node) && !isQueueDrain(node)
|
|
1221
1289
|
);
|
|
1222
1290
|
}
|
|
1223
1291
|
var no_sequential_await_default = import_utils11.ESLintUtils.RuleCreator(
|
|
@@ -1238,10 +1306,10 @@ var no_sequential_await_default = import_utils11.ESLintUtils.RuleCreator(
|
|
|
1238
1306
|
create(context) {
|
|
1239
1307
|
function loopParts(node) {
|
|
1240
1308
|
if (node.type === "ForStatement") {
|
|
1241
|
-
return [node.body, node.
|
|
1309
|
+
return [node.body, node.test, node.update];
|
|
1242
1310
|
}
|
|
1243
1311
|
if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
|
|
1244
|
-
return [node.body
|
|
1312
|
+
return [node.body];
|
|
1245
1313
|
}
|
|
1246
1314
|
return [node.body, node.test];
|
|
1247
1315
|
}
|
|
@@ -1897,10 +1965,10 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
|
|
|
1897
1965
|
"currentcolor",
|
|
1898
1966
|
"inherit"
|
|
1899
1967
|
]);
|
|
1900
|
-
var
|
|
1968
|
+
var isInsideSvg = (node) => {
|
|
1901
1969
|
let current = node.parent;
|
|
1902
1970
|
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)) {
|
|
1971
|
+
if (current.type === import_utils17.AST_NODE_TYPES.JSXElement && current.openingElement.name.type === import_utils17.AST_NODE_TYPES.JSXIdentifier && (current.openingElement.name.name === "svg" || SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))) {
|
|
1904
1972
|
return true;
|
|
1905
1973
|
}
|
|
1906
1974
|
current = current.parent;
|
|
@@ -2010,7 +2078,7 @@ var prefer_semantic_colors_default = import_utils17.ESLintUtils.RuleCreator(
|
|
|
2010
2078
|
if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
|
|
2011
2079
|
return;
|
|
2012
2080
|
}
|
|
2013
|
-
if (
|
|
2081
|
+
if (isInsideSvg(node)) return;
|
|
2014
2082
|
checkColorValueNode(node.value);
|
|
2015
2083
|
},
|
|
2016
2084
|
// Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
|
|
@@ -2538,7 +2606,7 @@ function propertyKeyName(prop) {
|
|
|
2538
2606
|
}
|
|
2539
2607
|
return void 0;
|
|
2540
2608
|
}
|
|
2541
|
-
function
|
|
2609
|
+
function calleeName3(node) {
|
|
2542
2610
|
const callee = node.callee;
|
|
2543
2611
|
if (callee.type === "Identifier") {
|
|
2544
2612
|
return callee.name;
|
|
@@ -2549,7 +2617,7 @@ function calleeName2(node) {
|
|
|
2549
2617
|
return void 0;
|
|
2550
2618
|
}
|
|
2551
2619
|
function isCorsWildcardCredentialsCall(node) {
|
|
2552
|
-
const name =
|
|
2620
|
+
const name = calleeName3(node);
|
|
2553
2621
|
if (name === void 0 || name.toLowerCase() !== "cors") {
|
|
2554
2622
|
return false;
|
|
2555
2623
|
}
|
|
@@ -3664,7 +3732,7 @@ var rules = {
|
|
|
3664
3732
|
var plugin = {
|
|
3665
3733
|
meta: {
|
|
3666
3734
|
name: "@sarj/eslint-plugin",
|
|
3667
|
-
version: "2.4.
|
|
3735
|
+
version: "2.4.1"
|
|
3668
3736
|
},
|
|
3669
3737
|
rules,
|
|
3670
3738
|
configs: {
|