@blumintinc/eslint-plugin-blumint 1.12.6 → 1.14.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 (258) hide show
  1. package/README.md +171 -99
  2. package/lib/index.js +300 -17
  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/class-methods-read-top-to-bottom.js +24 -5
  6. package/lib/rules/consistent-callback-naming.js +1 -1
  7. package/lib/rules/dynamic-https-errors.d.ts +3 -1
  8. package/lib/rules/dynamic-https-errors.js +48 -11
  9. package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
  10. package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +52 -96
  11. package/lib/rules/enforce-assert-throws.d.ts +3 -1
  12. package/lib/rules/enforce-assert-throws.js +493 -51
  13. package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
  14. package/lib/rules/enforce-boolean-naming-prefixes.js +820 -39
  15. package/lib/rules/enforce-callable-types.js +4 -4
  16. package/lib/rules/enforce-callback-memo.js +143 -18
  17. package/lib/rules/enforce-centralized-mock-firestore.js +5 -2
  18. package/lib/rules/enforce-console-error.d.ts +3 -0
  19. package/lib/rules/enforce-console-error.js +278 -0
  20. package/lib/rules/enforce-css-media-queries.js +24 -46
  21. package/lib/rules/enforce-dynamic-file-naming.d.ts +2 -0
  22. package/lib/rules/enforce-dynamic-file-naming.js +53 -28
  23. package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
  24. package/lib/rules/enforce-dynamic-imports.js +1 -1
  25. package/lib/rules/enforce-early-destructuring.d.ts +2 -0
  26. package/lib/rules/enforce-early-destructuring.js +980 -0
  27. package/lib/rules/enforce-empty-object-check.d.ts +11 -0
  28. package/lib/rules/enforce-empty-object-check.js +502 -0
  29. package/lib/rules/enforce-exported-function-types.js +4 -4
  30. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
  31. package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +262 -0
  32. package/lib/rules/enforce-firestore-doc-ref-generic.js +350 -3
  33. package/lib/rules/enforce-firestore-facade.js +349 -157
  34. package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
  35. package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
  36. package/lib/rules/enforce-firestore-set-merge.js +3 -4
  37. package/lib/rules/enforce-global-constants.d.ts +4 -1
  38. package/lib/rules/enforce-global-constants.js +240 -12
  39. package/lib/rules/enforce-identifiable-firestore-type.js +108 -58
  40. package/lib/rules/enforce-memoize-async.d.ts +2 -1
  41. package/lib/rules/enforce-memoize-async.js +92 -27
  42. package/lib/rules/enforce-memoize-getters.d.ts +3 -0
  43. package/lib/rules/enforce-memoize-getters.js +147 -0
  44. package/lib/rules/enforce-microdiff.js +3 -2
  45. package/lib/rules/enforce-object-literal-as-const.js +4 -4
  46. package/lib/rules/enforce-positive-naming.js +9 -7
  47. package/lib/rules/enforce-props-argument-name.d.ts +2 -7
  48. package/lib/rules/enforce-props-argument-name.js +165 -151
  49. package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
  50. package/lib/rules/enforce-props-naming-consistency.js +145 -0
  51. package/lib/rules/enforce-querykey-ts.d.ts +9 -0
  52. package/lib/rules/enforce-querykey-ts.js +274 -0
  53. package/lib/rules/enforce-safe-stringify.js +1 -1
  54. package/lib/rules/enforce-serializable-params.js +3 -3
  55. package/lib/rules/enforce-singular-type-names.js +10 -6
  56. package/lib/rules/enforce-stable-hash-spread-props.d.ts +13 -0
  57. package/lib/rules/enforce-stable-hash-spread-props.js +342 -0
  58. package/lib/rules/enforce-storage-context.d.ts +9 -0
  59. package/lib/rules/enforce-storage-context.js +646 -0
  60. package/lib/rules/enforce-timestamp-now.js +23 -7
  61. package/lib/rules/enforce-transform-memoization.d.ts +4 -0
  62. package/lib/rules/enforce-transform-memoization.js +416 -0
  63. package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
  64. package/lib/rules/enforce-typescript-markdown-code-blocks.js +100 -0
  65. package/lib/rules/enforce-unique-cursor-headers.d.ts +16 -0
  66. package/lib/rules/enforce-unique-cursor-headers.js +365 -0
  67. package/lib/rules/enforce-verb-noun-naming.js +90 -14
  68. package/lib/rules/ensure-pointer-events-none.js +28 -2
  69. package/lib/rules/export-if-in-doubt.js +27 -4
  70. package/lib/rules/extract-global-constants.js +92 -53
  71. package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
  72. package/lib/rules/fast-deep-equal-over-microdiff.js +351 -83
  73. package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
  74. package/lib/rules/firestore-transaction-reads-before-writes.js +277 -0
  75. package/lib/rules/flatten-push-calls.d.ts +2 -0
  76. package/lib/rules/flatten-push-calls.js +428 -0
  77. package/lib/rules/generic-starts-with-t.js +8 -2
  78. package/lib/rules/global-const-style.js +50 -19
  79. package/lib/rules/jsdoc-above-field.d.ts +11 -0
  80. package/lib/rules/jsdoc-above-field.js +208 -0
  81. package/lib/rules/key-only-outermost-element.js +21 -3
  82. package/lib/rules/logical-top-to-bottom-grouping.d.ts +5 -0
  83. package/lib/rules/logical-top-to-bottom-grouping.js +1258 -0
  84. package/lib/rules/memo-compare-deeply-complex-props.d.ts +3 -0
  85. package/lib/rules/memo-compare-deeply-complex-props.js +788 -0
  86. package/lib/rules/memo-nested-react-components.d.ts +8 -0
  87. package/lib/rules/memo-nested-react-components.js +410 -0
  88. package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
  89. package/lib/rules/memoize-root-level-hocs.js +242 -0
  90. package/lib/rules/no-always-true-false-conditions.d.ts +2 -1
  91. package/lib/rules/no-always-true-false-conditions.js +68 -8
  92. package/lib/rules/no-array-length-in-deps.d.ts +12 -0
  93. package/lib/rules/no-array-length-in-deps.js +314 -0
  94. package/lib/rules/no-async-array-filter.js +5 -2
  95. package/lib/rules/no-async-foreach.js +210 -12
  96. package/lib/rules/no-circular-references.js +18 -17
  97. package/lib/rules/no-class-instance-destructuring.js +55 -12
  98. package/lib/rules/no-complex-cloud-params.js +22 -5
  99. package/lib/rules/no-compositing-layer-props.js +6 -4
  100. package/lib/rules/no-conditional-literals-in-jsx.js +37 -12
  101. package/lib/rules/no-console-error.d.ts +9 -0
  102. package/lib/rules/no-console-error.js +525 -0
  103. package/lib/rules/no-curly-brackets-around-commented-properties.d.ts +2 -0
  104. package/lib/rules/no-curly-brackets-around-commented-properties.js +258 -0
  105. package/lib/rules/no-empty-dependency-use-callbacks.d.ts +11 -0
  106. package/lib/rules/no-empty-dependency-use-callbacks.js +576 -0
  107. package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
  108. package/lib/rules/no-entire-object-hook-deps.js +320 -68
  109. package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
  110. package/lib/rules/no-excessive-parent-chain.js +273 -0
  111. package/lib/rules/no-explicit-return-type.d.ts +2 -1
  112. package/lib/rules/no-explicit-return-type.js +215 -26
  113. package/lib/rules/no-filter-without-return.js +5 -1
  114. package/lib/rules/no-firestore-jest-mock.d.ts +2 -1
  115. package/lib/rules/no-firestore-jest-mock.js +126 -8
  116. package/lib/rules/no-firestore-object-arrays.js +398 -28
  117. package/lib/rules/no-handler-suffix.d.ts +12 -0
  118. package/lib/rules/no-handler-suffix.js +305 -0
  119. package/lib/rules/no-hungarian.js +14 -14
  120. package/lib/rules/no-inline-component-prop.d.ts +10 -0
  121. package/lib/rules/no-inline-component-prop.js +456 -0
  122. package/lib/rules/no-jsx-in-hooks.js +6 -1
  123. package/lib/rules/no-jsx-whitespace-literal.js +8 -2
  124. package/lib/rules/no-margin-properties.d.ts +7 -1
  125. package/lib/rules/no-margin-properties.js +22 -9
  126. package/lib/rules/no-memoize-on-static.js +9 -1
  127. package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
  128. package/lib/rules/no-misleading-boolean-prefixes.js +331 -0
  129. package/lib/rules/no-misused-switch-case.js +22 -1
  130. package/lib/rules/no-mixed-firestore-transactions.d.ts +3 -1
  131. package/lib/rules/no-mixed-firestore-transactions.js +296 -34
  132. package/lib/rules/no-mock-firebase-admin.js +5 -2
  133. package/lib/rules/no-object-values-on-strings.js +10 -2
  134. package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
  135. package/lib/rules/no-overridable-method-calls-in-constructor.js +272 -0
  136. package/lib/rules/no-passthrough-getters.d.ts +4 -0
  137. package/lib/rules/no-passthrough-getters.js +206 -0
  138. package/lib/rules/no-redundant-annotation-assertion.d.ts +2 -0
  139. package/lib/rules/no-redundant-annotation-assertion.js +402 -0
  140. package/lib/rules/no-redundant-param-types.js +16 -6
  141. package/lib/rules/no-redundant-this-params.d.ts +3 -0
  142. package/lib/rules/no-redundant-this-params.js +459 -0
  143. package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
  144. package/lib/rules/no-redundant-usecallback-wrapper.js +328 -0
  145. package/lib/rules/no-res-error-status-in-onrequest.d.ts +4 -0
  146. package/lib/rules/no-res-error-status-in-onrequest.js +521 -0
  147. package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
  148. package/lib/rules/no-restricted-properties-fix.js +173 -0
  149. package/lib/rules/no-separate-loading-state.d.ts +8 -0
  150. package/lib/rules/no-separate-loading-state.js +133 -0
  151. package/lib/rules/no-stale-state-across-await.d.ts +1 -0
  152. package/lib/rules/no-stale-state-across-await.js +185 -0
  153. package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
  154. package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
  155. package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
  156. package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
  157. package/lib/rules/no-type-assertion-returns.js +49 -49
  158. package/lib/rules/no-undefined-null-passthrough.js +217 -40
  159. package/lib/rules/no-unmemoized-memo-without-props.d.ts +8 -0
  160. package/lib/rules/no-unmemoized-memo-without-props.js +426 -0
  161. package/lib/rules/no-unnecessary-destructuring-rename.d.ts +2 -0
  162. package/lib/rules/no-unnecessary-destructuring-rename.js +347 -0
  163. package/lib/rules/no-unnecessary-destructuring.js +14 -4
  164. package/lib/rules/no-unnecessary-verb-suffix.js +2 -3
  165. package/lib/rules/no-unpinned-dependencies.js +36 -5
  166. package/lib/rules/no-unsafe-firestore-spread.js +8 -5
  167. package/lib/rules/no-unused-props.d.ts +5 -2
  168. package/lib/rules/no-unused-props.js +451 -112
  169. package/lib/rules/no-unused-usestate.js +6 -2
  170. package/lib/rules/no-useless-fragment.js +28 -2
  171. package/lib/rules/no-useless-usememo-primitives.d.ts +9 -0
  172. package/lib/rules/no-useless-usememo-primitives.js +393 -0
  173. package/lib/rules/no-usememo-for-pass-by-value.d.ts +13 -0
  174. package/lib/rules/no-usememo-for-pass-by-value.js +757 -0
  175. package/lib/rules/no-uuidv4-base62-as-key.js +18 -13
  176. package/lib/rules/omit-index-html.d.ts +2 -1
  177. package/lib/rules/omit-index-html.js +62 -7
  178. package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
  179. package/lib/rules/optimize-object-boolean-conditions.js +236 -0
  180. package/lib/rules/parallelize-async-operations.d.ts +8 -0
  181. package/lib/rules/parallelize-async-operations.js +394 -0
  182. package/lib/rules/prefer-batch-operations.d.ts +1 -3
  183. package/lib/rules/prefer-batch-operations.js +228 -35
  184. package/lib/rules/prefer-block-comments-for-declarations.js +22 -7
  185. package/lib/rules/prefer-clone-deep.js +3 -3
  186. package/lib/rules/prefer-destructuring-no-class.d.ts +2 -1
  187. package/lib/rules/prefer-destructuring-no-class.js +244 -59
  188. package/lib/rules/prefer-docsetter-setall.d.ts +2 -0
  189. package/lib/rules/prefer-docsetter-setall.js +243 -0
  190. package/lib/rules/prefer-document-flattening.d.ts +4 -0
  191. package/lib/rules/prefer-document-flattening.js +239 -0
  192. package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
  193. package/lib/rules/prefer-field-paths-in-transforms.js +251 -0
  194. package/lib/rules/prefer-fragment-component.js +4 -4
  195. package/lib/rules/prefer-fragment-shorthand.js +2 -1
  196. package/lib/rules/prefer-getter-over-parameterless-method.d.ts +13 -0
  197. package/lib/rules/prefer-getter-over-parameterless-method.js +648 -0
  198. package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
  199. package/lib/rules/prefer-global-router-state-key.js +305 -31
  200. package/lib/rules/prefer-memoized-props.d.ts +3 -0
  201. package/lib/rules/prefer-memoized-props.js +445 -0
  202. package/lib/rules/prefer-next-dynamic.d.ts +9 -0
  203. package/lib/rules/prefer-next-dynamic.js +357 -0
  204. package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
  205. package/lib/rules/prefer-nullish-coalescing-boolean-props.js +435 -0
  206. package/lib/rules/prefer-nullish-coalescing-override.d.ts +7 -0
  207. package/lib/rules/prefer-nullish-coalescing-override.js +188 -0
  208. package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
  209. package/lib/rules/prefer-params-over-parent-id.js +277 -0
  210. package/lib/rules/prefer-settings-object.js +23 -15
  211. package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
  212. package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
  213. package/lib/rules/prefer-type-over-interface.js +7 -2
  214. package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
  215. package/lib/rules/prefer-url-tostring-over-tojson.js +169 -0
  216. package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
  217. package/lib/rules/prefer-use-deep-compare-memo.js +431 -0
  218. package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +25 -2
  219. package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
  220. package/lib/rules/prefer-utility-function-over-private-static.js +34 -2
  221. package/lib/rules/prevent-children-clobber.d.ts +2 -0
  222. package/lib/rules/prevent-children-clobber.js +536 -0
  223. package/lib/rules/react-memoize-literals.d.ts +4 -0
  224. package/lib/rules/react-memoize-literals.js +495 -0
  225. package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
  226. package/lib/rules/react-usememo-should-be-component.js +144 -78
  227. package/lib/rules/require-dynamic-firebase-imports.js +2 -1
  228. package/lib/rules/require-hooks-default-params.js +17 -16
  229. package/lib/rules/require-https-error-cause.d.ts +4 -0
  230. package/lib/rules/require-https-error-cause.js +136 -0
  231. package/lib/rules/require-https-error.js +43 -21
  232. package/lib/rules/require-image-optimized.js +2 -2
  233. package/lib/rules/require-memo.js +12 -2
  234. package/lib/rules/require-memoize-jsx-returners.d.ts +3 -0
  235. package/lib/rules/require-memoize-jsx-returners.js +485 -0
  236. package/lib/rules/require-usememo-object-literals.js +9 -4
  237. package/lib/rules/semantic-function-prefixes.js +38 -18
  238. package/lib/rules/sync-onwrite-name-func.js +5 -1
  239. package/lib/rules/test-file-location-enforcement.d.ts +1 -0
  240. package/lib/rules/test-file-location-enforcement.js +57 -0
  241. package/lib/rules/use-custom-link.js +6 -1
  242. package/lib/rules/use-custom-router.js +6 -1
  243. package/lib/rules/use-latest-callback.d.ts +3 -0
  244. package/lib/rules/use-latest-callback.js +271 -0
  245. package/lib/rules/vertically-group-related-functions.d.ts +16 -0
  246. package/lib/rules/vertically-group-related-functions.js +480 -0
  247. package/lib/utils/ASTHelpers.d.ts +13 -1
  248. package/lib/utils/ASTHelpers.js +34 -0
  249. package/lib/utils/createRule.js +1 -1
  250. package/lib/utils/getMethodName.d.ts +27 -0
  251. package/lib/utils/getMethodName.js +35 -0
  252. package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
  253. package/lib/utils/ruleTester.d.ts +1 -0
  254. package/lib/utils/ruleTester.js +4 -1
  255. package/lib/utils/tsTypeClassifier.d.ts +30 -0
  256. package/lib/utils/tsTypeClassifier.js +149 -0
  257. package/package.json +23 -14
  258. package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.noHandlerSuffix = void 0;
