@blumintinc/eslint-plugin-blumint 1.7.3 → 1.8.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.
Files changed (38) hide show
  1. package/README.md +39 -62
  2. package/lib/index.js +37 -1
  3. package/lib/rules/enforce-assert-throws.js +48 -3
  4. package/lib/rules/enforce-assertSafe-object-key.d.ts +2 -0
  5. package/lib/rules/enforce-assertSafe-object-key.js +284 -0
  6. package/lib/rules/enforce-centralized-mock-firestore.js +192 -14
  7. package/lib/rules/enforce-firestore-facade.js +8 -0
  8. package/lib/rules/enforce-microdiff.d.ts +3 -0
  9. package/lib/rules/enforce-microdiff.js +379 -0
  10. package/lib/rules/enforce-object-literal-as-const.d.ts +4 -0
  11. package/lib/rules/enforce-object-literal-as-const.js +88 -0
  12. package/lib/rules/enforce-positive-naming.d.ts +1 -0
  13. package/lib/rules/enforce-positive-naming.js +363 -0
  14. package/lib/rules/enforce-props-argument-name.d.ts +8 -0
  15. package/lib/rules/enforce-props-argument-name.js +182 -0
  16. package/lib/rules/enforce-render-hits-memoization.js +155 -26
  17. package/lib/rules/enforce-timestamp-now.d.ts +1 -0
  18. package/lib/rules/enforce-timestamp-now.js +223 -0
  19. package/lib/rules/extract-global-constants.d.ts +1 -1
  20. package/lib/rules/extract-global-constants.js +109 -1
  21. package/lib/rules/global-const-style.js +3 -2
  22. package/lib/rules/no-always-true-false-conditions.d.ts +3 -0
  23. package/lib/rules/no-always-true-false-conditions.js +1202 -0
  24. package/lib/rules/no-firestore-jest-mock.js +27 -4
  25. package/lib/rules/no-mock-firebase-admin.js +20 -7
  26. package/lib/rules/no-type-assertion-returns.d.ts +9 -0
  27. package/lib/rules/no-type-assertion-returns.js +289 -0
  28. package/lib/rules/no-unnecessary-verb-suffix.d.ts +1 -0
  29. package/lib/rules/no-unnecessary-verb-suffix.js +203 -0
  30. package/lib/rules/prefer-clone-deep.js +294 -22
  31. package/lib/rules/prefer-fragment-component.js +265 -34
  32. package/lib/rules/prefer-global-router-state-key.d.ts +5 -0
  33. package/lib/rules/prefer-global-router-state-key.js +89 -0
  34. package/lib/rules/prefer-utility-function-over-private-static.d.ts +1 -0
  35. package/lib/rules/prefer-utility-function-over-private-static.js +77 -0
  36. package/lib/rules/react-usememo-should-be-component.d.ts +1 -0
  37. package/lib/rules/react-usememo-should-be-component.js +256 -0
  38. package/package.json +5 -5
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reactUseMemoShouldBeComponent = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ /**
7
+ * Checks if a node is a JSX element or fragment
8
+ */
9
+ const isJsxElement = (node) => {
10
+ if (!node)
11
+ return false;
12
+ if (node.type === utils_1.AST_NODE_TYPES.ConditionalExpression) {
13
+ return isJsxElement(node.consequent) || isJsxElement(node.alternate);
14
+ }
15
+ return (node.type === utils_1.AST_NODE_TYPES.JSXElement ||
16
+ node.type === utils_1.AST_NODE_TYPES.JSXFragment);
17
+ };
18
+ /**
19
+ * Checks if an object contains JSX elements in its properties
20
+ */
21
+ const containsJsxInObject = (node) => {
22
+ for (const property of node.properties) {
23
+ if (property.type === utils_1.AST_NODE_TYPES.Property && property.value) {
24
+ if (isJsxElement(property.value)) {
25
+ return true;
26
+ }
27
+ // Check nested objects
28
+ if (property.value.type === utils_1.AST_NODE_TYPES.ObjectExpression) {
29
+ if (containsJsxInObject(property.value)) {
30
+ return true;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ return false;
36
+ };
37
+ /**
38
+ * Checks if a switch statement contains JSX elements
39
+ */
40
+ const containsJsxInSwitchStatement = (node) => {
41
+ for (const switchCase of node.cases) {
42
+ for (const statement of switchCase.consequent) {
43
+ if (statement.type === utils_1.AST_NODE_TYPES.ReturnStatement && statement.argument) {
44
+ if (isJsxElement(statement.argument)) {
45
+ return true;
46
+ }
47
+ }
48
+ if (statement.type === utils_1.AST_NODE_TYPES.BlockStatement) {
49
+ if (containsJsxInBlockStatement(statement)) {
50
+ return true;
51
+ }
52
+ }
53
+ }
54
+ }
55
+ return false;
56
+ };
57
+ /**
58
+ * Checks if a function contains JSX elements
59
+ */
60
+ const containsJsxInFunction = (node) => {
61
+ const body = node.body;
62
+ // Direct JSX return
63
+ if (isJsxElement(body)) {
64
+ return true;
65
+ }
66
+ // JSX in block statement
67
+ if (body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
68
+ return containsJsxInBlockStatement(body);
69
+ }
70
+ // Check for array methods returning JSX
71
+ if (body.type === utils_1.AST_NODE_TYPES.CallExpression) {
72
+ if (body.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
73
+ body.callee.property.type === utils_1.AST_NODE_TYPES.Identifier) {
74
+ // Check array methods like map, filter, find, etc.
75
+ const arrayMethods = ['map', 'filter', 'find', 'findIndex', 'some', 'every', 'reduce'];
76
+ if (arrayMethods.includes(body.callee.property.name) && body.arguments.length > 0) {
77
+ const callback = body.arguments[0];
78
+ if ((callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
79
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) &&
80
+ containsJsxInFunction(callback)) {
81
+ return true;
82
+ }
83
+ }
84
+ }
85
+ // Check for IIFE
86
+ if ((body.callee.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
87
+ body.callee.type === utils_1.AST_NODE_TYPES.FunctionExpression) &&
88
+ containsJsxInFunction(body.callee)) {
89
+ return true;
90
+ }
91
+ // Check for IIFE with parentheses
92
+ if (body.callee.type === utils_1.AST_NODE_TYPES.CallExpression) {
93
+ return containsJsxInExpression(body);
94
+ }
95
+ }
96
+ return false;
97
+ };
98
+ /**
99
+ * Checks if an expression contains JSX elements
100
+ */
101
+ const containsJsxInExpression = (node) => {
102
+ if (!node)
103
+ return false;
104
+ if (isJsxElement(node)) {
105
+ return true;
106
+ }
107
+ switch (node.type) {
108
+ case utils_1.AST_NODE_TYPES.ConditionalExpression:
109
+ return containsJsxInExpression(node.consequent) || containsJsxInExpression(node.alternate);
110
+ case utils_1.AST_NODE_TYPES.LogicalExpression:
111
+ return containsJsxInExpression(node.left) || containsJsxInExpression(node.right);
112
+ case utils_1.AST_NODE_TYPES.ObjectExpression:
113
+ return containsJsxInObject(node);
114
+ case utils_1.AST_NODE_TYPES.CallExpression:
115
+ // Check if it's an IIFE
116
+ if (node.callee.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
117
+ node.callee.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
118
+ return containsJsxInFunction(node.callee);
119
+ }
120
+ // Check array methods
121
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
122
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier) {
123
+ const arrayMethods = ['map', 'filter', 'find', 'findIndex', 'some', 'every', 'reduce'];
124
+ if (arrayMethods.includes(node.callee.property.name) && node.arguments.length > 0) {
125
+ const callback = node.arguments[0];
126
+ if ((callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
127
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression)) {
128
+ return containsJsxInFunction(callback);
129
+ }
130
+ }
131
+ }
132
+ // Check arguments for JSX
133
+ for (const arg of node.arguments) {
134
+ if (arg.type !== utils_1.AST_NODE_TYPES.SpreadElement && containsJsxInExpression(arg)) {
135
+ return true;
136
+ }
137
+ }
138
+ return false;
139
+ case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
140
+ case utils_1.AST_NODE_TYPES.FunctionExpression:
141
+ return containsJsxInFunction(node);
142
+ default:
143
+ return false;
144
+ }
145
+ };
146
+ /**
147
+ * Checks if a block statement contains JSX elements
148
+ */
149
+ const containsJsxInBlockStatement = (node) => {
150
+ for (const statement of node.body) {
151
+ // Check return statements
152
+ if (statement.type === utils_1.AST_NODE_TYPES.ReturnStatement && statement.argument) {
153
+ if (containsJsxInExpression(statement.argument)) {
154
+ return true;
155
+ }
156
+ }
157
+ // Check if statements
158
+ if (statement.type === utils_1.AST_NODE_TYPES.IfStatement) {
159
+ if (statement.consequent.type === utils_1.AST_NODE_TYPES.ReturnStatement &&
160
+ statement.consequent.argument && containsJsxInExpression(statement.consequent.argument)) {
161
+ return true;
162
+ }
163
+ if (statement.consequent.type === utils_1.AST_NODE_TYPES.BlockStatement &&
164
+ containsJsxInBlockStatement(statement.consequent)) {
165
+ return true;
166
+ }
167
+ if (statement.alternate) {
168
+ if (statement.alternate.type === utils_1.AST_NODE_TYPES.ReturnStatement &&
169
+ statement.alternate.argument && containsJsxInExpression(statement.alternate.argument)) {
170
+ return true;
171
+ }
172
+ if (statement.alternate.type === utils_1.AST_NODE_TYPES.BlockStatement &&
173
+ containsJsxInBlockStatement(statement.alternate)) {
174
+ return true;
175
+ }
176
+ if (statement.alternate.type === utils_1.AST_NODE_TYPES.IfStatement) {
177
+ // Handle else if
178
+ if (containsJsxInExpression(statement.alternate.test)) {
179
+ return true;
180
+ }
181
+ if (statement.alternate.consequent &&
182
+ ((statement.alternate.consequent.type === utils_1.AST_NODE_TYPES.ReturnStatement &&
183
+ statement.alternate.consequent.argument &&
184
+ containsJsxInExpression(statement.alternate.consequent.argument)) ||
185
+ (statement.alternate.consequent.type === utils_1.AST_NODE_TYPES.BlockStatement &&
186
+ containsJsxInBlockStatement(statement.alternate.consequent)))) {
187
+ return true;
188
+ }
189
+ }
190
+ }
191
+ }
192
+ // Check switch statements
193
+ if (statement.type === utils_1.AST_NODE_TYPES.SwitchStatement) {
194
+ if (containsJsxInSwitchStatement(statement)) {
195
+ return true;
196
+ }
197
+ }
198
+ // Check variable declarations for JSX
199
+ if (statement.type === utils_1.AST_NODE_TYPES.VariableDeclaration) {
200
+ for (const declarator of statement.declarations) {
201
+ if (declarator.init && containsJsxInExpression(declarator.init)) {
202
+ return true;
203
+ }
204
+ }
205
+ }
206
+ // Check expressions
207
+ if (statement.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
208
+ containsJsxInExpression(statement.expression)) {
209
+ return true;
210
+ }
211
+ }
212
+ return false;
213
+ };
214
+ /**
215
+ * Checks if a useMemo call contains JSX elements
216
+ */
217
+ const containsJsxInUseMemo = (node) => {
218
+ if (node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
219
+ node.callee.name === 'useMemo' &&
220
+ node.arguments.length > 0) {
221
+ const callback = node.arguments[0];
222
+ if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
223
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
224
+ return containsJsxInFunction(callback);
225
+ }
226
+ }
227
+ return false;
228
+ };
229
+ exports.reactUseMemoShouldBeComponent = (0, createRule_1.createRule)({
230
+ name: 'react-usememo-should-be-component',
231
+ meta: {
232
+ type: 'suggestion',
233
+ docs: {
234
+ description: 'Enforce that useMemo hooks returning React nodes should be abstracted into separate React components',
235
+ recommended: 'error',
236
+ },
237
+ schema: [],
238
+ messages: {
239
+ useMemoShouldBeComponent: 'useMemo returning JSX should be extracted into a separate component. Use React.memo() for component memoization instead.',
240
+ },
241
+ },
242
+ defaultOptions: [],
243
+ create(context) {
244
+ return {
245
+ CallExpression(node) {
246
+ if (containsJsxInUseMemo(node)) {
247
+ context.report({
248
+ node,
249
+ messageId: 'useMemoShouldBeComponent',
250
+ });
251
+ }
252
+ },
253
+ };
254
+ },
255
+ });
256
+ //# sourceMappingURL=react-usememo-should-be-component.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "1.7.3",
3
+ "version": "1.8.0",
4
4
  "description": "Custom eslint rules for use within BluMint",
5
5
  "author": {
6
6
  "name": "Brodie McGuire",
@@ -71,7 +71,7 @@
71
71
  "dotenv-cli": "5.0.0",
72
72
  "eslint": "8.57.0",
73
73
  "eslint-config-prettier": "8.5.0",
74
- "eslint-doc-generator": "^1.7.1",
74
+ "eslint-doc-generator": "1.7.1",
75
75
  "eslint-import-resolver-typescript": "3.5.5",
76
76
  "eslint-plugin-eslint-plugin": "5.0.0",
77
77
  "eslint-plugin-import": "2.26.0",
@@ -81,7 +81,7 @@
81
81
  "eslint-plugin-security": "1.5.0",
82
82
  "fs": "0.0.1-security",
83
83
  "husky": "9.1.7",
84
- "jest": "29.3.1",
84
+ "jest": "29.7.0",
85
85
  "jest-junit": "14.0.0",
86
86
  "jsonc-eslint-parser": "2.3.0",
87
87
  "npm-run-all": "4.1.5",
@@ -90,7 +90,7 @@
90
90
  "remark-lint": "9.1.1",
91
91
  "remark-preset-lint-recommended": "6.1.2",
92
92
  "semantic-release": "19.0.3",
93
- "ts-jest": "29.0.5",
93
+ "ts-jest": "29.2.6",
94
94
  "ts-node": "10.9.1",
95
95
  "typescript": "4.9.5"
96
96
  },
@@ -98,7 +98,7 @@
98
98
  "eslint": ">=7"
99
99
  },
100
100
  "engines": {
101
- "node": "^22.0.0"
101
+ "node": ">=22.0.0"
102
102
  },
103
103
  "config": {
104
104
  "commitizen": {