Skip to content

Commit cbbf6f8

Browse files
committed
Merge branch 'master' into tripleEquals
2 parents 3bdec69 + 62f44fb commit cbbf6f8

File tree

368 files changed

+7404
-2766
lines changed

Some content is hidden

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

368 files changed

+7404
-2766
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ branches:
1818
- master
1919
- release-2.1
2020
- release-2.2
21+
- release-2.3
2122

2223
install:
2324
- npm uninstall typescript
2425
- npm uninstall tslint
2526
- npm install
26-
- npm update
2727

2828
cache:
2929
directories:

Gulpfile.ts

Lines changed: 39 additions & 35 deletions
Large diffs are not rendered by default.

Jakefile.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ var librarySourceMap = [
205205

206206
// JavaScript + all host library
207207
{ target: "lib.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(hostsLibrarySources) },
208-
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") }
208+
{ target: "lib.es6.d.ts", sources: ["header.d.ts", "es5.d.ts"].concat(es2015LibrarySources, hostsLibrarySources, "dom.iterable.d.ts") },
209+
{ target: "lib.es2016.full.d.ts", sources: ["header.d.ts", "es2016.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") },
210+
{ target: "lib.es2017.full.d.ts", sources: ["header.d.ts", "es2017.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") },
211+
{ target: "lib.esnext.full.d.ts", sources: ["header.d.ts", "esnext.d.ts"].concat(hostsLibrarySources, "dom.iterable.d.ts") },
209212
].concat(es2015LibrarySourceMap, es2016LibrarySourceMap, es2017LibrarySourceMap, esnextLibrarySourceMap);
210213

211214
var libraryTargets = librarySourceMap.map(function (f) {
@@ -1197,7 +1200,7 @@ task("lint", ["build-rules"], () => {
11971200
const fileMatcher = process.env.f || process.env.file || process.env.files;
11981201
const files = fileMatcher
11991202
? `src/**/${fileMatcher}`
1200-
: "Gulpfile.ts 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
1203+
: "Gulpfile.ts 'scripts/tslint/*.ts' 'src/**/*.ts' --exclude src/lib/es5.d.ts --exclude 'src/lib/*.generated.d.ts'";
12011204
const cmd = `node node_modules/tslint/bin/tslint ${files} --format stylish`;
12021205
console.log("Linting: " + cmd);
12031206
jake.exec([cmd], { interactive: true }, () => {

scripts/tslint/booleanTriviaRule.ts

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,94 @@ import * as Lint from "tslint/lib";
22
import * as ts from "typescript";
33

44
export class Rule extends Lint.Rules.AbstractRule {
5-
public static FAILURE_STRING_FACTORY(name: string, currently?: string): string {
6-
const current = currently ? ` (currently '${currently}')` : "";
7-
return `Tag boolean argument as '${name}'${current}`;
8-
}
9-
105
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
11-
// Cheat to get type checker
12-
const program = ts.createProgram([sourceFile.fileName], Lint.createCompilerOptions());
13-
const checker = program.getTypeChecker();
14-
return this.applyWithFunction(program.getSourceFile(sourceFile.fileName), ctx => walk(ctx, checker));
6+
return this.applyWithFunction(sourceFile, ctx => walk(ctx));
157
}
168
}
179

18-
function walk(ctx: Lint.WalkContext<void>, checker: ts.TypeChecker): void {
19-
ts.forEachChild(ctx.sourceFile, recur);
20-
function recur(node: ts.Node): void {
10+
function walk(ctx: Lint.WalkContext<void>): void {
11+
const { sourceFile } = ctx;
12+
ts.forEachChild(sourceFile, function recur(node: ts.Node): void {
2113
if (node.kind === ts.SyntaxKind.CallExpression) {
2214
checkCall(node as ts.CallExpression);
2315
}
2416
ts.forEachChild(node, recur);
25-
}
17+
});
2618

2719
function checkCall(node: ts.CallExpression): void {
28-
if (!node.arguments || !node.arguments.some(arg => arg.kind === ts.SyntaxKind.TrueKeyword || arg.kind === ts.SyntaxKind.FalseKeyword)) {
20+
if (!shouldIgnoreCalledExpression(node.expression)) {
21+
for (const arg of node.arguments) {
22+
checkArg(arg);
23+
}
24+
}
25+
}
26+
27+
/** Skip certain function/method names whose parameter names are not informative. */
28+
function shouldIgnoreCalledExpression(expression: ts.Expression): boolean {
29+
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
30+
const methodName = (expression as ts.PropertyAccessExpression).name.text;
31+
if (methodName.indexOf("set") === 0) {
32+
return true;
33+
}
34+
switch (methodName) {
35+
case "apply":
36+
case "assert":
37+
case "call":
38+
case "equal":
39+
case "fail":
40+
case "isTrue":
41+
case "output":
42+
case "stringify":
43+
return true;
44+
}
45+
}
46+
else if (expression.kind === ts.SyntaxKind.Identifier) {
47+
const functionName = (expression as ts.Identifier).text;
48+
if (functionName.indexOf("set") === 0) {
49+
return true;
50+
}
51+
switch (functionName) {
52+
case "assert":
53+
case "contains":
54+
case "createAnonymousType":
55+
case "createImportSpecifier":
56+
case "createProperty":
57+
case "createSignature":
58+
case "resolveName":
59+
return true;
60+
}
61+
}
62+
return false;
63+
}
64+
65+
function checkArg(arg: ts.Expression): void {
66+
if (!isTrivia(arg)) {
2967
return;
3068
}
3169

32-
const targetCallSignature = checker.getResolvedSignature(node);
33-
if (!targetCallSignature) {
70+
const ranges = ts.getTrailingCommentRanges(sourceFile.text, arg.pos) || ts.getLeadingCommentRanges(sourceFile.text, arg.pos);
71+
if (ranges === undefined || ranges.length !== 1 || ranges[0].kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
72+
ctx.addFailureAtNode(arg, "Tag boolean argument with parameter name");
3473
return;
3574
}
3675

37-
const targetParameters = targetCallSignature.getParameters();
38-
for (let index = 0; index < targetParameters.length; index++) {
39-
const param = targetParameters[index];
40-
const arg = node.arguments[index];
41-
if (!(arg && param)) {
42-
continue;
43-
}
76+
const range = ranges[0];
77+
const argStart = arg.getStart(sourceFile);
78+
if (range.end + 1 !== argStart && sourceFile.text.slice(range.end, argStart).indexOf("\n") === -1) {
79+
ctx.addFailureAtNode(arg, "There should be 1 space between an argument and its comment.");
80+
}
81+
}
4482

45-
const argType = checker.getContextualType(arg);
46-
if (argType && (argType.getFlags() & ts.TypeFlags.Boolean)) {
47-
if (arg.kind !== ts.SyntaxKind.TrueKeyword && arg.kind !== ts.SyntaxKind.FalseKeyword) {
48-
continue;
49-
}
50-
let triviaContent: string | undefined;
51-
const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0);
52-
if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) {
53-
triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/
54-
}
55-
56-
const paramName = param.getName();
57-
if (triviaContent !== paramName && triviaContent !== paramName + ":") {
58-
ctx.addFailureAtNode(arg, Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent));
59-
}
60-
}
83+
function isTrivia(arg: ts.Expression): boolean {
84+
switch (arg.kind) {
85+
case ts.SyntaxKind.TrueKeyword:
86+
case ts.SyntaxKind.FalseKeyword:
87+
case ts.SyntaxKind.NullKeyword:
88+
return true;
89+
case ts.SyntaxKind.Identifier:
90+
return (arg as ts.Identifier).originalKeywordKind === ts.SyntaxKind.UndefinedKeyword;
91+
default:
92+
return false;
6193
}
6294
}
63-
}
95+
}

src/compiler/binder.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ namespace ts {
418418
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
419419
}
420420
else {
421-
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
421+
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
422422
}
423423
}
424424
else {
@@ -447,13 +447,13 @@ namespace ts {
447447
(symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0) |
448448
(symbolFlags & SymbolFlags.Type ? SymbolFlags.ExportType : 0) |
449449
(symbolFlags & SymbolFlags.Namespace ? SymbolFlags.ExportNamespace : 0);
450-
const local = declareSymbol(container.locals, undefined, node, exportKind, symbolExcludes);
450+
const local = declareSymbol(container.locals, /*parent*/ undefined, node, exportKind, symbolExcludes);
451451
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes);
452452
node.localSymbol = local;
453453
return local;
454454
}
455455
else {
456-
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
456+
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
457457
}
458458
}
459459
}
@@ -1545,7 +1545,7 @@ namespace ts {
15451545
function declareSourceFileMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
15461546
return isExternalModule(file)
15471547
? declareModuleMember(node, symbolFlags, symbolExcludes)
1548-
: declareSymbol(file.locals, undefined, node, symbolFlags, symbolExcludes);
1548+
: declareSymbol(file.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
15491549
}
15501550

15511551
function hasExportDeclarations(node: ModuleDeclaration | SourceFile): boolean {
@@ -1721,7 +1721,7 @@ namespace ts {
17211721
blockScopeContainer.locals = createMap<Symbol>();
17221722
addToContainerChain(blockScopeContainer);
17231723
}
1724-
declareSymbol(blockScopeContainer.locals, undefined, node, symbolFlags, symbolExcludes);
1724+
declareSymbol(blockScopeContainer.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
17251725
}
17261726
}
17271727

@@ -2298,7 +2298,7 @@ namespace ts {
22982298

22992299
function isNameOfExportsOrModuleExportsAliasDeclaration(node: Node) {
23002300
if (node.kind === SyntaxKind.Identifier) {
2301-
const symbol = container.locals.get((<Identifier>node).text);
2301+
const symbol = lookupSymbolForName((<Identifier>node).text);
23022302
if (symbol && symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
23032303
const declaration = symbol.valueDeclaration as VariableDeclaration;
23042304
if (declaration.initializer) {
@@ -2333,7 +2333,7 @@ namespace ts {
23332333

23342334
function bindThisPropertyAssignment(node: BinaryExpression) {
23352335
Debug.assert(isInJavaScriptFile(node));
2336-
const container = getThisContainer(node, /*includeArrowFunctions*/false);
2336+
const container = getThisContainer(node, /*includeArrowFunctions*/ false);
23372337
switch (container.kind) {
23382338
case SyntaxKind.FunctionDeclaration:
23392339
case SyntaxKind.FunctionExpression:
@@ -2400,8 +2400,12 @@ namespace ts {
24002400
}
24012401
}
24022402

2403+
function lookupSymbolForName(name: string) {
2404+
return (container.symbol && container.symbol.exports && container.symbol.exports.get(name)) || container.locals.get(name);
2405+
}
2406+
24032407
function bindPropertyAssignment(functionName: string, propertyAccessExpression: PropertyAccessExpression, isPrototypeProperty: boolean) {
2404-
let targetSymbol = container.locals.get(functionName);
2408+
let targetSymbol = lookupSymbolForName(functionName);
24052409

24062410
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
24072411
targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol;
@@ -2423,7 +2427,7 @@ namespace ts {
24232427
function bindCallExpression(node: CallExpression) {
24242428
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
24252429
// this check if we've already seen the module indicator
2426-
if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteral*/false)) {
2430+
if (!file.commonJsModuleIndicator && isRequireCall(node, /*checkArgumentIsStringLiteral*/ false)) {
24272431
setCommonJsModuleIndicator(node);
24282432
}
24292433
}

0 commit comments

Comments
 (0)