@blumintinc/eslint-plugin-blumint 1.16.2 → 1.17.1

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 (51) hide show
  1. package/README.md +21 -0
  2. package/lib/index.js +64 -1
  3. package/lib/rules/enforce-boolean-naming-prefixes.js +30 -14
  4. package/lib/rules/enforce-cloud-function-id-length.d.ts +5 -0
  5. package/lib/rules/enforce-cloud-function-id-length.js +104 -0
  6. package/lib/rules/enforce-is-prefix-validators.d.ts +13 -0
  7. package/lib/rules/enforce-is-prefix-validators.js +304 -0
  8. package/lib/rules/enforce-m3-sentence-case.d.ts +12 -0
  9. package/lib/rules/enforce-m3-sentence-case.js +430 -0
  10. package/lib/rules/enforce-snapshot-state-narrowing.d.ts +10 -0
  11. package/lib/rules/enforce-snapshot-state-narrowing.js +281 -0
  12. package/lib/rules/enforce-types-directory-placement.d.ts +9 -0
  13. package/lib/rules/enforce-types-directory-placement.js +276 -0
  14. package/lib/rules/no-direct-function-state.d.ts +8 -0
  15. package/lib/rules/no-direct-function-state.js +285 -0
  16. package/lib/rules/no-fill-template-mutation.d.ts +1 -0
  17. package/lib/rules/no-fill-template-mutation.js +324 -0
  18. package/lib/rules/no-hungarian.js +18 -26
  19. package/lib/rules/no-portal-inside-tooltip.d.ts +10 -0
  20. package/lib/rules/no-portal-inside-tooltip.js +219 -0
  21. package/lib/rules/no-redundant-boolean-callback-props.d.ts +11 -0
  22. package/lib/rules/no-redundant-boolean-callback-props.js +355 -0
  23. package/lib/rules/no-satisfies-in-frontend-bundle.d.ts +8 -0
  24. package/lib/rules/no-satisfies-in-frontend-bundle.js +126 -0
  25. package/lib/rules/no-single-dismiss-dialog-button.d.ts +7 -0
  26. package/lib/rules/no-single-dismiss-dialog-button.js +127 -0
  27. package/lib/rules/no-stablehash-react-nodes.d.ts +1 -0
  28. package/lib/rules/no-stablehash-react-nodes.js +325 -0
  29. package/lib/rules/parallelize-loop-awaits.d.ts +8 -0
  30. package/lib/rules/parallelize-loop-awaits.js +582 -0
  31. package/lib/rules/prefer-flat-transform-each-keys.d.ts +1 -0
  32. package/lib/rules/prefer-flat-transform-each-keys.js +228 -0
  33. package/lib/rules/prefer-getter-over-parameterless-method.d.ts +1 -0
  34. package/lib/rules/prefer-getter-over-parameterless-method.js +44 -0
  35. package/lib/rules/prefer-spread-over-reassembly.d.ts +5 -0
  36. package/lib/rules/prefer-spread-over-reassembly.js +401 -0
  37. package/lib/rules/prefer-sx-prop-over-system-props.d.ts +9 -0
  38. package/lib/rules/prefer-sx-prop-over-system-props.js +401 -0
  39. package/lib/rules/prefer-use-base62-id.d.ts +8 -0
  40. package/lib/rules/prefer-use-base62-id.js +483 -0
  41. package/lib/rules/prefer-use-theme.d.ts +1 -0
  42. package/lib/rules/prefer-use-theme.js +206 -0
  43. package/lib/rules/prefer-utility-function-own-file.d.ts +9 -0
  44. package/lib/rules/prefer-utility-function-own-file.js +505 -0
  45. package/lib/rules/react-memoize-literals.js +106 -1
  46. package/lib/rules/require-props-composition.d.ts +10 -0
  47. package/lib/rules/require-props-composition.js +433 -0
  48. package/lib/rules/require-server-timestamp-for-firestore-dates.d.ts +9 -0
  49. package/lib/rules/require-server-timestamp-for-firestore-dates.js +313 -0
  50. package/package.json +1 -1
  51. package/release-manifest.json +212 -0
package/README.md CHANGED
@@ -93,6 +93,7 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
93
93
  | [enforce-callable-types](docs/rules/enforce-callable-types.md) | Enforce Props and Response type exports in callable functions | ✅ | | | | | |
94
94
  | [enforce-callback-memo](docs/rules/enforce-callback-memo.md) | Enforce useCallback for inline functions and useMemo for objects/arrays containing functions in JSX props to prevent unnecessary re-renders. This improves React component performance by ensuring stable function references across renders and memoizing complex objects. | ✅ | | | | | |
95
95
  | [enforce-centralized-mock-firestore](docs/rules/enforce-centralized-mock-firestore.md) | Enforce usage of centralized mockFirestore from predefined location | ✅ | | | 🔧 | | |
96
+ | [enforce-cloud-function-id-length](docs/rules/enforce-cloud-function-id-length.md) | Ensures .f.ts file paths generate Firebase Cloud Function IDs within the 62-character limit | ✅ | | | | | |
96
97
  | [enforce-console-error](docs/rules/enforce-console-error.md) | Enforce proper logging for useAlertDialog based on severity. When severity is "error", console.error must be included. When severity is "warning", console.warn must be included. This ensures all user-facing errors and warnings are properly logged to observability systems. | ✅ | | | | | |
97
98
  | [enforce-css-media-queries](docs/rules/enforce-css-media-queries.md) | Enforce CSS media queries over JS breakpoints | ✅ | | | | | |
98
99
  | [enforce-date-ttime](docs/rules/enforce-date-ttime.md) | Enforce that any generic type parameter named TTime is explicitly set to Date in frontend code | ✅ | | | 🔧 | | |
@@ -112,6 +113,8 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
112
113
  | [enforce-global-constants](docs/rules/enforce-global-constants.md) | Enforce global static constants for React components/hooks | ✅ | | | 🔧 | | |
113
114
  | [enforce-id-capitalization](docs/rules/enforce-id-capitalization.md) | Enforce the use of "ID" instead of "id" in user-facing text | ✅ | | | 🔧 | | |
