@blumintinc/eslint-plugin-blumint 1.8.0 → 1.8.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/README.md +84 -39
- package/lib/index.js +50 -2
- package/lib/rules/enforce-assertSafe-object-key.js +1 -1
- package/lib/rules/enforce-css-media-queries.d.ts +5 -0
- package/lib/rules/enforce-css-media-queries.js +87 -0
- package/lib/rules/enforce-dynamic-imports.d.ts +9 -0
- package/lib/rules/enforce-dynamic-imports.js +84 -0
- package/lib/rules/enforce-id-capitalization.d.ts +6 -0
- package/lib/rules/enforce-id-capitalization.js +118 -0
- package/lib/rules/enforce-mui-rounded-icons.d.ts +1 -0
- package/lib/rules/enforce-mui-rounded-icons.js +54 -0
- package/lib/rules/enforce-object-literal-as-const.js +37 -0
- package/lib/rules/enforce-positive-naming.js +116 -168
- package/lib/rules/enforce-react-type-naming.d.ts +3 -0
- package/lib/rules/enforce-react-type-naming.js +191 -0
- package/lib/rules/enforce-singular-type-names.d.ts +2 -0
- package/lib/rules/enforce-singular-type-names.js +112 -0
- package/lib/rules/enforce-verb-noun-naming.js +5 -2
- package/lib/rules/ensure-pointer-events-none.d.ts +1 -0
- package/lib/rules/ensure-pointer-events-none.js +211 -0
- package/lib/rules/key-only-outermost-element.d.ts +3 -0
- package/lib/rules/key-only-outermost-element.js +152 -0
- package/lib/rules/no-always-true-false-conditions.js +19 -0
- package/lib/rules/no-circular-references.d.ts +1 -0
- package/lib/rules/no-circular-references.js +523 -0
- package/lib/rules/no-hungarian.d.ts +5 -0
- package/lib/rules/no-hungarian.js +223 -0
- package/lib/rules/no-object-values-on-strings.d.ts +2 -0
- package/lib/rules/no-object-values-on-strings.js +294 -0
- package/lib/rules/no-type-assertion-returns.js +143 -118
- package/lib/rules/no-unnecessary-destructuring.d.ts +5 -0
- package/lib/rules/no-unnecessary-destructuring.js +69 -0
- package/lib/rules/no-unused-props.js +109 -11
- package/lib/rules/no-unused-usestate.d.ts +8 -0
- package/lib/rules/no-unused-usestate.js +84 -0
- package/lib/rules/omit-index-html.d.ts +7 -0
- package/lib/rules/omit-index-html.js +91 -0
- package/lib/rules/prefer-usememo-over-useeffect-usestate.d.ts +5 -0
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +129 -0
- package/lib/rules/react-usememo-should-be-component.js +369 -2
- package/package.json +7 -4
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.keyOnlyOutermostElement = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.keyOnlyOutermostElement = (0, createRule_1.createRule)({
|
|
6
|
+
name: 'key-only-outermost-element',
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Enforce that only the outermost element in list rendering has a key prop',
|
|
11
|
+
recommended: 'error',
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
keyOnlyOutermostElement: 'Only the outermost element in a list rendering should have a key prop. Remove the key from this nested element.',
|
|
15
|
+
fragmentShouldHaveKey: 'Fragment used as the outermost element in a list should use <React.Fragment key={...}> instead of shorthand syntax.',
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
// Track JSXElements that are direct children of a map callback
|
|
23
|
+
const mapCallbackElements = new Set();
|
|
24
|
+
// Track JSXFragments that are direct children of a map callback
|
|
25
|
+
const mapCallbackFragments = new Set();
|
|
26
|
+
// Track JSX attributes that have already been reported to avoid duplicate reports
|
|
27
|
+
const reportedAttributes = new Set();
|
|
28
|
+
// Helper function to process map calls
|
|
29
|
+
const processMapCall = (node) => {
|
|
30
|
+
// Get the callback function
|
|
31
|
+
const callback = node.arguments[0];
|
|
32
|
+
if (callback && (callback.type === 'ArrowFunctionExpression' ||
|
|
33
|
+
callback.type === 'FunctionExpression')) {
|
|
34
|
+
// Find the return statement or expression
|
|
35
|
+
let returnExpr = null;
|
|
36
|
+
if (callback.type === 'ArrowFunctionExpression' &&
|
|
37
|
+
callback.expression &&
|
|
38
|
+
callback.body.type !== 'BlockStatement') {
|
|
39
|
+
// Arrow function with implicit return
|
|
40
|
+
returnExpr = callback.body;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Look for return statements in the function body
|
|
44
|
+
const body = callback.body;
|
|
45
|
+
if (body.type === 'BlockStatement') {
|
|
46
|
+
for (const stmt of body.body) {
|
|
47
|
+
if (stmt.type === 'ReturnStatement' && stmt.argument) {
|
|
48
|
+
returnExpr = stmt.argument;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// If we found a JSX element or fragment as the return value, mark it
|
|
55
|
+
if (returnExpr) {
|
|
56
|
+
if (returnExpr.type === 'JSXElement') {
|
|
57
|
+
mapCallbackElements.add(returnExpr);
|
|
58
|
+
}
|
|
59
|
+
else if (returnExpr.type === 'JSXFragment') {
|
|
60
|
+
mapCallbackFragments.add(returnExpr);
|
|
61
|
+
// Check if it's a shorthand fragment (<>)
|
|
62
|
+
// Shorthand fragments can't have keys, so suggest using React.Fragment
|
|
63
|
+
context.report({
|
|
64
|
+
node: returnExpr.openingFragment,
|
|
65
|
+
messageId: 'fragmentShouldHaveKey',
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
// Find array.map() calls
|
|
73
|
+
'CallExpression[callee.property.name="map"]'(node) {
|
|
74
|
+
processMapCall(node);
|
|
75
|
+
},
|
|
76
|
+
// Check all JSX elements for key props
|
|
77
|
+
JSXElement(node) {
|
|
78
|
+
// Skip if this is the outermost element in a map callback
|
|
79
|
+
if (mapCallbackElements.has(node)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Check if this element has a key prop
|
|
83
|
+
const openingElement = node.openingElement;
|
|
84
|
+
const attributes = openingElement.attributes;
|
|
85
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
86
|
+
const attr = attributes[i];
|
|
87
|
+
if (attr.type === 'JSXAttribute' && attr.name.name === 'key' && !reportedAttributes.has(attr)) {
|
|
88
|
+
// Check if this element is nested inside a map callback element or fragment
|
|
89
|
+
let parent = node.parent;
|
|
90
|
+
let isNestedInMapCallback = false;
|
|
91
|
+
while (parent) {
|
|
92
|
+
if ((parent.type === 'JSXElement' && mapCallbackElements.has(parent)) ||
|
|
93
|
+
(parent.type === 'JSXFragment' && mapCallbackFragments.has(parent))) {
|
|
94
|
+
isNestedInMapCallback = true;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
parent = parent.parent;
|
|
98
|
+
}
|
|
99
|
+
if (isNestedInMapCallback) {
|
|
100
|
+
// Mark this attribute as reported to avoid duplicate reports
|
|
101
|
+
reportedAttributes.add(attr);
|
|
102
|
+
const sourceCode = context.getSourceCode();
|
|
103
|
+
context.report({
|
|
104
|
+
node: attr,
|
|
105
|
+
messageId: 'keyOnlyOutermostElement',
|
|
106
|
+
fix(fixer) {
|
|
107
|
+
// Find the exact range of the attribute in the source code
|
|
108
|
+
const startPos = attr.range[0];
|
|
109
|
+
const endPos = attr.range[1];
|
|
110
|
+
// Get the text before and after the attribute to check for whitespace
|
|
111
|
+
const fullText = sourceCode.getText();
|
|
112
|
+
// Check if there's a space after the attribute
|
|
113
|
+
let rangeEnd = endPos;
|
|
114
|
+
if (rangeEnd < fullText.length && fullText[rangeEnd] === ' ') {
|
|
115
|
+
rangeEnd++;
|
|
116
|
+
}
|
|
117
|
+
return fixer.replaceTextRange([startPos, rangeEnd], '');
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
// Handle conditional expressions that might contain map callbacks
|
|
125
|
+
ConditionalExpression(node) {
|
|
126
|
+
// Check both the consequent and alternate branches
|
|
127
|
+
if (node.consequent.type === 'CallExpression' &&
|
|
128
|
+
node.consequent.callee.type === 'MemberExpression' &&
|
|
129
|
+
node.consequent.callee.property.type === 'Identifier' &&
|
|
130
|
+
node.consequent.callee.property.name === 'map') {
|
|
131
|
+
processMapCall(node.consequent);
|
|
132
|
+
}
|
|
133
|
+
if (node.alternate.type === 'CallExpression' &&
|
|
134
|
+
node.alternate.callee.type === 'MemberExpression' &&
|
|
135
|
+
node.alternate.callee.property.type === 'Identifier' &&
|
|
136
|
+
node.alternate.callee.property.name === 'map') {
|
|
137
|
+
processMapCall(node.alternate);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
// Handle logical expressions (&&, ||) that might contain map callbacks
|
|
141
|
+
LogicalExpression(node) {
|
|
142
|
+
if (node.right.type === 'CallExpression' &&
|
|
143
|
+
node.right.callee.type === 'MemberExpression' &&
|
|
144
|
+
node.right.callee.property.type === 'Identifier' &&
|
|
145
|
+
node.right.callee.property.name === 'map') {
|
|
146
|
+
processMapCall(node.right);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=key-only-outermost-element.js.map
|
|
@@ -301,6 +301,25 @@ exports.noAlwaysTrueFalseConditions = (0, createRule_1.createRule)({
|
|
|
301
301
|
}
|
|
302
302
|
// For ||: if either side is always truthy, the whole expression is truthy
|
|
303
303
|
if (node.operator === '||') {
|
|
304
|
+
// Skip evaluation if this is a destructuring assignment with fallback pattern
|
|
305
|
+
if (node.parent) {
|
|
306
|
+
// Check for variable declarator with destructuring pattern
|
|
307
|
+
if (node.parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
|
308
|
+
(node.parent.id.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
309
|
+
node.parent.id.type === utils_1.AST_NODE_TYPES.ArrayPattern)) {
|
|
310
|
+
// This is a destructuring with fallback pattern like: const { x } = obj || {}
|
|
311
|
+
// Don't flag this as an always true/false condition
|
|
312
|
+
return {};
|
|
313
|
+
}
|
|
314
|
+
// Check for assignment expression with destructuring pattern
|
|
315
|
+
if (node.parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
|
|
316
|
+
(node.parent.left.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
317
|
+
node.parent.left.type === utils_1.AST_NODE_TYPES.ArrayPattern)) {
|
|
318
|
+
// This is a destructuring with fallback pattern like: ({ x } = obj || {})
|
|
319
|
+
// Don't flag this as an always true/false condition
|
|
320
|
+
return {};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
304
323
|
if (leftResult.isTruthy) {
|
|
305
324
|
// Short circuit for || - if left is truthy, right is never evaluated
|
|
306
325
|
return { isTruthy: true };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const noCircularReferences: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"circularReference", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|