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

Commit

Permalink
Added an optional TSLintErrorSeverity flag (#45)
Browse files Browse the repository at this point in the history
* Added an optional `TSLintErrorSeverity` flag

Optional MSBuild error severity override, as `"error"` or `"warning"`.

Fixes #19.

* Fixed README.md ordering for error severity

* Moved the "X errors found" message above errors

Now that error printing is a source of errors (albeit very unlikely) it
makes sense to have the summary first.
  • Loading branch information
Josh Goldberg authored Jul 2, 2016
1 parent d115db3 commit f4ce855
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The following properties may be overidden via your targets:
* **TSLintBreakBuildOnError** - Whether linting failures should break the build. Defaults to `false`.
* **TSLintConfig** - Path to a specific tslint.json. Defaults to blank, for any tslint.json on the path.
* **TSLintDeleteFileListFile** - Whether to delete the file list file when done. Defaults to `true`.
* **TSLintErrorSeverity** - Optional MSBuild error severity override, as `"error"` or `"warning"`.
* **TSLintExclude** - Blob of matching file names to exclude. Defaults to none.
* **TSLintFilesRootDir** - Root directory to work within. Defaults to `$(MSBuildProjectDirectory)`.
* **TSLintFileListDir** - Directory to put the file list in. Defaults to `$(IntermediateOutDir)`.
Expand Down
14 changes: 13 additions & 1 deletion src/ArgumentsCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ interface ICollected {
*/
"--config"?: string;

/**
* Override for MSBuild error severity level.
*/
"--error-severity"?: "error" | "warning";

/**
* A glob path to exclude from linting.
*/
Expand Down Expand Up @@ -36,7 +41,7 @@ export class ArgumentsCollection {
* Whitelist of allowed keys from the .targets file.
*/
private static allowedKeys: Set<string> = new Set<string>([
"--config", "--exclude", "--file-list-file", "--files-root-dir", "--rules-directory"
"--config", "--error-severity", "--exclude", "--file-list-file", "--files-root-dir", "--rules-directory"
]);

/**
Expand Down Expand Up @@ -92,6 +97,13 @@ export class ArgumentsCollection {
return this.collected["--config"];
}

/**
* @returns The override for MSBuild error severity level.
*/
public getErrorSeverity(): "error" | "warning" {
return this.collected["--error-severity"];
}

/**
* @returns The root directory to work within.
*/
Expand Down
110 changes: 110 additions & 0 deletions src/ErrorsPrinter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* MSBuild error printers, keyed by severity level.
*/
interface IErrorPrinters {
[i: string]: IErrorPrinter;
}

/**
* Prints a single pre-formatted MSBuild error.
*
* @param error A pre-formatted MSBuild error.
*/
interface IErrorPrinter {
(error: string): void;
}

/**
* Prints MSBuild errors from the TSLint CLI with a severity level.
*/
export class ErrorsPrinter {
/**
* MSBuild error printers, keyed by severity level.
*/
private errorPrinters: IErrorPrinters = {
error: (error: string): void => console.error(error),
warning: (error: string): void => console.warn(error)
};

/**
* Overridden severity level for errors, if provided.
*/
private severityOverride: string;

/**
* Initializes a new instance of the ErrorsPrinter class.
*
* @param severityOverride Overridden severity level for errors, if provided.
*/
public constructor(severityOverride?: string) {
this.severityOverride = severityOverride;
}

/**
* Prints MSBuild errors.
*
* @param errors MSBuild errors.
*/
public print(errors: string[]): void {
for (const error of errors) {
this.printError(error);
}
}

/**
* Prints an MSBuild error.
*
* @param error An MSBuild error.
*/
public printError(error: string): void {
const errorSeverity = this.getSeverityFromError(error);

if (this.severityOverride && this.severityOverride !== errorSeverity) {
error = this.replaceErrorSeverity(error, errorSeverity, this.severityOverride);
}

const severity = this.severityOverride || errorSeverity;
const printer = this.errorPrinters[severity];

if (!printer) {
throw new Error(`Unknown error severity: '${severity}'.`);
}

printer(error);
}

/**
* @param error An MSBuild error.
* @returns The error's severity.
*/
private getSeverityFromError(error: string): string {
return error
.match(/\):\s.+:/)
[0]
.replace(/\W/g, "");
}

/**
* Replaces an error's severity with a new severity.
*
* @param error An MSBuild error.
* @param originalSeverity The current severity level of the error.
* @param newSeverity A new severity level for the error.
* @returns A copy of the error with thenew severity level.
*/
private replaceErrorSeverity(error: string, originalSeverity: string, newSeverity: string): string {
return error.replace(
this.wrapErrorFormat(originalSeverity),
this.wrapErrorFormat(newSeverity));
}

/**
* Wraps a severity string with find-and-replace safe markers.
*
* @param severity A severity level.
* @returns The severity with find-and-replace safe markers.
*/
private wrapErrorFormat(severity: string): string {
return `): ${severity}`;
}
}
13 changes: 9 additions & 4 deletions src/LintRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class LintRunner {
*
* @returns A promise for TSLint errors, in alphabetical order of file path.
*/
public runTSLint(): Promise<string> {
public runTSLint(): Promise<string[]> {
const linter: ChildProcess = this.runSpawn(
"node",
[
Expand All @@ -50,11 +50,16 @@ export class LintRunner {
"msbuild",
...this.filePaths
]);
let errors: string = "";
let errors: string[] = [];

return new Promise((resolve: (errors: string) => void, reject: (error: string) => void): void => {
return new Promise((resolve: (errors: string[]) => void, reject: (error: string) => void): void => {
linter.stdout.on("data", (data: Buffer): void => {
errors += data.toString();
errors.push(
...data
.toString()
.replace(/\r/g, "")
.split(/\n/g)
.filter((error: string): boolean => !!error));
});

linter.stderr.on("data", (data: Buffer): void => {
Expand Down
3 changes: 2 additions & 1 deletion src/TSLint.MSBuild.targets
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<TSLintBreakBuildOnError Condition="'$(TSLintBreakBuildOnError)' == ''">false</TSLintBreakBuildOnError>
<TSLintConfig Condition="'$(TSLintConfig)' == ''"></TSLintConfig>
<TSLintDeleteFileListFile Condition="'$(TSLintDeleteFileListFile)' == ''">true</TSLintDeleteFileListFile>
<TSLintErrorSeverity Condition="'$(TSLintErrorSeverity)' == ''"></TSLintErrorSeverity>
<TSLintExclude Condition="'$(TSLintExclude)' == ''"></TSLintExclude>
<TSLintFilesRootDir Condition="'$(TSLintFilesRootDir)' == ''">$(MSBuildProjectDirectory)</TSLintFilesRootDir>
<TSLintFileListDir Condition="'$(TSLintFileListDir)' == ''">$(IntermediateOutDir)</TSLintFileListDir>
Expand All @@ -36,7 +37,7 @@

<!-- Run TSLint via the runner -->
<Exec
Command="&quot;$(TSLintNodeExe)&quot; --harmony --harmony_modules &quot;$(TSLintRunnerScript)&quot; --config &quot;$(TSLintConfig)&quot; --exclude &quot;$(TSLintExclude)&quot; --file-list-file &quot;$(TSLintFileListFile)&quot; --files-root-dir &quot;$(TSLintFilesRootDir)&quot; --rules-directory &quot;$(TSLintRulesDirectory)&quot;"
Command="&quot;$(TSLintNodeExe)&quot; --harmony --harmony_modules &quot;$(TSLintRunnerScript)&quot; --config &quot;$(TSLintConfig)&quot; --error-severity &quot;$(TSLintErrorSeverity)&quot; --exclude &quot;$(TSLintExclude)&quot; --file-list-file &quot;$(TSLintFileListFile)&quot; --files-root-dir &quot;$(TSLintFilesRootDir)&quot; --rules-directory &quot;$(TSLintRulesDirectory)&quot;"
IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
Expand Down
12 changes: 4 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ console.log("Starting TSLint runner.");
import * as fs from "fs";
import * as path from "path";
import { ArgumentsCollection } from "./ArgumentsCollection";
import { ErrorsPrinter } from "./ErrorsPrinter";
import { LintRunner } from "./LintRunner";

/**
Expand Down Expand Up @@ -33,14 +34,9 @@ function getInputFilesList(filePath): string[] {
console.log(`Running TSLint on ${filePaths.length} file(s).`);

runner.runTSLint()
.then(lintErrors => {
const numErrors = lintErrors.match(/\n/g).length;

if (numErrors !== 0) {
console.error(lintErrors);
}

console.log(`${numErrors} error(s) found in ${filePaths.length} file(s).`);
.then((lintErrors: string[]): void => {
console.log(`${lintErrors.length} error(s) found in ${filePaths.length} file(s).`);
new ErrorsPrinter(argumentsCollection.getErrorSeverity()).print(lintErrors);
})
.catch(error => {
console.error("Error running TSLint!");
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"files": [
"src/ArgumentsCollection.ts",
"src/ErrorsPrinter.ts",
"src/index.ts",
"src/LintRunner.ts",
"src/TSLintSearcher.ts"
Expand Down

0 comments on commit f4ce855

Please sign in to comment.