Skip to content

Commit

Permalink
Set --lib es6, and use Map/Set methods where possible. (palanti…
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-hanson authored and nchen63 committed Jan 7, 2017
1 parent 5ff7615 commit 4ee7839
Show file tree
Hide file tree
Showing 27 changed files with 183 additions and 172 deletions.
17 changes: 14 additions & 3 deletions docs/_data/rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -951,10 +951,21 @@
"description": "Disallows unused expression statements.",
"descriptionDetails": "\nUnused expressions are expression statements which are not assignments or function calls\n(and thus usually no-ops).",
"rationale": "\nDetects potential errors where an assignment or function call was intended.",
"optionsDescription": "Not configurable.",
"options": null,
"optionsDescription": "\nOne argument may be optionally provided:\n\n* `allow-fast-null-checks` allows to use logical operators to perform fast null checks and perform\nmethod or function calls for side effects (e.g. `e && e.preventDefault()`).",
"options": {
"type": "array",
"items": {
"type": "string",
"enum": [
"allow-fast-null-checks"
]
},
"minLength": 0,
"maxLength": 1
},
"optionExamples": [
"true"
"true",
"[true, \"allow-fast-null-checks\"]"
],
"type": "functionality",
"typescriptOnly": false
Expand Down
30 changes: 27 additions & 3 deletions docs/rules/no-unused-expression/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,37 @@
rationale: |-

Detects potential errors where an assignment or function call was intended.
optionsDescription: Not configurable.
options: null
optionsDescription: |-

One argument may be optionally provided:

* `allow-fast-null-checks` allows to use logical operators to perform fast null checks and perform
method or function calls for side effects (e.g. `e && e.preventDefault()`).
options:
type: array
items:
type: string
enum:
- allow-fast-null-checks
minLength: 0
maxLength: 1
optionExamples:
- 'true'
- '[true, "allow-fast-null-checks"]'
type: functionality
typescriptOnly: false
layout: rule
title: 'Rule: no-unused-expression'
optionsJSON: 'null'
optionsJSON: |-
{
"type": "array",
"items": {
"type": "string",
"enum": [
"allow-fast-null-checks"
]
},
"minLength": 0,
"maxLength": 1
}
---
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
18 changes: 9 additions & 9 deletions src/language/walker/skippableTokenAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,10 @@

import * as ts from "typescript";

import {IOptions} from "../rule/rule";
import {RuleWalker} from "./ruleWalker";

export class SkippableTokenAwareRuleWalker extends RuleWalker {
protected tokensToSkipStartEndMap: {[start: number]: number};

constructor(sourceFile: ts.SourceFile, options: IOptions) {
super(sourceFile, options);
this.tokensToSkipStartEndMap = {};
}
private tokensToSkipStartEndMap = new Map<number, number>();

protected visitRegularExpressionLiteral(node: ts.Node) {
this.addTokenToSkipFromNode(node);
Expand All @@ -44,9 +38,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
Loading

0 comments on commit 4ee7839

Please sign in to comment.