Skip to content

Commit

Permalink
feat(linter): use overrides in root eslint config
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesHenry committed Oct 22, 2020
1 parent cf7d779 commit cfea9ea
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 26 deletions.
30 changes: 25 additions & 5 deletions e2e/linter/src/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ forEachCli('nx', () => {
runCLI(`generate @nrwl/react:app ${myapp}`);

const eslintrc = readJson('.eslintrc.json');
eslintrc.rules['no-console'] = 'error';
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = 'error';
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));

updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
Expand All @@ -35,7 +39,11 @@ forEachCli('nx', () => {
runCLI(`generate @nrwl/react:app ${myapp}`);

const eslintrc = readJson('.eslintrc.json');
eslintrc.rules['no-console'] = 'error';
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = 'error';
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));

updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
Expand All @@ -50,7 +58,11 @@ forEachCli('nx', () => {
runCLI(`generate @nrwl/react:app ${myapp}`);

const eslintrc = readJson('.eslintrc.json');
eslintrc.rules['no-console'] = undefined;
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = undefined;
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));

updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
Expand Down Expand Up @@ -82,7 +94,11 @@ forEachCli('nx', () => {
updateFile('workspace.json', JSON.stringify(workspaceJson, null, 2));

const eslintrc = readJson('.eslintrc.json');
eslintrc.rules['no-console'] = undefined;
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = undefined;
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));

updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
Expand Down Expand Up @@ -130,7 +146,11 @@ forEachCli('nx', () => {
runCLI(`generate @nrwl/react:app ${myapp}`);

const eslintrc = readJson('.eslintrc.json');
eslintrc.rules['no-console'] = 'error';
eslintrc.overrides.forEach((override) => {
if (override.files.includes('*.ts')) {
override.rules['no-console'] = 'error';
}
});
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);

Expand Down
37 changes: 37 additions & 0 deletions packages/eslint-plugin-nx/src/configs/javascript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* This configuration is intended to be applied to ALL .js and .jsx files
* within an Nx workspace.
*
* It should therefore NOT contain any rules or plugins which are specific
* to one ecosystem, such as React, Angular, Node etc.
*
* We use @typescript-eslint/parser rather than the built in JS parser
* because that is what Nx ESLint configs have always done and we don't
* want to change too much all at once.
*
* TODO: Evaluate switching to the built-in JS parser (espree) in Nx v11,
* it should yield a performance improvement but could introduce subtle
* breaking changes - we should also look to replace all the @typescript-eslint
* related plugins and rules below.
*/
export default {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'prettier/@typescript-eslint',
],
rules: {
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-parameter-properties': 'off',
},
};
2 changes: 2 additions & 0 deletions packages/eslint-plugin-nx/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typescript from './configs/typescript';
import javascript from './configs/javascript';
import reactTmp from './configs/react-tmp';
import reactBase from './configs/react-base';
import reactJsx from './configs/react-jsx';
Expand All @@ -11,6 +12,7 @@ import enforceModuleBoundaries, {
module.exports = {
configs: {
typescript,
javascript,
react: reactTmp,
'react-base': reactBase,
'react-typescript': reactTypescript,
Expand Down
17 changes: 17 additions & 0 deletions packages/storybook/src/schematics/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,28 @@ function updateLintConfig(schema: StorybookConfigureSchema): Rule {
return updateJsonInTree(
`${projectConfig.root}/.eslintrc.json`,
(json) => {
if (typeof json.parserOptions?.project === 'string') {
json.parserOptions.project = [json.parserOptions.project];
}

if (Array.isArray(json.parserOptions?.project)) {
json.parserOptions.project.push(
`${projectConfig.root}/.storybook/tsconfig.json`
);
}

const overrides = json.overrides || [];
for (const override of overrides) {
if (typeof override.parserOptions?.project === 'string') {
override.parserOptions.project = [override.parserOptions.project];
}
if (Array.isArray(override.parserOptions?.project)) {
override.parserOptions.project.push(
`${projectConfig.root}/.storybook/tsconfig.json`
);
}
}

return json;
}
);
Expand Down
87 changes: 66 additions & 21 deletions packages/workspace/src/utils/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,24 +234,69 @@ const globalTsLint = `
}
`;

const globalESLint = `
{
"root": true,
"ignorePatterns": ["**/*"],
"plugins": ["@nrwl/nx"],
"extends": ["plugin:@nrwl/nx/typescript"],
"parserOptions": { "project": "./tsconfig.*?.json" },
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"enforceBuildableLibDependency": true,
"allow": [],
"depConstraints": [
{ "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] }
]
}
]
}
}
`;
const globalESLint = JSON.stringify({
root: true,
ignorePatterns: ['**/*'],
plugins: ['@nrwl/nx'],
/**
* We leverage ESLint's "overrides" capability so that we can set up a root config which will support
* all permutations of Nx workspaces across all frameworks, libraries and tools.
*
* The key point is that we need entirely different ESLint config to apply to different types of files,
* but we still want to share common config where possible.
*/
overrides: [
/**
* This configuration is intended to apply to all "source code" (but not
* markup like HTML, or other custom file types like GraphQL)
*/
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
rules: {
'@nrwl/nx/enforce-module-boundaries': [
'error',
{
enforceBuildableLibDependency: true,
allow: [],
depConstraints: [
{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] },
],
},
],
},
},

/**
* This configuration is intended to apply to all TypeScript source files.
* See the eslint-plugin-nx package for what is in the referenced shareable config.
*/
{
files: ['*.ts', '*.tsx'],
extends: ['plugin:@nrwl/nx/typescript'],
/**
* TODO: Remove this usage of project at the root in a follow up PR (and migration),
* it should be set in each project's config
*/
parserOptions: { project: './tsconfig.*?.json' },
/**
* Having an empty rules object present makes it more obvious to the user where they would
* extend things from if they needed to
*/
rules: {},
},

/**
* This configuration is intended to apply to all JavaScript source files.
* See the eslint-plugin-nx package for what is in the referenced shareable config.
*/
{
files: ['*.js', '*.jsx'],
extends: ['plugin:@nrwl/nx/javascript'],
/**
* Having an empty rules object present makes it more obvious to the user where they would
* extend things from if they needed to
*/
rules: {},
},
],
});

0 comments on commit cfea9ea

Please sign in to comment.