@checkdigit/eslint-plugin 7.12.1-PR.120-2bb5 → 7.12.1-PR.120-20b8
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-mjs/no-side-effects.mjs +36 -29
- package/package.json +1 -1
- package/src/no-side-effects.ts +107 -65
|
@@ -3,42 +3,49 @@ import { ESLintUtils } from "@typescript-eslint/utils";
|
|
|
3
3
|
import { TSESTree } from "@typescript-eslint/typescript-estree";
|
|
4
4
|
var ruleId = "no-side-effects";
|
|
5
5
|
var NO_SIDE_EFFECTS = "NO_SIDE_EFFECTS";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression && node.callee.object.type !== TSESTree.AST_NODE_TYPES.Identifier;
|
|
28
|
-
}
|
|
29
|
-
function isVariableDeclarationCallExpression(node, excludedIdentifiers) {
|
|
6
|
+
var isExpressionStatement = (node) => node.type === TSESTree.AST_NODE_TYPES.ExpressionStatement;
|
|
7
|
+
var isAwaitExpression = (statement) => isExpressionStatement(statement) && statement.expression.type === TSESTree.AST_NODE_TYPES.AwaitExpression;
|
|
8
|
+
var isVariableDeclarationAwaitExpression = (node) => node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration && node.declarations.length > 0 && node.declarations[0]?.init?.type === TSESTree.AST_NODE_TYPES.AwaitExpression;
|
|
9
|
+
var isNotValidVariableDeclaration = (node) => node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration && node.kind !== "const" && node.kind !== "using";
|
|
10
|
+
var isConstOrUsingVariableDeclaration = (node) => node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration && (node.kind === "const" || node.kind === "using");
|
|
11
|
+
var isControlFlowStatement = (node) => [
|
|
12
|
+
TSESTree.AST_NODE_TYPES.TryStatement,
|
|
13
|
+
TSESTree.AST_NODE_TYPES.IfStatement,
|
|
14
|
+
TSESTree.AST_NODE_TYPES.SwitchStatement,
|
|
15
|
+
TSESTree.AST_NODE_TYPES.ForStatement,
|
|
16
|
+
TSESTree.AST_NODE_TYPES.WhileStatement,
|
|
17
|
+
TSESTree.AST_NODE_TYPES.DoWhileStatement
|
|
18
|
+
].includes(node.type);
|
|
19
|
+
var isAssignmentExpression = (node) => node.type === TSESTree.AST_NODE_TYPES.ExpressionStatement && node.expression.type === TSESTree.AST_NODE_TYPES.AssignmentExpression;
|
|
20
|
+
var isIdentifierCallee = (node, excludedIdentifiers) => node.callee.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(node.callee.name);
|
|
21
|
+
var isMemberExpressionCallee = (node, excludedIdentifiers) => node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression && node.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier && node.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(`${node.callee.object.name}.${node.callee.property.name}`);
|
|
22
|
+
var isNonIdentifierObjectMemberExpressionCallee = (node) => node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression && node.callee.object.type !== TSESTree.AST_NODE_TYPES.Identifier;
|
|
23
|
+
var isCallExpressionCalleeMemberExpression = (statement, excludedIdentifiers) => isExpressionStatement(statement) && statement.expression.type === TSESTree.AST_NODE_TYPES.CallExpression && statement.expression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression && statement.expression.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier && statement.expression.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(statement.expression.callee.object.name) && !excludedIdentifiers.includes(
|
|
24
|
+
`${statement.expression.callee.object.name}.${statement.expression.callee.property.name}`
|
|
25
|
+
);
|
|
26
|
+
var isVariableDeclarationCallExpression = (node, excludedIdentifiers) => {
|
|
30
27
|
if (node.type !== TSESTree.AST_NODE_TYPES.VariableDeclaration || node.declarations.length === 0) {
|
|
31
28
|
return false;
|
|
32
29
|
}
|
|
30
|
+
if (node.kind === "const" || node.kind === "using") {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
33
|
const init = node.declarations[0]?.init;
|
|
34
34
|
if (init?.type !== TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
37
|
return isIdentifierCallee(init, excludedIdentifiers) || isMemberExpressionCallee(init, excludedIdentifiers) || isNonIdentifierObjectMemberExpressionCallee(init);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
38
|
+
};
|
|
39
|
+
var isExportNamedDeclarationWithSideEffects = (statement, excludedIdentifiers) => statement.type === TSESTree.AST_NODE_TYPES.ExportNamedDeclaration && statement.declaration !== null && (isVariableDeclarationAwaitExpression(statement.declaration) || isVariableDeclarationCallExpression(statement.declaration, excludedIdentifiers));
|
|
40
|
+
var isExpressionStatementWithSideEffects = (statement, excludedIdentifiers) => statement.type === TSESTree.AST_NODE_TYPES.ExpressionStatement && statement.expression.type === TSESTree.AST_NODE_TYPES.CallExpression && (statement.expression.callee.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(statement.expression.callee.name) || statement.expression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression && statement.expression.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier && statement.expression.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(
|
|
41
|
+
`${statement.expression.callee.object.name}.${statement.expression.callee.property.name}`
|
|
42
|
+
));
|
|
43
|
+
var hasSideEffects = (statement, excludedIdentifiers) => {
|
|
44
|
+
if (isConstOrUsingVariableDeclaration(statement)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return isAwaitExpression(statement) || isCallExpressionCalleeMemberExpression(statement, excludedIdentifiers) || isVariableDeclarationAwaitExpression(statement) || isVariableDeclarationCallExpression(statement, excludedIdentifiers) || isExportNamedDeclarationWithSideEffects(statement, excludedIdentifiers) || isExpressionStatementWithSideEffects(statement, excludedIdentifiers) || isControlFlowStatement(statement) || isNotValidVariableDeclaration(statement) || isAssignmentExpression(statement);
|
|
48
|
+
};
|
|
42
49
|
var createRule = ESLintUtils.RuleCreator((name) => name);
|
|
43
50
|
var rule = createRule({
|
|
44
51
|
name: ruleId,
|
|
@@ -92,4 +99,4 @@ export {
|
|
|
92
99
|
no_side_effects_default as default,
|
|
93
100
|
ruleId
|
|
94
101
|
};
|
|
95
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
102
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3JjL25vLXNpZGUtZWZmZWN0cy50cyJdLAogICJtYXBwaW5ncyI6ICI7QUFRQSxTQUFTLG1CQUFtQjtBQUM1QixTQUFTLGdCQUFnQjtBQU1sQixJQUFNLFNBQVM7QUFDdEIsSUFBTSxrQkFBa0I7QUFLeEIsSUFBTSx3QkFBd0IsQ0FBQyxTQUM3QixLQUFLLFNBQVMsU0FBUyxlQUFlO0FBR3hDLElBQU0sb0JBQW9CLENBQUMsY0FDekIsc0JBQXNCLFNBQVMsS0FBSyxVQUFVLFdBQVcsU0FBUyxTQUFTLGVBQWU7QUFHNUYsSUFBTSx1Q0FBdUMsQ0FBQyxTQUM1QyxLQUFLLFNBQVMsU0FBUyxlQUFlLHVCQUN0QyxLQUFLLGFBQWEsU0FBUyxLQUMzQixLQUFLLGFBQWEsQ0FBQyxHQUFHLE1BQU0sU0FBUyxTQUFTLGVBQWU7QUFHL0QsSUFBTSxnQ0FBZ0MsQ0FBQyxTQUNyQyxLQUFLLFNBQVMsU0FBUyxlQUFlLHVCQUF1QixLQUFLLFNBQVMsV0FBVyxLQUFLLFNBQVM7QUFHdEcsSUFBTSxvQ0FBb0MsQ0FBQyxTQUN6QyxLQUFLLFNBQVMsU0FBUyxlQUFlLHdCQUF3QixLQUFLLFNBQVMsV0FBVyxLQUFLLFNBQVM7QUFHdkcsSUFBTSx5QkFBeUIsQ0FBQyxTQUM5QjtBQUFBLEVBQ0UsU0FBUyxlQUFlO0FBQUEsRUFDeEIsU0FBUyxlQUFlO0FBQUEsRUFDeEIsU0FBUyxlQUFlO0FBQUEsRUFDeEIsU0FBUyxlQUFlO0FBQUEsRUFDeEIsU0FBUyxlQUFlO0FBQUEsRUFDeEIsU0FBUyxlQUFlO0FBQzFCLEVBQUUsU0FBUyxLQUFLLElBQUk7QUFHdEIsSUFBTSx5QkFBeUIsQ0FBQyxTQUM5QixLQUFLLFNBQVMsU0FBUyxlQUFlLHVCQUN0QyxLQUFLLFdBQVcsU0FBUyxTQUFTLGVBQWU7QUFLbkQsSUFBTSxxQkFBcUIsQ0FBQyxNQUErQix3QkFDekQsS0FBSyxPQUFPLFNBQVMsU0FBUyxlQUFlLGNBQWMsQ0FBQyxvQkFBb0IsU0FBUyxLQUFLLE9BQU8sSUFBSTtBQUczRyxJQUFNLDJCQUEyQixDQUFDLE1BQStCLHdCQUMvRCxLQUFLLE9BQU8sU0FBUyxTQUFTLGVBQWUsb0JBQzdDLEtBQUssT0FBTyxPQUFPLFNBQVMsU0FBUyxlQUFlLGNBQ3BELEtBQUssT0FBTyxTQUFTLFNBQVMsU0FBUyxlQUFlLGNBQ3RELENBQUMsb0JBQW9CLFNBQVMsR0FBRyxLQUFLLE9BQU8sT0FBTyxJQUFJLElBQUksS0FBSyxPQUFPLFNBQVMsSUFBSSxFQUFFO0FBR3pGLElBQU0sOENBQThDLENBQUMsU0FDbkQsS0FBSyxPQUFPLFNBQVMsU0FBUyxlQUFlLG9CQUM3QyxLQUFLLE9BQU8sT0FBTyxTQUFTLFNBQVMsZUFBZTtBQUd0RCxJQUFNLHlDQUF5QyxDQUFDLFdBQTBCLHdCQUN4RSxzQkFBc0IsU0FBUyxLQUMvQixVQUFVLFdBQVcsU0FBUyxTQUFTLGVBQWUsa0JBQ3RELFVBQVUsV0FBVyxPQUFPLFNBQVMsU0FBUyxlQUFlLG9CQUM3RCxVQUFVLFdBQVcsT0FBTyxPQUFPLFNBQVMsU0FBUyxlQUFlLGNBQ3BFLFVBQVUsV0FBVyxPQUFPLFNBQVMsU0FBUyxTQUFTLGVBQWUsY0FDdEUsQ0FBQyxvQkFBb0IsU0FBUyxVQUFVLFdBQVcsT0FBTyxPQUFPLElBQUksS0FDckUsQ0FBQyxvQkFBb0I7QUFBQSxFQUNuQixHQUFHLFVBQVUsV0FBVyxPQUFPLE9BQU8sSUFBSSxJQUFJLFVBQVUsV0FBVyxPQUFPLFNBQVMsSUFBSTtBQUN6RjtBQUdGLElBQU0sc0NBQXNDLENBQUMsTUFBcUIsd0JBQTJDO0FBQzNHLE1BQUksS0FBSyxTQUFTLFNBQVMsZUFBZSx1QkFBdUIsS0FBSyxhQUFhLFdBQVcsR0FBRztBQUMvRixXQUFPO0FBQUEsRUFDVDtBQUVBLE1BQUksS0FBSyxTQUFTLFdBQVcsS0FBSyxTQUFTLFNBQVM7QUFDbEQsV0FBTztBQUFBLEVBQ1Q7QUFFQSxRQUFNLE9BQU8sS0FBSyxhQUFhLENBQUMsR0FBRztBQUNuQyxNQUFJLE1BQU0sU0FBUyxTQUFTLGVBQWUsZ0JBQWdCO0FBQ3pELFdBQU87QUFBQSxFQUNUO0FBRUEsU0FDRSxtQkFBbUIsTUFBTSxtQkFBbUIsS0FDNUMseUJBQXlCLE1BQU0sbUJBQW1CLEtBQ2xELDRDQUE0QyxJQUFJO0FBRXBEO0FBR0EsSUFBTSwwQ0FBMEMsQ0FBQyxXQUEwQix3QkFDekUsVUFBVSxTQUFTLFNBQVMsZUFBZSwwQkFDM0MsVUFBVSxnQkFBZ0IsU0FDekIscUNBQXFDLFVBQVUsV0FBVyxLQUN6RCxvQ0FBb0MsVUFBVSxhQUFhLG1CQUFtQjtBQUdsRixJQUFNLHVDQUF1QyxDQUFDLFdBQTBCLHdCQUN0RSxVQUFVLFNBQVMsU0FBUyxlQUFlLHVCQUMzQyxVQUFVLFdBQVcsU0FBUyxTQUFTLGVBQWUsbUJBQ3BELFVBQVUsV0FBVyxPQUFPLFNBQVMsU0FBUyxlQUFlLGNBQzdELENBQUMsb0JBQW9CLFNBQVMsVUFBVSxXQUFXLE9BQU8sSUFBSSxLQUM3RCxVQUFVLFdBQVcsT0FBTyxTQUFTLFNBQVMsZUFBZSxvQkFDNUQsVUFBVSxXQUFXLE9BQU8sT0FBTyxTQUFTLFNBQVMsZUFBZSxjQUNwRSxVQUFVLFdBQVcsT0FBTyxTQUFTLFNBQVMsU0FBUyxlQUFlLGNBQ3RFLENBQUMsb0JBQW9CO0FBQUEsRUFDbkIsR0FBRyxVQUFVLFdBQVcsT0FBTyxPQUFPLElBQUksSUFBSSxVQUFVLFdBQVcsT0FBTyxTQUFTLElBQUk7QUFDekY7QUFHTixJQUFNLGlCQUFpQixDQUFDLFdBQTBCLHdCQUEyQztBQUMzRixNQUFJLGtDQUFrQyxTQUFTLEdBQUc7QUFDaEQsV0FBTztBQUFBLEVBQ1Q7QUFFQSxTQUNFLGtCQUFrQixTQUFTLEtBQzNCLHVDQUF1QyxXQUFXLG1CQUFtQixLQUNyRSxxQ0FBcUMsU0FBUyxLQUM5QyxvQ0FBb0MsV0FBVyxtQkFBbUIsS0FDbEUsd0NBQXdDLFdBQVcsbUJBQW1CLEtBQ3RFLHFDQUFxQyxXQUFXLG1CQUFtQixLQUNuRSx1QkFBdUIsU0FBUyxLQUNoQyw4QkFBOEIsU0FBUyxLQUN2Qyx1QkFBdUIsU0FBUztBQUVwQztBQUVBLElBQU0sYUFBeUQsWUFBWSxZQUFZLENBQUMsU0FBUyxJQUFJO0FBRXJHLElBQU0sT0FBc0MsV0FBVztBQUFBLEVBQ3JELE1BQU07QUFBQSxFQUNOLE1BQU07QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxNQUNKLGFBQWE7QUFBQSxJQUNmO0FBQUEsSUFDQSxRQUFRO0FBQUEsTUFDTjtBQUFBLFFBQ0UsTUFBTTtBQUFBLFFBQ04sWUFBWTtBQUFBLFVBQ1YscUJBQXFCO0FBQUEsWUFDbkIsTUFBTTtBQUFBLFlBQ04sT0FBTyxFQUFFLE1BQU0sU0FBUztBQUFBLFVBQzFCO0FBQUEsUUFDRjtBQUFBLFFBQ0Esc0JBQXNCO0FBQUEsTUFDeEI7QUFBQSxJQUNGO0FBQUEsSUFDQSxVQUFVO0FBQUEsTUFDUixDQUFDLGVBQWUsR0FBRztBQUFBLElBQ3JCO0FBQUEsRUFDRjtBQUFBLEVBQ0EsZ0JBQWdCLENBQUMsRUFBRSxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUFBLEVBQzlDLE9BQU8sU0FBUztBQUNkLFVBQU0sVUFBdUIsUUFBUSxRQUFRLENBQUM7QUFDOUMsVUFBTSxzQkFBc0IsUUFBUSxvQkFBb0IsU0FBUyxJQUFJLFFBQVEsc0JBQXNCLENBQUM7QUFDcEcsV0FBTztBQUFBLE1BQ0wsUUFBUSxNQUF3QjtBQUM5QixjQUFNLFlBQVksS0FBSyxLQUFLO0FBQUEsVUFDMUIsQ0FBQyxjQUNDLFVBQVUsU0FBUyxTQUFTLGVBQWUsMEJBQzNDLFVBQVUsU0FBUyxTQUFTLGVBQWUsNEJBQzNDLFVBQVUsU0FBUyxTQUFTLGVBQWU7QUFBQSxRQUMvQztBQUVBLFlBQUksQ0FBQyxXQUFXO0FBQ2Q7QUFBQSxRQUNGO0FBRUEsYUFBSyxLQUFLLFFBQVEsQ0FBQyxjQUE2QjtBQUM5QyxjQUFJLGVBQWUsV0FBVyxtQkFBbUIsR0FBRztBQUNsRCxvQkFBUSxPQUFPO0FBQUEsY0FDYixNQUFNO0FBQUEsY0FDTixXQUFXO0FBQUEsWUFDYixDQUFDO0FBQUEsVUFDSDtBQUFBLFFBQ0YsQ0FBQztBQUFBLE1BQ0g7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUNGLENBQUM7QUFFRCxJQUFPLDBCQUFROyIsCiAgIm5hbWVzIjogW10KfQo=
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@checkdigit/eslint-plugin","version":"7.12.1-PR.120-
|
|
1
|
+
{"name":"@checkdigit/eslint-plugin","version":"7.12.1-PR.120-20b8","description":"Check Digit eslint plugins","keywords":["eslint","eslintplugin"],"homepage":"https://github.com/checkdigit/eslint-plugin#readme","bugs":{"url":"https://github.com/checkdigit/eslint-plugin/issues"},"repository":{"type":"git","url":"https://github.com/checkdigit/eslint-plugin"},"license":"MIT","author":"Check Digit, LLC","sideEffects":false,"type":"module","exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist-mjs/index.mjs","default":"./dist-mjs/index.mjs"}},"files":["src","dist-types","dist-mjs","!src/**/test/**","!src/**/*.test.ts","!src/**/*.spec.ts","!dist-types/**/test/**","!dist-types/**/*.test.d.ts","!dist-types/**/*.spec.d.ts","!dist-mjs/**/test/**","!dist-mjs/**/*.test.mjs","!dist-mjs/**/*.spec.mjs","SECURITY.md"],"scripts":{"build:dist-mjs":"rimraf dist-mjs && npx builder --type=module --sourceMap --outDir=dist-mjs && node dist-mjs/index.mjs","build:dist-types":"rimraf dist-types && npx builder --type=types --outDir=dist-types","ci:compile":"tsc --noEmit","ci:coverage":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=true","ci:lint":"npm run lint","ci:style":"npm run prettier","ci:test":"NODE_OPTIONS=\"--disable-warning ExperimentalWarning --experimental-vm-modules\" jest --coverage=false","lint":"eslint --max-warnings 0 .","lint:fix":"eslint --max-warnings 0 --fix .","prepare":"","prepublishOnly":"npm run build:dist-types && npm run build:dist-mjs","prettier":"prettier --ignore-path .gitignore --list-different .","prettier:fix":"prettier --ignore-path .gitignore --write .","test":"npm run ci:compile && npm run ci:test && npm run ci:lint && npm run ci:style"},"prettier":"@checkdigit/prettier-config","jest":{"preset":"@checkdigit/jest-config"},"dependencies":{"@typescript-eslint/type-utils":"^8.23.0","@typescript-eslint/utils":"^8.23.0","http-status-codes":"^2.3.0","ts-api-utils":"^2.0.1"},"devDependencies":{"@checkdigit/jest-config":"^6.0.2","@checkdigit/prettier-config":"^6.1.0","@checkdigit/typescript-config":"^9.0.0","@eslint/js":"^9.19.0","@types/eslint":"^9.6.1","@types/eslint-config-prettier":"^6.11.3","@typescript-eslint/parser":"^8.23.0","@typescript-eslint/rule-tester":"^8.23.0","eslint":"^9.19.0","eslint-config-prettier":"^10.0.1","eslint-import-resolver-typescript":"^3.7.0","eslint-plugin-eslint-plugin":"^6.4.0","eslint-plugin-import":"^2.31.0","eslint-plugin-no-only-tests":"^3.3.0","eslint-plugin-no-secrets":"^2.2.1","eslint-plugin-node":"^11.1.0","eslint-plugin-sonarjs":"1.0.4","rimraf":"^6.0.1","typescript-eslint":"^8.23.0"},"peerDependencies":{"eslint":">=9 <10"},"engines":{"node":">=20.17"}}
|
package/src/no-side-effects.ts
CHANGED
|
@@ -16,69 +16,86 @@ interface RuleOptions {
|
|
|
16
16
|
export const ruleId = 'no-side-effects';
|
|
17
17
|
const NO_SIDE_EFFECTS = 'NO_SIDE_EFFECTS';
|
|
18
18
|
|
|
19
|
-
// Type
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
19
|
+
// Type guards
|
|
20
|
+
|
|
21
|
+
// Checks if a node is an ExpressionStatement
|
|
22
|
+
const isExpressionStatement = (node: TSESTree.Node): node is TSESTree.ExpressionStatement =>
|
|
23
|
+
node.type === TSESTree.AST_NODE_TYPES.ExpressionStatement;
|
|
24
|
+
|
|
25
|
+
// Checks if a statement is an AwaitExpression
|
|
26
|
+
const isAwaitExpression = (statement: TSESTree.Node): boolean =>
|
|
27
|
+
isExpressionStatement(statement) && statement.expression.type === TSESTree.AST_NODE_TYPES.AwaitExpression;
|
|
28
|
+
|
|
29
|
+
// Checks if a node is a VariableDeclaration with an AwaitExpression
|
|
30
|
+
const isVariableDeclarationAwaitExpression = (node: TSESTree.Node): boolean =>
|
|
31
|
+
node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration &&
|
|
32
|
+
node.declarations.length > 0 &&
|
|
33
|
+
node.declarations[0]?.init?.type === TSESTree.AST_NODE_TYPES.AwaitExpression;
|
|
34
|
+
|
|
35
|
+
// Checks if a node is a VariableDeclaration that is not const or using
|
|
36
|
+
const isNotValidVariableDeclaration = (node: TSESTree.Node): boolean =>
|
|
37
|
+
node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration && node.kind !== 'const' && node.kind !== 'using';
|
|
38
|
+
|
|
39
|
+
// Checks if a node is a VariableDeclaration that is const or using
|
|
40
|
+
const isConstOrUsingVariableDeclaration = (node: TSESTree.Node): boolean =>
|
|
41
|
+
node.type === TSESTree.AST_NODE_TYPES.VariableDeclaration && (node.kind === 'const' || node.kind === 'using');
|
|
42
|
+
|
|
43
|
+
// Checks if a node is a control flow statement
|
|
44
|
+
const isControlFlowStatement = (node: TSESTree.Node): boolean =>
|
|
45
|
+
[
|
|
46
|
+
TSESTree.AST_NODE_TYPES.TryStatement,
|
|
47
|
+
TSESTree.AST_NODE_TYPES.IfStatement,
|
|
48
|
+
TSESTree.AST_NODE_TYPES.SwitchStatement,
|
|
49
|
+
TSESTree.AST_NODE_TYPES.ForStatement,
|
|
50
|
+
TSESTree.AST_NODE_TYPES.WhileStatement,
|
|
51
|
+
TSESTree.AST_NODE_TYPES.DoWhileStatement,
|
|
52
|
+
].includes(node.type);
|
|
53
|
+
|
|
54
|
+
// Checks if a node is an AssignmentExpression
|
|
55
|
+
const isAssignmentExpression = (node: TSESTree.Node): boolean =>
|
|
56
|
+
node.type === TSESTree.AST_NODE_TYPES.ExpressionStatement &&
|
|
57
|
+
node.expression.type === TSESTree.AST_NODE_TYPES.AssignmentExpression;
|
|
58
|
+
|
|
59
|
+
// Helper functions
|
|
60
|
+
|
|
61
|
+
// Checks if the callee is an identifier and not excluded
|
|
62
|
+
const isIdentifierCallee = (node: TSESTree.CallExpression, excludedIdentifiers: string[]): boolean =>
|
|
63
|
+
node.callee.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(node.callee.name);
|
|
64
|
+
|
|
65
|
+
// Checks if the callee is a member expression and not excluded
|
|
66
|
+
const isMemberExpressionCallee = (node: TSESTree.CallExpression, excludedIdentifiers: string[]): boolean =>
|
|
67
|
+
node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
68
|
+
node.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
69
|
+
node.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
70
|
+
!excludedIdentifiers.includes(`${node.callee.object.name}.${node.callee.property.name}`);
|
|
71
|
+
|
|
72
|
+
// Checks if the callee is a member expression with a non-identifier object
|
|
73
|
+
const isNonIdentifierObjectMemberExpressionCallee = (node: TSESTree.CallExpression): boolean =>
|
|
74
|
+
node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
75
|
+
node.callee.object.type !== TSESTree.AST_NODE_TYPES.Identifier;
|
|
76
|
+
|
|
77
|
+
// Checks if a statement is a CallExpression with a member expression callee
|
|
78
|
+
const isCallExpressionCalleeMemberExpression = (statement: TSESTree.Node, excludedIdentifiers: string[]): boolean =>
|
|
79
|
+
isExpressionStatement(statement) &&
|
|
80
|
+
statement.expression.type === TSESTree.AST_NODE_TYPES.CallExpression &&
|
|
81
|
+
statement.expression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
82
|
+
statement.expression.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
83
|
+
statement.expression.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
84
|
+
!excludedIdentifiers.includes(statement.expression.callee.object.name) &&
|
|
85
|
+
!excludedIdentifiers.includes(
|
|
86
|
+
`${statement.expression.callee.object.name}.${statement.expression.callee.property.name}`,
|
|
50
87
|
);
|
|
51
|
-
}
|
|
52
88
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
return node.callee.type === TSESTree.AST_NODE_TYPES.Identifier && !excludedIdentifiers.includes(node.callee.name);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Helper function to check if the callee is a member expression and not excluded
|
|
59
|
-
function isMemberExpressionCallee(node: TSESTree.CallExpression, excludedIdentifiers: string[]): boolean {
|
|
60
|
-
return (
|
|
61
|
-
node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
62
|
-
node.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
63
|
-
node.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
64
|
-
!excludedIdentifiers.includes(`${node.callee.object.name}.${node.callee.property.name}`)
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Helper function to check if the callee is a member expression with a non-identifier object
|
|
69
|
-
function isNonIdentifierObjectMemberExpressionCallee(node: TSESTree.CallExpression): boolean {
|
|
70
|
-
return (
|
|
71
|
-
node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
72
|
-
node.callee.object.type !== TSESTree.AST_NODE_TYPES.Identifier
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// To check if it is a variable declaration with a call expression i.e const configuration = new Class(); or Member Expressions i.e const server = http.createServer();
|
|
77
|
-
function isVariableDeclarationCallExpression(node: TSESTree.Node, excludedIdentifiers: string[]): boolean {
|
|
89
|
+
// Checks if a node is a VariableDeclaration with a CallExpression
|
|
90
|
+
const isVariableDeclarationCallExpression = (node: TSESTree.Node, excludedIdentifiers: string[]): boolean => {
|
|
78
91
|
if (node.type !== TSESTree.AST_NODE_TYPES.VariableDeclaration || node.declarations.length === 0) {
|
|
79
92
|
return false;
|
|
80
93
|
}
|
|
81
94
|
|
|
95
|
+
if (node.kind === 'const' || node.kind === 'using') {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
82
99
|
const init = node.declarations[0]?.init;
|
|
83
100
|
if (init?.type !== TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
84
101
|
return false;
|
|
@@ -89,21 +106,46 @@ function isVariableDeclarationCallExpression(node: TSESTree.Node, excludedIdenti
|
|
|
89
106
|
isMemberExpressionCallee(init, excludedIdentifiers) ||
|
|
90
107
|
isNonIdentifierObjectMemberExpressionCallee(init)
|
|
91
108
|
);
|
|
92
|
-
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// Checks if an ExportNamedDeclaration has side effects
|
|
112
|
+
const isExportNamedDeclarationWithSideEffects = (statement: TSESTree.Node, excludedIdentifiers: string[]): boolean =>
|
|
113
|
+
statement.type === TSESTree.AST_NODE_TYPES.ExportNamedDeclaration &&
|
|
114
|
+
statement.declaration !== null &&
|
|
115
|
+
(isVariableDeclarationAwaitExpression(statement.declaration) ||
|
|
116
|
+
isVariableDeclarationCallExpression(statement.declaration, excludedIdentifiers));
|
|
117
|
+
|
|
118
|
+
// Checks if an ExpressionStatement has side effects
|
|
119
|
+
const isExpressionStatementWithSideEffects = (statement: TSESTree.Node, excludedIdentifiers: string[]): boolean =>
|
|
120
|
+
statement.type === TSESTree.AST_NODE_TYPES.ExpressionStatement &&
|
|
121
|
+
statement.expression.type === TSESTree.AST_NODE_TYPES.CallExpression &&
|
|
122
|
+
((statement.expression.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
123
|
+
!excludedIdentifiers.includes(statement.expression.callee.name)) ||
|
|
124
|
+
(statement.expression.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression &&
|
|
125
|
+
statement.expression.callee.object.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
126
|
+
statement.expression.callee.property.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
|
127
|
+
!excludedIdentifiers.includes(
|
|
128
|
+
`${statement.expression.callee.object.name}.${statement.expression.callee.property.name}`,
|
|
129
|
+
)));
|
|
130
|
+
|
|
131
|
+
// Checks if a statement has side effects
|
|
132
|
+
const hasSideEffects = (statement: TSESTree.Node, excludedIdentifiers: string[]): boolean => {
|
|
133
|
+
if (isConstOrUsingVariableDeclaration(statement)) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
93
136
|
|
|
94
|
-
// Helper function to check if a given AST node (statement) has any side effects that should be reported
|
|
95
|
-
function hasSideEffects(statement: TSESTree.Node, excludedIdentifiers: string[]): boolean {
|
|
96
137
|
return (
|
|
97
138
|
isAwaitExpression(statement) ||
|
|
98
139
|
isCallExpressionCalleeMemberExpression(statement, excludedIdentifiers) ||
|
|
99
140
|
isVariableDeclarationAwaitExpression(statement) ||
|
|
100
141
|
isVariableDeclarationCallExpression(statement, excludedIdentifiers) ||
|
|
101
|
-
(statement
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
142
|
+
isExportNamedDeclarationWithSideEffects(statement, excludedIdentifiers) ||
|
|
143
|
+
isExpressionStatementWithSideEffects(statement, excludedIdentifiers) ||
|
|
144
|
+
isControlFlowStatement(statement) ||
|
|
145
|
+
isNotValidVariableDeclaration(statement) ||
|
|
146
|
+
isAssignmentExpression(statement)
|
|
105
147
|
);
|
|
106
|
-
}
|
|
148
|
+
};
|
|
107
149
|
|
|
108
150
|
const createRule: ReturnType<typeof ESLintUtils.RuleCreator> = ESLintUtils.RuleCreator((name) => name);
|
|
109
151
|
|