diff --git a/packages/linter/src/generators/lint-project/lint-project.spec.ts b/packages/linter/src/generators/lint-project/lint-project.spec.ts index 0aa0aded2d58f..d384900cacbd5 100644 --- a/packages/linter/src/generators/lint-project/lint-project.spec.ts +++ b/packages/linter/src/generators/lint-project/lint-project.spec.ts @@ -1,7 +1,9 @@ import { addProjectConfiguration, readProjectConfiguration, + updateJson, Tree, + readJson, } from '@nx/devkit'; import { Linter } from '../utils/linter'; @@ -175,4 +177,48 @@ describe('@nx/linter:lint-project', () => { " `); }); + + it('should update nx.json to enable source analysis when using npm.json preset', async () => { + updateJson(tree, 'nx.json', (json) => { + // npm preset disables source analysis + json.extends = 'nx/presets/npm.json'; + return json; + }); + + await lintProjectGenerator(tree, { + ...defaultOptions, + linter: Linter.EsLint, + eslintFilePatterns: ['libs/buildable-lib/**/*.ts'], + project: 'buildable-lib', + setParserOptionsProject: false, + }); + + expect(readJson(tree, 'nx.json').pluginsConfig['@nx/js']).toEqual({ + analyzeSourceFiles: true, + }); + }); + + it('should update nx.json to enable source analysis when it is disabled', async () => { + updateJson(tree, 'nx.json', (json) => { + // npm preset disables source analysis + json.pluginsConfig = { + '@nx/js': { + analyzeSourceFiles: false, + }, + }; + return json; + }); + + await lintProjectGenerator(tree, { + ...defaultOptions, + linter: Linter.EsLint, + eslintFilePatterns: ['libs/buildable-lib/**/*.ts'], + project: 'buildable-lib', + setParserOptionsProject: false, + }); + + expect(readJson(tree, 'nx.json').pluginsConfig['@nx/js']).toEqual({ + analyzeSourceFiles: true, + }); + }); }); diff --git a/packages/linter/src/generators/lint-project/lint-project.ts b/packages/linter/src/generators/lint-project/lint-project.ts index 0cc2012f6b068..c46646159f84e 100644 --- a/packages/linter/src/generators/lint-project/lint-project.ts +++ b/packages/linter/src/generators/lint-project/lint-project.ts @@ -1,8 +1,14 @@ -import type { ProjectConfiguration, Tree } from '@nx/devkit'; +import type { + NxJsonConfiguration, + ProjectConfiguration, + Tree, +} from '@nx/devkit'; import { formatFiles, offsetFromRoot, + readJson, readProjectConfiguration, + updateJson, updateProjectConfiguration, writeJson, } from '@nx/devkit'; @@ -108,6 +114,19 @@ export async function lintProjectGenerator( ); } + // Buildable libs need source analysis enabled for linting `package.json`. + if ( + isBuildableLibraryProject(projectConfig) && + !isJsAnalyzeSourceFilesEnabled(tree) + ) { + updateJson(tree, 'nx.json', (json) => { + json.pluginsConfig ??= {}; + json.pluginsConfig['@nx/js'] ??= {}; + json.pluginsConfig['@nx/js'].analyzeSourceFiles = true; + return json; + }); + } + updateProjectConfiguration(tree, options.project, projectConfig); if (!options.skipFormat) { @@ -163,19 +182,18 @@ function createEsLintConfiguration( files: ['*.js', '*.jsx'], rules: {}, }, - ...(isBuildableLibraryProject(projectConfig) - ? [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': 'error', - } as Linter.RulesRecord, - }, - ] - : []), ]; + if (isBuildableLibraryProject(projectConfig)) { + overrides.push({ + files: ['*.json'], + parser: 'jsonc-eslint-parser', + rules: { + '@nx/dependency-checks': 'error', + }, + }); + } + if (useFlatConfig(tree)) { const isCompatNeeded = addDependencyChecks; const nodes = []; @@ -204,6 +222,18 @@ function createEsLintConfiguration( } } +function isJsAnalyzeSourceFilesEnabled(tree: Tree): boolean { + const nxJson = readJson(tree, 'nx.json'); + const jsPluginConfig = nxJson.pluginsConfig?.['@nx/js'] as { + analyzeSourceFiles?: boolean; + }; + + return ( + jsPluginConfig?.analyzeSourceFiles ?? + nxJson.extends !== 'nx/presets/npm.json' + ); +} + function isBuildableLibraryProject( projectConfig: ProjectConfiguration ): boolean {