Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
Extend cli options (#2322)
Browse files Browse the repository at this point in the history
[bugfix] exit with 0 on type check errors when `--force` is specified
Fixes: #2087
[bugfix] `--test` now correctly strips single quotes from patterns on windows
[enhancement] `--test` can handle multiple paths at once
[enhancement] added `-p` as shorthand for `--project` to be consistent with `tsc`
Kind of fixes: #2291
[enhancement] print error when `--type-check` is used without `--project`
[enhancement]  don't print stack trace on type check error
  • Loading branch information
ajafff authored and nchen63 committed Mar 10, 2017
1 parent 6196caf commit e2b0ff8
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 32 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Options:
-h, --help display detailed help
-i, --init generate a tslint.json config file in the current working directory
-o, --out output file
--project tsconfig.json file
-p, --project tsconfig.json file
-r, --rules-dir rules directory
-s, --formatters-dir formatters directory
-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist) [default: "prose"]
Expand Down Expand Up @@ -200,7 +200,7 @@ tslint accepts the following command-line options:
the tests. See the full tslint documentation for more details on how
this can be used to test custom rules.
--project:
-p, --project:
The location of a tsconfig.json file that will be used to determine which
files will be linted.
Expand Down
4 changes: 2 additions & 2 deletions docs/usage/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Options:
-h, --help display detailed help
-i, --init generate a tslint.json config file in the current working directory
-o, --out output file
--project tsconfig.json file
-p, --project tsconfig.json file
-r, --rules-dir rules directory
-s, --formatters-dir formatters directory
-t, --format output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame) [default: "prose"]
Expand Down Expand Up @@ -115,7 +115,7 @@ tslint accepts the following command-line options:
specified directory as the configuration file for the tests. See the
full tslint documentation for more details on how this can be used to test custom rules.
--project:
-p, --project:
The location of a tsconfig.json file that will be used to determine which
files will be linted.
Expand Down
36 changes: 16 additions & 20 deletions src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,35 +112,30 @@ export class Runner {
public run(onComplete: (status: number) => void) {
if (this.options.version) {
this.outputStream.write(Linter.VERSION + "\n");
onComplete(0);
return;
return onComplete(0);
}

if (this.options.init) {
if (fs.existsSync(CONFIG_FILENAME)) {
console.error(`Cannot generate ${CONFIG_FILENAME}: file already exists`);
onComplete(1);
return;
return onComplete(1);
}

const tslintJSON = JSON.stringify(DEFAULT_CONFIG, undefined, " ");
fs.writeFileSync(CONFIG_FILENAME, tslintJSON);
onComplete(0);
return;
return onComplete(0);
}

if (this.options.test) {
const results = runTests(this.options.test, this.options.rulesDirectory);
const results = runTests((this.options.files || []).map(Runner.trimSingleQuotes), this.options.rulesDirectory);
const didAllTestsPass = consoleTestResultsHandler(results);
onComplete(didAllTestsPass ? 0 : 1);
return;
return onComplete(didAllTestsPass ? 0 : 1);
}

// when provided, it should point to an existing location
if (this.options.config && !fs.existsSync(this.options.config)) {
console.error("Invalid option for configuration: " + this.options.config);
onComplete(1);
return;
return onComplete(1);
}

// if both files and tsconfig are present, use files
Expand All @@ -150,8 +145,7 @@ export class Runner {
if (this.options.project != null) {
if (!fs.existsSync(this.options.project)) {
console.error("Invalid option for project: " + this.options.project);
onComplete(1);
return;
return onComplete(1);
}
program = Linter.createProgram(this.options.project, path.dirname(this.options.project));
if (files.length === 0) {
Expand All @@ -171,12 +165,16 @@ export class Runner {
message += " " + ts.flattenDiagnosticMessageText(diag.messageText, "\n");
return message;
});
throw new Error(messages.join("\n"));
console.error(messages.join("\n"));
return onComplete(this.options.force ? 0 : 1);
}
} else {
// if not type checking, we don't need to pass in a program object
program = undefined;
}
} else if (this.options.typeCheck) {
console.error("--project must be specified in order to enable type checking.");
return onComplete(1);
}

let ignorePatterns: string[] = [];
Expand All @@ -197,7 +195,7 @@ export class Runner {
} catch (error) {
if (error.name === FatalError.NAME) {
console.error(error.message);
onComplete(1);
return onComplete(1);
}
// rethrow unhandled error
throw error;
Expand All @@ -218,21 +216,19 @@ export class Runner {
for (const file of files) {
if (!fs.existsSync(file)) {
console.error(`Unable to open file: ${file}`);
onComplete(1);
return;
return onComplete(1);
}

const buffer = new Buffer(256);
buffer.fill(0);
const fd = fs.openSync(file, "r");
try {
fs.readSync(fd, buffer, 0, 256, 0);
if (buffer.readInt8(0) === 0x47 && buffer.readInt8(188) === 0x47) {
if (buffer.readInt8(0, true) === 0x47 && buffer.readInt8(188, true) === 0x47) {
// MPEG transport streams use the '.ts' file extension. They use 0x47 as the frame
// separator, repeating every 188 bytes. It is unlikely to find that pattern in
// TypeScript source, so tslint ignores files with the specific pattern.
console.warn(`${file}: ignoring MPEG transport stream`);
return;
continue;
}
} finally {
fs.closeSync(fd);
Expand Down
9 changes: 6 additions & 3 deletions src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ export interface TestResult {
};
}

export function runTests(pattern: string, rulesDirectory?: string | string[]): TestResult[] {
return glob.sync(`${pattern}/tslint.json`)
.map((directory: string): TestResult => runTest(path.dirname(directory), rulesDirectory));
export function runTests(patterns: string[], rulesDirectory?: string | string[]): TestResult[] {
const files: string[] = [];
for (const pattern of patterns) {
files.push(...glob.sync(`${pattern}/tslint.json`));
}
return files.map((directory: string): TestResult => runTest(path.dirname(directory), rulesDirectory));
}

export function runTest(testDirectory: string, rulesDirectory?: string | string[]): TestResult {
Expand Down
9 changes: 5 additions & 4 deletions src/tslint-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ const processed = optimist
describe: "output file",
type: "string",
},
"project": {
"p": {
alias: "project",
describe: "tsconfig.json file",
type: "string",
},
Expand All @@ -92,7 +93,7 @@ const processed = optimist
},
"test": {
describe: "test that tslint produces the correct output for the specified directory",
type: "string",
type: "boolean",
},
"type-check": {
describe: "enable type checking when linting a project",
Expand Down Expand Up @@ -186,7 +187,7 @@ tslint accepts the following commandline options:
the tests. See the full tslint documentation for more details on how
this can be used to test custom rules.
--project:
-p, --project:
The location of a tsconfig.json file that will be used to determine which
files will be linted.
Expand All @@ -213,7 +214,7 @@ const options: IRunnerOptions = {
formattersDirectory: argv.s,
init: argv.init,
out: argv.out,
project: argv.project,
project: argv.p,
rulesDirectory: argv.r,
test: argv.test,
typeCheck: argv["type-check"],
Expand Down
21 changes: 20 additions & 1 deletion test/executable/executableTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) {
done();
});
});

it("can be used with multiple paths", (done) => {
// pass a failing test as second path to make sure it gets executed
execCli(["--test", "test/files/custom-rule-rule-test", "test/files/incorrect-fixes-test"], (err) => {
assert.isNotNull(err, "process should exit with error");
assert.strictEqual(err.code, 1, "error code should be 1");
done();
});
});
});

describe("tsconfig.json", () => {
Expand All @@ -230,14 +239,24 @@ describe("Executable", function(this: Mocha.ISuiteCallbackContext) {
});

it("exits with code 0 if `tsconfig.json` is passed but it includes no ts files", (done) => {
execCli(["-c", "test/files/tsconfig-no-ts-files/tslint.json", "--project", "test/files/tsconfig-no-ts-files/tsconfig.json"],
execCli(["-c", "test/files/tsconfig-no-ts-files/tslint.json", "-p", "test/files/tsconfig-no-ts-files/tsconfig.json"],
(err) => {
assert.isNull(err, "process should exit without an error");
done();
});
});
});

describe("--type-check", () => {
it("exits with code 1 if --project is not passed", (done) => {
execCli(["--type-check"], (err) => {
assert.isNotNull(err, "process should exit with error");
assert.strictEqual(err.code, 2, "error code should be 2");
done();
});
});
});

describe("--init flag", () => {
// remove temp file before calling tslint --init
beforeEach(cleanTempInitFile);
Expand Down

0 comments on commit e2b0ff8

Please sign in to comment.