@blumintinc/eslint-plugin-blumint 1.9.1 → 1.11.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/README.md +99 -83
- package/lib/index.js +16 -1
- package/lib/rules/class-methods-read-top-to-bottom.js +10 -0
- package/lib/rules/consistent-callback-naming.js +20 -16
- package/lib/rules/enforce-assert-throws.js +10 -5
- package/lib/rules/enforce-boolean-naming-prefixes.d.ts +7 -0
- package/lib/rules/enforce-boolean-naming-prefixes.js +462 -0
- package/lib/rules/enforce-callable-types.d.ts +1 -1
- package/lib/rules/enforce-callable-types.js +13 -13
- package/lib/rules/enforce-callback-memo.js +6 -3
- package/lib/rules/enforce-centralized-mock-firestore.js +8 -6
- package/lib/rules/enforce-css-media-queries.js +3 -3
- package/lib/rules/enforce-dynamic-file-naming.d.ts +3 -0
- package/lib/rules/enforce-dynamic-file-naming.js +82 -0
- package/lib/rules/enforce-dynamic-imports.js +1 -1
- package/lib/rules/enforce-firestore-doc-ref-generic.js +16 -12
- package/lib/rules/enforce-firestore-facade.js +7 -3
- package/lib/rules/enforce-firestore-path-utils.js +5 -2
- package/lib/rules/enforce-id-capitalization.js +59 -0
- package/lib/rules/enforce-identifiable-firestore-type.js +17 -10
- package/lib/rules/enforce-memoize-async.js +2 -2
- package/lib/rules/enforce-positive-naming.js +71 -27
- package/lib/rules/enforce-props-argument-name.js +31 -9
- package/lib/rules/enforce-realtimedb-path-utils.js +2 -1
- package/lib/rules/enforce-singular-type-names.js +4 -1
- package/lib/rules/enforce-timestamp-now.js +3 -4
- package/lib/rules/enforce-verb-noun-naming.js +18 -8
- package/lib/rules/ensure-pointer-events-none.js +20 -11
- package/lib/rules/extract-global-constants.js +25 -10
- package/lib/rules/fast-deep-equal-over-microdiff.d.ts +3 -0
- package/lib/rules/fast-deep-equal-over-microdiff.js +182 -0
- package/lib/rules/key-only-outermost-element.js +13 -7
- package/lib/rules/no-always-true-false-conditions.js +189 -5
- package/lib/rules/no-async-array-filter.js +1 -1
- package/lib/rules/no-circular-references.js +121 -59
- package/lib/rules/no-complex-cloud-params.js +4 -2
- package/lib/rules/no-entire-object-hook-deps.js +113 -29
- package/lib/rules/no-explicit-return-type.js +3 -2
- package/lib/rules/no-firestore-jest-mock.js +1 -1
- package/lib/rules/no-firestore-object-arrays.js +2 -1
- package/lib/rules/no-hungarian.js +18 -1
- package/lib/rules/no-jsx-in-hooks.js +4 -3
- package/lib/rules/no-margin-properties.d.ts +1 -0
- package/lib/rules/no-margin-properties.js +314 -0
- package/lib/rules/no-mixed-firestore-transactions.js +8 -4
- package/lib/rules/no-mock-firebase-admin.js +6 -1
- package/lib/rules/no-object-values-on-strings.js +28 -10
- package/lib/rules/no-type-assertion-returns.js +47 -6
- package/lib/rules/no-unnecessary-destructuring.js +1 -1
- package/lib/rules/no-unnecessary-verb-suffix.js +0 -31
- package/lib/rules/no-unused-props.js +10 -7
- package/lib/rules/no-unused-usestate.js +19 -6
- package/lib/rules/omit-index-html.js +1 -1
- package/lib/rules/prefer-batch-operations.js +19 -6
- package/lib/rules/prefer-clone-deep.js +16 -11
- package/lib/rules/prefer-destructuring-no-class.js +19 -0
- package/lib/rules/prefer-fragment-component.js +19 -16
- package/lib/rules/prefer-global-router-state-key.js +6 -4
- package/lib/rules/prefer-settings-object.js +1 -1
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.d.ts +8 -0
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +180 -0
- package/lib/rules/react-usememo-should-be-component.js +139 -17
- package/lib/rules/require-hooks-default-params.js +25 -15
- package/lib/rules/require-usememo-object-literals.js +3 -2
- package/lib/rules/semantic-function-prefixes.js +15 -3
- package/lib/rules/sync-onwrite-name-func.js +5 -3
- package/lib/utils/ASTHelpers.js +6 -2
- package/lib/utils/graph/ClassGraphBuilder.js +4 -1
- package/lib/utils/graph/ClassGraphSorterReadability.js +3 -1
- package/package.json +3 -3
- package/lib/rules/require-image-overlayed.d.ts +0 -7
- package/lib/rules/require-image-overlayed.js +0 -82
|
@@ -22,6 +22,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
25
26
|
const createRule_1 = require("../utils/createRule");
|
|
26
27
|
const utils_1 = require("@typescript-eslint/utils");
|
|
27
28
|
const ts = __importStar(require("typescript"));
|
|
@@ -60,10 +61,12 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
60
61
|
// Check for JSX element types
|
|
61
62
|
if (ts.isTypeAliasDeclaration(declaration)) {
|
|
62
63
|
const typeText = declaration.type.getText();
|
|
63
|
-
return typeText.includes('JSX.Element') ||
|
|
64
|
+
return (typeText.includes('JSX.Element') ||
|
|
65
|
+
typeText.includes('ReactElement'));
|
|
64
66
|
}
|
|
65
67
|
// Check for class/interface component patterns
|
|
66
|
-
if (ts.isClassDeclaration(declaration) ||
|
|
68
|
+
if (ts.isClassDeclaration(declaration) ||
|
|
69
|
+
ts.isInterfaceDeclaration(declaration)) {
|
|
67
70
|
const name = declaration.name?.text ?? '';
|
|
68
71
|
return (name.includes('Component') ||
|
|
69
72
|
name.includes('Element') ||
|
|
@@ -74,10 +77,10 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
74
77
|
});
|
|
75
78
|
// Check if the type itself is a component or element type
|
|
76
79
|
const typeString = checker.typeToString(type);
|
|
77
|
-
const isComponentType =
|
|
80
|
+
const isComponentType = typeString.includes('JSX.Element') ||
|
|
78
81
|
typeString.includes('ReactElement') ||
|
|
79
82
|
typeString.includes('Component') ||
|
|
80
|
-
typeString.includes('FC')
|
|
83
|
+
typeString.includes('FC');
|
|
81
84
|
return isComponent || isComponentType;
|
|
82
85
|
}
|
|
83
86
|
function isPascalCase(str) {
|
|
@@ -161,7 +164,8 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
161
164
|
}
|
|
162
165
|
// Skip autofixing for class parameters and getters
|
|
163
166
|
const parent = node.parent;
|
|
164
|
-
if (parent?.type === utils_1.AST_NODE_TYPES.PropertyDefinition ||
|
|
167
|
+
if (parent?.type === utils_1.AST_NODE_TYPES.PropertyDefinition ||
|
|
168
|
+
parent?.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
|
|
165
169
|
context.report({
|
|
166
170
|
node,
|
|
167
171
|
messageId: 'callbackFunctionPrefix',
|
|
@@ -170,7 +174,7 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
170
174
|
}
|
|
171
175
|
// Get all references to this variable
|
|
172
176
|
const scope = context.getScope();
|
|
173
|
-
const variable = scope.variables.find(v => v.name === functionName);
|
|
177
|
+
const variable = scope.variables.find((v) => v.name === functionName);
|
|
174
178
|
const references = new Set(variable?.references ?? []);
|
|
175
179
|
// Get references from all scopes
|
|
176
180
|
const allScopes = [scope];
|
|
@@ -182,16 +186,16 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
182
186
|
// Get references from all scopes and their children
|
|
183
187
|
for (const s of allScopes) {
|
|
184
188
|
// Get references from current scope
|
|
185
|
-
const currentVar = s.variables.find(v => v.name === functionName);
|
|
189
|
+
const currentVar = s.variables.find((v) => v.name === functionName);
|
|
186
190
|
if (currentVar) {
|
|
187
|
-
currentVar.references.forEach(ref => references.add(ref));
|
|
191
|
+
currentVar.references.forEach((ref) => references.add(ref));
|
|
188
192
|
}
|
|
189
193
|
// Get references from child scopes
|
|
190
194
|
const childScopes = s.childScopes;
|
|
191
195
|
for (const childScope of childScopes) {
|
|
192
|
-
const childVar = childScope.variables.find(v => v.name === functionName);
|
|
196
|
+
const childVar = childScope.variables.find((v) => v.name === functionName);
|
|
193
197
|
if (childVar) {
|
|
194
|
-
childVar.references.forEach(ref => references.add(ref));
|
|
198
|
+
childVar.references.forEach((ref) => references.add(ref));
|
|
195
199
|
}
|
|
196
200
|
}
|
|
197
201
|
}
|
|
@@ -199,24 +203,24 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
199
203
|
const siblingScopes = scope.upper?.childScopes ?? [];
|
|
200
204
|
for (const siblingScope of siblingScopes) {
|
|
201
205
|
if (siblingScope !== scope) {
|
|
202
|
-
const siblingVar = siblingScope.variables.find(v => v.name === functionName);
|
|
206
|
+
const siblingVar = siblingScope.variables.find((v) => v.name === functionName);
|
|
203
207
|
if (siblingVar) {
|
|
204
|
-
siblingVar.references.forEach(ref => references.add(ref));
|
|
208
|
+
siblingVar.references.forEach((ref) => references.add(ref));
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
}
|
|
208
212
|
// Get references from global scope
|
|
209
213
|
const sourceCode = context.getSourceCode();
|
|
210
214
|
if (sourceCode.scopeManager?.globalScope) {
|
|
211
|
-
const globalVar = sourceCode.scopeManager.globalScope.variables.find(v => v.name === functionName);
|
|
215
|
+
const globalVar = sourceCode.scopeManager.globalScope.variables.find((v) => v.name === functionName);
|
|
212
216
|
if (globalVar) {
|
|
213
|
-
globalVar.references.forEach(ref => references.add(ref));
|
|
217
|
+
globalVar.references.forEach((ref) => references.add(ref));
|
|
214
218
|
}
|
|
215
219
|
}
|
|
216
220
|
context.report({
|
|
217
221
|
node,
|
|
218
222
|
messageId: 'callbackFunctionPrefix',
|
|
219
|
-
|
|
223
|
+
fix(fixer) {
|
|
220
224
|
// Remove 'handle' prefix and convert first character to lowercase
|
|
221
225
|
const newName = functionName.slice(6).charAt(0).toLowerCase() +
|
|
222
226
|
functionName.slice(7);
|
|
@@ -267,7 +271,7 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
267
271
|
}
|
|
268
272
|
},
|
|
269
273
|
// Check constructor parameters
|
|
270
|
-
|
|
274
|
+
TSParameterProperty(node) {
|
|
271
275
|
if (node.parameter.type === 'Identifier' &&
|
|
272
276
|
node.parameter.name.startsWith('handle')) {
|
|
273
277
|
context.report({
|
|
@@ -107,7 +107,7 @@ exports.enforceAssertThrows = (0, createRule_1.createRule)({
|
|
|
107
107
|
}
|
|
108
108
|
// Handle BlockStatement specially
|
|
109
109
|
if (node.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
110
|
-
node.body.forEach(stmt => walk(stmt));
|
|
110
|
+
node.body.forEach((stmt) => walk(stmt));
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
// Handle IfStatement specially
|
|
@@ -122,13 +122,15 @@ exports.enforceAssertThrows = (0, createRule_1.createRule)({
|
|
|
122
122
|
for (const key of Object.keys(node)) {
|
|
123
123
|
const value = node[key];
|
|
124
124
|
if (Array.isArray(value)) {
|
|
125
|
-
value.forEach(item => {
|
|
125
|
+
value.forEach((item) => {
|
|
126
126
|
if (item && typeof item === 'object' && !('parent' in item)) {
|
|
127
127
|
walk(item);
|
|
128
128
|
}
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
|
-
else if (value &&
|
|
131
|
+
else if (value &&
|
|
132
|
+
typeof value === 'object' &&
|
|
133
|
+
!('parent' in value)) {
|
|
132
134
|
walk(value);
|
|
133
135
|
}
|
|
134
136
|
}
|
|
@@ -140,7 +142,8 @@ exports.enforceAssertThrows = (0, createRule_1.createRule)({
|
|
|
140
142
|
function checkFunction(node) {
|
|
141
143
|
let functionName = '';
|
|
142
144
|
if (node.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
|
|
143
|
-
functionName =
|
|
145
|
+
functionName =
|
|
146
|
+
node.key.type === utils_1.AST_NODE_TYPES.Identifier ? node.key.name : '';
|
|
144
147
|
}
|
|
145
148
|
else if (node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration && node.id) {
|
|
146
149
|
functionName = node.id.name;
|
|
@@ -156,7 +159,9 @@ exports.enforceAssertThrows = (0, createRule_1.createRule)({
|
|
|
156
159
|
}
|
|
157
160
|
if (functionName.toLowerCase().startsWith('assert')) {
|
|
158
161
|
currentFunction = node;
|
|
159
|
-
const functionBody = node.type === utils_1.AST_NODE_TYPES.MethodDefinition
|
|
162
|
+
const functionBody = node.type === utils_1.AST_NODE_TYPES.MethodDefinition
|
|
163
|
+
? node.value.body
|
|
164
|
+
: node.body;
|
|
160
165
|
if (functionBody && !hasThrowStatement(functionBody)) {
|
|
161
166
|
context.report({
|
|
162
167
|
node,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Options = [
|
|
2
|
+
{
|
|
3
|
+
prefixes?: string[];
|
|
4
|
+
}
|
|
5
|
+
];
|
|
6
|
+
export declare const enforceBooleanNamingPrefixes: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"missingBooleanPrefix", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enforceBooleanNamingPrefixes = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
// Default approved boolean prefixes
|
|
7
|
+
const DEFAULT_BOOLEAN_PREFIXES = [
|
|
8
|
+
'is',
|
|
9
|
+
'has',
|
|
10
|
+
'does',
|
|
11
|
+
'can',
|
|
12
|
+
'should',
|
|
13
|
+
'will',
|
|
14
|
+
'was',
|
|
15
|
+
'had',
|
|
16
|
+
'did',
|
|
17
|
+
'would',
|
|
18
|
+
'must',
|
|
19
|
+
'allows',
|
|
20
|
+
'supports',
|
|
21
|
+
'needs',
|
|
22
|
+
'asserts',
|
|
23
|
+
];
|
|
24
|
+
exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
25
|
+
name: 'enforce-boolean-naming-prefixes',
|
|
26
|
+
meta: {
|
|
27
|
+
type: 'suggestion',
|
|
28
|
+
docs: {
|
|
29
|
+
description: 'Enforce consistent naming conventions for boolean values by requiring approved prefixes',
|
|
30
|
+
recommended: 'error',
|
|
31
|
+
},
|
|
32
|
+
fixable: 'code',
|
|
33
|
+
schema: [
|
|
34
|
+
{
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
prefixes: {
|
|
38
|
+
type: 'array',
|
|
39
|
+
items: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
messages: {
|
|
48
|
+
missingBooleanPrefix: 'Boolean {{type}} "{{name}}" should start with an approved prefix: {{prefixes}}',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
defaultOptions: [{ prefixes: DEFAULT_BOOLEAN_PREFIXES }],
|
|
52
|
+
create(context, [options]) {
|
|
53
|
+
const approvedPrefixes = options.prefixes || DEFAULT_BOOLEAN_PREFIXES;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a name starts with any of the approved prefixes
|
|
56
|
+
*/
|
|
57
|
+
function hasApprovedPrefix(name) {
|
|
58
|
+
return approvedPrefixes.some((prefix) => name.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Format the list of approved prefixes for error messages
|
|
62
|
+
*/
|
|
63
|
+
function formatPrefixes() {
|
|
64
|
+
return approvedPrefixes.join(', ');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a node is a TypeScript type predicate
|
|
68
|
+
*/
|
|
69
|
+
function isTypePredicate(node) {
|
|
70
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation &&
|
|
71
|
+
node.parent.parent?.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
72
|
+
node.parent.parent.parent?.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
73
|
+
const typeAnnotation = node.parent;
|
|
74
|
+
return (typeAnnotation.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypePredicate);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if a node has a boolean type annotation
|
|
80
|
+
*/
|
|
81
|
+
function hasBooleanTypeAnnotation(node) {
|
|
82
|
+
if (node.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
83
|
+
// Check for explicit boolean type annotation
|
|
84
|
+
if (node.typeAnnotation?.typeAnnotation.type ===
|
|
85
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// Check if it's a parameter in a function with a boolean type
|
|
89
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
90
|
+
node.parent?.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
91
|
+
node.parent?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
92
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
93
|
+
node.typeAnnotation.typeAnnotation.type ===
|
|
94
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Check for property signature with boolean type
|
|
100
|
+
if (node.type === utils_1.AST_NODE_TYPES.TSPropertySignature &&
|
|
101
|
+
node.typeAnnotation?.typeAnnotation.type ===
|
|
102
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if a node is initialized with a boolean value
|
|
109
|
+
*/
|
|
110
|
+
function hasInitialBooleanValue(node) {
|
|
111
|
+
if (node.type === utils_1.AST_NODE_TYPES.VariableDeclarator && node.init) {
|
|
112
|
+
// Check for direct boolean literal initialization
|
|
113
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
114
|
+
typeof node.init.value === 'boolean') {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// Check for logical expressions that typically return boolean
|
|
118
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
|
|
119
|
+
['===', '!==', '==', '!=', '>', '<', '>=', '<='].includes(node.init.operator)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
// Check for logical expressions (&&, ||)
|
|
123
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
|
124
|
+
['&&', '||'].includes(node.init.operator)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
// Check for unary expressions with ! operator
|
|
128
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
|
|
129
|
+
node.init.operator === '!') {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
// Check for function calls that might return boolean
|
|
133
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
134
|
+
node.init.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
135
|
+
const calleeName = node.init.callee.name;
|
|
136
|
+
// Check if the function name suggests it returns a boolean
|
|
137
|
+
return approvedPrefixes.some((prefix) => calleeName.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Check if a function returns a boolean value
|
|
144
|
+
*/
|
|
145
|
+
function returnsBooleanValue(node) {
|
|
146
|
+
// Check for explicit boolean return type annotation
|
|
147
|
+
if (node.returnType?.typeAnnotation &&
|
|
148
|
+
node.returnType.typeAnnotation.type ===
|
|
149
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
// For arrow functions with expression bodies, check if the expression is boolean-like
|
|
153
|
+
if (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
154
|
+
node.expression &&
|
|
155
|
+
node.body) {
|
|
156
|
+
if (node.body.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
157
|
+
typeof node.body.value === 'boolean') {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (node.body.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
|
|
161
|
+
['===', '!==', '==', '!=', '>', '<', '>=', '<='].includes(node.body.operator)) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
if (node.body.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
|
|
165
|
+
node.body.operator === '!') {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Check for arrow function with boolean return type
|
|
170
|
+
if (node.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
171
|
+
const variableDeclarator = node.parent;
|
|
172
|
+
if (variableDeclarator?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
|
173
|
+
variableDeclarator.id.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
174
|
+
// Check if the arrow function has a boolean return type annotation
|
|
175
|
+
if (node.returnType?.typeAnnotation &&
|
|
176
|
+
node.returnType.typeAnnotation.type ===
|
|
177
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check variable declarations for boolean naming
|
|
186
|
+
*/
|
|
187
|
+
function checkVariableDeclaration(node) {
|
|
188
|
+
if (node.id.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
189
|
+
return;
|
|
190
|
+
const variableName = node.id.name;
|
|
191
|
+
// Skip checking if it's a type predicate
|
|
192
|
+
if (isTypePredicate(node.id))
|
|
193
|
+
return;
|
|
194
|
+
// Check if it's a boolean variable
|
|
195
|
+
let isBooleanVar = hasBooleanTypeAnnotation(node.id) || hasInitialBooleanValue(node);
|
|
196
|
+
// Check if it's an arrow function with boolean return type
|
|
197
|
+
if (node.init?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
198
|
+
node.init.returnType?.typeAnnotation &&
|
|
199
|
+
node.init.returnType.typeAnnotation.type ===
|
|
200
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
201
|
+
isBooleanVar = true;
|
|
202
|
+
}
|
|
203
|
+
if (isBooleanVar && !hasApprovedPrefix(variableName)) {
|
|
204
|
+
context.report({
|
|
205
|
+
node: node.id,
|
|
206
|
+
messageId: 'missingBooleanPrefix',
|
|
207
|
+
data: {
|
|
208
|
+
type: 'variable',
|
|
209
|
+
name: variableName,
|
|
210
|
+
prefixes: formatPrefixes(),
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Check function declarations for boolean return values
|
|
217
|
+
*/
|
|
218
|
+
function checkFunctionDeclaration(node) {
|
|
219
|
+
// Skip anonymous functions
|
|
220
|
+
if (!node.id && node.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// Get function name
|
|
224
|
+
let functionName = '';
|
|
225
|
+
if (node.id) {
|
|
226
|
+
functionName = node.id.name;
|
|
227
|
+
}
|
|
228
|
+
else if (node.parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
|
229
|
+
node.parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
230
|
+
functionName = node.parent.id.name;
|
|
231
|
+
}
|
|
232
|
+
else if (node.parent?.type === utils_1.AST_NODE_TYPES.Property &&
|
|
233
|
+
node.parent.key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
234
|
+
functionName = node.parent.key.name;
|
|
235
|
+
}
|
|
236
|
+
else if (node.parent?.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
237
|
+
node.parent.key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
238
|
+
functionName = node.parent.key.name;
|
|
239
|
+
}
|
|
240
|
+
if (!functionName)
|
|
241
|
+
return;
|
|
242
|
+
// Skip checking if it's a type predicate (these are allowed to use 'is' prefix regardless)
|
|
243
|
+
if (node.returnType?.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypePredicate) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Check if it returns a boolean
|
|
247
|
+
if (returnsBooleanValue(node) && !hasApprovedPrefix(functionName)) {
|
|
248
|
+
context.report({
|
|
249
|
+
node: node.id || node,
|
|
250
|
+
messageId: 'missingBooleanPrefix',
|
|
251
|
+
data: {
|
|
252
|
+
type: 'function',
|
|
253
|
+
name: functionName,
|
|
254
|
+
prefixes: formatPrefixes(),
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Check method definitions for boolean return values
|
|
261
|
+
*/
|
|
262
|
+
function checkMethodDefinition(node) {
|
|
263
|
+
if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
264
|
+
return;
|
|
265
|
+
const methodName = node.key.name;
|
|
266
|
+
// Skip checking if it's a type predicate
|
|
267
|
+
if (node.value.returnType?.typeAnnotation &&
|
|
268
|
+
node.value.returnType.typeAnnotation.type ===
|
|
269
|
+
utils_1.AST_NODE_TYPES.TSTypePredicate) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
// Check if it returns a boolean
|
|
273
|
+
if (node.value.returnType?.typeAnnotation &&
|
|
274
|
+
node.value.returnType.typeAnnotation.type ===
|
|
275
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword &&
|
|
276
|
+
!hasApprovedPrefix(methodName)) {
|
|
277
|
+
context.report({
|
|
278
|
+
node: node.key,
|
|
279
|
+
messageId: 'missingBooleanPrefix',
|
|
280
|
+
data: {
|
|
281
|
+
type: 'method',
|
|
282
|
+
name: methodName,
|
|
283
|
+
prefixes: formatPrefixes(),
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Check class property definitions for boolean values
|
|
290
|
+
*/
|
|
291
|
+
function checkClassProperty(node) {
|
|
292
|
+
if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
293
|
+
return;
|
|
294
|
+
const propertyName = node.key.name;
|
|
295
|
+
// Check if it's a boolean property
|
|
296
|
+
let isBooleanProperty = false;
|
|
297
|
+
// Check if it has a boolean type annotation
|
|
298
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
299
|
+
node.typeAnnotation.typeAnnotation.type ===
|
|
300
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
301
|
+
isBooleanProperty = true;
|
|
302
|
+
}
|
|
303
|
+
// Check if it's initialized with a boolean value
|
|
304
|
+
if (node.value?.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
305
|
+
typeof node.value.value === 'boolean') {
|
|
306
|
+
isBooleanProperty = true;
|
|
307
|
+
}
|
|
308
|
+
if (isBooleanProperty && !hasApprovedPrefix(propertyName)) {
|
|
309
|
+
context.report({
|
|
310
|
+
node: node.key,
|
|
311
|
+
messageId: 'missingBooleanPrefix',
|
|
312
|
+
data: {
|
|
313
|
+
type: 'property',
|
|
314
|
+
name: propertyName,
|
|
315
|
+
prefixes: formatPrefixes(),
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Check class property declarations for boolean values
|
|
322
|
+
*/
|
|
323
|
+
function checkClassPropertyDeclaration(node) {
|
|
324
|
+
if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
325
|
+
return;
|
|
326
|
+
const propertyName = node.key.name;
|
|
327
|
+
// Check if it's a boolean property
|
|
328
|
+
let isBooleanProperty = false;
|
|
329
|
+
// Check if it has a boolean type annotation
|
|
330
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
331
|
+
node.typeAnnotation.typeAnnotation.type ===
|
|
332
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
333
|
+
isBooleanProperty = true;
|
|
334
|
+
}
|
|
335
|
+
// Check if it's initialized with a boolean value
|
|
336
|
+
if (node.value?.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
337
|
+
typeof node.value.value === 'boolean') {
|
|
338
|
+
isBooleanProperty = true;
|
|
339
|
+
}
|
|
340
|
+
if (isBooleanProperty && !hasApprovedPrefix(propertyName)) {
|
|
341
|
+
context.report({
|
|
342
|
+
node: node.key,
|
|
343
|
+
messageId: 'missingBooleanPrefix',
|
|
344
|
+
data: {
|
|
345
|
+
type: 'property',
|
|
346
|
+
name: propertyName,
|
|
347
|
+
prefixes: formatPrefixes(),
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Check property definitions for boolean values
|
|
354
|
+
*/
|
|
355
|
+
function checkProperty(node) {
|
|
356
|
+
if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
357
|
+
return;
|
|
358
|
+
const propertyName = node.key.name;
|
|
359
|
+
// Check if it's a boolean property
|
|
360
|
+
let isBooleanProperty = false;
|
|
361
|
+
// Check if it's initialized with a boolean value
|
|
362
|
+
if (node.value.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
363
|
+
typeof node.value.value === 'boolean') {
|
|
364
|
+
isBooleanProperty = true;
|
|
365
|
+
}
|
|
366
|
+
// Check if it's a method that returns a boolean
|
|
367
|
+
if ((node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
368
|
+
node.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) &&
|
|
369
|
+
node.value.returnType?.typeAnnotation.type ===
|
|
370
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
371
|
+
isBooleanProperty = true;
|
|
372
|
+
}
|
|
373
|
+
if (isBooleanProperty && !hasApprovedPrefix(propertyName)) {
|
|
374
|
+
context.report({
|
|
375
|
+
node: node.key,
|
|
376
|
+
messageId: 'missingBooleanPrefix',
|
|
377
|
+
data: {
|
|
378
|
+
type: 'property',
|
|
379
|
+
name: propertyName,
|
|
380
|
+
prefixes: formatPrefixes(),
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Check property signatures in interfaces/types for boolean types
|
|
387
|
+
*/
|
|
388
|
+
function checkPropertySignature(node) {
|
|
389
|
+
if (node.key.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
390
|
+
return;
|
|
391
|
+
const propertyName = node.key.name;
|
|
392
|
+
// Check if it has a boolean type
|
|
393
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
394
|
+
node.typeAnnotation.typeAnnotation.type ===
|
|
395
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword &&
|
|
396
|
+
!hasApprovedPrefix(propertyName)) {
|
|
397
|
+
context.report({
|
|
398
|
+
node: node.key,
|
|
399
|
+
messageId: 'missingBooleanPrefix',
|
|
400
|
+
data: {
|
|
401
|
+
type: 'property',
|
|
402
|
+
name: propertyName,
|
|
403
|
+
prefixes: formatPrefixes(),
|
|
404
|
+
},
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Check parameters for boolean types
|
|
410
|
+
*/
|
|
411
|
+
function checkParameter(node) {
|
|
412
|
+
if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
413
|
+
return;
|
|
414
|
+
const paramName = node.name;
|
|
415
|
+
// Check if it has a boolean type annotation
|
|
416
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
417
|
+
node.typeAnnotation.typeAnnotation.type ===
|
|
418
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword &&
|
|
419
|
+
!hasApprovedPrefix(paramName)) {
|
|
420
|
+
context.report({
|
|
421
|
+
node,
|
|
422
|
+
messageId: 'missingBooleanPrefix',
|
|
423
|
+
data: {
|
|
424
|
+
type: 'parameter',
|
|
425
|
+
name: paramName,
|
|
426
|
+
prefixes: formatPrefixes(),
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
VariableDeclarator: checkVariableDeclaration,
|
|
433
|
+
FunctionDeclaration: checkFunctionDeclaration,
|
|
434
|
+
FunctionExpression(node) {
|
|
435
|
+
if (node.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
436
|
+
checkFunctionDeclaration(node);
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
ArrowFunctionExpression(node) {
|
|
440
|
+
if (node.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
441
|
+
checkFunctionDeclaration(node);
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
MethodDefinition: checkMethodDefinition,
|
|
445
|
+
Property: checkProperty,
|
|
446
|
+
ClassProperty: checkClassProperty,
|
|
447
|
+
PropertyDefinition: checkClassPropertyDeclaration,
|
|
448
|
+
TSPropertySignature: checkPropertySignature,
|
|
449
|
+
Identifier(node) {
|
|
450
|
+
// Check parameter names in function declarations
|
|
451
|
+
if (node.parent &&
|
|
452
|
+
(node.parent.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
453
|
+
node.parent.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
454
|
+
node.parent.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) &&
|
|
455
|
+
node.parent.params.includes(node)) {
|
|
456
|
+
checkParameter(node);
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
//# sourceMappingURL=enforce-boolean-naming-prefixes.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
type MessageIds = '
|
|
1
|
+
type MessageIds = 'missingPropsType' | 'missingResponseType' | 'unusedPropsType' | 'unusedResponseType';
|
|
2
2
|
export declare const enforceCallableTypes: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
3
3
|
export {};
|