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

Set --lib es6, and use Map/Set methods where possible. #1984

Merged
merged 9 commits into from
Jan 7, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"glob": "^7.1.1",
"optimist": "~0.6.0",
"resolve": "^1.1.7",
"underscore.string": "^3.3.4",
"update-notifier": "^1.0.2"
},
"peerDependencies": {
Expand All @@ -60,8 +59,6 @@
"@types/node": "^6.0.56",
"@types/optimist": "0.0.29",
"@types/resolve": "0.0.4",
"@types/underscore": "^1.7.36",
"@types/underscore.string": "0.0.30",
"chai": "^3.5.0",
"js-yaml": "^3.7.0",
"mocha": "^3.2.0",
Expand All @@ -71,5 +68,8 @@
"tslint-test-config-non-relative": "file:test/external/tslint-test-config-non-relative",
"typescript": "2.1.4"
},
"license": "Apache-2.0"
"license": "Apache-2.0",
"engines": {
"node": ">=4.2.6"
}
}
3 changes: 2 additions & 1 deletion scripts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"noUnusedParameters": true,
"noUnusedLocals": true,
"sourceMap": true,
"target": "es5"
"target": "es5",
"lib": ["es6"]
}
}
7 changes: 4 additions & 3 deletions src/enableDisableRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ export class EnableDisableRulesWalker extends SkippableTokenAwareRuleWalker {

scanAllTokens(scan, (scanner: ts.Scanner) => {
const startPos = scanner.getStartPos();
if (this.tokensToSkipStartEndMap[startPos] != null) {
const skip = this.getSkipEndFromStart(startPos);
if (skip !== undefined) {
// tokens to skip are places where the scanner gets confused about what the token is, without the proper context
// (specifically, regex, identifiers, and templates). So skip those tokens.
scanner.setTextPos(this.tokensToSkipStartEndMap[startPos]);
scanner.setTextPos(skip);
return;
}

Expand Down Expand Up @@ -117,7 +118,7 @@ export class EnableDisableRulesWalker extends SkippableTokenAwareRuleWalker {
rulesList = commentTextParts[1].split(/\s+/).slice(1);

// remove empty items and potential comment end.
rulesList = rulesList.filter((item) => !!item && item.indexOf("*/") === -1);
rulesList = rulesList.filter((item) => !!item && !item.includes("*/"));

// potentially there were no items, so default to `all`.
rulesList = rulesList.length > 0 ? rulesList : ["all"];
Expand Down
2 changes: 1 addition & 1 deletion src/formatterLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import * as fs from "fs";
import * as path from "path";
import {camelize} from "underscore.string";
import {camelize} from "./utils";

const moduleDirectory = path.dirname(module.filename);
const CORE_FORMATTERS_DIRECTORY = path.resolve(moduleDirectory, ".", "formatters");
Expand Down
6 changes: 2 additions & 4 deletions src/formatters/msbuildFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,18 @@
* limitations under the License.
*/

import {camelize} from "underscore.string";

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

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

export class Formatter extends AbstractFormatter {
/* tslint:disable:object-literal-sort-keys */
public static metadata: IFormatterMetadata = {
formatterName: "msbuild",
description: "Formats errors for consumption by msbuild.",
descriptionDetails: Utils.dedent`
descriptionDetails: dedent`
The output is compatible with both msbuild and Visual Studio. All failures have the
'warning' severity.`,
sample: "myFile.ts(1,14): warning: Missing semicolon",
Expand Down
11 changes: 3 additions & 8 deletions src/formatters/proseFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,12 @@ export class Formatter extends AbstractFormatter {

const fixLines: string[] = [];
if (fixes) {
const perFileFixes: { [fileName: string]: number } = {};
const perFileFixes = new Map<string, number>();
for (const fix of fixes) {
if (perFileFixes[fix.getFileName()] == null) {
perFileFixes[fix.getFileName()] = 1;
} else {
perFileFixes[fix.getFileName()]++;
}
perFileFixes.set(fix.getFileName(), (perFileFixes.get(fix.getFileName()) || 0) + 1);
}

Object.keys(perFileFixes).forEach((fixedFile: string) => {
const fixCount = perFileFixes[fixedFile];
perFileFixes.forEach((fixCount, fixedFile) => {
fixLines.push(`Fixed ${fixCount} error(s) in ${fixedFile}`);
});
fixLines.push(""); // add a blank line between fixes and failures
Expand Down
23 changes: 12 additions & 11 deletions src/language/languageServiceHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,32 @@ interface LanguageServiceEditableHost extends ts.LanguageServiceHost {
}

export function wrapProgram(program: ts.Program): ts.LanguageService {
const files: {[name: string]: string} = {};
const fileVersions: {[name: string]: number} = {};
const files = new Map<string, string>(); // file name -> content
const fileVersions = new Map<string, number>();
const host: LanguageServiceEditableHost = {
getCompilationSettings: () => program.getCompilerOptions(),
getCurrentDirectory: () => program.getCurrentDirectory(),
getDefaultLibFileName: () => "lib.d.ts",
getScriptFileNames: () => program.getSourceFiles().map((sf) => sf.fileName),
getScriptSnapshot: (name: string) => {
if (files.hasOwnProperty(name)) {
return ts.ScriptSnapshot.fromString(files[name]);
const file = files.get(name);
if (file !== undefined) {
return ts.ScriptSnapshot.fromString(file);
}
if (!program.getSourceFile(name)) {
return undefined;
}
return ts.ScriptSnapshot.fromString(program.getSourceFile(name).getFullText());
},
getScriptVersion: (name: string) => fileVersions.hasOwnProperty(name) ? fileVersions[name] + "" : "1",
getScriptVersion: (name: string) => {
const version = fileVersions.get(name);
return version === undefined ? "1" : String(version);
},
log: () => { /* */ },
editFile(fileName: string, newContent: string) {
files[fileName] = newContent;
if (fileVersions.hasOwnProperty(fileName)) {
fileVersions[fileName]++;
} else {
fileVersions[fileName] = 0;
}
files.set(fileName, newContent);
const prevVersion = fileVersions.get(fileName);
fileVersions.set(fileName, prevVersion === undefined ? 0 : prevVersion + 1);
},
};
const langSvc = ts.createLanguageService(host, ts.createDocumentRegistry());
Expand Down
12 changes: 1 addition & 11 deletions src/language/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,12 @@ export function getBindingElementVariableDeclaration(node: ts.BindingElement): t
return currentParent as ts.VariableDeclaration;
}

/** Shim of Array.find */
function find<T>(a: T[], predicate: (value: T) => boolean): T | undefined {
for (const value of a) {
if (predicate(value)) {
return value;
}
}
return undefined;
}

/**
* Finds a child of a given node with a given kind.
* Note: This uses `node.getChildren()`, which does extra parsing work to include tokens.
*/
export function childOfKind(node: ts.Node, kind: ts.SyntaxKind): ts.Node | undefined {
return find(node.getChildren(), (child) => child.kind === kind);
return node.getChildren().find((child) => child.kind === kind);
}

/**
Expand Down
13 changes: 9 additions & 4 deletions src/language/walker/skippableTokenAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import {IOptions} from "../rule/rule";
import {RuleWalker} from "./ruleWalker";

export class SkippableTokenAwareRuleWalker extends RuleWalker {
protected tokensToSkipStartEndMap: {[start: number]: number};
private tokensToSkipStartEndMap = new Map<number, number>();

constructor(sourceFile: ts.SourceFile, options: IOptions) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need constructor anymore

super(sourceFile, options);
this.tokensToSkipStartEndMap = {};
}

protected visitRegularExpressionLiteral(node: ts.Node) {
Expand All @@ -44,9 +43,15 @@ export class SkippableTokenAwareRuleWalker extends RuleWalker {
}

protected addTokenToSkipFromNode(node: ts.Node) {
if (node.getStart() < node.getEnd()) {
const start = node.getStart();
const end = node.getEnd();
if (start < end) {
// only add to the map nodes whose end comes after their start, to prevent infinite loops
this.tokensToSkipStartEndMap[node.getStart()] = node.getEnd();
this.tokensToSkipStartEndMap.set(start, end);
}
}

protected getSkipEndFromStart(start: number): number | undefined {
return this.tokensToSkipStartEndMap.get(start);
}
}
5 changes: 2 additions & 3 deletions src/ruleLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@

import * as fs from "fs";
import * as path from "path";
import {camelize} from "underscore.string";

import {getRulesDirectories} from "./configuration";
import {IDisabledInterval, IRule} from "./language/rule/rule";
import {dedent} from "./utils";
import {camelize, dedent} from "./utils";

const moduleDirectory = path.dirname(module.filename);
const CORE_RULES_DIRECTORY = path.resolve(moduleDirectory, ".", "rules");
Expand Down Expand Up @@ -151,7 +150,7 @@ function buildDisabledIntervalsFromSwitches(ruleSpecificList: IEnableDisablePosi
while (i < ruleSpecificList.length) {
const startPosition = ruleSpecificList[i].position;

// rule enabled state is always alternating therefore we can use position of next switch as end of disabled interval
// rule enabled state is always alternating therefore we can use position of next switch as end of disabled interval
// set endPosition as Infinity in case when last switch for rule in a file is disabled
const endPosition = ruleSpecificList[i + 1] ? ruleSpecificList[i + 1].position : Infinity;

Expand Down
6 changes: 3 additions & 3 deletions src/rules/adjacentOverloadSignaturesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ class AdjacentOverloadSignaturesWalker extends Lint.RuleWalker {
/** 'getOverloadName' may return undefined for nodes that cannot be overloads, e.g. a `const` declaration. */
private checkOverloadsAdjacent<T extends ts.Node>(overloads: T[], getOverload: (node: T) => Overload | undefined) {
let lastKey: string | undefined = undefined;
const seen: { [key: string]: true } = Object.create(null);
const seen = new Set<string>();
for (const node of overloads) {
const overload = getOverload(node);
if (overload) {
const { name, key } = overload;
if (key in seen && lastKey !== key) {
if (seen.has(key) && lastKey !== key) {
this.addFailureAtNode(node, Rule.FAILURE_STRING_FACTORY(name));
}
seen[key] = true;
seen.add(key);
lastKey = key;
} else {
lastKey = undefined;
Expand Down
6 changes: 3 additions & 3 deletions src/rules/commentFormatRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ class CommentWalker extends Lint.SkippableTokenAwareRuleWalker {
public visitSourceFile(node: ts.SourceFile) {
super.visitSourceFile(node);
Lint.scanAllTokens(ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, node.text), (scanner: ts.Scanner) => {
const startPos = scanner.getStartPos();
if (this.tokensToSkipStartEndMap[startPos] != null) {
const skip = this.getSkipEndFromStart(scanner.getStartPos());
if (skip !== undefined) {
// tokens to skip are places where the scanner gets confused about what the token is, without the proper context
// (specifically, regex, identifiers, and templates). So skip those tokens.
scanner.setTextPos(this.tokensToSkipStartEndMap[startPos]);
scanner.setTextPos(skip);
return;
}

Expand Down
8 changes: 3 additions & 5 deletions src/rules/completedDocsRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,10 @@ export class Rule extends Lint.Rules.TypedRule {
}

export class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker {
private nodesToCheck: { [i: string]: boolean } = {};
private nodesToCheck: Set<string>;

public setNodesToCheck(nodesToCheck: string[]): void {
for (const nodeType of nodesToCheck) {
this.nodesToCheck[nodeType] = true;
}
this.nodesToCheck = new Set(nodesToCheck);
}

public visitClassDeclaration(node: ts.ClassDeclaration): void {
Expand All @@ -99,7 +97,7 @@ export class CompletedDocsWalker extends Lint.ProgramAwareRuleWalker {
}

private checkComments(node: ts.Declaration, nodeToCheck: string): void {
if (!this.nodesToCheck[nodeToCheck] || node.name === undefined) {
if (!this.nodesToCheck.has(nodeToCheck) || node.name === undefined) {
return;
}

Expand Down
6 changes: 3 additions & 3 deletions src/rules/jsdocFormatRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ class JsdocWalker extends Lint.SkippableTokenAwareRuleWalker {
public visitSourceFile(node: ts.SourceFile) {
super.visitSourceFile(node);
Lint.scanAllTokens(ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, node.text), (scanner: ts.Scanner) => {
const startPos = scanner.getStartPos();
if (this.tokensToSkipStartEndMap[startPos] != null) {
const skip = this.getSkipEndFromStart(scanner.getStartPos());
if (skip !== undefined) {
// tokens to skip are places where the scanner gets confused about what the token is, without the proper context
// (specifically, regex, identifiers, and templates). So skip those tokens.
scanner.setTextPos(this.tokensToSkipStartEndMap[startPos]);
scanner.setTextPos(skip);
return;
}

Expand Down
38 changes: 17 additions & 21 deletions src/rules/noMagicNumbersRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ export class Rule extends Lint.Rules.AbstractRule {

public static FAILURE_STRING = "'magic numbers' are not allowed";

public static ALLOWED_NODES = {
[ts.SyntaxKind.ExportAssignment]: true,
[ts.SyntaxKind.FirstAssignment]: true,
[ts.SyntaxKind.LastAssignment]: true,
[ts.SyntaxKind.PropertyAssignment]: true,
[ts.SyntaxKind.ShorthandPropertyAssignment]: true,
[ts.SyntaxKind.VariableDeclaration]: true,
[ts.SyntaxKind.VariableDeclarationList]: true,
[ts.SyntaxKind.EnumMember]: true,
[ts.SyntaxKind.PropertyDeclaration]: true,
};
public static ALLOWED_NODES = new Set<ts.SyntaxKind>([
ts.SyntaxKind.ExportAssignment,
ts.SyntaxKind.FirstAssignment,
ts.SyntaxKind.LastAssignment,
ts.SyntaxKind.PropertyAssignment,
ts.SyntaxKind.ShorthandPropertyAssignment,
ts.SyntaxKind.VariableDeclaration,
ts.SyntaxKind.VariableDeclarationList,
ts.SyntaxKind.EnumMember,
ts.SyntaxKind.PropertyDeclaration,
]);

public static DEFAULT_ALLOWED = [ -1, 0, 1 ];

Expand All @@ -68,25 +68,21 @@ export class Rule extends Lint.Rules.AbstractRule {

class NoMagicNumbersWalker extends Lint.RuleWalker {
// lookup object for allowed magic numbers
private allowed: { [prop: string]: boolean } = {};
private allowed: Set<string>;
constructor (sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);

const configOptions = this.getOptions();
const allowedNumbers: number[] = configOptions.length > 0 ? configOptions : Rule.DEFAULT_ALLOWED;

allowedNumbers.forEach((value) => {
this.allowed[value] = true;
});
this.allowed = new Set(allowedNumbers.map(String));
}

public visitNode(node: ts.Node) {
const isUnary = this.isUnaryNumericExpression(node);
if (node.kind === ts.SyntaxKind.NumericLiteral && node.parent !== undefined && !Rule.ALLOWED_NODES[node.parent.kind] || isUnary) {
const text = node.getText();
if (!this.allowed[text]) {
this.addFailureAtNode(node, Rule.FAILURE_STRING);
}
const isNumber = node.kind === ts.SyntaxKind.NumericLiteral && !Rule.ALLOWED_NODES.has(node.parent!.kind);
const isMagicNumber = (isNumber || isUnary) && !this.allowed.has(node.getText());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the isUnary case should also check for ALLOWED_NODES, but this is what it did before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Opened issue #2005

if (isMagicNumber) {
this.addFailureAtNode(node, Rule.FAILURE_STRING);
}
if (!isUnary) {
super.visitNode(node);
Expand Down
6 changes: 3 additions & 3 deletions src/rules/noTrailingWhitespaceRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ class NoTrailingWhitespaceWalker extends Lint.SkippableTokenAwareRuleWalker {
let lastSeenWasWhitespace = false;
let lastSeenWhitespacePosition = 0;
Lint.scanAllTokens(ts.createScanner(ts.ScriptTarget.ES5, false, ts.LanguageVariant.Standard, node.text), (scanner: ts.Scanner) => {
const startPos = scanner.getStartPos();
if (this.tokensToSkipStartEndMap[startPos] != null) {
const skip = this.getSkipEndFromStart(scanner.getStartPos());
if (skip !== undefined) {
// tokens to skip are places where the scanner gets confused about what the token is, without the proper context
// (specifically, regex, identifiers, and templates). So skip those tokens.
scanner.setTextPos(this.tokensToSkipStartEndMap[startPos]);
scanner.setTextPos(skip);
lastSeenWasWhitespace = false;
return;
}
Expand Down
Loading