114
115
  | [enforce-identifiable-firestore-type](docs/rules/enforce-identifiable-firestore-type.md) | Enforce that Firestore type definitions extend Identifiable and match their folder name | ✅ | | | | | |
116
+ | [enforce-is-prefix-validators](docs/rules/enforce-is-prefix-validators.md) | Enforce the `is` (or other allowed predicate) prefix for exported validators in **/validators/**/*.ts files | ✅ | | | | | |
117
+ | [enforce-m3-sentence-case](docs/rules/enforce-m3-sentence-case.md) | Enforce Material Design 3 sentence-case capitalisation for user-facing text — flag Title Case and ALL CAPS strings in JSX text and configured string props. | | ✅ | | | 💡 | |
115
118
  | [enforce-memoize-async](docs/rules/enforce-memoize-async.md) | Enforce @Memoize() decorator on async methods with 0-1 parameters to cache results and prevent redundant API calls or expensive computations. Without memoization, repeated calls trigger redundant requests or expensive computations, increasing latency. @Memoize() caches results by parameter, ensuring subsequent calls with identical inputs return immediately. | ✅ | | | 🔧 | | |
116
119
  | [enforce-memoize-getters](docs/rules/enforce-memoize-getters.md) | Enforce @Memoize() decorator on private class getters to avoid re-instantiation and preserve state across accesses. | ✅ | | | 🔧 | | |
117
120
  | [enforce-microdiff](docs/rules/enforce-microdiff.md) | Enforce using microdiff for object and array comparison operations | ✅ | | | 🔧 | | |
@@ -128,10 +131,12 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
128
131
  | [enforce-safe-stringify](docs/rules/enforce-safe-stringify.md) | Enforce using safe-stable-stringify instead of JSON.stringify to handle circular references and ensure deterministic output. JSON.stringify can throw errors on circular references and produce inconsistent output for objects with the same properties in different orders. safe-stable-stringify handles these cases safely. | ✅ | | | 🔧 | | |
129
132
  | [enforce-serializable-params](docs/rules/enforce-serializable-params.md) | Enforce serializable parameters for Firebase callable/HTTPS functions. | ✅ | | | | | |
130
133
  | [enforce-singular-type-names](docs/rules/enforce-singular-type-names.md) | Enforce TypeScript type names to be singular | ✅ | | | | | |
134
+ | [enforce-snapshot-state-narrowing](docs/rules/enforce-snapshot-state-narrowing.md) | Enforce correct narrowing of FirestoreSnapshotState<T> variables. Falsy/truthy checks are semantic bugs because all string states are truthy; raw typeof narrowing to data bypasses the isSnapshotReady abstraction. | ✅ | | | | 💡 | |
131
135
  | [enforce-stable-hash-spread-props](docs/rules/enforce-stable-hash-spread-props.md) | Require stableHash wrapping when spread props rest objects are used in React hook dependency arrays to avoid re-renders triggered by new object references on every render. | ✅ | | | 🔧 | | |
132
136
  | [enforce-storage-context](docs/rules/enforce-storage-context.md) | Require storage access to go through the LocalStorage and SessionStorage context providers instead of direct browser APIs | ✅ | | | | | |
133
137
  | [enforce-timestamp-now](docs/rules/enforce-timestamp-now.md) | Enforce the use of Timestamp.now() for getting the current timestamp in backend code. This rule prevents using alternatives like Timestamp.fromDate(new Date()) or other date creation patterns that could lead to inconsistency. | ✅ | | | 🔧 | | |
134
138
  | [enforce-transform-memoization](docs/rules/enforce-transform-memoization.md) | Enforce memoization of transformValue and transformOnChange in adaptValue | ✅ | | | | | |
139
+ | [enforce-types-directory-placement](docs/rules/enforce-types-directory-placement.md) | Enforce that type-only files (containing only type/interface/enum declarations) live under the canonical types directory | ✅ | | | | | |
135
140
  | [enforce-typescript-markdown-code-blocks](docs/rules/enforce-typescript-markdown-code-blocks.md) | Ensure Markdown fenced code blocks without a language specifier default to typescript for consistent highlighting. | ✅ | | | 🔧 | | |
136
141
  | [enforce-unique-cursor-headers](docs/rules/enforce-unique-cursor-headers.md) | Ensure files have exactly one cursor header containing required tags (e.g., @fileoverview) before any code | ✅ | | | 🔧 | | |
137
142
  | [enforce-verb-noun-naming](docs/rules/enforce-verb-noun-naming.md) | Enforce verb phrases for functions and methods | ✅ | | | | | |
@@ -160,10 +165,12 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
160
165
  | [no-conditional-literals-in-jsx](docs/rules/no-conditional-literals-in-jsx.md) | Disallow conditional string literals beside other JSX text to avoid fragmented text nodes, translation issues, and hydration mismatches. | ✅ | | | | | |
161
166
  | [no-console-error](docs/rules/no-console-error.md) | Disallow console.error so errors flow through structured handling (HttpsError/useErrorAlert on frontend, structured loggers on backend). | | ✅ | | | | |
162
167
  | [no-curly-brackets-around-commented-properties](docs/rules/no-curly-brackets-around-commented-properties.md) | Disallow curly-brace blocks that only wrap commented-out members inside type declarations | ✅ | | | 🔧 | | |
168
+ | [no-direct-function-state](docs/rules/no-direct-function-state.md) | Prevent passing a function directly to a useState setter — React will invoke it as a functional updater instead of storing it. Wrap in a thunk: setState(() => fn). | ✅ | | | 🔧 | | |
163
169
  | [no-empty-dependency-use-callbacks](docs/rules/no-empty-dependency-use-callbacks.md) | Discourage useCallback([]) or useLatestCallback around static functions. Static callbacks do not need hook machinery—extract them to module-level utilities for clarity and to avoid unnecessary hook overhead. | ✅ | | | 🔧 | | |
164
170
  | [no-entire-object-hook-deps](docs/rules/no-entire-object-hook-deps.md) | Avoid using entire objects in React hook dependency arrays. | ✅ | | | 🔧 | | 💭 |
