Skip to content

Commit 4bc754b

Browse files
committed
feat(lint): add ability to exclude files and directories
Fixes #4350
1 parent c889dd8 commit 4bc754b

File tree

4 files changed

+119
-27
lines changed

4 files changed

+119
-27
lines changed

packages/@angular/cli/blueprints/ng2/files/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"ng": "ng",
88
"start": "ng serve",
99
"test": "ng test",
10+
"lint": "ng lint",
1011
"pree2e": "webdriver-manager update --standalone false --gecko false",
1112
"e2e": "protractor"
1213
},

packages/@angular/cli/lib/config/schema.json

+30-2
Original file line numberDiff line numberDiff line change
@@ -181,18 +181,46 @@
181181
"type": "object",
182182
"properties": {
183183
"files": {
184-
"type": "string"
184+
"description": "File glob(s) to lint.",
185+
"oneOf": [
186+
{
187+
"type": "string"
188+
},
189+
{
190+
"type": "array",
191+
"items": {
192+
"type": "string"
193+
}
194+
}
195+
],
196+
"default": []
185197
},
186198
"project": {
199+
"description": "Location of the tsconfig.json project file. Will also use as files to lint if 'files' property not present.",
187200
"type": "string"
188201
},
189202
"tslintConfig": {
203+
"description": "Location of the tslint.json configuration.",
190204
"type": "string",
191205
"default": "tslint.json"
206+
},
207+
"exclude": {
208+
"description": "File glob(s) to ignore.",
209+
"oneOf": [
210+
{
211+
"type": "string"
212+
},
213+
{
214+
"type": "array",
215+
"items": {
216+
"type": "string"
217+
}
218+
}
219+
],
220+
"default": []
192221
}
193222
},
194223
"required": [
195-
"files",
196224
"project"
197225
],
198226
"additionalProperties": false

packages/@angular/cli/tasks/lint.ts

+60-25
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,46 @@
11
const Task = require('../ember-cli/lib/models/task');
22
import * as chalk from 'chalk';
33
import * as path from 'path';
4+
import * as glob from 'glob';
5+
import * as ts from 'typescript';
46
import { requireDependency } from '../utilities/require-project-module';
57
import { CliConfig } from '../models/config';
68
import { LintCommandOptions } from '../commands/lint';
79
import { oneLine } from 'common-tags';
810

11+
interface CliLintConfig {
12+
files?: (string | string[]);
13+
project?: string;
14+
tslintConfig?: string;
15+
exclude?: (string | string[]);
16+
}
17+
918
export default Task.extend({
1019
run: function (commandOptions: LintCommandOptions) {
1120
const ui = this.ui;
1221
const projectRoot = this.project.root;
22+
const lintConfigs: CliLintConfig[] = CliConfig.fromProject().config.lint || [];
1323

14-
return new Promise(function (resolve, reject) {
15-
const tslint = requireDependency(projectRoot, 'tslint');
16-
const Linter = tslint.Linter;
17-
const Configuration = tslint.Configuration;
24+
if (lintConfigs.length === 0) {
25+
ui.writeLine(chalk.yellow(oneLine`
26+
No lint config(s) found.
27+
If this is not intended, run "ng update".
28+
`));
1829

19-
const lintConfigs = CliConfig.fromProject().config.lint || [];
30+
return Promise.resolve(0);
31+
}
2032

21-
if (lintConfigs.length === 0) {
22-
ui.writeLine(chalk.yellow(oneLine`
23-
No lint config(s) found.
24-
If this is not intended, run "ng update".
25-
`));
26-
return resolve(0);
27-
}
33+
const tslint = requireDependency(projectRoot, 'tslint');
34+
const Linter = tslint.Linter;
35+
const Configuration = tslint.Configuration;
2836

29-
let errors = 0;
37+
let errors = 0;
38+
let results = '';
3039

31-
lintConfigs.forEach((config) => {
32-
const program = Linter.createProgram(config.project);
33-
const files: string[] = Linter.getFileNames(program);
40+
lintConfigs
41+
.forEach((config) => {
42+
const program: ts.Program = Linter.createProgram(config.project);
43+
const files = getFilesToLint(program, config, Linter);
3444

3545
const linter = new Linter({
3646
fix: commandOptions.fix,
@@ -45,17 +55,42 @@ export default Task.extend({
4555

4656
const result = linter.getResult();
4757
errors += result.failureCount;
48-
49-
ui.writeLine(result.output.trim().concat('\n'));
58+
results = results.concat(result.output.trim().concat('\n'));
5059
});
5160

52-
if (errors > 0) {
53-
ui.writeLine(chalk.red('Lint errors found in the listed files.'));
54-
return commandOptions.force ? resolve(0) : resolve(2);
55-
}
61+
if (errors > 0) {
62+
ui.writeLine(results.trim());
63+
ui.writeLine(chalk.red('Lint errors found in the listed files.'));
64+
return commandOptions.force ? Promise.resolve(0) : Promise.resolve(2);
65+
}
5666

57-
ui.writeLine(chalk.green('All files pass linting.'));
58-
return resolve(0);
59-
});
67+
ui.writeLine(chalk.green('All files pass linting.'));
68+
return Promise.resolve(0);
6069
}
6170
});
71+
72+
function getFilesToLint(program: ts.Program, lintConfig: CliLintConfig, Linter: any): string[] {
73+
let files: string[] = [];
74+
75+
if (lintConfig.files !== null) {
76+
files = Array.isArray(lintConfig.files) ? lintConfig.files : [lintConfig.files];
77+
} else {
78+
files = Linter.getFileNames(program);
79+
}
80+
81+
let globOptions = {};
82+
83+
if (lintConfig.exclude !== null) {
84+
const excludePatterns = Array.isArray(lintConfig.exclude)
85+
? lintConfig.exclude
86+
: [lintConfig.exclude];
87+
88+
globOptions = { ignore: excludePatterns, nodir: true };
89+
}
90+
91+
files = files
92+
.map((file: string) => glob.sync(file, globOptions))
93+
.reduce((a: string[], b: string[]) => a.concat(b), []);
94+
95+
return files;
96+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { ng } from '../../utils/process';
2+
import { writeFile } from '../../utils/fs';
3+
import { oneLine } from 'common-tags';
4+
5+
export default function () {
6+
const fileName = 'src/app/foo.ts';
7+
8+
return Promise.resolve()
9+
.then(() => ng('set', 'lint', `
10+
[
11+
{
12+
"files": "src/**/*.ts",
13+
"project": "src/tsconfig.json",
14+
"tslintConfig": "tslint.json",
15+
"exclude": "**/foo.ts"
16+
}
17+
]`))
18+
.then(() => writeFile(fileName, 'const foo = "";\n'))
19+
.then(() => ng('lint'))
20+
.then((output) => {
21+
if (!output.match(/All files pass linting\./)) {
22+
throw new Error(oneLine`
23+
Expected to match "All files pass linting."
24+
in ${output}.
25+
`);
26+
}
27+
});
28+
}

0 commit comments

Comments
 (0)