Repository: testing-library/eslint-plugin-testing-library

Issue:
Bundle plugin in ESM format
The current bundle is in CJS format. Since ESLint flat config default format is ESM, we need to build the plugin for this format by default. Let's keep compatibility with CJS format for now, so we get both (we will have to point to the corresponding `dist/` paths for each in the `exports` field of the `package.json`.

Some resources on how to publish in both CJS and ESM with TS:

- https://blog.logrocket.com/publishing-node-modules-typescript-es-modules/
- https://thesametech.com/how-to-build-typescript-project/

Hints from issue comments:
@sdavids: Any update?

Flat config has been the default for 10 months now.

[ESLint 8 has reached EOL](https://eslint.org/blog/2024/09/eslint-v8-eol-version-support/)

While you are at it, you might want to update `README.md` with flat config examples as well.@sdavids: Does not work:

eslint.config.js
```
import testingLibrary from 'eslint-plugin-testing-library';

export default [
  {
    files: ['**/*.test.js'],
    ...testingLibrary.configs['flat/dom'],
  },
];

Edit: It works.@G-Rath: @sdavids could you open a new issue with more information on how it's not working, ideally with a reproduction? We already support ESLint v9 + flat config (with examples of that in our README), and I personally have been using it in `cjs` and `mjs` configs without any issues@sdavids: https://github.com/testing-library/eslint-plugin-testing-library/issues/900#issuecomment-2592836914 is obsolete.@Belco90: Discarding this idea, since it's quite difficult to achieve this goal and most (if not all) plugins don't bundle the code this way.@Belco90: Actually, we can mirror the bundling mechanism from [`eslint-plugin-vitest`](https://github.com/vitest-dev/eslint-plugin-vitest/blob/main/package.json), which uses [`tsdown`](https://tsdown.dev/) for it.@github-actions: :tada: This issue has been resolved in version 7.15.0 :tada:

The release is available on:
- [npm package (@latest dist-tag)](https://www.npmjs.com/package/eslint-plugin-testing-library/v/7.15.0)
- [GitHub release](https://github.com/testing-library/eslint-plugin-testing-library/releases/tag/v7.15.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:

Solution patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index 0423f90..93a919d 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -14,17 +14,6 @@ module.exports = {
 	rules: {
 		// Base
 		'max-lines-per-function': 'off',
-		'no-restricted-imports': [
-			'error',
-			{
-				patterns: [
-					{
-						group: ['@typescript-eslint/utils/dist/*'],
-						message: 'Import from `@typescript-eslint/utils` instead.',
-					},
-				],
-			},
-		],
 
 		// Import
 		'import/order': [
@@ -51,12 +40,12 @@ module.exports = {
 			files: ['**/*.ts?(x)'],
 			parser: '@typescript-eslint/parser',
 			parserOptions: {
+				project: './tsconfig.eslint.json',
 				tsconfigRootDir: __dirname,
-				project: ['./tsconfig.eslint.json'],
 			},
 			extends: [
 				'plugin:@typescript-eslint/recommended',
-				'plugin:@typescript-eslint/recommended-requiring-type-checking',
+				'plugin:@typescript-eslint/recommended-type-checked',
 				'plugin:import/typescript',
 			],
 			rules: {
diff --git a/.github/workflows/verifications.yml b/.github/workflows/verifications.yml
index 0d5b16b..0923858 100644
--- a/.github/workflows/verifications.yml
+++ b/.github/workflows/verifications.yml
@@ -35,22 +35,8 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        node: [12.22.0, 12, 14.17.0, 14, 16, 17, 18, 19, 20, 22]
-        eslint: [7.5, 7, 8, 9]
-        exclude:
-          # eslint@9 doesn't support < Node v18
-          - node: 17
-            eslint: 9
-          - node: 16
-            eslint: 9
-          - node: 14
-            eslint: 9
-          - node: 14.17.0
-            eslint: 9
-          - node: 12
-            eslint: 9
-          - node: 12.22.0
-            eslint: 9
+        node: [18.18.0, 18, 20.9.0, 20, 21.1.0, 21, 22, 23]
+        eslint: [8.57.0, 8, 9]
     steps:
       - name: Checkout
         uses: actions/checkout@v4
diff --git a/README.md b/README.md
index 0fa4619..12761bc 100644
--- a/README.md
+++ b/README.md
@@ -22,19 +22,19 @@
 [![PRs Welcome][pr-badge]][pr-url]
 [![All Contributors][all-contributors-badge]](#contributors-)
 
-## Installation
+## Prerequisites
 
-You'll first need to install [ESLint](https://eslint.org):
+To use this plugin, you must have [Node.js](https://nodejs.org/en/) (`^18.18.0`, `^20.9.0`, or `>=21.1.0`) installed.
 
-```shell
-$ npm install --save-dev eslint
-# or
-$ yarn add --dev eslint
-```
+## Installation
+
+You'll first need to [install ESLint](https://eslint.org/docs/latest/use/getting-started).
 
 Next, install `eslint-plugin-testing-library`:
 
 ```shell
+$ pnpm add --save-dev eslint-plugin-testing-library
+# or
 $ npm install --save-dev eslint-plugin-testing-library
 # or
 $ yarn add --dev eslint-plugin-testing-library
@@ -49,6 +49,7 @@ You can find detailed guides for migrating `eslint-plugin-testing-library` in th
 - [Migration guide for v4](docs/migration-guides/v4.md)
 - [Migration guide for v5](docs/migration-guides/v5.md)
 - [Migration guide for v6](docs/migration-guides/v6.md)
+- [Migration guide for v7](docs/migration-guides/v7.md)
 
 ## Usage
 
diff --git a/docs/migration-guides/v7.md b/docs/migration-guides/v7.md
new file mode 100644
index 0000000..f46957a
--- /dev/null
+++ b/docs/migration-guides/v7.md
@@ -0,0 +1,14 @@
+# Guide: migrating to v7
+
+If you are not on v6 yet, we recommend first following the [v6 migration guide](docs/migration-guides/v6.md).
+
+## Overview
+
+- **(Breaking)** Supported versions of Node.js have been updated to `^18.18.0`, `^20.9.0`, or `>=21.1.0`, matching ESLint.
+- **(Breaking)** Supported versions of ESLint have been updated to `^8.57.0`, or `^9.0.0`.
+- Full support for ESLint v9 (v8 still compatible) and typescript-eslint v8
+
+## Steps to upgrade
+
+1. Make sure you are using a supported version of Node.js, and upgrade if not.
+2. Make sure you are using a supported version of ESLint, and upgrade if not.
diff --git a/lib/configs/index.ts b/lib/configs/index.ts
index 15bcc70..eb441b2 100644
--- a/lib/configs/index.ts
+++ b/lib/configs/index.ts
@@ -1,6 +1,6 @@
 import { join } from 'path';
 
-import { type TSESLint } from '@typescript-eslint/utils';
+import type { TSESLint } from '@typescript-eslint/utils';
 
 import {
 	importDefault,
@@ -8,12 +8,10 @@ import {
 	SupportedTestingFramework,
 } from '../utils';
 
-export type LinterConfigRules = Pick<Required<TSESLint.Linter.Config>, 'rules'>;
-
 const configsDir = __dirname;
 
 const getConfigForFramework = (framework: SupportedTestingFramework) =>
-	importDefault<LinterConfigRules>(join(configsDir, framework));
+	importDefault<TSESLint.SharedConfig.RulesRecord>(join(configsDir, framework));
 
 export default SUPPORTED_TESTING_FRAMEWORKS.reduce(
 	(allConfigs, framework) => ({
@@ -21,4 +19,4 @@ export default SUPPORTED_TESTING_FRAMEWORKS.reduce(
 		[framework]: getConfigForFramework(framework),
 	}),
 	{}
-) as Record<SupportedTestingFramework, LinterConfigRules>;
+) as Record<SupportedTestingFramework, TSESLint.SharedConfig.RulesRecord>;
diff --git a/lib/create-testing-library-rule/detect-testing-library-utils.ts b/lib/create-testing-library-rule/detect-testing-library-utils.ts
index af263a9..001dc53 100644
--- a/lib/create-testing-library-rule/detect-testing-library-utils.ts
+++ b/lib/create-testing-library-rule/detect-testing-library-utils.ts
@@ -25,17 +25,19 @@ import {
 	PRESENCE_MATCHERS,
 } from '../utils';
 
-const SETTING_OPTION_OFF = 'off' as const;
+const SETTING_OPTION_OFF = 'off';
 
 export type TestingLibrarySettings = {
-	'testing-library/utils-module'?: string | typeof SETTING_OPTION_OFF;
+	'testing-library/utils-module'?:
+		| typeof SETTING_OPTION_OFF
+		| (string & NonNullable<unknown>);
 	'testing-library/custom-renders'?: string[] | typeof SETTING_OPTION_OFF;
 	'testing-library/custom-queries'?: string[] | typeof SETTING_OPTION_OFF;
 };
 
 export type TestingLibraryContext<
-	TOptions extends readonly unknown[],
 	TMessageIds extends string,
+	TOptions extends readonly unknown[],
 > = Readonly<
 	TSESLint.RuleContext<TMessageIds, TOptions> & {
 		settings: TestingLibrarySettings;
@@ -43,14 +45,13 @@ export type TestingLibraryContext<
 >;
 
 export type EnhancedRuleCreate<
-	TOptions extends readonly unknown[],
 	TMessageIds extends string,
-	TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
+	TOptions extends readonly unknown[],
 > = (
-	context: TestingLibraryContext<TOptions, TMessageIds>,
+	context: TestingLibraryContext<TMessageIds, TOptions>,
 	optionsWithDefault: Readonly<TOptions>,
 	detectionHelpers: Readonly<DetectionHelpers>
-) => TRuleListener;
+) => TSESLint.RuleListener;
 
 // Helpers methods
 type GetTestingLibraryImportNodeFn = () => ImportModuleNode | null;
@@ -154,15 +155,14 @@ export type DetectionOptions = {
  * Enhances a given rule `create` with helpers to detect Testing Library utils.
  */
 export function detectTestingLibraryUtils<
-	TOptions extends readonly unknown[],
 	TMessageIds extends string,
-	TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
+	TOptions extends readonly unknown[],
 >(
-	ruleCreate: EnhancedRuleCreate<TOptions, TMessageIds, TRuleListener>,
+	ruleCreate: EnhancedRuleCreate<TMessageIds, TOptions>,
 	{ skipRuleReportingCheck = false }: Partial<DetectionOptions> = {}
 ) {
 	return (
-		context: TestingLibraryContext<TOptions, TMessageIds>,
+		context: TestingLibraryContext<TMessageIds, TOptions>,
 		optionsWithDefault: Readonly<TOptions>
 	): TSESLint.RuleListener => {
 		const importedTestingLibraryNodes: ImportModuleNode[] = [];
@@ -212,6 +212,7 @@ export function detectTestingLibraryUtils<
 
 			const originalNodeName =
 				isImportSpecifier(importedUtilSpecifier) &&
+				ASTUtils.isIdentifier(importedUtilSpecifier.imported) &&
 				importedUtilSpecifier.local.name !== importedUtilSpecifier.imported.name
 					? importedUtilSpecifier.imported.name
 					: undefined;
diff --git a/lib/create-testing-library-rule/index.ts b/lib/create-testing-library-rule/index.ts
index c87f641..82e2840 100644
--- a/lib/create-testing-library-rule/index.ts
+++ b/lib/create-testing-library-rule/index.ts
@@ -1,6 +1,6 @@
-import { ESLintUtils, TSESLint } from '@typescript-eslint/utils';
+import { ESLintUtils } from '@typescript-eslint/utils';
 
-import { getDocsUrl, TestingLibraryRuleMeta } from '../utils';
+import { getDocsUrl, TestingLibraryPluginDocs } from '../utils';
 
 import {
 	DetectionOptions,
@@ -8,37 +8,30 @@ import {
 	EnhancedRuleCreate,
 } from './detect-testing-library-utils';
 
-export function createTestingLibraryRule<
+export const createTestingLibraryRule = <
 	TOptions extends readonly unknown[],
 	TMessageIds extends string,
-	TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
 >({
 	create,
 	detectionOptions = {},
-	meta,
 	...remainingConfig
-}: Readonly<{
-	name: string;
-	meta: TestingLibraryRuleMeta<TMessageIds, TOptions>;
-	defaultOptions: Readonly<TOptions>;
-	detectionOptions?: Partial<DetectionOptions>;
-	create: EnhancedRuleCreate<TOptions, TMessageIds, TRuleListener>;
-}>): TSESLint.RuleModule<TMessageIds, TOptions> {
-	// eslint-disable-next-line new-cap
-	return ESLintUtils.RuleCreator(getDocsUrl)({
+}: Readonly<
+	Omit<
+		ESLintUtils.RuleWithMetaAndName<
+			TOptions,
+			TMessageIds,
+			TestingLibraryPluginDocs<TOptions>
+		>,
+		'create'
+	> & {
+		create: EnhancedRuleCreate<TMessageIds, TOptions>;
+		detectionOptions?: Partial<DetectionOptions>;
+	}
+>) =>
+	ESLintUtils.RuleCreator<TestingLibraryPluginDocs<TOptions>>(getDocsUrl)({
 		...remainingConfig,
-		create: detectTestingLibraryUtils<TOptions, TMessageIds, TRuleListener>(
+		create: detectTestingLibraryUtils<TMessageIds, TOptions>(
 			create,
 			detectionOptions
 		),
-		meta: {
-			...meta,
-			docs: {
-				...meta.docs,
-				// We're using our own recommendedConfig meta to tell our build tools
-				// if the rule is recommended on a config basis
-				recommended: false,
-			},
-		},
 	});
-}
diff --git a/lib/index.ts b/lib/index.ts
index bfcdfb1..bb6f4db 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -8,7 +8,7 @@ import { SupportedTestingFramework } from './utils';
 const {
 	name: packageName,
 	version: packageVersion,
-	// eslint-disable-next-line @typescript-eslint/no-var-requires
+	// eslint-disable-next-line @typescript-eslint/no-require-imports
 } = require('../package.json') as { name: string; version: string };
 
 const plugin = {
@@ -20,7 +20,7 @@ const plugin = {
 	// we don't have types for flat config yet
 	configs: {} as Record<
 		SupportedTestingFramework | `flat/${SupportedTestingFramework}`,
-		Pick<Required<TSESLint.Linter.Config>, 'rules'>
+		TSESLint.SharedConfig.RulesRecord
 	>,
 	rules,
 };
@@ -35,9 +35,9 @@ plugin.configs = {
 				rules: config.rules,
 			},
 		])
-	) as Record<
+	) as unknown as Record<
 		`flat/${SupportedTestingFramework}`,
-		Pick<Required<TSESLint.Linter.Config>, 'rules'> & { plugins: unknown }
+		TSESLint.SharedConfig.RulesRecord & { plugins: unknown }
 	>),
 };
 
diff --git a/lib/node-utils/index.ts b/lib/node-utils/index.ts
index 9e9e9b0..85714c4 100644
--- a/lib/node-utils/index.ts
+++ b/lib/node-utils/index.ts
@@ -1,8 +1,8 @@
+import { FunctionScope, ScopeType } from '@typescript-eslint/scope-manager';
 import {
 	AST_NODE_TYPES,
 	ASTUtils,
 	TSESLint,
-	TSESLintScope,
 	TSESTree,
 } from '@typescript-eslint/utils';
 
@@ -188,7 +188,7 @@ export function isPromiseAllSettled(node: TSESTree.CallExpression): boolean {
 }
 
 /**
- * Determines whether a given node belongs to handled Promise.all or Promise.allSettled
+ * Determines whether a given node belongs to handled `Promise.all` or `Promise.allSettled`
  * array expression.
  */
 export function isPromisesArrayResolved(node: TSESTree.Node): boolean {
@@ -295,7 +295,7 @@ export function getVariableReferences(
 	return [];
 }
 
-interface InnermostFunctionScope extends TSESLintScope.FunctionScope {
+interface InnermostFunctionScope extends FunctionScope {
 	block:
 		| TSESTree.ArrowFunctionExpression
 		| TSESTree.FunctionDeclaration
@@ -312,7 +312,7 @@ export function getInnermostFunctionScope(
 	);
 
 	if (
-		innermostScope.type === 'function' &&
+		innermostScope.type === ScopeType.function &&
 		ASTUtils.isFunction(innermostScope.block)
 	) {
 		return innermostScope as unknown as InnermostFunctionScope;
@@ -665,6 +665,7 @@ export function findImportSpecifier(
 		const namedExport = node.specifiers.find((n) => {
 			return (
 				isImportSpecifier(n) &&
+				ASTUtils.isIdentifier(n.imported) &&
 				[n.imported.name, n.local.name].includes(specifierName)
 			);
 		});
diff --git a/lib/rules/await-async-events.ts b/lib/rules/await-async-events.ts
index 219c45b..7d4d81e 100644
--- a/lib/rules/await-async-events.ts
+++ b/lib/rules/await-async-events.ts
@@ -55,15 +55,15 @@ export default createTestingLibraryRule<Options, MessageIds>({
 						default: USER_EVENT_NAME,
 						oneOf: [
 							{
+								enum: EVENTS_SIMULATORS.concat(),
 								type: 'string',
-								enum: EVENTS_SIMULATORS,
 							},
 							{
-								type: 'array',
 								items: {
 									type: 'string',
-									enum: EVENTS_SIMULATORS,
+									enum: EVENTS_SIMULATORS.concat(),
 								},
+								type: 'array',
 							},
 						],
 					},
diff --git a/lib/rules/index.ts b/lib/rules/index.ts
index 7a340ac..94dc675 100644
--- a/lib/rules/index.ts
+++ b/lib/rules/index.ts
@@ -1,15 +1,7 @@
 import { readdirSync } from 'fs';
 import { join, parse } from 'path';
 
-import { TSESLint } from '@typescript-eslint/utils';
-
-import { importDefault, TestingLibraryRuleMeta } from '../utils';
-
-type RuleModule = TSESLint.RuleModule<string, unknown[]> & {
-	meta: TestingLibraryRuleMeta<string, unknown[]> & {
-		recommended: false;
-	};
-};
+import { importDefault, TestingLibraryPluginRuleModule } from '../utils';
 
 const rulesDir = __dirname;
 const excludedFiles = ['index'];
@@ -17,10 +9,12 @@ const excludedFiles = ['index'];
 export default readdirSync(rulesDir)
 	.map((rule) => parse(rule).name)
 	.filter((ruleName) => !excludedFiles.includes(ruleName))
-	.reduce<Record<string, RuleModule>>(
+	.reduce<Record<string, TestingLibraryPluginRuleModule<string, unknown[]>>>(
 		(allRules, ruleName) => ({
 			...allRules,
-			[ruleName]: importDefault<RuleModule>(join(rulesDir, ruleName)),
+			[ruleName]: importDefault<
+				TestingLibraryPluginRuleModule<string, unknown[]>
+			>(join(rulesDir, ruleName)),
 		}),
 		{}
 	);
diff --git a/lib/rules/no-await-sync-events.ts b/lib/rules/no-await-sync-events.ts
index 0a18b19..534c334 100644
--- a/lib/rules/no-await-sync-events.ts
+++ b/lib/rules/no-await-sync-events.ts
@@ -9,9 +9,9 @@ import {
 	isProperty,
 } from '../node-utils';
 
-const USER_EVENT_ASYNC_EXCEPTIONS: string[] = ['type', 'keyboard'];
-const FIRE_EVENT_OPTION = 'fire-event' as const;
-const USER_EVENT_OPTION = 'user-event' as const;
+const USER_EVENT_ASYNC_EXCEPTIONS = ['type', 'keyboard'];
+const FIRE_EVENT_OPTION = 'fire-event';
+const USER_EVENT_OPTION = 'user-event';
 const VALID_EVENT_MODULES = [FIRE_EVENT_OPTION, USER_EVENT_OPTION];
 const DEFAULT_EVENT_MODULES = [FIRE_EVENT_OPTION];
 
diff --git a/lib/rules/no-debugging-utils.ts b/lib/rules/no-debugging-utils.ts
index 3978fbd..cccc69d 100644
--- a/lib/rules/no-debugging-utils.ts
+++ b/lib/rules/no-debugging-utils.ts
@@ -53,7 +53,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
 					utilsToCheckFor: {
 						type: 'object',
 						properties: DEBUG_UTILS.reduce<
-							Record<string, JSONSchema.JSONSchema7>
+							Record<string, JSONSchema.JSONSchema4>
 						>(
 							(obj, name) => ({
 								[name]: { type: 'boolean' },
diff --git a/lib/rules/no-dom-import.ts b/lib/rules/no-dom-import.ts
index a095e01..b35e720 100644
--- a/lib/rules/no-dom-import.ts
+++ b/lib/rules/no-dom-import.ts
@@ -13,7 +13,7 @@ const DOM_TESTING_LIBRARY_MODULES = [
 ];
 
 const CORRECT_MODULE_NAME_BY_FRAMEWORK: Record<
-	'angular' | 'marko' | string,
+	'angular' | 'marko' | (string & NonNullable<unknown>),
 	string | undefined
 > = {
 	angular: '@testing-library/angular', // ATL is *always* called `@testing-library/angular`
diff --git a/lib/rules/no-manual-cleanup.ts b/lib/rules/no-manual-cleanup.ts
index ee65ee7..184f23e 100644
--- a/lib/rules/no-manual-cleanup.ts
+++ b/lib/rules/no-manual-cleanup.ts
@@ -75,6 +75,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
 				const cleanupSpecifier = moduleNode.specifiers.find(
 					(specifier) =>
 						isImportSpecifier(specifier) &&
+						ASTUtils.isIdentifier(specifier.imported) &&
 						specifier.imported.name === 'cleanup'
 				);
 
diff --git a/lib/rules/no-render-in-lifecycle.ts b/lib/rules/no-render-in-lifecycle.ts
index 2e5e52c..27771c5 100644
--- a/lib/rules/no-render-in-lifecycle.ts
+++ b/lib/rules/no-render-in-lifecycle.ts
@@ -68,6 +68,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
 				properties: {
 					allowTestingFrameworkSetupHook: {
 						enum: TESTING_FRAMEWORK_SETUP_HOOKS,
+						type: 'string',
 					},
 				},
 			},
diff --git a/lib/rules/prefer-explicit-assert.ts b/lib/rules/prefer-explicit-assert.ts
index 4b0d57e..82cfaaf 100644
--- a/lib/rules/prefer-explicit-assert.ts
+++ b/lib/rules/prefer-explicit-assert.ts
@@ -21,10 +21,11 @@ type Options = [
 
 const isAtTopLevel = (node: TSESTree.Node) =>
 	(!!node.parent?.parent &&
-		node.parent.parent.type === 'ExpressionStatement') ||
-	(node.parent?.parent?.type === 'AwaitExpression' &&
+		node.parent.parent.type === TSESTree.AST_NODE_TYPES.ExpressionStatement) ||
+	(node.parent?.parent?.type === TSESTree.AST_NODE_TYPES.AwaitExpression &&
 		!!node.parent.parent.parent &&
-		node.parent.parent.parent.type === 'ExpressionStatement');
+		node.parent.parent.parent.type ===
+			TSESTree.AST_NODE_TYPES.ExpressionStatement);
 
 const isVariableDeclaration = (node: TSESTree.Node) => {
 	if (
diff --git a/lib/rules/prefer-query-by-disappearance.ts b/lib/rules/prefer-query-by-disappearance.ts
index f19b379..19aa670 100644
--- a/lib/rules/prefer-query-by-disappearance.ts
+++ b/lib/rules/prefer-query-by-disappearance.ts
@@ -53,10 +53,10 @@ export default createTestingLibraryRule<Options, MessageIds>({
 		/**
 		 * Checks if node is reportable (starts with "get" or "find") and if it is, reports it with `context.report()`.
 		 *
-		 * @param {TSESTree.LeftHandSideExpression} node - Node to be tested
+		 * @param {TSESTree.Expression} node - Node to be tested
 		 * @returns {Boolean} Boolean indicating if expression was reported
 		 */
-		function reportExpression(node: TSESTree.LeftHandSideExpression): boolean {
+		function reportExpression(node: TSESTree.Expression): boolean {
 			const argumentProperty = isMemberExpression(node)
 				? getPropertyIdentifierNode(node.property)
 				: getPropertyIdentifierNode(node);
diff --git a/lib/utils/compat.ts b/lib/utils/compat.ts
index 2216dd8..0ad5e68 100644
--- a/lib/utils/compat.ts
+++ b/lib/utils/compat.ts
@@ -1,50 +1,4 @@
-import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
-
-declare module '@typescript-eslint/utils/dist/ts-eslint/Rule' {
-	export interface RuleContext<
-		// eslint-disable-next-line @typescript-eslint/no-unused-vars
-		TMessageIds extends string,
-		// eslint-disable-next-line @typescript-eslint/no-unused-vars
-		TOptions extends readonly unknown[],
-	> {
-		/**
-		 * The filename associated with the source.
-		 */
-		filename: string;
-
-		/**
-		 * A SourceCode object that you can use to work with the source that
-		 * was passed to ESLint.
-		 */
-		sourceCode: Readonly<TSESLint.SourceCode>;
-	}
-}
-
-declare module '@typescript-eslint/utils/dist/ts-eslint/SourceCode' {
-	export interface SourceCode {
-		/**
-		 * Returns the scope of the given node.
-		 * This information can be used track references to variables.
-		 * @since 8.37.0
-		 */
-		getScope(node: TSESTree.Node): TSESLint.Scope.Scope;
-		/**
-		 * Returns an array of the ancestors of the given node, starting at
-		 * the root of the AST and continuing through the direct parent of the current node.
-		 * This array does not include the currently-traversed node itself.
-		 * @since 8.38.0
-		 */
-		getAncestors(node: TSESTree.Node): TSESTree.Node[];
-		/**
-		 * Returns a list of variables declared by the given node.
-		 * This information can be used to track references to variables.
-		 * @since 8.38.0
-		 */
-		getDeclaredVariables(
-			node: TSESTree.Node
-		): readonly TSESLint.Scope.Variable[];
-	}
-}
+import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
 
 /* istanbul ignore next */
 export const getFilename = (
diff --git a/lib/utils/file-import.ts b/lib/utils/file-import.ts
index 6bfeae0..c419808 100644
--- a/lib/utils/file-import.ts
+++ b/lib/utils/file-import.ts
@@ -5,5 +5,5 @@ const interopRequireDefault = <T>(obj: any): { default: T } =>
 	obj?.__esModule ? obj : { default: obj };
 
 export const importDefault = <T>(moduleName: string): T =>
-	// eslint-disable-next-line @typescript-eslint/no-var-requires
+	// eslint-disable-next-line @typescript-eslint/no-require-imports
 	interopRequireDefault<T>(require(moduleName)).default;
diff --git a/lib/utils/types.ts b/lib/utils/types.ts
index 1dd6d9d..6b42fbd 100644
--- a/lib/utils/types.ts
+++ b/lib/utils/types.ts
@@ -1,29 +1,30 @@
-import { type TSESLint } from '@typescript-eslint/utils';
+import { TSESLint } from '@typescript-eslint/utils';
 
+type Recommended = 'error' | 'warn' | false;
 type RecommendedConfig<TOptions extends readonly unknown[]> =
-	| TSESLint.RuleMetaDataDocs['recommended']
-	| [TSESLint.RuleMetaDataDocs['recommended'], ...TOptions];
+	| Recommended
+	| [Recommended, ...TOptions];
 
-// These 2 types are copied from @typescript-eslint/utils' CreateRuleMeta
-// and modified to our needs
-export type TestingLibraryRuleMetaDocs<TOptions extends readonly unknown[]> =
-	Omit<TSESLint.RuleMetaDataDocs, 'recommended' | 'url'> & {
-		/**
-		 * The recommendation level for the rule on a framework basis.
-		 * Used by the build tools to generate the framework config.
-		 * Set to false to not include it the config
-		 */
-		recommendedConfig: Record<
-			SupportedTestingFramework,
-			RecommendedConfig<TOptions>
-		>;
-	};
-export type TestingLibraryRuleMeta<
+export type TestingLibraryPluginDocs<TOptions extends readonly unknown[]> = {
+	/**
+	 * The recommendation level for the rule on a framework basis.
+	 * Used by the build tools to generate the framework config.
+	 * Set to `false` to not include it the config
+	 */
+	recommendedConfig: Record<
+		SupportedTestingFramework,
+		RecommendedConfig<TOptions>
+	>;
+};
+
+export type TestingLibraryPluginRuleModule<
 	TMessageIds extends string,
 	TOptions extends readonly unknown[],
-> = Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'> & {
-	docs: TestingLibraryRuleMetaDocs<TOptions>;
-};
+> = TSESLint.RuleModuleWithMetaDocs<
+	TMessageIds,
+	TOptions,
+	TestingLibraryPluginDocs<TOptions>
+>;
 
 export const SUPPORTED_TESTING_FRAMEWORKS = [
 	'dom',
diff --git a/lint-staged.config.js b/lint-staged.config.js
index bbbe515..cb75792 100644
--- a/lint-staged.config.js
+++ b/lint-staged.config.js
@@ -1,4 +1,4 @@
-//eslint-disable-next-line @typescript-eslint/no-var-requires
+//eslint-disable-next-line @typescript-eslint/no-require-imports
 const { ESLint } = require('eslint');
 
 const removeIgnoredFiles = async (files) => {
diff --git a/package-lock.json b/package-lock.json
index eb037db..e9fccd9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
 			"version": "0.0.0-semantically-released",
 			"license": "MIT",
 			"dependencies": {
-				"@typescript-eslint/utils": "^5.62.0"
+				"@typescript-eslint/scope-manager": "^8.15.0",
+				"@typescript-eslint/utils": "^8.15.0"
 			},
 			"devDependencies": {
 				"@babel/core": "^7.25.8",
@@ -21,15 +22,16 @@
 				"@swc/jest": "^0.2.36",
 				"@types/jest": "^27.5.2",
 				"@types/node": "^22.8.6",
-				"@typescript-eslint/eslint-plugin": "^5.62.0",
-				"@typescript-eslint/parser": "^5.62.0",
+				"@typescript-eslint/eslint-plugin": "^8.15.0",
+				"@typescript-eslint/parser": "^8.15.0",
+				"@typescript-eslint/rule-tester": "^8.15.0",
 				"del-cli": "^5.1.0",
 				"eslint": "^8.57.1",
 				"eslint-config-prettier": "^9.1.0",
 				"eslint-doc-generator": "^1.7.1",
 				"eslint-import-resolver-typescript": "^3.6.3",
 				"eslint-plugin-import": "^2.31.0",
-				"eslint-plugin-jest": "^27.9.0",
+				"eslint-plugin-jest": "^28.8.3",
 				"eslint-plugin-jest-formatting": "^3.1.0",
 				"eslint-plugin-node": "^11.1.0",
 				"eslint-plugin-promise": "^6.6.0",
@@ -47,11 +49,11 @@
 				"typescript": "5.0.4"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0",
-				"npm": ">=6"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
+				"npm": ">=9.8.1"
 			},
 			"peerDependencies": {
-				"eslint": "^7.5.0 || ^8.0.0 || ^9.0.0"
+				"eslint": "^8.57.0 || ^9.0.0"
 			}
 		},
 		"node_modules/@ampproject/remapping": {
@@ -3562,7 +3564,8 @@
 		"node_modules/@types/json-schema": {
 			"version": "7.0.15",
 			"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
-			"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
+			"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+			"dev": true
 		},
 		"node_modules/@types/json5": {
 			"version": "0.0.29",
@@ -3606,7 +3609,8 @@
 		"node_modules/@types/semver": {
 			"version": "7.5.8",
 			"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
-			"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="
+			"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
+			"dev": true
 		},
 		"node_modules/@types/stack-utils": {
 			"version": "2.0.3",
@@ -3636,32 +3640,32 @@
 			"dev": true
 		},
 		"node_modules/@typescript-eslint/eslint-plugin": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
-			"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz",
+			"integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==",
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
-				"@eslint-community/regexpp": "^4.4.0",
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/type-utils": "5.62.0",
-				"@typescript-eslint/utils": "5.62.0",
-				"debug": "^4.3.4",
+				"@eslint-community/regexpp": "^4.10.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/type-utils": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"graphemer": "^1.4.0",
-				"ignore": "^5.2.0",
-				"natural-compare-lite": "^1.4.0",
-				"semver": "^7.3.7",
-				"tsutils": "^3.21.0"
+				"ignore": "^5.3.1",
+				"natural-compare": "^1.4.0",
+				"ts-api-utils": "^1.3.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"@typescript-eslint/parser": "^5.0.0",
-				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+				"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
+				"eslint": "^8.57.0 || ^9.0.0"
 			},
 			"peerDependenciesMeta": {
 				"typescript": {
@@ -3670,25 +3674,27 @@
 			}
 		},
 		"node_modules/@typescript-eslint/parser": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
-			"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz",
+			"integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==",
 			"dev": true,
+			"license": "BSD-2-Clause",
 			"dependencies": {
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/typescript-estree": "5.62.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"debug": "^4.3.4"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+				"eslint": "^8.57.0 || ^9.0.0"
 			},
 			"peerDependenciesMeta": {
 				"typescript": {
@@ -3696,16 +3702,66 @@
 				}
 			}
 		},
+		"node_modules/@typescript-eslint/rule-tester": {
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-8.15.0.tgz",
+			"integrity": "sha512-G9lQX5jX64wrP5nI1nAEBj48dgyYFH8f0pjruQD9byK0Ln2cOyZPMt51rnzsm5ru8Nc7exV5SYyRppEhzaqSfg==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
+				"ajv": "^6.12.6",
+				"json-stable-stringify-without-jsonify": "^1.0.1",
+				"lodash.merge": "4.6.2",
+				"semver": "^7.6.0"
+			},
+			"engines": {
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^8.57.0 || ^9.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/rule-tester/node_modules/ajv": {
+			"version": "6.12.6",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"fast-deep-equal": "^3.1.1",
+				"fast-json-stable-stringify": "^2.0.0",
+				"json-schema-traverse": "^0.4.1",
+				"uri-js": "^4.2.2"
+			},
+			"funding": {
+				"type": "github",
+				"url": "https://github.com/sponsors/epoberezkin"
+			}
+		},
+		"node_modules/@typescript-eslint/rule-tester/node_modules/json-schema-traverse": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+			"dev": true,
+			"license": "MIT"
+		},
 		"node_modules/@typescript-eslint/scope-manager": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
-			"integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz",
+			"integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==",
+			"license": "MIT",
 			"dependencies": {
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/visitor-keys": "5.62.0"
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
@@ -3713,25 +3769,26 @@
 			}
 		},
 		"node_modules/@typescript-eslint/type-utils": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
-			"integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz",
+			"integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==",
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
-				"@typescript-eslint/typescript-estree": "5.62.0",
-				"@typescript-eslint/utils": "5.62.0",
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
 				"debug": "^4.3.4",
-				"tsutils": "^3.21.0"
+				"ts-api-utils": "^1.3.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "*"
+				"eslint": "^8.57.0 || ^9.0.0"
 			},
 			"peerDependenciesMeta": {
 				"typescript": {
@@ -3740,11 +3797,12 @@
 			}
 		},
 		"node_modules/@typescript-eslint/types": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
-			"integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz",
+			"integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==",
+			"license": "MIT",
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
@@ -3752,20 +3810,22 @@
 			}
 		},
 		"node_modules/@typescript-eslint/typescript-estree": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
-			"integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz",
+			"integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==",
+			"license": "BSD-2-Clause",
 			"dependencies": {
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/visitor-keys": "5.62.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"debug": "^4.3.4",
-				"globby": "^11.1.0",
+				"fast-glob": "^3.3.2",
 				"is-glob": "^4.0.3",
-				"semver": "^7.3.7",
-				"tsutils": "^3.21.0"
+				"minimatch": "^9.0.4",
+				"semver": "^7.6.0",
+				"ts-api-utils": "^1.3.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
@@ -3777,41 +3837,68 @@
 				}
 			}
 		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"license": "MIT",
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+			"version": "9.0.5",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+			"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+			"license": "ISC",
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
 		"node_modules/@typescript-eslint/utils": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
-			"integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz",
+			"integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==",
+			"license": "MIT",
 			"dependencies": {
-				"@eslint-community/eslint-utils": "^4.2.0",
-				"@types/json-schema": "^7.0.9",
-				"@types/semver": "^7.3.12",
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/typescript-estree": "5.62.0",
-				"eslint-scope": "^5.1.1",
-				"semver": "^7.3.7"
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/typescript-estree": "8.15.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+				"eslint": "^8.57.0 || ^9.0.0"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
 			}
 		},
 		"node_modules/@typescript-eslint/visitor-keys": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
-			"integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz",
+			"integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==",
+			"license": "MIT",
 			"dependencies": {
-				"@typescript-eslint/types": "5.62.0",
-				"eslint-visitor-keys": "^3.3.0"
+				"@typescript-eslint/types": "8.15.0",
+				"eslint-visitor-keys": "^4.2.0"
 			},
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"type": "opencollective",
@@ -3819,11 +3906,12 @@
 			}
 		},
 		"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
-			"version": "3.4.3",
-			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-			"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+			"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+			"license": "Apache-2.0",
 			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 			},
 			"funding": {
 				"url": "https://opencollective.com/eslint"
@@ -4050,6 +4138,7 @@
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
 			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+			"dev": true,
 			"engines": {
 				"node": ">=8"
 			}
@@ -5439,6 +5528,7 @@
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+			"dev": true,
 			"dependencies": {
 				"path-type": "^4.0.0"
 			},
@@ -5791,6 +5881,111 @@
 				"eslint": ">= 7"
 			}
 		},
+		"node_modules/eslint-doc-generator/node_modules/@typescript-eslint/scope-manager": {
+			"version": "5.62.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
+			"integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/types": "5.62.0",
+				"@typescript-eslint/visitor-keys": "5.62.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/eslint-doc-generator/node_modules/@typescript-eslint/types": {
+			"version": "5.62.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
+			"integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
+			"dev": true,
+			"license": "MIT",
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/eslint-doc-generator/node_modules/@typescript-eslint/typescript-estree": {
+			"version": "5.62.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
+			"integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
+			"dev": true,
+			"license": "BSD-2-Clause",
+			"dependencies": {
+				"@typescript-eslint/types": "5.62.0",
+				"@typescript-eslint/visitor-keys": "5.62.0",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"semver": "^7.3.7",
+				"tsutils": "^3.21.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/eslint-doc-generator/node_modules/@typescript-eslint/utils": {
+			"version": "5.62.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
+			"integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.2.0",
+				"@types/json-schema": "^7.0.9",
+				"@types/semver": "^7.3.12",
+				"@typescript-eslint/scope-manager": "5.62.0",
+				"@typescript-eslint/types": "5.62.0",
+				"@typescript-eslint/typescript-estree": "5.62.0",
+				"eslint-scope": "^5.1.1",
+				"semver": "^7.3.7"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/eslint-doc-generator/node_modules/@typescript-eslint/visitor-keys": {
+			"version": "5.62.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
+			"integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
+			"dev": true,
+			"license": "MIT",
+			"dependencies": {
+				"@typescript-eslint/types": "5.62.0",
+				"eslint-visitor-keys": "^3.3.0"
+			},
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
 		"node_modules/eslint-doc-generator/node_modules/dot-prop": {
 			"version": "7.2.0",
 			"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
@@ -5818,6 +6013,19 @@
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
+		"node_modules/eslint-doc-generator/node_modules/eslint-visitor-keys": {
+			"version": "3.4.3",
+			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+			"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+			"dev": true,
+			"license": "Apache-2.0",
+			"engines": {
+				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/eslint"
+			}
+		},
 		"node_modules/eslint-import-resolver-node": {
 			"version": "0.3.9",
 			"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -5983,19 +6191,20 @@
 			}
 		},
 		"node_modules/eslint-plugin-jest": {
-			"version": "27.9.0",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz",
-			"integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==",
+			"version": "28.8.3",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.3.tgz",
+			"integrity": "sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==",
 			"dev": true,
+			"license": "MIT",
 			"dependencies": {
-				"@typescript-eslint/utils": "^5.10.0"
+				"@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0"
 			},
 			"engines": {
-				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+				"node": "^16.10.0 || ^18.12.0 || >=20.0.0"
 			},
 			"peerDependencies": {
-				"@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0",
-				"eslint": "^7.0.0 || ^8.0.0",
+				"@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0",
+				"eslint": "^7.0.0 || ^8.0.0 || ^9.0.0",
 				"jest": "*"
 			},
 			"peerDependenciesMeta": {
@@ -6183,6 +6392,7 @@
 			"version": "5.1.1",
 			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
 			"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+			"dev": true,
 			"dependencies": {
 				"esrecurse": "^4.3.0",
 				"estraverse": "^4.1.1"
@@ -6468,6 +6678,7 @@
 			"version": "4.3.0",
 			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
 			"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+			"dev": true,
 			"engines": {
 				"node": ">=4.0"
 			}
@@ -7162,6 +7373,7 @@
 			"version": "11.1.0",
 			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
 			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+			"dev": true,
 			"dependencies": {
 				"array-union": "^2.1.0",
 				"dir-glob": "^3.0.1",
@@ -7181,6 +7393,7 @@
 			"version": "3.0.0",
 			"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
 			"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+			"dev": true,
 			"engines": {
 				"node": ">=8"
 			}
@@ -12123,12 +12336,6 @@
 			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
 			"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
 		},
-		"node_modules/natural-compare-lite": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
-			"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
-			"dev": true
-		},
 		"node_modules/neo-async": {
 			"version": "2.6.2",
 			"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -15173,6 +15380,7 @@
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
 			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+			"dev": true,
 			"engines": {
 				"node": ">=8"
 			}
@@ -16982,6 +17190,18 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/ts-api-utils": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+			"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+			"license": "MIT",
+			"engines": {
+				"node": ">=16"
+			},
+			"peerDependencies": {
+				"typescript": ">=4.2.0"
+			}
+		},
 		"node_modules/ts-node": {
 			"version": "10.9.2",
 			"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -17068,6 +17288,8 @@
 			"version": "3.21.0",
 			"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
 			"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+			"dev": true,
+			"license": "MIT",
 			"dependencies": {
 				"tslib": "^1.8.1"
 			},
@@ -17081,7 +17303,9 @@
 		"node_modules/tsutils/node_modules/tslib": {
 			"version": "1.14.1",
 			"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-			"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+			"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+			"dev": true,
+			"license": "0BSD"
 		},
 		"node_modules/type-check": {
 			"version": "0.4.0",
@@ -20262,7 +20486,8 @@
 		"@types/json-schema": {
 			"version": "7.0.15",
 			"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
-			"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
+			"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+			"dev": true
 		},
 		"@types/json5": {
 			"version": "0.0.29",
@@ -20306,7 +20531,8 @@
 		"@types/semver": {
 			"version": "7.5.8",
 			"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
-			"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="
+			"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
+			"dev": true
 		},
 		"@types/stack-utils": {
 			"version": "2.0.3",
@@ -20336,103 +20562,152 @@
 			"dev": true
 		},
 		"@typescript-eslint/eslint-plugin": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
-			"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz",
+			"integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==",
 			"dev": true,
 			"requires": {
-				"@eslint-community/regexpp": "^4.4.0",
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/type-utils": "5.62.0",
-				"@typescript-eslint/utils": "5.62.0",
-				"debug": "^4.3.4",
+				"@eslint-community/regexpp": "^4.10.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/type-utils": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"graphemer": "^1.4.0",
-				"ignore": "^5.2.0",
-				"natural-compare-lite": "^1.4.0",
-				"semver": "^7.3.7",
-				"tsutils": "^3.21.0"
+				"ignore": "^5.3.1",
+				"natural-compare": "^1.4.0",
+				"ts-api-utils": "^1.3.0"
 			}
 		},
 		"@typescript-eslint/parser": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
-			"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz",
+			"integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==",
 			"dev": true,
 			"requires": {
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/typescript-estree": "5.62.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"debug": "^4.3.4"
 			}
 		},
+		"@typescript-eslint/rule-tester": {
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/rule-tester/-/rule-tester-8.15.0.tgz",
+			"integrity": "sha512-G9lQX5jX64wrP5nI1nAEBj48dgyYFH8f0pjruQD9byK0Ln2cOyZPMt51rnzsm5ru8Nc7exV5SYyRppEhzaqSfg==",
+			"dev": true,
+			"requires": {
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
+				"ajv": "^6.12.6",
+				"json-stable-stringify-without-jsonify": "^1.0.1",
+				"lodash.merge": "4.6.2",
+				"semver": "^7.6.0"
+			},
+			"dependencies": {
+				"ajv": {
+					"version": "6.12.6",
+					"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+					"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+					"dev": true,
+					"requires": {
+						"fast-deep-equal": "^3.1.1",
+						"fast-json-stable-stringify": "^2.0.0",
+						"json-schema-traverse": "^0.4.1",
+						"uri-js": "^4.2.2"
+					}
+				},
+				"json-schema-traverse": {
+					"version": "0.4.1",
+					"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+					"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+					"dev": true
+				}
+			}
+		},
 		"@typescript-eslint/scope-manager": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
-			"integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz",
+			"integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==",
 			"requires": {
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/visitor-keys": "5.62.0"
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0"
 			}
 		},
 		"@typescript-eslint/type-utils": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
-			"integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz",
+			"integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==",
 			"dev": true,
 			"requires": {
-				"@typescript-eslint/typescript-estree": "5.62.0",
-				"@typescript-eslint/utils": "5.62.0",
+				"@typescript-eslint/typescript-estree": "8.15.0",
+				"@typescript-eslint/utils": "8.15.0",
 				"debug": "^4.3.4",
-				"tsutils": "^3.21.0"
+				"ts-api-utils": "^1.3.0"
 			}
 		},
 		"@typescript-eslint/types": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
-			"integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ=="
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz",
+			"integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ=="
 		},
 		"@typescript-eslint/typescript-estree": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
-			"integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz",
+			"integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==",
 			"requires": {
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/visitor-keys": "5.62.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/visitor-keys": "8.15.0",
 				"debug": "^4.3.4",
-				"globby": "^11.1.0",
+				"fast-glob": "^3.3.2",
 				"is-glob": "^4.0.3",
-				"semver": "^7.3.7",
-				"tsutils": "^3.21.0"
+				"minimatch": "^9.0.4",
+				"semver": "^7.6.0",
+				"ts-api-utils": "^1.3.0"
+			},
+			"dependencies": {
+				"brace-expansion": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+					"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+					"requires": {
+						"balanced-match": "^1.0.0"
+					}
+				},
+				"minimatch": {
+					"version": "9.0.5",
+					"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+					"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+					"requires": {
+						"brace-expansion": "^2.0.1"
+					}
+				}
 			}
 		},
 		"@typescript-eslint/utils": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
-			"integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz",
+			"integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==",
 			"requires": {
-				"@eslint-community/eslint-utils": "^4.2.0",
-				"@types/json-schema": "^7.0.9",
-				"@types/semver": "^7.3.12",
-				"@typescript-eslint/scope-manager": "5.62.0",
-				"@typescript-eslint/types": "5.62.0",
-				"@typescript-eslint/typescript-estree": "5.62.0",
-				"eslint-scope": "^5.1.1",
-				"semver": "^7.3.7"
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"@typescript-eslint/scope-manager": "8.15.0",
+				"@typescript-eslint/types": "8.15.0",
+				"@typescript-eslint/typescript-estree": "8.15.0"
 			}
 		},
 		"@typescript-eslint/visitor-keys": {
-			"version": "5.62.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
-			"integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
+			"version": "8.15.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz",
+			"integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==",
 			"requires": {
-				"@typescript-eslint/types": "5.62.0",
-				"eslint-visitor-keys": "^3.3.0"
+				"@typescript-eslint/types": "8.15.0",
+				"eslint-visitor-keys": "^4.2.0"
 			},
 			"dependencies": {
 				"eslint-visitor-keys": {
-					"version": "3.4.3",
-					"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-					"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="
+					"version": "4.2.0",
+					"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+					"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="
 				}
 			}
 		},
@@ -20597,7 +20872,8 @@
 		"array-union": {
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
+			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+			"dev": true
 		},
 		"array.prototype.findlastindex": {
 			"version": "1.2.5",
@@ -21557,6 +21833,7 @@
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+			"dev": true,
 			"requires": {
 				"path-type": "^4.0.0"
 			}
@@ -21937,6 +22214,63 @@
 				"type-fest": "^3.0.0"
 			},
 			"dependencies": {
+				"@typescript-eslint/scope-manager": {
+					"version": "5.62.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
+					"integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "5.62.0",
+						"@typescript-eslint/visitor-keys": "5.62.0"
+					}
+				},
+				"@typescript-eslint/types": {
+					"version": "5.62.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
+					"integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
+					"dev": true
+				},
+				"@typescript-eslint/typescript-estree": {
+					"version": "5.62.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
+					"integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "5.62.0",
+						"@typescript-eslint/visitor-keys": "5.62.0",
+						"debug": "^4.3.4",
+						"globby": "^11.1.0",
+						"is-glob": "^4.0.3",
+						"semver": "^7.3.7",
+						"tsutils": "^3.21.0"
+					}
+				},
+				"@typescript-eslint/utils": {
+					"version": "5.62.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
+					"integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
+					"dev": true,
+					"requires": {
+						"@eslint-community/eslint-utils": "^4.2.0",
+						"@types/json-schema": "^7.0.9",
+						"@types/semver": "^7.3.12",
+						"@typescript-eslint/scope-manager": "5.62.0",
+						"@typescript-eslint/types": "5.62.0",
+						"@typescript-eslint/typescript-estree": "5.62.0",
+						"eslint-scope": "^5.1.1",
+						"semver": "^7.3.7"
+					}
+				},
+				"@typescript-eslint/visitor-keys": {
+					"version": "5.62.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
+					"integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "5.62.0",
+						"eslint-visitor-keys": "^3.3.0"
+					}
+				},
 				"dot-prop": {
 					"version": "7.2.0",
 					"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
@@ -21953,6 +22287,12 @@
 							"dev": true
 						}
 					}
+				},
+				"eslint-visitor-keys": {
+					"version": "3.4.3",
+					"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+					"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+					"dev": true
 				}
 			}
 		},
@@ -22078,12 +22418,12 @@
 			}
 		},
 		"eslint-plugin-jest": {
-			"version": "27.9.0",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz",
-			"integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==",
+			"version": "28.8.3",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.3.tgz",
+			"integrity": "sha512-HIQ3t9hASLKm2IhIOqnu+ifw7uLZkIlR7RYNv7fMcEi/p0CIiJmfriStQS2LDkgtY4nyLbIZAD+JL347Yc2ETQ==",
 			"dev": true,
 			"requires": {
-				"@typescript-eslint/utils": "^5.10.0"
+				"@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0"
 			}
 		},
 		"eslint-plugin-jest-formatting": {
@@ -22204,6 +22544,7 @@
 			"version": "5.1.1",
 			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
 			"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+			"dev": true,
 			"requires": {
 				"esrecurse": "^4.3.0",
 				"estraverse": "^4.1.1"
@@ -22288,7 +22629,8 @@
 		"estraverse": {
 			"version": "4.3.0",
 			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-			"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+			"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+			"dev": true
 		},
 		"esutils": {
 			"version": "2.0.3",
@@ -22804,6 +23146,7 @@
 			"version": "11.1.0",
 			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
 			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+			"dev": true,
 			"requires": {
 				"array-union": "^2.1.0",
 				"dir-glob": "^3.0.1",
@@ -22816,7 +23159,8 @@
 				"slash": {
 					"version": "3.0.0",
 					"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-					"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
+					"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+					"dev": true
 				}
 			}
 		},
@@ -26442,12 +26786,6 @@
 			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
 			"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
 		},
-		"natural-compare-lite": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
-			"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
-			"dev": true
-		},
 		"neo-async": {
 			"version": "2.6.2",
 			"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -28567,7 +28905,8 @@
 		"path-type": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
+			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+			"dev": true
 		},
 		"picocolors": {
 			"version": "1.1.1",
@@ -29909,6 +30248,12 @@
 			"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
 			"dev": true
 		},