165
171
  | [no-excessive-parent-chain](docs/rules/no-excessive-parent-chain.md) | Discourage excessive use of the ref.parent property chain in Firestore and RealtimeDB change handlers | | | | | 💡 | |
166
172
  | [no-explicit-return-type](docs/rules/no-explicit-return-type.md) | Disallow explicit return type annotations on functions when TypeScript can infer them. This reduces code verbosity and maintenance burden while leveraging TypeScript's powerful type inference. Exceptions are made for type guard functions (using the `is` keyword), recursive functions, overloaded functions, interface methods, and abstract methods where explicit types improve clarity. | ✅ | | | 🔧 | | |
173
+ | [no-fill-template-mutation](docs/rules/no-fill-template-mutation.md) | Disallow mutating the return value of fillTemplate() via string concatenation, template literals, or string method calls. The filled Algolia filter must be used verbatim so matchesTemplate() can regex-match it; post-fill modification silently breaks realtime hash parity. | ✅ | | | | | |
167
174
  | [no-filter-without-return](docs/rules/no-filter-without-return.md) | Disallow Array.filter callbacks without an explicit return (if part of a block statement) | ✅ | | | | | |
168
175
  | [no-firestore-jest-mock](docs/rules/no-firestore-jest-mock.md) | Prevent importing firestore-jest-mock in test files | ✅ | | | 🔧 | | |
169
176
  | [no-firestore-object-arrays](docs/rules/no-firestore-object-arrays.md) | Disallow arrays of object types in Firestore models. Prefer Record maps keyed by id with an index field, or subcollections/arrays of IDs. | ✅ | | | | | |
@@ -180,13 +187,18 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
180
187
  | [no-object-values-on-strings](docs/rules/no-object-values-on-strings.md) | Disallow Object.values() on strings as it treats strings as arrays of characters, which is likely unintended behavior. | ✅ | | | | | |
181
188
  | [no-overridable-method-calls-in-constructor](docs/rules/no-overridable-method-calls-in-constructor.md) | Disallow calling overridable methods in constructors to prevent unexpected behavior | ✅ | | | | | |
182
189
  | [no-passthrough-getters](docs/rules/no-passthrough-getters.md) | Avoid getter methods that only re-expose nested properties on constructor-injected objects without adding behavior | ✅ | | | | | |
190
+ | [no-portal-inside-tooltip](docs/rules/no-portal-inside-tooltip.md) | Disallow portal-rendering components (Dialog, Drawer, Menu, Popover, Portal, Modal) inside Tooltip wrapper components. React Portals preserve React-tree event bubbling, so a portal nested under a Tooltip leaves the tooltip orphaned over the modal. | ✅ | | | | | |
183
191
  | [no-redundant-annotation-assertion](docs/rules/no-redundant-annotation-assertion.md) | Disallow combining a type annotation with an identical type assertion on the same value. Keep a single source of truth to avoid redundant type declarations that can drift apart. | ✅ | | | 🔧 | | 💭 |
192
+ | [no-redundant-boolean-callback-props](docs/rules/no-redundant-boolean-callback-props.md) | Disallow redundant boolean props that duplicate the semantic meaning of optional callback props, violating the Interface Segregation Principle. | ✅ | | | | | |
184
193
  | [no-redundant-param-types](docs/rules/no-redundant-param-types.md) | Disallow redundant parameter type annotations | ✅ | | | 🔧 | | |
185
194
  | [no-redundant-this-params](docs/rules/no-redundant-this-params.md) | Disallow passing class instance members (this.foo) into class instance methods; access the member from this inside the method instead. | ✅ | | | | | |
186
195
  | [no-redundant-usecallback-wrapper](docs/rules/no-redundant-usecallback-wrapper.md) | Prevent wrapping already memoized/stable callbacks from hooks/contexts in an extra useCallback() | ✅ | | | 🔧 | | |
187
196
  | [no-res-error-status-in-onrequest](docs/rules/no-res-error-status-in-onrequest.md) | Forbid sending 4xx/5xx Express responses inside onRequest handlers; throw structured HttpsError instances instead so the wrapper can format, log, and map errors consistently. | ✅ | | | | | |
188
197
  | [no-restricted-properties-fix](docs/rules/no-restricted-properties-fix.md) | Disallow certain properties on certain objects, with special handling for Object.keys() and Object.values() | | | | 🔧 | | |
198
+ | [no-satisfies-in-frontend-bundle](docs/rules/no-satisfies-in-frontend-bundle.md) | Disallow the `satisfies` operator in files that reach the frontend webpack bundle (Next.js 12 SWC cannot parse it) | ✅ | | | | | |
189
199
  | [no-separate-loading-state](docs/rules/no-separate-loading-state.md) | Disallow separate loading state variables that track the loading status of other state | ✅ | | | | | |
200
+ | [no-single-dismiss-dialog-button](docs/rules/no-single-dismiss-dialog-button.md) | Disallow a single dialog button whose label is a dismiss action (Cancel, Close, Dismiss, Not now, Never mind). Use navigation.onClose for dismissal; the buttons array should only contain affirmative actions. | ✅ | | | | | |
201
+ | [no-stablehash-react-nodes](docs/rules/no-stablehash-react-nodes.md) | Prevent passing ReactNodes or render-tree values to stableHash(), which deep-stringifies its argument and can freeze the browser. | ✅ | | | | | |
190
202
  | [no-stale-state-across-await](docs/rules/no-stale-state-across-await.md) | Prevent stale intermediate state by disallowing useState setter calls both before and after async boundaries (await, .then(), yield) within the same function | ✅ | | | | | |
191
203
  | [no-static-constants-in-dynamic-files](docs/rules/no-static-constants-in-dynamic-files.md) | Disallow exporting SCREAMING_SNAKE_CASE constants from .dynamic.ts/.dynamic.tsx files; move static constants to non-dynamic modules instead. | ✅ | | | | | |
192
204
  | [no-try-catch-already-exists-in-transaction](docs/rules/no-try-catch-already-exists-in-transaction.md) | Disallow catching ALREADY_EXISTS errors inside Firestore transaction callbacks | ✅ | | | | | |