4
+ const utils_1 = require("@typescript-eslint/utils");
5
+ const minimatch_1 = require("minimatch");
6
+ const createRule_1 = require("../utils/createRule");
7
+ const DEFAULT_OPTIONS = {
8
+ ignoreClassMethods: false,
9
+ ignoreInterfaceImplementations: false,
10
+ interfaceAllowlist: [],
11
+ allowNames: [],
12
+ allowPatterns: [],
13
+ allowFilePatterns: [],
14
+ };
15
+ function toEntityName(entity) {
16
+ if (entity.type === utils_1.AST_NODE_TYPES.Identifier) {
17
+ return entity.name;
18
+ }
19
+ if (entity.type === utils_1.AST_NODE_TYPES.TSQualifiedName) {
20
+ return `${toEntityName(entity.left)}.${entity.right.name}`;
21
+ }
22
+ return '';
23
+ }
24
+ function isUnsafeAllowPattern(pattern) {
25
+ // Flag nested quantifiers that commonly lead to catastrophic backtracking
26
+ const nestedQuantifierPattern = /\((?:[^()\\]|\\.)*[+*{][^)]*\)\s*[+*{]/;
27
+ return nestedQuantifierPattern.test(pattern);
28
+ }
29
+ function getStaticKeyName(key) {
30
+ if (key.type === utils_1.AST_NODE_TYPES.Identifier) {
31
+ return key.name;
32
+ }
33
+ if (key.type === utils_1.AST_NODE_TYPES.Literal && typeof key.value === 'string') {
34
+ return key.value;
35
+ }
36
+ return null;
37
+ }
38
+ function getHandlerSuffix(name) {
39
+ const match = name.match(/^(.*?)(Handlers?)$/i);
40
+ if (!match)
41
+ return null;
42
+ const [, baseName, suffix] = match;
43
+ if (!suffix)
44
+ return null;
45
+ const normalizedSuffix = suffix.toLowerCase() === 'handlers' ? 'Handlers' : 'Handler';
46
+ return {
47
+ baseName,
48
+ suffix: normalizedSuffix,
49
+ };
50
+ }
51
+ function isInAllowedFile(filename, allowFilePatterns) {
52
+ return allowFilePatterns.some((pattern) => (0, minimatch_1.minimatch)(filename, pattern));
53
+ }
54
+ function toMemberExpressionName(expr) {
55
+ if (expr.computed || expr.property.type !== utils_1.AST_NODE_TYPES.Identifier) {
56
+ return null;
57
+ }
58
+ const objectName = expr.object.type === utils_1.AST_NODE_TYPES.Identifier
59
+ ? expr.object.name
60
+ : expr.object.type === utils_1.AST_NODE_TYPES.MemberExpression
61
+ ? toMemberExpressionName(expr.object)
62
+ : null;
63
+ return objectName ? `${objectName}.${expr.property.name}` : null;
64
+ }
65
+ function getImplementedInterfaces(classNode) {
66
+ return (classNode.implements?.flatMap((impl) => {
67
+ const expr = impl.expression;
68
+ const name = expr.type === utils_1.AST_NODE_TYPES.Identifier
69
+ ? expr.name
70
+ : expr.type === utils_1.AST_NODE_TYPES.MemberExpression
71
+ ? toMemberExpressionName(expr)
72
+ : null;
73
+ return name ? [name] : [];
74
+ }) ?? []);
75
+ }
76
+ function getClassFromMember(node) {
77
+ const classBody = node.parent;
78
+ if (classBody &&
79
+ classBody.type === utils_1.AST_NODE_TYPES.ClassBody &&
80
+ classBody.parent &&
81
+ (classBody.parent.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
82
+ classBody.parent.type === utils_1.AST_NODE_TYPES.ClassExpression)) {
83
+ return classBody.parent;
84
+ }
85
+ return null;
86
+ }
87
+ function getTypeAnnotationName(annotation) {
88
+ if (!annotation)
89
+ return null;
90
+ if (annotation.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
91
+ const typeName = annotation.typeAnnotation.typeName;
92
+ if (typeName.type === utils_1.AST_NODE_TYPES.Identifier ||
93
+ typeName.type === utils_1.AST_NODE_TYPES.TSQualifiedName) {
94
+ return toEntityName(typeName);
95
+ }
96
+ }
97
+ return null;
98
+ }
99
+ exports.noHandlerSuffix = (0, createRule_1.createRule)({
100
+ name: 'no-handler-suffix',
101
+ meta: {
102
+ type: 'suggestion',
103
+ docs: {
104
+ description: 'Disallow the generic "handler" suffix in callback names so names explain the action they perform',
105
+ recommended: 'error',
106
+ },
107
+ schema: [
108
+ {
109
+ type: 'object',
110
+ properties: {
111
+ ignoreClassMethods: { type: 'boolean' },
112
+ ignoreInterfaceImplementations: { type: 'boolean' },
113
+ interfaceAllowlist: {
114
+ type: 'array',
115
+ items: { type: 'string' },
116
+ },
117
+ allowNames: { type: 'array', items: { type: 'string' } },
118
+ allowPatterns: { type: 'array', items: { type: 'string' } },
119
+ allowFilePatterns: { type: 'array', items: { type: 'string' } },
120
+ },
121
+ additionalProperties: false,
122
+ },
123
+ ],
124
+ messages: {
125
+ handlerSuffix: 'Function "{{name}}" ends with the generic {{suffix}} suffix. Handler names hide the outcome of the callback and make call sites indistinguishable. Rename it to describe the effect (e.g., "{{suggestedName}}" or another action phrase) so readers know what the function actually does.',
126
+ },
127
+ },
128
+ defaultOptions: [DEFAULT_OPTIONS],
129
+ create(context, [options]) {
130
+ const filename = context.getFilename();
131
+ const resolvedOptions = { ...DEFAULT_OPTIONS, ...(options ?? {}) };
132
+ const allowNames = new Set(resolvedOptions.allowNames);
133
+ const interfaceAllowlist = new Set(resolvedOptions.interfaceAllowlist);
134
+ const invalidAllowPatterns = [];
135
+ const unsafeAllowPatterns = [];
136
+ const allowPatterns = (resolvedOptions.allowPatterns ?? []).flatMap((pattern) => {
137
+ try {
138
+ if (isUnsafeAllowPattern(pattern)) {
139
+ unsafeAllowPatterns.push(pattern);
140
+ return [];
141
+ }
142
+ return [new RegExp(pattern)];
143
+ }
144
+ catch (error) {
145
+ const reason = error && typeof error === 'object' && 'message' in error
146
+ ? ` (${String(error.message)})`
147
+ : '';
148
+ invalidAllowPatterns.push(`${pattern}${reason}`);
149
+ return [];
150
+ }
151
+ });
152
+ if (invalidAllowPatterns.length > 0 || unsafeAllowPatterns.length > 0) {
153
+ const errorParts = [];
154
+ if (invalidAllowPatterns.length > 0) {
155
+ errorParts.push(`invalid allowPatterns: ${invalidAllowPatterns.join(', ')}`);
156
+ }
157
+ if (unsafeAllowPatterns.length > 0) {
158
+ errorParts.push(`unsafe allowPatterns (avoid nested quantifiers that risk catastrophic backtracking): ${unsafeAllowPatterns.join(', ')}`);
159
+ }
160
+ throw new Error(`no-handler-suffix: ${errorParts.join('; ')}`);
161
+ }
162
+ if (isInAllowedFile(filename, resolvedOptions.allowFilePatterns ?? [])) {
163
+ return {};
164
+ }
165
+ function isAllowedName(name) {
166
+ if (allowNames.has(name))
167
+ return true;
168
+ return allowPatterns.some((regex) => regex.test(name));
169
+ }
170
+ function shouldIgnoreForInterfaces(node) {
171
+ const { ignoreInterfaceImplementations } = resolvedOptions;
172
+ if ((node.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
173
+ node.type === utils_1.AST_NODE_TYPES.PropertyDefinition) &&
174
+ !node.computed &&
175
+ (node.key.type === utils_1.AST_NODE_TYPES.Identifier ||
176
+ node.key.type === utils_1.AST_NODE_TYPES.PrivateIdentifier ||
177
+ (node.key.type === utils_1.AST_NODE_TYPES.Literal &&
178
+ typeof node.key.value === 'string'))) {
179
+ const classNode = getClassFromMember(node);
180
+ if (!classNode)
181
+ return false;
182
+ const implemented = getImplementedInterfaces(classNode);
183
+ if (implemented.length === 0)
184
+ return false;
185
+ if (ignoreInterfaceImplementations) {
186
+ return true;
187
+ }
188
+ if (interfaceAllowlist.size > 0) {
189
+ return implemented.some((iface) => interfaceAllowlist.has(iface));
190
+ }
191
+ }
192
+ if (node.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
193
+ node.id.type === utils_1.AST_NODE_TYPES.Identifier) {
194
+ const annotationName = getTypeAnnotationName(node.id.typeAnnotation);
195
+ if (annotationName &&
196
+ (interfaceAllowlist.has(annotationName) ||
197
+ resolvedOptions.ignoreInterfaceImplementations)) {
198
+ return true;
199
+ }
200
+ }
201
+ return false;
202
+ }
203
+ function getParentName(parent) {
204
+ if (!parent)
205
+ return null;
206
+ if (parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
207
+ parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
208
+ return parent.id.name;
209
+ }
210
+ if ((parent.type === utils_1.AST_NODE_TYPES.Property ||
211
+ parent.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
212
+ parent.type === utils_1.AST_NODE_TYPES.PropertyDefinition) &&
213
+ !parent.computed &&
214
+ parent.key.type !== utils_1.AST_NODE_TYPES.PrivateIdentifier) {
215
+ return getStaticKeyName(parent.key);
216
+ }
217
+ return null;
218
+ }
219
+ function reportIfHandlerName(name, identifierNode, owner) {
220
+ if (!name || !identifierNode)
221
+ return;
222
+ const suffixInfo = getHandlerSuffix(name);
223
+ if (!suffixInfo)
224
+ return;
225
+ if (isAllowedName(name))
226
+ return;
227
+ if ((owner.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
228
+ owner.type === utils_1.AST_NODE_TYPES.PropertyDefinition) &&
229
+ resolvedOptions.ignoreClassMethods) {
230
+ return;
231
+ }
232
+ if (owner.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
233
+ owner.type === utils_1.AST_NODE_TYPES.PropertyDefinition ||
234
+ owner.type === utils_1.AST_NODE_TYPES.VariableDeclarator ||
235
+ owner.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
236
+ if (shouldIgnoreForInterfaces(owner)) {
237
+ return;
238
+ }
239
+ }
240
+ const suggestedName = suffixInfo.baseName || 'a verb phrase that states the outcome';
241
+ context.report({
242
+ node: identifierNode,
243
+ messageId: 'handlerSuffix',
244
+ data: {
245
+ name,
246
+ suffix: suffixInfo.suffix,
247
+ suggestedName,
248
+ },
249
+ });
250
+ }
251
+ return {
252
+ FunctionDeclaration(node) {
253
+ if (node.id?.type === utils_1.AST_NODE_TYPES.Identifier) {
254
+ reportIfHandlerName(node.id.name, node.id, node);
255
+ }
256
+ },
257
+ VariableDeclarator(node) {
258
+ if (node.id.type === utils_1.AST_NODE_TYPES.Identifier &&
259
+ (node.init?.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
260
+ node.init?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
261
+ reportIfHandlerName(node.id.name, node.id, node);
262
+ }
263
+ },
264
+ MethodDefinition(node) {
265
+ if (!node.computed) {
266
+ const name = getStaticKeyName(node.key);
267
+ if (name) {
268
+ reportIfHandlerName(name, node.key, node);
269
+ }
270
+ }
271
+ },
272
+ PropertyDefinition(node) {
273
+ if (!node.computed &&
274
+ (node.value?.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
275
+ node.value?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
276
+ const name = getStaticKeyName(node.key);
277
+ if (name) {
278
+ reportIfHandlerName(name, node.key, node);
279
+ }
280
+ }
281
+ },
282
+ Property(node) {
283
+ if (!node.computed &&
284
+ (node.value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
285
+ node.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
286
+ const name = getStaticKeyName(node.key);
287
+ if (name) {
288
+ reportIfHandlerName(name, node.key, node);
289
+ }
290
+ }
291
+ },
292
+ FunctionExpression(node) {
293
+ if (!node.id)
294
+ return;
295
+ // Avoid double-reporting when the parent already names the function
296
+ const parentName = getParentName(node.parent);
297
+ if (parentName && parentName === node.id.name) {
298
+ return;
299
+ }
300
+ reportIfHandlerName(node.id.name, node.id, node);
301
+ },
302
+ };
303
+ },
304
+ });
305
+ //# sourceMappingURL=no-handler-suffix.js.map
@@ -46,11 +46,7 @@ const ALLOWED_SUFFIXES = [
46
46
  'Displayed',
47
47
  ];
48
48
  // Common compound nouns that should not be flagged as Hungarian notation
49
- const ALLOWED_COMPOUND_NOUNS = [
50
- 'PhoneNumber',
51
- 'EmailAddress',
52
- 'PostalCode',
53
- ];
49
+ const ALLOWED_COMPOUND_NOUNS = ['PhoneNumber', 'EmailAddress', 'PostalCode'];
54
50
  // Common built-in JavaScript prototype methods
55
51
  const BUILT_IN_METHODS = new Set([
56
52
  // String methods
@@ -205,7 +201,7 @@ exports.noHungarian = (0, createRule_1.createRule)({
205
201
  fixable: undefined,
206
202
  schema: [],
207
203
  messages: {
208
- noHungarian: 'Avoid Hungarian notation in variable name "{{name}}"',
204
+ noHungarian: 'Identifier "{{name}}" encodes its type through a prefix or suffix (Hungarian notation). Type-coded names hide the domain concept and become misleading when the underlying type changes. Rename it to a domain-focused name without the type marker and rely on TypeScript for type information.',
209
205
  },
210
206
  },
211
207
  defaultOptions: [],
@@ -225,11 +221,12 @@ exports.noHungarian = (0, createRule_1.createRule)({
225
221
  if (variableName.includes(compoundNoun)) {
226
222
  // Check if it's a prefix like "strPhoneNumber" (which should be flagged)
227
223
  const prefix = variableName.substring(0, variableName.indexOf(compoundNoun));
228
- if (TYPE_MARKERS.some(marker => prefix.toLowerCase() === marker.toLowerCase())) {
224
+ if (TYPE_MARKERS.some((marker) => prefix.toLowerCase() === marker.toLowerCase())) {
229
225
  // This is a type marker prefix + compound noun, so it should be flagged
230
226
  return true;
231
227
  }
232
- // Otherwise, it's a valid use of the compound noun
228
+ // Otherwise treat the compound noun as an allowed descriptive phrase
229
+ // (e.g., userPhoneNumber is acceptable even though it contains "Number")
233
230
  return false;
234
231
  }
235
232
  }
@@ -281,7 +278,8 @@ exports.noHungarian = (0, createRule_1.createRule)({
281
278
  // Check if it's a suffix with proper boundary (e.g., userString, itemArray)
282
279
  if (normalizedVarName.endsWith(normalizedMarker) &&
283
280
  normalizedVarName.length > normalizedMarker.length &&
284
- /[A-Z0-9]/.test(variableName[variableName.length - normalizedMarker.length - 1])) {
281
+ (/[A-Z0-9]/.test(variableName[variableName.length - normalizedMarker.length - 1]) ||
282
+ /[A-Z]/.test(variableName[variableName.length - normalizedMarker.length]))) {
285
283
  return true;
286
284
  }
287
285
  // Check for word boundaries to avoid matching substrings
@@ -290,17 +288,19 @@ exports.noHungarian = (0, createRule_1.createRule)({
290
288
  if (markerIndex === -1) {
291
289
  return false;
292
290
  }
293
- const markerPrefix = variableName.at(markerIndex);
294
- const preMarkerPrefix = variableName.at(markerIndex - 1);
295
- const suffix = variableName.at(markerIndex + normalizedMarker.length);
291
+ const preMarkerPrefix = markerIndex > 0 ? variableName[markerIndex - 1] : '';
292
+ const suffix = variableName[markerIndex + normalizedMarker.length] ?? '';
296
293
  // Ensure we have proper word boundaries
297
294
  // A word boundary is defined by:
298
295
  // 1. Start of string OR underscore OR capital letter before the marker
299
296
  // 2. End of string OR underscore OR capital letter after the marker
300
- const hasStartBoundary = markerIndex === 0 || preMarkerPrefix === '_' || /[A-Z]/.test(markerPrefix || '');
297
+ const hasStartBoundary = markerIndex === 0 ||
298
+ preMarkerPrefix === '_' ||
299
+ /[A-Z]/.test(preMarkerPrefix) ||
300
+ /[A-Z]/.test(variableName[markerIndex]);
301
301
  const hasEndBoundary = markerIndex + normalizedMarker.length === normalizedVarName.length ||
302
302
  suffix === '_' ||
303
- /[A-Z]/.test(suffix || '');
303
+ /[A-Z]/.test(suffix);
304
304
  return hasStartBoundary && hasEndBoundary;
305
305
  });
306
306
  }
@@ -0,0 +1,10 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ type Options = [
3
+ {
4
+ props?: string[];
5
+ allowRenderProps?: boolean;
6
+ allowModuleScopeFactories?: boolean;
7
+ }
8
+ ];
9
+ export declare const noInlineComponentProp: TSESLint.RuleModule<"inlineComponentProp", Options, TSESLint.RuleListener>;
10
+ export {};