Skip to content

Commit e873bc0

Browse files
committed
Merge remote-tracking branch 'Microsoft/master'
2 parents 077e0bd + 331d26f commit e873bc0

370 files changed

Lines changed: 6542 additions & 3847 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/tasks.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@
1818
"problemMatcher": [
1919
"$tsc"
2020
]
21+
},
22+
{
23+
"taskName": "lint-server",
24+
"args": [],
25+
"problemMatcher": {
26+
"owner": "typescript",
27+
"fileLocation": ["relative", "${workspaceRoot}"],
28+
"pattern": {
29+
"regexp": "^(warning|error)\\s+([^(]+)\\s+\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(.*)$",
30+
"severity": 1,
31+
"file": 2,
32+
"location": 3,
33+
"message": 4
34+
},
35+
"watchedTaskBeginsRegExp": "^\\*\\*\\*Lint failure\\*\\*\\*$",
36+
"watchedTaskEndsRegExp": "^\\*\\*\\* Total \\d+ failures\\.$"
37+
},
38+
"showOutput": "always",
39+
"isWatching": true
2140
}
2241
]
2342
}

Jakefile.js

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var fs = require("fs");
44
var os = require("os");
55
var path = require("path");
66
var child_process = require("child_process");
7+
var Linter = require("tslint");
78

