@fjall/eslint-plugin 3.11.0 → 4.0.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/index.js +3 -1
- package/no-raw-exit-code.js +82 -0
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -26,6 +26,7 @@ import requireAbortPrecheckInSdkLoop from "./require-abort-precheck-in-sdk-loop.
|
|
|
26
26
|
import requireAbortCompositionOnSdkSend from "./require-abort-composition-on-sdk-send.js";
|
|
27
27
|
import noClassicConnectedAccountAssume from "./no-classic-connected-account-assume.js";
|
|
28
28
|
import noRawDbTransaction from "./no-raw-db-transaction.js";
|
|
29
|
+
import noRawExitCode from "./no-raw-exit-code.js";
|
|
29
30
|
|
|
30
31
|
export default {
|
|
31
32
|
rules: {
|
|
@@ -58,6 +59,7 @@ export default {
|
|
|
58
59
|
"require-abort-precheck-in-sdk-loop": requireAbortPrecheckInSdkLoop,
|
|
59
60
|
"require-abort-composition-on-sdk-send": requireAbortCompositionOnSdkSend,
|
|
60
61
|
"no-classic-connected-account-assume": noClassicConnectedAccountAssume,
|
|
61
|
-
"no-raw-db-transaction": noRawDbTransaction
|
|
62
|
+
"no-raw-db-transaction": noRawDbTransaction,
|
|
63
|
+
"no-raw-exit-code": noRawExitCode
|
|
62
64
|
}
|
|
63
65
|
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Rule: no-raw-exit-code
|
|
3
|
+
*
|
|
4
|
+
* Exit codes live in the registry (cli/src/util/exitCodes.ts) - one owner
|
|
5
|
+
* per number, per-family tables, documented cross-family reuse. A raw
|
|
6
|
+
* numeric literal in `process.exit(N)` or `process.exitCode = N` bypasses
|
|
7
|
+
* that contract and reintroduces the collision class the registry closed
|
|
8
|
+
* (codemod IO_ERROR 4 vs deploy destruction-withheld 4).
|
|
9
|
+
*
|
|
10
|
+
* Flags:
|
|
11
|
+
* - process.exit(<numeric literal>)
|
|
12
|
+
* - process.exitCode = <numeric literal> (including negated literals)
|
|
13
|
+
*
|
|
14
|
+
* Allowed:
|
|
15
|
+
* - process.exit(SOME_CONSTANT) / process.exitCode = someVariable
|
|
16
|
+
* - the registry module itself (it defines the numbers)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const REGISTRY_PATH_FRAGMENT = "util/exitCodes.ts";
|
|
20
|
+
|
|
21
|
+
function isNumericLiteral(node) {
|
|
22
|
+
if (node === undefined || node === null) return false;
|
|
23
|
+
if (node.type === "Literal" && typeof node.value === "number") return true;
|
|
24
|
+
// -1 parses as UnaryExpression("-", Literal(1))
|
|
25
|
+
return (
|
|
26
|
+
node.type === "UnaryExpression" &&
|
|
27
|
+
node.operator === "-" &&
|
|
28
|
+
isNumericLiteral(node.argument)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isProcessMember(node, propertyName) {
|
|
33
|
+
return (
|
|
34
|
+
node.type === "MemberExpression" &&
|
|
35
|
+
node.object.type === "Identifier" &&
|
|
36
|
+
node.object.name === "process" &&
|
|
37
|
+
node.property.type === "Identifier" &&
|
|
38
|
+
node.property.name === propertyName
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
43
|
+
export default {
|
|
44
|
+
meta: {
|
|
45
|
+
type: "problem",
|
|
46
|
+
docs: {
|
|
47
|
+
description:
|
|
48
|
+
"Exit codes must come from the registry (cli/src/util/exitCodes.ts), never raw numeric literals",
|
|
49
|
+
category: "Best Practices",
|
|
50
|
+
recommended: false
|
|
51
|
+
},
|
|
52
|
+
messages: {
|
|
53
|
+
rawExit:
|
|
54
|
+
"Raw numeric exit code. Import a named constant from util/exitCodes.ts (the exit-code registry) so the number keeps exactly one meaning per family."
|
|
55
|
+
},
|
|
56
|
+
schema: []
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
create(context) {
|
|
60
|
+
const filename = context.filename ?? context.getFilename();
|
|
61
|
+
if (filename.replaceAll("\\", "/").endsWith(REGISTRY_PATH_FRAGMENT)) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
CallExpression(node) {
|
|
67
|
+
if (!isProcessMember(node.callee, "exit")) return;
|
|
68
|
+
if (node.arguments.length === 0) return;
|
|
69
|
+
if (isNumericLiteral(node.arguments[0])) {
|
|
70
|
+
context.report({ node, messageId: "rawExit" });
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
AssignmentExpression(node) {
|
|
74
|
+
if (node.operator !== "=") return;
|
|
75
|
+
if (!isProcessMember(node.left, "exitCode")) return;
|
|
76
|
+
if (isNumericLiteral(node.right)) {
|
|
77
|
+
context.report({ node, messageId: "rawExit" });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/eslint-plugin",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "ESLint plugin with Fjall-specific coding standard rules",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
"vitest": "^4.1.5"
|
|
33
33
|
},
|
|
34
34
|
"license": "SEE LICENSE IN LICENSE",
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "14031063ccd2685e390b70f6a3f4efe2bac7ced9"
|
|
36
36
|
}
|