diff --git a/packages/angular/src/generators/storybook-configuration/__snapshots__/storybook-configuration.spec.ts.snap b/packages/angular/src/generators/storybook-configuration/__snapshots__/storybook-configuration.spec.ts.snap index a297023349..33813fbffd 100644 --- a/packages/angular/src/generators/storybook-configuration/__snapshots__/storybook-configuration.spec.ts.snap +++ b/packages/angular/src/generators/storybook-configuration/__snapshots__/storybook-configuration.spec.ts.snap @@ -28,6 +28,7 @@ module.exports = { exports[`StorybookConfiguration generator should generate in the correct folder 1`] = ` Array [ + ".eslintignore", ".eslintrc.json", ".prettierrc", "apps/.gitignore", @@ -157,6 +158,7 @@ Array [ exports[`StorybookConfiguration generator should generate the right files 1`] = ` Array [ + ".eslintignore", ".eslintrc.json", ".prettierrc", "apps/.gitignore", diff --git a/packages/linter/migrations.json b/packages/linter/migrations.json index 78ca854082..4c6212884f 100644 --- a/packages/linter/migrations.json +++ b/packages/linter/migrations.json @@ -53,6 +53,12 @@ "version": "15.0.0-beta.0", "description": "Stop hashing eslint config files for build targets and dependent tasks", "factory": "./src/migrations/update-15-0-0/add-eslint-inputs" + }, + "add-eslint-ignore": { + "cli": "nx", + "version": "15.7.1-beta.0", + "description": "Add node_modules to root eslint ignore", + "factory": "./src/migrations/update-15-7-1/add-eslint-ignore" } }, "packageJsonUpdates": { diff --git a/packages/linter/src/generators/init/init.spec.ts b/packages/linter/src/generators/init/init.spec.ts index 8b6b84d1ef..e6579e584e 100644 --- a/packages/linter/src/generators/init/init.spec.ts +++ b/packages/linter/src/generators/init/init.spec.ts @@ -18,6 +18,10 @@ describe('@nrwl/linter:init', () => { }); expect(tree.read('.eslintrc.json', 'utf-8')).toMatchSnapshot(); + expect(tree.read('.eslintignore', 'utf-8')).toMatchInlineSnapshot(` + "node_modules + " + `); }); it('should add the root eslint config to the lint targetDefaults for lint', async () => { @@ -26,7 +30,11 @@ describe('@nrwl/linter:init', () => { }); expect(readJson(tree, 'nx.json').targetDefaults.lint).toEqual({ - inputs: ['default', '{workspaceRoot}/.eslintrc.json'], + inputs: [ + 'default', + '{workspaceRoot}/.eslintrc.json', + '{workspaceRoot}/.eslintignore', + ], }); }); diff --git a/packages/linter/src/generators/init/init.ts b/packages/linter/src/generators/init/init.ts index aae2a668b3..57c7bbbe04 100644 --- a/packages/linter/src/generators/init/init.ts +++ b/packages/linter/src/generators/init/init.ts @@ -42,6 +42,7 @@ function addTargetDefaults(tree: Tree) { nxJson.targetDefaults.lint.inputs ??= [ 'default', `{workspaceRoot}/.eslintrc.json`, + `{workspaceRoot}/.eslintignore`, ]; updateNxJson(tree, nxJson); } @@ -60,6 +61,7 @@ function initEsLint(tree: Tree, options: LinterInitOptions): GeneratorCallback { '.eslintrc.json', getGlobalEsLintConfiguration(options.unitTestRunner, options.rootProject) ); + tree.write('.eslintignore', 'node_modules\n'); addTargetDefaults(tree); if (tree.exists('.vscode/extensions.json')) { diff --git a/packages/linter/src/generators/utils/eslint-targets.ts b/packages/linter/src/generators/utils/eslint-targets.ts new file mode 100644 index 0000000000..9e27a4efde --- /dev/null +++ b/packages/linter/src/generators/utils/eslint-targets.ts @@ -0,0 +1,10 @@ +import { Tree } from '@nrwl/devkit'; +import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; + +export function getEslintTargets(tree: Tree) { + const eslintTargetNames = new Set(); + forEachExecutorOptions(tree, '@nrwl/linter:eslint', (_, __, target) => { + eslintTargetNames.add(target); + }); + return eslintTargetNames; +} diff --git a/packages/linter/src/migrations/update-15-0-0/add-eslint-inputs.ts b/packages/linter/src/migrations/update-15-0-0/add-eslint-inputs.ts index a7bb1d0497..06d265aeae 100644 --- a/packages/linter/src/migrations/update-15-0-0/add-eslint-inputs.ts +++ b/packages/linter/src/migrations/update-15-0-0/add-eslint-inputs.ts @@ -5,8 +5,8 @@ import { Tree, updateNxJson, } from '@nrwl/devkit'; -import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; import { eslintConfigFileWhitelist } from '../../generators/utils/eslint-file'; +import { getEslintTargets } from '../../generators/utils/eslint-targets'; export default async function addEslintInputs(tree: Tree) { const nxJson = readNxJson(tree); @@ -40,11 +40,3 @@ export default async function addEslintInputs(tree: Tree) { await formatFiles(tree); } - -function getEslintTargets(tree: Tree) { - const eslintTargetNames = new Set(); - forEachExecutorOptions(tree, '@nrwl/linter:eslint', (_, __, target) => { - eslintTargetNames.add(target); - }); - return eslintTargetNames; -} diff --git a/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.spec.ts b/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.spec.ts new file mode 100644 index 0000000000..e44fe1cd5d --- /dev/null +++ b/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.spec.ts @@ -0,0 +1,107 @@ +import { + addProjectConfiguration, + readJson, + readNxJson, + Tree, + updateNxJson, +} from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import addEslintIgnore from './add-eslint-ignore'; + +describe('15.7.1 migration (add-eslintignore)', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + + updateNxJson(tree, { + namedInputs: { + default: ['{projectRoot}/**/*', 'sharedGlobals'], + sharedGlobals: [], + }, + }); + + addProjectConfiguration(tree, 'proj', { + root: 'proj', + targets: { + lint: { + executor: '@nrwl/linter:eslint', + options: {}, + }, + lint2: { + executor: '@nrwl/linter:eslint', + options: {}, + }, + notTest: { + executor: 'nx:run-commands', + }, + }, + }); + }); + + it('should not add .eslintignore if eslint config does not exist', async () => { + await addEslintIgnore(tree); + expect(tree.exists('.eslintignore')).toBeFalsy(); + }); + + it('should add .eslintignore if it does not exist', async () => { + ensureGlobalConfig(tree); + + await addEslintIgnore(tree); + + expect(tree.exists('.eslintignore')).toBeTruthy(); + expect(tree.read('.eslintignore', 'utf-8')).toEqual('node_modules\n'); + }); + + it('should add node_modules if missing in .eslintignore', async () => { + ensureGlobalConfig(tree); + + const original = 'dist\ntmp\n'; + tree.write('.eslintignore', original); + + await addEslintIgnore(tree); + + expect(tree.read('.eslintignore', 'utf-8')).toEqual( + `node_modules\n${original}` + ); + }); + + it('should not add node_modules if already in .eslintignore', async () => { + ensureGlobalConfig(tree); + + const original = `dist\nnode_modules\ntmp\n`; + tree.write('.eslintignore', original); + + await addEslintIgnore(tree); + + expect(tree.read('.eslintignore', 'utf-8')).toEqual(original); + }); + + it('should add lint target', async () => { + ensureGlobalConfig(tree); + + await addEslintIgnore(tree); + + expect(tree.exists('.eslintignore')).toBeTruthy(); + expect(readJson(tree, 'nx.json').targetDefaults).toMatchInlineSnapshot(` + Object { + "lint": Object { + "inputs": Array [ + "default", + "{workspaceRoot}/.eslintrc.json", + ], + }, + "lint2": Object { + "inputs": Array [ + "default", + "{workspaceRoot}/.eslintrc.json", + ], + }, + } + `); + }); +}); + +function ensureGlobalConfig(tree: Tree) { + tree.write('.eslintrc.json', '{}'); +} diff --git a/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.ts b/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.ts new file mode 100644 index 0000000000..9f1e7c766c --- /dev/null +++ b/packages/linter/src/migrations/update-15-7-1/add-eslint-ignore.ts @@ -0,0 +1,49 @@ +import { + formatFiles, + joinPathFragments, + readJson, + Tree, + updateNxJson, +} from '@nrwl/devkit'; +import { eslintConfigFileWhitelist } from '../../generators/utils/eslint-file'; +import { getEslintTargets } from '../../generators/utils/eslint-targets'; + +export default async function addEslintIgnore(tree: Tree) { + const nxJson = readJson(tree, 'nx.json'); + + const globalEslintFile = eslintConfigFileWhitelist.find((file) => + tree.exists(file) + ); + + if (globalEslintFile) { + if (tree.exists('.eslintignore')) { + const content = tree.read('.eslintignore', 'utf-8'); + if (!content.includes('node_modules')) { + tree.write('.eslintignore', `node_modules\n${content}`); + } + } else { + tree.write('.eslintignore', 'node_modules\n'); + } + + for (const targetName of getEslintTargets(tree)) { + nxJson.targetDefaults ??= {}; + const lintTargetDefaults = (nxJson.targetDefaults[targetName] ??= {}); + + const lintIgnorePath = joinPathFragments( + '{workspaceRoot}', + globalEslintFile + ); + + if (lintTargetDefaults.inputs) { + if (!lintTargetDefaults.inputs.includes(lintIgnorePath)) { + lintTargetDefaults.inputs.push(lintIgnorePath); + } + } else { + lintTargetDefaults.inputs = ['default', lintIgnorePath]; + } + } + + updateNxJson(tree, nxJson); + await formatFiles(tree); + } +}