@@ -207,6 +219,7 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
207
219
  | [omit-index-html](docs/rules/omit-index-html.md) | Disallow the use of "index.html" in URLs | ✅ | | | 🔧 | | |
208
220
  | [optimize-object-boolean-conditions](docs/rules/optimize-object-boolean-conditions.md) | Detects and suggests optimizations for boolean conditions formed over objects in React hook dependencies. Suggests extracting boolean conditions into separate variables to reduce unnecessary re-computations when objects change frequently but the boolean condition changes less frequently. | ✅ | | | | | |
209
221
  | [parallelize-async-operations](docs/rules/parallelize-async-operations.md) | Enforce the use of Promise.all() when multiple independent asynchronous operations are awaited sequentially | ✅ | | | 🔧 | | |
222
+ | [parallelize-loop-awaits](docs/rules/parallelize-loop-awaits.md) | Disallow sequential await expressions inside loops when iterations could be parallelized with Promise.all(items.map(...)) | ✅ | | | | | |
210
223
  | [prefer-batch-operations](docs/rules/prefer-batch-operations.md) | Enforce using setAll() and overwriteAll() instead of multiple set() or overwrite() calls | ✅ | | | 🔧 | | |
211
224
  | [prefer-block-comments-for-declarations](docs/rules/prefer-block-comments-for-declarations.md) | Enforce the use of block comments for declarations | ✅ | | | 🔧 | | |
212
225
  | [prefer-clone-deep](docs/rules/prefer-clone-deep.md) | Prefer using cloneDeep over nested spread copying | ✅ | | | 🔧 | | |
@@ -214,6 +227,7 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
214
227
  | [prefer-docsetter-setall](docs/rules/prefer-docsetter-setall.md) | Enforce batching DocSetter and DocSetterTransaction writes by using setAll instead of set inside loops or array callbacks. | ✅ | | | | | |
215
228
  | [prefer-document-flattening](docs/rules/prefer-document-flattening.md) | Enforce using the shouldFlatten option when setting deeply nested objects in Firestore documents | | | | | 💡 | |
216
229
  | [prefer-field-paths-in-transforms](docs/rules/prefer-field-paths-in-transforms.md) | Flatten aggregation updates inside transformEach so diff-based deletes remove only the intended fields instead of wiping sibling data. | | ✅ | | 🔧 | | |
230
+ | [prefer-flat-transform-each-keys](docs/rules/prefer-flat-transform-each-keys.md) | Warn when transformEach in a propagation strategy returns nested object values instead of flat dot-notation keys. | | ✅ | | | | |
217
231
  | [prefer-fragment-component](docs/rules/prefer-fragment-component.md) | Require the Fragment named import instead of shorthand fragments or React.Fragment to keep fragments explicit and prop-friendly | | | ✅ | 🔧 | | |
218
232
  | [prefer-fragment-shorthand](docs/rules/prefer-fragment-shorthand.md) | Prefer <> shorthand for <React.Fragment> | ✅ | | | 🔧 | | |
219
233
  | [prefer-getter-over-parameterless-method](docs/rules/prefer-getter-over-parameterless-method.md) | Enforce getter syntax for synchronous parameterless methods that return values, improving semantic clarity and avoiding accidental method invocation without parentheses. | ✅ | | | 🔧 | | |
@@ -222,13 +236,18 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
222
236
  | [prefer-nullish-coalescing-boolean-props](docs/rules/prefer-nullish-coalescing-boolean-props.md) | Prefer nullish coalescing over logical OR, but allow logical OR in boolean contexts | ✅ | | | 🔧 | | |
223
237
  | [prefer-params-over-parent-id](docs/rules/prefer-params-over-parent-id.md) | Prefer event.params over ref.parent.id for type-safe Firebase trigger paths. | ✅ | | | 🔧 | | |
224
238
  | [prefer-settings-object](docs/rules/prefer-settings-object.md) | Enforce using a settings object for functions with multiple parameters | ✅ | | | 🔧 | | |
239
+ | [prefer-spread-over-reassembly](docs/rules/prefer-spread-over-reassembly.md) | Prefer spread syntax over destructure-then-reassemble when all destructured fields are forwarded identically to a single target | ✅ | | | 🔧 | | |
240
+ | [prefer-sx-prop-over-system-props](docs/rules/prefer-sx-prop-over-system-props.md) | Enforce using the MUI `sx` prop instead of deprecated system props (e.g. `mt`, `display`, `flexDirection`) on MUI components. | ✅ | | | 🔧 | | |
225
241
  | [prefer-type-alias-over-typeof-constant](docs/rules/prefer-type-alias-over-typeof-constant.md) | Prefer named type aliases over `typeof` on same-file global constants; ensure types are declared before constants. | ✅ | | | | | |
226
242
  | [prefer-type-over-interface](docs/rules/prefer-type-over-interface.md) | Prefer using type alias over interface | ✅ | | | 🔧 | | |
227
243
  | [prefer-url-tostring-over-tojson](docs/rules/prefer-url-tostring-over-tojson.md) | Enforce the use of toString() over toJSON() on URL objects. | ✅ | | | 🔧 | | |
244
+ | [prefer-use-base62-id](docs/rules/prefer-use-base62-id.md) | Prefer `useBase62Id()` over `uuidv4Base62()` inside useState/useRef/useMemo for stable component IDs to avoid SSR hydration mismatches | ✅ | | | | | |
228
245
  | [prefer-use-deep-compare-memo](docs/rules/prefer-use-deep-compare-memo.md) | Enforce using useDeepCompareMemo when dependency array contains non-primitive values (objects, arrays) that are not already memoized. This prevents unnecessary re-renders due to reference changes. | ✅ | | | 🔧 | | |
