add eslint

This commit is contained in:
Alexander T 2019-06-13 13:37:14 +03:00
parent 74c6bc1f85
commit 55b8a38d50
18 changed files with 145 additions and 734 deletions

3
.eslintignore Normal file
View file

@ -0,0 +1,3 @@
/built/local/**
/tests/**
/lib/**

121
.eslintrc Normal file
View file

@ -0,0 +1,121 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"warnOnUnsupportedTypeScriptVersion": false,
"ecmaVersion": 6,
"sourceType": "module",
"project": "./src/tsconfig-base.json"
},
"env": {
"browser": false,
"node": true,
"es6": true
},
"plugins": [
"@typescript-eslint", "microsoft-typescript"
],
"rules": {
"@typescript-eslint/adjacent-overload-signatures": "off",
"@typescript-eslint/array-type": "off",
"@typescript-eslint/ban-types": "off",
"camelcase": "off",
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/class-name-casing": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/import/order": "off",
"indent": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/no-angle-bracket-type-assertion": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-object-literal-type-assertion": "off",
"@typescript-eslint/no-parameter-properties": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/no-triple-slash-reference": "off",
"@typescript-eslint/no-unnecessary-qualifier": "off",
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "off",
"@typescript-eslint/prefer-interface": "off",
"@typescript-eslint/prefer-namespace-keyword": "off",
"semi": "off",
"@typescript-eslint/semi": "off",
"@typescript-eslint/type-annotation-spacing": "off",
"@typescript-eslint/unified-signatures": "off",
"microsoft-typescript/object-literal-surrounding-space": "off",
"microsoft-typescript/no-type-assertion-whitespace": "error",
"microsoft-typescript/type-operator-spacing": "off",
"microsoft-typescript/only-arrow-functions": "off",
"microsoft-typescript/no-double-space": "off",
"microsoft-typescript/boolean-trivia": "off",
"microsoft-typescript/no-in-operator": "off",
"microsoft-typescript/debug-assert": "off",
"microsoft-typescript/no-keywords": "off",
"arrow-body-style": "off",
"arrow-parens": "off",
"brace-style": "off",
"comma-dangle": "off",
"complexity": "off",
"constructor-super": "error",
"curly": ["error", "multi-line"],
"dot-notation": "off",
"eol-last": "off",
"eqeqeq": "error",
"guard-for-in": "off",
"linebreak-style": "off",
"max-classes-per-file": "off",
"max-len": "off",
"new-parens": "error",
"no-bitwise": "off",
"no-caller": "error",
"no-cond-assign": "off",
"no-console": "off",
"no-debugger": "off",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-empty": "off",
"no-eval": "off",
"no-extra-bind": "error",
"no-fallthrough": "off",
"no-invalid-this": "off",
"no-multiple-empty-lines": "off",
"no-new-func": "off",
"no-new-wrappers": "error",
"no-redeclare": "off",
"no-return-await": "error",
"no-restricted-globals": "off",
"no-sequences": "off",
"no-shadow": "off",
"no-sparse-arrays": "error",
"no-template-curly-in-string": "off",
"no-throw-literal": "off",
"no-trailing-spaces": "off",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "off",
"no-unused-labels": "error",
"no-var": "off",
"object-shorthand": "off",
"one-var": "off",
"prefer-const": "off",
"prefer-object-spread": "error",
"quote-props": ["error", "consistent-as-needed"],
"quotes": "off",
"radix": "off",
"sort-keys": "off",
"space-before-function-paren": "off",
"space-in-parens": "off",
"unicode-bom": ["error", "never"],
"use-isnan": "error",
"valid-typeof": "off"
}
}

View file

@ -318,34 +318,23 @@ task("clean-tests").description = "Cleans the outputs for the test infrastructur
const watchTests = () => watchProject("src/testRunner", cmdLineOptions);
const buildRules = () => buildProject("scripts/tslint");
task("build-rules", buildRules);
task("build-rules").description = "Compiles tslint rules to js";
const cleanRules = () => cleanProject("scripts/tslint");
cleanTasks.push(cleanRules);
task("clean-rules", cleanRules);
task("clean-rules").description = "Cleans the outputs for the lint rules";
const lintFoldStart = async () => { if (fold.isTravis()) console.log(fold.start("lint")); };
const lintFoldEnd = async () => { if (fold.isTravis()) console.log(fold.end("lint")); };
const lint = series([
lintFoldStart,
...["scripts/tslint/tsconfig.json", "src/tsconfig-base.json"].map(project => {
const lintOne = () => {
const args = ["node_modules/tslint/bin/tslint", "--project", project, "--formatters-dir", "./built/local/tslint/formatters", "--format", "autolinkableStylish"];
if (cmdLineOptions.fix) args.push("--fix");
log(`Linting: node ${args.join(" ")}`);
return exec(process.execPath, args);
};
lintOne.dispayName = `lint(${project})`;
return lintOne;
}),
lintFoldEnd
]);
const eslint = async () => {
const args = [
"node_modules/eslint/bin/eslint", "-f", "autolinkable-stylish", "-c", ".eslintrc", "--ext", ".ts", "."
];
if (cmdLineOptions.fix) {
args.push("--fix");
}
log(`Linting: ${args.join(" ")}`);
return exec(process.execPath, args);
}
const lint = series([lintFoldStart, eslint, lintFoldEnd]);
lint.displayName = "lint";
task("lint", series(buildRules, lint));
task("lint").description = "Runs tslint on the compiler sources.";
task("lint", lint);
task("lint").description = "Runs eslint on the compiler sources.";
task("lint").flags = {
" --f[iles]=<regex>": "pattern to match files to lint",
};
@ -393,7 +382,7 @@ const generateCodeCoverage = () => exec("istanbul", ["cover", "node_modules/moch
task("generate-code-coverage", series(preBuild, buildTests, generateCodeCoverage));
task("generate-code-coverage").description = "Generates code coverage data via istanbul";
const preTest = parallel(buildRules, buildTests, buildServices, buildLssl);
const preTest = parallel(buildTests, buildServices, buildLssl);
preTest.displayName = "preTest";
const postTest = (done) => cmdLineOptions.lint ? lint(done) : done();

View file

@ -82,7 +82,7 @@ gulp runtests # Run tests using the built compiler and test infrastructu
# You can override the host or specify a test for this command.
# Use --host=<hostName> or --tests=<testPath>.
gulp baseline-accept # This replaces the baseline test results with the results obtained from gulp runtests.
gulp lint # Runs tslint on the TypeScript source.
gulp lint # Runs eslint on the TypeScript source.
gulp help # List the above commands.
```

View file

@ -54,6 +54,8 @@
"@types/through2": "latest",
"@types/travis-fold": "latest",
"@types/xml2js": "^0.4.0",
"@typescript-eslint/eslint-plugin": "latest",
"@typescript-eslint/parser": "latest",
"azure-devops-node-api": "^8.0.0",
"browser-resolve": "^1.11.2",
"browserify": "latest",
@ -61,6 +63,9 @@
"chalk": "latest",
"convert-source-map": "latest",
"del": "latest",
"eslint": "latest",
"eslint-formatter-autolinkable-stylish": "latest",
"eslint-plugin-microsoft-typescript": "0.1.11",
"fancy-log": "latest",
"fs-extra": "^6.0.1",
"gulp": "^4.0.0",
@ -85,7 +90,6 @@
"source-map-support": "latest",
"through2": "latest",
"travis-fold": "latest",
"tslint": "latest",
"typescript": "next",
"vinyl": "latest",
"vinyl-sourcemaps-apply": "latest",

View file

@ -1,97 +0,0 @@
import * as Lint from "tslint";
import chalk from "chalk";
import { sep } from "path";
function groupBy<T>(array: ReadonlyArray<T> | undefined, getGroupId: (elem: T, index: number) => number | string): T[][] {
if (!array) {
return [];
}
const groupIdToGroup: { [index: string]: T[] } = {};
let result: T[][] | undefined; // Compacted array for return value
for (let index = 0; index < array.length; index++) {
const value = array[index];
const key = getGroupId(value, index);
if (groupIdToGroup[key]) {
groupIdToGroup[key].push(value);
}
else {
const newGroup = [value];
groupIdToGroup[key] = newGroup;
if (!result) {
result = [newGroup];
}
else {
result.push(newGroup);
}
}
}
return result || [];
}
function max<T>(array: ReadonlyArray<T> | undefined, selector: (elem: T) => number): number {
if (!array) {
return 0;
}
let max = 0;
for (const item of array) {
const scalar = selector(item);
if (scalar > max) {
max = scalar;
}
}
return max;
}
function getLink(failure: Lint.RuleFailure, color: boolean): string {
const lineAndCharacter = failure.getStartPosition().getLineAndCharacter();
const sev = failure.getRuleSeverity().toUpperCase();
let path = failure.getFileName();
// Most autolinks only become clickable if they contain a slash in some way; so we make a top level file into a relative path here
if (path.indexOf("/") === -1 && path.indexOf("\\") === -1) {
path = `.${sep}${path}`;
}
return `${color ? (sev === "WARNING" ? chalk.blue(sev) : chalk.red(sev)) : sev}: ${path}:${lineAndCharacter.line + 1}:${lineAndCharacter.character + 1}`;
}
function getLinkMaxSize(failures: Lint.RuleFailure[]): number {
return max(failures, f => getLink(f, /*color*/ false).length);
}
function getNameMaxSize(failures: Lint.RuleFailure[]): number {
return max(failures, f => f.getRuleName().length);
}
function pad(str: string, visiblelen: number, len: number) {
if (visiblelen >= len) return str;
const count = len - visiblelen;
for (let i = 0; i < count; i++) {
str += " ";
}
return str;
}
export class Formatter extends Lint.Formatters.AbstractFormatter {
public static metadata: Lint.IFormatterMetadata = {
formatterName: "autolinkableStylish",
description: "Human-readable formatter which creates stylish messages with autolinkable filepaths.",
descriptionDetails: Lint.Utils.dedent`
Colorized output grouped by file, with autolinkable filepaths containing line and column information
`,
sample: Lint.Utils.dedent`
src/myFile.ts
ERROR: src/myFile.ts:1:14 semicolon Missing semicolon`,
consumer: "human"
};
public format(failures: Lint.RuleFailure[]): string {
return groupBy(failures, f => f.getFileName()).map(group => {
const currentFile = group[0].getFileName();
const linkMaxSize = getLinkMaxSize(group);
const nameMaxSize = getNameMaxSize(group);
return `
${currentFile}
${group.map(f => `${pad(getLink(f, /*color*/ true), getLink(f, /*color*/ false).length, linkMaxSize)} ${chalk.grey(pad(f.getRuleName(), f.getRuleName().length, nameMaxSize))} ${chalk.yellow(f.getFailure())}`).join("\n")}`;
}).join("\n");
}
}

