feat(linter): add explicit file extension to config files (#3847)
* feat(linter): add explicit file extension to config files * feat(linter): update references to .eslintrc for new projects * fix(linter): fix quotes in global eslint config
This commit is contained in:
parent
b45734b1d2
commit
e339ece224
@ -44,7 +44,7 @@ happynrwl/
|
||||
│ │ ├── jest.conf.js
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ ├── tsconfig.spec.json
|
||||
│ │ └── .eslintrc
|
||||
│ │ └── .eslintrc.json
|
||||
│ └── tuskdesk-e2e/
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── integrations/
|
||||
@ -54,14 +54,14 @@ happynrwl/
|
||||
│ │ │ └── support/
|
||||
│ │ ├── cypress.json
|
||||
│ │ ├── tsconfig.e2e.json
|
||||
│ │ └── .eslintrc
|
||||
│ │ └── .eslintrc.json
|
||||
├── libs/
|
||||
├── workspace.json
|
||||
├── nx.json
|
||||
├── package.json
|
||||
├── tools/
|
||||
├── tsconfig.json
|
||||
└── .eslintrc
|
||||
└── .eslintrc.json
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
@ -167,7 +167,7 @@ Read more about workspace schematics in the Workspace Schematics guide.
|
||||
|
||||
### Workspace Lint Checks
|
||||
|
||||
Custom lint checks is another great way to enforce best practices. We can create custom lint checks in the `tools/lint` directory and then register them in `tslint.json`or `.eslintrc`.
|
||||
Custom lint checks is another great way to enforce best practices. We can create custom lint checks in the `tools/lint` directory and then register them in `tslint.json`or `.eslintrc.json`.
|
||||
|
||||
## Developer Workflow
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ First, use `nx.json` to annotate your projects with tags. In this example, we wi
|
||||
}
|
||||
```
|
||||
|
||||
Next open the top-level `.eslintrc` or `tslint.json` to add the constraints.
|
||||
Next open the top-level `.eslintrc.json` or `tslint.json` to add the constraints.
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@ -38,7 +38,7 @@ myorg/
|
||||
│ │ ├── jest.conf.js
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ ├── tsconfig.spec.json
|
||||
│ │ └── .eslintrc
|
||||
│ │ └── .eslintrc.json
|
||||
│ └── myapp-e2e/
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── integrations/
|
||||
@ -48,14 +48,14 @@ myorg/
|
||||
│ │ │ └── support/
|
||||
│ │ ├── cypress.json
|
||||
│ │ ├── tsconfig.e2e.json
|
||||
│ │ └── .eslintrc
|
||||
│ │ └── .eslintrc.json
|
||||
├── libs/
|
||||
├── workspace.json
|
||||
├── nx.json
|
||||
├── package.json
|
||||
├── tools/
|
||||
├── tsconfig.json
|
||||
└── .eslintrc
|
||||
└── .eslintrc.json
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
@ -18,9 +18,9 @@ forEachCli('nx', () => {
|
||||
|
||||
runCLI(`generate @nrwl/react:app ${myapp}`);
|
||||
|
||||
const eslintrc = readJson('.eslintrc');
|
||||
const eslintrc = readJson('.eslintrc.json');
|
||||
eslintrc.rules['no-console'] = 'error';
|
||||
updateFile('.eslintrc', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
|
||||
|
||||
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
|
||||
|
||||
@ -34,9 +34,9 @@ forEachCli('nx', () => {
|
||||
|
||||
runCLI(`generate @nrwl/react:app ${myapp}`);
|
||||
|
||||
const eslintrc = readJson('.eslintrc');
|
||||
const eslintrc = readJson('.eslintrc.json');
|
||||
eslintrc.rules['no-console'] = 'error';
|
||||
updateFile('.eslintrc', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
|
||||
|
||||
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
|
||||
|
||||
@ -49,9 +49,9 @@ forEachCli('nx', () => {
|
||||
|
||||
runCLI(`generate @nrwl/react:app ${myapp}`);
|
||||
|
||||
const eslintrc = readJson('.eslintrc');
|
||||
const eslintrc = readJson('.eslintrc.json');
|
||||
eslintrc.rules['no-console'] = undefined;
|
||||
updateFile('.eslintrc', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
|
||||
|
||||
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
|
||||
|
||||
@ -81,9 +81,9 @@ forEachCli('nx', () => {
|
||||
};
|
||||
updateFile('workspace.json', JSON.stringify(workspaceJson, null, 2));
|
||||
|
||||
const eslintrc = readJson('.eslintrc');
|
||||
const eslintrc = readJson('.eslintrc.json');
|
||||
eslintrc.rules['no-console'] = undefined;
|
||||
updateFile('.eslintrc', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
|
||||
|
||||
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
|
||||
|
||||
@ -129,9 +129,9 @@ forEachCli('nx', () => {
|
||||
|
||||
runCLI(`generate @nrwl/react:app ${myapp}`);
|
||||
|
||||
const eslintrc = readJson('.eslintrc');
|
||||
const eslintrc = readJson('.eslintrc.json');
|
||||
eslintrc.rules['no-console'] = 'error';
|
||||
updateFile('.eslintrc', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2));
|
||||
updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`);
|
||||
|
||||
const outputFile = 'a/b/c/lint-output.json';
|
||||
@ -167,9 +167,12 @@ forEachCli('nx', () => {
|
||||
|
||||
runCLI(`generate @nrwl/react:app ${myapp}`);
|
||||
|
||||
const eslintrc = readJson(`apps/${myapp}/.eslintrc`);
|
||||
const eslintrc = readJson(`apps/${myapp}/.eslintrc.json`);
|
||||
eslintrc.rules['no-console'] = 'warn';
|
||||
updateFile(`apps/${myapp}/.eslintrc`, JSON.stringify(eslintrc, null, 2));
|
||||
updateFile(
|
||||
`apps/${myapp}/.eslintrc.json`,
|
||||
JSON.stringify(eslintrc, null, 2)
|
||||
);
|
||||
updateFile(
|
||||
`apps/${myapp}/src/main.ts`,
|
||||
`console.log('once'); console.log('twice');`
|
||||
|
||||
@ -246,7 +246,7 @@ describe('schematic:cypress-project', () => {
|
||||
const packageJson = readJsonInTree(tree, 'package.json');
|
||||
const eslintrcJson = readJsonInTree(
|
||||
tree,
|
||||
'apps/my-app-e2e/.eslintrc'
|
||||
'apps/my-app-e2e/.eslintrc.json'
|
||||
);
|
||||
|
||||
expect(
|
||||
|
||||
@ -9,6 +9,11 @@
|
||||
"version": "10.3.0-beta.0",
|
||||
"description": "Migrate to the new ESLint builder and ESLint config style",
|
||||
"factory": "./src/migrations/update-10-3-0/update-eslint-builder-and-config"
|
||||
},
|
||||
"add-json-ext-to-eslintrc": {
|
||||
"version": "10.3.0-beta.2",
|
||||
"description": "Add explicit .json file extension to .eslintrc files, not using an extension is deprecated",
|
||||
"factory": "./src/migrations/update-10-3-0/add-json-ext-to-eslintrc"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
|
||||
@ -39,7 +39,7 @@ function createValidRunBuilderOptions(
|
||||
): Schema {
|
||||
return {
|
||||
lintFilePatterns: [],
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: 'cacheLocation1',
|
||||
@ -118,7 +118,7 @@ describe('Linter Builder', () => {
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
lintFilePatterns: [],
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: 'cacheLocation1',
|
||||
@ -131,9 +131,9 @@ describe('Linter Builder', () => {
|
||||
quiet: false,
|
||||
})
|
||||
);
|
||||
expect(lint).toHaveBeenCalledWith('/root/.eslintrc', {
|
||||
expect(lint).toHaveBeenCalledWith('/root/.eslintrc.json', {
|
||||
lintFilePatterns: [],
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: 'cacheLocation1',
|
||||
@ -164,7 +164,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
})
|
||||
@ -172,7 +172,7 @@ describe('Linter Builder', () => {
|
||||
expect(mockLoadFormatter).toHaveBeenCalledWith('json');
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'html',
|
||||
})
|
||||
@ -184,7 +184,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
fix: false,
|
||||
@ -212,7 +212,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: false,
|
||||
@ -255,7 +255,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: false,
|
||||
@ -303,7 +303,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -347,7 +347,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -375,7 +375,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -403,7 +403,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -422,7 +422,7 @@ describe('Linter Builder', () => {
|
||||
const { createDirectory } = require('@nrwl/workspace');
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -442,7 +442,7 @@ describe('Linter Builder', () => {
|
||||
jest.spyOn(fs, 'writeFileSync').mockImplementation();
|
||||
await runBuilder(
|
||||
createValidRunBuilderOptions({
|
||||
eslintConfig: './.eslintrc',
|
||||
eslintConfig: './.eslintrc.json',
|
||||
lintFilePatterns: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
|
||||
@ -40,7 +40,7 @@ async function run(
|
||||
|
||||
/**
|
||||
* We want users to have the option of not specifying the config path, and let
|
||||
* eslint automatically resolve the `.eslintrc` files in each folder.
|
||||
* eslint automatically resolve the `.eslintrc.json` files in each folder.
|
||||
*/
|
||||
const eslintConfigPath = options.eslintConfig
|
||||
? path.resolve(systemRoot, options.eslintConfig)
|
||||
|
||||
@ -18,14 +18,14 @@ describe('eslint-utils', () => {
|
||||
});
|
||||
|
||||
it('should create the ESLint instance with the proper parameters', async () => {
|
||||
await lint('./.eslintrc', <any>{
|
||||
await lint('./.eslintrc.json', <any>{
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: '/root/cache',
|
||||
}).catch(() => {});
|
||||
|
||||
expect(ESLint).toHaveBeenCalledWith({
|
||||
overrideConfigFile: './.eslintrc',
|
||||
overrideConfigFile: './.eslintrc.json',
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: '/root/cache',
|
||||
|
||||
@ -75,7 +75,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const result = runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: [],
|
||||
});
|
||||
await expect(result).rejects.toThrow(
|
||||
@ -88,7 +88,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const result = runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: [],
|
||||
});
|
||||
await expect(result).resolves.not.toThrow();
|
||||
@ -97,7 +97,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const result = runBuilder({
|
||||
linter: 'tslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: [],
|
||||
});
|
||||
await expect(result).rejects.toThrow(
|
||||
@ -112,7 +112,7 @@ describe('Linter Builder', () => {
|
||||
const { createProgram } = require('./utility/ts-utils');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
tsConfig: './tsconfig.json',
|
||||
});
|
||||
expect(createProgram).toHaveBeenCalledTimes(1);
|
||||
@ -120,7 +120,7 @@ describe('Linter Builder', () => {
|
||||
expect(lint).toHaveBeenCalledTimes(1);
|
||||
expect(lint).toHaveBeenCalledWith(
|
||||
'/root',
|
||||
'/root/.eslintrc',
|
||||
'/root/.eslintrc.json',
|
||||
expect.anything(),
|
||||
expect.any(Set),
|
||||
'/root/tsconfig.json-program',
|
||||
@ -133,7 +133,7 @@ describe('Linter Builder', () => {
|
||||
const { createProgram } = require('./utility/ts-utils');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
tsConfig: ['./tsconfig.json', './tsconfig2.json'],
|
||||
});
|
||||
expect(createProgram).toHaveBeenCalledTimes(2);
|
||||
@ -143,7 +143,7 @@ describe('Linter Builder', () => {
|
||||
expect(lint).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/root',
|
||||
'/root/.eslintrc',
|
||||
'/root/.eslintrc.json',
|
||||
expect.anything(),
|
||||
expect.any(Set),
|
||||
'/root/tsconfig.json-program',
|
||||
@ -152,7 +152,7 @@ describe('Linter Builder', () => {
|
||||
expect(lint).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/root',
|
||||
'/root/.eslintrc',
|
||||
'/root/.eslintrc.json',
|
||||
expect.anything(),
|
||||
expect.any(Set),
|
||||
'/root/tsconfig2.json-program',
|
||||
@ -165,14 +165,14 @@ describe('Linter Builder', () => {
|
||||
const { createProgram } = require('./utility/ts-utils');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: [],
|
||||
});
|
||||
expect(createProgram).not.toHaveBeenCalled();
|
||||
expect(lint).toHaveBeenCalledTimes(1);
|
||||
expect(lint).toHaveBeenCalledWith(
|
||||
'/root',
|
||||
'/root/.eslintrc',
|
||||
'/root/.eslintrc.json',
|
||||
expect.anything(),
|
||||
expect.any(Set)
|
||||
);
|
||||
@ -184,7 +184,7 @@ describe('Linter Builder', () => {
|
||||
const { lint } = require('./utility/eslint-utils');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
exclude: ['excludedFile1'],
|
||||
fix: true,
|
||||
@ -195,7 +195,7 @@ describe('Linter Builder', () => {
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
{
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
exclude: ['excludedFile1'],
|
||||
fix: true,
|
||||
@ -219,7 +219,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const result = runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
});
|
||||
await expect(result).rejects.toThrow(
|
||||
@ -230,14 +230,14 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
});
|
||||
expect(mockGetFormatter).toHaveBeenCalledWith('json');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'html',
|
||||
});
|
||||
@ -247,7 +247,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
fix: false,
|
||||
@ -274,7 +274,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: false,
|
||||
@ -315,7 +315,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: false,
|
||||
@ -353,7 +353,7 @@ describe('Linter Builder', () => {
|
||||
const { createDirectory } = require('@nrwl/workspace');
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
outputFile: 'a/b/c/outputFile1',
|
||||
});
|
||||
@ -368,7 +368,7 @@ describe('Linter Builder', () => {
|
||||
jest.spyOn(fs, 'writeFileSync').mockImplementation();
|
||||
await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
});
|
||||
expect(fs.writeFileSync).not.toHaveBeenCalled();
|
||||
@ -391,7 +391,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -434,7 +434,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -459,7 +459,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -485,7 +485,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
@ -511,7 +511,7 @@ describe('Linter Builder', () => {
|
||||
setupMocks();
|
||||
const output = await runBuilder({
|
||||
linter: 'eslint',
|
||||
config: './.eslintrc',
|
||||
config: './.eslintrc.json',
|
||||
files: ['includedFile1'],
|
||||
format: 'json',
|
||||
silent: true,
|
||||
|
||||
@ -42,7 +42,7 @@ async function run(options: Schema, context: BuilderContext): Promise<any> {
|
||||
}
|
||||
|
||||
// We want users to have the option of not specifying the config path, and let
|
||||
// eslint automatically resolve the `.eslintrc` files in each folder.
|
||||
// eslint automatically resolve the `.eslintrc.json` files in each folder.
|
||||
const eslintConfigPath = options.config
|
||||
? path.resolve(systemRoot, options.config)
|
||||
: undefined;
|
||||
|
||||
@ -31,7 +31,7 @@ describe('eslint-util', () => {
|
||||
const lintedFiles = new Set();
|
||||
await lint(
|
||||
'/root',
|
||||
'./.eslintrc',
|
||||
'./.eslintrc.json',
|
||||
<any>{ foo: 'bar' },
|
||||
lintedFiles,
|
||||
'ts-program'
|
||||
@ -46,13 +46,13 @@ describe('eslint-util', () => {
|
||||
const lintedFiles = new Set();
|
||||
await lint(
|
||||
'/root',
|
||||
'./.eslintrc',
|
||||
'./.eslintrc.json',
|
||||
<any>{ fix: true, cache: true, cacheLocation: '/root/cache' },
|
||||
lintedFiles,
|
||||
'ts-program'
|
||||
).catch(() => {});
|
||||
expect(CLIEngine).toHaveBeenCalledWith({
|
||||
configFile: './.eslintrc',
|
||||
configFile: './.eslintrc.json',
|
||||
fix: true,
|
||||
cache: true,
|
||||
cacheLocation: '/root/cache',
|
||||
@ -72,7 +72,7 @@ describe('eslint-util', () => {
|
||||
lintedFiles.add('file4');
|
||||
const reports = await lint(
|
||||
'/root',
|
||||
'./.eslintrc',
|
||||
'./.eslintrc.json',
|
||||
<any>{ foo: 'bar' },
|
||||
lintedFiles
|
||||
);
|
||||
@ -91,7 +91,7 @@ describe('eslint-util', () => {
|
||||
const lintedFiles = new Set();
|
||||
const lintPromise = lint(
|
||||
'/root',
|
||||
'./.eslintrc',
|
||||
'./.eslintrc.json',
|
||||
<any>{ tsConfig: 'my-ts-project' },
|
||||
lintedFiles,
|
||||
program,
|
||||
@ -114,7 +114,7 @@ describe('eslint-util', () => {
|
||||
const lintedFiles = new Set();
|
||||
const lintPromise = lint(
|
||||
'/root',
|
||||
'./.eslintrc',
|
||||
'./.eslintrc.json',
|
||||
<any>{ tsConfig: 'my-ts-project' },
|
||||
lintedFiles,
|
||||
program,
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
import { Tree } from '@angular-devkit/schematics';
|
||||
import {
|
||||
readJsonInTree,
|
||||
readWorkspace,
|
||||
updateJsonInTree,
|
||||
updateWorkspace,
|
||||
} from '@nrwl/workspace';
|
||||
import { callRule, createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||
import { runMigration } from '../../utils/testing';
|
||||
|
||||
describe('Add explicit .json file extension to .eslintrc files', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(async () => {
|
||||
tree = Tree.empty();
|
||||
tree = createEmptyWorkspace(tree);
|
||||
tree = await callRule(
|
||||
updateJsonInTree('.eslintrc', () => ({})),
|
||||
tree
|
||||
);
|
||||
tree = await callRule(
|
||||
updateWorkspace((workspace) => {
|
||||
// Old linter builder with ESLint, with explicit config file reference
|
||||
// that needs to be updated
|
||||
workspace.projects.add({
|
||||
name: 'testProject',
|
||||
root: 'apps/testProject',
|
||||
sourceRoot: 'apps/testProject/src',
|
||||
projectType: 'application',
|
||||
targets: {
|
||||
lint: {
|
||||
builder: '@nrwl/linter:lint',
|
||||
options: {
|
||||
linter: 'eslint',
|
||||
config: '.eslintrc',
|
||||
tsConfig: [
|
||||
'apps/testProject/tsconfig.app.json',
|
||||
'apps/testProject/tsconfig.spec.json',
|
||||
],
|
||||
exclude: ['**/node_modules/**', '!apps/testProject/**/*'],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// New eslint builder, with explicit config file reference
|
||||
// that needs to be updated
|
||||
workspace.projects.add({
|
||||
name: 'testProject2',
|
||||
root: 'apps/testProject2',
|
||||
sourceRoot: 'apps/testProject2/src',
|
||||
projectType: 'application',
|
||||
targets: {
|
||||
lint: {
|
||||
builder: '@nrwl/linter:eslint',
|
||||
options: {
|
||||
eslintConfig: '.eslintrc',
|
||||
lintFilePatterns: ['apps/testProject2/**/*.ts'],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
tree
|
||||
);
|
||||
tree = await callRule(
|
||||
updateJsonInTree('apps/testProject/.eslintrc', () => ({})),
|
||||
tree
|
||||
);
|
||||
tree = await callRule(
|
||||
updateJsonInTree('apps/testProject2/.eslintrc', () => ({})),
|
||||
tree
|
||||
);
|
||||
});
|
||||
|
||||
it('should rename .eslintrc files to .eslintrc.json and update any workspace.json references', async () => {
|
||||
const result = await runMigration('add-json-ext-to-eslintrc', {}, tree);
|
||||
|
||||
const workspace = readWorkspace(tree);
|
||||
|
||||
// ---------------------------------------- Root
|
||||
expect(() =>
|
||||
readJsonInTree(result, '.eslintrc')
|
||||
).toThrowErrorMatchingInlineSnapshot(`"Cannot find .eslintrc"`);
|
||||
expect(readJsonInTree(result, '.eslintrc.json')).toMatchInlineSnapshot(
|
||||
`Object {}`
|
||||
);
|
||||
|
||||
// ---------------------------------------- testProject
|
||||
expect(() =>
|
||||
readJsonInTree(result, 'apps/testProject/.eslintrc')
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Cannot find apps/testProject/.eslintrc"`
|
||||
);
|
||||
expect(
|
||||
readJsonInTree(result, 'apps/testProject/.eslintrc.json')
|
||||
).toMatchInlineSnapshot(`Object {}`);
|
||||
expect(
|
||||
workspace.projects['testProject'].architect.lint.options.config
|
||||
).toEqual('.eslintrc.json');
|
||||
|
||||
// ---------------------------------------- testProject2
|
||||
expect(() =>
|
||||
readJsonInTree(result, 'apps/testProject2/.eslintrc')
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Cannot find apps/testProject2/.eslintrc"`
|
||||
);
|
||||
expect(
|
||||
readJsonInTree(result, 'apps/testProject2/.eslintrc.json')
|
||||
).toMatchInlineSnapshot(`Object {}`);
|
||||
expect(
|
||||
workspace.projects['testProject2'].architect.lint.options.eslintConfig
|
||||
).toEqual('.eslintrc.json');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,64 @@
|
||||
import { basename } from '@angular-devkit/core';
|
||||
import { chain, Tree } from '@angular-devkit/schematics';
|
||||
import {
|
||||
formatFiles,
|
||||
readJsonInTree,
|
||||
serializeJson,
|
||||
updateWorkspace,
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nrwl/workspace';
|
||||
|
||||
function updateESLintConfigReferencesInWorkspace() {
|
||||
return updateWorkspace((workspace) => {
|
||||
workspace.projects.forEach((project) => {
|
||||
const lintTarget = project.targets.get('lint');
|
||||
if (
|
||||
lintTarget?.builder !== '@nrwl/linter:eslint' &&
|
||||
(lintTarget?.builder !== '@nrwl/linter:lint' ||
|
||||
lintTarget?.options?.linter === 'tslint')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lintTarget.builder === '@nrwl/linter:eslint') {
|
||||
if (!lintTarget.options.eslintConfig) {
|
||||
return;
|
||||
}
|
||||
lintTarget.options.eslintConfig = `${lintTarget.options.eslintConfig}.json`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lintTarget.builder === '@nrwl/linter:lint') {
|
||||
if (!lintTarget.options.config) {
|
||||
return;
|
||||
}
|
||||
lintTarget.options.config = `${lintTarget.options.config}.json`;
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renameESLintConfigFiles() {
|
||||
return visitNotIgnoredFiles((file, host, context) => {
|
||||
if (basename(file) !== '.eslintrc') {
|
||||
return;
|
||||
}
|
||||
// Using .eslintrc without an explicit file extension is deprecated
|
||||
const newFilePath = `${file}.json`;
|
||||
context.logger.info(`Renaming ${file} to ${newFilePath}`);
|
||||
try {
|
||||
return host.rename(file, newFilePath);
|
||||
} catch (e) {
|
||||
context.logger.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default function () {
|
||||
return chain([
|
||||
renameESLintConfigFiles,
|
||||
updateESLintConfigReferencesInWorkspace,
|
||||
formatFiles(),
|
||||
]);
|
||||
}
|
||||
@ -197,14 +197,14 @@ describe('app', () => {
|
||||
});
|
||||
|
||||
describe('--linter=eslint', () => {
|
||||
it('should add .eslintrc and dependencies', async () => {
|
||||
it('should add .eslintrc.json and dependencies', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', linter: 'eslint' },
|
||||
appTree
|
||||
);
|
||||
|
||||
const eslintJson = readJsonInTree(tree, '/apps/my-app/.eslintrc');
|
||||
const eslintJson = readJsonInTree(tree, '/apps/my-app/.eslintrc.json');
|
||||
const packageJson = readJsonInTree(tree, '/package.json');
|
||||
|
||||
expect(eslintJson.plugins).toEqual(
|
||||
|
||||
@ -112,9 +112,11 @@ describe('app', () => {
|
||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||
|
||||
const eslintrc = JSON.parse(
|
||||
stripJsonComments(getFileContent(tree, 'apps/my-node-app/.eslintrc'))
|
||||
stripJsonComments(
|
||||
getFileContent(tree, 'apps/my-node-app/.eslintrc.json')
|
||||
)
|
||||
);
|
||||
expect(eslintrc.extends).toEqual('../../.eslintrc');
|
||||
expect(eslintrc.extends).toEqual('../../.eslintrc.json');
|
||||
});
|
||||
});
|
||||
|
||||
@ -192,9 +194,9 @@ describe('app', () => {
|
||||
expectedValue: ['node'],
|
||||
},
|
||||
{
|
||||
path: 'apps/my-dir/my-node-app/.eslintrc',
|
||||
path: 'apps/my-dir/my-node-app/.eslintrc.json',
|
||||
lookupFn: (json) => json.extends,
|
||||
expectedValue: '../../../.eslintrc',
|
||||
expectedValue: '../../../.eslintrc.json',
|
||||
},
|
||||
].forEach(hasJsonValue);
|
||||
});
|
||||
|
||||
@ -71,9 +71,9 @@ describe('app', () => {
|
||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||
|
||||
const eslintJson = JSON.parse(
|
||||
stripJsonComments(tree.readContent('apps/my-app/.eslintrc'))
|
||||
stripJsonComments(tree.readContent('apps/my-app/.eslintrc.json'))
|
||||
);
|
||||
expect(eslintJson.extends).toEqual(['../../.eslintrc']);
|
||||
expect(eslintJson.extends).toEqual(['../../.eslintrc.json']);
|
||||
|
||||
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
||||
const tsconfigE2E = JSON.parse(
|
||||
@ -155,9 +155,9 @@ describe('app', () => {
|
||||
expectedValue: '../../../dist/out-tsc',
|
||||
},
|
||||
{
|
||||
path: 'apps/my-dir/my-app/.eslintrc',
|
||||
path: 'apps/my-dir/my-app/.eslintrc.json',
|
||||
lookupFn: (json) => json.extends,
|
||||
expectedValue: ['../../../.eslintrc'],
|
||||
expectedValue: ['../../../.eslintrc.json'],
|
||||
},
|
||||
].forEach(hasJsonValue);
|
||||
});
|
||||
@ -358,14 +358,14 @@ describe('app', () => {
|
||||
expect(appContent).not.toMatch(/extends Component/);
|
||||
});
|
||||
|
||||
it('should add .eslintrc and dependencies', async () => {
|
||||
it('should add .eslintrc.json and dependencies', async () => {
|
||||
const tree = await runSchematic(
|
||||
'app',
|
||||
{ name: 'myApp', linter: 'eslint' },
|
||||
appTree
|
||||
);
|
||||
|
||||
const eslintJson = readJsonInTree(tree, '/apps/my-app/.eslintrc');
|
||||
const eslintJson = readJsonInTree(tree, '/apps/my-app/.eslintrc.json');
|
||||
const packageJson = readJsonInTree(tree, '/package.json');
|
||||
|
||||
expect(eslintJson.plugins).toEqual(
|
||||
|
||||
@ -201,7 +201,7 @@ function configureTsSolutionConfig(schema: StorybookConfigureSchema): Rule {
|
||||
* which includes *.stories files.
|
||||
*
|
||||
* For TSLint this is done via the builder config, for ESLint this is
|
||||
* done within the .eslintrc file.
|
||||
* done within the .eslintrc.json file.
|
||||
*/
|
||||
function updateLintConfig(schema: StorybookConfigureSchema): Rule {
|
||||
const { name: projectName } = schema;
|
||||
@ -233,13 +233,16 @@ function updateLintConfig(schema: StorybookConfigureSchema): Rule {
|
||||
return;
|
||||
}
|
||||
|
||||
return updateJsonInTree(`${projectConfig.root}/.eslintrc`, (json) => {
|
||||
if (Array.isArray(json.parserOptions?.project)) {
|
||||
json.parserOptions.project.push(
|
||||
`${projectConfig.root}/.storybook/tsconfig.json`
|
||||
);
|
||||
return updateJsonInTree(
|
||||
`${projectConfig.root}/.eslintrc.json`,
|
||||
(json) => {
|
||||
if (Array.isArray(json.parserOptions?.project)) {
|
||||
json.parserOptions.project.push(
|
||||
`${projectConfig.root}/.storybook/tsconfig.json`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
@ -70,9 +70,9 @@ describe('app', () => {
|
||||
expect(tsconfigApp.extends).toEqual('./tsconfig.json');
|
||||
|
||||
const linter = JSON.parse(
|
||||
stripJsonComments(tree.readContent('apps/my-app/.eslintrc'))
|
||||
stripJsonComments(tree.readContent('apps/my-app/.eslintrc.json'))
|
||||
);
|
||||
expect(linter.extends).toEqual('../../.eslintrc');
|
||||
expect(linter.extends).toEqual('../../.eslintrc.json');
|
||||
|
||||
expect(tree.exists('apps/my-app-e2e/cypress.json')).toBeTruthy();
|
||||
const tsconfigE2E = JSON.parse(
|
||||
@ -154,9 +154,9 @@ describe('app', () => {
|
||||
expectedValue: '../../../dist/out-tsc',
|
||||
},
|
||||
{
|
||||
path: 'apps/my-dir/my-app/.eslintrc',
|
||||
path: 'apps/my-dir/my-app/.eslintrc.json',
|
||||
lookupFn: (json) => json.extends,
|
||||
expectedValue: '../../../.eslintrc',
|
||||
expectedValue: '../../../.eslintrc.json',
|
||||
},
|
||||
].forEach(hasJsonValue);
|
||||
});
|
||||
|
||||
@ -71,6 +71,7 @@ export { formatFiles } from './src/utils/rules/format-files';
|
||||
export { deleteFile } from './src/utils/rules/deleteFile';
|
||||
export * from './src/utils/rules/ng-add';
|
||||
export { updateKarmaConf } from './src/utils/rules/update-karma-conf';
|
||||
export { visitNotIgnoredFiles } from './src/utils/rules/visit-not-ignored-files';
|
||||
export { setDefaultCollection } from './src/utils/rules/workspace';
|
||||
import * as strings from './src/utils/strings';
|
||||
export { checkAndCleanWithSemver } from './src/utils/version-utils';
|
||||
|
||||
@ -184,7 +184,7 @@ describe('lib', () => {
|
||||
tree.exists('libs/my-dir/my-lib/src/lib/my-dir-my-lib.ts')
|
||||
).toBeTruthy();
|
||||
expect(tree.exists('libs/my-dir/my-lib/src/index.ts')).toBeTruthy();
|
||||
expect(tree.exists(`libs/my-dir/my-lib/.eslintrc`)).toBeTruthy();
|
||||
expect(tree.exists(`libs/my-dir/my-lib/.eslintrc.json`)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update workspace.json', async () => {
|
||||
@ -242,15 +242,15 @@ describe('lib', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('should create a local .eslintrc', async () => {
|
||||
it('should create a local .eslintrc.json', async () => {
|
||||
const tree = await runSchematic(
|
||||
'lib',
|
||||
{ name: 'myLib', directory: 'myDir' },
|
||||
appTree
|
||||
);
|
||||
|
||||
const lint = readJsonInTree(tree, 'libs/my-dir/my-lib/.eslintrc');
|
||||
expect(lint.extends).toEqual('../../../.eslintrc');
|
||||
const lint = readJsonInTree(tree, 'libs/my-dir/my-lib/.eslintrc.json');
|
||||
expect(lint.extends).toEqual('../../../.eslintrc.json');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -98,9 +98,9 @@ describe('preset', () => {
|
||||
expect(
|
||||
tree.exists('/libs/api-interfaces/src/lib/api-interfaces.ts')
|
||||
).toBe(true);
|
||||
expect(tree.exists('/apps/proj/.eslintrc')).toBe(true);
|
||||
expect(tree.exists('/apps/api/.eslintrc')).toBe(true);
|
||||
expect(tree.exists('/libs/api-interfaces/.eslintrc')).toBe(true);
|
||||
expect(tree.exists('/apps/proj/.eslintrc.json')).toBe(true);
|
||||
expect(tree.exists('/apps/api/.eslintrc.json')).toBe(true);
|
||||
expect(tree.exists('/libs/api-interfaces/.eslintrc.json')).toBe(true);
|
||||
});
|
||||
|
||||
it('should work with unnormalized names', async () => {
|
||||
|
||||
@ -92,9 +92,9 @@ export function addLintFiles(
|
||||
}
|
||||
|
||||
if (linter === 'eslint') {
|
||||
if (!host.exists('/.eslintrc')) {
|
||||
if (!host.exists('/.eslintrc.json')) {
|
||||
chainedCommands.push((host: Tree) => {
|
||||
host.create('/.eslintrc', globalESLint);
|
||||
host.create('/.eslintrc.json', globalESLint);
|
||||
|
||||
return addDepsToPackageJson(
|
||||
{
|
||||
@ -119,7 +119,7 @@ export function addLintFiles(
|
||||
if (!options.onlyGlobal) {
|
||||
chainedCommands.push((host: Tree) => {
|
||||
let configJson;
|
||||
const rootConfig = `${offsetFromRoot(projectRoot)}.eslintrc`;
|
||||
const rootConfig = `${offsetFromRoot(projectRoot)}.eslintrc.json`;
|
||||
|
||||
// Include all project files to be linted (since they are turned off in the root eslintrc file).
|
||||
const ignorePatterns = ['!**/*'];
|
||||
@ -155,7 +155,7 @@ export function addLintFiles(
|
||||
}
|
||||
|
||||
host.create(
|
||||
join(projectRoot as any, `.eslintrc`),
|
||||
join(projectRoot as any, `.eslintrc.json`),
|
||||
JSON.stringify(configJson)
|
||||
);
|
||||
});
|
||||
@ -246,11 +246,11 @@ const globalESLint = `
|
||||
"ignorePatterns": ["**/*"],
|
||||
"plugins": ["@typescript-eslint", "@nrwl/nx"],
|
||||
"extends": [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'prettier/@typescript-eslint'
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
"prettier/@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-member-accessibility": "off",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user