add eslint
This commit is contained in:
Родитель
74c6bc1f85
Коммит
55b8a38d50
|
@ -0,0 +1,3 @@
|
|||
/built/local/**
|
||||
/tests/**
|
||||
/lib/**
|
|
@ -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"
|
||||
}
|
||||
}
|
41
Gulpfile.js
41
Gulpfile.js
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
```
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
}
|
141
tslint.json
141
tslint.json
|
@ -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
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче