diff --git a/docs/getting-started/Quickstart.mdx b/docs/getting-started/Quickstart.mdx index d1daa5761be7..2731ff367f38 100644 --- a/docs/getting-started/Quickstart.mdx +++ b/docs/getting-started/Quickstart.mdx @@ -39,7 +39,7 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, + tseslint.configs.recommended, ); ``` @@ -52,6 +52,12 @@ The `.mjs` extension makes the file use the [ES modules (ESM)](https://developer +#### Details + +- `tseslint.config(...)` is an **_optional_** helper function — [read more about it here](../packages/TypeScript_ESLint.mdx#config). +- `'@eslint/js'` / `eslint.configs.recommended` turns on [eslint's recommended config](https://www.npmjs.com/package/@eslint/js). +- `tseslint.configs.recommended` turns on [our recommended config](../users/Shared_Configurations.mdx#recommended). + ### Step 3: Running ESLint Open a terminal to the root of your project and run the following command: @@ -82,12 +88,6 @@ pnpm eslint . ESLint will lint all TypeScript compatible files within the current folder, and will output the results to your terminal. -## Details - -- `tseslint.config(...)` is an _optional_ helper function — [read more about it here](../packages/TypeScript_ESLint.mdx#config). -- `'@eslint/js'` / `eslint.configs.recommended` turns on [eslint's recommended config](https://www.npmjs.com/package/@eslint/js). -- `...tseslint.configs.recommended` turns on [our recommended config](../users/Shared_Configurations.mdx#recommended). - ## Next Steps If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/faqs/General.mdx). @@ -103,11 +103,11 @@ We recommend you consider enabling the following two configs: export default tseslint.config( eslint.configs.recommended, // Remove this line - ...tseslint.configs.recommended, + tseslint.configs.recommended, // Add this line - ...tseslint.configs.strict, + tseslint.configs.strict, // Add this line - ...tseslint.configs.stylistic, + tseslint.configs.stylistic, ); ``` diff --git a/docs/getting-started/Typed_Linting.mdx b/docs/getting-started/Typed_Linting.mdx index e3c10288f0b8..96bf112253df 100644 --- a/docs/getting-started/Typed_Linting.mdx +++ b/docs/getting-started/Typed_Linting.mdx @@ -22,9 +22,9 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, // Remove this line - ...tseslint.configs.recommended, + tseslint.configs.recommended, // Added lines start - ...tseslint.configs.recommendedTypeChecked, + tseslint.configs.recommendedTypeChecked, { languageOptions: { parserOptions: { @@ -104,12 +104,12 @@ If you enabled the [`strict` shared config](../users/Shared_Configurations.mdx#s export default tseslint.config( eslint.configs.recommended, // Removed lines start - ...tseslint.configs.strict, - ...tseslint.configs.stylistic, + tseslint.configs.strict, + tseslint.configs.stylistic, // Removed lines end // Added lines start - ...tseslint.configs.strictTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, // Added lines end // ... ); @@ -205,8 +205,8 @@ You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configur ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.recommendedTypeChecked, + tseslint.configs.stylisticTypeChecked, { languageOptions: { parserOptions: { @@ -218,7 +218,7 @@ export default tseslint.config( // Added lines start { files: ['**/*.js'], - ...tseslint.configs.disableTypeChecked, + extends: [tseslint.configs.disableTypeChecked], }, // Added lines end ); diff --git a/docs/packages/TypeScript_ESLint.mdx b/docs/packages/TypeScript_ESLint.mdx index 5a9c2a4290db..83b57cbd7f19 100644 --- a/docs/packages/TypeScript_ESLint.mdx +++ b/docs/packages/TypeScript_ESLint.mdx @@ -51,7 +51,7 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, + tseslint.configs.recommended, ); ``` @@ -145,12 +145,12 @@ export default tseslint.config( { // disable type-aware linting on JS files files: ['**/*.js'], - ...tseslint.configs.disableTypeChecked, + extends: [tseslint.configs.disableTypeChecked], }, { // enable jest rules on test files files: ['test/**'], - ...jestPlugin.configs['flat/recommended'], + extends: [jestPlugin.configs['flat/recommended']], }, ); ``` @@ -172,7 +172,7 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, + tseslint.configs.recommended, { /*... */ }, @@ -216,7 +216,7 @@ export default tseslint.config({ files: ['**/*.ts'], extends: [ eslint.configs.recommended, - ...tseslint.configs.recommended, + tseslint.configs.recommended, ], rules: { '@typescript-eslint/array-type': 'error', diff --git a/docs/troubleshooting/faqs/General.mdx b/docs/troubleshooting/faqs/General.mdx index 174836130e71..53b752ab9b80 100644 --- a/docs/troubleshooting/faqs/General.mdx +++ b/docs/troubleshooting/faqs/General.mdx @@ -239,18 +239,22 @@ For example, the following config enables only the recommended config's type-che +{/* prettier-ignore */} ```js title="eslint.config.mjs" import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; -export default tseslint.config(...tseslint.configs.recommendedTypeCheckedOnly, { - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + tseslint.configs.recommendedTypeCheckedOnly, + { + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); ``` diff --git a/docs/troubleshooting/typed-linting/Monorepos.mdx b/docs/troubleshooting/typed-linting/Monorepos.mdx index 5924978b9947..85cc6ef264db 100644 --- a/docs/troubleshooting/typed-linting/Monorepos.mdx +++ b/docs/troubleshooting/typed-linting/Monorepos.mdx @@ -58,7 +58,7 @@ For each file being linted, the first matching project path will be used as its ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, + tseslint.configs.recommendedTypeChecked, { languageOptions: { parserOptions: { @@ -110,7 +110,7 @@ Instead of globs that use `**` to recursively check all folders, prefer paths th ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, + tseslint.configs.recommendedTypeChecked, { languageOptions: { parserOptions: { diff --git a/docs/troubleshooting/typed-linting/Performance.mdx b/docs/troubleshooting/typed-linting/Performance.mdx index 7c3e0400118d..f3cdbc569041 100644 --- a/docs/troubleshooting/typed-linting/Performance.mdx +++ b/docs/troubleshooting/typed-linting/Performance.mdx @@ -174,7 +174,7 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedRequiringTypeChecking, + tseslint.configs.recommendedRequiringTypeChecking, { languageOptions: { parserOptions: { diff --git a/docs/users/Shared_Configurations.mdx b/docs/users/Shared_Configurations.mdx index 66a649da33e0..bf0df1332de9 100644 --- a/docs/users/Shared_Configurations.mdx +++ b/docs/users/Shared_Configurations.mdx @@ -25,7 +25,7 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, + tseslint.configs.recommended, ); ``` @@ -39,8 +39,8 @@ If your project does not enable [typed linting](../getting-started/Typed_Linting ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, - ...tseslint.configs.stylistic, + tseslint.configs.recommended, + tseslint.configs.stylistic, ); ``` @@ -72,8 +72,8 @@ If your project enables [typed linting](../getting-started/Typed_Linting.mdx), w ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.recommendedTypeChecked, + tseslint.configs.stylisticTypeChecked, ); ``` @@ -125,8 +125,11 @@ These rules are those whose reports are almost always for a bad practice and/or +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.recommended); +export default tseslint.config( + tseslint.configs.recommended, +); ``` @@ -151,8 +154,11 @@ Rules newly added in this configuration are similarly useful to those in `recomm +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.recommendedTypeChecked); +export default tseslint.config( + tseslint.configs.recommendedTypeChecked, +); ``` @@ -177,8 +183,11 @@ Rules added in `strict` are more opinionated than recommended rules and might no +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.strict); +export default tseslint.config( + tseslint.configs.strict, +); ``` @@ -213,8 +222,11 @@ Rules newly added in this configuration are similarly useful (and opinionated) t +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.strictTypeChecked); +export default tseslint.config( + tseslint.configs.strictTypeChecked, +); ``` @@ -249,8 +261,11 @@ These rules are generally opinionated about enforcing simpler code patterns. +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.stylistic); +export default tseslint.config( + tseslint.configs.stylistic, +); ``` @@ -278,8 +293,11 @@ Rules newly added in this configuration are similarly opinionated to those in `s +{/* prettier-ignore */} ```js title="eslint.config.mjs" -export default tseslint.config(...tseslint.configs.stylisticTypeChecked); +export default tseslint.config( + tseslint.configs.stylisticTypeChecked, +); ``` @@ -346,7 +364,7 @@ If you use type-aware rules from other plugins, you will need to manually disabl ```js title="eslint.config.mjs" export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, + tseslint.configs.recommendedTypeChecked, { languageOptions: { parserOptions: { @@ -358,7 +376,7 @@ export default tseslint.config( // Added lines start { files: ['**/*.js'], - ...tseslint.configs.disableTypeChecked, + extends: [tseslint.configs.disableTypeChecked], }, // Added lines end ); diff --git a/docs/users/What_About_Formatting.mdx b/docs/users/What_About_Formatting.mdx index 44175985d518..a070fdfccfb2 100644 --- a/docs/users/What_About_Formatting.mdx +++ b/docs/users/What_About_Formatting.mdx @@ -56,8 +56,8 @@ import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.recommended, - ...someOtherConfig, + tseslint.configs.recommended, + someOtherConfig, // Add this line prettierConfig, ); diff --git a/eslint.config.mjs b/eslint.config.mjs index 1caf0d39663e..f57ac1c80f7f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -33,16 +33,15 @@ export default tseslint.config( ['@typescript-eslint/internal']: tseslintInternalPlugin, ['eslint-comments']: eslintCommentsPlugin, ['eslint-plugin']: eslintPluginPlugin, - // https://github.com/import-js/eslint-plugin-import/issues/2948 - ['import']: fixupPluginRules(importPlugin), + ['import']: importPlugin, ['jest']: jestPlugin, ['jsdoc']: jsdocPlugin, - ['jsx-a11y']: jsxA11yPlugin, + // @ts-expect-error -- https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/1038 + ['jsx-a11y']: jsxA11yPlugin.flatConfigs.recommended.plugins['jsx-a11y'], ['perfectionist']: perfectionistPlugin, // https://github.com/facebook/react/issues/28313 + ['react']: reactPlugin, ['react-hooks']: fixupPluginRules(reactHooksPlugin), - // https://github.com/jsx-eslint/eslint-plugin-react/issues/3699 - ['react']: fixupPluginRules(reactPlugin), ['regexp']: regexpPlugin, ['sonarjs']: sonarjsPlugin, ['unicorn']: unicornPlugin, @@ -86,8 +85,8 @@ export default tseslint.config( // extends ... eslint.configs.recommended, - ...tseslint.configs.strictTypeChecked, - ...tseslint.configs.stylisticTypeChecked, + tseslint.configs.strictTypeChecked, + tseslint.configs.stylisticTypeChecked, jsdocPlugin.configs['flat/recommended-typescript-error'], // base config @@ -457,7 +456,7 @@ export default tseslint.config( // { - extends: [...compat.config(eslintPluginPlugin.configs.recommended)], + extends: [eslintPluginPlugin.configs['flat/recommended']], files: [ 'packages/eslint-plugin-internal/**/*.{ts,tsx,cts,mts}', 'packages/eslint-plugin-tslint/**/*.{ts,tsx,cts,mts}', @@ -563,9 +562,10 @@ export default tseslint.config( { extends: [ - ...compat.config(jsxA11yPlugin.configs.recommended), - ...fixupConfigRules(compat.config(reactPlugin.configs.recommended)), - ...fixupConfigRules(compat.config(reactHooksPlugin.configs.recommended)), + jsxA11yPlugin.flatConfigs.recommended, + reactPlugin.configs.flat.recommended, + // https://github.com/facebook/react/pull/30774 + fixupConfigRules(compat.config(reactHooksPlugin.configs.recommended)), ], files: ['packages/website/**/*.{ts,tsx,mts,cts,js,jsx}'], rules: { diff --git a/package.json b/package.json index ec753633af65..87a3c880fd1f 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,9 @@ "hoistingLimits": "workspaces" }, "contributors": [ - "James Henry ", - "Nicholas C. Zakas", "Brad Zacher ", - "armano2", - "Jed Fox" + "Josh Goldberg ", + "James Henry " ], "type": "commonjs", "license": "BSD-2-Clause", @@ -95,12 +93,12 @@ "eslint": "^9.13.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-plugin": "^6.2.0", - "eslint-plugin-import": "^2.29.1", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^27.9.0", "eslint-plugin-jsdoc": "^47.0.2", - "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-perfectionist": "^3.8.0", - "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-regexp": "^2.6.0", "eslint-plugin-sonarjs": "^1.0.4", diff --git a/packages/rule-schema-to-typescript-types/package.json b/packages/rule-schema-to-typescript-types/package.json index cc3aa0ff0c6e..893dd90c7913 100644 --- a/packages/rule-schema-to-typescript-types/package.json +++ b/packages/rule-schema-to-typescript-types/package.json @@ -40,7 +40,8 @@ "prettier": "^3.2.5" }, "devDependencies": { - "@jest/types": "29.6.3" + "@jest/types": "29.6.3", + "typescript": "*" }, "funding": { "type": "opencollective", diff --git a/packages/typescript-eslint/src/config-helper.ts b/packages/typescript-eslint/src/config-helper.ts index 58866686d13c..4fc3ee070c76 100644 --- a/packages/typescript-eslint/src/config-helper.ts +++ b/packages/typescript-eslint/src/config-helper.ts @@ -18,6 +18,10 @@ TODO - convert this to /utils/ts-eslint */ import type { TSESLint } from '@typescript-eslint/utils'; +export type InfiniteDepthConfigWithExtends = + | ConfigWithExtends + | InfiniteDepthConfigWithExtends[]; + export interface ConfigWithExtends extends TSESLint.FlatConfig.Config { /** * Allows you to "extend" a set of configs similar to `extends` from the @@ -59,7 +63,7 @@ export interface ConfigWithExtends extends TSESLint.FlatConfig.Config { * ] * ``` */ - extends?: TSESLint.FlatConfig.ConfigArray; + extends?: InfiniteDepthConfigWithExtends[]; } /** @@ -83,14 +87,21 @@ export interface ConfigWithExtends extends TSESLint.FlatConfig.Config { * ``` */ export function config( - ...configs: ConfigWithExtends[] + ...configs: InfiniteDepthConfigWithExtends[] ): TSESLint.FlatConfig.ConfigArray { - return configs.flatMap((configWithExtends, configIndex) => { + const flattened = + // @ts-expect-error -- intentionally an infinite type + configs.flat(Infinity) as ConfigWithExtends[]; + return flattened.flatMap((configWithExtends, configIndex) => { const { extends: extendsArr, ...config } = configWithExtends; if (extendsArr == null || extendsArr.length === 0) { return config; } - const undefinedExtensions = extendsArr.reduce( + const extendsArrFlattened = extendsArr.flat( + Infinity, + ) as ConfigWithExtends[]; + + const undefinedExtensions = extendsArrFlattened.reduce( (acc, extension, extensionIndex) => { const maybeExtension = extension as | TSESLint.FlatConfig.Config @@ -115,7 +126,7 @@ export function config( } return [ - ...extendsArr.map(extension => { + ...extendsArrFlattened.map(extension => { const name = [config.name, extension.name].filter(Boolean).join('__'); return { ...extension, diff --git a/packages/typescript-eslint/tests/config-helper.test.ts b/packages/typescript-eslint/tests/config-helper.test.ts new file mode 100644 index 000000000000..b30ba7958658 --- /dev/null +++ b/packages/typescript-eslint/tests/config-helper.test.ts @@ -0,0 +1,250 @@ +import type { TSESLint } from '@typescript-eslint/utils'; + +import plugin from '../src/index'; + +describe('config helper', () => { + it('works without extends', () => { + expect( + plugin.config({ + files: ['file'], + ignores: ['ignored'], + rules: { rule: 'error' }, + }), + ).toEqual([ + { + files: ['file'], + ignores: ['ignored'], + rules: { rule: 'error' }, + }, + ]); + }); + + it('flattens extended configs', () => { + expect( + plugin.config({ + extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], + rules: { rule: 'error' }, + }), + ).toEqual([ + { rules: { rule1: 'error' } }, + { rules: { rule2: 'error' } }, + { rules: { rule: 'error' } }, + ]); + }); + + it('flattens extended configs with files and ignores', () => { + expect( + plugin.config({ + extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule: 'error' }, + }), + ).toEqual([ + { + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule1: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule2: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule: 'error' }, + }, + ]); + }); + + it('throws error containing config name when some extensions are undefined', () => { + const extension: TSESLint.FlatConfig.Config = { rules: { rule1: 'error' } }; + + expect(() => + plugin.config( + { + extends: [extension], + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config-1', + rules: { rule: 'error' }, + }, + { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + extends: [undefined as any, extension, undefined as any], + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config-2', + rules: { rule: 'error' }, + }, + ), + ).toThrow( + 'Your config at index 1, named "my-config-2", contains undefined ' + + 'extensions at the following indices: 0, 2', + ); + }); + + it('throws error without config name when some extensions are undefined', () => { + const extension: TSESLint.FlatConfig.Config = { rules: { rule1: 'error' } }; + + expect(() => + plugin.config( + { + extends: [extension], + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config-1', + rules: { rule: 'error' }, + }, + { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + extends: [undefined as any, extension, undefined as any], + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule: 'error' }, + }, + ), + ).toThrow( + 'Your config at index 1 (anonymous) contains undefined extensions at ' + + 'the following indices: 0, 2', + ); + }); + + it('flattens extended configs with config name', () => { + expect( + plugin.config({ + extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule: 'error' }, + }), + ).toEqual([ + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule1: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule2: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule: 'error' }, + }, + ]); + }); + + it('flattens extended configs with names if base config is unnamed', () => { + expect( + plugin.config({ + extends: [ + { name: 'extension-1', rules: { rule1: 'error' } }, + { rules: { rule2: 'error' } }, + ], + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule: 'error' }, + }), + ).toEqual([ + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'extension-1', + rules: { rule1: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule2: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + rules: { rule: 'error' }, + }, + ]); + }); + + it('merges config items names', () => { + expect( + plugin.config({ + extends: [ + { name: 'extension-1', rules: { rule1: 'error' } }, + { rules: { rule2: 'error' } }, + ], + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule: 'error' }, + }), + ).toEqual([ + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config__extension-1', + rules: { rule1: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule2: 'error' }, + }, + { + files: ['common-file'], + ignores: ['common-ignored'], + name: 'my-config', + rules: { rule: 'error' }, + }, + ]); + }); + + it('allows nested arrays in the config function', () => { + expect( + plugin.config( + { rules: { rule1: 'error' } }, + [{ rules: { rule2: 'error' } }], + [[{ rules: { rule3: 'error' } }]], + [[[{ rules: { rule4: 'error' } }]]], + [[[[{ rules: { rule5: 'error' } }]]]], + ), + ).toEqual([ + { rules: { rule1: 'error' } }, + { rules: { rule2: 'error' } }, + { rules: { rule3: 'error' } }, + { rules: { rule4: 'error' } }, + { rules: { rule5: 'error' } }, + ]); + }); + + it('allows nested arrays in extends', () => { + expect( + plugin.config({ + extends: [ + { rules: { rule1: 'error' } }, + [{ rules: { rule2: 'error' } }], + [[{ rules: { rule3: 'error' } }]], + [[[{ rules: { rule4: 'error' } }]]], + [[[[{ rules: { rule5: 'error' } }]]]], + ], + rules: { rule: 'error' }, + }), + ).toEqual([ + { rules: { rule1: 'error' } }, + { rules: { rule2: 'error' } }, + { rules: { rule3: 'error' } }, + { rules: { rule4: 'error' } }, + { rules: { rule5: 'error' } }, + { rules: { rule: 'error' } }, + ]); + }); +}); diff --git a/packages/typescript-eslint/tests/configs.test.ts b/packages/typescript-eslint/tests/configs.test.ts index e020dba758b5..742178196c81 100644 --- a/packages/typescript-eslint/tests/configs.test.ts +++ b/packages/typescript-eslint/tests/configs.test.ts @@ -1,4 +1,3 @@ -import type { TSESLint } from '@typescript-eslint/utils'; import type { FlatConfig, RuleRecommendation, @@ -311,210 +310,3 @@ describe('stylistic-type-checked-only.ts', () => { itHasBaseRulesOverriden(unfilteredConfigRules); }); - -describe('config helper', () => { - it('works without extends', () => { - expect( - plugin.config({ - files: ['file'], - ignores: ['ignored'], - rules: { rule: 'error' }, - }), - ).toEqual([ - { - files: ['file'], - ignores: ['ignored'], - rules: { rule: 'error' }, - }, - ]); - }); - - it('flattens extended configs', () => { - expect( - plugin.config({ - extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], - rules: { rule: 'error' }, - }), - ).toEqual([ - { rules: { rule1: 'error' } }, - { rules: { rule2: 'error' } }, - { rules: { rule: 'error' } }, - ]); - }); - - it('flattens extended configs with files and ignores', () => { - expect( - plugin.config({ - extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule: 'error' }, - }), - ).toEqual([ - { - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule1: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule2: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule: 'error' }, - }, - ]); - }); - - it('throws error containing config name when some extensions are undefined', () => { - const extension: TSESLint.FlatConfig.Config = { rules: { rule1: 'error' } }; - - expect(() => - plugin.config( - { - extends: [extension], - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config-1', - rules: { rule: 'error' }, - }, - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - extends: [undefined as any, extension, undefined as any], - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config-2', - rules: { rule: 'error' }, - }, - ), - ).toThrow( - 'Your config at index 1, named "my-config-2", contains undefined ' + - 'extensions at the following indices: 0, 2', - ); - }); - - it('throws error without config name when some extensions are undefined', () => { - const extension: TSESLint.FlatConfig.Config = { rules: { rule1: 'error' } }; - - expect(() => - plugin.config( - { - extends: [extension], - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config-1', - rules: { rule: 'error' }, - }, - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - extends: [undefined as any, extension, undefined as any], - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule: 'error' }, - }, - ), - ).toThrow( - 'Your config at index 1 (anonymous) contains undefined extensions at ' + - 'the following indices: 0, 2', - ); - }); - - it('flattens extended configs with config name', () => { - expect( - plugin.config({ - extends: [{ rules: { rule1: 'error' } }, { rules: { rule2: 'error' } }], - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule: 'error' }, - }), - ).toEqual([ - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule1: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule2: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule: 'error' }, - }, - ]); - }); - - it('flattens extended configs with names if base config is unnamed', () => { - expect( - plugin.config({ - extends: [ - { name: 'extension-1', rules: { rule1: 'error' } }, - { rules: { rule2: 'error' } }, - ], - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule: 'error' }, - }), - ).toEqual([ - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'extension-1', - rules: { rule1: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule2: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - rules: { rule: 'error' }, - }, - ]); - }); - - it('merges config items names', () => { - expect( - plugin.config({ - extends: [ - { name: 'extension-1', rules: { rule1: 'error' } }, - { rules: { rule2: 'error' } }, - ], - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule: 'error' }, - }), - ).toEqual([ - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config__extension-1', - rules: { rule1: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule2: 'error' }, - }, - { - files: ['common-file'], - ignores: ['common-ignored'], - name: 'my-config', - rules: { rule: 'error' }, - }, - ]); - }); -}); diff --git a/typings/eslint-plugin-eslint-plugin.d.ts b/typings/eslint-plugin-eslint-plugin.d.ts index 9b038cb9a949..a0c843fa1aa4 100644 --- a/typings/eslint-plugin-eslint-plugin.d.ts +++ b/typings/eslint-plugin-eslint-plugin.d.ts @@ -1,17 +1,14 @@ declare module 'eslint-plugin-eslint-plugin' { - import type { - ClassicConfig, - Linter, - } from '@typescript-eslint/utils/ts-eslint'; + import type { FlatConfig, Linter } from '@typescript-eslint/utils/ts-eslint'; declare const exprt: { configs: { - all: ClassicConfig.Config; - recommended: ClassicConfig.Config; - rules: ClassicConfig.Config; - 'rules-recommended': ClassicConfig.Config; - tests: ClassicConfig.Config; - 'tests-recommended': ClassicConfig.Config; + 'flat/all': FlatConfig.Config; + 'flat/recommended': FlatConfig.Config; + 'flat/rules': FlatConfig.Config; + 'flat/rules-recommended': FlatConfig.Config; + 'flat/tests': FlatConfig.Config; + 'flat/tests-recommended': FlatConfig.Config; }; rules: NonNullable; }; diff --git a/typings/eslint-plugin-jsx-a11y.d.ts b/typings/eslint-plugin-jsx-a11y.d.ts index d5fba291eb1f..3af810ca0290 100644 --- a/typings/eslint-plugin-jsx-a11y.d.ts +++ b/typings/eslint-plugin-jsx-a11y.d.ts @@ -1,13 +1,10 @@ declare module 'eslint-plugin-jsx-a11y' { - import type { - ClassicConfig, - Linter, - } from '@typescript-eslint/utils/ts-eslint'; + import type { FlatConfig, Linter } from '@typescript-eslint/utils/ts-eslint'; declare const exprt: { - configs: { - recommended: ClassicConfig.Config; - strict: ClassicConfig.Config; + flatConfigs: { + recommended: FlatConfig.Config; + strict: FlatConfig.Config; }; rules: NonNullable; }; diff --git a/typings/eslint-plugin-react.d.ts b/typings/eslint-plugin-react.d.ts index 0c95dd1ada07..5aa3c23e93ef 100644 --- a/typings/eslint-plugin-react.d.ts +++ b/typings/eslint-plugin-react.d.ts @@ -1,14 +1,13 @@ declare module 'eslint-plugin-react' { - import type { - ClassicConfig, - Linter, - } from '@typescript-eslint/utils/ts-eslint'; + import type { FlatConfig, Linter } from '@typescript-eslint/utils/ts-eslint'; declare const exprt: { configs: { - all: ClassicConfig.Config; - 'jsx-runtime': ClassicConfig.Config; - recommended: ClassicConfig.Config; + flat: { + all: FlatConfig.Config; + 'jsx-runtime': FlatConfig.Config; + recommended: FlatConfig.Config; + }; }; rules: NonNullable; }; diff --git a/yarn.lock b/yarn.lock index e9340a82c391..8b1c52533826 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5740,6 +5740,7 @@ __metadata: "@typescript-eslint/utils": 8.14.0 natural-compare: ^1.4.0 prettier: ^3.2.5 + typescript: "*" languageName: unknown linkType: soft @@ -5888,12 +5889,12 @@ __metadata: eslint: ^9.13.0 eslint-plugin-eslint-comments: ^3.2.0 eslint-plugin-eslint-plugin: ^6.2.0 - eslint-plugin-import: ^2.29.1 + eslint-plugin-import: ^2.31.0 eslint-plugin-jest: ^27.9.0 eslint-plugin-jsdoc: ^47.0.2 - eslint-plugin-jsx-a11y: ^6.8.0 + eslint-plugin-jsx-a11y: ^6.10.2 eslint-plugin-perfectionist: ^3.8.0 - eslint-plugin-react: ^7.34.1 + eslint-plugin-react: ^7.37.2 eslint-plugin-react-hooks: ^4.6.0 eslint-plugin-regexp: ^2.6.0 eslint-plugin-sonarjs: ^1.0.4 @@ -6613,16 +6614,14 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:~5.1.3": - version: 5.1.3 - resolution: "aria-query@npm:5.1.3" - dependencies: - deep-equal: ^2.0.5 - checksum: 929ff95f02857b650fb4cbcd2f41072eee2f46159a6605ea03bf63aa572e35ffdff43d69e815ddc462e16e07de8faba3978afc2813650b4448ee18c9895d982b +"aria-query@npm:^5.3.2": + version: 5.3.2 + resolution: "aria-query@npm:5.3.2" + checksum: d971175c85c10df0f6d14adfe6f1292409196114ab3c62f238e208b53103686f46cc70695a4f775b73bc65f6a09b6a092fd963c4f3a5a7d690c8fc5094925717 languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1": +"array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" dependencies: @@ -8703,32 +8702,6 @@ __metadata: languageName: node linkType: hard -"deep-equal@npm:^2.0.5": - version: 2.2.3 - resolution: "deep-equal@npm:2.2.3" - dependencies: - array-buffer-byte-length: ^1.0.0 - call-bind: ^1.0.5 - es-get-iterator: ^1.1.3 - get-intrinsic: ^1.2.2 - is-arguments: ^1.1.1 - is-array-buffer: ^3.0.2 - is-date-object: ^1.0.5 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - isarray: ^2.0.5 - object-is: ^1.1.5 - object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.5.1 - side-channel: ^1.0.4 - which-boxed-primitive: ^1.0.2 - which-collection: ^1.0.1 - which-typed-array: ^1.1.13 - checksum: ee8852f23e4d20a5626c13b02f415ba443a1b30b4b3d39eaf366d59c4a85e6545d7ec917db44d476a85ae5a86064f7e5f7af7479f38f113995ba869f3a1ddc53 - languageName: node - linkType: hard - "deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" @@ -9374,26 +9347,9 @@ __metadata: languageName: node linkType: hard -"es-get-iterator@npm:^1.1.3": - version: 1.1.3 - resolution: "es-get-iterator@npm:1.1.3" - dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - has-symbols: ^1.0.3 - is-arguments: ^1.1.1 - is-map: ^2.0.2 - is-set: ^2.0.2 - is-string: ^1.0.7 - isarray: ^2.0.5 - stop-iteration-iterator: ^1.0.0 - checksum: 8fa118da42667a01a7c7529f8a8cca514feeff243feec1ce0bb73baaa3514560bd09d2b3438873cf8a5aaec5d52da248131de153b28e2638a061b6e4df13267d - languageName: node - linkType: hard - -"es-iterator-helpers@npm:^1.0.19": - version: 1.0.19 - resolution: "es-iterator-helpers@npm:1.0.19" +"es-iterator-helpers@npm:^1.1.0": + version: 1.2.0 + resolution: "es-iterator-helpers@npm:1.2.0" dependencies: call-bind: ^1.0.7 define-properties: ^1.2.1 @@ -9402,14 +9358,15 @@ __metadata: es-set-tostringtag: ^2.0.3 function-bind: ^1.1.2 get-intrinsic: ^1.2.4 - globalthis: ^1.0.3 + globalthis: ^1.0.4 + gopd: ^1.0.1 has-property-descriptors: ^1.0.2 has-proto: ^1.0.3 has-symbols: ^1.0.3 internal-slot: ^1.0.7 - iterator.prototype: ^1.1.2 + iterator.prototype: ^1.1.3 safe-array-concat: ^1.1.2 - checksum: 7ae112b88359fbaf4b9d7d1d1358ae57c5138768c57ba3a8fb930393662653b0512bfd7917c15890d1471577fb012fee8b73b4465e59b331739e6ee94f961683 + checksum: c5f5ff10d57f956539581aca7a2d8726c5a8a3e49e6285700d74dcd8b64c7a337b9ab5e81b459b079dac745d2fe02e4f6b80a842e3df45d9cfe3f12325fda8c0 languageName: node linkType: hard @@ -9719,7 +9676,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.29.1": +"eslint-plugin-import@npm:^2.31.0": version: 2.31.0 resolution: "eslint-plugin-import@npm:2.31.0" dependencies: @@ -9785,11 +9742,11 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.8.0": - version: 6.10.0 - resolution: "eslint-plugin-jsx-a11y@npm:6.10.0" +"eslint-plugin-jsx-a11y@npm:^6.10.2": + version: 6.10.2 + resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" dependencies: - aria-query: ~5.1.3 + aria-query: ^5.3.2 array-includes: ^3.1.8 array.prototype.flatmap: ^1.3.2 ast-types-flow: ^0.0.8 @@ -9797,17 +9754,16 @@ __metadata: axobject-query: ^4.1.0 damerau-levenshtein: ^1.0.8 emoji-regex: ^9.2.2 - es-iterator-helpers: ^1.0.19 hasown: ^2.0.2 jsx-ast-utils: ^3.3.5 language-tags: ^1.0.9 minimatch: ^3.1.2 object.fromentries: ^2.0.8 safe-regex-test: ^1.0.3 - string.prototype.includes: ^2.0.0 + string.prototype.includes: ^2.0.1 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - checksum: 1009deca12ddbe3624586bc5fc3534ca98d00a5841a2563cb6abd9339b984f0a99075dc2a703a517f4087eb84d659c87e60beda17645883de2ba1d86f2b20c96 + checksum: 0cc861398fa26ada61ed5703eef5b335495fcb96253263dcd5e399488ff019a2636372021baacc040e3560d1a34bfcd5d5ad9f1754f44cd0509c956f7df94050 languageName: node linkType: hard @@ -9847,16 +9803,16 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:^7.34.1": - version: 7.37.1 - resolution: "eslint-plugin-react@npm:7.37.1" +"eslint-plugin-react@npm:^7.37.2": + version: 7.37.2 + resolution: "eslint-plugin-react@npm:7.37.2" dependencies: array-includes: ^3.1.8 array.prototype.findlast: ^1.2.5 array.prototype.flatmap: ^1.3.2 array.prototype.tosorted: ^1.1.4 doctrine: ^2.1.0 - es-iterator-helpers: ^1.0.19 + es-iterator-helpers: ^1.1.0 estraverse: ^5.3.0 hasown: ^2.0.2 jsx-ast-utils: ^2.4.1 || ^3.0.0 @@ -9871,7 +9827,7 @@ __metadata: string.prototype.repeat: ^1.0.0 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 22d1bdf0dd4cdbf8c57ce563c58d43c5f5e1da0b08d27d0a69d7126d9e8afcb74a5befae97dab4019b4c6029ae617b6a0af1709cb9e0439d5757b01b392d2ca7 + checksum: 7f5203afee7fbe3702b27fdd2b9a3c0ccbbb47d0672f58311b9d8a08dea819c9da4a87c15e8bd508f2562f327a9d29ee8bd9cd189bf758d8dc903de5648b0bfa languageName: node linkType: hard @@ -10901,7 +10857,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -11149,6 +11105,16 @@ __metadata: languageName: node linkType: hard +"globalthis@npm:^1.0.4": + version: 1.0.4 + resolution: "globalthis@npm:1.0.4" + dependencies: + define-properties: ^1.2.1 + gopd: ^1.0.1 + checksum: 39ad667ad9f01476474633a1834a70842041f70a55571e8dcef5fb957980a92da5022db5430fca8aecc5d47704ae30618c0bc877a579c70710c904e9ef06108a + languageName: node + linkType: hard + "globby@npm:^11.0.1, globby@npm:^11.0.4, globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" @@ -12023,7 +11989,7 @@ __metadata: languageName: node linkType: hard -"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7": +"internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" dependencies: @@ -12088,17 +12054,7 @@ __metadata: languageName: node linkType: hard -"is-arguments@npm:^1.1.1": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 7f02700ec2171b691ef3e4d0e3e6c0ba408e8434368504bb593d0d7c891c0dbfda6d19d30808b904a6cb1929bca648c061ba438c39f296c2a8ca083229c49f27 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": +"is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" dependencies: @@ -12324,7 +12280,7 @@ __metadata: languageName: node linkType: hard -"is-map@npm:^2.0.1, is-map@npm:^2.0.2": +"is-map@npm:^2.0.1": version: 2.0.3 resolution: "is-map@npm:2.0.3" checksum: e6ce5f6380f32b141b3153e6ba9074892bbbbd655e92e7ba5ff195239777e767a976dcd4e22f864accaf30e53ebf961ab1995424aef91af68788f0591b7396cc @@ -12466,7 +12422,7 @@ __metadata: languageName: node linkType: hard -"is-set@npm:^2.0.1, is-set@npm:^2.0.2": +"is-set@npm:^2.0.1": version: 2.0.3 resolution: "is-set@npm:2.0.3" checksum: 36e3f8c44bdbe9496c9689762cc4110f6a6a12b767c5d74c0398176aa2678d4467e3bf07595556f2dba897751bde1422480212b97d973c7b08a343100b0c0dfe @@ -12679,16 +12635,16 @@ __metadata: languageName: node linkType: hard -"iterator.prototype@npm:^1.1.2": - version: 1.1.2 - resolution: "iterator.prototype@npm:1.1.2" +"iterator.prototype@npm:^1.1.3": + version: 1.1.3 + resolution: "iterator.prototype@npm:1.1.3" dependencies: define-properties: ^1.2.1 get-intrinsic: ^1.2.1 has-symbols: ^1.0.3 reflect.getprototypeof: ^1.0.4 set-function-name: ^2.0.1 - checksum: d8a507e2ccdc2ce762e8a1d3f4438c5669160ac72b88b648e59a688eec6bc4e64b22338e74000518418d9e693faf2a092d2af21b9ec7dbf7763b037a54701168 + checksum: 7d2a1f8bcbba7b76f72e956faaf7b25405f4de54430c9d099992e6fb9d571717c3044604e8cdfb8e624cb881337d648030ee8b1541d544af8b338835e3f47ebe languageName: node linkType: hard @@ -15562,16 +15518,6 @@ __metadata: languageName: node linkType: hard -"object-is@npm:^1.1.5": - version: 1.1.6 - resolution: "object-is@npm:1.1.6" - dependencies: - call-bind: ^1.0.7 - define-properties: ^1.2.1 - checksum: 3ea22759967e6f2380a2cbbd0f737b42dc9ddb2dfefdb159a1b927fea57335e1b058b564bfa94417db8ad58cddab33621a035de6f5e5ad56d89f2dd03e66c6a1 - languageName: node - linkType: hard - "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -17301,7 +17247,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2": +"regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: @@ -18574,15 +18520,6 @@ __metadata: languageName: node linkType: hard -"stop-iteration-iterator@npm:^1.0.0": - version: 1.0.0 - resolution: "stop-iteration-iterator@npm:1.0.0" - dependencies: - internal-slot: ^1.0.4 - checksum: d04173690b2efa40e24ab70e5e51a3ff31d56d699550cfad084104ab3381390daccb36652b25755e420245f3b0737de66c1879eaa2a8d4fc0a78f9bf892fcb42 - languageName: node - linkType: hard - "string-argv@npm:~0.3.1, string-argv@npm:~0.3.2": version: 0.3.2 resolution: "string-argv@npm:0.3.2" @@ -18633,13 +18570,14 @@ __metadata: languageName: node linkType: hard -"string.prototype.includes@npm:^2.0.0": - version: 2.0.0 - resolution: "string.prototype.includes@npm:2.0.0" +"string.prototype.includes@npm:^2.0.1": + version: 2.0.1 + resolution: "string.prototype.includes@npm:2.0.1" dependencies: - define-properties: ^1.1.3 - es-abstract: ^1.17.5 - checksum: cf413e7f603b0414b65fdf1e7e3670ba85fd992b31c7eadfbdd9a484b86d265f0260431e7558cdb44a318dcadd1da8442b7bb8193b9ddd0aea3c376d2a559859 + call-bind: ^1.0.7 + define-properties: ^1.2.1 + es-abstract: ^1.23.3 + checksum: ed4b7058b092f30d41c4df1e3e805eeea92479d2c7a886aa30f42ae32fde8924a10cc99cccc99c29b8e18c48216608a0fe6bf887f8b4aadf9559096a758f313a languageName: node linkType: hard @@ -20387,7 +20325,7 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.9": +"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15, which-typed-array@npm:^1.1.9": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy