Skip to content

Commit

Permalink
Support for ERROR & WARN per rule (palantir#1738)
Browse files Browse the repository at this point in the history
  • Loading branch information
olore authored and nchen63 committed Mar 1, 2017
1 parent 127d0fd commit fd54825
Show file tree
Hide file tree
Showing 51 changed files with 500 additions and 202 deletions.
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
Change Log
===

<!--
v5.0.0
---
* **BREAKING CHANGES**
* The severity level is now configurable, and defaults to severity "error"
* The following formatters have change output:
- msbuildFormatter - default was "warning"; it is now "error"
- pmdFormatter - default was priority 1; it is now "error" (priority 3). If set to "warning", it will output priority 4
* [enhancement] Enable WARN with new config file format (#629, #345)
* Valid values for `severity`: "error|warn|warning|none|off"
* Old style
* ```{
"extends": "tslint:latest",
"rules": {
"callable-types": true
}
}``
* New style, with `interface-name` generating warnings, and passing options to `max-line-length`
* ``` {
"extends": "tslint:latest",
"rules": {
"callable-types": true,
"interface-name": {
"severity": "warn"
},
"max-line-length": {
"options": 140,
"severity": "warning"
}
}
}``
-->

v4.5.1
---

Expand Down
6 changes: 3 additions & 3 deletions docs/_data/formatters.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
"formatterName": "pmd",
"description": "Formats errors as through they were PMD output.",
"descriptionDetails": "Imitates the XML output from PMD. All errors have a priority of 1.",
"sample": "\n<pmd version=\"tslint\">\n <file name=\"myFile.ts\">\n <violation begincolumn=\"14\" beginline=\"1\" priority=\"1\" rule=\"Missing semicolon\"></violation>\n </file>\n</pmd>",
"sample": "\n<pmd version=\"tslint\">\n <file name=\"myFile.ts\">\n <violation begincolumn=\"14\" beginline=\"1\" priority=\"3\" rule=\"Missing semicolon\"></violation>\n </file>\n</pmd>",
"consumer": "machine"
},
{
"formatterName": "prose",
"description": "The default formatter which outputs simple human-readable messages.",
"sample": "myFile.ts[1, 14]: Missing semicolon",
"sample": "ERROR: myFile.ts[1, 14]: Missing semicolon",
"consumer": "human"
},
{
Expand All @@ -56,7 +56,7 @@
"formatterName": "verbose",
"description": "The human-readable formatter which includes the rule name in messages.",
"descriptionDetails": "The output is the same as the prose formatter with the rule name included",
"sample": "(semicolon) myFile.ts[1, 14]: Missing semicolon",
"sample": "ERROR: (semicolon) myFile.ts[1, 14]: Missing semicolon",
"consumer": "human"
},
{
Expand Down
2 changes: 1 addition & 1 deletion docs/formatters/pmd/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<pmd version="tslint">
<file name="myFile.ts">
<violation begincolumn="14" beginline="1" priority="1" rule="Missing semicolon"></violation>
<violation begincolumn="14" beginline="1" priority="3" rule="Missing semicolon"></violation>
</file>
</pmd>
consumer: machine
Expand Down
2 changes: 1 addition & 1 deletion docs/formatters/prose/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
formatterName: prose
description: The default formatter which outputs simple human-readable messages.
sample: 'myFile.ts[1, 14]: Missing semicolon'
sample: 'ERROR: myFile.ts[1, 14]: Missing semicolon'
consumer: human
layout: formatter
title: 'Formatter: prose'
Expand Down
2 changes: 1 addition & 1 deletion docs/formatters/verbose/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
formatterName: verbose
description: The human-readable formatter which includes the rule name in messages.
descriptionDetails: The output is the same as the prose formatter with the rule name included
sample: '(semicolon) myFile.ts[1, 14]: Missing semicolon'
sample: 'ERROR: (semicolon) myFile.ts[1, 14]: Missing semicolon'
consumer: human
layout: formatter
title: 'Formatter: verbose'
Expand Down
33 changes: 29 additions & 4 deletions src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as path from "path";
import * as resolve from "resolve";
import { FatalError } from "./error";

import {arrayify, objectify, stripComments} from "./utils";
import { arrayify, objectify, stripComments } from "./utils";

export interface IConfigurationFile {
extends?: string | string[];
Expand All @@ -39,11 +39,9 @@ export interface IConfigurationLoadResult {
}

export const CONFIG_FILENAME = "tslint.json";
/* tslint:disable:object-literal-key-quotes */
export const DEFAULT_CONFIG = {
"extends": "tslint:recommended",
extends: "tslint:recommended",
};
/* tslint:enable:object-literal-key-quotes */

const BUILT_IN_CONFIG = /^tslint:(.*)$/;

Expand Down Expand Up @@ -244,3 +242,30 @@ export function getRulesDirectories(directories?: string | string[], relativeTo?

return rulesDirectories;
}

export function isRuleEnabled(ruleConfigValue: any): boolean {
if (typeof ruleConfigValue === "boolean") {
return ruleConfigValue;
}

if (Array.isArray(ruleConfigValue) && ruleConfigValue.length > 0) {
return ruleConfigValue[0];
}

if (ruleConfigValue.severity !== "off" && ruleConfigValue.severity !== "none") {
return true;
}

return false;
}

export function getRuleSeverity(ruleConfigValue: any) {
if (ruleConfigValue.severity &&
(ruleConfigValue.severity.toLowerCase() === "warn" ||
ruleConfigValue.severity.toLowerCase() === "warning")) {

return "warning";
}

return "error";
}
4 changes: 2 additions & 2 deletions src/enableDisableRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import * as utils from "tsutils";
import * as ts from "typescript";

import {AbstractRule} from "./language/rule/abstractRule";
import {isRuleEnabled} from "./configuration";
import {IEnableDisablePosition} from "./ruleLoader";

export class EnableDisableRulesWalker {
Expand All @@ -30,7 +30,7 @@ export class EnableDisableRulesWalker {
this.enabledRules = [];
if (rules) {
for (const rule of Object.keys(rules)) {
if (AbstractRule.isRuleEnabled(rules[rule])) {
if (isRuleEnabled(rules[rule])) {
this.enabledRules.push(rule);
this.enableDisableRuleMap[rule] = [{
isEnabled: true,
Expand Down
5 changes: 3 additions & 2 deletions src/formatters/checkstyleFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import {AbstractFormatter} from "../language/formatter/abstractFormatter";
import {IFormatterMetadata} from "../language/formatter/formatter";
import {RuleFailure} from "../language/rule/rule";
import { RuleFailure } from "../language/rule/rule";

import * as Utils from "../utils";

Expand Down Expand Up @@ -48,6 +48,7 @@ export class Formatter extends AbstractFormatter {
});
let previousFilename: string | null = null;
for (const failure of failuresSorted) {
const severity = failure.getRuleSeverity();
if (failure.getFileName() !== previousFilename) {
if (previousFilename) {
output += "</file>";
Expand All @@ -57,7 +58,7 @@ export class Formatter extends AbstractFormatter {
}
output += "<error line=\"" + (failure.getStartPosition().getLineAndCharacter().line + 1) + "\" ";
output += "column=\"" + (failure.getStartPosition().getLineAndCharacter().character + 1) + "\" ";
output += "severity=\"warning\" ";
output += "severity=\"" + severity + "\" ";
output += "message=\"" + this.escapeXml(failure.getFailure()) + "\" ";
// checkstyle parser wants "source" to have structure like <anything>dot<category>dot<type>
output += "source=\"failure.tslint." + this.escapeXml(failure.getRuleName()) + "\" />";
Expand Down
5 changes: 3 additions & 2 deletions src/formatters/msbuildFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import {AbstractFormatter} from "../language/formatter/abstractFormatter";
import {IFormatterMetadata} from "../language/formatter/formatter";
import {RuleFailure} from "../language/rule/rule";
import { RuleFailure } from "../language/rule/rule";

import {camelize, dedent} from "../utils";

Expand All @@ -42,8 +42,9 @@ export class Formatter extends AbstractFormatter {

const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const positionTuple = `(${lineAndCharacter.line + 1},${lineAndCharacter.character + 1})`;
const severity = failure.getRuleSeverity();

return `${fileName}${positionTuple}: warning ${camelizedRule}: ${failureString}`;
return `${fileName}${positionTuple}: ${severity} ${camelizedRule}: ${failureString}`;
});

return outputLines.join("\n") + "\n";
Expand Down
7 changes: 4 additions & 3 deletions src/formatters/pmdFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import {AbstractFormatter} from "../language/formatter/abstractFormatter";
import {IFormatterMetadata} from "../language/formatter/formatter";
import {RuleFailure} from "../language/rule/rule";
import { RuleFailure } from "../language/rule/rule";

import * as Utils from "../utils";

Expand All @@ -30,7 +30,7 @@ export class Formatter extends AbstractFormatter {
sample: Utils.dedent`
<pmd version="tslint">
<file name="myFile.ts">
<violation begincolumn="14" beginline="1" priority="1" rule="Missing semicolon"></violation>
<violation begincolumn="14" beginline="1" priority="3" rule="Missing semicolon"></violation>
</file>
</pmd>`,
consumer: "machine",
Expand All @@ -49,11 +49,12 @@ export class Formatter extends AbstractFormatter {
.replace(/"/g, "&quot;");

const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const priority = failure.getRuleSeverity() === "warning" ? 4 : 3;

output += "<file name=\"" + failure.getFileName();
output += "\"><violation begincolumn=\"" + (lineAndCharacter.character + 1);
output += "\" beginline=\"" + (lineAndCharacter.line + 1);
output += "\" priority=\"1\"";
output += "\" priority=\"" + priority + "\"";
output += " rule=\"" + failureString + "\"> </violation></file>";
}

Expand Down
6 changes: 3 additions & 3 deletions src/formatters/proseFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ export class Formatter extends AbstractFormatter {
public static metadata: IFormatterMetadata = {
formatterName: "prose",
description: "The default formatter which outputs simple human-readable messages.",
sample: "myFile.ts[1, 14]: Missing semicolon",
sample: "ERROR: myFile.ts[1, 14]: Missing semicolon",
consumer: "human",
};
/* tslint:enable:object-literal-sort-keys */

public format(failures: RuleFailure[], fixes?: RuleFailure[]): string {
if (failures.length === 0 && (!fixes || fixes.length === 0)) {
return "";
return "\n";
}

const fixLines: string[] = [];
Expand All @@ -54,7 +54,7 @@ export class Formatter extends AbstractFormatter {
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const positionTuple = `[${lineAndCharacter.line + 1}, ${lineAndCharacter.character + 1}]`;

return `${fileName}${positionTuple}: ${failureString}`;
return `${failure.getRuleSeverity().toUpperCase()}: ${fileName}${positionTuple}: ${failureString}`;
});

return fixLines.concat(errorLines).join("\n") + "\n";
Expand Down
35 changes: 22 additions & 13 deletions src/formatters/stylishFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import {AbstractFormatter} from "../language/formatter/abstractFormatter";
import {IFormatterMetadata} from "../language/formatter/formatter";
import {RuleFailure} from "../language/rule/rule";
import { RuleFailure } from "../language/rule/rule";

import * as colors from "colors";

Expand All @@ -39,10 +39,20 @@ export class Formatter extends AbstractFormatter {
/* tslint:enable:object-literal-sort-keys */

public format(failures: RuleFailure[]): string {
if (typeof failures[0] === "undefined") {
return "\n";
const outputLines = this.mapToMessages(failures);

// Removes initial blank line
if (outputLines[0] === "") {
outputLines.shift();
}

return outputLines.join("\n") + "\n";
}

private mapToMessages(failures: RuleFailure[]): string[] {
if (!failures) {
return [];
}
const outputLines: string[] = [];
const positionMaxSize = this.getPositionMaxSize(failures);
const ruleMaxSize = this.getRuleMaxSize(failures);
Expand Down Expand Up @@ -71,21 +81,20 @@ export class Formatter extends AbstractFormatter {
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();

let positionTuple = `${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`;
positionTuple = this.pad(positionTuple, positionMaxSize);
positionTuple = colors.red(positionTuple);
positionTuple = this.pad(positionTuple, positionMaxSize);

// Ouput
if (failure.getRuleSeverity() === "warning") {
positionTuple = colors.blue(failure.getRuleSeverity().toUpperCase() + ": " + positionTuple);
} else {
positionTuple = colors.red(failure.getRuleSeverity().toUpperCase() + ": " + positionTuple);
}

// Output
const output = `${positionTuple} ${ruleName} ${failureString}`;

outputLines.push(output);
}

// Removes initial blank line
if (outputLines[0] === "") {
outputLines.shift();
}

return outputLines.join("\n") + "\n\n";
return outputLines;
}

private pad(str: string, len: number): string {
Expand Down
15 changes: 10 additions & 5 deletions src/formatters/verboseFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,36 @@

import {AbstractFormatter} from "../language/formatter/abstractFormatter";
import {IFormatterMetadata} from "../language/formatter/formatter";
import {RuleFailure} from "../language/rule/rule";
import { RuleFailure } from "../language/rule/rule";

export class Formatter extends AbstractFormatter {
/* tslint:disable:object-literal-sort-keys */
public static metadata: IFormatterMetadata = {
formatterName: "verbose",
description: "The human-readable formatter which includes the rule name in messages.",
descriptionDetails: "The output is the same as the prose formatter with the rule name included",
sample: "(semicolon) myFile.ts[1, 14]: Missing semicolon",
sample: "ERROR: (semicolon) myFile.ts[1, 14]: Missing semicolon",
consumer: "human",
};
/* tslint:enable:object-literal-sort-keys */

public format(failures: RuleFailure[]): string {
const outputLines = failures.map((failure: RuleFailure) => {

return this.mapToMessages(failures)
.join("\n") + "\n";
}

private mapToMessages(failures: RuleFailure[]): string[] {
return failures.map((failure: RuleFailure) => {
const fileName = failure.getFileName();
const failureString = failure.getFailure();
const ruleName = failure.getRuleName();

const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const positionTuple = "[" + (lineAndCharacter.line + 1) + ", " + (lineAndCharacter.character + 1) + "]";

return `(${ruleName}) ${fileName}${positionTuple}: ${failureString}`;
return `${failure.getRuleSeverity().toUpperCase()}: (${ruleName}) ${fileName}${positionTuple}: ${failureString}`;
});

return outputLines.join("\n") + "\n";
}
}
6 changes: 4 additions & 2 deletions src/formatters/vsoFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ export class Formatter extends AbstractFormatter {
};
/* tslint:enable:object-literal-sort-keys */

public format(failures: RuleFailure[]): string {
const outputLines = failures.map((failure: RuleFailure) => {
public format(failures: RuleFailure[], warnings: RuleFailure[] = []): string {
const all = failures.concat(warnings);

const outputLines = all.map((failure: RuleFailure) => {
const fileName = failure.getFileName();
const failureString = failure.getFailure();
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export * from "./language/walker";
export * from "./language/formatter/formatter";

export interface LintResult {
failureCount: number;
errorCount: number;
warningCount: number;
failures: RuleFailure[];
fixes?: RuleFailure[];
format: string | FormatterFunction;
Expand Down
Loading

0 comments on commit fd54825

Please sign in to comment.