From 4d8d63d725595178529aabafedb97085db0c8462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ari=20Perkki=C3=B6?= Date: Tue, 28 May 2024 15:19:49 +0300 Subject: [PATCH] feat!: support `eslint@9` and flat config --- package.json | 1 - .../eslint-local-rules.cjs | 0 ...fig.cjs => eslint-remote-tester.config.js} | 22 +- packages/eslint-remote-tester/package.json | 11 +- .../eslint-remote-tester/src/config/config.ts | 4 +- .../eslint-remote-tester/src/config/load.ts | 11 +- .../eslint-remote-tester/src/config/types.ts | 11 +- .../src/config/validator.ts | 26 +- .../src/engine/worker-task.ts | 18 +- .../test/integration/base.config.cjs | 20 -- .../test/integration/base.config.js | 26 ++ .../test/integration/integration.test.ts | 8 +- .../test/smoke/base.config.cjs | 15 - .../test/smoke/base.config.js | 20 ++ .../test/smoke/smoke.test.ts | 18 +- packages/eslint-remote-tester/test/utils.ts | 38 +-- pnpm-lock.yaml | 273 +----------------- 17 files changed, 138 insertions(+), 384 deletions(-) rename eslint-local-rules.js => packages/eslint-remote-tester/eslint-local-rules.cjs (100%) rename packages/eslint-remote-tester/{eslint-remote-tester.config.cjs => eslint-remote-tester.config.js} (77%) delete mode 100644 packages/eslint-remote-tester/test/integration/base.config.cjs create mode 100644 packages/eslint-remote-tester/test/integration/base.config.js delete mode 100644 packages/eslint-remote-tester/test/smoke/base.config.cjs create mode 100644 packages/eslint-remote-tester/test/smoke/base.config.js diff --git a/package.json b/package.json index 145cf033..5ed1a1d5 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "conventional-changelog-cli": "^5.0.0", "eslint": "^9.3.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-local-rules": "^2.0.1", "eslint-plugin-prettier": "^5.1.3", "pkg-pr-new": "^0.0.5", "prettier": "^3.2.5", diff --git a/eslint-local-rules.js b/packages/eslint-remote-tester/eslint-local-rules.cjs similarity index 100% rename from eslint-local-rules.js rename to packages/eslint-remote-tester/eslint-local-rules.cjs diff --git a/packages/eslint-remote-tester/eslint-remote-tester.config.cjs b/packages/eslint-remote-tester/eslint-remote-tester.config.js similarity index 77% rename from packages/eslint-remote-tester/eslint-remote-tester.config.cjs rename to packages/eslint-remote-tester/eslint-remote-tester.config.js index 7858126c..3af6313f 100644 --- a/packages/eslint-remote-tester/eslint-remote-tester.config.cjs +++ b/packages/eslint-remote-tester/eslint-remote-tester.config.js @@ -1,4 +1,7 @@ -module.exports = { +import js from '@eslint/js'; + +/** @type {import('./src/config/types').Config} */ +const config = { repositories: [ 'AriPerkkio/eslint-remote-tester-integration-test-target', 'AriPerkkio/aria-live-capture', @@ -17,20 +20,7 @@ module.exports = { concurrentTasks: 3, - eslintrc: { - root: true, - env: { - es6: true, - }, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - ecmaFeatures: { - jsx: true, - }, - }, - extends: ['eslint:recommended'], - }, + eslintConfig: [js.configs.recommended], cache: true, @@ -61,3 +51,5 @@ module.exports = { */ onComplete: undefined, }; + +export default config; diff --git a/packages/eslint-remote-tester/package.json b/packages/eslint-remote-tester/package.json index 05a38419..55ac6dc9 100644 --- a/packages/eslint-remote-tester/package.json +++ b/packages/eslint-remote-tester/package.json @@ -22,9 +22,8 @@ "scripts": { "prebuild": "rm -rf ./dist", "build": "tsc --project tsconfig.prod.json", - "start": "node dist --config eslint-remote-tester.config.cjs", + "start": "node dist --config eslint-remote-tester.config.js", "start:memory-limit-crash": "NODE_OPTIONS=--max_old_space_size=50 node dist", - "lint": "eslint . --max-warnings 0 --ext .js,.ts,.tsx && publint", "test:integration": "vitest run --config test/integration/vitest.config.integration.ts", "test:smoke": "vitest run --config test/smoke/vitest.config.smoke.ts", "validate": "pnpm build && pnpm lint && pnpm test && pnpm test:integration" @@ -45,15 +44,15 @@ "simple-git": "^3.24.0" }, "devDependencies": { + "@eslint/eslintrc": "^3.1.0", "@types/babel__code-frame": "^7.0.6", "@types/eslint": "^8.56.10", "@types/node": "^20.12.12", "@types/object-hash": "^3.0.6", "@types/react": "^17.0.80", - "@typescript-eslint/eslint-plugin": "^7.11.0", - "@typescript-eslint/parser": "^7.11.0", "conventional-changelog-cli": "^5.0.0", - "eslint": "^8.57.0", + "eslint": "^9.3.0", + "eslint-plugin-local-rules": "^2.0.1", "eslint-remote-tester-repositories": "workspace:*", "ink-testing-library": "^2.1.0", "node-pty": "^1.0.0", @@ -63,7 +62,7 @@ "vitest": "^1.6.0" }, "peerDependencies": { - "eslint": ">=7", + "eslint": ">=9", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { diff --git a/packages/eslint-remote-tester/src/config/config.ts b/packages/eslint-remote-tester/src/config/config.ts index e2119170..f2694d63 100644 --- a/packages/eslint-remote-tester/src/config/config.ts +++ b/packages/eslint-remote-tester/src/config/config.ts @@ -8,7 +8,7 @@ import { loadConfig } from './load.js'; import { WorkerData } from '../engine/types.js'; const DEFAULT_CONFIGURATION_FILE_NAME = 'eslint-remote-tester.config'; -const DEFAULT_CONFIGURATION_FILE_JS = `${DEFAULT_CONFIGURATION_FILE_NAME}.cjs`; +const DEFAULT_CONFIGURATION_FILE_JS = `${DEFAULT_CONFIGURATION_FILE_NAME}.js`; const DEFAULT_CONFIGURATION_FILE_TS = `${DEFAULT_CONFIGURATION_FILE_NAME}.ts`; const CLI_ARGS_CONFIG = ['-c', '--config']; @@ -48,7 +48,7 @@ if (!fs.existsSync(CONFIGURATION_FILE)) { process.exit(); } -const configFileContents = loadConfig(path.resolve(CONFIGURATION_FILE)); +const configFileContents = await loadConfig(path.resolve(CONFIGURATION_FILE)); const config = getConfigWithDefaults(configFileContents); export default config; diff --git a/packages/eslint-remote-tester/src/config/load.ts b/packages/eslint-remote-tester/src/config/load.ts index 308c5358..916aad3f 100644 --- a/packages/eslint-remote-tester/src/config/load.ts +++ b/packages/eslint-remote-tester/src/config/load.ts @@ -1,5 +1,5 @@ import { createRequire } from 'node:module'; -import type { Service, RegisterOptions } from 'ts-node'; +import type { Service } from 'ts-node'; let registerer: Service | null = null; const require = createRequire(import.meta.url); @@ -11,9 +11,7 @@ const interopRequireDefault = (obj: any): { default: any } => /** @internal */ export const loadTSConfig = (configPath: string) => { try { - registerer ||= require('ts-node').register({ - moduleTypes: { '**/*.ts': 'cjs' }, - } satisfies RegisterOptions) as Service; + registerer ||= require('ts-node').register() as Service; } catch (e: any) { if (e.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -33,10 +31,11 @@ export const loadTSConfig = (configPath: string) => { return configObject; }; -export const loadConfig = (configPath: string) => { +export const loadConfig = async (configPath: string) => { if (configPath.endsWith('.ts')) { return loadTSConfig(configPath); } - return require(configPath); + const { default: config } = await import(configPath); + return config; }; diff --git a/packages/eslint-remote-tester/src/config/types.ts b/packages/eslint-remote-tester/src/config/types.ts index 3f645876..e63cb572 100644 --- a/packages/eslint-remote-tester/src/config/types.ts +++ b/packages/eslint-remote-tester/src/config/types.ts @@ -45,12 +45,12 @@ export interface Config { * Supports lazy initialization based on currently tested repository when a function is passed. * Function is called with current repository and its location on filesystem. */ - eslintrc: - | Linter.Config + eslintConfig: + | Linter.FlatConfig | ((options?: { repository: string; location: string; - }) => Linter.Config); + }) => Linter.FlatConfig | Promise); /** Flag used to set CI mode. `process.env.CI` is used when not set. */ CI: boolean; @@ -102,7 +102,10 @@ export interface Config { ) => Promise | void; } -type RequiredFields = Pick; +type RequiredFields = Pick< + Config, + 'repositories' | 'extensions' | 'eslintConfig' +>; type OptionalFields = AllKeysOptional< Pick< Config, diff --git a/packages/eslint-remote-tester/src/config/validator.ts b/packages/eslint-remote-tester/src/config/validator.ts index 437ac32a..2e00f86e 100644 --- a/packages/eslint-remote-tester/src/config/validator.ts +++ b/packages/eslint-remote-tester/src/config/validator.ts @@ -100,7 +100,7 @@ export default async function validate( rulesUnderTesting, resultParser, concurrentTasks, - eslintrc, + eslintConfig, CI, logLevel, slowLintTimeLimit, @@ -127,24 +127,26 @@ export default async function validate( errors.push(validateStringArray('extensions', extensions)); - if (!eslintrc) { - errors.push(`Missing eslintrc.`); + if (!eslintConfig) { + errors.push(`Missing eslintConfig.`); } else { try { - // This will throw when eslintrc is invalid + // This will throw when eslintConfig is invalid const linter = new ESLint({ - useEslintrc: false, + // @ts-expect-error -- `@types/eslint` for v9 are unavailable overrideConfig: - typeof eslintrc === 'function' ? eslintrc() : eslintrc, + typeof eslintConfig === 'function' + ? await eslintConfig() + : eslintConfig, }); errors.push(await validateEslintRules(linter)); } catch (e) { - errors.push(`eslintrc: ${e.message}`); + errors.push(`eslintConfig: ${e.message}`); - if (typeof eslintrc === 'function') { + if (typeof eslintConfig === 'function') { errors.push( - 'Note that "config.eslintrc" is called with empty options during configuration validation.' + 'Note that "config.eslintConfig" is called with empty options during configuration validation.' ); } } @@ -152,7 +154,7 @@ export default async function validate( // Optional fields - // TODO nice-to-have: Validate rules match eslintrc config + // TODO nice-to-have: Validate rules match eslintConfig config // https://eslint.org/docs/developer-guide/nodejs-api#lintergetrules if (rulesUnderTesting) { if (Array.isArray(rulesUnderTesting)) { @@ -294,7 +296,7 @@ export function getConfigWithDefaults(config: ConfigWithOptionals): Config { } /** - * Validate given rules of `config.eslintrc.rules` + * Validate given rules of `config.eslintConfig.rules` * - When unknown rules are defined, or known ones are misspelled they are not * reported during linting. We need to specifically look for them. */ @@ -313,7 +315,7 @@ async function validateEslintRules( } if (errors.length) { - return `Configuration validation errors at eslintrc.rules: \n - ${errors.join( + return `Configuration validation errors at eslintConfig.rules: \n - ${errors.join( '\n - ' )}`; } diff --git a/packages/eslint-remote-tester/src/engine/worker-task.ts b/packages/eslint-remote-tester/src/engine/worker-task.ts index e122ede8..1d390515 100644 --- a/packages/eslint-remote-tester/src/engine/worker-task.ts +++ b/packages/eslint-remote-tester/src/engine/worker-task.ts @@ -211,17 +211,20 @@ export default async function workerTask(): Promise { onReadFailure: () => postMessage({ type: 'READ_FAILURE' }), }); - const eslintrc = - typeof config.eslintrc === 'function' - ? config.eslintrc({ + const eslintConfig = + typeof config.eslintConfig === 'function' + ? await config.eslintConfig({ repository, location: resolve(`${CACHE_LOCATION}/${repository}`), }) - : config.eslintrc; + : config.eslintConfig; const linter = new ESLint({ - useEslintrc: false, - overrideConfig: eslintrc, + // @ts-expect-error -- `@types/eslint` for v9 are unavailable + overrideConfigFile: true, + + // @ts-expect-error -- `@types/eslint` for v9 are unavailable + overrideConfig: eslintConfig, // Only rules set in configuration are expected. // Ignore all inline configurations found from target repositories. @@ -229,7 +232,8 @@ export default async function workerTask(): Promise { // Lint all given files, ignore none. Cache is located under node_modules. // config.pathIgnorePattern is used for exclusions. - ignore: false, + ignore: true, + ignorePatterns: ['!**/node_modules/'], }); postMessage({ type: 'LINT_START', payload: files.length }); diff --git a/packages/eslint-remote-tester/test/integration/base.config.cjs b/packages/eslint-remote-tester/test/integration/base.config.cjs deleted file mode 100644 index 1530ea3c..00000000 --- a/packages/eslint-remote-tester/test/integration/base.config.cjs +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - repositories: ['AriPerkkio/eslint-remote-tester-integration-test-target'], - extensions: ['.js'], - pathIgnorePattern: '(expected-to-be-excluded)', - rulesUnderTesting: [ - 'no-unreachable', - 'no-undef', - 'no-empty', - 'getter-return', - 'no-compare-neg-zero', - ], - eslintrc: { - root: true, - extends: ['eslint:recommended'], - plugins: ['eslint-plugin-local-rules'], - rules: { - 'local-rules/some-unstable-rule': 'error', - }, - }, -}; diff --git a/packages/eslint-remote-tester/test/integration/base.config.js b/packages/eslint-remote-tester/test/integration/base.config.js new file mode 100644 index 00000000..a9cc2bf9 --- /dev/null +++ b/packages/eslint-remote-tester/test/integration/base.config.js @@ -0,0 +1,26 @@ +/** @type {import('../../src/config/types').Config} */ +const config = { + repositories: ['AriPerkkio/eslint-remote-tester-integration-test-target'], + extensions: ['.js'], + pathIgnorePattern: '(expected-to-be-excluded)', + rulesUnderTesting: [ + 'no-unreachable', + 'no-undef', + 'no-empty', + 'getter-return', + 'no-compare-neg-zero', + ], + eslintConfig: async function initialize() { + const { default: js } = await eval(`import('@eslint/js')`); + const { FlatCompat } = await eval(`import('@eslint/eslintrc')`); + const compat = new FlatCompat({ baseDirectory: process.cwd() }); + + return [ + js.configs.recommended, + ...compat.plugins('eslint-plugin-local-rules'), + { rules: { 'local-rules/some-unstable-rule': 'error' } }, + ]; + }, +}; + +export default config; diff --git a/packages/eslint-remote-tester/test/integration/integration.test.ts b/packages/eslint-remote-tester/test/integration/integration.test.ts index abf8d920..372d24d6 100644 --- a/packages/eslint-remote-tester/test/integration/integration.test.ts +++ b/packages/eslint-remote-tester/test/integration/integration.test.ts @@ -13,7 +13,7 @@ import { Config } from '../../src/config/types'; const DEBUG_LOG_PATTERN = /\[DEBUG (\S|:)*\] /g; -test('results are rendered on CI mode', async () => { +test.only('results are rendered on CI mode', async () => { const { output } = await runProductionBuild({ CI: true }); const finalLog = output.pop(); @@ -35,7 +35,7 @@ test('results are rendered on CI mode', async () => { TypeError: Cannot read property 'someAttribute' of undefined Occurred while linting /node_modules/.cache-eslint-remote-tester/AriPerkkio/eslint-remote-tester-integration-test-target/expected-to-crash-linter.js Rule: "local-rules/some-unstable-rule" - at Identifier (/eslint-local-rules.js) + at Identifier (/eslint-local-rules.cjs:22:56) at ruleErrorHandler (//node_modules/eslint/lib/linter/linter.js) at //node_modules/eslint/lib/linter/safe-emitter.js at Array.forEach () @@ -43,8 +43,8 @@ test('results are rendered on CI mode', async () => { at NodeEventGenerator.applySelector (//node_modules/eslint/lib/linter/node-event-generator.js) at NodeEventGenerator.applySelectors (//node_modules/eslint/lib/linter/node-event-generator.js) at NodeEventGenerator.enterNode (//node_modules/eslint/lib/linter/node-event-generator.js) - at CodePathAnalyzer.enterNode (//node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js) - at //node_modules/eslint/lib/linter/linter.js + at runRules (//node_modules/eslint/lib/linter/linter.js) + at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (//node_modules/eslint/lib/linter/linter.js) Repository: AriPerkkio/eslint-remote-tester-integration-test-target Rule: no-undef diff --git a/packages/eslint-remote-tester/test/smoke/base.config.cjs b/packages/eslint-remote-tester/test/smoke/base.config.cjs deleted file mode 100644 index d9aaa317..00000000 --- a/packages/eslint-remote-tester/test/smoke/base.config.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - repositories: ['AriPerkkio/eslint-remote-tester-integration-test-target'], - extensions: ['.js'], - rulesUnderTesting: [ - 'local-rules/verbose-rule', - 'local-rules/verbose-rule-2', - ], - eslintrc: { - root: true, - plugins: ['local-rules'], - rules: { - 'local-rules/verbose-rule': 'error', - }, - }, -}; diff --git a/packages/eslint-remote-tester/test/smoke/base.config.js b/packages/eslint-remote-tester/test/smoke/base.config.js new file mode 100644 index 00000000..fc156ea7 --- /dev/null +++ b/packages/eslint-remote-tester/test/smoke/base.config.js @@ -0,0 +1,20 @@ +/** @type {import('../../src/config/types').Config} */ +const config = { + repositories: ['AriPerkkio/eslint-remote-tester-integration-test-target'], + extensions: ['.js'], + rulesUnderTesting: [ + 'local-rules/verbose-rule', + 'local-rules/verbose-rule-2', + ], + eslintConfig: async function initialize() { + const { FlatCompat } = await eval(`import('@eslint/eslintrc')`); + const compat = new FlatCompat({ baseDirectory: process.cwd() }); + + return [ + ...compat.plugins('eslint-plugin-local-rules'), + { rules: { 'local-rules/verbose-rule': 'error' } }, + ]; + }, +}; + +export default config; diff --git a/packages/eslint-remote-tester/test/smoke/smoke.test.ts b/packages/eslint-remote-tester/test/smoke/smoke.test.ts index 0212f828..2d05f656 100644 --- a/packages/eslint-remote-tester/test/smoke/smoke.test.ts +++ b/packages/eslint-remote-tester/test/smoke/smoke.test.ts @@ -1,7 +1,7 @@ import { expect, test } from 'vitest'; import { runProductionBuild } from '../utils'; -const BASE_CONFIG = './smoke/base.config.cjs'; +const BASE_CONFIG = './smoke/base.config.js'; test('does not crash when handling 500Mb results', async () => { await runProductionBuild({ CI: false, compare: true }, BASE_CONFIG); @@ -10,13 +10,15 @@ test('does not crash when handling 500Mb results', async () => { { CI: false, compare: true, - eslintrc: { - root: true, - plugins: ['local-rules'], - rules: { - 'local-rules/verbose-rule-2': 'error', - }, - }, + eslintConfig: async function initialize() { + const { FlatCompat } = await eval(`import('@eslint/eslintrc')`); + const compat = new FlatCompat({ baseDirectory: process.cwd() }); + + return [ + ...compat.plugins('eslint-plugin-local-rules'), + { rules: { 'local-rules/verbose-rule-2': 'error' } }, + ]; + } as any, }, BASE_CONFIG ); diff --git a/packages/eslint-remote-tester/test/utils.ts b/packages/eslint-remote-tester/test/utils.ts index 892de5ef..4dfb2651 100644 --- a/packages/eslint-remote-tester/test/utils.ts +++ b/packages/eslint-remote-tester/test/utils.ts @@ -11,12 +11,10 @@ import { import { ComparisonTypes } from '../src/file-client/result-templates'; import { removeDirectorySync } from '../src/file-client/file-utils'; import { Config, ConfigToValidate } from '../src/config/types'; -import { createRequire } from 'node:module'; import { resolve } from 'node:path'; declare const console: { log: Mock; error: (...args: any) => void }; -const require = createRequire(import.meta.url); export const INTEGRATION_REPO_OWNER = 'AriPerkkio'; export const INTEGRATION_REPO_NAME = 'eslint-remote-tester-integration-test-target'; @@ -26,23 +24,24 @@ const LAST_RENDER_PATTERN = /(Results|Full log)[\s|\S]*/; const COMPARISON_RESULTS_PATTERN = /(Comparison results:[\s|\S]*)Results/; const ON_COMPLETE_PATTERN = /("onComplete": )"([\s|\S]*)"/; const RULES_UNDER_TESTING_PATTERN = /("rulesUnderTesting": )"([\s|\S]*)",/; -const ESLINTRC_PATTERN = /("eslintrc": )"([\s|\S]*)",/; +const ESLINT_CONFIG_PATTERN = /("eslintConfig": )"([\s|\S]*)",/; const ESCAPED_NEWLINE_PATTERN = /\\n/g; +const ESCAPED_QUOTE_PATTERN = /\\"/g; let idCounter = 0; /** * Create temporary configuration file for integration test */ -function createConfiguration( +async function createConfiguration( options: ConfigToValidate, - baseConfigPath = './integration/base.config.cjs', - fileExtension: 'cjs' | 'ts' -): { name: string; cleanup: () => void } { + baseConfigPath = './integration/base.config.js', + fileExtension: 'js' | 'ts' +): Promise<{ name: string; cleanup: () => void }> { const name = `./test/integration/integration.config-${idCounter++}.${fileExtension}`; - const baseConfig: Config = require(baseConfigPath); - const config = { ...baseConfig, ...options }; + const { default: baseConfig } = await import(baseConfigPath); + const config: Config = { ...baseConfig, ...options }; // Passing function to config file is tricky // - Add it as string to JSON @@ -53,20 +52,21 @@ function createConfiguration( if (typeof options.rulesUnderTesting === 'function') { config.rulesUnderTesting = options.rulesUnderTesting.toString() as any; } - if (typeof options.eslintrc === 'function') { - config.eslintrc = options.eslintrc.toString() as any; + if (typeof options.eslintConfig === 'function') { + config.eslintConfig = options.eslintConfig.toString() as any; + } + if (typeof config.eslintConfig === 'function') { + config.eslintConfig = config.eslintConfig.toString() as any; } const configText = JSON.stringify(config, null, 4) .replace(ON_COMPLETE_PATTERN, '$1$2') .replace(RULES_UNDER_TESTING_PATTERN, '$1$2,') - .replace(ESLINTRC_PATTERN, '$1$2,') - .replace(ESCAPED_NEWLINE_PATTERN, '\n'); - - const configExport = - fileExtension === 'ts' ? 'export default' : 'module.exports='; + .replace(ESLINT_CONFIG_PATTERN, '$1$2,') + .replace(ESCAPED_NEWLINE_PATTERN, '\n') + .replace(ESCAPED_QUOTE_PATTERN, '"'); - fs.writeFileSync(name, `${configExport} ${configText}`, 'utf8'); + fs.writeFileSync(name, `export default ${configText}`, 'utf8'); return { name, cleanup: () => fs.unlinkSync(name) }; } @@ -77,9 +77,9 @@ function createConfiguration( export async function runProductionBuild( options: ConfigToValidate = {}, baseConfigPath?: string, - fileExtension: 'cjs' | 'ts' = 'cjs' + fileExtension: 'js' | 'ts' = 'js' ): Promise<{ output: string[]; exitCode: number }> { - const { name, cleanup } = createConfiguration( + const { name, cleanup } = await createConfiguration( options, baseConfigPath, fileExtension diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 140450c3..7fc9b577 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,6 @@ importers: eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@9.3.0) - eslint-plugin-local-rules: - specifier: ^2.0.1 - version: 2.0.1 eslint-plugin-prettier: specifier: ^5.1.3 version: 5.1.3(eslint-config-prettier@9.1.0)(eslint@9.3.0)(prettier@3.2.5) @@ -66,6 +63,9 @@ importers: specifier: ^3.24.0 version: 3.24.0 devDependencies: + '@eslint/eslintrc': + specifier: ^3.1.0 + version: 3.1.0 '@types/babel__code-frame': specifier: ^7.0.6 version: 7.0.6 @@ -81,18 +81,15 @@ importers: '@types/react': specifier: ^17.0.80 version: 17.0.80 - '@typescript-eslint/eslint-plugin': - specifier: ^7.11.0 - version: 7.11.0(@typescript-eslint/parser@7.11.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': - specifier: ^7.11.0 - version: 7.11.0(eslint@8.57.0)(typescript@5.4.5) conventional-changelog-cli: specifier: ^5.0.0 version: 5.0.0 eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^9.3.0 + version: 9.3.0 + eslint-plugin-local-rules: + specifier: ^2.0.1 + version: 2.0.1 eslint-remote-tester-repositories: specifier: workspace:* version: link:../repositories @@ -392,16 +389,6 @@ packages: dev: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 8.57.0 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@9.3.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -417,23 +404,6 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.4 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/eslintrc@3.1.0: resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -451,27 +421,11 @@ packages: - supports-color dev: true - /@eslint/js@8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@eslint/js@9.3.0: resolution: {integrity: sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /@humanwhocodes/config-array@0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - /@humanwhocodes/config-array@0.13.0: resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -896,33 +850,6 @@ packages: resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} dev: false - /@typescript-eslint/eslint-plugin@7.11.0(@typescript-eslint/parser@7.11.0)(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.11.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.11.0 - '@typescript-eslint/type-utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.11.0 - eslint: 8.57.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/eslint-plugin@7.11.0(@typescript-eslint/parser@7.11.0)(eslint@9.3.0)(typescript@5.4.5): resolution: {integrity: sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -950,27 +877,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@7.11.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 7.11.0 - '@typescript-eslint/types': 7.11.0 - '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.11.0 - debug: 4.3.4 - eslint: 8.57.0 - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@7.11.0(eslint@9.3.0)(typescript@5.4.5): resolution: {integrity: sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==} engines: {node: ^18.18.0 || >=20.0.0} @@ -1000,26 +906,6 @@ packages: '@typescript-eslint/visitor-keys': 7.11.0 dev: true - /@typescript-eslint/type-utils@7.11.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.11.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.4 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/type-utils@7.11.0(eslint@9.3.0)(typescript@5.4.5): resolution: {integrity: sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==} engines: {node: ^18.18.0 || >=20.0.0} @@ -1067,22 +953,6 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@7.11.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.11.0 - '@typescript-eslint/types': 7.11.0 - '@typescript-eslint/typescript-estree': 7.11.0(typescript@5.4.5) - eslint: 8.57.0 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/utils@7.11.0(eslint@9.3.0)(typescript@5.4.5): resolution: {integrity: sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==} engines: {node: ^18.18.0 || >=20.0.0} @@ -1107,10 +977,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true - /@vitest/expect@1.6.0: resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} dependencies: @@ -1637,13 +1503,6 @@ packages: path-type: 4.0.0 dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - /dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -1734,14 +1593,6 @@ packages: synckit: 0.8.8 dev: true - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - /eslint-scope@8.0.1: resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1760,53 +1611,6 @@ packages: engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: true - /eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.5.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.1 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true - /eslint@9.3.0: resolution: {integrity: sha512-5Iv4CsZW030lpUqHBapdPo3MJetAPtejVW8B84GIcIIv8+ohFaddXsrn1Gn8uD9ijDb+kcYKFUVmC8qG8B2ORQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1859,15 +1663,6 @@ packages: eslint-visitor-keys: 4.0.0 dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 - dev: true - /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} @@ -1946,13 +1741,6 @@ packages: reusify: 1.0.4 dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.2.0 - dev: true - /file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1985,15 +1773,6 @@ packages: path-exists: 4.0.0 dev: true - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.3.1 - keyv: 4.5.4 - rimraf: 3.0.2 - dev: true - /flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -2078,18 +1857,6 @@ packages: is-glob: 4.0.3 dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - /glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} @@ -2102,13 +1869,6 @@ packages: once: 1.4.0 dev: true - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - /globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -2687,11 +2447,6 @@ packages: engines: {node: '>=8'} dev: true - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2917,13 +2672,6 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - /rollup@4.17.2: resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3255,11 +3003,6 @@ packages: engines: {node: '>=10'} dev: false - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'}