diff --git a/packages/eslint-config-next/index.js b/packages/eslint-config-next/index.js index 24a28c0c523b5..da560e059efcc 100644 --- a/packages/eslint-config-next/index.js +++ b/packages/eslint-config-next/index.js @@ -107,7 +107,13 @@ module.exports = { version: 'detect', }, 'import/parsers': { - [require.resolve('@typescript-eslint/parser')]: ['.ts', '.tsx', '.d.ts'], + [require.resolve('@typescript-eslint/parser')]: [ + '.ts', + '.mts', + '.cts', + '.tsx', + '.d.ts', + ], }, 'import/resolver': { [require.resolve('eslint-import-resolver-node')]: { diff --git a/packages/next/cli/next-lint.ts b/packages/next/cli/next-lint.ts index ca0d1e5246a02..83f0a53bb9dec 100755 --- a/packages/next/cli/next-lint.ts +++ b/packages/next/cli/next-lint.ts @@ -18,7 +18,16 @@ import { getProjectDir } from '../lib/get-project-dir' const eslintOptions = (args: arg.Spec, defaultCacheLocation: string) => ({ overrideConfigFile: args['--config'] || null, - extensions: args['--ext'] ?? ['.js', '.jsx', '.ts', '.tsx'], + extensions: args['--ext'] ?? [ + '.js', + '.mjs', + '.cjs', + '.jsx', + '.ts', + '.mts', + '.cts', + '.tsx', + ], resolvePluginsRelativeTo: args['--resolve-plugins-relative-to'] || null, rulePaths: args['--rulesdir'] ?? [], fix: args['--fix'] ?? false, diff --git a/test/integration/eslint/mjs-cjs-linting/.eslintrc.json b/test/integration/eslint/mjs-cjs-linting/.eslintrc.json new file mode 100644 index 0000000000000..abd5579b49c15 --- /dev/null +++ b/test/integration/eslint/mjs-cjs-linting/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": "next", + "root": true +} diff --git a/test/integration/eslint/mjs-cjs-linting/pages/bar.mjs b/test/integration/eslint/mjs-cjs-linting/pages/bar.mjs new file mode 100644 index 0000000000000..5358a886e2f8a --- /dev/null +++ b/test/integration/eslint/mjs-cjs-linting/pages/bar.mjs @@ -0,0 +1,10 @@ +export default class Bar { + render() { + return ( +
+

Hello title

+ +
+ ) + } +} diff --git a/test/integration/eslint/mjs-cjs-linting/pages/index.cjs b/test/integration/eslint/mjs-cjs-linting/pages/index.cjs new file mode 100644 index 0000000000000..8a7809113b54f --- /dev/null +++ b/test/integration/eslint/mjs-cjs-linting/pages/index.cjs @@ -0,0 +1,10 @@ +export default class Home { + render() { + return ( +
+

Hello title

+ +
+ ) + } +} diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index 2097d0b43bb7b..5c03a46ec14b5 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -34,6 +34,7 @@ const dirNoConfig = join(__dirname, '../no-config') const dirEslintCache = join(__dirname, '../eslint-cache') const dirEslintCacheCustomDir = join(__dirname, '../eslint-cache-custom-dir') const dirFileLinting = join(__dirname, '../file-linting') +const mjsCjsLinting = join(__dirname, '../mjs-cjs-linting') describe('ESLint', () => { describe('Next Build', () => { @@ -767,5 +768,27 @@ describe('ESLint', () => { `Cannot write to output file path, it is a directory: ${filePath}` ) }) + + test('lint files with cjs and mjs file extension', async () => { + const { stdout, stderr } = await nextLint(mjsCjsLinting, [], { + stdout: true, + stderr: true, + }) + + const output = stdout + stderr + + expect(output).toContain('pages/bar.mjs') + expect(output).toContain( + 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' + ) + expect(output).toContain( + 'Do not use `` element. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' + ) + + expect(output).toContain('pages/index.cjs') + expect(output).toContain( + 'Synchronous scripts should not be used. See: https://nextjs.org/docs/messages/no-sync-scripts' + ) + }) }) })