diff --git a/packages/wxt/e2e/tests/__snapshots__/auto-imports.test.ts.snap b/packages/wxt/e2e/tests/__snapshots__/auto-imports.test.ts.snap index abd8c412e..177f1d7ef 100644 --- a/packages/wxt/e2e/tests/__snapshots__/auto-imports.test.ts.snap +++ b/packages/wxt/e2e/tests/__snapshots__/auto-imports.test.ts.snap @@ -119,6 +119,15 @@ export default { " `; +exports[`Auto Imports > eslint config > "enabled: 9" should output a flat config file compatible with ESLint >=9 2`] = ` +".wxt/eslint-auto-imports.d.mts +---------------------------------------- +import type { ConfigObject } from "@eslint/core"; +declare const config: ConfigObject; +export default config; +" +`; + exports[`Auto Imports > eslint config > "enabled: auto" should output a JSON config file compatible with ESLint of package.json 1`] = ` ".wxt/eslint-auto-imports.mjs ---------------------------------------- @@ -182,6 +191,15 @@ export default { " `; +exports[`Auto Imports > eslint config > "enabled: auto" should output a JSON config file compatible with ESLint of package.json 2`] = ` +".wxt/eslint-auto-imports.d.mts +---------------------------------------- +import type { ConfigObject } from "@eslint/core"; +declare const config: ConfigObject; +export default config; +" +`; + exports[`Auto Imports > eslint config > "enabled: true" should output a JSON config file compatible with ESLint of package.json 1`] = ` ".wxt/eslint-auto-imports.mjs ---------------------------------------- @@ -245,6 +263,15 @@ export default { " `; +exports[`Auto Imports > eslint config > "enabled: true" should output a JSON config file compatible with ESLint of package.json 2`] = ` +".wxt/eslint-auto-imports.d.mts +---------------------------------------- +import type { ConfigObject } from "@eslint/core"; +declare const config: ConfigObject; +export default config; +" +`; + exports[`Auto Imports > eslint config > should allow customizing the output 1`] = ` "example.json ---------------------------------------- @@ -307,3 +334,12 @@ export default { }; " `; + +exports[`Auto Imports > eslint config > should allow customizing the output 2`] = ` +"example.d.ts +---------------------------------------- +import type { ConfigObject } from "@eslint/core"; +declare const config: ConfigObject; +export default config; +" +`; diff --git a/packages/wxt/e2e/tests/auto-imports.test.ts b/packages/wxt/e2e/tests/auto-imports.test.ts index 2e4ad34ff..1c3c5b11c 100644 --- a/packages/wxt/e2e/tests/auto-imports.test.ts +++ b/packages/wxt/e2e/tests/auto-imports.test.ts @@ -235,6 +235,9 @@ describe('Auto Imports', () => { expect( await project.serializeFile('.wxt/eslint-auto-imports.mjs'), ).toMatchSnapshot(); + expect( + await project.serializeFile('.wxt/eslint-auto-imports.d.mts'), + ).toMatchSnapshot(); }, ); @@ -270,6 +273,9 @@ describe('Auto Imports', () => { expect( await project.serializeFile('.wxt/eslint-auto-imports.mjs'), ).toMatchSnapshot(); + expect( + await project.serializeFile('.wxt/eslint-auto-imports.d.mts'), + ).toMatchSnapshot(); }); it('"enabled: false" should NOT output an ESLint config file', async () => { @@ -307,6 +313,7 @@ describe('Auto Imports', () => { }); expect(await project.serializeFile('example.json')).toMatchSnapshot(); + expect(await project.serializeFile('example.d.ts')).toMatchSnapshot(); }); describe('Actual linting results', () => { diff --git a/packages/wxt/src/builtin-modules/unimport.ts b/packages/wxt/src/builtin-modules/unimport.ts index 8e9ec12d2..458cecf06 100644 --- a/packages/wxt/src/builtin-modules/unimport.ts +++ b/packages/wxt/src/builtin-modules/unimport.ts @@ -7,8 +7,9 @@ import type { WxtResolvedUnimportOptions, EslintConfigVersion, } from '../types'; -import { type Unimport, createUnimport, toExports } from 'unimport'; +import { createUnimport, toExports, type Unimport } from 'unimport'; import UnimportPlugin from 'unimport/unplugin'; +import { extname } from 'node:path'; export default defineWxtModule({ name: 'wxt:built-in:unimport', @@ -52,14 +53,13 @@ export default defineWxtModule({ if (!wxt.config.imports.eslintrc.enabled) return; - // Only generate ESLint config if that feature is enabled - entries.push( - await getEslintConfigEntry( - unimport, - wxt.config.imports.eslintrc.enabled, - wxt.config.imports, - ), + const eslintConfigEntries = await getEslintConfigEntry( + unimport, + wxt.config.imports.eslintrc.enabled, + wxt.config.imports, ); + + entries.push(...eslintConfigEntries); }); // Add vite plugin @@ -106,7 +106,7 @@ async function getEslintConfigEntry( unimport: Unimport, configVersion: EslintConfigVersion, options: WxtResolvedUnimportOptions, -): Promise { +): Promise { const globals = (await unimport.getImports()) .map((i) => i.as ?? i.name) .filter(Boolean) @@ -123,18 +123,20 @@ async function getEslintConfigEntry( export function getEslint8ConfigEntry( options: WxtResolvedUnimportOptions, globals: Record, -): WxtDirFileEntry { - return { - path: options.eslintrc.filePath, - text: JSON.stringify({ globals }, null, 2) + '\n', - }; +): WxtDirFileEntry[] { + return [ + { + path: options.eslintrc.filePath, + text: JSON.stringify({ globals }, null, 2) + '\n', + }, + ]; } export function getEslint9ConfigEntry( options: WxtResolvedUnimportOptions, globals: Record, -): WxtDirFileEntry { - return { +): WxtDirFileEntry[] { + const javaScriptFileEntry: WxtDirFileEntry = { path: options.eslintrc.filePath, text: `const globals = ${JSON.stringify(globals, null, 2)} @@ -148,4 +150,20 @@ export default { }; `, }; + + const ext = extname(options.eslintrc.filePath); + const declarationExt = + ext === '.mjs' ? '.d.mts' : ext === '.cjs' ? '.d.cts' : '.d.ts'; + const typeScriptFilePath = + options.eslintrc.filePath.slice(0, -ext.length) + declarationExt; + + const typeScriptFileEntry: WxtDirFileEntry = { + path: typeScriptFilePath, + text: `import type { ConfigObject } from "@eslint/core"; +declare const config: ConfigObject; +export default config; +`, + }; + + return [javaScriptFileEntry, typeScriptFileEntry]; }