eslint-plugin-th-rules 3.1.8 → 3.2.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/plugin.d.ts +6 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/dist/rules/no-destructuring.d.ts.map +1 -1
- package/dist/rules/no-destructuring.js +7 -6
- package/dist/rules/no-explicit-nil-compare.d.ts +6 -0
- package/dist/rules/no-explicit-nil-compare.d.ts.map +1 -0
- package/dist/rules/no-explicit-nil-compare.js +82 -0
- package/package.json +1 -1
package/dist/plugin.d.ts
CHANGED
|
@@ -36,6 +36,9 @@ export declare const rules: {
|
|
|
36
36
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
37
37
|
name: string;
|
|
38
38
|
};
|
|
39
|
+
noExplicitNilCompare: import("@typescript-eslint/utils/ts-eslint").RuleModule<"useIsNull" | "useIsUndefined", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
40
|
+
name: string;
|
|
41
|
+
};
|
|
39
42
|
};
|
|
40
43
|
declare const plugin: {
|
|
41
44
|
rules: {
|
|
@@ -76,6 +79,9 @@ declare const plugin: {
|
|
|
76
79
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
77
80
|
name: string;
|
|
78
81
|
};
|
|
82
|
+
noExplicitNilCompare: import("@typescript-eslint/utils/ts-eslint").RuleModule<"useIsNull" | "useIsUndefined", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
83
|
+
name: string;
|
|
84
|
+
};
|
|
79
85
|
};
|
|
80
86
|
};
|
|
81
87
|
export default plugin;
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAUjB,CAAC;AAEF,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAY,CAAC;AACzB,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -2,6 +2,7 @@ import noBooleanCoercion from './rules/no-boolean-coercion.js';
|
|
|
2
2
|
import noComments from './rules/no-comments.js';
|
|
3
3
|
import noDefaultExport from './rules/no-default-export.js';
|
|
4
4
|
import noDestructuring from './rules/no-destructuring.js';
|
|
5
|
+
import noExplicitNilCompare from './rules/no-explicit-nil-compare.js';
|
|
5
6
|
import preferIsEmpty from './rules/prefer-is-empty.js';
|
|
6
7
|
import schemasInSchemasFile from './rules/schemas-in-schemas-file.js';
|
|
7
8
|
import topLevelFunctions from './rules/top-level-functions.js';
|
|
@@ -15,6 +16,7 @@ export const rules = {
|
|
|
15
16
|
schemasInSchemasFile,
|
|
16
17
|
topLevelFunctions,
|
|
17
18
|
typesInDts,
|
|
19
|
+
noExplicitNilCompare,
|
|
18
20
|
};
|
|
19
21
|
const plugin = { rules };
|
|
20
22
|
export default plugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-destructuring.d.ts","sourceRoot":"","sources":["../../src/rules/no-destructuring.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-destructuring.d.ts","sourceRoot":"","sources":["../../src/rules/no-destructuring.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAItF,QAAA,MAAM,eAAe;;;;;CAyInB,CAAC;AACH,eAAe,eAAe,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable new-cap */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
+
import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
|
|
2
4
|
const MAX_TAB_COUNT = 3;
|
|
3
5
|
const noDestructuring = ESLintUtils.RuleCreator(() => 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/no-destructuring.md')({
|
|
4
6
|
name: 'no-destructuring',
|
|
@@ -32,19 +34,18 @@ const noDestructuring = ESLintUtils.RuleCreator(() => 'https://github.com/tomerh
|
|
|
32
34
|
create(context, [options]) {
|
|
33
35
|
const MAX_VARIABLES = options.maximumDestructuredVariables ?? 2;
|
|
34
36
|
const MAX_LINE_LENGTH = options.maximumLineLength ?? 100;
|
|
35
|
-
const sourceCode = context.getSourceCode();
|
|
36
37
|
function reportIfNeeded(patternNode, reportNode = patternNode) {
|
|
37
|
-
if (patternNode?.type !==
|
|
38
|
+
if (patternNode?.type !== AST_NODE_TYPES.ObjectPattern || !patternNode.loc) {
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
const startLine = patternNode.loc.start.line;
|
|
41
42
|
const endLine = patternNode.loc.end.line;
|
|
42
|
-
const lineText = sourceCode.lines[startLine - 1] ?? '';
|
|
43
|
+
const lineText = context.sourceCode.lines[startLine - 1] ?? '';
|
|
43
44
|
const indentCount = lineText.search(/\S|$/);
|
|
44
45
|
const propertyCount = patternNode.properties?.length ?? 0;
|
|
45
46
|
let maxSpannedLineLength = 0;
|
|
46
47
|
for (let i = startLine; i <= endLine; i++) {
|
|
47
|
-
const t = sourceCode.lines[i - 1] ?? '';
|
|
48
|
+
const t = context.sourceCode.lines[i - 1] ?? '';
|
|
48
49
|
if (t.length > maxSpannedLineLength) {
|
|
49
50
|
maxSpannedLineLength = t.length;
|
|
50
51
|
}
|
|
@@ -83,7 +84,7 @@ const noDestructuring = ESLintUtils.RuleCreator(() => 'https://github.com/tomerh
|
|
|
83
84
|
if (!p) {
|
|
84
85
|
continue;
|
|
85
86
|
}
|
|
86
|
-
if (p.type ===
|
|
87
|
+
if (p.type === AST_NODE_TYPES.AssignmentPattern) {
|
|
87
88
|
reportIfNeeded(p.left, p);
|
|
88
89
|
continue;
|
|
89
90
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
declare const noExplicitNilCompare: ESLintUtils.RuleModule<"useIsNull" | "useIsUndefined", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export default noExplicitNilCompare;
|
|
6
|
+
//# sourceMappingURL=no-explicit-nil-compare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-explicit-nil-compare.d.ts","sourceRoot":"","sources":["../../src/rules/no-explicit-nil-compare.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAItF,QAAA,MAAM,oBAAoB;;CAmFxB,CAAC;AAEH,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/* eslint-disable new-cap */
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
|
|
6
|
+
const createRule = ESLintUtils.RuleCreator(() => 'https://github.com/tomerh2001/eslint-plugin-th-rules/blob/main/docs/rules/no-explicit-nil-compare.md');
|
|
7
|
+
const noExplicitNilCompare = createRule({
|
|
8
|
+
name: 'no-explicit-nil-compare',
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'problem',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Disallow direct comparisons to null or undefined. Use _.isNull(x) / _.isUndefined(x) instead.',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
useIsNull: 'Use _.isNull({{value}}) instead of comparing directly to null.',
|
|
18
|
+
useIsUndefined: 'Use _.isUndefined({{value}}) instead of comparing directly to undefined.',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
/** Ensure lodash default import exists */
|
|
24
|
+
function ensureLodashImport(fixer) {
|
|
25
|
+
const existingImport = context.sourceCode.ast.body.find((node) => node.type === AST_NODE_TYPES.ImportDeclaration && node.source.value === 'lodash');
|
|
26
|
+
if (existingImport)
|
|
27
|
+
return null;
|
|
28
|
+
return fixer.insertTextBeforeRange([0, 0], `import _ from 'lodash';\n`);
|
|
29
|
+
}
|
|
30
|
+
function isNullLiteral(node) {
|
|
31
|
+
return node.type === AST_NODE_TYPES.Literal && _.isNull(node.value);
|
|
32
|
+
}
|
|
33
|
+
function isUndefinedIdentifier(node) {
|
|
34
|
+
return node.type === AST_NODE_TYPES.Identifier && node.name === 'undefined';
|
|
35
|
+
}
|
|
36
|
+
function reportComparison(node, left, right) {
|
|
37
|
+
let targetNode;
|
|
38
|
+
let isNull = false;
|
|
39
|
+
const isNegated = node.operator === '!=' || node.operator === '!==';
|
|
40
|
+
if (isNullLiteral(right)) {
|
|
41
|
+
targetNode = left;
|
|
42
|
+
isNull = true;
|
|
43
|
+
}
|
|
44
|
+
else if (isNullLiteral(left)) {
|
|
45
|
+
targetNode = right;
|
|
46
|
+
isNull = true;
|
|
47
|
+
}
|
|
48
|
+
else if (isUndefinedIdentifier(right)) {
|
|
49
|
+
targetNode = left;
|
|
50
|
+
}
|
|
51
|
+
else if (isUndefinedIdentifier(left)) {
|
|
52
|
+
targetNode = right;
|
|
53
|
+
}
|
|
54
|
+
if (!targetNode)
|
|
55
|
+
return;
|
|
56
|
+
const text = context.sourceCode.getText(targetNode);
|
|
57
|
+
const positive = isNull ? `_.isNull(${text})` : `_.isUndefined(${text})`;
|
|
58
|
+
const replacement = isNegated ? `!${positive}` : positive;
|
|
59
|
+
context.report({
|
|
60
|
+
node,
|
|
61
|
+
messageId: isNull ? 'useIsNull' : 'useIsUndefined',
|
|
62
|
+
data: { value: text },
|
|
63
|
+
fix(fixer) {
|
|
64
|
+
const fixes = [];
|
|
65
|
+
const importFix = ensureLodashImport(fixer);
|
|
66
|
+
if (importFix)
|
|
67
|
+
fixes.push(importFix);
|
|
68
|
+
fixes.push(fixer.replaceText(node, replacement));
|
|
69
|
+
return fixes;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
BinaryExpression(node) {
|
|
75
|
+
if (!['==', '===', '!=', '!=='].includes(node.operator))
|
|
76
|
+
return;
|
|
77
|
+
reportComparison(node, node.left, node.right);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
export default noExplicitNilCompare;
|