246
+ | [prefer-use-theme](docs/rules/prefer-use-theme.md) | Enforce reading MUI theme values via useTheme() or the sx theme callback instead of importing theme constants directly from src/styles/* modules. | ✅ | | | | | |
229
247
  | [prefer-usecallback-over-usememo-for-functions](docs/rules/prefer-usecallback-over-usememo-for-functions.md) | Enforce using useCallback instead of useMemo for memoizing functions | ✅ | | | 🔧 | | |
230
248
  | [prefer-usememo-over-useeffect-usestate](docs/rules/prefer-usememo-over-useeffect-usestate.md) | Prefer useMemo over useEffect + useState for pure computations to avoid extra render cycles and stale derived state. | ✅ | | | | | |
231
249
  | [prefer-utility-function-over-private-static](docs/rules/prefer-utility-function-over-private-static.md) | Enforce abstraction of private static methods into utility functions | ✅ | | | | | |
250
+ | [prefer-utility-function-own-file](docs/rules/prefer-utility-function-own-file.md) | Enforce that sizable utility functions live in their own file rather than being co-located inside an entry-point or consumer file | | ✅ | | | | |
232
251
  | [prevent-children-clobber](docs/rules/prevent-children-clobber.md) | Prevent JSX spreads from silently discarding props.children | ✅ | | | | | |
233
252
  | [react-memoize-literals](docs/rules/react-memoize-literals.md) | Detect object, array, and function literals created in React components or hooks that create new references every render. Prefer memoized values (useMemo/useCallback) or module-level constants to keep referential stability. | ✅ | | | | 💡 | |
234
253
  | [react-usememo-should-be-component](docs/rules/react-usememo-should-be-component.md) | Enforce that useMemo hooks explicitly returning JSX should be abstracted into separate React components | ✅ | | | | | |
@@ -240,6 +259,8 @@ full closed loop is documented in agora's `.claude/skills/eslint-autonomy/SKILL.
240
259
  | [require-memo](docs/rules/require-memo.md) | React components must be memoized | ✅ | | | 🔧 | | |
241
260
  | [require-memoize-jsx-returners](docs/rules/require-memoize-jsx-returners.md) | Require @Memoize() decorator on instance members that return JSX or JSX factories | ✅ | | | 🔧 | | |
242
261
  | [require-migration-script-metadata](docs/rules/require-migration-script-metadata.md) | Enforce JSDoc migration metadata in callable scripts | ✅ | | | | | |
262
+ | [require-props-composition](docs/rules/require-props-composition.md) | Require React component Props types to compose (via Pick/Omit) with the props types of non-leaf child components rendered in JSX | | ✅ | | | | |
263
+ | [require-server-timestamp-for-firestore-dates](docs/rules/require-server-timestamp-for-firestore-dates.md) | Enforce serverTimestamp() instead of new Date() for Firestore timestamp fields | ✅ | | | | | |
243
264
  | [semantic-function-prefixes](docs/rules/semantic-function-prefixes.md) | Require semantic function prefixes instead of generic verbs so callers know whether a function fetches data, transforms input, or mutates state | ✅ | | | | | |
244
265
  | [sync-onwrite-name-func](docs/rules/sync-onwrite-name-func.md) | Ensure that the name field matches the func field in onWrite handlers | ✅ | | | 🔧 | | |
245
266
  | [test-file-location-enforcement](docs/rules/test-file-location-enforcement.md) | Enforce colocating *.test.ts or *.test.tsx files with the code they cover. | ✅ | | | | | |
package/lib/index.js CHANGED
@@ -10,12 +10,14 @@ const class_methods_read_top_to_bottom_1 = require("./rules/class-methods-read-t
10
10
  const consistent_callback_naming_1 = __importDefault(require("./rules/consistent-callback-naming"));
11
11
  const no_handler_suffix_1 = require("./rules/no-handler-suffix");
12
12
  const parallelize_async_operations_1 = require("./rules/parallelize-async-operations");
13
+ const parallelize_loop_awaits_1 = require("./rules/parallelize-loop-awaits");
13
14
  const dynamic_https_errors_1 = require("./rules/dynamic-https-errors");
14
15
  const enforce_empty_object_check_1 = require("./rules/enforce-empty-object-check");
15
16
  const enforce_identifiable_firestore_type_1 = require("./rules/enforce-identifiable-firestore-type");
16
17
  const enforce_callback_memo_1 = __importDefault(require("./rules/enforce-callback-memo"));
17
18
  const react_memoize_literals_1 = require("./rules/react-memoize-literals");
18
19
  const enforce_callable_types_1 = require("./rules/enforce-callable-types");
20
+ const enforce_cloud_function_id_length_1 = require("./rules/enforce-cloud-function-id-length");
19
21
  const enforce_console_error_1 = require("./rules/enforce-console-error");
20
22
  const enforce_dynamic_firebase_imports_1 = __importDefault(require("./rules/enforce-dynamic-firebase-imports"));
21
23
  const enforce_mui_rounded_icons_1 = require("./rules/enforce-mui-rounded-icons");
@@ -170,6 +172,25 @@ const test_file_location_enforcement_1 = require("./rules/test-file-location-enf
170
172
  const prevent_children_clobber_1 = require("./rules/prevent-children-clobber");
171
173
  const require_migration_script_metadata_1 = require("./rules/require-migration-script-metadata");
172
174
  const warn_https_error_message_user_friendly_1 = require("./rules/warn-https-error-message-user-friendly");
175
+ const no_stablehash_react_nodes_1 = require("./rules/no-stablehash-react-nodes");
176
+ const require_props_composition_1 = require("./rules/require-props-composition");
177
+ const require_server_timestamp_for_firestore_dates_1 = require("./rules/require-server-timestamp-for-firestore-dates");
178
+ const prefer_spread_over_reassembly_1 = require("./rules/prefer-spread-over-reassembly");
179
+ const prefer_sx_prop_over_system_props_1 = require("./rules/prefer-sx-prop-over-system-props");
180
+ const enforce_m3_sentence_case_1 = require("./rules/enforce-m3-sentence-case");
181
+ const no_redundant_boolean_callback_props_1 = require("./rules/no-redundant-boolean-callback-props");
182
+ const enforce_is_prefix_validators_1 = require("./rules/enforce-is-prefix-validators");
183
+ const enforce_types_directory_placement_1 = require("./rules/enforce-types-directory-placement");
184
+ const prefer_use_base62_id_1 = require("./rules/prefer-use-base62-id");
185
+ const no_direct_function_state_1 = require("./rules/no-direct-function-state");
186
+ const no_fill_template_mutation_1 = require("./rules/no-fill-template-mutation");
187
+ const enforce_snapshot_state_narrowing_1 = require("./rules/enforce-snapshot-state-narrowing");
188
+ const prefer_flat_transform_each_keys_1 = require("./rules/prefer-flat-transform-each-keys");
189
+ const prefer_use_theme_1 = require("./rules/prefer-use-theme");
190
+ const no_single_dismiss_dialog_button_1 = require("./rules/no-single-dismiss-dialog-button");
191
+ const no_portal_inside_tooltip_1 = require("./rules/no-portal-inside-tooltip");
192
+ const no_satisfies_in_frontend_bundle_1 = require("./rules/no-satisfies-in-frontend-bundle");
193
+ const prefer_utility_function_own_file_1 = require("./rules/prefer-utility-function-own-file");
173
194
  const NO_FRONTEND_IMPORTS_FROM_FUNCTIONS_MESSAGE = 'Backend Cloud Functions (.f.ts under functions/) must not import frontend modules from the repo root src/**. Frontend code can depend on browser-only APIs and bundling it into Cloud Functions breaks server execution; move shared logic into functions/src or a shared package.';
174
195
  function noFrontendImportsFromFunctionsPatterns(pattern) {
175
196
  return [
@@ -196,7 +217,7 @@ function noFrontendImportsFromFunctionsPatterns(pattern) {
196
217
  module.exports = {
197
218
  meta: {
198
219
  name: '@blumintinc/eslint-plugin-blumint',
199
- version: '1.16.2',
220
+ version: '1.17.1',
200
221
  },
201
222
  parseOptions: {
202
223
  ecmaVersion: 2020,
@@ -213,6 +234,7 @@ module.exports = {
213
234
  '@blumintinc/blumint/key-only-outermost-element': 'error',
214
235
  '@blumintinc/blumint/logical-top-to-bottom-grouping': 'error',
215
236
  '@blumintinc/blumint/parallelize-async-operations': 'error',
237
+ '@blumintinc/blumint/parallelize-loop-awaits': 'error',
216
238
  '@blumintinc/blumint/avoid-utils-directory': 'error',
217
239
  '@blumintinc/blumint/enforce-firestore-path-utils': 'error',
218
240
  '@blumintinc/blumint/enforce-firestore-rules-get-access': 'error',
@@ -227,6 +249,7 @@ module.exports = {
227
249
  '@blumintinc/blumint/enforce-callback-memo': 'error',
228
250
  '@blumintinc/blumint/react-memoize-literals': 'error',
229
251
  '@blumintinc/blumint/enforce-callable-types': 'error',
252
+ '@blumintinc/blumint/enforce-cloud-function-id-length': 'error',
230
253
  '@blumintinc/blumint/enforce-console-error': 'error',
231
254
  '@blumintinc/blumint/enforce-dynamic-firebase-imports': 'error',
232
255
  '@blumintinc/blumint/enforce-react-type-naming': 'error',
@@ -360,6 +383,7 @@ module.exports = {
360
383
  '@blumintinc/blumint/no-res-error-status-in-onrequest': 'error',
361
384
  '@blumintinc/blumint/no-array-length-in-deps': 'error',
362
385
  '@blumintinc/blumint/enforce-stable-hash-spread-props': 'error',
386
+ '@blumintinc/blumint/no-stablehash-react-nodes': 'error',
363
387
  '@blumintinc/blumint/prefer-use-deep-compare-memo': 'error',
364
388
  '@blumintinc/blumint/memo-nested-react-components': 'error',
365
389
  '@blumintinc/blumint/memo-compare-deeply-complex-props': 'error',
@@ -372,6 +396,24 @@ module.exports = {
372
396
  '@blumintinc/blumint/test-file-location-enforcement': 'error',
373
397
  '@blumintinc/blumint/require-migration-script-metadata': 'error',
374
398
  '@blumintinc/blumint/warn-https-error-message-user-friendly': 'warn',
399
+ '@blumintinc/blumint/require-props-composition': 'warn',
400
+ '@blumintinc/blumint/require-server-timestamp-for-firestore-dates': 'error',
401
+ '@blumintinc/blumint/prefer-spread-over-reassembly': 'error',
402
+ '@blumintinc/blumint/prefer-sx-prop-over-system-props': 'error',
403
+ '@blumintinc/blumint/enforce-m3-sentence-case': 'warn',
404
+ '@blumintinc/blumint/no-redundant-boolean-callback-props': 'error',
405
+ '@blumintinc/blumint/enforce-is-prefix-validators': 'error',
406
+ '@blumintinc/blumint/enforce-types-directory-placement': 'error',
407
+ '@blumintinc/blumint/prefer-use-base62-id': 'error',
408
+ '@blumintinc/blumint/no-direct-function-state': 'error',
409
+ '@blumintinc/blumint/no-fill-template-mutation': 'error',
410
+ '@blumintinc/blumint/enforce-snapshot-state-narrowing': 'error',
411
+ '@blumintinc/blumint/prefer-flat-transform-each-keys': 'warn',
412
+ '@blumintinc/blumint/prefer-use-theme': 'error',
413
+ '@blumintinc/blumint/no-single-dismiss-dialog-button': 'error',
414
+ '@blumintinc/blumint/no-portal-inside-tooltip': 'error',
415
+ '@blumintinc/blumint/no-satisfies-in-frontend-bundle': 'error',
416
+ '@blumintinc/blumint/prefer-utility-function-own-file': 'warn',
375
417
  },
376
418
  /**
377
419
  * Depth-specific overrides block only import strings that traverse to the
@@ -468,6 +510,7 @@ module.exports = {
468
510
  'class-methods-read-top-to-bottom': class_methods_read_top_to_bottom_1.classMethodsReadTopToBottom,
469
511
  'consistent-callback-naming': consistent_callback_naming_1.default,
470
512
  'parallelize-async-operations': parallelize_async_operations_1.parallelizeAsyncOperations,
513
+ 'parallelize-loop-awaits': parallelize_loop_awaits_1.parallelizeLoopAwaits,
471
514
  'dynamic-https-errors': dynamic_https_errors_1.dynamicHttpsErrors,
472
515
  'enforce-empty-object-check': enforce_empty_object_check_1.enforceEmptyObjectCheck,
473
516
  'enforce-identifiable-firestore-type': enforce_identifiable_firestore_type_1.enforceIdentifiableFirestoreType,
@@ -476,6 +519,7 @@ module.exports = {
476
519
  'enforce-react-type-naming': enforce_react_type_naming_1.enforceReactTypeNaming,
477
520
  'enforce-firestore-rules-get-access': enforce_firestore_rules_get_access_1.enforceFirestoreRulesGetAccess,
478
521
  'enforce-callable-types': enforce_callable_types_1.enforceCallableTypes,
522
+ 'enforce-cloud-function-id-length': enforce_cloud_function_id_length_1.enforceCloudFunctionIdLength,
479
523
  'enforce-console-error': enforce_console_error_1.enforceConsoleError,
480
524
  'enforce-dynamic-firebase-imports': enforce_dynamic_firebase_imports_1.default,
481
525
  'enforce-mui-rounded-icons': enforce_mui_rounded_icons_1.enforceMuiRoundedIcons,
@@ -560,6 +604,7 @@ module.exports = {
560
604
  'enforce-assert-safe-object-key': enforce_assert_safe_object_key_1.enforceAssertSafeObjectKey,
561
605
  'enforce-object-literal-as-const': enforce_object_literal_as_const_1.enforceObjectLiteralAsConst,
562
606
  'enforce-stable-hash-spread-props': enforce_stable_hash_spread_props_1.enforceStableHashSpreadProps,
607
+ 'no-stablehash-react-nodes': no_stablehash_react_nodes_1.noStablehashReactNodes,
563
608
  'enforce-positive-naming': enforce_positive_naming_1.enforcePositiveNaming,
564
609
  'no-type-assertion-returns': no_type_assertion_returns_1.noTypeAssertionReturns,
565
610
  'prefer-utility-function-over-private-static': prefer_utility_function_over_private_static_1.preferUtilityFunctionOverPrivateStatic,
@@ -622,6 +667,24 @@ module.exports = {
622
667
  'test-file-location-enforcement': test_file_location_enforcement_1.testFileLocationEnforcement,
623
668
  'require-migration-script-metadata': require_migration_script_metadata_1.requireMigrationScriptMetadata,
624
669
  'warn-https-error-message-user-friendly': warn_https_error_message_user_friendly_1.warnHttpsErrorMessageUserFriendly,
670
+ 'require-props-composition': require_props_composition_1.requirePropsComposition,
671
+ 'require-server-timestamp-for-firestore-dates': require_server_timestamp_for_firestore_dates_1.requireServerTimestampForFirestoreDates,
672
+ 'prefer-spread-over-reassembly': prefer_spread_over_reassembly_1.preferSpreadOverReassembly,
673
+ 'prefer-sx-prop-over-system-props': prefer_sx_prop_over_system_props_1.preferSxPropOverSystemProps,
674
+ 'enforce-m3-sentence-case': enforce_m3_sentence_case_1.enforceM3SentenceCase,
675
+ 'no-redundant-boolean-callback-props': no_redundant_boolean_callback_props_1.noRedundantBooleanCallbackProps,
676
+ 'enforce-is-prefix-validators': enforce_is_prefix_validators_1.enforceIsPrefixValidators,
677
+ 'enforce-types-directory-placement': enforce_types_directory_placement_1.enforceTypesDirectoryPlacement,
678
+ 'prefer-use-base62-id': prefer_use_base62_id_1.preferUseBase62Id,
679
+ 'no-direct-function-state': no_direct_function_state_1.noDirectFunctionState,
680
+ 'no-fill-template-mutation': no_fill_template_mutation_1.noFillTemplateMutation,
681
+ 'enforce-snapshot-state-narrowing': enforce_snapshot_state_narrowing_1.enforceSnapshotStateNarrowing,
682
+ 'prefer-flat-transform-each-keys': prefer_flat_transform_each_keys_1.preferFlatTransformEachKeys,
683
+ 'prefer-use-theme': prefer_use_theme_1.preferUseTheme,
684
+ 'no-single-dismiss-dialog-button': no_single_dismiss_dialog_button_1.noSingleDismissDialogButton,
685
+ 'no-portal-inside-tooltip': no_portal_inside_tooltip_1.noPortalInsideTooltip,
686
+ 'no-satisfies-in-frontend-bundle': no_satisfies_in_frontend_bundle_1.noSatisfiesInFrontendBundle,
687
+ 'prefer-utility-function-own-file': prefer_utility_function_own_file_1.preferUtilityFunctionOwnFile,
625
688
  },
626
689
  };
627
690
  //# sourceMappingURL=index.js.map
@@ -399,13 +399,25 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
399
399
  if (lowerCallee.startsWith('assert')) {
400
400
  return identifierReturnsBoolean(calleeName) ? 'boolean' : 'unknown';
401
401
  }
402
- const matchesPrefix = isPrefixedByBooleanKeyword(calleeName, approvedPrefixesWithoutAsserts);
403
- if (matchesPrefix ||
404
- lowerCallee.includes('boolean') ||
405
- lowerCallee.includes('enabled') ||
406
- lowerCallee.includes('auth') ||
407
- lowerCallee.includes('valid') ||
408
- lowerCallee.includes('check')) {
402
+ // Treat the callee as returning boolean when it has a boolean-indicating
403
+ // prefix at a proper name boundary. We check both the approved output
404
+ // prefixes (is/has/can/…) and additional callee-specific indicators
405
+ // (check, auth, valid, enabled, boolean). The critical constraint is
406
+ // boundary-correct starts-with: `checkAuth` (check + Auth, uppercase
407
+ // boundary) → boolean; `preserveUsersCheckedIn` (check is a substring
408
+ // mid-word, not a boundary prefix) → not boolean. Using
409
+ // isPrefixedByBooleanKeyword for all checks prevents the false-positive
410
+ // that raw String.includes() caused.
411
+ const calleeBooleanPrefixes = [
412
+ ...approvedPrefixesWithoutAsserts,
413
+ 'check',
414
+ 'auth',
415
+ 'valid',
416
+ 'enabled',
417
+ 'boolean',
418
+ ];
419
+ const matchesPrefix = isPrefixedByBooleanKeyword(calleeName, calleeBooleanPrefixes);
420
+ if (matchesPrefix) {
409
421
  return 'boolean';
410
422
  }
411
423
  if (lowerCallee.startsWith('get') ||
@@ -423,13 +435,17 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
423
435
  if (lowerMethodName.startsWith('assert')) {
424
436
  return 'unknown';
425
437
  }
426
- const matchesPrefix = isPrefixedByBooleanKeyword(methodName, approvedPrefixesWithoutAsserts);
427
- if (matchesPrefix ||
428
- lowerMethodName.includes('boolean') ||
429
- lowerMethodName.includes('enabled') ||
430
- lowerMethodName.includes('auth') ||
431
- lowerMethodName.includes('valid') ||
432
- lowerMethodName.includes('check')) {
438
+ // Same boundary-aware prefix check for method names on member expressions.
439
+ const methodBooleanPrefixes = [
440
+ ...approvedPrefixesWithoutAsserts,
441
+ 'check',
442
+ 'auth',
443
+ 'valid',
444
+ 'enabled',
445
+ 'boolean',
446
+ ];
447
+ const matchesPrefix = isPrefixedByBooleanKeyword(methodName, methodBooleanPrefixes);
448
+ if (matchesPrefix) {
433
449
  return 'boolean';
434
450
  }
435
451
  }
@@ -0,0 +1,5 @@
1
+ type Options = [{
2
+ maxLength?: number;
3
+ }?];
4
+ export declare const enforceCloudFunctionIdLength: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"tooLong", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
5
+ export {};
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.enforceCloudFunctionIdLength = void 0;
27
+ const createRule_1 = require("../utils/createRule");
28
+ const path = __importStar(require("path"));
29
+ const DEFAULT_MAX_LENGTH = 62;
30
+ const F_TS_EXTENSION = '.f.ts';
31
+ // Normalize any backslashes to forward slashes so the marker check works
32
+ // identically on Windows and POSIX. Firebase derives function IDs the same
33
+ // way regardless of OS, so the normalized form is canonical.
34
+ // We replace both the OS separator AND the literal backslash so that tests
35
+ // running on POSIX hosts can also exercise Windows-style paths.
36
+ function normalizeSeparators(filepath) {
37
+ // Replace OS-specific sep first, then any remaining backslashes.
38
+ return filepath.split(path.sep).join('/').split('\\').join('/');
39
+ }
40
+ // Build a normalized marker that always uses forward slashes after
41
+ // normalizeSeparators is applied.
42
+ const FUNCTIONS_SRC_MARKER = '/functions/src/';
43
+ function deriveFunctionId(filename) {
44
+ const normalized = normalizeSeparators(filename);
45
+ const idx = normalized.lastIndexOf(FUNCTIONS_SRC_MARKER);
46
+ if (idx === -1)
47
+ return null;
48
+ const relative = normalized.slice(idx + FUNCTIONS_SRC_MARKER.length);
49
+ if (!relative.endsWith(F_TS_EXTENSION))
50
+ return null;
51
+ const withoutExtension = relative.slice(0, -F_TS_EXTENSION.length);
52
+ // Firebase replaces path separators with hyphens and lowercases the result.
53
+ // After normalizeSeparators, separators are already forward slashes.
54
+ return withoutExtension.split('/').join('-').toLowerCase();
55
+ }
56
+ exports.enforceCloudFunctionIdLength = (0, createRule_1.createRule)({
57
+ name: 'enforce-cloud-function-id-length',
58
+ meta: {
59
+ type: 'problem',
60
+ docs: {
61
+ description: 'Ensures .f.ts file paths generate Firebase Cloud Function IDs within the 62-character limit',
62
+ recommended: 'error',
63
+ },
64
+ messages: {
65
+ tooLong: 'Firebase Cloud Function ID "{{id}}" is {{length}} characters; the limit is {{max}}. Shorten the filename or flatten the containing path.',
66
+ },
67
+ schema: [
68
+ {
69
+ type: 'object',
70
+ properties: {
71
+ maxLength: {
72
+ type: 'number',
73
+ default: DEFAULT_MAX_LENGTH,
74
+ },
75
+ },
76
+ additionalProperties: false,
77
+ },
78
+ ],
79
+ },
80
+ defaultOptions: [{}],
81
+ create(context, [options]) {
82
+ const maxLength = options?.maxLength ?? DEFAULT_MAX_LENGTH;
83
+ return {
84
+ Program(node) {
85
+ const filename = context.getFilename();
86
+ const id = deriveFunctionId(filename);
87
+ if (id === null)
88
+ return;
89
+ if (id.length <= maxLength)
90
+ return;
91
+ context.report({
92
+ node,
93
+ messageId: 'tooLong',
94
+ data: {
95
+ id,
96
+ length: String(id.length),
97
+ max: String(maxLength),
98
+ },
99
+ });
100
+ },
101
+ };
102
+ },
103
+ });
104
+ //# sourceMappingURL=enforce-cloud-function-id-length.js.map
@@ -0,0 +1,13 @@
1
+ type MessageIds = 'disallowedPrefix' | 'missingRequiredPrefix';
2
+ type Options = [
3
+ {
4
+ targetPaths?: string[];
5
+ requiredPrefix?: string;
6
+ allowedPrefixes?: string[];
7
+ disallowedPrefixes?: string[];
8
+ excludeNames?: string[];
9
+ excludePatterns?: string[];
10
+ }
11
+ ];
12
+ export declare const enforceIsPrefixValidators: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
13
+ export {};