+		"ts-api-utils": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+			"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+			"requires": {}
+		},
 		"ts-node": {
 			"version": "10.9.2",
 			"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -29969,6 +30314,7 @@
 			"version": "3.21.0",
 			"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
 			"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+			"dev": true,
 			"requires": {
 				"tslib": "^1.8.1"
 			},
@@ -29976,7 +30322,8 @@
 				"tslib": {
 					"version": "1.14.1",
 					"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-					"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+					"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+					"dev": true
 				}
 			}
 		},
diff --git a/package.json b/package.json
index 30ae54f..ba109d7 100644
--- a/package.json
+++ b/package.json
@@ -53,7 +53,8 @@
 		"type-check": "tsc --noEmit"
 	},
 	"dependencies": {
-		"@typescript-eslint/utils": "^5.62.0"
+		"@typescript-eslint/scope-manager": "^8.15.0",
+		"@typescript-eslint/utils": "^8.15.0"
 	},
 	"devDependencies": {
 		"@babel/core": "^7.25.8",
@@ -65,15 +66,16 @@
 		"@swc/jest": "^0.2.36",
 		"@types/jest": "^27.5.2",
 		"@types/node": "^22.8.6",
-		"@typescript-eslint/eslint-plugin": "^5.62.0",
-		"@typescript-eslint/parser": "^5.62.0",
+		"@typescript-eslint/eslint-plugin": "^8.15.0",
+		"@typescript-eslint/parser": "^8.15.0",
+		"@typescript-eslint/rule-tester": "^8.15.0",
 		"del-cli": "^5.1.0",
 		"eslint": "^8.57.1",
 		"eslint-config-prettier": "^9.1.0",
 		"eslint-doc-generator": "^1.7.1",
 		"eslint-import-resolver-typescript": "^3.6.3",
 		"eslint-plugin-import": "^2.31.0",
-		"eslint-plugin-jest": "^27.9.0",
+		"eslint-plugin-jest": "^28.8.3",
 		"eslint-plugin-jest-formatting": "^3.1.0",
 		"eslint-plugin-node": "^11.1.0",
 		"eslint-plugin-promise": "^6.6.0",
@@ -91,10 +93,10 @@
 		"typescript": "5.0.4"
 	},
 	"peerDependencies": {
-		"eslint": "^7.5.0 || ^8.0.0 || ^9.0.0"
+		"eslint": "^8.57.0 || ^9.0.0"
 	},
 	"engines": {
-		"node": "^12.22.0 || ^14.17.0 || >=16.0.0",
-		"npm": ">=6"
+		"node": "^18.18.0 || ^20.9.0 || >=21.1.0",
+		"npm": ">=9.8.1"
 	}
 }