View file

@ -1,93 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
}
}
function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
ts.forEachChild(sourceFile, function recur(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.CallExpression) {
checkCall(node as ts.CallExpression);
}
ts.forEachChild(node, recur);
});
function checkCall(node: ts.CallExpression): void {
if (!shouldIgnoreCalledExpression(node.expression)) {
for (const arg of node.arguments) {
checkArg(arg);
}
}
}
/** Skip certain function/method names whose parameter names are not informative. */
function shouldIgnoreCalledExpression(expression: ts.Expression): boolean {
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
const methodName = (expression as ts.PropertyAccessExpression).name.text;
if (methodName.startsWith("set") || methodName.startsWith("assert")) {
return true;
}
switch (methodName) {
case "apply":
case "call":
case "equal":
case "fail":
case "isTrue":
case "output":
case "stringify":
return true;
}
}
else if (expression.kind === ts.SyntaxKind.Identifier) {
const functionName = (expression as ts.Identifier).text;
if (functionName.startsWith("set") || functionName.startsWith("assert")) {
return true;
}
switch (functionName) {
case "contains":
case "createAnonymousType":
case "createImportSpecifier":
case "createProperty":
case "createSignature":
case "resolveName":
return true;
}
}
return false;
}
function checkArg(arg: ts.Expression): void {
if (!isTrivia(arg)) {
return;
}
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
ctx.addFailureAtNode(arg, "Tag argument with parameter name");
return;
}
const range = ranges[0];
const argStart = arg.getStart(sourceFile);
if (range.end + 1 !== argStart && sourceFile.text.slice(range.end, argStart).indexOf("\n") === -1) {
ctx.addFailureAtNode(arg, "There should be 1 space between an argument and its comment.");
}
}
function isTrivia(arg: ts.Expression): boolean {
switch (arg.kind) {
case ts.SyntaxKind.TrueKeyword:
case ts.SyntaxKind.FalseKeyword:
case ts.SyntaxKind.NullKeyword:
return true;
case ts.SyntaxKind.Identifier:
return (arg as ts.Identifier).originalKeywordKind === ts.SyntaxKind.UndefinedKeyword;
default:
return false;
}
}
}

