Skip to content

Commit

Permalink
fix(linter): check for all .eslintrc.* files when generating a package (
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr Mo committed Oct 12, 2022
1 parent 82d43af commit d4fd7c0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 133 deletions.
24 changes: 8 additions & 16 deletions packages/linter/src/generators/utils/eslint-file.spec.ts
@@ -1,4 +1,4 @@
import { findEslintFile } from './eslint-file';
import { eslintConfigFileWhitelist, findEslintFile } from './eslint-file';

import { Tree } from '@nrwl/devkit';
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
Expand All @@ -15,20 +15,12 @@ describe('@nrwl/linter:eslint-file', () => {
expect(findEslintFile(tree)).toBe(null);
});

it('should return the name of the eslint config when calling findEslintFile', () => {
tree.write('.eslintrc.json', '{}');
expect(findEslintFile(tree)).toBe('.eslintrc.json');
});

it('should return the name of the eslint config when calling findEslintFile', () => {
tree.write('.eslintrc.js', '{}');
expect(findEslintFile(tree)).toBe('.eslintrc.js');
});

it('should return default name when calling findEslintFile when no eslint is found', () => {
tree.write('.eslintrc.yaml', '{}');

expect(findEslintFile(tree)).toBe(null);
});
test.each(eslintConfigFileWhitelist)(
'should return %p when calling findEslintFile',
(eslintFileName) => {
tree.write(eslintFileName, '{}');
expect(findEslintFile(tree)).toBe(eslintFileName);
}
);
});
});
12 changes: 10 additions & 2 deletions packages/linter/src/generators/utils/eslint-file.ts
@@ -1,12 +1,20 @@
import type { Tree } from '@nrwl/devkit';

const eslintFileList = ['.eslintrc.json', '.eslintrc.js'];
export const eslintConfigFileWhitelist = [
'.eslintrc',
'.eslintrc.js',
'.eslintrc.cjs',
'.eslintrc.yaml',
'.eslintrc.yml',
'.eslintrc.json',
];

