@blumintinc/eslint-plugin-blumint 1.12.0 → 1.12.2
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/lib/index.js
CHANGED
|
@@ -106,7 +106,7 @@ const enforce_boolean_naming_prefixes_1 = require("./rules/enforce-boolean-namin
|
|
|
106
106
|
module.exports = {
|
|
107
107
|
meta: {
|
|
108
108
|
name: '@blumintinc/eslint-plugin-blumint',
|
|
109
|
-
version: '1.12.
|
|
109
|
+
version: '1.12.2',
|
|
110
110
|
},
|
|
111
111
|
parseOptions: {
|
|
112
112
|
ecmaVersion: 2020,
|
|
@@ -119,11 +119,86 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
|
119
119
|
['===', '!==', '==', '!=', '>', '<', '>=', '<='].includes(node.init.operator)) {
|
|
120
120
|
return true;
|
|
121
121
|
}
|
|
122
|
-
// Check for logical expressions (
|
|
122
|
+
// Check for logical expressions (&&)
|
|
123
123
|
if (node.init.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
|
124
|
-
|
|
124
|
+
node.init.operator === '&&') {
|
|
125
|
+
// Check if the right side is a method call that might return a non-boolean value
|
|
126
|
+
const rightSide = node.init.right;
|
|
127
|
+
if (rightSide.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
128
|
+
// If the method name doesn't suggest it returns a boolean, don't flag it
|
|
129
|
+
if (rightSide.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
130
|
+
rightSide.callee.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
131
|
+
const methodName = rightSide.callee.property.name;
|
|
132
|
+
// Check if the method name suggests it returns a boolean
|
|
133
|
+
const isBooleanMethod = approvedPrefixes.some((prefix) => methodName.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
134
|
+
// If the method name suggests it returns a boolean (starts with a boolean prefix or contains 'boolean' or 'enabled'),
|
|
135
|
+
// then the variable should be treated as a boolean
|
|
136
|
+
if (isBooleanMethod ||
|
|
137
|
+
methodName.toLowerCase().includes('boolean') ||
|
|
138
|
+
methodName.toLowerCase().includes('enabled') ||
|
|
139
|
+
methodName.toLowerCase().includes('auth') ||
|
|
140
|
+
methodName.toLowerCase().includes('valid') ||
|
|
141
|
+
methodName.toLowerCase().includes('check')) {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
// For methods like getVolume(), getData(), etc., assume they return non-boolean values
|
|
145
|
+
if (methodName.toLowerCase().startsWith('get') ||
|
|
146
|
+
methodName.toLowerCase().startsWith('fetch') ||
|
|
147
|
+
methodName.toLowerCase().startsWith('retrieve') ||
|
|
148
|
+
methodName.toLowerCase().startsWith('load') ||
|
|
149
|
+
methodName.toLowerCase().startsWith('read')) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// For property access like user.isAuthenticated, treat as boolean
|
|
155
|
+
if (rightSide.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
156
|
+
rightSide.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
157
|
+
const propertyName = rightSide.property.name;
|
|
158
|
+
const isBooleanProperty = approvedPrefixes.some((prefix) => propertyName.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
159
|
+
if (isBooleanProperty) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Default to true for other cases with && to avoid false negatives
|
|
125
164
|
return true;
|
|
126
165
|
}
|
|
166
|
+
// Special case for logical OR (||) - only consider it boolean if:
|
|
167
|
+
// 1. It's used with boolean literals or
|
|
168
|
+
// 2. It's not used with array/object literals as fallbacks
|
|
169
|
+
if (node.init.type === utils_1.AST_NODE_TYPES.LogicalExpression &&
|
|
170
|
+
node.init.operator === '||') {
|
|
171
|
+
// Check if right side is a non-boolean literal (array, object, string, number)
|
|
172
|
+
const rightSide = node.init.right;
|
|
173
|
+
if (rightSide.type === utils_1.AST_NODE_TYPES.ArrayExpression ||
|
|
174
|
+
rightSide.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
|
|
175
|
+
(rightSide.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
176
|
+
typeof rightSide.value !== 'boolean')) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
// If right side is a boolean literal, it's likely a boolean variable
|
|
180
|
+
if (rightSide.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
181
|
+
typeof rightSide.value === 'boolean') {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
// For other cases, we need to be more careful
|
|
185
|
+
// If we can determine the left side is a boolean, then it's a boolean variable
|
|
186
|
+
const leftSide = node.init.left;
|
|
187
|
+
if ((leftSide.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
188
|
+
typeof leftSide.value === 'boolean') ||
|
|
189
|
+
(leftSide.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
|
|
190
|
+
leftSide.operator === '!')) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
// For function calls, check if the function name suggests it returns a boolean
|
|
194
|
+
if (leftSide.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
195
|
+
leftSide.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
196
|
+
const calleeName = leftSide.callee.name;
|
|
197
|
+
return approvedPrefixes.some((prefix) => calleeName.toLowerCase().startsWith(prefix.toLowerCase()));
|
|
198
|
+
}
|
|
199
|
+
// Default to false for other cases with || to avoid false positives
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
127
202
|
// Check for unary expressions with ! operator
|
|
128
203
|
if (node.init.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
|
|
129
204
|
node.init.operator === '!') {
|
|
@@ -930,9 +930,12 @@ exports.enforcePositiveNaming = (0, createRule_1.createRule)({
|
|
|
930
930
|
// Split the name into words
|
|
931
931
|
const words = splitNameIntoWords(name);
|
|
932
932
|
// Check if this follows the pattern IS_NOT_SOMETHING or HAS_NO_SOMETHING
|
|
933
|
-
|
|
934
|
-
if (
|
|
935
|
-
|
|
933
|
+
// Make sure words[1] exists before trying to access it
|
|
934
|
+
if (words.length > 1) {
|
|
935
|
+
const secondWord = words[1].toLowerCase();
|
|
936
|
+
if (EXCEPTION_WORDS.some((exception) => secondWord === exception.toLowerCase())) {
|
|
937
|
+
return { isNegative: false, alternatives: [] };
|
|
938
|
+
}
|
|
936
939
|
}
|
|
937
940
|
const nameLowercase = name.toLowerCase();
|
|
938
941
|
// Check for negative prefixes in boolean-like variables
|
|
@@ -37,7 +37,7 @@ exports.noCompositingLayerProps = (0, createRule_1.createRule)({
|
|
|
37
37
|
meta: {
|
|
38
38
|
type: 'suggestion',
|
|
39
39
|
docs: {
|
|
40
|
-
description: 'Warn when using CSS properties that trigger compositing layers, which can impact performance. Properties like transform, opacity, filter, and will-change create new GPU layers. While sometimes beneficial for animations, excessive layer creation can increase memory usage and hurt performance. Consider alternatives or explicitly document intentional layer promotion.',
|
|
40
|
+
description: 'Warn when using CSS properties that trigger compositing layers, which can impact performance. Properties like transform, opacity, filter, and will-change create new GPU layers. While sometimes beneficial for animations, excessive layer creation can increase memory usage and hurt performance. This rule checks both regular style objects and MUI sx props. Consider alternatives or explicitly document intentional layer promotion.',
|
|
41
41
|
recommended: 'error',
|
|
42
42
|
},
|
|
43
43
|
schema: [],
|
|
@@ -79,7 +79,7 @@ exports.noCompositingLayerProps = (0, createRule_1.createRule)({
|
|
|
79
79
|
// Check for JSX style attribute
|
|
80
80
|
if (current.parent.type === utils_1.AST_NODE_TYPES.JSXAttribute &&
|
|
81
81
|
current.parent.name.type === utils_1.AST_NODE_TYPES.JSXIdentifier &&
|
|
82
|
-
current.parent.name.name === 'style') {
|
|
82
|
+
(current.parent.name.name === 'style' || current.parent.name.name === 'sx')) {
|
|
83
83
|
return true;
|
|
84
84
|
}
|
|
85
85
|
// Check for style-related variable names or properties
|
|
@@ -91,7 +91,7 @@ exports.noCompositingLayerProps = (0, createRule_1.createRule)({
|
|
|
91
91
|
// Check for style-related object property assignments
|
|
92
92
|
if (current.parent.type === utils_1.AST_NODE_TYPES.Property &&
|
|
93
93
|
current.parent.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
94
|
-
/style/i.test(current.parent.key.name)) {
|
|
94
|
+
(/style/i.test(current.parent.key.name) || current.parent.key.name === 'sx')) {
|
|
95
95
|
return true;
|
|
96
96
|
}
|
|
97
97
|
// Skip if we're in a TypeScript type definition
|
|
@@ -142,9 +142,9 @@ exports.noCompositingLayerProps = (0, createRule_1.createRule)({
|
|
|
142
142
|
return;
|
|
143
143
|
checkNode(node);
|
|
144
144
|
},
|
|
145
|
-
// Handle JSX style attributes
|
|
145
|
+
// Handle JSX style and sx attributes
|
|
146
146
|
JSXAttribute(node) {
|
|
147
|
-
if (node.name.name !== 'style')
|
|
147
|
+
if (node.name.name !== 'style' && node.name.name !== 'sx')
|
|
148
148
|
return;
|
|
149
149
|
if (node.value?.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer &&
|
|
150
150
|
node.value.expression.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
|