View file

@ -1,45 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, function recur(node) {
if (ts.isCallExpression(node)) {
checkCall(node);
}
ts.forEachChild(node, recur);
});
function checkCall(node: ts.CallExpression) {
if (!isDebugAssert(node.expression) || node.arguments.length < 2) {
return;
}
const message = node.arguments[1];
if (!ts.isStringLiteral(message)) {
ctx.addFailureAtNode(message, "Second argument to 'Debug.assert' should be a string literal.");
}
if (node.arguments.length < 3) {
return;
}
const message2 = node.arguments[2];
if (!ts.isStringLiteral(message2) && !ts.isArrowFunction(message2)) {
ctx.addFailureAtNode(message, "Third argument to 'Debug.assert' should be a string literal or arrow function.");
}
}
function isDebugAssert(expr: ts.Node): boolean {
return ts.isPropertyAccessExpression(expr) && isName(expr.expression, "Debug") && isName(expr.name, "assert");
}
function isName(expr: ts.Node, text: string): boolean {
return ts.isIdentifier(expr) && expr.text === text;
}
}

View file

@ -1,67 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
const OPTION_CATCH = "check-catch";
const OPTION_ELSE = "check-else";
export class Rule extends Lint.Rules.AbstractRule {
public static CATCH_FAILURE_STRING = "'catch' should not be on the same line as the preceeding block's curly brace";
public static ELSE_FAILURE_STRING = "'else' should not be on the same line as the preceeding block's curly brace";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
const options = this.getOptions().ruleArguments;
const checkCatch = options.indexOf(OPTION_CATCH) !== -1;
const checkElse = options.indexOf(OPTION_ELSE) !== -1;
return this.applyWithFunction(sourceFile, ctx => walk(ctx, checkCatch, checkElse));
}
}
function walk(ctx: Lint.WalkContext<void>, checkCatch: boolean, checkElse: boolean): void {
const { sourceFile } = ctx;
ts.forEachChild(sourceFile, function recur(node) {
switch (node.kind) {
case ts.SyntaxKind.IfStatement:
checkIf(node as ts.IfStatement);
break;
case ts.SyntaxKind.TryStatement:
checkTry(node as ts.TryStatement);
break;
}
ts.forEachChild(node, recur);
});
function checkIf(node: ts.IfStatement): void {
const { thenStatement, elseStatement } = node;
if (!elseStatement) {
return;
}
// find the else keyword
const elseKeyword = getFirstChildOfKind(node, ts.SyntaxKind.ElseKeyword);
if (checkElse && !!elseKeyword) {
const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
if (thenStatementEndLoc.line === elseKeywordLoc.line) {
ctx.addFailureAtNode(elseKeyword, Rule.ELSE_FAILURE_STRING);
}
}
}
function checkTry({ tryBlock, catchClause }: ts.TryStatement): void {
if (!checkCatch || !catchClause) {
return;
}
const tryClosingBrace = tryBlock.getLastToken(sourceFile)!;
const catchKeyword = catchClause.getFirstToken(sourceFile)!;
const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
ctx.addFailureAtNode(catchKeyword, Rule.CATCH_FAILURE_STRING);
}
}
}
function getFirstChildOfKind(node: ts.Node, kind: ts.SyntaxKind) {
return node.getChildren().filter((child) => child.kind === kind)[0];
}