export function findEslintFile(tree: Tree): string | null {
for (const file of eslintFileList) {
for (const file of eslintConfigFileWhitelist) {
if (tree.exists(file)) {
return file;
}
}

return null;
}
282 changes: 170 additions & 112 deletions packages/linter/src/migrations/update-15-0-0/add-eslint-inputs.spec.ts
Expand Up @@ -6,135 +6,193 @@ import {
updateWorkspaceConfiguration,
} from '@nrwl/devkit';
import addEslintInputs from './add-eslint-inputs';
import { eslintConfigFileWhitelist } from '../../generators/utils/eslint-file';

describe('15.0.0 migration (add-eslint-inputs)', () => {
let tree: Tree;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
describe('production', () => {
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();

it('should add inputs configuration for lint targets', async () => {
updateWorkspaceConfiguration(tree, {
version: 2,
namedInputs: {
default: ['{projectRoot}/**/*', 'sharedGlobals'],
sharedGlobals: [],
production: ['default'],
},
});
addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
lint: {
executor: '@nrwl/linter:eslint',
options: {},
},
lint2: {
executor: '@nrwl/linter:eslint',
options: {},
},
notTest: {
executor: 'nx:run-commands',
updateWorkspaceConfiguration(tree, {
version: 2,
namedInputs: {
default: ['{projectRoot}/**/*', 'sharedGlobals'],
sharedGlobals: [],
production: ['default'],
},
},
});
tree.write('.eslintrc.json', '');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);
expect(updated).toMatchInlineSnapshot(`
Object {
"namedInputs": Object {
"default": Array [
"{projectRoot}/**/*",
"sharedGlobals",
],
"production": Array [
"default",
"!{projectRoot}/.eslintrc.json",
],
"sharedGlobals": Array [],
},
"targetDefaults": Object {
"lint": Object {
"inputs": Array [
"default",
"{workspaceRoot}/.eslintrc.json",
],
});

addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
lint: {
executor: '@nrwl/linter:eslint',
options: {},
},
"lint2": Object {
"inputs": Array [
"default",
"{workspaceRoot}/.eslintrc.json",
],
lint2: {
executor: '@nrwl/linter:eslint',
options: {},
},
notTest: {
executor: 'nx:run-commands',
},
},
"version": 2,
});
});

test.each(eslintConfigFileWhitelist)(
'should ignore %p for production',
async (eslintConfigFilename) => {
tree.write(eslintConfigFilename, '{}');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);

expect(updated.namedInputs.production).toEqual([
'default',
`!{projectRoot}/${eslintConfigFilename}`,
]);
}
`);
);

test.each(eslintConfigFileWhitelist)(
'should add %p to all lint targets',
async (eslintConfigFilename) => {
tree.write(eslintConfigFilename, '{}');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);
const result = ['default', `{workspaceRoot}/${eslintConfigFilename}`];

expect(updated.targetDefaults.lint.inputs).toEqual(result);
expect(updated.targetDefaults.lint2.inputs).toEqual(result);
}
);
});

it('should add inputs configuration for .eslintrc.js', async () => {
updateWorkspaceConfiguration(tree, {
version: 2,
namedInputs: {
default: ['{projectRoot}/**/*', 'sharedGlobals'],
sharedGlobals: [],
production: ['default'],
},
});
addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
lint: {
executor: '@nrwl/linter:eslint',
options: {},
},
lint2: {
executor: '@nrwl/linter:eslint',
options: {},
},
notTest: {
executor: 'nx:run-commands',
describe('development', () => {
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();

addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
lint: {
executor: '@nrwl/linter:eslint',
options: {},
},
lint2: {
executor: '@nrwl/linter:eslint',
options: {},
},
notTest: {
executor: 'nx:run-commands',
},
},
},
});
});
tree.write('.eslintrc.js', '');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);
expect(updated).toMatchInlineSnapshot(`
Object {
"namedInputs": Object {
"default": Array [
"{projectRoot}/**/*",
"sharedGlobals",
],
"production": Array [
"default",
"!{projectRoot}/.eslintrc.json",
],
"sharedGlobals": Array [],
},
"targetDefaults": Object {
"lint": Object {
"inputs": Array [
"default",
"{workspaceRoot}/.eslintrc.js",
],

test.each(eslintConfigFileWhitelist)(
'should not add `!{projectRoot}/%s` if `workspaceConfiguration.namedInputs` is undefined',
async (eslintConfigFilename) => {
updateWorkspaceConfiguration(tree, {
version: 2,
});

tree.write(eslintConfigFilename, '{}');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);

expect(updated.namedInputs?.production).toBeUndefined();
}
);

test.each(eslintConfigFileWhitelist)(
'should not add `!{projectRoot}/%s` if `workspaceConfiguration.namedInputs.production` is undefined',
async (eslintConfigFilename) => {
updateWorkspaceConfiguration(tree, {
version: 2,
namedInputs: {},
});

tree.write(eslintConfigFilename, '{}');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);

expect(updated.namedInputs?.production).toBeUndefined();
}
);
});

describe('lintTargetDefaults.input fallback values', () => {
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();

addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
lint: {
executor: '@nrwl/linter:eslint',
options: {},
},
"lint2": Object {
"inputs": Array [
"default",
"{workspaceRoot}/.eslintrc.js",
],
lint2: {
executor: '@nrwl/linter:eslint',
options: {},
},
notTest: {
executor: 'nx:run-commands',
},
},
"version": 2,
});
});

test.each(eslintConfigFileWhitelist)(
'should not override `targetDefaults.lint.inputs` with `%s` as there was a default target set in the workspace config',
async (eslintConfigFilename) => {
updateWorkspaceConfiguration(tree, {
version: 2,
targetDefaults: {
lint: {
inputs: ['{workspaceRoot}/.eslintrc.default'],
},
},
});

tree.write(eslintConfigFilename, '{}');

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);

expect(updated.targetDefaults.lint.inputs).toEqual([
'{workspaceRoot}/.eslintrc.default',
]);
expect(updated.targetDefaults.lint2.inputs).toEqual([
'default',
`{workspaceRoot}/${eslintConfigFilename}`,
]);
}
`);
);

it('should return `default` if there is no globalEslintFile', async () => {
updateWorkspaceConfiguration(tree, {
version: 2,
});

await addEslintInputs(tree);

const updated = readWorkspaceConfiguration(tree);

expect(updated.targetDefaults.lint.inputs).toEqual(['default']);
expect(updated.targetDefaults.lint2.inputs).toEqual(['default']);
});
});
});
Expand Up @@ -6,25 +6,29 @@ import {
updateWorkspaceConfiguration,
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { eslintConfigFileWhitelist } from '../../generators/utils/eslint-file';

export default async function (tree: Tree) {
export default async function addEslintInputs(tree: Tree) {
const workspaceConfiguration = readWorkspaceConfiguration(tree);

const globalEslintFile = ['.eslintrc.js', '.eslintrc.json'].find((file) =>
const globalEslintFile = eslintConfigFileWhitelist.find((file) =>
tree.exists(file)
);

if (globalEslintFile && workspaceConfiguration.namedInputs?.production) {
const productionFileset = new Set(
workspaceConfiguration.namedInputs.production
);
productionFileset.add('!{projectRoot}/.eslintrc.json');

productionFileset.add(`!{projectRoot}/${globalEslintFile}`);

workspaceConfiguration.namedInputs.production =
Array.from(productionFileset);
}

for (const targetName of getEslintTargets(tree)) {
workspaceConfiguration.targetDefaults ??= {};

const lintTargetDefaults = (workspaceConfiguration.targetDefaults[
targetName
] ??= {});
Expand Down

0 comments on commit d4fd7c0

Please sign in to comment.