@blumintinc/eslint-plugin-blumint 1.12.5 → 1.13.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 (142) hide show
  1. package/README.md +140 -99
  2. package/lib/index.js +111 -20
  3. package/lib/rules/array-methods-this-context.js +20 -2
  4. package/lib/rules/avoid-utils-directory.js +11 -2
  5. package/lib/rules/dynamic-https-errors.d.ts +3 -1
  6. package/lib/rules/dynamic-https-errors.js +48 -10
  7. package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
  8. package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +51 -95
  9. package/lib/rules/enforce-assert-throws.d.ts +3 -1
  10. package/lib/rules/enforce-assert-throws.js +493 -51
  11. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
  12. package/lib/rules/enforce-boolean-naming-prefixes.js +832 -39
  13. package/lib/rules/enforce-callable-types.js +4 -4
  14. package/lib/rules/enforce-callback-memo.js +143 -18
  15. package/lib/rules/enforce-centralized-mock-firestore.js +4 -1
  16. package/lib/rules/enforce-console-error.d.ts +3 -0
  17. package/lib/rules/enforce-console-error.js +250 -0
  18. package/lib/rules/enforce-css-media-queries.js +24 -46
  19. package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
  20. package/lib/rules/enforce-dynamic-imports.js +1 -1
  21. package/lib/rules/enforce-exported-function-types.js +3 -3
  22. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
  23. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +212 -0
  24. package/lib/rules/enforce-firestore-doc-ref-generic.js +335 -0
  25. package/lib/rules/enforce-firestore-facade.js +347 -157
  26. package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
  27. package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
  28. package/lib/rules/enforce-global-constants.d.ts +4 -1
  29. package/lib/rules/enforce-global-constants.js +240 -12
  30. package/lib/rules/enforce-memoize-async.d.ts +2 -1
  31. package/lib/rules/enforce-memoize-async.js +96 -27
  32. package/lib/rules/enforce-memoize-getters.d.ts +3 -0
  33. package/lib/rules/enforce-memoize-getters.js +123 -0
  34. package/lib/rules/enforce-microdiff.js +2 -1
  35. package/lib/rules/enforce-positive-naming.js +5 -7
  36. package/lib/rules/enforce-props-argument-name.d.ts +2 -7
  37. package/lib/rules/enforce-props-argument-name.js +165 -151
  38. package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
  39. package/lib/rules/enforce-props-naming-consistency.js +145 -0
  40. package/lib/rules/enforce-querykey-ts.d.ts +9 -0
  41. package/lib/rules/enforce-querykey-ts.js +274 -0
  42. package/lib/rules/enforce-singular-type-names.js +9 -5
  43. package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
  44. package/lib/rules/enforce-typescript-markdown-code-blocks.js +96 -0
  45. package/lib/rules/enforce-verb-noun-naming.js +85 -10
  46. package/lib/rules/extract-global-constants.js +57 -45
  47. package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
  48. package/lib/rules/fast-deep-equal-over-microdiff.js +356 -78
  49. package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
  50. package/lib/rules/firestore-transaction-reads-before-writes.js +231 -0
  51. package/lib/rules/generic-starts-with-t.js +8 -2
  52. package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
  53. package/lib/rules/memoize-root-level-hocs.js +242 -0
  54. package/lib/rules/no-array-length-in-deps.d.ts +12 -0
  55. package/lib/rules/no-array-length-in-deps.js +308 -0
  56. package/lib/rules/no-async-array-filter.js +5 -2
  57. package/lib/rules/no-complex-cloud-params.js +15 -2
  58. package/lib/rules/no-compositing-layer-props.js +4 -2
  59. package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
  60. package/lib/rules/no-entire-object-hook-deps.js +317 -63
  61. package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
  62. package/lib/rules/no-excessive-parent-chain.js +273 -0
  63. package/lib/rules/no-firestore-object-arrays.js +345 -30
  64. package/lib/rules/no-hungarian.js +13 -13
  65. package/lib/rules/no-margin-properties.d.ts +7 -1
  66. package/lib/rules/no-margin-properties.js +16 -3
  67. package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
  68. package/lib/rules/no-misleading-boolean-prefixes.js +327 -0
  69. package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
  70. package/lib/rules/no-overridable-method-calls-in-constructor.js +260 -0
  71. package/lib/rules/no-passthrough-getters.d.ts +4 -0
  72. package/lib/rules/no-passthrough-getters.js +170 -0
  73. package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
  74. package/lib/rules/no-redundant-usecallback-wrapper.js +315 -0
  75. package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
  76. package/lib/rules/no-restricted-properties-fix.js +172 -0
  77. package/lib/rules/no-separate-loading-state.d.ts +8 -0
  78. package/lib/rules/no-separate-loading-state.js +142 -0
  79. package/lib/rules/no-stale-state-across-await.d.ts +1 -0
  80. package/lib/rules/no-stale-state-across-await.js +185 -0
  81. package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
  82. package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
  83. package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
  84. package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
  85. package/lib/rules/no-undefined-null-passthrough.js +166 -19
  86. package/lib/rules/no-unnecessary-verb-suffix.js +0 -2
  87. package/lib/rules/no-unsafe-firestore-spread.js +8 -5
  88. package/lib/rules/no-unused-props.d.ts +3 -0
  89. package/lib/rules/no-unused-props.js +213 -78
  90. package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
  91. package/lib/rules/optimize-object-boolean-conditions.js +234 -0
  92. package/lib/rules/parallelize-async-operations.d.ts +8 -0
  93. package/lib/rules/parallelize-async-operations.js +375 -0
  94. package/lib/rules/prefer-batch-operations.js +199 -33
  95. package/lib/rules/prefer-block-comments-for-declarations.js +13 -3
  96. package/lib/rules/prefer-document-flattening.d.ts +4 -0
  97. package/lib/rules/prefer-document-flattening.js +239 -0
  98. package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
  99. package/lib/rules/prefer-field-paths-in-transforms.js +250 -0
  100. package/lib/rules/prefer-fragment-component.js +3 -3
  101. package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
  102. package/lib/rules/prefer-global-router-state-key.js +230 -31
  103. package/lib/rules/prefer-next-dynamic.d.ts +9 -0
  104. package/lib/rules/prefer-next-dynamic.js +366 -0
  105. package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
  106. package/lib/rules/prefer-nullish-coalescing-boolean-props.js +430 -0
  107. package/lib/rules/prefer-nullish-coalescing-override.d.ts +6 -0
  108. package/lib/rules/prefer-nullish-coalescing-override.js +182 -0
  109. package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
  110. package/lib/rules/prefer-params-over-parent-id.js +228 -0
  111. package/lib/rules/prefer-settings-object.js +23 -15
  112. package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
  113. package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
  114. package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
  115. package/lib/rules/prefer-url-tostring-over-tojson.js +166 -0
  116. package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
  117. package/lib/rules/prefer-use-deep-compare-memo.js +428 -0
  118. package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +24 -1
  119. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
  120. package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
  121. package/lib/rules/react-usememo-should-be-component.js +144 -78
  122. package/lib/rules/require-dynamic-firebase-imports.js +2 -1
  123. package/lib/rules/require-image-optimized.js +1 -1
  124. package/lib/rules/require-memo.js +11 -1
  125. package/lib/rules/require-usememo-object-literals.js +7 -1
  126. package/lib/rules/semantic-function-prefixes.js +38 -18
  127. package/lib/rules/sync-onwrite-name-func.js +5 -1
  128. package/lib/rules/test-file-location-enforcement.d.ts +1 -0
  129. package/lib/rules/test-file-location-enforcement.js +57 -0
  130. package/lib/rules/use-custom-link.js +6 -1
  131. package/lib/rules/use-custom-router.js +6 -1
  132. package/lib/rules/use-latest-callback.d.ts +3 -0
  133. package/lib/rules/use-latest-callback.js +270 -0
  134. package/lib/utils/ASTHelpers.js +10 -0
  135. package/lib/utils/createRule.js +1 -1
  136. package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
  137. package/lib/utils/ruleTester.d.ts +1 -0
  138. package/lib/utils/ruleTester.js +4 -1
  139. package/package.json +21 -14
  140. package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
  141. package/lib/rules/no-restricted-imports-dynamic.d.ts +0 -25
  142. package/lib/rules/no-restricted-imports-dynamic.js +0 -213