89
// Variables
910
var compilerDirectory = "src/compiler/";
@@ -812,7 +813,6 @@ task("update-sublime", ["local", serverFile], function() {
812813
var tslintRuleDir = "scripts/tslint";
813814
var tslintRules = ([
814815
"nextLineRule",
815-
"noInferrableTypesRule",
816816
"noNullRule",
817817
"booleanTriviaRule"
818818
]);
@@ -828,17 +828,93 @@ tslintRulesFiles.forEach(function(ruleFile, i) {
828828
compileFile(tslintRulesOutFiles[i], [ruleFile], [ruleFile], [], /*useBuiltCompiler*/ true, /*noOutFile*/ true, /*generateDeclarations*/ false, path.join(builtLocalDirectory, "tslint"));
829829
});
830830

831+
function getLinterOptions() {
832+
return {
833+
configuration: require("./tslint.json"),
834+
formatter: "prose",
835+
formattersDirectory: undefined,
836+
rulesDirectory: "built/local/tslint"
837+
};
838+
}
839+
840+
function lintFileContents(options, path, contents) {
841+
var ll = new Linter(path, contents, options);
842+
return ll.lint();
843+
}
844+
845+
function lintFile(options, path) {
846+
var contents = fs.readFileSync(path, "utf8");
847+
return lintFileContents(options, path, contents);
848+
}
849+
850+
function lintFileAsync(options, path, cb) {
851+
fs.readFile(path, "utf8", function(err, contents) {
852+
if (err) {
853+
return cb(err);
854+
}
855+
var result = lintFileContents(options, path, contents);
856+
cb(undefined, result);
857+
});
858+
}
859+
860+
var lintTargets = compilerSources.concat(harnessCoreSources);
861+
831862
// if the codebase were free of linter errors we could make jake runtests
832863
// run this task automatically
833864
desc("Runs tslint on the compiler sources");
834865
task("lint", ["build-rules"], function() {
835-
function success(f) { return function() { console.log('SUCCESS: No linter errors in ' + f + '\n'); }};
836-
function failure(f) { return function() { console.log('FAILURE: Please fix linting errors in ' + f + '\n') }};
837-
838-
var lintTargets = compilerSources.concat(harnessCoreSources);
866+
var lintOptions = getLinterOptions();
839867
for (var i in lintTargets) {
840-
var f = lintTargets[i];
841-
var cmd = 'tslint --rules-dir built/local/tslint -c tslint.json ' + f;
842-
exec(cmd, success(f), failure(f));
868+
var result = lintFile(lintOptions, lintTargets[i]);
869+
if (result.failureCount > 0) {
870+
console.log(result.output);
871+
fail('Linter errors.', result.failureCount);
872+
}
843873
}
844-
}, { async: true });
874+
});
875+
876+
/**
877+
* This is required because file watches on Windows get fires _twice_
878+
* when a file changes on some node/windows version configuations
879+
* (node v4 and win 10, for example). By not running a lint for a file
880+
* which already has a pending lint, we avoid duplicating our work.
881+
* (And avoid printing duplicate results!)
882+
*/
883+
var lintSemaphores = {};
884+
885+
function lintWatchFile(filename) {
886+
fs.watch(filename, {persistent: true}, function(event) {
887+
if (event !== "change") {
888+
return;
889+
}
890+
891+
if (!lintSemaphores[filename]) {
892+
lintSemaphores[filename] = true;
893+
lintFileAsync(getLinterOptions(), filename, function(err, result) {
894+
delete lintSemaphores[filename];
895+
if (err) {
896+
console.log(err);
897+
return;
898+
}
899+
if (result.failureCount > 0) {
900+
console.log("***Lint failure***");
901+
for (var i = 0; i < result.failures.length; i++) {
902+
var failure = result.failures[i];
903+
var start = failure.startPosition.lineAndCharacter;
904+
var end = failure.endPosition.lineAndCharacter;
905+
console.log("warning " + filename + " (" + (start.line + 1) + "," + (start.character + 1) + "," + (end.line + 1) + "," + (end.character + 1) + "): " + failure.failure);
906+
}
907+
console.log("*** Total " + result.failureCount + " failures.");
908+
}
909+
});
910+
}
911+
});
912+
}
913+
914+
desc("Watches files for changes to rerun a lint pass");
915+
task("lint-server", ["build-rules"], function() {
916+
console.log("Watching ./src for changes to linted files");
917+
for (var i = 0; i < lintTargets.length; i++) {
918+
lintWatchFile(lintTargets[i]);
919+
}
920+
});

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@
4040
},
4141
"scripts": {
4242
"pretest": "jake tests",
43-
"test": "jake runtests",
43+
"test": "jake runtests && npm run lint",
4444
"build": "npm run build:compiler && npm run build:tests",
4545
"build:compiler": "jake local",
4646
"build:tests": "jake tests",
4747
"clean": "jake clean",
4848
"jake": "jake",
49+
"lint": "jake lint",
4950
"setup-hooks": "node scripts/link-hooks.js"
5051
},
5152
"browser": {

scripts/tslint/nextLineRule.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ const OPTION_CATCH = "check-catch";
55
const OPTION_ELSE = "check-else";
66

77
export class Rule extends Lint.Rules.AbstractRule {
8-
public static CATCH_FAILURE_STRING = "'catch' should be on the line following the previous block's ending curly brace";
9-
public static ELSE_FAILURE_STRING = "'else' should be on the line following the previous block's ending curly brace";
8+
public static CATCH_FAILURE_STRING = "'catch' should not be on the same line as the preceeding block's curly brace";
9+
public static ELSE_FAILURE_STRING = "'else' should not be on the same line as the preceeding block's curly brace";
1010

1111
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
1212
return this.applyWithWalker(new NextLineWalker(sourceFile, this.getOptions()));
@@ -25,7 +25,7 @@ class NextLineWalker extends Lint.RuleWalker {
2525
if (this.hasOption(OPTION_ELSE) && !!elseKeyword) {
2626
const thenStatementEndLoc = sourceFile.getLineAndCharacterOfPosition(thenStatement.getEnd());
2727
const elseKeywordLoc = sourceFile.getLineAndCharacterOfPosition(elseKeyword.getStart(sourceFile));
28-
if (thenStatementEndLoc.line !== (elseKeywordLoc.line - 1)) {
28+
if (thenStatementEndLoc.line === elseKeywordLoc.line) {
2929
const failure = this.createFailure(elseKeyword.getStart(sourceFile), elseKeyword.getWidth(sourceFile), Rule.ELSE_FAILURE_STRING);
3030
this.addFailure(failure);
3131
}
@@ -47,7 +47,7 @@ class NextLineWalker extends Lint.RuleWalker {
4747
const catchKeyword = catchClause.getFirstToken(sourceFile);
4848
const tryClosingBraceLoc = sourceFile.getLineAndCharacterOfPosition(tryClosingBrace.getEnd());
4949
const catchKeywordLoc = sourceFile.getLineAndCharacterOfPosition(catchKeyword.getStart(sourceFile));
50-
if (tryClosingBraceLoc.line !== (catchKeywordLoc.line - 1)) {
50+
if (tryClosingBraceLoc.line === catchKeywordLoc.line) {
5151
const failure = this.createFailure(catchKeyword.getStart(sourceFile), catchKeyword.getWidth(sourceFile), Rule.CATCH_FAILURE_STRING);
5252
this.addFailure(failure);
5353
}
@@ -58,4 +58,4 @@ class NextLineWalker extends Lint.RuleWalker {
5858

5959
function getFirstChildOfKind(node: ts.Node, kind: ts.SyntaxKind) {
6060
return node.getChildren().filter((child) => child.kind === kind)[0];
61-
}
61+
}

scripts/tslint/noInferrableTypesRule.ts

Lines changed: 0 additions & 49 deletions
This file was deleted.

src/compiler/binder.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ namespace ts {
8888
let container: Node;
8989
let blockScopeContainer: Node;
9090
let lastContainer: Node;
91+
let seenThisKeyword: boolean;
9192

9293
// If this file is an external module, then it is automatically in strict-mode according to
9394
// ES6. If it is not an external module, then we'll determine if it is in strict mode or
@@ -329,7 +330,14 @@ namespace ts {
329330
blockScopeContainer.locals = undefined;
330331
}
331332

332-
forEachChild(node, bind);
333+
if (node.kind === SyntaxKind.InterfaceDeclaration) {
334+
seenThisKeyword = false;
335+
forEachChild(node, bind);
336+
node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis;
337+
}
338+
else {
339+
forEachChild(node, bind);
340+
}
333341

334342
container = saveContainer;
335343
parent = saveParent;
@@ -851,6 +859,9 @@ namespace ts {
851859
return checkStrictModePrefixUnaryExpression(<PrefixUnaryExpression>node);
852860
case SyntaxKind.WithStatement:
853861
return checkStrictModeWithStatement(<WithStatement>node);
862+
case SyntaxKind.ThisKeyword:
863+
seenThisKeyword = true;
864+
return;
854865

855866
case SyntaxKind.TypeParameter:
856867
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);

0 commit comments

Comments
 (0)