diff --git a/tools/generate-configs/index.ts b/tools/generate-configs/index.ts
index ac43967..db46054 100644
--- a/tools/generate-configs/index.ts
+++ b/tools/generate-configs/index.ts
@@ -4,24 +4,18 @@ import rules from '../../lib/rules';
 import {
 	SUPPORTED_TESTING_FRAMEWORKS,
 	SupportedTestingFramework,
+	TestingLibraryPluginRuleModule,
 } from '../../lib/utils';
 
-import { LinterConfig, writeConfig } from './utils';
+import { writeConfig } from './utils';
 
 const RULE_NAME_PREFIX = 'testing-library/';
 
 const getRecommendedRulesForTestingFramework = (
 	framework: SupportedTestingFramework
 ): Record<string, TSESLint.Linter.RuleEntry> =>
-	Object.entries(rules)
-		.filter(
-			([
-				_,
-				{
-					meta: { docs },
-				},
-			]) => Boolean(docs.recommendedConfig[framework])
-		)
+	Object.entries<TestingLibraryPluginRuleModule<string, unknown[]>>(rules)
+		.filter(([_, { meta }]) => Boolean(meta.docs.recommendedConfig[framework]))
 		.reduce((allRules, [ruleName, { meta }]) => {
 			const name = `${RULE_NAME_PREFIX}${ruleName}`;
 			const recommendation = meta.docs.recommendedConfig[framework];
@@ -34,7 +28,7 @@ const getRecommendedRulesForTestingFramework = (
 
 (async () => {
 	for (const framework of SUPPORTED_TESTING_FRAMEWORKS) {
-		const specificFrameworkConfig: LinterConfig = {
+		const specificFrameworkConfig: TSESLint.Linter.ConfigType = {
 			plugins: ['testing-library'],
 			rules: getRecommendedRulesForTestingFramework(framework),
 		};
diff --git a/tools/generate-configs/utils.ts b/tools/generate-configs/utils.ts
index 9e97915..b6f36a3 100644
--- a/tools/generate-configs/utils.ts
+++ b/tools/generate-configs/utils.ts
@@ -6,8 +6,6 @@ import { format, resolveConfig } from 'prettier';
 
 const prettierConfig = resolveConfig(__dirname);
 
-export type LinterConfig = TSESLint.Linter.Config;
-
 const addAutoGeneratedComment = (code: string) =>
 	[
 		'// THIS CODE WAS AUTOMATICALLY GENERATED',
@@ -21,7 +19,7 @@ const addAutoGeneratedComment = (code: string) =>
  * Helper function writes configuration.
  */
 export const writeConfig = async (
-	config: LinterConfig,
+	config: TSESLint.Linter.ConfigType,
 	configName: string
 ): Promise<void> => {
 	// note: we use `export =` because ESLint will import these configs via a commonjs import



Test patch:
diff --git a/tests/eslint-remote-tester.config.js b/tests/eslint-remote-tester.config.js
index 730b557..f7c6399 100644
--- a/tests/eslint-remote-tester.config.js
+++ b/tests/eslint-remote-tester.config.js
@@ -1,4 +1,4 @@
-/* eslint-disable  @typescript-eslint/no-var-requires  */
+/* eslint-disable  @typescript-eslint/no-require-imports  */
 /* eslint-disable import/no-extraneous-dependencies */
 const { rules } = require('eslint-plugin-testing-library');
 const {
diff --git a/tests/index.test.ts b/tests/index.test.ts
index 68cfb52..d6dc83e 100644
--- a/tests/index.test.ts
+++ b/tests/index.test.ts
@@ -72,7 +72,7 @@ it('should export configs that refer to actual rules', () => {
 		expect(rule.startsWith(ruleNamePrefix)).toBe(true);
 		expect(ruleNames).toContain(ruleName);
 
-		// eslint-disable-next-line @typescript-eslint/no-unsafe-return
+		// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-require-imports
 		expect(() => require(`../lib/rules/${ruleName}`)).not.toThrow();
 	});
 });
diff --git a/tests/lib/FlatCompatRuleTester.ts b/tests/lib/FlatCompatRuleTester.ts
deleted file mode 100644
index b3ef594..0000000
--- a/tests/lib/FlatCompatRuleTester.ts
+++ /dev/null
@@ -1,191 +0,0 @@
-import { TSESLint } from '@typescript-eslint/utils';
-import { version as eslintVersion } from 'eslint/package.json';
-import * as semver from 'semver';
-
-export const usingFlatConfig = semver.major(eslintVersion) >= 9;
-
-declare module '@typescript-eslint/utils/dist/ts-eslint' {
-	// eslint-disable-next-line @typescript-eslint/no-namespace
-	export namespace FlatConfig {
-		export interface LinterOptions {
-			/**
-			 * A Boolean value indicating if inline configuration is allowed.
-			 */
-			noInlineConfig?: boolean;
-			/**
-			 * A severity string indicating if and how unused disable and enable
-			 * directives should be tracked and reported. For legacy compatibility, `true`
-			 * is equivalent to `"warn"` and `false` is equivalent to `"off"`.
-			 * @default "off"
-			 */
-			reportUnusedDisableDirectives?:
-				| TSESLint.Linter.Severity
-				| TSESLint.Linter.SeverityString
-				| boolean;
-		}
-
-		export interface Config {
-			/**
-			 * An string to identify the configuration object. Used in error messages and inspection tools.
-			 */
-			name?: string;
-			/**
-			 * An array of glob patterns indicating the files that the configuration object should apply to.
-			 * If not specified, the configuration object applies to all files matched by any other configuration object.
-			 */
-			files?: (string | string[])[];
-			/**
-			 * An array of glob patterns indicating the files that the configuration object should not apply to.
-			 * If not specified, the configuration object applies to all files matched by files.
-			 */
-			ignores?: string[];
-			/**
-			 * An object containing settings related to how JavaScript is configured for linting.
-			 */
-			languageOptions?: LanguageOptions;
-			/**
-			 * An object containing settings related to the linting process.
-			 */
-			linterOptions?: LinterOptions;
-			/**
-			 * An object containing a name-value mapping of plugin names to plugin objects.
-			 * When `files` is specified, these plugins are only available to the matching files.
-			 */
-			plugins?: unknown;
-			/**
-			 * Either an object containing `preprocess()` and `postprocess()` methods or
-			 * a string indicating the name of a processor inside of a plugin
-			 * (i.e., `"pluginName/processorName"`).
-			 */
-			processor?: string | TSESLint.Linter.Processor;
-			/**
-			 * An object containing the configured rules.
-			 * When `files` or `ignores` are specified, these rule configurations are only available to the matching files.
-			 */
-			rules?: TSESLint.Linter.RulesRecord;
-			/**
-			 * An object containing name-value pairs of information that should be available to all rules.
-			 */
-			settings?: TSESLint.SharedConfigurationSettings;
-		}
-
-		export type ParserOptions = TSESLint.Linter.ParserOptions;
-
-		export interface LanguageOptions {
-			/**
-			 * The version of ECMAScript to support.
-			 * May be any year (i.e., `2022`) or version (i.e., `5`).
-			 * Set to `"latest"` for the most recent supported version.
-			 * @default "latest"
-			 */
-			ecmaVersion?: Required<TSESLint.ParserOptions>['ecmaVersion'];
-			/**
-			 * An object specifying additional objects that should be added to the global scope during linting.
-			 */
-			globals?:
-				| Record<string, 'readonly' | 'writable' | 'off' | true>
-				| undefined;
-			/**
-			 * An object containing a `parse()` method or a `parseForESLint()` method.
-			 * @default
-			 * ```
-			 * // https://github.com/eslint/espree
-			 * require('espree')
-			 * ```
-			 */
-			parser?: unknown;
-			/**
-			 * An object specifying additional options that are passed directly to the parser.
-			 * The available options are parser-dependent.
-			 */
-			parserOptions?: ParserOptions | undefined;
-			/**
-			 * The type of JavaScript source code.
-			 * Possible values are `"script"` for traditional script files, `"module"` for ECMAScript modules (ESM), and `"commonjs"` for CommonJS files.
-			 * @default
-			 * ```
-			 * // for `.js` and `.mjs` files
-			 * "module"
-			 * // for `.cjs` files
-			 * "commonjs"
-			 * ```
-			 */
-			sourceType?: Required<TSESLint.ParserOptions>['sourceType'];
-		}
-	}
-}
-
-export class FlatCompatRuleTester extends TSESLint.RuleTester {
-	public constructor(testerConfig?: TSESLint.RuleTesterConfig) {
-		super(FlatCompatRuleTester._flatCompat(testerConfig));
-	}
-
-	public override run<
-		TMessageIds extends string,
-		TOptions extends readonly unknown[],
-	>(
-		ruleName: string,
-		rule: TSESLint.RuleModule<TMessageIds, TOptions>,
-		tests: TSESLint.RunTests<TMessageIds, TOptions>
-	) {
-		super.run(ruleName, rule, {
-			valid: tests.valid.map((t) => FlatCompatRuleTester._flatCompat(t)),
-			invalid: tests.invalid.map((t) => FlatCompatRuleTester._flatCompat(t)),
-		});
-	}
-
-	/* istanbul ignore next */
-	private static _flatCompat<
-		T extends
-			| undefined
-			| TSESLint.RuleTesterConfig
-			| string
-			| TSESLint.ValidTestCase<unknown[]>
-			| TSESLint.InvalidTestCase<string, unknown[]>,
-	>(config: T): T {
-		if (!config || !usingFlatConfig || typeof config === 'string') {
-			return config;
-		}
-
-		const obj: TSESLint.FlatConfig.Config & {
-			languageOptions: TSESLint.FlatConfig.LanguageOptions & {
-				parserOptions: TSESLint.FlatConfig.ParserOptions;
-			};
-		} = {
-			languageOptions: { parserOptions: {} },
-		};
-
-		for (const [key, value] of Object.entries(config)) {
-			if (key === 'parser') {
-				obj.languageOptions.parser = require(value as string);
-
-				continue;
-			}
-
-			if (key === 'parserOptions') {
-				for (const [option, val] of Object.entries(
-					value as { [s: string]: unknown }
-				)) {
-					if (option === 'ecmaVersion' || option === 'sourceType') {
-						// @ts-expect-error: TS thinks the value could the opposite type of whatever option is
-						obj.languageOptions[option] =
-							val as TSESLint.FlatConfig.LanguageOptions[
-								| 'ecmaVersion'
-								| 'sourceType'];
-
-						continue;
-					}
-
-					obj.languageOptions.parserOptions[option] = val;
-				}
-
-				continue;
-			}
-
-			// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-			obj[key as keyof typeof obj] = value;
-		}
-
-		return obj as unknown as T;
-	}
-}
diff --git a/tests/lib/test-utils.ts b/tests/lib/test-utils.ts
index aed679c..c65ac6c 100644
--- a/tests/lib/test-utils.ts
+++ b/tests/lib/test-utils.ts
@@ -1,21 +1,18 @@
-import { resolve } from 'path';
+import tsESLintParser from '@typescript-eslint/parser';
+import { RuleTester, RunTests } from '@typescript-eslint/rule-tester';
 
-import { TSESLint } from '@typescript-eslint/utils';
-
-import { FlatCompatRuleTester } from './FlatCompatRuleTester';
+import { TestingLibraryPluginRuleModule } from '../../lib/utils';
 
 const DEFAULT_TEST_CASE_CONFIG = {
 	filename: 'MyComponent.test.js',
 };
 
-class TestingLibraryRuleTester extends FlatCompatRuleTester {
-	run<TMessageIds extends string, TOptions extends Readonly<unknown[]>>(
+class TestingLibraryRuleTester extends RuleTester {
+	run<TMessageIds extends string, TOptions extends readonly unknown[]>(
 		ruleName: string,
-		rule: TSESLint.RuleModule<TMessageIds, TOptions>,
-		tests: TSESLint.RunTests<TMessageIds, TOptions>
+		rule: TestingLibraryPluginRuleModule<TMessageIds, TOptions>,
+		{ invalid, valid }: RunTests<TMessageIds, TOptions>
 	): void {
-		const { valid, invalid } = tests;
-
 		const finalValid = valid.map((testCase) => {
 			if (typeof testCase === 'string') {
 				return {
@@ -35,18 +32,14 @@ class TestingLibraryRuleTester extends FlatCompatRuleTester {
 	}
 }
 
-export const createRuleTester = (
-	parserOptions: Partial<TSESLint.ParserOptions> = {}
-): TSESLint.RuleTester => {
-	return new TestingLibraryRuleTester({
-		parser: resolve('./node_modules/@typescript-eslint/parser'),
-		parserOptions: {
-			ecmaVersion: 2018,
-			sourceType: 'module',
-			ecmaFeatures: {
-				jsx: true,
+export const createRuleTester = () =>
+	new TestingLibraryRuleTester({
+		languageOptions: {
+			parser: tsESLintParser,
+			parserOptions: {
+				ecmaFeatures: {
+					jsx: true,
+				},
 			},
-			...parserOptions,
 		},
 	});
-};