View file

@ -1,16 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "This file has a BOM.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
if (ctx.sourceFile.text[0] === "\ufeff") {
ctx.addFailure(0, 1, Rule.FAILURE_STRING);
}
}

View file

@ -1,54 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
const lines = sourceFile.text.split("\n");
const strings = getLiterals(sourceFile);
lines.forEach((line, idx) => {
// Skip indentation.
const firstNonSpace = /\S/.exec(line);
if (firstNonSpace === null) {
return;
}
// Allow common uses of double spaces
// * To align `=` or `!=` signs
// * To align comments at the end of lines
// * To indent inside a comment
// * To use two spaces after a period
// * To include aligned `->` in a comment
const rgx = /[^/*. ] [^-!/= ]/g;
rgx.lastIndex = firstNonSpace.index;
const doubleSpace = rgx.exec(line);
// Also allow to align comments after `@param`
if (doubleSpace !== null && !line.includes("@param")) {
const pos = lines.slice(0, idx).reduce((len, line) => len + 1 + line.length, 0) + doubleSpace.index;
if (!strings.some(s => s.getStart() <= pos && s.end > pos)) {
ctx.addFailureAt(pos + 1, 2, "Use only one space.");
}
}
});
}
function getLiterals(sourceFile: ts.SourceFile): ReadonlyArray<ts.Node> {
const out: ts.Node[] = [];
sourceFile.forEachChild(function cb(node) {
switch (node.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.TemplateHead:
case ts.SyntaxKind.TemplateMiddle:
case ts.SyntaxKind.TemplateTail:
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.RegularExpressionLiteral:
out.push(node);
}
node.forEachChild(cb);
});
return out;
}

View file

@ -1,19 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "Don't use the 'in' keyword - use 'hasProperty' to check for key presence instead";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, recur);
function recur(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.InKeyword && node.parent.kind === ts.SyntaxKind.BinaryExpression) {
ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
}
}
}

View file

@ -1,55 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static POSTFIX_FAILURE_STRING = "Don't use '++' or '--' postfix operators outside statements or for loops.";
public static PREFIX_FAILURE_STRING = "Don't use '++' or '--' prefix operators.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, recur);
function recur(node: ts.Node): void {
switch (node.kind) {
case ts.SyntaxKind.PrefixUnaryExpression:
const { operator } = node as ts.PrefixUnaryExpression;
if (operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken) {
check(node as ts.PrefixUnaryExpression);
}
break;
case ts.SyntaxKind.PostfixUnaryExpression:
check(node as ts.PostfixUnaryExpression);
break;
}
}
function check(node: ts.UnaryExpression): void {
if (!isAllowedLocation(node.parent)) {
ctx.addFailureAtNode(node, Rule.POSTFIX_FAILURE_STRING);
}
}
}
function isAllowedLocation(node: ts.Node): boolean {
switch (node.kind) {
// Can be a statement
case ts.SyntaxKind.ExpressionStatement:
return true;
// Can be directly in a for-statement
case ts.SyntaxKind.ForStatement:
return true;
// Can be in a comma operator in a for statement (`for (let a = 0, b = 10; a < b; a++, b--)`)
case ts.SyntaxKind.BinaryExpression:
return (node as ts.BinaryExpression).operatorToken.kind === ts.SyntaxKind.CommaToken &&
node.parent.kind === ts.SyntaxKind.ForStatement;
default:
return false;
}
}

View file

@ -1,25 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static TRAILING_FAILURE_STRING = "Excess trailing whitespace found around type assertion.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
ts.forEachChild(ctx.sourceFile, recur);
function recur(node: ts.Node) {
if (node.kind === ts.SyntaxKind.TypeAssertionExpression) {
const refined = node as ts.TypeAssertion;
const leftSideWhitespaceStart = refined.type.getEnd() + 1;
const rightSideWhitespaceEnd = refined.expression.getStart();
if (leftSideWhitespaceStart !== rightSideWhitespaceEnd) {
ctx.addFailure(leftSideWhitespaceStart, rightSideWhitespaceEnd, Rule.TRAILING_FAILURE_STRING);
}
}
ts.forEachChild(node, recur);
}
}

View file

@ -1,44 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static LEADING_FAILURE_STRING = "No leading whitespace found on single-line object literal.";
public static TRAILING_FAILURE_STRING = "No trailing whitespace found on single-line object literal.";
public static LEADING_EXCESS_FAILURE_STRING = "Excess leading whitespace found on single-line object literal.";
public static TRAILING_EXCESS_FAILURE_STRING = "Excess trailing whitespace found on single-line object literal.";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
ts.forEachChild(sourceFile, recur);
function recur(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
check(node as ts.ObjectLiteralExpression);
}
ts.forEachChild(node, recur);
}
function check(node: ts.ObjectLiteralExpression): void {
const text = node.getText(sourceFile);
if (!text.match(/^{[^\n]+}$/g)) {
return;
}
if (text.charAt(1) !== " ") {
ctx.addFailureAtNode(node, Rule.LEADING_FAILURE_STRING);
}
if (text.charAt(2) === " ") {
ctx.addFailureAt(node.pos + 2, 1, Rule.LEADING_EXCESS_FAILURE_STRING);
}
if (text.charAt(text.length - 2) !== " ") {
ctx.addFailureAtNode(node, Rule.TRAILING_FAILURE_STRING);
}
if (text.charAt(text.length - 3) === " ") {
ctx.addFailureAt(node.pos + node.getWidth() - 3, 1, Rule.TRAILING_EXCESS_FAILURE_STRING);
}
}
}

View file

@ -1,30 +0,0 @@
import * as Lint from "tslint/lib";
import * as ts from "typescript";
export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "The '|' and '&' operators must be surrounded by spaces";
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}
function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
sourceFile.forEachChild(function cb(node: ts.Node): void {
if (ts.isUnionTypeNode(node) || ts.isIntersectionTypeNode(node)) {
check(node);
}
node.forEachChild(cb);
});
function check(node: ts.UnionTypeNode | ts.IntersectionTypeNode): void {
const list = node.getChildren().find(child => child.kind === ts.SyntaxKind.SyntaxList)!;
for (const child of list.getChildren()) {
if ((child.kind === ts.SyntaxKind.BarToken || child.kind === ts.SyntaxKind.AmpersandToken)
&& (/\S/.test(sourceFile.text[child.getStart(sourceFile) - 1]) || /\S/.test(sourceFile.text[child.end]))) {
ctx.addFailureAtNode(child, Rule.FAILURE_STRING);
}
}
}
}

View file

@ -1,20 +0,0 @@
{
"compilerOptions": {
"lib": ["es6"],
"sourceMap": false,
"declaration": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"module": "commonjs",
"outDir": "../../built/local/tslint",
"baseUrl": "../..",
"types": ["node"],
"paths": {
"typescript": ["lib/typescript.d.ts"]
}
}
}

View file

@ -1,141 +0,0 @@
{
"extends": "tslint:latest",
"rulesDirectory": "built/local/tslint/rules",
"linterOptions": {
"exclude": [
"tests/**/*"
]
},
"rules": {
"no-unnecessary-type-assertion": true,
"array-type": [true, "array"],
"ban": [
true,
"setInterval",
"setTimeout"
],
"ban-types": {
"options": [
["Object", "Avoid using the `Object` type. Did you mean `object`?"],
["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`, or use `ts.AnyFunction`."],
["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"],
["Number", "Avoid using the `Number` type. Did you mean `number`?"],
["String", "Avoid using the `String` type. Did you mean `string`?"]
]
},
"boolean-trivia": true,
"class-name": true,
"comment-format": [true,
"check-space"
],
"curly":[true, "ignore-same-line"],
"debug-assert": true,
"indent": [true,
"spaces"
],
"interface-name": [true, "never-prefix"],
"interface-over-type-literal": true,
"jsdoc-format": true,
"linebreak-style": [true, "CRLF"],
"next-line": [true,
"check-catch",
"check-else"
],
"no-bom": true,
"no-double-space": true,
"no-eval": true,
"no-in-operator": true,
"no-increment-decrement": true,
"no-inferrable-types": true,
"no-internal-module": true,
"no-null-keyword": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": [true, "ignore-template-strings"],
"no-type-assertion-whitespace": true,
"no-unnecessary-qualifier": true,
"no-var-keyword": true,
"object-literal-shorthand": true,
"object-literal-surrounding-space": true,
"one-line": [true,
"check-open-brace",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [true,
"double",
"avoid-escape"
],
"semicolon": [true, "always", "ignore-bound-class-methods"],
"space-within-parens": true,
"triple-equals": true,
"type-operator-spacing": true,
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
],
"whitespace": [true,
"check-branch",
"check-decl",
"check-operator",
"check-module",
"check-separator",
"check-type"
],
// Config different from tslint:latest
"no-implicit-dependencies": [true, "dev"],
"object-literal-key-quotes": [true, "consistent-as-needed"],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"],
// TODO
"arrow-parens": false, // [true, "ban-single-arg-parens"]
"arrow-return-shorthand": false,
"ban-types": false,
"forin": false,
"member-access": false, // [true, "no-public"]
"no-conditional-assignment": false,
"no-console": false,
"no-debugger": false,
"no-empty-interface": false,
"no-object-literal-type-assertion": false,
"no-shadowed-variable": false,
"no-submodule-imports": false,
"no-var-requires": false,
"ordered-imports": false,
"prefer-conditional-expression": false,
"radix": false,
"trailing-comma": false,
// These should be done automatically by a formatter. https://github.com/Microsoft/TypeScript/issues/18340
"align": false,
"eofline": false,
"max-line-length": false,
"no-consecutive-blank-lines": false,
"space-before-function-paren": false,
// Not doing
"ban-comma-operator": false,
"max-classes-per-file": false,
"member-ordering": false,
"no-angle-bracket-type-assertion": false,
"no-bitwise": false,
"no-namespace": false,
"no-reference": false,
"object-literal-sort-keys": false,
"one-variable-per-declaration": false
}
}