diff --git a/packages/eslint/src/generators/init/global-eslint-config.ts b/packages/eslint/src/generators/init/global-eslint-config.ts index 5b72b6d31d4e8f..211569817acb7b 100644 --- a/packages/eslint/src/generators/init/global-eslint-config.ts +++ b/packages/eslint/src/generators/init/global-eslint-config.ts @@ -122,6 +122,7 @@ export const getGlobalFlatEslintConfiguration = ( content = addBlockToFlatConfigExport( content, generateFlatOverride({ + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], rules: {}, }) ); diff --git a/packages/eslint/src/generators/lint-project/lint-project.spec.ts b/packages/eslint/src/generators/lint-project/lint-project.spec.ts index 4dcf1ee658151d..91151c50e09cd5 100644 --- a/packages/eslint/src/generators/lint-project/lint-project.spec.ts +++ b/packages/eslint/src/generators/lint-project/lint-project.spec.ts @@ -78,6 +78,7 @@ describe('@nx/eslint:lint-project', () => { }, }, { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], // Override or add rules here rules: {}, }, diff --git a/packages/eslint/src/generators/lint-project/lint-project.ts b/packages/eslint/src/generators/lint-project/lint-project.ts index 8f2a9da791ed09..d8844345a44c8e 100644 --- a/packages/eslint/src/generators/lint-project/lint-project.ts +++ b/packages/eslint/src/generators/lint-project/lint-project.ts @@ -55,7 +55,6 @@ interface LintProjectOptions { */ addExplicitTargets?: boolean; addPackageJsonDependencyChecks?: boolean; - skipExtendedBaseConfig?: boolean; } export function lintProjectGenerator(tree: Tree, options: LintProjectOptions) { @@ -194,10 +193,7 @@ function createEsLintConfiguration( rootProject: boolean ) { // we are only extending root for non-standalone projects or their complementary e2e apps - const extendedRootConfig = - rootProject || options.skipExtendedBaseConfig - ? undefined - : findEslintFile(tree); + const extendedRootConfig = rootProject ? undefined : findEslintFile(tree); const pathToRootConfig = extendedRootConfig ? `${offsetFromRoot(projectConfig.root)}${extendedRootConfig}` : undefined; diff --git a/packages/eslint/src/generators/utils/eslint-file.ts b/packages/eslint/src/generators/utils/eslint-file.ts index 88a07b195628b7..2db5e49f3f4694 100644 --- a/packages/eslint/src/generators/utils/eslint-file.ts +++ b/packages/eslint/src/generators/utils/eslint-file.ts @@ -319,7 +319,8 @@ export function addExtendsToLintConfig( plugin: | string | { name: string; needCompatFixup: boolean } - | Array + | Array, + insertAtTheEnd = false ): GeneratorCallback { if (useFlatConfig(tree)) { const pluginExtends: ts.SpreadElement[] = []; @@ -381,7 +382,7 @@ export function addExtendsToLintConfig( // start of the `extends` array for (const pluginExtend of pluginExtends.reverse()) { content = addBlockToFlatConfigExport(content, pluginExtend, { - insertAtTheEnd: false, + insertAtTheEnd, }); } tree.write(fileName, content); diff --git a/packages/eslint/src/generators/utils/flat-config/ast-utils.ts b/packages/eslint/src/generators/utils/flat-config/ast-utils.ts index 9a4d4dbc8f539e..94004e52bf3924 100644 --- a/packages/eslint/src/generators/utils/flat-config/ast-utils.ts +++ b/packages/eslint/src/generators/utils/flat-config/ast-utils.ts @@ -220,12 +220,12 @@ export function addImportToFlatConfig( ts.isObjectBindingPattern(node.declarationList.declarations[0].name) && ts.isCallExpression(node.declarationList.declarations[0].initializer) && node.declarationList.declarations[0].initializer.expression.getText() === - 'require' && + 'require' && ts.isStringLiteral( node.declarationList.declarations[0].initializer.arguments[0] ) && node.declarationList.declarations[0].initializer.arguments[0].text === - imp + imp ) { return node.declarationList.declarations[0].name.elements; } @@ -274,12 +274,12 @@ export function addImportToFlatConfig( node.declarationList.declarations[0].name.getText() === variable && ts.isCallExpression(node.declarationList.declarations[0].initializer) && node.declarationList.declarations[0].initializer.expression.getText() === - 'require' && + 'require' && ts.isStringLiteral( node.declarationList.declarations[0].initializer.arguments[0] ) && node.declarationList.declarations[0].initializer.arguments[0].text === - imp + imp ) { return true; } @@ -295,10 +295,10 @@ export function addImportToFlatConfig( typeof variable === 'string' ? variable : ts.factory.createObjectBindingPattern( - variable.map((v) => - ts.factory.createBindingElement(undefined, undefined, v) - ) - ), + variable.map((v) => + ts.factory.createBindingElement(undefined, undefined, v) + ) + ), imp ); const insert = printer.printNode( @@ -393,7 +393,7 @@ export function removePlugin( node.declarationList.declarations[0].initializer.arguments[0] ) && node.declarationList.declarations[0].initializer.arguments[0].text === - pluginImport + pluginImport ) { changes.push({ type: ChangeType.Delete, @@ -470,7 +470,7 @@ export function removePlugin( ) as ts.PropertyAssignment; const removeComma = pluginsObj.properties.indexOf(plugin) < - pluginsObj.properties.length - 1 || + pluginsObj.properties.length - 1 || pluginsObj.properties.hasTrailingComma; changes.push({ type: ChangeType.Delete, @@ -534,7 +534,7 @@ export function removeCompatExtends( const callExp = node.expression.expression.expression; if ( ((callExp.expression.getText() === 'compat.config' && - callExp.arguments[0].getText().includes('extends')) || + callExp.arguments[0].getText().includes('extends')) || callExp.expression.getText() === 'compat.extends') && compatExtends.some((ext) => callExp.arguments[0].getText().includes(ext) @@ -877,8 +877,8 @@ export function generateFlatOverride( [ ts.factory.createStringLiteral( override['languageOptions']?.['parserOptions']?.parser ?? - override['languageOptions']?.parser ?? - override.parser + override['languageOptions']?.parser ?? + override.parser ), ] ) diff --git a/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap index e51ca909a54ee1..798781bfef4297 100644 --- a/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/nuxt/src/generators/application/__snapshots__/application.spec.ts.snap @@ -20,16 +20,14 @@ exports[`app generated files content - as-provided - my-app general application exports[`app generated files content - as-provided - my-app general application should configure eslint correctly (eslintrc) 1`] = ` "{ + "extends": ["@nuxt/eslint-config", "../.eslintrc.json"], "ignorePatterns": ["!**/*", ".nuxt/**", ".output/**", "node_modules"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx", "*.vue"], - "rules": { - "vue/multi-word-component-names": "off" - } + "rules": {} } - ], - "extends": ["@nuxt/eslint-config"] + ] } " `; @@ -37,6 +35,7 @@ exports[`app generated files content - as-provided - my-app general application exports[`app generated files content - as-provided - my-app general application should configure eslint correctly (flat config) 1`] = ` "const { FlatCompat } = require('@eslint/eslintrc'); const js = require('@eslint/js'); +const baseConfig = require('../eslint.config.js'); const compat = new FlatCompat({ baseDirectory: __dirname, @@ -44,9 +43,18 @@ const compat = new FlatCompat({ }); module.exports = [ + ...baseConfig, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'], + // Override or add rules here + rules: {}, + }, ...compat.extends('@nuxt/eslint-config'), { - rules: { 'vue/multi-word-component-names': 'off' }, + files: ['**/*.vue'], + languageOptions: { + parserOptions: { parser: require('@typescript-eslint/parser') }, + }, }, { ignores: ['.nuxt/**', '.output/**', 'node_modules'] }, ]; @@ -379,16 +387,14 @@ exports[`app generated files content - as-provided - myApp general application s exports[`app generated files content - as-provided - myApp general application should configure eslint correctly (eslintrc) 1`] = ` "{ + "extends": ["@nuxt/eslint-config", "../.eslintrc.json"], "ignorePatterns": ["!**/*", ".nuxt/**", ".output/**", "node_modules"], "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx", "*.vue"], - "rules": { - "vue/multi-word-component-names": "off" - } + "rules": {} } - ], - "extends": ["@nuxt/eslint-config"] + ] } " `; @@ -396,6 +402,7 @@ exports[`app generated files content - as-provided - myApp general application s exports[`app generated files content - as-provided - myApp general application should configure eslint correctly (flat config) 1`] = ` "const { FlatCompat } = require('@eslint/eslintrc'); const js = require('@eslint/js'); +const baseConfig = require('../eslint.config.js'); const compat = new FlatCompat({ baseDirectory: __dirname, @@ -403,9 +410,18 @@ const compat = new FlatCompat({ }); module.exports = [ + ...baseConfig, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'], + // Override or add rules here + rules: {}, + }, ...compat.extends('@nuxt/eslint-config'), { - rules: { 'vue/multi-word-component-names': 'off' }, + files: ['**/*.vue'], + languageOptions: { + parserOptions: { parser: require('@typescript-eslint/parser') }, + }, }, { ignores: ['.nuxt/**', '.output/**', 'node_modules'] }, ]; diff --git a/packages/nuxt/src/utils/add-linting.ts b/packages/nuxt/src/utils/add-linting.ts index 800394ac0ebac0..988ac5fd1e8d1b 100644 --- a/packages/nuxt/src/utils/add-linting.ts +++ b/packages/nuxt/src/utils/add-linting.ts @@ -19,6 +19,7 @@ import { import { nuxtEslintConfigVersion } from './versions'; import { useFlatConfig } from '@nx/eslint/src/utils/flat-config'; +// TODO(colum): Look into the recommended set up using `withNuxt` inside eslint.config.mjs. https://eslint.nuxt.com/packages/config export async function addLinting( host: Tree, options: { @@ -39,18 +40,33 @@ export async function addLinting( skipFormat: true, rootProject: options.rootProject, addPlugin: true, - // Merging base flat config with `@nuxt/eslint-config` results in merge error due to `@typescript-eslint` being registered twice. - skipExtendedBaseConfig: true, }); tasks.push(lintTask); - editEslintConfigFiles(host, options.projectRoot); - if (isEslintConfigSupported(host, options.projectRoot)) { - const addExtendsTask = addExtendsToLintConfig(host, options.projectRoot, [ - '@nuxt/eslint-config', - ]); + editEslintConfigFiles(host, options.projectRoot); + + const addExtendsTask = addExtendsToLintConfig( + host, + options.projectRoot, + ['@nuxt/eslint-config'], + true + ); tasks.push(addExtendsTask); + + if (useFlatConfig(host)) { + addOverrideToLintConfig( + host, + options.projectRoot, + { + files: ['**/*.vue'], + languageOptions: { + parserOptions: { parser: '@typescript-eslint/parser' }, + }, + } as unknown // languageOptions is not in eslintrc format but for flat config + ); + } + addIgnoresToLintConfig(host, options.projectRoot, [ '.nuxt/**', '.output/**', @@ -89,49 +105,30 @@ function editEslintConfigFiles(tree: Tree, projectRoot: string) { o.files = [o.files, '*.vue']; } }; - - if (isEslintConfigSupported(tree, projectRoot)) { - if (useFlatConfig(tree)) { - addOverrideToLintConfig( - tree, - projectRoot, - { - rules: { 'vue/multi-word-component-names': 'off' }, - }, - { insertAtTheEnd: false } - ); - } else { - if ( - lintConfigHasOverride( - tree, - projectRoot, - (o) => o.parserOptions && !hasVueFiles(o), - true - ) - ) { - updateOverrideInLintConfig( - tree, - projectRoot, - (o) => !!o.parserOptions, - (o) => { - addVueFiles(o); - return o; - } - ); - } else { - replaceOverridesInLintConfig(tree, projectRoot, [ - { - files: ['*.ts', '*.tsx', '*.js', '*.jsx', '*.vue'], - rules: { 'vue/multi-word-component-names': 'off' }, - }, - ]); + if ( + lintConfigHasOverride( + tree, + projectRoot, + (o) => o.parserOptions && !hasVueFiles(o), + true + ) + ) { + updateOverrideInLintConfig( + tree, + projectRoot, + (o) => !!o.parserOptions, + (o) => { + addVueFiles(o); + return o; } - } - } - - // Edit root config too - if (!isEslintConfigSupported(tree)) { - return; + ); + } else { + replaceOverridesInLintConfig(tree, projectRoot, [ + { + files: ['*.ts', '*.tsx', '*.js', '*.jsx', '*.vue'], + rules: {}, + }, + ]); } if ( diff --git a/packages/nuxt/src/utils/versions.ts b/packages/nuxt/src/utils/versions.ts index 1142ef0d39a37e..6244e7e77df2e8 100644 --- a/packages/nuxt/src/utils/versions.ts +++ b/packages/nuxt/src/utils/versions.ts @@ -7,4 +7,4 @@ export const nuxtDevtoolsVersion = '1.0.0'; export const nuxtUiTemplatesVersion = '^1.3.1'; // linting deps -export const nuxtEslintConfigVersion = '~0.3.6'; +export const nuxtEslintConfigVersion = '~0.5.6'; diff --git a/packages/vue/src/generators/library/__snapshots__/library.spec.ts.snap b/packages/vue/src/generators/library/__snapshots__/library.spec.ts.snap index 3c4fc3848bf76c..a1939cf565e9e7 100644 --- a/packages/vue/src/generators/library/__snapshots__/library.spec.ts.snap +++ b/packages/vue/src/generators/library/__snapshots__/library.spec.ts.snap @@ -293,6 +293,7 @@ module.exports = [ }, }, { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'], rules: { 'vue/multi-word-component-names': 'off' }, }, ]; diff --git a/packages/vue/src/utils/add-linting.ts b/packages/vue/src/utils/add-linting.ts index 100aab352b2345..7b3eb3a9edcc3a 100644 --- a/packages/vue/src/utils/add-linting.ts +++ b/packages/vue/src/utils/add-linting.ts @@ -125,6 +125,7 @@ function editEslintConfigFiles(tree: Tree, projectRoot: string) { ); // Add an empty rules object to users know how to add/override rules addOverrideToLintConfig(tree, projectRoot, { + files: ['*.ts', '*.tsx', '*.js', '*.jsx', '*.vue'], rules: { 'vue/multi-word-component-names': 'off' }, }); } else {