@@ -14,7 +14,7 @@ exports.useCustomRouter = (0, createRule_1.createRule)({
14
14
  fixable: 'code',
15
15
  schema: [],
16
16
  messages: {
17
- useCustomRouter: 'Import useRouter from src/hooks/routing/useRouter instead of next/router',
17
+ useCustomRouter: 'useRouter import "{{imports}}" comes from next/router, which bypasses the app-specific hook that applies auth checks, analytics, and redirect helpers. Import it from src/hooks/routing/useRouter so routing code stays consistent with the rest of the app.',
18
18
  },
19
19
  },
20
20
  defaultOptions: [],
@@ -29,6 +29,11 @@ exports.useCustomRouter = (0, createRule_1.createRule)({
29
29
  context.report({
30
30
  node,
31
31
  messageId: 'useCustomRouter',
32
+ data: {
33
+ imports: specifiers
34
+ .map((specifier) => specifier.local.name)
35
+ .join(', '),
36
+ },
32
37
  fix(fixer) {
33
38
  // If there are other imports from next/router, keep them
34
39
  const otherSpecifiers = node.specifiers.filter((specifier) => specifier.type !== utils_1.AST_NODE_TYPES.ImportSpecifier ||
@@ -0,0 +1,3 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const useLatestCallback: TSESLint.RuleModule<"useLatestCallback", [], TSESLint.RuleListener>;
3
+ export default useLatestCallback;
@@ -0,0 +1,270 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useLatestCallback = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const createRule_1 = require("../utils/createRule");
6
+ exports.useLatestCallback = (0, createRule_1.createRule)({
7
+ name: 'use-latest-callback',
8
+ meta: {
9
+ type: 'suggestion',
10
+ docs: {
11
+ description: 'Enforce using useLatestCallback from use-latest-callback instead of React useCallback',
12
+ recommended: 'error',
13
+ },
14
+ fixable: 'code',
15
+ schema: [],
16
+ messages: {
17
+ useLatestCallback: 'Replace {{currentHook}} with {{recommendedHook}} from "use-latest-callback" so the callback keeps a stable reference while still reading the latest props/state. useCallback recreates functions whenever dependencies change, which can trigger needless renders and stale closures. Drop the dependency array when switching to {{recommendedHook}}.',
18
+ },
19
+ },
20
+ defaultOptions: [],
21
+ create(context) {
22
+ const filename = context.getFilename();
23
+ if (filename.includes('/node_modules/')) {
24
+ return {};
25
+ }
26
+ // Track if the file already has a useLatestCallback import
27
+ let hasUseLatestCallbackImport = false;
28
+ let useLatestCallbackImportName = 'useLatestCallback';
29
+ // Track if any useCallback calls should be replaced
30
+ let hasNonJsxUseCallbacks = false;
31
+ let useCallbackLocalNames = new Set();
32
+ const reactNamespaceNames = new Set();
33
+ const reactDefaultLikeNames = new Set();
34
+ let hasReactMemberUseCallback = false;
35
+ const isJSXLikeReturn = (node) => {
36
+ if (!node)
37
+ return false;
38
+ if (node.type === utils_1.AST_NODE_TYPES.JSXElement ||
39
+ node.type === utils_1.AST_NODE_TYPES.JSXFragment ||
40
+ node.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer) {
41
+ return true;
42
+ }
43
+ if (node.type === 'ParenthesizedExpression') {
44
+ return isJSXLikeReturn(node.expression);
45
+ }
46
+ if (node.type === utils_1.AST_NODE_TYPES.SequenceExpression) {
47
+ return isJSXLikeReturn(node.expressions[node.expressions.length - 1]);
48
+ }
49
+ if (node.type === utils_1.AST_NODE_TYPES.ArrayExpression) {
50
+ return node.elements.some((el) => isJSXLikeReturn(el && el.type === utils_1.AST_NODE_TYPES.SpreadElement
51
+ ? el.argument
52
+ : el));
53
+ }
54
+ if (node.type === utils_1.AST_NODE_TYPES.ConditionalExpression) {
55
+ return (isJSXLikeReturn(node.consequent) || isJSXLikeReturn(node.alternate));
56
+ }
57
+ if (node.type === utils_1.AST_NODE_TYPES.LogicalExpression) {
58
+ return (isJSXLikeReturn(node.left) || isJSXLikeReturn(node.right));
59
+ }
60
+ if (node.type === utils_1.AST_NODE_TYPES.CallExpression) {
61
+ if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
62
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
63
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
64
+ reactNamespaceNames.has(node.callee.object.name) &&
65
+ node.callee.property.name === 'createElement') {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ };
71
+ return {
72
+ // First pass: check imports
73
+ ImportDeclaration(node) {
74
+ if (node.importKind && node.importKind !== 'value')
75
+ return;
76
+ if (node.source.value === 'use-latest-callback') {
77
+ // Check if useLatestCallback is imported
78
+ const specifiers = node.specifiers.filter((specifier) => {
79
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier) {
80
+ return (specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
81
+ specifier.imported.name === 'useLatestCallback');
82
+ }
83
+ return (specifier.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
84
+ specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier);
85
+ });
86
+ if (specifiers.length > 0) {
87
+ hasUseLatestCallbackImport = true;
88
+ // Get the local name of the import (in case it's renamed)
89
+ if (specifiers[0].type === utils_1.AST_NODE_TYPES.ImportSpecifier) {
90
+ useLatestCallbackImportName = specifiers[0].local.name;
91
+ }
92
+ else if (specifiers[0].type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier) {
93
+ useLatestCallbackImportName = specifiers[0].local.name;
94
+ }
95
+ else if (specifiers[0].type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) {
96
+ useLatestCallbackImportName = `${specifiers[0].local.name}.useLatestCallback`;
97
+ }
98
+ }
99
+ }
100
+ else if (node.source.value === 'react') {
101
+ // Check if useCallback is imported from React
102
+ const useCallbackSpecifiers = node.specifiers.filter((specifier) => {
103
+ return (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
104
+ specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
105
+ specifier.imported.name === 'useCallback');
106
+ });
107
+ node.specifiers.forEach((specifier) => {
108
+ if (specifier.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
109
+ specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) {
110
+ reactNamespaceNames.add(specifier.local.name);
111
+ reactDefaultLikeNames.add(specifier.local.name);
112
+ }
113
+ });
114
+ if (useCallbackSpecifiers.length > 0) {
115
+ useCallbackSpecifiers.forEach((spec) => {
116
+ useCallbackLocalNames.add(spec.local.name);
117
+ });
118
+ }
119
+ }
120
+ },
121
+ // Check for useCallback usage and identify JSX-returning callbacks
122
+ CallExpression(node) {
123
+ const isUseCallbackIdentifierCall = node.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
124
+ useCallbackLocalNames.has(node.callee.name);
125
+ const isUseCallbackMemberCall = node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
126
+ node.callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
127
+ reactDefaultLikeNames.has(node.callee.object.name) &&
128
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
129
+ node.callee.property.name === 'useCallback';
130
+ if ((isUseCallbackIdentifierCall || isUseCallbackMemberCall) && node.arguments.length >= 1) {
131
+ if (isUseCallbackMemberCall) {
132
+ hasReactMemberUseCallback = true;
133
+ }
134
+ // Check if this is a JSX-returning callback (edge case where we shouldn't replace)
135
+ const callback = node.arguments[0];
136
+ let isJsxReturning = false;
137
+ if ((callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
138
+ callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) &&
139
+ callback.body) {
140
+ // For arrow functions with implicit return
141
+ if (callback.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
142
+ if (isJSXLikeReturn(callback.body)) {
143
+ isJsxReturning = true;
144
+ }
145
+ }
146
+ // For functions with block body - check all return statements
147
+ else if (callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
148
+ const returnStatements = callback.body.body.filter((statement) => statement.type === utils_1.AST_NODE_TYPES.ReturnStatement);
149
+ // If there are return statements, check if any return JSX
150
+ if (returnStatements.length > 0) {
151
+ isJsxReturning = returnStatements.some((returnStatement) => returnStatement.argument &&
152
+ isJSXLikeReturn(returnStatement.argument));
153
+ }
154
+ }
155
+ }
156
+ if (!isJsxReturning) {
157
+ hasNonJsxUseCallbacks = true;
158
+ const currentCallbackName = node.callee.type === utils_1.AST_NODE_TYPES.Identifier
159
+ ? node.callee.name
160
+ : node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
161
+ node.callee.property.type === utils_1.AST_NODE_TYPES.Identifier
162
+ ? node.callee.property.name
163
+ : 'useCallback';
164
+ const replacementName = hasUseLatestCallbackImport
165
+ ? useLatestCallbackImportName
166
+ : currentCallbackName === 'useCallback'
167
+ ? 'useLatestCallback'
168
+ : currentCallbackName;
169
+ // Report the useCallback call for replacement
170
+ context.report({
171
+ node,
172
+ messageId: 'useLatestCallback',
173
+ data: {
174
+ currentHook: currentCallbackName,
175
+ recommendedHook: replacementName,
176
+ },
177
+ fix(fixer) {
178
+ const sourceCode = context.getSourceCode();
179
+ const callbackText = sourceCode.getText(node.arguments[0]);
180
+ const typeParams = node.typeParameters
181
+ ? sourceCode.getText(node.typeParameters)
182
+ : '';
183
+ // Replace useCallback with useLatestCallback and remove the dependency array
184
+ return fixer.replaceText(node, `${replacementName}${typeParams}(${callbackText})`);
185
+ },
186
+ });
187
+ }
188
+ }
189
+ },
190
+ // Final pass: check for useCallback import from react (only if there are non-JSX callbacks)
191
+ 'Program:exit'() {
192
+ if (!hasNonJsxUseCallbacks) {
193
+ return; // Don't modify imports if all useCallback calls return JSX
194
+ }
195
+ const sourceCode = context.getSourceCode();
196
+ const program = sourceCode.ast;
197
+ for (const statement of program.body) {
198
+ if (statement.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
199
+ statement.source.value === 'react') {
200
+ if (statement.importKind && statement.importKind !== 'value') {
201
+ continue;
202
+ }
203
+ const specifiers = statement.specifiers.filter((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
204
+ specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
205
+ specifier.imported.name === 'useCallback');
206
+ if (specifiers.length > 0 || hasReactMemberUseCallback) {
207
+ const useCallbackLocalName = specifiers[0]?.local.name ?? 'useCallback';
208
+ const recommendedHook = hasUseLatestCallbackImport
209
+ ? useLatestCallbackImportName
210
+ : useCallbackLocalName === 'useCallback'
211
+ ? 'useLatestCallback'
212
+ : useCallbackLocalName;
213
+ context.report({
214
+ node: statement,
215
+ messageId: 'useLatestCallback',
216
+ data: {
217
+ currentHook: useCallbackLocalName,
218
+ recommendedHook,
219
+ },
220
+ fix(fixer) {
221
+ const importText = `import ${useCallbackLocalName === 'useCallback'
222
+ ? 'useLatestCallback'
223
+ : useCallbackLocalName} from 'use-latest-callback';`;
224
+ if (specifiers.length === 0) {
225
+ if (hasUseLatestCallbackImport)
226
+ return null;
227
+ return fixer.insertTextBefore(statement, `${importText}\n`);
228
+ }
229
+ const defaultOrNamespace = statement.specifiers.find((s) => s.type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier ||
230
+ s.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier);
231
+ const remainingNamed = statement.specifiers.filter((s) => s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
232
+ s.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
233
+ s.imported.name !== 'useCallback');
234
+ const prefix = statement.importKind && statement.importKind !== 'value'
235
+ ? 'import type'
236
+ : 'import';
237
+ if (remainingNamed.length === 0 && !defaultOrNamespace) {
238
+ if (!hasUseLatestCallbackImport) {
239
+ return fixer.replaceText(statement, importText);
240
+ }
241
+ return fixer.remove(statement);
242
+ }
243
+ const parts = [];
244
+ if (defaultOrNamespace) {
245
+ parts.push(sourceCode.getText(defaultOrNamespace));
246
+ }
247
+ if (remainingNamed.length > 0) {
248
+ parts.push(`{ ${remainingNamed
249
+ .map((s) => sourceCode.getText(s))
250
+ .join(', ')} }`);
251
+ }
252
+ const replacement = `${prefix} ${parts.join(', ')} from 'react';`;
253
+ const fixes = [];
254
+ if (!hasUseLatestCallbackImport) {
255
+ fixes.push(fixer.insertTextBefore(statement, `${importText}\n`));
256
+ }
257
+ fixes.push(fixer.replaceText(statement, replacement));
258
+ return fixes;
259
+ },
260
+ });
261
+ }
262
+ break;
263
+ }
264
+ }
265
+ },
266
+ };
267
+ },
268
+ });
269
+ exports.default = exports.useLatestCallback;
270
+ //# sourceMappingURL=use-latest-callback.js.map
@@ -14,9 +14,15 @@ class ASTHelpers {
14
14
  if (!node) {
15
15
  return false;
16
16
  }
17
+ // Gracefully handle ParenthesizedExpression without widening AST node types
18
+ if (node.type === 'ParenthesizedExpression') {
19
+ return this.declarationIncludesIdentifier(node.expression);
20
+ }
17
21
  switch (node.type) {
18
22
  case 'TSNonNullExpression':
19
23
  return this.declarationIncludesIdentifier(node.expression);
24
+ case 'TSSatisfiesExpression':
25
+ return this.declarationIncludesIdentifier(node.expression);
20
26
  case 'ArrayPattern':
21
27
  return node.elements.some((element) => ASTHelpers.declarationIncludesIdentifier(element));
22
28
  case 'ObjectPattern':
@@ -114,6 +120,10 @@ class ASTHelpers {
114
120
  if (!node) {
115
121
  return dependencies;
116
122
  }
123
+ // Gracefully handle ParenthesizedExpression without widening AST node types
124
+ if (node.type === 'ParenthesizedExpression') {
125
+ return ASTHelpers.classMethodDependenciesOf(node.expression, graph, className);
126
+ }
117
127
  switch (node.type) {
118
128
  case 'MethodDefinition':
119
129
  const functionBody = node.value.body;
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRule = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
- exports.createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/BluMintInc/eslint-custom-rules/plugin/docs/rules/${name}.md`);
5
+ exports.createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/BluMintInc/eslint-custom-rules/docs/rules/${name}.md`);
6
6
  //# sourceMappingURL=createRule.js.map
@@ -86,7 +86,6 @@ class ClassGraphSorterReadability extends ClassGraphSorter_1.ClassGraphSorter {
86
86
  return dfsSortedNodes;
87
87
  }
88
88
  }
89
- exports.ClassGraphSorterReadability = ClassGraphSorterReadability;
90
89
  ClassGraphSorterReadability.MODIFIER_PRIORITY_MAP = {
91
90
  isStatic: [true, false],
92
91
  accessibility: ['public', undefined, 'private'],
@@ -98,4 +97,5 @@ ClassGraphSorterReadability.SEARCH_NODE_PRIORITY_FUNCTIONS = [
98
97
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
99
98
  (method, _methods) => method.dependencies.length === 0,
100
99
  ];
100
+ exports.ClassGraphSorterReadability = ClassGraphSorterReadability;
101
101
  //# sourceMappingURL=ClassGraphSorterReadability.js.map
@@ -3,3 +3,4 @@ import { RuleTester } from 'eslint';
3
3
  export declare const ruleTesterTs: ESLintUtils.RuleTester;
4
4
  export declare const ruleTesterJsx: ESLintUtils.RuleTester;
5
5
  export declare const ruleTesterJson: RuleTester;
6
+ export declare const ruleTesterMarkdown: RuleTester;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ruleTesterJson = exports.ruleTesterJsx = exports.ruleTesterTs = void 0;
3
+ exports.ruleTesterMarkdown = exports.ruleTesterJson = exports.ruleTesterJsx = exports.ruleTesterTs = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const eslint_1 = require("eslint");
6
6
  exports.ruleTesterTs = new utils_1.ESLintUtils.RuleTester({
@@ -20,4 +20,7 @@ exports.ruleTesterJson = new eslint_1.RuleTester({
20
20
  ecmaVersion: 2020,
21
21
  },
22
22
  });
23
+ exports.ruleTesterMarkdown = new eslint_1.RuleTester({
24
+ parser: require.resolve('markdown-eslint-parser'),
25
+ });
23
26
  //# sourceMappingURL=ruleTester.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "1.12.5",
3
+ "version": "1.13.0",
4
4
  "description": "Custom eslint rules for use within BluMint",
5
5
  "author": {
6
6
  "name": "Brodie McGuire",
@@ -13,12 +13,12 @@
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/BluMintInc/custom-eslint-rules.git"
16
+ "url": "git+https://github.com/BluMintInc/eslint-custom-rules.git"
17
17
  },
18
18
  "bugs": {
19
- "url": "https://github.com/BluMintInc/custom-eslint-rules/issues"
19
+ "url": "https://github.com/BluMintInc/eslint-custom-rules/issues"
20
20
  },
21
- "homepage": "https://github.com/BluMintInc/custom-eslint-rules#readme",
21
+ "homepage": "https://github.com/BluMintInc/eslint-custom-rules#readme",
22
22
  "keywords": [
23
23
  "eslint",
24
24
  "eslintplugin",
@@ -29,10 +29,15 @@
29
29
  "lint": "npm-run-all \"lint:*\"",
30
30
  "lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"",
31
31
  "lint:js": "eslint ./src",
32
- "lint:shell": "shellcheck .devcontainer/git-flow-completion.bash",
33
32
  "lint:fix": "tsc && eslint \"./src/**/*\" --quiet --fix",
34
33
  "test": "jest --passWithNoTests --reporters=default --reporters=jest-junit",
35
34
  "test:ci": "jest --ci --passWithNoTests --reporters=default --reporters=jest-junit",
35
+ "address-review": "tsx ./.github/scripts/address-review.ts",
36
+ "merge-review": "tsx ./.github/scripts/merge-review.ts",
37
+ "fetch-unresolved-comments": "./scripts/pr-check-comments.sh",
38
+ "fetch-unresolved-bot-comments": "./scripts/pr-check-bot-comments.sh",
39
+ "resolve-comments": "./scripts/pr-resolve-comments.sh",
40
+ "apply-comment-decisions": "./scripts/pr-apply-comment-decisions.sh",
36
41
  "docs": "./scripts/make-docs.sh && npm run update:eslint-docs",
37
42
  "update:eslint-docs": "eslint-doc-generator --init-rule-docs",
38
43
  "build": "tsc",
@@ -54,12 +59,12 @@
54
59
  "devDependencies": {
55
60
  "@commitlint/cli": "19.6.1",
56
61
  "@commitlint/config-conventional": "19.6.0",
57
- "@semantic-release/changelog": "6.0.1",
58
- "@semantic-release/commit-analyzer": "9.0.2",
59
- "@semantic-release/exec": "6.0.3",
62
+ "@semantic-release/changelog": "6.0.3",
63
+ "@semantic-release/commit-analyzer": "13.0.1",
64
+ "@semantic-release/exec": "7.1.0",
60
65
  "@semantic-release/git": "10.0.1",
61
- "@semantic-release/npm": "9.0.1",
62
- "@semantic-release/release-notes-generator": "10.0.3",
66
+ "@semantic-release/npm": "13.1.2",
67
+ "@semantic-release/release-notes-generator": "14.1.0",
63
68
  "@types/eslint": "8.37.0",
64
69
  "@types/jest": "29.5.14",
65
70
  "@types/node": "18.7.13",
@@ -72,9 +77,9 @@
72
77
  "cz-conventional-changelog": "3.3.0",
73
78
  "del-cli": "4.0.1",
74
79
  "dotenv-cli": "5.0.0",
75
- "eslint": "8.57.0",
80
+ "eslint": "8.57.1",
76
81
  "eslint-config-prettier": "8.5.0",
77
- "eslint-doc-generator": "1.7.1",
82
+ "eslint-doc-generator": "2.2.0",
78
83
  "eslint-import-resolver-typescript": "3.5.5",
79
84
  "eslint-plugin-eslint-plugin": "5.0.0",
80
85
  "eslint-plugin-import": "2.26.0",
@@ -87,15 +92,17 @@
87
92
  "jest": "29.7.0",
88
93
  "jest-junit": "14.0.0",
89
94
  "jsonc-eslint-parser": "2.3.0",
95
+ "markdown-eslint-parser": "1.2.1",
90
96
  "npm-run-all": "4.1.5",
91
97
  "prettier": "2.7.1",
92
98
  "remark-cli": "10.0.1",
93
99
  "remark-lint": "9.1.1",
94
100
  "remark-preset-lint-recommended": "6.1.2",
95
- "semantic-release": "19.0.3",
101
+ "semantic-release": "25.0.2",
96
102
  "ts-jest": "29.2.6",
97
103
  "ts-node": "10.9.1",
98
- "typescript": "4.9.5"
104
+ "tsx": "4.19.4",
105
+ "typescript": "5.0.3"
99
106
  },
100
107
  "peerDependencies": {
101
108
  "eslint": ">=7"
@@ -1,2 +0,0 @@
1
- import { TSESLint } from '@typescript-eslint/utils';
2
- export declare const enforceAssertSafeObjectKey: TSESLint.RuleModule<"useAssertSafe", [], TSESLint.RuleListener>;
@@ -1,25 +0,0 @@
1
- export declare const RULE_NAME = "no-restricted-imports-dynamic";
2
- type Options = [
3
- {
4
- paths?: (string | {
5
- name: string;
6
- message?: string;
7
- allowTypeImports?: boolean;
8
- allowDynamicImports?: boolean;
9
- })[];
10
- patterns?: (string | {
11
- group: string[];
12
- message?: string;
13
- caseSensitive?: boolean;
14
- allowTypeImports?: boolean;
15
- allowDynamicImports?: boolean;
16
- })[];
17
- } | (string | {
18
- name: string;
19
- message?: string;
20
- allowTypeImports?: boolean;
21
- allowDynamicImports?: boolean;
22
- })[]
23
- ];
24
- declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"restrictedImport" | "restrictedImportPattern", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
25
- export default _default;