diff --git a/packages/@angular/cli/tasks/lint.ts b/packages/@angular/cli/tasks/lint.ts index 394862d21bc9..eaccefa9f134 100644 --- a/packages/@angular/cli/tasks/lint.ts +++ b/packages/@angular/cli/tasks/lint.ts @@ -1,11 +1,15 @@ -const Task = require('../ember-cli/lib/models/task'); import * as chalk from 'chalk'; +import * as fs from 'fs'; import * as glob from 'glob'; +import * as path from 'path'; import * as ts from 'typescript'; import { requireProjectModule } from '../utilities/require-project-module'; import { CliConfig } from '../models/config'; import { LintCommandOptions } from '../commands/lint'; +const SilentError = require('silent-error'); +const Task = require('../ember-cli/lib/models/task'); + interface CliLintConfig { files?: (string | string[]); project?: string; @@ -30,7 +34,12 @@ export default Task.extend({ const result = lintConfigs .map((config) => { - const program: ts.Program = Linter.createProgram(config.project); + let program: ts.Program; + if (config.project) { + program = Linter.createProgram(config.project); + } else if (commandOptions.typeCheck) { + ui.writeLine(chalk.yellow('A "project" must be specified to enable type checking.')); + } const files = getFilesToLint(program, config, Linter); const lintOptions = { fix: commandOptions.fix, @@ -39,13 +48,21 @@ export default Task.extend({ const lintProgram = commandOptions.typeCheck ? program : undefined; const linter = new Linter(lintOptions, lintProgram); + let lastDirectory: string; + let configLoad: any; files.forEach((file) => { - const sourceFile = program.getSourceFile(file); - if (!sourceFile) { + const fileContents = getFileContents(file, program); + if (!fileContents) { return; } - const fileContents = sourceFile.getFullText(); - const configLoad = Configuration.findConfiguration(config.tslintConfig, file); + + // Only check for a new tslint config if path changes + const currentDirectory = path.dirname(file); + if (currentDirectory !== lastDirectory) { + configLoad = Configuration.findConfiguration(config.tslintConfig, file); + lastDirectory = currentDirectory; + } + linter.lint(file, fileContents, configLoad.results); }); @@ -94,7 +111,7 @@ function getFilesToLint(program: ts.Program, lintConfig: CliLintConfig, Linter: if (lintConfig.files !== null) { files = Array.isArray(lintConfig.files) ? lintConfig.files : [lintConfig.files]; - } else { + } else if (program) { files = Linter.getFileNames(program); } @@ -114,3 +131,23 @@ function getFilesToLint(program: ts.Program, lintConfig: CliLintConfig, Linter: return files; } + +function getFileContents(file: string, program?: ts.Program): string { + let contents: string; + + if (program) { + const sourceFile = program.getSourceFile(file); + if (sourceFile) { + contents = sourceFile.getFullText(); + } + } else { + // NOTE: The tslint CLI checks for and excludes MPEG transport streams; this does not. + try { + contents = fs.readFileSync(file, 'utf8'); + } catch (e) { + throw new SilentError(`Could not read file "${file}".`); + } + } + + return contents; +} diff --git a/tests/e2e/tests/lint/lint-no-project.ts b/tests/e2e/tests/lint/lint-no-project.ts new file mode 100644 index 000000000000..d558a76c8d50 --- /dev/null +++ b/tests/e2e/tests/lint/lint-no-project.ts @@ -0,0 +1,26 @@ +import { ng } from '../../utils/process'; +import { writeFile } from '../../utils/fs'; +import { expectToFail } from '../../utils/utils'; +import { oneLine } from 'common-tags'; + +export default function () { + return Promise.resolve() + .then(() => ng('set', 'lint.0.project', '')) + .then(() => ng('lint', '--type-check')) + .then(({ stdout }) => { + if (!stdout.match(/A "project" must be specified to enable type checking./)) { + throw new Error(oneLine` + Expected to match "A "project" must be specified to enable type checking." + in ${stdout}. + `); + } + + return stdout; + }) + .then(() => ng('set', 'lint.0.files', '"**/baz.ts"')) + .then(() => writeFile('src/app/foo.ts', 'const foo = "";\n')) + .then(() => writeFile('src/app/baz.ts', 'const baz = \'\';\n')) + .then(() => ng('lint')) + .then(() => ng('set', 'lint.0.files', '"**/foo.ts"')) + .then(() => expectToFail(() => ng('lint'))); +}