From 6dcf3cf75696d79a7f422ab8a7f423bc36352aed Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 10 Nov 2015 12:06:25 -0800 Subject: [PATCH 01/35] Add case sensitivity-check, only error on failure when outDir is specified and resource based paths are found --- src/compiler/program.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8f031a4de43..aee66834a11 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -888,7 +888,7 @@ namespace ts { function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string { let commonPathComponents: string[]; - forEach(files, sourceFile => { + const failed = forEach(files, sourceFile => { // Each file contributes into common source file path if (isDeclarationFile(sourceFile)) { return; @@ -903,11 +903,12 @@ namespace ts { return; } + const caseSensitive = host.useCaseSensitiveFileNames(); for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { - if (commonPathComponents[i] !== sourcePathComponents[i]) { + if (caseSensitive ? commonPathComponents[i] !== sourcePathComponents[i] : commonPathComponents[i].toLocaleLowerCase() !== sourcePathComponents[i].toLocaleLowerCase()) { if (i === 0) { - programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); - return; + // Failed to find any common path component + return true; } // New common path found that is 0 -> i-1 @@ -922,6 +923,11 @@ namespace ts { } }); + // A common path can not be found when paths span multiple drives on windows, for example + if (failed) { + return ""; + } + if (!commonPathComponents) { // Can happen when all input files are .d.ts files return currentDirectory; } @@ -1045,6 +1051,10 @@ namespace ts { else { // Compute the commonSourceDirectory from the input files commonSourceDirectory = computeCommonSourceDirectory(files); + // If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure + if (options.outDir && commonSourceDirectory === "" && forEach(files, file => getRootLength(file.fileName) > 1)) { + programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); + } } if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) { From 97d170b388102bded0fdd68384c3a43b4f871fe6 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 10 Nov 2015 13:10:44 -0800 Subject: [PATCH 02/35] Support to tests for absolute paths, add common src dir edgecase tests --- src/harness/compilerRunner.ts | 22 ++++++------------- tests/baselines/reference/commonSourceDir1.js | 13 +++++++++++ .../reference/commonSourceDir1.symbols | 8 +++++++ .../reference/commonSourceDir1.types | 8 +++++++ .../reference/commonSourceDir2.errors.txt | 9 ++++++++ tests/baselines/reference/commonSourceDir2.js | 12 ++++++++++ tests/baselines/reference/commonSourceDir3.js | 12 ++++++++++ .../reference/commonSourceDir3.symbols | 8 +++++++ .../reference/commonSourceDir3.types | 8 +++++++ .../reference/commonSourceDir4.errors.txt | 9 ++++++++ tests/baselines/reference/commonSourceDir4.js | 12 ++++++++++ tests/cases/compiler/commonSourceDir1.ts | 6 +++++ tests/cases/compiler/commonSourceDir2.ts | 6 +++++ tests/cases/compiler/commonSourceDir3.ts | 6 +++++ tests/cases/compiler/commonSourceDir4.ts | 7 ++++++ 15 files changed, 131 insertions(+), 15 deletions(-) create mode 100644 tests/baselines/reference/commonSourceDir1.js create mode 100644 tests/baselines/reference/commonSourceDir1.symbols create mode 100644 tests/baselines/reference/commonSourceDir1.types create mode 100644 tests/baselines/reference/commonSourceDir2.errors.txt create mode 100644 tests/baselines/reference/commonSourceDir2.js create mode 100644 tests/baselines/reference/commonSourceDir3.js create mode 100644 tests/baselines/reference/commonSourceDir3.symbols create mode 100644 tests/baselines/reference/commonSourceDir3.types create mode 100644 tests/baselines/reference/commonSourceDir4.errors.txt create mode 100644 tests/baselines/reference/commonSourceDir4.js create mode 100644 tests/cases/compiler/commonSourceDir1.ts create mode 100644 tests/cases/compiler/commonSourceDir2.ts create mode 100644 tests/cases/compiler/commonSourceDir3.ts create mode 100644 tests/cases/compiler/commonSourceDir4.ts diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 848f229f109..f7bb23527dd 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -45,14 +45,10 @@ class CompilerBaselineRunner extends RunnerBase { // Mocha holds onto the closure environment of the describe callback even after the test is done. // Everything declared here should be cleared out in the "after" callback. let justName: string; - let content: string; - let testCaseContent: { settings: Harness.TestCaseParser.CompilerSettings; testUnitData: Harness.TestCaseParser.TestUnitData[]; }; - let units: Harness.TestCaseParser.TestUnitData[]; let tcSettings: Harness.TestCaseParser.CompilerSettings; let lastUnit: Harness.TestCaseParser.TestUnitData; - let rootDir: string; let result: Harness.Compiler.CompilerResult; let program: ts.Program; @@ -65,12 +61,12 @@ class CompilerBaselineRunner extends RunnerBase { before(() => { justName = fileName.replace(/^.*[\\\/]/, ""); // strips the fileName from the path. - content = Harness.IO.readFile(fileName); - testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); - units = testCaseContent.testUnitData; + const content = Harness.IO.readFile(fileName); + const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); + const units = testCaseContent.testUnitData; tcSettings = testCaseContent.settings; lastUnit = units[units.length - 1]; - rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; + const rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; harnessCompiler = Harness.Compiler.getCompiler(); // We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test) // If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references, @@ -78,16 +74,16 @@ class CompilerBaselineRunner extends RunnerBase { toBeCompiled = []; otherFiles = []; if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) { - toBeCompiled.push({ unitName: rootDir + lastUnit.name, content: lastUnit.content }); + toBeCompiled.push({ unitName: ts.isRootedDiskPath(lastUnit.name) ? lastUnit.name : rootDir + lastUnit.name, content: lastUnit.content }); units.forEach(unit => { if (unit.name !== lastUnit.name) { - otherFiles.push({ unitName: rootDir + unit.name, content: unit.content }); + otherFiles.push({ unitName: ts.isRootedDiskPath(unit.name) ? unit.name : rootDir + unit.name, content: unit.content }); } }); } else { toBeCompiled = units.map(unit => { - return { unitName: rootDir + unit.name, content: unit.content }; + return { unitName: ts.isRootedDiskPath(unit.name) ? unit.name : rootDir + unit.name, content: unit.content }; }); } @@ -104,12 +100,8 @@ class CompilerBaselineRunner extends RunnerBase { // Mocha holds onto the closure environment of the describe callback even after the test is done. // Therefore we have to clean out large objects after the test is done. justName = undefined; - content = undefined; - testCaseContent = undefined; - units = undefined; tcSettings = undefined; lastUnit = undefined; - rootDir = undefined; result = undefined; program = undefined; options = undefined; diff --git a/tests/baselines/reference/commonSourceDir1.js b/tests/baselines/reference/commonSourceDir1.js new file mode 100644 index 00000000000..68833aed49d --- /dev/null +++ b/tests/baselines/reference/commonSourceDir1.js @@ -0,0 +1,13 @@ +//// [tests/cases/compiler/commonSourceDir1.ts] //// + +//// [bar.ts] +var x: number; + +//// [baz.ts] +var y: number; + + +//// [bar.js] +var x; +//// [baz.js] +var y; diff --git a/tests/baselines/reference/commonSourceDir1.symbols b/tests/baselines/reference/commonSourceDir1.symbols new file mode 100644 index 00000000000..9248e0c97af --- /dev/null +++ b/tests/baselines/reference/commonSourceDir1.symbols @@ -0,0 +1,8 @@ +=== A:/foo/bar.ts === +var x: number; +>x : Symbol(x, Decl(bar.ts, 0, 3)) + +=== A:/foo/baz.ts === +var y: number; +>y : Symbol(y, Decl(baz.ts, 0, 3)) + diff --git a/tests/baselines/reference/commonSourceDir1.types b/tests/baselines/reference/commonSourceDir1.types new file mode 100644 index 00000000000..6c9864c02cc --- /dev/null +++ b/tests/baselines/reference/commonSourceDir1.types @@ -0,0 +1,8 @@ +=== A:/foo/bar.ts === +var x: number; +>x : number + +=== A:/foo/baz.ts === +var y: number; +>y : number + diff --git a/tests/baselines/reference/commonSourceDir2.errors.txt b/tests/baselines/reference/commonSourceDir2.errors.txt new file mode 100644 index 00000000000..85bcf5d9c72 --- /dev/null +++ b/tests/baselines/reference/commonSourceDir2.errors.txt @@ -0,0 +1,9 @@ +error TS5009: Cannot find the common subdirectory path for the input files. + + +!!! error TS5009: Cannot find the common subdirectory path for the input files. +==== A:/foo/bar.ts (0 errors) ==== + var x: number; + +==== B:/foo/baz.ts (0 errors) ==== + var y: number; \ No newline at end of file diff --git a/tests/baselines/reference/commonSourceDir2.js b/tests/baselines/reference/commonSourceDir2.js new file mode 100644 index 00000000000..cf263b51fb6 --- /dev/null +++ b/tests/baselines/reference/commonSourceDir2.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/commonSourceDir2.ts] //// + +//// [bar.ts] +var x: number; + +//// [baz.ts] +var y: number; + +//// [bar.js] +var x; +//// [baz.js] +var y; diff --git a/tests/baselines/reference/commonSourceDir3.js b/tests/baselines/reference/commonSourceDir3.js new file mode 100644 index 00000000000..0535d51f4bf --- /dev/null +++ b/tests/baselines/reference/commonSourceDir3.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/commonSourceDir3.ts] //// + +//// [bar.ts] +var x: number; + +//// [baz.ts] +var y: number; + +//// [bar.js] +var x; +//// [baz.js] +var y; diff --git a/tests/baselines/reference/commonSourceDir3.symbols b/tests/baselines/reference/commonSourceDir3.symbols new file mode 100644 index 00000000000..b8783523dfd --- /dev/null +++ b/tests/baselines/reference/commonSourceDir3.symbols @@ -0,0 +1,8 @@ +=== A:/foo/bar.ts === +var x: number; +>x : Symbol(x, Decl(bar.ts, 0, 3)) + +=== a:/foo/baz.ts === +var y: number; +>y : Symbol(y, Decl(baz.ts, 0, 3)) + diff --git a/tests/baselines/reference/commonSourceDir3.types b/tests/baselines/reference/commonSourceDir3.types new file mode 100644 index 00000000000..a0b95275897 --- /dev/null +++ b/tests/baselines/reference/commonSourceDir3.types @@ -0,0 +1,8 @@ +=== A:/foo/bar.ts === +var x: number; +>x : number + +=== a:/foo/baz.ts === +var y: number; +>y : number + diff --git a/tests/baselines/reference/commonSourceDir4.errors.txt b/tests/baselines/reference/commonSourceDir4.errors.txt new file mode 100644 index 00000000000..f3493504e4d --- /dev/null +++ b/tests/baselines/reference/commonSourceDir4.errors.txt @@ -0,0 +1,9 @@ +error TS5009: Cannot find the common subdirectory path for the input files. + + +!!! error TS5009: Cannot find the common subdirectory path for the input files. +==== A:/foo/bar.ts (0 errors) ==== + var x: number; + +==== a:/foo/baz.ts (0 errors) ==== + var y: number; \ No newline at end of file diff --git a/tests/baselines/reference/commonSourceDir4.js b/tests/baselines/reference/commonSourceDir4.js new file mode 100644 index 00000000000..2f2af9f68b2 --- /dev/null +++ b/tests/baselines/reference/commonSourceDir4.js @@ -0,0 +1,12 @@ +//// [tests/cases/compiler/commonSourceDir4.ts] //// + +//// [bar.ts] +var x: number; + +//// [baz.ts] +var y: number; + +//// [bar.js] +var x; +//// [baz.js] +var y; diff --git a/tests/cases/compiler/commonSourceDir1.ts b/tests/cases/compiler/commonSourceDir1.ts new file mode 100644 index 00000000000..1a178ac0226 --- /dev/null +++ b/tests/cases/compiler/commonSourceDir1.ts @@ -0,0 +1,6 @@ +// @outDir: A:/ +// @Filename: A:/foo/bar.ts +var x: number; + +// @Filename: A:/foo/baz.ts +var y: number; diff --git a/tests/cases/compiler/commonSourceDir2.ts b/tests/cases/compiler/commonSourceDir2.ts new file mode 100644 index 00000000000..68dab0727a3 --- /dev/null +++ b/tests/cases/compiler/commonSourceDir2.ts @@ -0,0 +1,6 @@ +// @outDir: A:/ +// @Filename: A:/foo/bar.ts +var x: number; + +// @Filename: B:/foo/baz.ts +var y: number; \ No newline at end of file diff --git a/tests/cases/compiler/commonSourceDir3.ts b/tests/cases/compiler/commonSourceDir3.ts new file mode 100644 index 00000000000..cc42eb8f267 --- /dev/null +++ b/tests/cases/compiler/commonSourceDir3.ts @@ -0,0 +1,6 @@ +// @outDir: A:/ +// @Filename: A:/foo/bar.ts +var x: number; + +// @Filename: a:/foo/baz.ts +var y: number; \ No newline at end of file diff --git a/tests/cases/compiler/commonSourceDir4.ts b/tests/cases/compiler/commonSourceDir4.ts new file mode 100644 index 00000000000..41ee7a0344a --- /dev/null +++ b/tests/cases/compiler/commonSourceDir4.ts @@ -0,0 +1,7 @@ +// @useCaseSensitiveFileNames: true +// @outDir: A:/ +// @Filename: A:/foo/bar.ts +var x: number; + +// @Filename: a:/foo/baz.ts +var y: number; \ No newline at end of file From a1cf51faacf18f4a3f91530688ec2c77fefd698d Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 10 Nov 2015 13:25:09 -0800 Subject: [PATCH 03/35] use canonical filename function --- src/compiler/program.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index aee66834a11..03305dd368d 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -894,7 +894,7 @@ namespace ts { return; } - const sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory); + const sourcePathComponents = getNormalizedPathComponents(getCanonicalFileName(sourceFile.fileName), currentDirectory); sourcePathComponents.pop(); // The base file name is not part of the common directory path if (!commonPathComponents) { @@ -903,9 +903,8 @@ namespace ts { return; } - const caseSensitive = host.useCaseSensitiveFileNames(); for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { - if (caseSensitive ? commonPathComponents[i] !== sourcePathComponents[i] : commonPathComponents[i].toLocaleLowerCase() !== sourcePathComponents[i].toLocaleLowerCase()) { + if (commonPathComponents[i] !== sourcePathComponents[i]) { if (i === 0) { // Failed to find any common path component return true; From 79b7146d0bbb3c80cb3a73a6fa2d86894af97d6a Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Nov 2015 13:30:26 -0800 Subject: [PATCH 04/35] Cleanup of types --- src/compiler/checker.ts | 2 +- src/compiler/parser.ts | 56 +++---- src/compiler/types.ts | 337 +++++++++++++++++++++++++++++++++----- src/compiler/utilities.ts | 4 +- src/services/services.ts | 96 +++++------ 5 files changed, 371 insertions(+), 124 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f1593abb177..bfd2eb8d7b8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9766,7 +9766,7 @@ namespace ts { return type; } - function checkFunctionExpressionOrObjectLiteralMethodBody(node: FunctionExpression | MethodDeclaration) { + function checkFunctionExpressionOrObjectLiteralMethodBody(node: ArrowFunction | FunctionExpression | MethodDeclaration) { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); const isAsync = isAsyncFunctionLike(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 18e9cdea406..39b5a5d322e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1082,7 +1082,7 @@ namespace ts { token === SyntaxKind.NumericLiteral; } - function parsePropertyNameWorker(allowComputedPropertyNames: boolean): DeclarationName { + function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral) { return parseLiteralNode(/*internName*/ true); } @@ -1092,7 +1092,7 @@ namespace ts { return parseIdentifierName(); } - function parsePropertyName(): DeclarationName { + function parsePropertyName(): PropertyName { return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ true); } @@ -1152,7 +1152,7 @@ namespace ts { } function parseAnyContextualModifier(): boolean { - return isModifier(token) && tryParse(nextTokenCanFollowModifier); + return isModifierKind(token) && tryParse(nextTokenCanFollowModifier); } function canFollowModifier(): boolean { @@ -1999,7 +1999,7 @@ namespace ts { } function isStartOfParameter(): boolean { - return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifier(token) || token === SyntaxKind.AtToken; + return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifierKind(token) || token === SyntaxKind.AtToken; } function setModifiers(node: Node, modifiers: ModifiersArray) { @@ -2020,7 +2020,7 @@ namespace ts { node.name = parseIdentifierOrPattern(); - if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifier(token)) { + if (getFullWidth(node.name) === 0 && node.flags === 0 && isModifierKind(token)) { // in cases like // 'use strict' // function foo(static) @@ -2127,8 +2127,8 @@ namespace ts { parseSemicolon(); } - function parseSignatureMember(kind: SyntaxKind): SignatureDeclaration { - const node = createNode(kind); + function parseSignatureMember(kind: SyntaxKind): CallSignatureDeclaration | ConstructSignatureDeclaration { + const node = createNode(kind); if (kind === SyntaxKind.ConstructSignature) { parseExpected(SyntaxKind.NewKeyword); } @@ -2167,7 +2167,7 @@ namespace ts { return true; } - if (isModifier(token)) { + if (isModifierKind(token)) { nextToken(); if (isIdentifier()) { return true; @@ -2210,13 +2210,13 @@ namespace ts { return finishNode(node); } - function parsePropertyOrMethodSignature(): Declaration { + function parsePropertyOrMethodSignature(): PropertySignature | MethodSignature { const fullStart = scanner.getStartPos(); const name = parsePropertyName(); const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { - const method = createNode(SyntaxKind.MethodSignature, fullStart); + const method = createNode(SyntaxKind.MethodSignature, fullStart); method.name = name; method.questionToken = questionToken; @@ -2227,7 +2227,7 @@ namespace ts { return finishNode(method); } else { - const property = createNode(SyntaxKind.PropertySignature, fullStart); + const property = createNode(SyntaxKind.PropertySignature, fullStart); property.name = name; property.questionToken = questionToken; property.type = parseTypeAnnotation(); @@ -2243,7 +2243,7 @@ namespace ts { case SyntaxKind.OpenBracketToken: // Both for indexers and computed properties return true; default: - if (isModifier(token)) { + if (isModifierKind(token)) { const result = lookAhead(isStartOfIndexSignatureDeclaration); if (result) { return result; @@ -2255,7 +2255,7 @@ namespace ts { } function isStartOfIndexSignatureDeclaration() { - while (isModifier(token)) { + while (isModifierKind(token)) { nextToken(); } @@ -2271,7 +2271,7 @@ namespace ts { canParseSemicolon(); } - function parseTypeMember(): Declaration { + function parseTypeMember(): TypeElement { switch (token) { case SyntaxKind.OpenParenToken: case SyntaxKind.LessThanToken: @@ -2296,7 +2296,7 @@ namespace ts { // when incrementally parsing as the parser will produce the Index declaration // if it has the same text regardless of whether it is inside a class or an // object type. - if (isModifier(token)) { + if (isModifierKind(token)) { const result = tryParse(parseIndexSignatureWithModifiers); if (result) { return result; @@ -2329,14 +2329,14 @@ namespace ts { return finishNode(node); } - function parseObjectTypeMembers(): NodeArray { - let members: NodeArray; + function parseObjectTypeMembers(): NodeArray { + let members: NodeArray; if (parseExpected(SyntaxKind.OpenBraceToken)) { members = parseList(ParsingContext.TypeMembers, parseTypeMember); parseExpected(SyntaxKind.CloseBraceToken); } else { - members = createMissingList(); + members = createMissingList(); } return members; @@ -2478,11 +2478,11 @@ namespace ts { // ( ... return true; } - if (isIdentifier() || isModifier(token)) { + if (isIdentifier() || isModifierKind(token)) { nextToken(); if (token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || token === SyntaxKind.QuestionToken || token === SyntaxKind.EqualsToken || - isIdentifier() || isModifier(token)) { + isIdentifier() || isModifierKind(token)) { // ( id : // ( id , // ( id ? @@ -2889,7 +2889,7 @@ namespace ts { } // This *could* be a parenthesized arrow function. - // Return Unknown to const the caller know. + // Return Unknown to let the caller know. return Tristate.Unknown; } else { @@ -2988,7 +2988,7 @@ namespace ts { // user meant to supply a block. For example, if the user wrote: // // a => - // const v = 0; + // let v = 0; // } // // they may be missing an open brace. Check to see if that's the case so we can @@ -3215,7 +3215,7 @@ namespace ts { /** * Parse ES7 unary expression and await expression - * + * * ES7 UnaryExpression: * 1) SimpleUnaryExpression[?yield] * 2) IncrementExpression[?yield] ** UnaryExpression[?yield] @@ -4716,7 +4716,7 @@ namespace ts { return finishNode(node); } - function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { + function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { const method = createNode(SyntaxKind.MethodDeclaration, fullStart); method.decorators = decorators; setModifiers(method, modifiers); @@ -4730,7 +4730,7 @@ namespace ts { return finishNode(method); } - function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: DeclarationName, questionToken: Node): ClassElement { + function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement { const property = createNode(SyntaxKind.PropertyDeclaration, fullStart); property.decorators = decorators; setModifiers(property, modifiers); @@ -4804,7 +4804,7 @@ namespace ts { } // Eat up all modifiers, but hold on to the last one in case it is actually an identifier. - while (isModifier(token)) { + while (isModifierKind(token)) { idToken = token; // If the idToken is a class modifier (protected, private, public, and static), it is // certain that we are starting to parse class member. This allows better error recovery @@ -5014,8 +5014,8 @@ namespace ts { // implements is a future reserved word so // 'class implements' might mean either // - class expression with omitted name, 'implements' starts heritage clause - // - class with name 'implements' - // 'isImplementsClause' helps to disambiguate between these two cases + // - class with name 'implements' + // 'isImplementsClause' helps to disambiguate between these two cases return isIdentifier() && !isImplementsClause() ? parseIdentifier() : undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 08313f832a2..2489c049b68 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -348,7 +348,7 @@ namespace ts { LastKeyword = OfKeyword, FirstFutureReservedWord = ImplementsKeyword, LastFutureReservedWord = YieldKeyword, - FirstTypeNode = TypeReference, + FirstTypeNode = TypePredicate, LastTypeNode = ParenthesizedType, FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, @@ -474,15 +474,29 @@ namespace ts { hasTrailingComma?: boolean; } - export interface ModifiersArray extends NodeArray { + export interface ModifiersArray extends NodeArray { flags: number; } + // @kind(SyntaxKind.AbstractKeyword) + // @kind(SyntaxKind.AsyncKeyword) + // @kind(SyntaxKind.ConstKeyword) + // @kind(SyntaxKind.DeclareKeyword) + // @kind(SyntaxKind.DefaultKeyword) + // @kind(SyntaxKind.ExportKeyword) + // @kind(SyntaxKind.PublicKeyword) + // @kind(SyntaxKind.PrivateKeyword) + // @kind(SyntaxKind.ProtectedKeyword) + // @kind(SyntaxKind.StaticKeyword) + export interface Modifier extends Node { } + + // @kind(SyntaxKind.Identifier) export interface Identifier extends PrimaryExpression { text: string; // Text of identifier (with escapes converted to characters) originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later } + // @kind(SyntaxKind.QualifiedName) export interface QualifiedName extends Node { // Must have same layout as PropertyAccess left: EntityName; @@ -491,6 +505,8 @@ namespace ts { export type EntityName = Identifier | QualifiedName; + export type PropertyName = Identifier | LiteralExpression | ComputedPropertyName; + export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName | BindingPattern; export interface Declaration extends Node { @@ -498,14 +514,21 @@ namespace ts { name?: DeclarationName; } + export interface DeclarationStatement extends Declaration, Statement { + name?: Identifier; + } + + // @kind(SyntaxKind.ComputedPropertyName) export interface ComputedPropertyName extends Node { expression: Expression; } + // @kind(SyntaxKind.Decorator) export interface Decorator extends Node { expression: LeftHandSideExpression; } + // @kind(SyntaxKind.TypeParameter) export interface TypeParameterDeclaration extends Declaration { name: Identifier; constraint?: TypeNode; @@ -515,12 +538,19 @@ namespace ts { } export interface SignatureDeclaration extends Declaration { + name?: PropertyName; typeParameters?: NodeArray; parameters: NodeArray; type?: TypeNode; } - // SyntaxKind.VariableDeclaration + // @kind(SyntaxKind.CallSignature) + export interface CallSignatureDeclaration extends SignatureDeclaration, TypeElement { } + + // @kind(SyntaxKind.ConstructSignature) + export interface ConstructSignatureDeclaration extends SignatureDeclaration, TypeElement { } + + // @kind(SyntaxKind.VariableDeclaration) export interface VariableDeclaration extends Declaration { parent?: VariableDeclarationList; name: Identifier | BindingPattern; // Declared variable name @@ -528,11 +558,12 @@ namespace ts { initializer?: Expression; // Optional initializer } + // @kind(SyntaxKind.VariableDeclarationList) export interface VariableDeclarationList extends Node { declarations: NodeArray; } - // SyntaxKind.Parameter + // @kind(SyntaxKind.Parameter) export interface ParameterDeclaration extends Declaration { dotDotDotToken?: Node; // Present on rest parameter name: Identifier | BindingPattern; // Declared parameter name @@ -541,7 +572,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - // SyntaxKind.BindingElement + // @kind(SyntaxKind.BindingElement) export interface BindingElement extends Declaration { propertyName?: Identifier; // Binding property name (in object binding pattern) dotDotDotToken?: Node; // Present on rest binding element @@ -549,27 +580,35 @@ namespace ts { initializer?: Expression; // Optional initializer } - // SyntaxKind.Property - export interface PropertyDeclaration extends Declaration, ClassElement { - name: DeclarationName; // Declared property name + // @kind(SyntaxKind.PropertySignature) + export interface PropertySignature extends TypeElement { + name: PropertyName; // Declared property name questionToken?: Node; // Present on optional property type?: TypeNode; // Optional type annotation + } + + // @kind(SyntaxKind.PropertyDeclaration) + export interface PropertyDeclaration extends ClassElement { + questionToken?: Node; // Present for use with reporting a grammar error + name: PropertyName; + type?: TypeNode; initializer?: Expression; // Optional initializer } export interface ObjectLiteralElement extends Declaration { _objectLiteralBrandBrand: any; - } + name?: PropertyName; + } - // SyntaxKind.PropertyAssignment + // @kind(SyntaxKind.PropertyAssignment) export interface PropertyAssignment extends ObjectLiteralElement { _propertyAssignmentBrand: any; - name: DeclarationName; + name: PropertyName; questionToken?: Node; initializer: Expression; } - // SyntaxKind.ShorthandPropertyAssignment + // @kind(SyntaxKind.ShorthandPropertyAssignment) export interface ShorthandPropertyAssignment extends ObjectLiteralElement { name: Identifier; questionToken?: Node; @@ -595,10 +634,20 @@ namespace ts { initializer?: Expression; } + export interface PropertyLikeDeclaration extends Declaration { + name: PropertyName; + } + export interface BindingPattern extends Node { elements: NodeArray; } + // @kind(SyntaxKind.ObjectBindingPattern) + export interface ObjectBindingPattern extends BindingPattern { } + + // @kind(SyntaxKind.ArrayBindingPattern) + export interface ArrayBindingPattern extends BindingPattern { } + /** * Several node kinds share function-like features such as a signature, * a name, and a body. These nodes should extend FunctionLikeDeclaration. @@ -615,9 +664,15 @@ namespace ts { body?: Block | Expression; } - export interface FunctionDeclaration extends FunctionLikeDeclaration, Statement { + // @kind(SyntaxKind.FunctionDeclaration) + export interface FunctionDeclaration extends FunctionLikeDeclaration, DeclarationStatement { name?: Identifier; - body?: Block; + body?: FunctionBody; + } + + // @kind(SyntaxKind.MethodSignature) + export interface MethodSignature extends SignatureDeclaration, TypeElement { + name: PropertyName; } // Note that a MethodDeclaration is considered both a ClassElement and an ObjectLiteralElement. @@ -629,15 +684,19 @@ namespace ts { // Because of this, it may be necessary to determine what sort of MethodDeclaration you have // at later stages of the compiler pipeline. In that case, you can either check the parent kind // of the method, or use helpers like isObjectLiteralMethodDeclaration + // @kind(SyntaxKind.MethodDeclaration) export interface MethodDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { - body?: Block; + name: PropertyName; + body?: FunctionBody; } + // @kind(SyntaxKind.Constructor) export interface ConstructorDeclaration extends FunctionLikeDeclaration, ClassElement { - body?: Block; + body?: FunctionBody; } // For when we encounter a semicolon in a class declaration. ES6 allows these as class elements. + // @kind(SyntaxKind.SemicolonClassElement) export interface SemicolonClassElement extends ClassElement { _semicolonClassElementBrand: any; } @@ -646,13 +705,27 @@ namespace ts { // ClassElement and an ObjectLiteralElement. export interface AccessorDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { _accessorDeclarationBrand: any; - body: Block; + name: PropertyName; + body: FunctionBody; } - export interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement { + // @kind(SyntaxKind.GetAccessor) + export interface GetAccessorDeclaration extends AccessorDeclaration { } + + // @kind(SyntaxKind.SetAccessor) + export interface SetAccessorDeclaration extends AccessorDeclaration { } + + // @kind(SyntaxKind.IndexSignature) + export interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement, TypeElement { _indexSignatureDeclarationBrand: any; } + // @kind(SyntaxKind.AnyKeyword) + // @kind(SyntaxKind.NumberKeyword) + // @kind(SyntaxKind.BooleanKeyword) + // @kind(SyntaxKind.StringKeyword) + // @kind(SyntaxKind.SymbolKeyword) + // @kind(SyntaxKind.VoidKeyword) export interface TypeNode extends Node { _typeNodeBrand: any; } @@ -661,29 +734,41 @@ namespace ts { _functionOrConstructorTypeNodeBrand: any; } + // @kind(SyntaxKind.FunctionType) + export interface FunctionTypeNode extends FunctionOrConstructorTypeNode { } + + // @kind(SyntaxKind.ConstructorType) + export interface ConstructorTypeNode extends FunctionOrConstructorTypeNode { } + + // @kind(SyntaxKind.TypeReference) export interface TypeReferenceNode extends TypeNode { typeName: EntityName; typeArguments?: NodeArray; } + // @kind(SyntaxKind.TypePredicate) export interface TypePredicateNode extends TypeNode { parameterName: Identifier; type: TypeNode; } + // @kind(SyntaxKind.TypeQuery) export interface TypeQueryNode extends TypeNode { exprName: EntityName; } // A TypeLiteral is the declaration node for an anonymous symbol. + // @kind(SyntaxKind.TypeLiteral) export interface TypeLiteralNode extends TypeNode, Declaration { - members: NodeArray; + members: NodeArray; } + // @kind(SyntaxKind.ArrayType) export interface ArrayTypeNode extends TypeNode { elementType: TypeNode; } + // @kind(SyntaxKind.TupleType) export interface TupleTypeNode extends TypeNode { elementTypes: NodeArray; } @@ -692,16 +777,20 @@ namespace ts { types: NodeArray; } + // @kind(SyntaxKind.UnionType) export interface UnionTypeNode extends UnionOrIntersectionTypeNode { } + // @kind(SyntaxKind.IntersectionType) export interface IntersectionTypeNode extends UnionOrIntersectionTypeNode { } + // @kind(SyntaxKind.ParenthesizedType) export interface ParenthesizedTypeNode extends TypeNode { type: TypeNode; } // Note that a StringLiteral AST node is both an Expression and a TypeNode. The latter is // because string literals can appear in type annotations as well. + // @kind(SyntaxKind.StringLiteral) export interface StringLiteral extends LiteralExpression, TypeNode { _stringLiteralBrand: any; } @@ -718,6 +807,9 @@ namespace ts { contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution } + // @kind(SyntaxKind.OmittedExpression) + export interface OmittedExpression extends Expression { } + export interface UnaryExpression extends Expression { _unaryExpressionBrand: any; } @@ -726,11 +818,13 @@ namespace ts { _incrementExpressionBrand: any; } + // @kind(SyntaxKind.PrefixUnaryExpression) export interface PrefixUnaryExpression extends IncrementExpression { operator: SyntaxKind; operand: UnaryExpression; } + // @kind(SyntaxKind.PostfixUnaryExpression) export interface PostfixUnaryExpression extends IncrementExpression { operand: LeftHandSideExpression; operator: SyntaxKind; @@ -748,37 +842,49 @@ namespace ts { _memberExpressionBrand: any; } + // @kind(SyntaxKind.TrueKeyword) + // @kind(SyntaxKind.FalseKeyword) + // @kind(SyntaxKind.NullKeyword) + // @kind(SyntaxKind.ThisKeyword) + // @kind(SyntaxKind.SuperKeyword) export interface PrimaryExpression extends MemberExpression { _primaryExpressionBrand: any; } + // @kind(SyntaxKind.DeleteExpression) export interface DeleteExpression extends UnaryExpression { expression: UnaryExpression; } + // @kind(SyntaxKind.TypeOfExpression) export interface TypeOfExpression extends UnaryExpression { expression: UnaryExpression; } + // @kind(SyntaxKind.VoidExpression) export interface VoidExpression extends UnaryExpression { expression: UnaryExpression; } + // @kind(SyntaxKind.AwaitExpression) export interface AwaitExpression extends UnaryExpression { expression: UnaryExpression; } + // @kind(SyntaxKind.YieldExpression) export interface YieldExpression extends Expression { asteriskToken?: Node; expression?: Expression; } + // @kind(SyntaxKind.BinaryExpression) export interface BinaryExpression extends Expression { left: Expression; operatorToken: Node; right: Expression; } + // @kind(SyntaxKind.ConditionalExpression) export interface ConditionalExpression extends Expression { condition: Expression; questionToken: Node; @@ -787,24 +893,37 @@ namespace ts { whenFalse: Expression; } + export type FunctionBody = Block; + export type ConciseBody = FunctionBody | Expression; + + // @kind(SyntaxKind.FunctionExpression) export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclaration { name?: Identifier; - body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional + body: FunctionBody; // Required, whereas the member inherited from FunctionDeclaration is optional } + // @kind(SyntaxKind.ArrowFunction) export interface ArrowFunction extends Expression, FunctionLikeDeclaration { equalsGreaterThanToken: Node; + body: ConciseBody; } // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral, // or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters. // For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1". + // @kind(SyntaxKind.NumericLiteral) + // @kind(SyntaxKind.RegularExpressionLiteral) + // @kind(SyntaxKind.NoSubstitutionTemplateLiteral) + // @kind(SyntaxKind.TemplateHead) + // @kind(SyntaxKind.TemplateMiddle) + // @kind(SyntaxKind.TemplateTail) export interface LiteralExpression extends PrimaryExpression { text: string; isUnterminated?: boolean; hasExtendedUnicodeEscape?: boolean; } + // @kind(SyntaxKind.TemplateExpression) export interface TemplateExpression extends PrimaryExpression { head: LiteralExpression; templateSpans: NodeArray; @@ -812,52 +931,63 @@ namespace ts { // Each of these corresponds to a substitution expression and a template literal, in that order. // The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral. + // @kind(SyntaxKind.TemplateSpan) export interface TemplateSpan extends Node { expression: Expression; literal: LiteralExpression; } + // @kind(SyntaxKind.ParenthesizedExpression) export interface ParenthesizedExpression extends PrimaryExpression { expression: Expression; } + // @kind(SyntaxKind.ArrayLiteralExpression) export interface ArrayLiteralExpression extends PrimaryExpression { elements: NodeArray; } + // @kind(SyntaxKind.SpreadElementExpression) export interface SpreadElementExpression extends Expression { expression: Expression; } // An ObjectLiteralExpression is the declaration node for an anonymous symbol. + // @kind(SyntaxKind.ObjectLiteralExpression) export interface ObjectLiteralExpression extends PrimaryExpression, Declaration { properties: NodeArray; } + // @kind(SyntaxKind.PropertyAccessExpression) export interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; dotToken: Node; name: Identifier; } + // @kind(SyntaxKind.ElementAccessExpression) export interface ElementAccessExpression extends MemberExpression { expression: LeftHandSideExpression; argumentExpression?: Expression; } + // @kind(SyntaxKind.CallExpression) export interface CallExpression extends LeftHandSideExpression { expression: LeftHandSideExpression; typeArguments?: NodeArray; arguments: NodeArray; } + // @kind(SyntaxKind.ExpressionWithTypeArguments) export interface ExpressionWithTypeArguments extends TypeNode { expression: LeftHandSideExpression; typeArguments?: NodeArray; } + // @kind(SyntaxKind.NewExpression) export interface NewExpression extends CallExpression, PrimaryExpression { } + // @kind(SyntaxKind.TaggedTemplateExpression) export interface TaggedTemplateExpression extends MemberExpression { tag: LeftHandSideExpression; template: LiteralExpression | TemplateExpression; @@ -865,11 +995,13 @@ namespace ts { export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression | Decorator; + // @kind(SyntaxKind.AsExpression) export interface AsExpression extends Expression { expression: Expression; type: TypeNode; } + // @kind(SyntaxKind.TypeAssertionExpression) export interface TypeAssertion extends UnaryExpression { type: TypeNode; expression: UnaryExpression; @@ -878,6 +1010,7 @@ namespace ts { export type AssertionExpression = TypeAssertion | AsExpression; /// A JSX expression of the form ... + // @kind(SyntaxKind.JsxElement) export interface JsxElement extends PrimaryExpression { openingElement: JsxOpeningElement; children: NodeArray; @@ -885,6 +1018,7 @@ namespace ts { } /// The opening element of a ... JsxElement + // @kind(SyntaxKind.JsxOpeningElement) export interface JsxOpeningElement extends Expression { _openingElementBrand?: any; tagName: EntityName; @@ -892,6 +1026,7 @@ namespace ts { } /// A JSX expression of the form + // @kind(SyntaxKind.JsxSelfClosingElement) export interface JsxSelfClosingElement extends PrimaryExpression, JsxOpeningElement { _selfClosingElementBrand?: any; } @@ -899,24 +1034,29 @@ namespace ts { /// Either the opening tag in a ... pair, or the lone in a self-closing form export type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement; + // @kind(SyntaxKind.JsxAttribute) export interface JsxAttribute extends Node { name: Identifier; /// JSX attribute initializers are optional; is sugar for initializer?: Expression; } + // @kind(SyntaxKind.JsxSpreadAttribute) export interface JsxSpreadAttribute extends Node { expression: Expression; } + // @kind(SyntaxKind.JsxClosingElement) export interface JsxClosingElement extends Node { tagName: EntityName; } + // @kind(SyntaxKind.JsxExpression) export interface JsxExpression extends Expression { expression?: Expression; } + // @kind(SyntaxKind.JsxText) export interface JsxText extends Node { _jsxTextExpressionBrand: any; } @@ -927,18 +1067,36 @@ namespace ts { _statementBrand: any; } + // @kind(SyntaxKind.EmptyStatement) + export interface EmptyStatement extends Statement { } + + // @kind(SyntaxKind.DebuggerStatement) + export interface DebuggerStatement extends Statement { } + + // @kind(SyntaxKind.MissingDeclaration) + // @factoryhidden("name", true) + export interface MissingDeclaration extends DeclarationStatement, ClassElement, ObjectLiteralElement, TypeElement { + name?: Identifier; + } + + export type BlockLike = SourceFile | Block | ModuleBlock | CaseClause; + + // @kind(SyntaxKind.Block) export interface Block extends Statement { statements: NodeArray; } + // @kind(SyntaxKind.VariableStatement) export interface VariableStatement extends Statement { declarationList: VariableDeclarationList; } + // @kind(SyntaxKind.ExpressionStatement) export interface ExpressionStatement extends Statement { expression: Expression; } + // @kind(SyntaxKind.IfStatement) export interface IfStatement extends Statement { expression: Expression; thenStatement: Statement; @@ -949,78 +1107,101 @@ namespace ts { statement: Statement; } + // @kind(SyntaxKind.DoStatement) export interface DoStatement extends IterationStatement { expression: Expression; } + // @kind(SyntaxKind.WhileStatement) export interface WhileStatement extends IterationStatement { expression: Expression; } + // @kind(SyntaxKind.ForStatement) export interface ForStatement extends IterationStatement { initializer?: VariableDeclarationList | Expression; condition?: Expression; incrementor?: Expression; } + // @kind(SyntaxKind.ForInStatement) export interface ForInStatement extends IterationStatement { initializer: VariableDeclarationList | Expression; expression: Expression; } + // @kind(SyntaxKind.ForOfStatement) export interface ForOfStatement extends IterationStatement { initializer: VariableDeclarationList | Expression; expression: Expression; } - export interface BreakOrContinueStatement extends Statement { + // @kind(SyntaxKind.BreakStatement) + export interface BreakStatement extends Statement { label?: Identifier; } + // @kind(SyntaxKind.ContinueStatement) + export interface ContinueStatement extends Statement { + label?: Identifier; + } + + export type BreakOrContinueStatement = BreakStatement | ContinueStatement; + + // @kind(SyntaxKind.ReturnStatement) export interface ReturnStatement extends Statement { expression?: Expression; } + // @kind(SyntaxKind.WithStatement) export interface WithStatement extends Statement { expression: Expression; statement: Statement; } + // @kind(SyntaxKind.SwitchStatement) export interface SwitchStatement extends Statement { expression: Expression; caseBlock: CaseBlock; } + // @kind(SyntaxKind.CaseBlock) export interface CaseBlock extends Node { clauses: NodeArray; } + // @kind(SyntaxKind.CaseClause) export interface CaseClause extends Node { expression?: Expression; statements: NodeArray; } + // @kind(SyntaxKind.DefaultClause) export interface DefaultClause extends Node { statements: NodeArray; } export type CaseOrDefaultClause = CaseClause | DefaultClause; + // @kind(SyntaxKind.LabeledStatement) export interface LabeledStatement extends Statement { label: Identifier; statement: Statement; } + // @kind(SyntaxKind.ThrowStatement) export interface ThrowStatement extends Statement { expression: Expression; } + // @kind(SyntaxKind.TryStatement) export interface TryStatement extends Statement { tryBlock: Block; catchClause?: CatchClause; finallyBlock?: Block; } + // @kind(SyntaxKind.CatchClause) export interface CatchClause extends Node { variableDeclaration: VariableDeclaration; block: Block; @@ -1033,34 +1214,49 @@ namespace ts { members: NodeArray; } - export interface ClassDeclaration extends ClassLikeDeclaration, Statement { + // @kind(SyntaxKind.ClassDeclaration) + export interface ClassDeclaration extends ClassLikeDeclaration, DeclarationStatement { + name?: Identifier; } + // @kind(SyntaxKind.ClassExpression) export interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression { } export interface ClassElement extends Declaration { _classElementBrand: any; + name?: PropertyName; } - export interface InterfaceDeclaration extends Declaration, Statement { + export interface TypeElement extends Declaration { + _typeElementBrand: any; + name?: PropertyName; + // @factoryparam + questionToken?: Node; + } + + // @kind(SyntaxKind.InterfaceDeclaration) + export interface InterfaceDeclaration extends DeclarationStatement { name: Identifier; typeParameters?: NodeArray; heritageClauses?: NodeArray; - members: NodeArray; + members: NodeArray; } + // @kind(SyntaxKind.HeritageClause) export interface HeritageClause extends Node { token: SyntaxKind; types?: NodeArray; } - export interface TypeAliasDeclaration extends Declaration, Statement { + // @kind(SyntaxKind.TypeAliasDeclaration) + export interface TypeAliasDeclaration extends DeclarationStatement { name: Identifier; typeParameters?: NodeArray; type: TypeNode; } + // @kind(SyntaxKind.EnumMember) export interface EnumMember extends Declaration { // This does include ComputedPropertyName, but the parser will give an error // if it parses a ComputedPropertyName in an EnumMember @@ -1068,21 +1264,27 @@ namespace ts { initializer?: Expression; } - export interface EnumDeclaration extends Declaration, Statement { + // @kind(SyntaxKind.EnumDeclaration) + export interface EnumDeclaration extends DeclarationStatement { name: Identifier; members: NodeArray; } - export interface ModuleDeclaration extends Declaration, Statement { + export type ModuleBody = ModuleBlock | ModuleDeclaration; + + // @kind(SyntaxKind.ModuleDeclaration) + export interface ModuleDeclaration extends DeclarationStatement { name: Identifier | LiteralExpression; body: ModuleBlock | ModuleDeclaration; } + // @kind(SyntaxKind.ModuleBlock) export interface ModuleBlock extends Node, Statement { statements: NodeArray; } - export interface ImportEqualsDeclaration extends Declaration, Statement { + // @kind(SyntaxKind.ImportEqualsDeclaration) + export interface ImportEqualsDeclaration extends DeclarationStatement { name: Identifier; // 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external @@ -1090,6 +1292,7 @@ namespace ts { moduleReference: EntityName | ExternalModuleReference; } + // @kind(SyntaxKind.ExternalModuleReference) export interface ExternalModuleReference extends Node { expression?: Expression; } @@ -1098,6 +1301,7 @@ namespace ts { // import "mod" => importClause = undefined, moduleSpecifier = "mod" // In rest of the cases, module specifier is string literal corresponding to module // ImportClause information is shown at its declaration below. + // @kind(SyntaxKind.ImportDeclaration) export interface ImportDeclaration extends Statement { importClause?: ImportClause; moduleSpecifier: Expression; @@ -1109,36 +1313,51 @@ namespace ts { // import d, * as ns from "mod" => name = d, namedBinding: NamespaceImport = { name: ns } // import { a, b as x } from "mod" => name = undefined, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} // import d, { a, b as x } from "mod" => name = d, namedBinding: NamedImports = { elements: [{ name: a }, { name: x, propertyName: b}]} + // @kind(SyntaxKind.ImportClause) export interface ImportClause extends Declaration { name?: Identifier; // Default binding namedBindings?: NamespaceImport | NamedImports; } + // @kind(SyntaxKind.NamespaceImport) export interface NamespaceImport extends Declaration { name: Identifier; } - export interface ExportDeclaration extends Declaration, Statement { + // @kind(SyntaxKind.ExportDeclaration) + export interface ExportDeclaration extends DeclarationStatement { exportClause?: NamedExports; moduleSpecifier?: Expression; } - export interface NamedImportsOrExports extends Node { - elements: NodeArray; + // @kind(SyntaxKind.NamedImports) + export interface NamedImports extends Node { + elements: NodeArray; } - export type NamedImports = NamedImportsOrExports; - export type NamedExports = NamedImportsOrExports; + // @kind(SyntaxKind.NamedExports) + export interface NamedExports extends Node { + elements: NodeArray; + } - export interface ImportOrExportSpecifier extends Declaration { + export type NamedImportsOrExports = NamedImports | NamedExports; + + // @kind(SyntaxKind.ImportSpecifier) + export interface ImportSpecifier extends Declaration { propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) name: Identifier; // Declared name } - export type ImportSpecifier = ImportOrExportSpecifier; - export type ExportSpecifier = ImportOrExportSpecifier; + // @kind(SyntaxKind.ExportSpecifier) + export interface ExportSpecifier extends Declaration { + propertyName?: Identifier; // Name preceding "as" keyword (or undefined when "as" is absent) + name: Identifier; // Declared name + } - export interface ExportAssignment extends Declaration, Statement { + export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier; + + // @kind(SyntaxKind.ExportAssignment) + export interface ExportAssignment extends DeclarationStatement { isExportEquals?: boolean; expression: Expression; } @@ -1153,6 +1372,7 @@ namespace ts { } // represents a top level: { type } expression in a JSDoc comment. + // @kind(SyntaxKind.JSDocTypeExpression) export interface JSDocTypeExpression extends Node { type: JSDocType; } @@ -1161,90 +1381,111 @@ namespace ts { _jsDocTypeBrand: any; } + // @kind(SyntaxKind.JSDocAllType) export interface JSDocAllType extends JSDocType { _JSDocAllTypeBrand: any; } + // @kind(SyntaxKind.JSDocUnknownType) export interface JSDocUnknownType extends JSDocType { _JSDocUnknownTypeBrand: any; } + // @kind(SyntaxKind.JSDocArrayType) export interface JSDocArrayType extends JSDocType { elementType: JSDocType; } + // @kind(SyntaxKind.JSDocUnionType) export interface JSDocUnionType extends JSDocType { types: NodeArray; } + // @kind(SyntaxKind.JSDocTupleType) export interface JSDocTupleType extends JSDocType { types: NodeArray; } + // @kind(SyntaxKind.JSDocNonNullableType) export interface JSDocNonNullableType extends JSDocType { type: JSDocType; } + // @kind(SyntaxKind.JSDocNullableType) export interface JSDocNullableType extends JSDocType { type: JSDocType; } + // @kind(SyntaxKind.JSDocRecordType) export interface JSDocRecordType extends JSDocType, TypeLiteralNode { members: NodeArray; } + // @kind(SyntaxKind.JSDocTypeReference) export interface JSDocTypeReference extends JSDocType { name: EntityName; typeArguments: NodeArray; } + // @kind(SyntaxKind.JSDocOptionalType) export interface JSDocOptionalType extends JSDocType { type: JSDocType; } + // @kind(SyntaxKind.JSDocFunctionType) export interface JSDocFunctionType extends JSDocType, SignatureDeclaration { parameters: NodeArray; type: JSDocType; } + // @kind(SyntaxKind.JSDocVariadicType) export interface JSDocVariadicType extends JSDocType { type: JSDocType; } + // @kind(SyntaxKind.JSDocConstructorType) export interface JSDocConstructorType extends JSDocType { type: JSDocType; } + // @kind(SyntaxKind.JSDocThisType) export interface JSDocThisType extends JSDocType { type: JSDocType; } - export interface JSDocRecordMember extends PropertyDeclaration { + // @kind(SyntaxKind.JSDocRecordMember) + export interface JSDocRecordMember extends PropertySignature { name: Identifier | LiteralExpression; type?: JSDocType; } + // @kind(SyntaxKind.JSDocComment) export interface JSDocComment extends Node { tags: NodeArray; } + // @kind(SyntaxKind.JSDocTag) export interface JSDocTag extends Node { atToken: Node; tagName: Identifier; } + // @kind(SyntaxKind.JSDocTemplateTag) export interface JSDocTemplateTag extends JSDocTag { typeParameters: NodeArray; } + // @kind(SyntaxKind.JSDocReturnTag) export interface JSDocReturnTag extends JSDocTag { typeExpression: JSDocTypeExpression; } + // @kind(SyntaxKind.JSDocTypeTag) export interface JSDocTypeTag extends JSDocTag { typeExpression: JSDocTypeExpression; } + // @kind(SyntaxKind.JSDocParameterTag) export interface JSDocParameterTag extends JSDocTag { preParameterName?: Identifier; typeExpression?: JSDocTypeExpression; @@ -1252,7 +1493,13 @@ namespace ts { isBracketed: boolean; } + export interface AmdDependency { + path: string; + name: string; + } + // Source files are declarations when they are external modules. + // @kind(SyntaxKind.SourceFile) export interface SourceFile extends Declaration { statements: NodeArray; endOfFileToken: Node; @@ -1261,7 +1508,7 @@ namespace ts { /* internal */ path: Path; text: string; - amdDependencies: {path: string; name: string}[]; + amdDependencies: AmdDependency[]; moduleName: string; referencedFiles: FileReference[]; languageVariant: LanguageVariant; @@ -2336,7 +2583,7 @@ namespace ts { export interface ModuleResolutionHost { fileExists(fileName: string): boolean; // readFile function is used to read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json' - // to determine location of bundled typings for node module + // to determine location of bundled typings for node module readFile(fileName: string): string; } @@ -2344,7 +2591,7 @@ namespace ts { resolvedFileName: string; /* * Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be proper external module: - * - be a .d.ts file + * - be a .d.ts file * - use top level imports\exports * - don't use tripleslash references */ @@ -2367,11 +2614,11 @@ namespace ts { getNewLine(): string; /* - * CompilerHost must either implement resolveModuleNames (in case if it wants to be completely in charge of - * module name resolution) or provide implementation for methods from ModuleResolutionHost (in this case compiler + * CompilerHost must either implement resolveModuleNames (in case if it wants to be completely in charge of + * module name resolution) or provide implementation for methods from ModuleResolutionHost (in this case compiler * will appply built-in module resolution logic and use members of ModuleResolutionHost to ask host specific questions). - * If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just - * 'throw new Error("NotImplemented")' + * If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just + * 'throw new Error("NotImplemented")' */ resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 17d780df574..199ca4e636f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1273,7 +1273,7 @@ namespace ts { } // True if the given identifier, string literal, or number literal is the name of a declaration node - export function isDeclarationName(name: Node): boolean { + export function isDeclarationName(name: Node): name is Identifier | StringLiteral | LiteralExpression { if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) { return false; } @@ -1483,7 +1483,7 @@ namespace ts { return node.kind === SyntaxKind.Identifier && (node).text === "Symbol"; } - export function isModifier(token: SyntaxKind): boolean { + export function isModifierKind(token: SyntaxKind): boolean { switch (token) { case SyntaxKind.AbstractKeyword: case SyntaxKind.AsyncKeyword: diff --git a/src/services/services.ts b/src/services/services.ts index 113a52459e9..529a70b1453 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -132,43 +132,43 @@ namespace ts { let scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true); let emptyArray: any[] = []; - + const jsDocTagNames = [ - "augments", - "author", - "argument", - "borrows", - "class", - "constant", - "constructor", - "constructs", - "default", - "deprecated", - "description", - "event", - "example", - "extends", - "field", - "fileOverview", - "function", - "ignore", - "inner", - "lends", - "link", - "memberOf", - "name", - "namespace", - "param", - "private", - "property", - "public", - "requires", - "returns", - "see", - "since", - "static", - "throws", - "type", + "augments", + "author", + "argument", + "borrows", + "class", + "constant", + "constructor", + "constructs", + "default", + "deprecated", + "description", + "event", + "example", + "extends", + "field", + "fileOverview", + "function", + "ignore", + "inner", + "lends", + "link", + "memberOf", + "name", + "namespace", + "param", + "private", + "property", + "public", + "requires", + "returns", + "see", + "since", + "static", + "throws", + "type", "version" ]; let jsDocCompletionEntries: CompletionEntry[]; @@ -816,7 +816,7 @@ namespace ts { constructor(kind: SyntaxKind, pos: number, end: number) { super(kind, pos, end) } - + public update(newText: string, textChangeRange: TextChangeRange): SourceFile { return updateSourceFile(this, newText, textChangeRange); } @@ -1030,7 +1030,7 @@ namespace ts { /* * LS host can optionally implement this method if it wants to be completely in charge of module name resolution. - * if implementation is omitted then language service will use built-in module resolution logic and get answers to + * if implementation is omitted then language service will use built-in module resolution logic and get answers to * host specific questions using 'getScriptSnapshot'. */ resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[]; @@ -1854,7 +1854,7 @@ namespace ts { * - allowNonTsExtensions = true * - noLib = true * - noResolve = true - */ + */ export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput { let options = transpileOptions.compilerOptions ? clone(transpileOptions.compilerOptions) : getDefaultCompilerOptions(); @@ -2574,7 +2574,7 @@ namespace ts { } } - export function createLanguageService(host: LanguageServiceHost, + export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService { let syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); @@ -2662,10 +2662,10 @@ namespace ts { getDefaultLibFileName: (options) => host.getDefaultLibFileName(options), writeFile: (fileName, data, writeByteOrderMark) => { }, getCurrentDirectory: () => currentDirectory, - fileExists: (fileName): boolean => { + fileExists: (fileName): boolean => { // stub missing host functionality Debug.assert(!host.resolveModuleNames); - return hostCache.getOrCreateEntry(fileName) !== undefined; + return hostCache.getOrCreateEntry(fileName) !== undefined; }, readFile: (fileName): string => { // stub missing host functionality @@ -3068,7 +3068,7 @@ namespace ts { log("getCompletionData: Is inside comment: " + (new Date().getTime() - start)); if (insideComment) { - // The current position is next to the '@' sign, when no tag name being provided yet. + // The current position is next to the '@' sign, when no tag name being provided yet. // Provide a full list of tag names if (hasDocComment(sourceFile, position) && sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) { isJsDocTagName = true; @@ -3101,7 +3101,7 @@ namespace ts { } if (!insideJsDocTagExpression) { - // Proceed if the current position is in jsDoc tag expression; otherwise it is a normal + // Proceed if the current position is in jsDoc tag expression; otherwise it is a normal // comment or the plain text part of a jsDoc comment, so no completion should be available log("Returning an empty list because completion was inside a regular comment or plain text part of a JsDoc comment."); return undefined; @@ -3622,8 +3622,8 @@ namespace ts { case SyntaxKind.CloseBraceToken: if (parent && - parent.kind === SyntaxKind.JsxExpression && - parent.parent && + parent.kind === SyntaxKind.JsxExpression && + parent.parent && (parent.parent.kind === SyntaxKind.JsxAttribute)) { return parent.parent.parent; } @@ -3672,7 +3672,7 @@ namespace ts { containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A Date: Tue, 10 Nov 2015 16:48:08 -0800 Subject: [PATCH 05/35] extract method --- src/harness/compilerRunner.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index f7bb23527dd..4a599e96812 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -40,6 +40,10 @@ class CompilerBaselineRunner extends RunnerBase { this.basePath += "/" + this.testSuiteName; } + private makeUnitName(name: string, root: string) { + return ts.isRootedDiskPath(name) ? name : (root + name); + }; + public checkTestCodeOutput(fileName: string) { describe("compiler tests for " + fileName, () => { // Mocha holds onto the closure environment of the describe callback even after the test is done. @@ -74,16 +78,16 @@ class CompilerBaselineRunner extends RunnerBase { toBeCompiled = []; otherFiles = []; if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) { - toBeCompiled.push({ unitName: ts.isRootedDiskPath(lastUnit.name) ? lastUnit.name : rootDir + lastUnit.name, content: lastUnit.content }); + toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content }); units.forEach(unit => { if (unit.name !== lastUnit.name) { - otherFiles.push({ unitName: ts.isRootedDiskPath(unit.name) ? unit.name : rootDir + unit.name, content: unit.content }); + otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content }); } }); } else { toBeCompiled = units.map(unit => { - return { unitName: ts.isRootedDiskPath(unit.name) ? unit.name : rootDir + unit.name, content: unit.content }; + return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content }; }); } From 5ea25ba9a09f5a9860b92093012a3cedd32bf664 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 11 Nov 2015 10:57:32 -0800 Subject: [PATCH 06/35] remove whitespace --- src/harness/compilerRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 4a599e96812..011b10e4e6b 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -43,7 +43,7 @@ class CompilerBaselineRunner extends RunnerBase { private makeUnitName(name: string, root: string) { return ts.isRootedDiskPath(name) ? name : (root + name); }; - + public checkTestCodeOutput(fileName: string) { describe("compiler tests for " + fileName, () => { // Mocha holds onto the closure environment of the describe callback even after the test is done. From 527f4658ad71135ee2a5d7bf441d3c84fdfa7aeb Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 11 Nov 2015 11:39:46 -0800 Subject: [PATCH 07/35] Use string literal types in the command line parser. --- src/compiler/types.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8b0027c1377..5f9f82d9a64 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2179,17 +2179,17 @@ namespace ts { /* @internal */ export interface CommandLineOptionBase { name: string; - type: string | Map; // "string", "number", "boolean", or an object literal mapping named values to actual values - isFilePath?: boolean; // True if option value is a path or fileName - shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' - description?: DiagnosticMessage; // The message describing what the command line switch does - paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter + type: "string" | "number" | "boolean" | Map; // a value of a primitive type, or an object literal mapping named values to actual values + isFilePath?: boolean; // True if option value is a path or fileName + shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' + description?: DiagnosticMessage; // The message describing what the command line switch does + paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter experimental?: boolean; } /* @internal */ export interface CommandLineOptionOfPrimitiveType extends CommandLineOptionBase { - type: string; // "string" | "number" | "boolean" + type: "string" | "number" | "boolean"; } /* @internal */ From 15f505e6aa0a3ec3e701b9e2c30cc40a478b88d0 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 11 Nov 2015 13:30:26 -0800 Subject: [PATCH 08/35] use tslint@next --- package.json | 2 +- scripts/tslint/booleanTriviaRule.ts | 11 +++++------ scripts/tslint/nextLineRule.ts | 4 ++-- scripts/tslint/noNullRule.ts | 4 ++-- scripts/tslint/preferConstRule.ts | 8 ++++---- scripts/tslint/typeOperatorSpacingRule.ts | 4 ++-- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 7b8abfaae43..ebdcb73c082 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "browserify": "latest", "istanbul": "latest", "mocha-fivemat-progress-reporter": "latest", - "tslint": "latest", + "tslint": "next", "tsd": "latest" }, "scripts": { diff --git a/scripts/tslint/booleanTriviaRule.ts b/scripts/tslint/booleanTriviaRule.ts index be32a870ff4..93c312ab870 100644 --- a/scripts/tslint/booleanTriviaRule.ts +++ b/scripts/tslint/booleanTriviaRule.ts @@ -1,6 +1,5 @@ -/// -/// - +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { public static FAILURE_STRING_FACTORY = (name: string, currently: string) => `Tag boolean argument as '${name}' (currently '${currently}')`; @@ -19,7 +18,7 @@ class BooleanTriviaWalker extends Lint.RuleWalker { visitCallExpression(node: ts.CallExpression) { super.visitCallExpression(node); - if (node.arguments) { + if (node.arguments) { const targetCallSignature = this.checker.getResolvedSignature(node); if (!!targetCallSignature) { const targetParameters = targetCallSignature.getParameters(); @@ -37,7 +36,7 @@ class BooleanTriviaWalker extends Lint.RuleWalker { let triviaContent: string; const ranges = ts.getLeadingCommentRanges(arg.getFullText(), 0); if (ranges && ranges.length === 1 && ranges[0].kind === ts.SyntaxKind.MultiLineCommentTrivia) { - triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); //+/-2 to remove /**/ + triviaContent = arg.getFullText().slice(ranges[0].pos + 2, ranges[0].end - 2); // +/-2 to remove /**/ } if (triviaContent !== param.getName()) { this.addFailure(this.createFailure(arg.getStart(source), arg.getWidth(source), Rule.FAILURE_STRING_FACTORY(param.getName(), triviaContent))); @@ -45,6 +44,6 @@ class BooleanTriviaWalker extends Lint.RuleWalker { } } } - } + } } } diff --git a/scripts/tslint/nextLineRule.ts b/scripts/tslint/nextLineRule.ts index 6d803fc7f88..d25652f7bce 100644 --- a/scripts/tslint/nextLineRule.ts +++ b/scripts/tslint/nextLineRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; const OPTION_CATCH = "check-catch"; const OPTION_ELSE = "check-else"; diff --git a/scripts/tslint/noNullRule.ts b/scripts/tslint/noNullRule.ts index 2a2c5bc3717..8e9deca996b 100644 --- a/scripts/tslint/noNullRule.ts +++ b/scripts/tslint/noNullRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index 29160a9c634..e4ffa396fb7 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { @@ -101,13 +101,13 @@ class PreferConstWalker extends Lint.RuleWalker { this.visitBindingLiteralExpression(node as (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression)); } } - + private visitBindingLiteralExpression(node: ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) { if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { const pattern = node as ts.ObjectLiteralExpression; for (const element of pattern.properties) { if (element.name.kind === ts.SyntaxKind.Identifier) { - this.markAssignment(element.name as ts.Identifier) + this.markAssignment(element.name as ts.Identifier); } else if (isBindingPattern(element.name)) { this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern); diff --git a/scripts/tslint/typeOperatorSpacingRule.ts b/scripts/tslint/typeOperatorSpacingRule.ts index 23925493340..4196d024768 100644 --- a/scripts/tslint/typeOperatorSpacingRule.ts +++ b/scripts/tslint/typeOperatorSpacingRule.ts @@ -1,5 +1,5 @@ -/// -/// +import * as Lint from "tslint/lib/lint"; +import * as ts from "typescript"; export class Rule extends Lint.Rules.AbstractRule { From 77f8d89883c65733f3690dd01bad8bbbfa76c05a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 11 Nov 2015 13:42:46 -0800 Subject: [PATCH 09/35] because it needs to work with npm 2 as well --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index ebdcb73c082..474b35a3e1f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "clean": "jake clean", "jake": "jake", "lint": "jake lint", - "setup-hooks": "node scripts/link-hooks.js" + "setup-hooks": "node scripts/link-hooks.js", + "postinstall": "npm dedupe" }, "browser": { "buffer": false, From ee10ea1baa39f259c84bc020723d60c8b5f76d0a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 11 Nov 2015 13:58:09 -0800 Subject: [PATCH 10/35] this should work better than dedupe --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 474b35a3e1f..261cdfa64b7 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "istanbul": "latest", "mocha-fivemat-progress-reporter": "latest", "tslint": "next", + "typescript": "next", "tsd": "latest" }, "scripts": { @@ -47,8 +48,7 @@ "clean": "jake clean", "jake": "jake", "lint": "jake lint", - "setup-hooks": "node scripts/link-hooks.js", - "postinstall": "npm dedupe" + "setup-hooks": "node scripts/link-hooks.js" }, "browser": { "buffer": false, From b24f8f35b762e6239454f4ab7431c2ab57086e43 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 12 Nov 2015 14:09:51 -0800 Subject: [PATCH 11/35] go go go --- tests/cases/compiler/commonSourceDir3.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cases/compiler/commonSourceDir3.ts b/tests/cases/compiler/commonSourceDir3.ts index cc42eb8f267..54b6e8c89b7 100644 --- a/tests/cases/compiler/commonSourceDir3.ts +++ b/tests/cases/compiler/commonSourceDir3.ts @@ -1,3 +1,4 @@ +// @useCaseSensitiveFileNames: false // @outDir: A:/ // @Filename: A:/foo/bar.ts var x: number; From 5bcf8611210e5e988bb6317def16389a71b2074c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 12 Nov 2015 15:58:11 -0800 Subject: [PATCH 12/35] use relative path from current directory --- src/compiler/program.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 3981d5a2421..28c51ce2f3a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -947,7 +947,9 @@ namespace ts { return currentDirectory; } - return getNormalizedPathFromPathComponents(commonPathComponents); + const path = getNormalizedPathFromPathComponents(commonPathComponents); + const relativePath = convertToRelativePath(path, currentDirectory, getCanonicalFileName); + return relativePath; } function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean { From ecd4435986be2e0e2ff9492ca524a2af7f2ebf02 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 12 Nov 2015 16:22:35 -0800 Subject: [PATCH 13/35] Go all the way back to the original solution --- src/compiler/program.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 3fb432d9668..1f0096e7f6e 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -910,7 +910,7 @@ namespace ts { return; } - const sourcePathComponents = getNormalizedPathComponents(getCanonicalFileName(sourceFile.fileName), currentDirectory); + const sourcePathComponents = getNormalizedPathComponents(sourceFile.fileName, currentDirectory); sourcePathComponents.pop(); // The base file name is not part of the common directory path if (!commonPathComponents) { @@ -919,8 +919,9 @@ namespace ts { return; } + const caseSensitive = host.useCaseSensitiveFileNames(); for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { - if (commonPathComponents[i] !== sourcePathComponents[i]) { + if (caseSensitive ? commonPathComponents[i] !== sourcePathComponents[i] : commonPathComponents[i].toLocaleLowerCase() !== sourcePathComponents[i].toLocaleLowerCase()) { if (i === 0) { // Failed to find any common path component return true; @@ -947,9 +948,7 @@ namespace ts { return currentDirectory; } - const path = getNormalizedPathFromPathComponents(commonPathComponents); - const relativePath = convertToRelativePath(path, currentDirectory, getCanonicalFileName); - return relativePath; + return getNormalizedPathFromPathComponents(commonPathComponents); } function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean { From b93feb87be769e0fed76b825e2df51b772ad115c Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Nov 2015 11:14:51 -0800 Subject: [PATCH 14/35] cleanup test harness code --- src/harness/compilerRunner.ts | 41 ++++---- src/harness/fourslash.ts | 33 ++++-- src/harness/harness.ts | 182 +++++++++++++--------------------- src/harness/projectsRunner.ts | 2 +- src/harness/rwcRunner.ts | 24 +++-- src/harness/test262Runner.ts | 24 +++-- 6 files changed, 141 insertions(+), 165 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 848f229f109..d46d0bde08c 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -49,7 +49,7 @@ class CompilerBaselineRunner extends RunnerBase { let testCaseContent: { settings: Harness.TestCaseParser.CompilerSettings; testUnitData: Harness.TestCaseParser.TestUnitData[]; }; let units: Harness.TestCaseParser.TestUnitData[]; - let tcSettings: Harness.TestCaseParser.CompilerSettings; + let harnessSettings: Harness.TestCaseParser.CompilerSettings; let lastUnit: Harness.TestCaseParser.TestUnitData; let rootDir: string; @@ -58,46 +58,43 @@ class CompilerBaselineRunner extends RunnerBase { let program: ts.Program; let options: ts.CompilerOptions; // equivalent to the files that will be passed on the command line - let toBeCompiled: { unitName: string; content: string }[]; + let toBeCompiled: Harness.Compiler.TestFile[]; // equivalent to other files on the file system not directly passed to the compiler (ie things that are referenced by other files) - let otherFiles: { unitName: string; content: string }[]; - let harnessCompiler: Harness.Compiler.HarnessCompiler; + let otherFiles: Harness.Compiler.TestFile[]; before(() => { justName = fileName.replace(/^.*[\\\/]/, ""); // strips the fileName from the path. content = Harness.IO.readFile(fileName); testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); units = testCaseContent.testUnitData; - tcSettings = testCaseContent.settings; + harnessSettings = testCaseContent.settings; lastUnit = units[units.length - 1]; rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; - harnessCompiler = Harness.Compiler.getCompiler(); // We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test) // If the last file in a test uses require or a triple slash reference we'll assume all other files will be brought in via references, // otherwise, assume all files are just meant to be in the same compilation session without explicit references to one another. toBeCompiled = []; otherFiles = []; if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) { - toBeCompiled.push({ unitName: rootDir + lastUnit.name, content: lastUnit.content }); + toBeCompiled.push({ unitName: ts.combinePaths(rootDir, lastUnit.name), content: lastUnit.content }); units.forEach(unit => { if (unit.name !== lastUnit.name) { - otherFiles.push({ unitName: rootDir + unit.name, content: unit.content }); + otherFiles.push({ unitName: ts.combinePaths(rootDir, unit.name), content: unit.content }); } }); } else { toBeCompiled = units.map(unit => { - return { unitName: rootDir + unit.name, content: unit.content }; + return { unitName: ts.combinePaths(rootDir, unit.name), content: unit.content }; }); } - options = harnessCompiler.compileFiles(toBeCompiled, otherFiles, function (compileResult, _program) { - result = compileResult; - // The program will be used by typeWriter - program = _program; - }, function (settings) { - harnessCompiler.setCompilerSettings(tcSettings); - }); + const output = Harness.Compiler.HarnessCompiler.compileFiles( + toBeCompiled, otherFiles, harnessSettings, /* options */ undefined, /* currentDirectory */ undefined); + + options = output.options; + result = output.result; + program = output.program; }); after(() => { @@ -107,7 +104,7 @@ class CompilerBaselineRunner extends RunnerBase { content = undefined; testCaseContent = undefined; units = undefined; - tcSettings = undefined; + harnessSettings = undefined; lastUnit = undefined; rootDir = undefined; result = undefined; @@ -115,14 +112,13 @@ class CompilerBaselineRunner extends RunnerBase { options = undefined; toBeCompiled = undefined; otherFiles = undefined; - harnessCompiler = undefined; }); function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string { return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : ""; } - function getErrorBaseline(toBeCompiled: { unitName: string; content: string }[], otherFiles: { unitName: string; content: string }[], result: Harness.Compiler.CompilerResult) { + function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) { return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors); } @@ -184,9 +180,9 @@ class CompilerBaselineRunner extends RunnerBase { } } - const declFileCompilationResult = harnessCompiler.compileDeclarationFiles(toBeCompiled, otherFiles, result, function (settings) { - harnessCompiler.setCompilerSettings(tcSettings); - }, options); + const declFileCompilationResult = + Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + toBeCompiled, otherFiles, result, harnessSettings, options, /* currentDirectory */ undefined); if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; @@ -367,7 +363,6 @@ class CompilerBaselineRunner extends RunnerBase { public initializeTests() { describe(this.testSuiteName + " tests", () => { describe("Setup compiler for compiler baselines", () => { - const harnessCompiler = Harness.Compiler.getCompiler(); this.parseOptions(); }); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 1c8593a9e12..23aadb53241 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2383,10 +2383,16 @@ namespace FourSlash { // here we cache the JS output and reuse it for every test. let fourslashJsOutput: string; { - const host = Harness.Compiler.createCompilerHost([{ unitName: Harness.Compiler.fourslashFileName, content: undefined }], + const fourslashFile: Harness.Compiler.TestFileWithPath = { + unitName: Harness.Compiler.fourslashFileName, + content: undefined, + path: ts.toPath(Harness.Compiler.fourslashFileName, Harness.IO.getCurrentDirectory(), Harness.Compiler.getCanonicalFileName) + }; + const host = Harness.Compiler.createCompilerHost([fourslashFile], (fn, contents) => fourslashJsOutput = contents, ts.ScriptTarget.Latest, - Harness.IO.useCaseSensitiveFileNames()); + Harness.IO.useCaseSensitiveFileNames(), + Harness.IO.getCurrentDirectory()); const program = ts.createProgram([Harness.Compiler.fourslashFileName], { noResolve: true, target: ts.ScriptTarget.ES3 }, host); @@ -2400,15 +2406,28 @@ namespace FourSlash { currentTestState = new TestState(basePath, testType, testData); + const currentDirectory = Harness.IO.getCurrentDirectory(); + const useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); + let result = ""; + const fourslashFile: Harness.Compiler.TestFileWithPath = { + unitName: Harness.Compiler.fourslashFileName, + content: undefined, + path: ts.toPath(Harness.Compiler.fourslashFileName, currentDirectory, getCanonicalFileName) + }; + const testFile: Harness.Compiler.TestFileWithPath = { + unitName: fileName, + content: content, + path: ts.toPath(fileName, currentDirectory, getCanonicalFileName) + }; + const host = Harness.Compiler.createCompilerHost( - [ - { unitName: Harness.Compiler.fourslashFileName, content: undefined }, - { unitName: fileName, content: content } - ], + [ fourslashFile, testFile ], (fn, contents) => result = contents, ts.ScriptTarget.Latest, - Harness.IO.useCaseSensitiveFileNames()); + useCaseSensitiveFileNames, + currentDirectory); const program = ts.createProgram([Harness.Compiler.fourslashFileName, fileName], { outFile: "fourslashTestOutput.js", noResolve: true, target: ts.ScriptTarget.ES3 }, host); diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 16c3b2d3488..468517b68f7 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -903,41 +903,34 @@ namespace Harness { } export function createCompilerHost( - inputFiles: { unitName: string; content: string; }[], + inputFiles: TestFileWithPath[], writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void, scriptTarget: ts.ScriptTarget, useCaseSensitiveFileNames: boolean, // the currentDirectory is needed for rwcRunner to passed in specified current directory to compiler host - currentDirectory?: string, + currentDirectory: string, newLineKind?: ts.NewLineKind): ts.CompilerHost { // Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames - function getCanonicalFileName(fileName: string): string { - return useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); - } + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); - const filemap: { [fileName: string]: ts.SourceFile; } = {}; - const getCurrentDirectory = currentDirectory === undefined ? Harness.IO.getCurrentDirectory : () => currentDirectory; + const fileMap: ts.FileMap = ts.createFileMap(); // Register input files - function register(file: { unitName: string; content: string; }) { + function register(file: TestFileWithPath) { if (file.content !== undefined) { const fileName = ts.normalizePath(file.unitName); const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget); - filemap[getCanonicalFileName(fileName)] = sourceFile; - filemap[getCanonicalFileName(ts.getNormalizedAbsolutePath(fileName, getCurrentDirectory()))] = sourceFile; + fileMap.set(file.path, sourceFile); } }; inputFiles.forEach(register); function getSourceFile(fn: string, languageVersion: ts.ScriptTarget) { fn = ts.normalizePath(fn); - if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) { - return filemap[getCanonicalFileName(fn)]; - } - else if (currentDirectory) { - const canonicalAbsolutePath = getCanonicalFileName(ts.getNormalizedAbsolutePath(fn, currentDirectory)); - return Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(canonicalAbsolutePath)) ? filemap[canonicalAbsolutePath] : undefined; + const path = ts.toPath(fn, currentDirectory, getCanonicalFileName); + if (fileMap.contains(path)) { + return fileMap.get(path); } else if (fn === fourslashFileName) { const tsFn = "tests/cases/fourslash/" + fourslashFileName; @@ -959,7 +952,7 @@ namespace Harness { Harness.IO.newLine(); return { - getCurrentDirectory, + getCurrentDirectory: () => currentDirectory, getSourceFile, getDefaultLibFileName: options => defaultLibFileName, writeFile, @@ -1034,95 +1027,74 @@ namespace Harness { } } - export class HarnessCompiler { - private inputFiles: { unitName: string; content: string }[] = []; - private compileOptions: ts.CompilerOptions; - private settings: Harness.TestCaseParser.CompilerSettings = {}; + export interface TestFile { + unitName: string; + content: string; + } + export interface TestFileWithPath extends TestFile { + path: ts.Path; + } - private lastErrors: ts.Diagnostic[]; + export interface CompilationOutput { + result: CompilerResult; + program: ts.Program; + options: ts.CompilerOptions & HarnessOptions; + } - public reset() { - this.inputFiles = []; - this.settings = {}; - this.lastErrors = []; - } - - public reportCompilationErrors() { - return this.lastErrors; - } - - public setCompilerSettings(tcSettings: Harness.TestCaseParser.CompilerSettings) { - this.settings = tcSettings; - } - - public addInputFiles(files: { unitName: string; content: string }[]) { - files.forEach(file => this.addInputFile(file)); - } - - public addInputFile(file: { unitName: string; content: string }) { - this.inputFiles.push(file); - } - - public setCompilerOptions(options?: ts.CompilerOptions) { - this.compileOptions = options || { noResolve: false }; - } - - public emitAll(ioHost?: IEmitterIOHost) { - this.compileFiles(this.inputFiles, - /*otherFiles*/ [], - /*onComplete*/ result => { - result.files.forEach(writeFile); - result.declFilesCode.forEach(writeFile); - result.sourceMaps.forEach(writeFile); - }, - /*settingsCallback*/ () => { }, - this.compileOptions); - - function writeFile(file: GeneratedFile) { - ioHost.writeFile(file.fileName, file.code, false); - } - } - - public compileFiles(inputFiles: { unitName: string; content: string }[], - otherFiles: { unitName: string; content: string }[], - onComplete: (result: CompilerResult, program: ts.Program) => void, - settingsCallback?: (settings: ts.CompilerOptions) => void, - options?: ts.CompilerOptions & HarnessOptions, + export namespace HarnessCompiler { + export function compileFiles( + inputFiles: TestFile[], + otherFiles: TestFile[], + harnessSettings: TestCaseParser.CompilerSettings, + compilerOptions: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory?: string) { + currentDirectory: string): CompilationOutput { - options = options || { noResolve: false }; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false }; options.target = options.target || ts.ScriptTarget.ES3; options.module = options.module || ts.ModuleKind.None; options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; options.noErrorTruncation = true; options.skipDefaultLibCheck = true; - if (settingsCallback) { - settingsCallback(null); - } - const newLine = "\r\n"; + currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory(); // Parse settings - setCompilerOptionsFromHarnessSetting(this.settings, options); + let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); + if (harnessSettings) { + setCompilerOptionsFromHarnessSetting(harnessSettings, options); + } + if (options.useCaseSensitiveFileNames !== undefined) { + useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; + } + const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); + const inputFilesWiithPath = inputFiles.map(f => { + return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; + }); + const otherFilesWithPath = otherFiles.map(f => { + return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; + }); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. // Treat them as library files, so include them in build, but not in baselines. - const includeBuiltFiles: { unitName: string; content: string }[] = []; + const includeBuiltFiles: TestFileWithPath[] = []; if (options.includeBuiltFile) { const builtFileName = libFolder + options.includeBuiltFile; - includeBuiltFiles.push({ unitName: builtFileName, content: normalizeLineEndings(IO.readFile(builtFileName), newLine) }); + const builtFile: TestFileWithPath = { + unitName: builtFileName, + content: normalizeLineEndings(IO.readFile(builtFileName), newLine), + path: ts.toPath(builtFileName, currentDirectory, getCanonicalFileName) + }; + includeBuiltFiles.push(builtFile); } - const useCaseSensitiveFileNames = options.useCaseSensitiveFileNames !== undefined ? options.useCaseSensitiveFileNames : Harness.IO.useCaseSensitiveFileNames(); - const fileOutputs: GeneratedFile[] = []; const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); const compilerHost = createCompilerHost( - inputFiles.concat(includeBuiltFiles).concat(otherFiles), + inputFilesWiithPath.concat(includeBuiltFiles).concat(otherFilesWithPath), (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }), options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); const program = ts.createProgram(programFiles, options, compilerHost); @@ -1130,40 +1102,35 @@ namespace Harness { const emitResult = program.emit(); const errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); - this.lastErrors = errors; const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps); - onComplete(result, program); - - return options; + return { result, program, options }; } - public compileDeclarationFiles(inputFiles: { unitName: string; content: string; }[], - otherFiles: { unitName: string; content: string; }[], + export function compileDeclarationFiles(inputFiles: TestFile[], + otherFiles: TestFile[], result: CompilerResult, - settingsCallback?: (settings: ts.CompilerOptions) => void, - options?: ts.CompilerOptions, + harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions, + options: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory?: string) { + currentDirectory: string) { if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) { throw new Error("There were no errors and declFiles generated did not match number of js files generated"); } - const declInputFiles: { unitName: string; content: string }[] = []; - const declOtherFiles: { unitName: string; content: string }[] = []; - let declResult: Harness.Compiler.CompilerResult; + const declInputFiles: TestFile[] = []; + const declOtherFiles: TestFile[] = []; // if the .d.ts is non-empty, confirm it compiles correctly as well if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) { ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); - this.compileFiles(declInputFiles, declOtherFiles, function (compileResult) { declResult = compileResult; }, - settingsCallback, options, currentDirectory); + const output = this.compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory); - return { declInputFiles, declOtherFiles, declResult }; + return { declInputFiles, declOtherFiles, declResult: output.result }; } - function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) { + function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { if (isDTS(file.unitName)) { dtsFiles.push(file); } @@ -1200,7 +1167,7 @@ namespace Harness { return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined); } - function findUnit(fileName: string, units: { unitName: string; content: string; }[]) { + function findUnit(fileName: string, units: TestFile[]) { return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined); } } @@ -1230,7 +1197,7 @@ namespace Harness { return errorOutput; } - export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: ts.Diagnostic[]) { + export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) { diagnostics.sort(ts.compareDiagnostics); const outputLines: string[] = []; // Count up all errors that were found in files other than lib.d.ts so we don't miss any @@ -1371,16 +1338,6 @@ namespace Harness { } } - /** The harness' compiler instance used when tests are actually run. Reseting or changing settings of this compiler instance must be done within a test case (i.e., describe/it) */ - let harnessCompiler: HarnessCompiler; - - /** Returns the singleton harness compiler instance for generating and running tests. - If required a fresh compiler instance will be created, otherwise the existing singleton will be re-used. - */ - export function getCompiler() { - return harnessCompiler = harnessCompiler || new HarnessCompiler(); - } - // This does not need to exist strictly speaking, but many tests will need to be updated if it's removed export function compileString(code: string, unitName: string, callback: (result: CompilerResult) => void) { // NEWTODO: Re-implement 'compileString' @@ -1711,12 +1668,9 @@ namespace Harness { return filePath.indexOf(Harness.libFolder) === 0; } - export function getDefaultLibraryFile(io: Harness.IO): { unitName: string, content: string } { + export function getDefaultLibraryFile(io: Harness.IO): Harness.Compiler.TestFile { const libFile = Harness.userSpecifiedRoot + Harness.libFolder + "lib.d.ts"; - return { - unitName: libFile, - content: io.readFile(libFile) - }; + return { unitName: libFile, content: io.readFile(libFile) }; } if (Error) (Error).stackTraceLimit = 1; diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index f48822f1220..dc6cbfac646 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -349,7 +349,7 @@ class ProjectRunner extends RunnerBase { const inputFiles = ts.map(ts.filter(compilerResult.program.getSourceFiles(), sourceFile => sourceFile.fileName !== "lib.d.ts"), sourceFile => { - return { unitName: RunnerBase.removeFullPaths(sourceFile.fileName), content: sourceFile.text }; + return { unitName: RunnerBase.removeFullPaths(sourceFile.fileName), content: sourceFile.text, }; }); return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors); diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index a350eda08f3..fc1397b294c 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -27,8 +27,8 @@ namespace RWC { export function runRWCTest(jsonPath: string) { describe("Testing a RWC project: " + jsonPath, () => { - let inputFiles: { unitName: string; content: string; }[] = []; - let otherFiles: { unitName: string; content: string; }[] = []; + let inputFiles: Harness.Compiler.TestFile[] = []; + let otherFiles: Harness.Compiler.TestFile[] = []; let compilerResult: Harness.Compiler.CompilerResult; let compilerOptions: ts.CompilerOptions; let baselineOpts: Harness.Baseline.BaselineOptions = { @@ -55,7 +55,6 @@ namespace RWC { }); it("can compile", () => { - const harnessCompiler = Harness.Compiler.getCompiler(); let opts: ts.ParsedCommandLine; const ioLog: IOLog = JSON.parse(Harness.IO.readFile(jsonPath)); @@ -71,8 +70,6 @@ namespace RWC { }); runWithIOLog(ioLog, oldIO => { - harnessCompiler.reset(); - let fileNames = opts.fileNames; const tsconfigFile = ts.forEach(ioLog.filesRead, f => isTsConfigFile(f) ? f : undefined); @@ -128,17 +125,21 @@ namespace RWC { opts.options.noLib = true; // Emit the results - compilerOptions = harnessCompiler.compileFiles( + compilerOptions = null; + const output = Harness.Compiler.HarnessCompiler.compileFiles( inputFiles, otherFiles, - newCompilerResults => { compilerResult = newCompilerResults; }, - /*settingsCallback*/ undefined, opts.options, + /* harnessOptions */ undefined, + opts.options, // Since each RWC json file specifies its current directory in its json file, we need // to pass this information in explicitly instead of acquiring it from the process. currentDirectory); + + compilerOptions = output.options; + compilerResult = output.result; }); - function getHarnessCompilerInputUnit(fileName: string) { + function getHarnessCompilerInputUnit(fileName: string): Harness.Compiler.TestFile { const unitName = ts.normalizeSlashes(Harness.IO.resolvePath(fileName)); let content: string = null; try { @@ -201,8 +202,9 @@ namespace RWC { it("has the expected errors in generated declaration files", () => { if (compilerOptions.declaration && !compilerResult.errors.length) { Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => { - const declFileCompilationResult = Harness.Compiler.getCompiler().compileDeclarationFiles(inputFiles, otherFiles, compilerResult, - /*settingscallback*/ undefined, compilerOptions, currentDirectory); + const declFileCompilationResult = Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory); + if (declFileCompilationResult.declResult.errors.length === 0) { return null; } diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index f25e0c79b63..859f10dc4cc 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -5,9 +5,9 @@ class Test262BaselineRunner extends RunnerBase { private static basePath = "internal/cases/test262"; private static helpersFilePath = "tests/cases/test262-harness/helpers.d.ts"; - private static helperFile = { + private static helperFile: Harness.Compiler.TestFile = { unitName: Test262BaselineRunner.helpersFilePath, - content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath) + content: Harness.IO.readFile(Test262BaselineRunner.helpersFilePath), }; private static testFileExtensionRegex = /\.js$/; private static options: ts.CompilerOptions = { @@ -31,7 +31,7 @@ class Test262BaselineRunner extends RunnerBase { let testState: { filename: string; compilerResult: Harness.Compiler.CompilerResult; - inputFiles: { unitName: string; content: string }[]; + inputFiles: Harness.Compiler.TestFile[]; program: ts.Program; }; @@ -40,8 +40,9 @@ class Test262BaselineRunner extends RunnerBase { const testFilename = ts.removeFileExtension(filePath).replace(/\//g, "_") + ".test"; const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, testFilename); - const inputFiles = testCaseContent.testUnitData.map(unit => { - return { unitName: Test262BaselineRunner.getTestFilePath(unit.name), content: unit.content }; + const inputFiles: Harness.Compiler.TestFile[] = testCaseContent.testUnitData.map(unit => { + const unitName = Test262BaselineRunner.getTestFilePath(unit.name); + return { unitName, content: unit.content }; }); // Emit the results @@ -52,10 +53,15 @@ class Test262BaselineRunner extends RunnerBase { program: undefined, }; - Harness.Compiler.getCompiler().compileFiles([Test262BaselineRunner.helperFile].concat(inputFiles), /*otherFiles*/ [], (compilerResult, program) => { - testState.compilerResult = compilerResult; - testState.program = program; - }, /*settingsCallback*/ undefined, Test262BaselineRunner.options); + const output = Harness.Compiler.HarnessCompiler.compileFiles( + [Test262BaselineRunner.helperFile].concat(inputFiles), + /*otherFiles*/ [], + /* harnessOptions */ undefined, + Test262BaselineRunner.options, + /* currentDirectory */ undefined + ); + testState.compilerResult = output.result; + testState.program = output.program; }); after(() => { From 50aab7a05fc79ba29116b19311bca10e112675dd Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 13 Nov 2015 15:10:16 -0800 Subject: [PATCH 15/35] fix typo --- src/harness/harness.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 468517b68f7..aa70087ea31 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1069,7 +1069,7 @@ namespace Harness { useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; } const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); - const inputFilesWiithPath = inputFiles.map(f => { + const inputFilesWithPath = inputFiles.map(f => { return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; }); const otherFilesWithPath = otherFiles.map(f => { @@ -1094,7 +1094,7 @@ namespace Harness { const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); const compilerHost = createCompilerHost( - inputFilesWiithPath.concat(includeBuiltFiles).concat(otherFilesWithPath), + inputFilesWithPath.concat(includeBuiltFiles).concat(otherFilesWithPath), (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }), options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); const program = ts.createProgram(programFiles, options, compilerHost); From ff95731507bcf831f7339d25f72c37cc6c12fdd4 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 13 Nov 2015 16:49:16 -0800 Subject: [PATCH 16/35] :S --- src/harness/compilerRunner.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 0785faccdf2..16616505c4e 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -50,9 +50,8 @@ class CompilerBaselineRunner extends RunnerBase { // Everything declared here should be cleared out in the "after" callback. let justName: string; - let tcSettings: Harness.TestCaseParser.CompilerSettings; - let lastUnit: Harness.TestCaseParser.TestUnitData; + let tcSettings: Harness.TestCaseParser.CompilerSettings; let result: Harness.Compiler.CompilerResult; let program: ts.Program; @@ -67,7 +66,7 @@ class CompilerBaselineRunner extends RunnerBase { const content = Harness.IO.readFile(fileName); const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); const units = testCaseContent.testUnitData; - harnessSettings = testCaseContent.settings; + const tcSettings = testCaseContent.settings; lastUnit = units[units.length - 1]; const rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; // We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test) @@ -90,7 +89,7 @@ class CompilerBaselineRunner extends RunnerBase { } const output = Harness.Compiler.HarnessCompiler.compileFiles( - toBeCompiled, otherFiles, harnessSettings, /* options */ undefined, /* currentDirectory */ undefined); + toBeCompiled, otherFiles, tcSettings, /* options */ undefined, /* currentDirectory */ undefined); options = output.options; result = output.result; @@ -101,7 +100,6 @@ class CompilerBaselineRunner extends RunnerBase { // Mocha holds onto the closure environment of the describe callback even after the test is done. // Therefore we have to clean out large objects after the test is done. justName = undefined; - harnessSettings = undefined; lastUnit = undefined; result = undefined; program = undefined; @@ -178,7 +176,7 @@ class CompilerBaselineRunner extends RunnerBase { const declFileCompilationResult = Harness.Compiler.HarnessCompiler.compileDeclarationFiles( - toBeCompiled, otherFiles, result, harnessSettings, options, /* currentDirectory */ undefined); + toBeCompiled, otherFiles, result, tcSettings, options, /* currentDirectory */ undefined); if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; From bfdb2d0fc98a2966b3564dde62860f93d87f0dac Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 13 Nov 2015 16:57:17 -0800 Subject: [PATCH 17/35] and somehow all that caused was a lint error --- src/harness/compilerRunner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 16616505c4e..dbe22beabcf 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -66,7 +66,7 @@ class CompilerBaselineRunner extends RunnerBase { const content = Harness.IO.readFile(fileName); const testCaseContent = Harness.TestCaseParser.makeUnitsFromTest(content, fileName); const units = testCaseContent.testUnitData; - const tcSettings = testCaseContent.settings; + tcSettings = testCaseContent.settings; lastUnit = units[units.length - 1]; const rootDir = lastUnit.originalFilePath.indexOf("conformance") === -1 ? "tests/cases/compiler/" : lastUnit.originalFilePath.substring(0, lastUnit.originalFilePath.lastIndexOf("/")) + "/"; // We need to assemble the list of input files for the compiler and other related files on the 'filesystem' (ie in a multi-file test) From e41bfd1ccc753957b94b252ef62b98b011a99d0e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 13 Nov 2015 17:43:53 -0800 Subject: [PATCH 18/35] fix many lints --- src/compiler/checker.ts | 18 +++++----- src/compiler/core.ts | 2 +- src/compiler/emitter.ts | 56 ++++++++++++++++---------------- src/compiler/parser.ts | 44 ++++++++++++------------- src/compiler/program.ts | 14 ++++---- src/compiler/scanner.ts | 4 +-- src/harness/compilerRunner.ts | 10 +++--- src/harness/fourslash.ts | 16 ++++----- src/harness/harness.ts | 6 ++-- src/harness/loggedIO.ts | 2 +- src/harness/sourceMapRecorder.ts | 2 +- src/server/editorServices.ts | 6 ++-- src/server/session.ts | 2 +- 13 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6d9efda2003..7f5f73a58db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -122,8 +122,8 @@ namespace ts { const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, false, false); - const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, false, false); + const anySignature = createSignature(undefined, undefined, emptyArray, anyType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); + const unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false); const globals: SymbolTable = {}; @@ -2276,7 +2276,7 @@ namespace ts { return false; } resolutionTargets.push(target); - resolutionResults.push(true); + resolutionResults.push(/*items*/ true); resolutionPropertyNames.push(propertyName); return true; } @@ -3348,7 +3348,7 @@ namespace ts { function getDefaultConstructSignatures(classType: InterfaceType): Signature[] { if (!hasClassBaseType(classType)) { - return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, false, false)]; + return [createSignature(undefined, classType.localTypeParameters, emptyArray, classType, undefined, 0, /*hasRestParameter*/ false, /*hasStringLiterals*/ false)]; } const baseConstructorType = getBaseConstructorTypeOfClass(classType); const baseSignatures = getSignaturesOfType(baseConstructorType, SignatureKind.Construct); @@ -3973,7 +3973,7 @@ namespace ts { } function getSignatureInstantiation(signature: Signature, typeArguments: Type[]): Signature { - return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), true); + return instantiateSignature(signature, createTypeMapper(signature.typeParameters, typeArguments), /*eraseTypeParameters*/ true); } function getErasedSignature(signature: Signature): Signature { @@ -3983,7 +3983,7 @@ namespace ts { signature.erasedSignatureCache = instantiateSignature(getErasedSignature(signature.target), signature.mapper); } else { - signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), true); + signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true); } } return signature.erasedSignatureCache; @@ -5099,7 +5099,7 @@ namespace ts { let result = Ternary.True; const sourceTypes = source.types; for (const sourceType of sourceTypes) { - const related = typeRelatedToSomeType(sourceType, target, false); + const related = typeRelatedToSomeType(sourceType, target, /*reportErrors*/ false); if (!related) { return Ternary.False; } @@ -5497,7 +5497,7 @@ namespace ts { const saveErrorInfo = errorInfo; let related = isRelatedTo(s, t, reportErrors); if (!related) { - related = isRelatedTo(t, s, false); + related = isRelatedTo(t, s, /*reportErrors*/ false); if (!related) { if (reportErrors) { reportError(Diagnostics.Types_of_parameters_0_and_1_are_incompatible, @@ -5624,7 +5624,7 @@ namespace ts { let related: Ternary; if (sourceStringType && sourceNumberType) { // If we know for sure we're testing both string and numeric index types then only report errors from the second one - related = isRelatedTo(sourceStringType, targetType, false) || isRelatedTo(sourceNumberType, targetType, reportErrors); + related = isRelatedTo(sourceStringType, targetType, /*reportErrors*/ false) || isRelatedTo(sourceNumberType, targetType, reportErrors); } else { related = isRelatedTo(sourceStringType || sourceNumberType, targetType, reportErrors); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index c866cf41a92..2092a59a545 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -842,7 +842,7 @@ namespace ts { } export function fail(message?: string): void { - Debug.assert(false, message); + Debug.assert(/*expression*/ false, message); } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 2ea8c81c7e2..e4cd57542a7 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1292,7 +1292,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitCommaList(nodes: Node[]) { if (nodes) { - emitList(nodes, 0, nodes.length, /*multiline*/ false, /*trailingComma*/ false); + emitList(nodes, 0, nodes.length, /*multiLine*/ false, /*trailingComma*/ false); } } @@ -2191,7 +2191,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi } else if (languageVersion >= ScriptTarget.ES6 || !forEach(elements, isSpreadElementExpression)) { write("["); - emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces:*/ false); + emitLinePreservingList(node, node.elements, elements.hasTrailingComma, /*spacesBetweenBraces*/ false); write("]"); } else { @@ -2215,7 +2215,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // then try to preserve the original shape of the object literal. // Otherwise just try to preserve the formatting. if (numElements === properties.length) { - emitLinePreservingList(node, properties, /* allowTrailingComma */ languageVersion >= ScriptTarget.ES5, /* spacesBetweenBraces */ true); + emitLinePreservingList(node, properties, /*allowTrailingComma*/ languageVersion >= ScriptTarget.ES5, /*spacesBetweenBraces*/ true); } else { const multiLine = (node.flags & NodeFlags.MultiLine) !== 0; @@ -2765,7 +2765,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(".bind.apply("); emit(target); write(", [void 0].concat("); - emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiline*/ false, /*trailingComma*/ false, /*useConcat*/ false); + emitListWithSpread(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false, /*trailingComma*/ false, /*useConcat*/ false); write(")))"); write("()"); } @@ -2982,7 +2982,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi synthesizedLHS = createSynthesizedNode(SyntaxKind.ElementAccessExpression, /*startsOnNewLine*/ false); - const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldEmitCommaBeforeAssignment*/ false); + const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false); synthesizedLHS.expression = identifier; if (leftHandSideExpression.argumentExpression.kind !== SyntaxKind.NumericLiteral && @@ -3001,7 +3001,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write("("); synthesizedLHS = createSynthesizedNode(SyntaxKind.PropertyAccessExpression, /*startsOnNewLine*/ false); - const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefinedTempVariablesInPlaces*/ false, /*shouldemitCommaBeforeAssignment*/ false); + const identifier = emitTempVariableAssignment(leftHandSideExpression.expression, /*canDefineTempVariablesInPlace*/ false, /*shouldEmitCommaBeforeAssignment*/ false); synthesizedLHS.expression = identifier; (synthesizedLHS).dotToken = leftHandSideExpression.dotToken; @@ -3181,10 +3181,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi function emitDoStatementWorker(node: DoStatement, loop: ConvertedLoop) { write("do"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } if (node.statement.kind === SyntaxKind.Block) { write(" "); @@ -3207,10 +3207,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(")"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3532,8 +3532,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(`switch(${loopResultVariable}) {`); increaseIndent(); - emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /* isBreak */ true, loopResultVariable, outerLoop); - emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /* isBreak */ false, loopResultVariable, outerLoop); + emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalBreaks, /*isBreak*/ true, loopResultVariable, outerLoop); + emitDispatchEntriesForLabeledJumps(currentLoop.labeledNonLocalContinues, /*isBreak*/ false, loopResultVariable, outerLoop); decreaseIndent(); writeLine(); @@ -3597,10 +3597,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(")"); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3638,10 +3638,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitToken(SyntaxKind.CloseParenToken, node.expression.end); if (loop) { - emitConvertedLoopCall(loop, /* emitAsBlock */ true); + emitConvertedLoopCall(loop, /*emitAsBlock*/ true); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ true); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ true); } } @@ -3781,10 +3781,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi if (loop) { writeLine(); - emitConvertedLoopCall(loop, /* emitAsBlock */ false); + emitConvertedLoopCall(loop, /*emitAsBlock*/ false); } else { - emitNormalLoopBody(node, /* emitAsEmbeddedStatement */ false); + emitNormalLoopBody(node, /*emitAsEmbeddedStatement*/ false); } writeLine(); @@ -3818,11 +3818,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let labelMarker: string; if (node.kind === SyntaxKind.BreakStatement) { labelMarker = `break-${node.label.text}`; - setLabeledJump(convertedLoopState, /* isBreak */ true, node.label.text, labelMarker); + setLabeledJump(convertedLoopState, /*isBreak*/ true, node.label.text, labelMarker); } else { labelMarker = `continue-${node.label.text}`; - setLabeledJump(convertedLoopState, /* isBreak */ false, node.label.text, labelMarker); + setLabeledJump(convertedLoopState, /*isBreak*/ false, node.label.text, labelMarker); } write(`return "${labelMarker}";`); } @@ -4248,7 +4248,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let index: Expression; const nameIsComputed = propName.kind === SyntaxKind.ComputedPropertyName; if (nameIsComputed) { - index = ensureIdentifier((propName).expression, /* reuseIdentifierExpression */ false); + index = ensureIdentifier((propName).expression, /*reuseIdentifierExpressions*/ false); } else { // We create a synthetic copy of the identifier in order to avoid the rewriting that might @@ -5380,7 +5380,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitEnd(baseTypeElement); } } - emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ false)); + emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ false)); if (ctor) { let statements: Node[] = (ctor.body).statements; if (superCall) { @@ -5502,7 +5502,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // This keeps the expression as an expression, while ensuring that the static parts // of it have been initialized by the time it is used. - const staticProperties = getInitializedProperties(node, /*static:*/ true); + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression; let tempVariable: Identifier; @@ -5564,7 +5564,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi for (var property of staticProperties) { write(","); writeLine(); - emitPropertyDeclaration(node, property, /*receiver:*/ tempVariable, /*isExpression:*/ true); + emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true); } write(","); writeLine(); @@ -5638,7 +5638,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); emitConstructor(node, baseTypeNode); emitMemberFunctionsForES5AndLower(node); - emitPropertyDeclarations(node, getInitializedProperties(node, /*static:*/ true)); + emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true)); writeLine(); emitDecoratorsOfClass(node); writeLine(); @@ -8094,11 +8094,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi * Emit comments associated with node that will not be emitted into JS file */ function emitCommentsOnNotEmittedNode(node: Node) { - emitLeadingCommentsWorker(node, /*isEmittedNode:*/ false); + emitLeadingCommentsWorker(node, /*isEmittedNode*/ false); } function emitLeadingComments(node: Node) { - return emitLeadingCommentsWorker(node, /*isEmittedNode:*/ true); + return emitLeadingCommentsWorker(node, /*isEmittedNode*/ true); } function emitLeadingCommentsWorker(node: Node, isEmittedNode: boolean) { @@ -8127,7 +8127,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator:*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); } function emitTrailingComments(node: Node) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index ac37f608417..9a72593d3b0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -722,10 +722,10 @@ namespace ts { const contextFlagsToClear = context & contextFlags; if (contextFlagsToClear) { // clear the requested context flags - setContextFlag(false, contextFlagsToClear); + setContextFlag(/*val*/ false, contextFlagsToClear); const result = func(); // restore the context flags we just cleared - setContextFlag(true, contextFlagsToClear); + setContextFlag(/*val*/ true, contextFlagsToClear); return result; } @@ -743,10 +743,10 @@ namespace ts { const contextFlagsToSet = context & ~contextFlags; if (contextFlagsToSet) { // set the requested context flags - setContextFlag(true, contextFlagsToSet); + setContextFlag(/*val*/ true, contextFlagsToSet); const result = func(); // reset the context flags we just set - setContextFlag(false, contextFlagsToSet); + setContextFlag(/*val*/ false, contextFlagsToSet); return result; } @@ -1098,11 +1098,11 @@ namespace ts { } function parsePropertyName(): PropertyName { - return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ true); + return parsePropertyNameWorker(/*allowComputedPropertyNames*/ true); } function parseSimplePropertyName(): Identifier | LiteralExpression { - return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ false); + return parsePropertyNameWorker(/*allowComputedPropertyNames*/ false); } function isSimplePropertyName() { @@ -1385,7 +1385,7 @@ namespace ts { function isInSomeParsingContext(): boolean { for (let kind = 0; kind < ParsingContext.Count; kind++) { if (parsingContext & (1 << kind)) { - if (isListElement(kind, /* inErrorRecovery */ true) || isListTerminator(kind)) { + if (isListElement(kind, /*inErrorRecovery*/ true) || isListTerminator(kind)) { return true; } } @@ -1402,7 +1402,7 @@ namespace ts { result.pos = getNodePos(); while (!isListTerminator(kind)) { - if (isListElement(kind, /* inErrorRecovery */ false)) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { const element = parseListElement(kind, parseElement); result.push(element); @@ -1751,7 +1751,7 @@ namespace ts { let commaStart = -1; // Meaning the previous token was not a comma while (true) { - if (isListElement(kind, /* inErrorRecovery */ false)) { + if (isListElement(kind, /*inErrorRecovery*/ false)) { result.push(parseListElement(kind, parseElement)); commaStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.CommaToken)) { @@ -1859,7 +1859,7 @@ namespace ts { // Report that we need an identifier. However, report it right after the dot, // and not on the next token. This is because the next token might actually // be an identifier and the error would be quite confusing. - return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentToken*/ true, Diagnostics.Identifier_expected); + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); } } @@ -2609,7 +2609,7 @@ namespace ts { // clear the decorator context when parsing Expression, as it should be unambiguous when parsing a decorator const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } let expr = parseAssignmentExpressionOrHigher(); @@ -2619,7 +2619,7 @@ namespace ts { } if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } return expr; } @@ -2773,7 +2773,7 @@ namespace ts { node.parameters.pos = parameter.pos; node.parameters.end = parameter.end; - node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, false, Diagnostics._0_expected, "=>"); + node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>"); node.body = parseArrowFunctionExpressionBody(/*isAsync*/ false); return finishNode(node); @@ -3573,7 +3573,7 @@ namespace ts { parseExpected(SyntaxKind.GreaterThanToken); } else { - parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } node = createNode(SyntaxKind.JsxSelfClosingElement, fullStart); @@ -3609,7 +3609,7 @@ namespace ts { parseExpected(SyntaxKind.CloseBraceToken); } else { - parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } @@ -3654,7 +3654,7 @@ namespace ts { parseExpected(SyntaxKind.GreaterThanToken); } else { - parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*advance*/ false); + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); scanJsxText(); } return finishNode(node); @@ -3973,7 +3973,7 @@ namespace ts { // function BindingIdentifier[opt](FormalParameters){ FunctionBody } const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } const node = createNode(SyntaxKind.FunctionExpression); @@ -3993,7 +3993,7 @@ namespace ts { node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false); if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } return finishNode(node); @@ -4039,13 +4039,13 @@ namespace ts { // arrow function. The body of the function is not in [Decorator] context. const saveDecoratorContext = inDecoratorContext(); if (saveDecoratorContext) { - setDecoratorContext(false); + setDecoratorContext(/*val*/ false); } const block = parseBlock(ignoreMissingOpenBrace, diagnosticMessage); if (saveDecoratorContext) { - setDecoratorContext(true); + setDecoratorContext(/*val*/ true); } setYieldContext(savedYieldContext); @@ -6162,7 +6162,7 @@ namespace ts { if (sourceFile.statements.length === 0) { // If we don't have any statements in the current source file, then there's no real // way to incrementally parse. So just do a full parse instead. - return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true); + return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true); } // Make sure we're not trying to incrementally update a source file more than once. Once @@ -6226,7 +6226,7 @@ namespace ts { // inconsistent tree. Setting the parents on the new tree should be very fast. We // will immediately bail out of walking any subtrees when we can see that their parents // are already correct. - const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true); + const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true); return result; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ca0c7d9adaa..86fbc2e6259 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -364,13 +364,13 @@ namespace ts { } if (!tryReuseStructureFromOldProgram()) { - forEach(rootNames, name => processRootFile(name, false)); + forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false)); // Do not process the default library if: // - The '--noLib' flag is used. // - A 'no-default-lib' reference comment is encountered in // processing the root files. if (!skipDefaultLib) { - processRootFile(host.getDefaultLibFileName(options), true); + processRootFile(host.getDefaultLibFileName(options), /*isDefaultLib*/ true); } } @@ -693,7 +693,7 @@ namespace ts { let imports: LiteralExpression[]; for (const node of file.statements) { - collect(node, /* allowRelativeModuleNames */ true, /* collectOnlyRequireCalls */ false); + collect(node, /*allowRelativeModuleNames*/ true, /*collectOnlyRequireCalls*/ false); } file.imports = imports || emptyArray; @@ -729,7 +729,7 @@ namespace ts { // TypeScript 1.0 spec (April 2014): 12.1.6 // An ExternalImportDeclaration in anAmbientExternalModuleDeclaration may reference other external modules // only through top - level external module names. Relative external module names are not permitted. - collect(node, /* allowRelativeModuleNames */ false, collectOnlyRequireCalls); + collect(node, /*allowRelativeModuleNames*/ false, collectOnlyRequireCalls); }); } break; @@ -741,7 +741,7 @@ namespace ts { (imports || (imports = [])).push((node).arguments[0]); } else { - forEachChild(node, node => collect(node, allowRelativeModuleNames, /* collectOnlyRequireCalls */ true)); + forEachChild(node, node => collect(node, allowRelativeModuleNames, /*collectOnlyRequireCalls*/ true)); } } } @@ -862,7 +862,7 @@ namespace ts { function processReferencedFiles(file: SourceFile, basePath: string) { forEach(file.referencedFiles, ref => { const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName); - processSourceFile(referencedFileName, /* isDefaultLib */ false, file, ref.pos, ref.end); + processSourceFile(referencedFileName, /*isDefaultLib*/ false, file, ref.pos, ref.end); }); } @@ -880,7 +880,7 @@ namespace ts { const resolution = resolutions[i]; setResolvedModule(file, moduleNames[i], resolution); if (resolution && !options.noResolve) { - const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /* isDefaultLib */ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end); + const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end); if (importedFile && resolution.isExternalLibraryImport) { if (!isExternalModule(importedFile)) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 9703ef8517b..4289d910608 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1634,11 +1634,11 @@ namespace ts { } function lookAhead(callback: () => T): T { - return speculationHelper(callback, /*isLookahead:*/ true); + return speculationHelper(callback, /*isLookahead*/ true); } function tryScan(callback: () => T): T { - return speculationHelper(callback, /*isLookahead:*/ false); + return speculationHelper(callback, /*isLookahead*/ false); } function setText(newText: string, start: number, length: number) { diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index d46d0bde08c..fd8b248dfe2 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -182,7 +182,7 @@ class CompilerBaselineRunner extends RunnerBase { const declFileCompilationResult = Harness.Compiler.HarnessCompiler.compileDeclarationFiles( - toBeCompiled, otherFiles, result, harnessSettings, options, /* currentDirectory */ undefined); + toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined); if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n"; @@ -255,8 +255,8 @@ class CompilerBaselineRunner extends RunnerBase { const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); - const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true); - const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false); + const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); + const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ false); const fullResults: ts.Map = {}; const pullResults: ts.Map = {}; @@ -270,14 +270,14 @@ class CompilerBaselineRunner extends RunnerBase { // The second gives symbols for all identifiers. let e1: Error, e2: Error; try { - checkBaseLines(/*isSymbolBaseLine:*/ false); + checkBaseLines(/*isSymbolBaseLine*/ false); } catch (e) { e1 = e; } try { - checkBaseLines(/*isSymbolBaseLine:*/ true); + checkBaseLines(/*isSymbolBaseLine*/ true); } catch (e) { e2 = e; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 839a4521a29..ebc58096d6f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -514,7 +514,7 @@ namespace FourSlash { this.scenarioActions.push(``); if (actual !== expected) { - this.printErrorLog(false, errors); + this.printErrorLog(/*expectErrors*/ false, errors); const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; Harness.IO.log(errorMsg); this.raiseError(errorMsg); @@ -567,7 +567,7 @@ namespace FourSlash { public verifyMemberListCount(expectedCount: number, negative: boolean) { if (expectedCount === 0) { if (negative) { - this.verifyMemberListIsEmpty(false); + this.verifyMemberListIsEmpty(/*negative*/ false); return; } else { @@ -1347,7 +1347,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); // this.checkPostEditInletiants(); } } @@ -1389,7 +1389,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); } } } @@ -1449,7 +1449,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); // this.checkPostEditInletiants(); } } @@ -1477,7 +1477,7 @@ namespace FourSlash { if (this.enableFormatting) { const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); if (edits.length) { - offset += this.applyEdits(this.activeFile.fileName, edits, true); + offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.checkPostEditInletiants(); } } @@ -1563,7 +1563,7 @@ namespace FourSlash { this.scenarioActions.push(""); const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions); - this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); + this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); } @@ -1571,7 +1571,7 @@ namespace FourSlash { this.taoInvalidReason = "formatSelection NYI"; const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeOptions); - this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); + this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index aa70087ea31..9bc36e257ad 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -628,7 +628,7 @@ namespace Harness { function getResolvedPathFromServer(path: string) { const xhr = new XMLHttpRequest(); try { - xhr.open("GET", path + "?resolve", false); + xhr.open("GET", path + "?resolve", /*async*/ false); xhr.send(); } catch (e) { @@ -647,7 +647,7 @@ namespace Harness { export function getFileFromServerSync(url: string): XHRResponse { const xhr = new XMLHttpRequest(); try { - xhr.open("GET", url, false); + xhr.open("GET", url, /*async*/ false); xhr.send(); } catch (e) { @@ -662,7 +662,7 @@ namespace Harness { const xhr = new XMLHttpRequest(); try { const actionMsg = "?action=" + action; - xhr.open("POST", url + actionMsg, false); + xhr.open("POST", url + actionMsg, /*async*/ false); xhr.setRequestHeader("Access-Control-Allow-Origin", "*"); xhr.send(contents); } diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index bf56f1aa3ea..0bae91f7976 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -174,7 +174,7 @@ namespace Playback { return true; } else { - return findResultByFields(replayLog.fileExists, { path }, false); + return findResultByFields(replayLog.fileExists, { path }, /*defaultValue*/ false); } }) ); diff --git a/src/harness/sourceMapRecorder.ts b/src/harness/sourceMapRecorder.ts index ce0a6a6528e..75246a9a266 100644 --- a/src/harness/sourceMapRecorder.ts +++ b/src/harness/sourceMapRecorder.ts @@ -190,7 +190,7 @@ namespace Harness.SourceMapRecoder { return { error: errorDecodeOfEncodedMapping, sourceMapSpan: decodeOfEncodedMapping }; } - createErrorIfCondition(true, "No encoded entry found"); + createErrorIfCondition(/*condition*/ true, "No encoded entry found"); } export function hasCompletedDecoding() { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 795bd7db732..c3cd65e857b 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -388,7 +388,7 @@ namespace ts.server { } openReferencedFile(filename: string) { - return this.projectService.openFile(filename, false); + return this.projectService.openFile(filename, /*openedByClient*/ false); } getRootFiles() { @@ -1068,7 +1068,7 @@ namespace ts.server { */ openClientFile(fileName: string, fileContent?: string) { this.openOrUpdateConfiguredProjectForFile(fileName); - const info = this.openFile(fileName, true, fileContent); + const info = this.openFile(fileName, /*openedByClient*/ true, fileContent); this.addOpenFile(info); this.printProjects(); return info; @@ -1277,7 +1277,7 @@ namespace ts.server { for (const fileName of fileNamesToAdd) { let info = this.getScriptInfo(fileName); if (!info) { - info = this.openFile(fileName, false); + info = this.openFile(fileName, /*openedByClient*/ false); } else { // if the root file was opened by client, it would belong to either diff --git a/src/server/session.ts b/src/server/session.ts index f04f73f644c..dae2384ce54 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -901,7 +901,7 @@ namespace ts.server { } getDiagnosticsForProject(delay: number, fileName: string) { - const { configFileName, fileNames } = this.getProjectInfo(fileName, true); + const { configFileName, fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true); // No need to analyze lib.d.ts let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0); From e49e55287a3b205ffa263b6fc58fa59fa8395e7b Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sat, 14 Nov 2015 12:08:47 -0800 Subject: [PATCH 19/35] do not crash when variable and function declarations collide --- src/compiler/checker.ts | 6 ++++-- .../reference/nonMergedOverloads.errors.txt | 20 +++++++++++++++++++ .../baselines/reference/nonMergedOverloads.js | 12 +++++++++++ tests/cases/compiler/nonMergedOverloads.ts | 5 +++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/nonMergedOverloads.errors.txt create mode 100644 tests/baselines/reference/nonMergedOverloads.js create mode 100644 tests/cases/compiler/nonMergedOverloads.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7f5f73a58db..f975c110b03 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11360,12 +11360,14 @@ namespace ts { const errorNode: Node = (subsequentNode).name || subsequentNode; // TODO(jfreeman): These are methods, so handle computed name case if (node.name && (subsequentNode).name && (node.name).text === ((subsequentNode).name).text) { - Debug.assert(node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature); + const reportError = + (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && + (node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static); // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging // here we'll report error only for the first case since for second we should already report error in binder - if ((node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static)) { + if (reportError) { const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); } diff --git a/tests/baselines/reference/nonMergedOverloads.errors.txt b/tests/baselines/reference/nonMergedOverloads.errors.txt new file mode 100644 index 00000000000..9a38ebdc3b3 --- /dev/null +++ b/tests/baselines/reference/nonMergedOverloads.errors.txt @@ -0,0 +1,20 @@ +tests/cases/compiler/nonMergedOverloads.ts(1,5): error TS2300: Duplicate identifier 'f'. +tests/cases/compiler/nonMergedOverloads.ts(3,17): error TS1148: Cannot compile modules unless the '--module' flag is provided. +tests/cases/compiler/nonMergedOverloads.ts(3,17): error TS2300: Duplicate identifier 'f'. +tests/cases/compiler/nonMergedOverloads.ts(4,17): error TS2300: Duplicate identifier 'f'. + + +==== tests/cases/compiler/nonMergedOverloads.ts (4 errors) ==== + var f = 10; + ~ +!!! error TS2300: Duplicate identifier 'f'. + + export function f(); + ~ +!!! error TS1148: Cannot compile modules unless the '--module' flag is provided. + ~ +!!! error TS2300: Duplicate identifier 'f'. + export function f() { + ~ +!!! error TS2300: Duplicate identifier 'f'. + } \ No newline at end of file diff --git a/tests/baselines/reference/nonMergedOverloads.js b/tests/baselines/reference/nonMergedOverloads.js new file mode 100644 index 00000000000..2e7f7f67ee6 --- /dev/null +++ b/tests/baselines/reference/nonMergedOverloads.js @@ -0,0 +1,12 @@ +//// [nonMergedOverloads.ts] +var f = 10; + +export function f(); +export function f() { +} + +//// [nonMergedOverloads.js] +var f = 10; +function f() { +} +exports.f = f; diff --git a/tests/cases/compiler/nonMergedOverloads.ts b/tests/cases/compiler/nonMergedOverloads.ts new file mode 100644 index 00000000000..582cd72e1f4 --- /dev/null +++ b/tests/cases/compiler/nonMergedOverloads.ts @@ -0,0 +1,5 @@ +var f = 10; + +export function f(); +export function f() { +} \ No newline at end of file From 762e1eb0a886a13de3b62b771c1778ae506ccbd0 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sat, 14 Nov 2015 13:57:11 -0800 Subject: [PATCH 20/35] cleanup harness code --- src/harness/compilerRunner.ts | 13 +- src/harness/fourslash.ts | 36 ++- src/harness/harness.ts | 330 ++++++++++---------------- src/harness/harnessLanguageService.ts | 10 +- src/harness/rwcRunner.ts | 4 +- src/harness/test262Runner.ts | 11 +- 6 files changed, 161 insertions(+), 243 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index fd8b248dfe2..85a51b8f2a4 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -55,7 +55,6 @@ class CompilerBaselineRunner extends RunnerBase { let rootDir: string; let result: Harness.Compiler.CompilerResult; - let program: ts.Program; let options: ts.CompilerOptions; // equivalent to the files that will be passed on the command line let toBeCompiled: Harness.Compiler.TestFile[]; @@ -89,12 +88,11 @@ class CompilerBaselineRunner extends RunnerBase { }); } - const output = Harness.Compiler.HarnessCompiler.compileFiles( + const output = Harness.Compiler.compileFiles( toBeCompiled, otherFiles, harnessSettings, /* options */ undefined, /* currentDirectory */ undefined); options = output.options; result = output.result; - program = output.program; }); after(() => { @@ -108,7 +106,6 @@ class CompilerBaselineRunner extends RunnerBase { lastUnit = undefined; rootDir = undefined; result = undefined; - program = undefined; options = undefined; toBeCompiled = undefined; otherFiles = undefined; @@ -181,7 +178,7 @@ class CompilerBaselineRunner extends RunnerBase { } const declFileCompilationResult = - Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + Harness.Compiler.compileDeclarationFiles( toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined); if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) { @@ -253,10 +250,10 @@ class CompilerBaselineRunner extends RunnerBase { // These types are equivalent, but depend on what order the compiler observed // certain parts of the program. - const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); + const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)); - const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); - const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ false); + const fullWalker = new TypeWriterWalker(result.program, /*fullTypeCheck*/ true); + const pullWalker = new TypeWriterWalker(result.program, /*fullTypeCheck*/ false); const fullResults: ts.Map = {}; const pullResults: ts.Map = {}; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ebc58096d6f..f62e1c58412 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2383,10 +2383,9 @@ namespace FourSlash { // here we cache the JS output and reuse it for every test. let fourslashJsOutput: string; { - const fourslashFile: Harness.Compiler.TestFileWithPath = { + const fourslashFile: Harness.Compiler.TestFile = { unitName: Harness.Compiler.fourslashFileName, - content: undefined, - path: ts.toPath(Harness.Compiler.fourslashFileName, Harness.IO.getCurrentDirectory(), Harness.Compiler.getCanonicalFileName) + content: undefined }; const host = Harness.Compiler.createCompilerHost([fourslashFile], (fn, contents) => fourslashJsOutput = contents, @@ -2399,35 +2398,28 @@ namespace FourSlash { program.emit(host.getSourceFile(Harness.Compiler.fourslashFileName, ts.ScriptTarget.ES3)); } - export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): TestXmlData { // Parse out the files and their metadata const testData = parseTestData(basePath, content, fileName); currentTestState = new TestState(basePath, testType, testData); - const currentDirectory = Harness.IO.getCurrentDirectory(); - const useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); - const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); - let result = ""; - const fourslashFile: Harness.Compiler.TestFileWithPath = { + const fourslashFile: Harness.Compiler.TestFile = { unitName: Harness.Compiler.fourslashFileName, content: undefined, - path: ts.toPath(Harness.Compiler.fourslashFileName, currentDirectory, getCanonicalFileName) }; - const testFile: Harness.Compiler.TestFileWithPath = { + const testFile: Harness.Compiler.TestFile = { unitName: fileName, - content: content, - path: ts.toPath(fileName, currentDirectory, getCanonicalFileName) + content: content }; const host = Harness.Compiler.createCompilerHost( [ fourslashFile, testFile ], (fn, contents) => result = contents, ts.ScriptTarget.Latest, - useCaseSensitiveFileNames, - currentDirectory); + Harness.IO.useCaseSensitiveFileNames(), + Harness.IO.getCurrentDirectory()); const program = ts.createProgram([Harness.Compiler.fourslashFileName, fileName], { outFile: "fourslashTestOutput.js", noResolve: true, target: ts.ScriptTarget.ES3 }, host); @@ -2444,18 +2436,22 @@ namespace FourSlash { result = fourslashJsOutput + "\r\n" + result; + runCode(result); + + const xmlData = currentTestState.getTestXmlData(); + xmlData.originalName = fileName; + return xmlData; + } + + function runCode(code: string): void { // Compile and execute the test try { - eval(result); + eval(code); } catch (err) { // Debugging: FourSlash.currentTestState.printCurrentFileState(); throw err; } - - const xmlData = currentTestState.getTestXmlData(); - xmlData.originalName = fileName; - return xmlData; } function chompLeadingSpace(content: string) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 9bc36e257ad..e58e6635434 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -767,25 +767,8 @@ namespace Harness { } namespace Harness { - let tcServicesFileName = "typescriptServices.js"; - - export let libFolder: string; - switch (Utils.getExecutionEnvironment()) { - case Utils.ExecutionEnvironment.CScript: - libFolder = "built/local/"; - tcServicesFileName = "built/local/typescriptServices.js"; - break; - case Utils.ExecutionEnvironment.Node: - libFolder = "built/local/"; - tcServicesFileName = "built/local/typescriptServices.js"; - break; - case Utils.ExecutionEnvironment.Browser: - libFolder = "built/local/"; - tcServicesFileName = "built/local/typescriptServices.js"; - break; - default: - throw new Error("Unknown context"); - } + const tcServicesFileName = "built/local/typescriptServices.js"; + export const libFolder = "built/local/"; export let tcServicesFile = IO.readFile(tcServicesFileName); export interface SourceMapEmitterCallback { @@ -827,57 +810,14 @@ namespace Harness { } } - export interface IEmitterIOHost { - writeFile(path: string, contents: string, writeByteOrderMark: boolean): void; - resolvePath(path: string): string; - } - - /** Mimics having multiple files, later concatenated to a single file. */ - export class EmitterIOHost implements IEmitterIOHost { - private fileCollection: any = {}; - - /** create file gets the whole path to create, so this works as expected with the --out parameter */ - public writeFile(s: string, contents: string, writeByteOrderMark: boolean): void { - let writer: ITextWriter; - if (this.fileCollection[s]) { - writer = this.fileCollection[s]; - } - else { - writer = new Harness.Compiler.WriterAggregator(); - this.fileCollection[s] = writer; - } - - writer.Write(contents); - writer.Close(); - } - - public resolvePath(s: string) { return s; } - - public reset() { this.fileCollection = {}; } - - public toArray(): { fileName: string; file: WriterAggregator; }[] { - const result: { fileName: string; file: WriterAggregator; }[] = []; - for (const p in this.fileCollection) { - if (this.fileCollection.hasOwnProperty(p)) { - const current = this.fileCollection[p]; - if (current.lines.length > 0) { - if (p.indexOf(".d.ts") !== -1) { current.lines.unshift(["////[", Path.getFileName(p), "]"].join("")); } - result.push({ fileName: p, file: this.fileCollection[p] }); - } - } - } - return result; - } - } - export function createSourceFileAndAssertInvariants( fileName: string, sourceText: string, languageVersion: ts.ScriptTarget) { - // We'll only assert inletiants outside of light mode. + // We'll only assert invariants outside of light mode. const shouldAssertInvariants = !Harness.lightMode; - // Only set the parent nodes if we're asserting inletiants. We don't need them otherwise. + // Only set the parent nodes if we're asserting invariants. We don't need them otherwise. const result = ts.createSourceFile(fileName, sourceText, languageVersion, /*setParentNodes:*/ shouldAssertInvariants); if (shouldAssertInvariants) { @@ -890,12 +830,12 @@ namespace Harness { const carriageReturnLineFeed = "\r\n"; const lineFeed = "\n"; - export let defaultLibFileName = "lib.d.ts"; - export let defaultLibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest); - export let defaultES6LibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.es6.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest); + export const defaultLibFileName = "lib.d.ts"; + export const defaultLibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest); + export const defaultES6LibSourceFile = createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.core.es6.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest); // Cache these between executions so we don't have to re-parse them for every test - export let fourslashFileName = "fourslash.ts"; + export const fourslashFileName = "fourslash.ts"; export let fourslashSourceFile: ts.SourceFile; export function getCanonicalFileName(fileName: string): string { @@ -903,7 +843,7 @@ namespace Harness { } export function createCompilerHost( - inputFiles: TestFileWithPath[], + inputFiles: TestFile[], writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void, scriptTarget: ts.ScriptTarget, useCaseSensitiveFileNames: boolean, @@ -915,16 +855,14 @@ namespace Harness { const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); const fileMap: ts.FileMap = ts.createFileMap(); - - // Register input files - function register(file: TestFileWithPath) { + for (const file of inputFiles) { if (file.content !== undefined) { const fileName = ts.normalizePath(file.unitName); const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget); - fileMap.set(file.path, sourceFile); + const path = ts.toPath(file.unitName, currentDirectory, getCanonicalFileName); + fileMap.set(path, sourceFile); } - }; - inputFiles.forEach(register); + } function getSourceFile(fn: string, languageVersion: ts.ScriptTarget) { fn = ts.normalizePath(fn); @@ -1031,147 +969,133 @@ namespace Harness { unitName: string; content: string; } - export interface TestFileWithPath extends TestFile { - path: ts.Path; - } export interface CompilationOutput { result: CompilerResult; - program: ts.Program; options: ts.CompilerOptions & HarnessOptions; } - export namespace HarnessCompiler { - export function compileFiles( - inputFiles: TestFile[], - otherFiles: TestFile[], - harnessSettings: TestCaseParser.CompilerSettings, - compilerOptions: ts.CompilerOptions, - // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory: string): CompilationOutput { + export function compileFiles( + inputFiles: TestFile[], + otherFiles: TestFile[], + harnessSettings: TestCaseParser.CompilerSettings, + compilerOptions: ts.CompilerOptions, + // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file + currentDirectory: string): CompilationOutput { - const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false }; - options.target = options.target || ts.ScriptTarget.ES3; - options.module = options.module || ts.ModuleKind.None; - options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; - options.noErrorTruncation = true; - options.skipDefaultLibCheck = true; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false }; + options.target = options.target || ts.ScriptTarget.ES3; + options.module = options.module || ts.ModuleKind.None; + options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; + options.noErrorTruncation = true; + options.skipDefaultLibCheck = true; - const newLine = "\r\n"; - currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory(); + const newLine = "\r\n"; + currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory(); - // Parse settings - let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); - if (harnessSettings) { - setCompilerOptionsFromHarnessSetting(harnessSettings, options); - } - if (options.useCaseSensitiveFileNames !== undefined) { - useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; - } - const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames); - const inputFilesWithPath = inputFiles.map(f => { - return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; - }); - const otherFilesWithPath = otherFiles.map(f => { - return { unitName: f.unitName, content: f.content, path: ts.toPath(f.unitName, currentDirectory, getCanonicalFileName) }; - }); - - // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. - // Treat them as library files, so include them in build, but not in baselines. - const includeBuiltFiles: TestFileWithPath[] = []; - if (options.includeBuiltFile) { - const builtFileName = libFolder + options.includeBuiltFile; - const builtFile: TestFileWithPath = { - unitName: builtFileName, - content: normalizeLineEndings(IO.readFile(builtFileName), newLine), - path: ts.toPath(builtFileName, currentDirectory, getCanonicalFileName) - }; - includeBuiltFiles.push(builtFile); - } - - const fileOutputs: GeneratedFile[] = []; - - const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); - - const compilerHost = createCompilerHost( - inputFilesWithPath.concat(includeBuiltFiles).concat(otherFilesWithPath), - (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }), - options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); - const program = ts.createProgram(programFiles, options, compilerHost); - - const emitResult = program.emit(); - - const errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); - - const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps); - return { result, program, options }; + // Parse settings + let useCaseSensitiveFileNames = Harness.IO.useCaseSensitiveFileNames(); + if (harnessSettings) { + setCompilerOptionsFromHarnessSetting(harnessSettings, options); + } + if (options.useCaseSensitiveFileNames !== undefined) { + useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; } - export function compileDeclarationFiles(inputFiles: TestFile[], - otherFiles: TestFile[], - result: CompilerResult, - harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions, - options: ts.CompilerOptions, - // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory: string) { - if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) { - throw new Error("There were no errors and declFiles generated did not match number of js files generated"); + // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. + // Treat them as library files, so include them in build, but not in baselines. + const includeBuiltFiles: TestFile[] = []; + if (options.includeBuiltFile) { + const builtFileName = libFolder + options.includeBuiltFile; + const builtFile: TestFile = { + unitName: builtFileName, + content: normalizeLineEndings(IO.readFile(builtFileName), newLine), + }; + includeBuiltFiles.push(builtFile); + } + + const fileOutputs: GeneratedFile[] = []; + + const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); + + const compilerHost = createCompilerHost( + inputFiles.concat(includeBuiltFiles).concat(otherFiles), + (fileName, code, writeByteOrderMark) => fileOutputs.push({ fileName, code, writeByteOrderMark }), + options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); + const program = ts.createProgram(programFiles, options, compilerHost); + + const emitResult = program.emit(); + + const errors = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics); + + const result = new CompilerResult(fileOutputs, errors, program, Harness.IO.getCurrentDirectory(), emitResult.sourceMaps); + return { result, options }; + } + + export function compileDeclarationFiles(inputFiles: TestFile[], + otherFiles: TestFile[], + result: CompilerResult, + harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions, + options: ts.CompilerOptions, + // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file + currentDirectory: string) { + if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) { + throw new Error("There were no errors and declFiles generated did not match number of js files generated"); + } + + const declInputFiles: TestFile[] = []; + const declOtherFiles: TestFile[] = []; + + // if the .d.ts is non-empty, confirm it compiles correctly as well + if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) { + ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); + ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); + const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory); + + return { declInputFiles, declOtherFiles, declResult: output.result }; + } + + function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { + if (isDTS(file.unitName)) { + dtsFiles.push(file); } - - const declInputFiles: TestFile[] = []; - const declOtherFiles: TestFile[] = []; - - // if the .d.ts is non-empty, confirm it compiles correctly as well - if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) { - ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles)); - ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles)); - const output = this.compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory); - - return { declInputFiles, declOtherFiles, declResult: output.result }; - } - - function addDtsFile(file: TestFile, dtsFiles: TestFile[]) { - if (isDTS(file.unitName)) { - dtsFiles.push(file); - } - else if (isTS(file.unitName)) { - const declFile = findResultCodeFile(file.unitName); - if (declFile && !findUnit(declFile.fileName, declInputFiles) && !findUnit(declFile.fileName, declOtherFiles)) { - dtsFiles.push({ unitName: declFile.fileName, content: declFile.code }); - } - } - - function findResultCodeFile(fileName: string) { - const sourceFile = result.program.getSourceFile(fileName); - assert(sourceFile, "Program has no source file with name '" + fileName + "'"); - // Is this file going to be emitted separately - let sourceFileName: string; - const outFile = options.outFile || options.out; - if (ts.isExternalModule(sourceFile) || !outFile) { - if (options.outDir) { - let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, result.currentDirectoryForProgram); - sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), ""); - sourceFileName = ts.combinePaths(options.outDir, sourceFilePath); - } - else { - sourceFileName = sourceFile.fileName; - } - } - else { - // Goes to single --out file - sourceFileName = outFile; - } - - const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts"; - - return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined); - } - - function findUnit(fileName: string, units: TestFile[]) { - return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined); + else if (isTS(file.unitName)) { + const declFile = findResultCodeFile(file.unitName); + if (declFile && !findUnit(declFile.fileName, declInputFiles) && !findUnit(declFile.fileName, declOtherFiles)) { + dtsFiles.push({ unitName: declFile.fileName, content: declFile.code }); } } } + + function findResultCodeFile(fileName: string) { + const sourceFile = result.program.getSourceFile(fileName); + assert(sourceFile, "Program has no source file with name '" + fileName + "'"); + // Is this file going to be emitted separately + let sourceFileName: string; + const outFile = options.outFile || options.out; + if (ts.isExternalModule(sourceFile) || !outFile) { + if (options.outDir) { + let sourceFilePath = ts.getNormalizedAbsolutePath(sourceFile.fileName, result.currentDirectoryForProgram); + sourceFilePath = sourceFilePath.replace(result.program.getCommonSourceDirectory(), ""); + sourceFileName = ts.combinePaths(options.outDir, sourceFilePath); + } + else { + sourceFileName = sourceFile.fileName; + } + } + else { + // Goes to single --out file + sourceFileName = outFile; + } + + const dTsFileName = ts.removeFileExtension(sourceFileName) + ".d.ts"; + + return ts.forEach(result.declFilesCode, declFile => declFile.fileName === dTsFileName ? declFile : undefined); + } + + function findUnit(fileName: string, units: TestFile[]) { + return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined); + } } function normalizeLineEndings(text: string, lineEnding: string): string { @@ -1388,7 +1312,7 @@ namespace Harness { constructor(fileResults: GeneratedFile[], errors: ts.Diagnostic[], public program: ts.Program, public currentDirectoryForProgram: string, private sourceMapData: ts.SourceMapData[]) { - fileResults.forEach(emittedFile => { + for (const emittedFile of fileResults) { if (isDTS(emittedFile.fileName)) { // .d.ts file, add to declFiles emit this.declFilesCode.push(emittedFile); @@ -1403,7 +1327,7 @@ namespace Harness { else { throw new Error("Unrecognized file extension for file " + emittedFile.fileName); } - }); + } this.errors = errors; } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 0c267c38f14..3c7814df562 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -7,7 +7,7 @@ namespace Harness.LanguageService { export class ScriptInfo { public version: number = 1; public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = []; - public lineMap: number[] = undefined; + private lineMap: number[] = undefined; constructor(public fileName: string, public content: string) { this.setContent(content); @@ -15,7 +15,11 @@ namespace Harness.LanguageService { private setContent(content: string): void { this.content = content; - this.lineMap = ts.computeLineStarts(content); + this.lineMap = undefined; + } + + public getLineMap(): number[] { + return this.lineMap || (this.lineMap = ts.computeLineStarts(this.content)); } public updateContent(content: string): void { @@ -164,7 +168,7 @@ namespace Harness.LanguageService { const script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); - return ts.computeLineAndCharacterOfPosition(script.lineMap, position); + return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position); } } diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index fc1397b294c..ce570a7d6ad 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -126,7 +126,7 @@ namespace RWC { // Emit the results compilerOptions = null; - const output = Harness.Compiler.HarnessCompiler.compileFiles( + const output = Harness.Compiler.compileFiles( inputFiles, otherFiles, /* harnessOptions */ undefined, @@ -202,7 +202,7 @@ namespace RWC { it("has the expected errors in generated declaration files", () => { if (compilerOptions.declaration && !compilerResult.errors.length) { Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => { - const declFileCompilationResult = Harness.Compiler.HarnessCompiler.compileDeclarationFiles( + const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles( inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory); if (declFileCompilationResult.declResult.errors.length === 0) { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index 859f10dc4cc..262145b4764 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -32,7 +32,6 @@ class Test262BaselineRunner extends RunnerBase { filename: string; compilerResult: Harness.Compiler.CompilerResult; inputFiles: Harness.Compiler.TestFile[]; - program: ts.Program; }; before(() => { @@ -50,10 +49,9 @@ class Test262BaselineRunner extends RunnerBase { filename: testFilename, inputFiles: inputFiles, compilerResult: undefined, - program: undefined, }; - const output = Harness.Compiler.HarnessCompiler.compileFiles( + const output = Harness.Compiler.compileFiles( [Test262BaselineRunner.helperFile].concat(inputFiles), /*otherFiles*/ [], /* harnessOptions */ undefined, @@ -61,7 +59,6 @@ class Test262BaselineRunner extends RunnerBase { /* currentDirectory */ undefined ); testState.compilerResult = output.result; - testState.program = output.program; }); after(() => { @@ -86,14 +83,14 @@ class Test262BaselineRunner extends RunnerBase { }, false, Test262BaselineRunner.baselineOptions); }); - it("satisfies inletiants", () => { - const sourceFile = testState.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); + it("satisfies invariants", () => { + const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); Utils.assertInvariants(sourceFile, /*parent:*/ undefined); }); it("has the expected AST", () => { Harness.Baseline.runBaseline("has the expected AST", testState.filename + ".AST.txt", () => { - const sourceFile = testState.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); + const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); return Utils.sourceFileToJSON(sourceFile); }, false, Test262BaselineRunner.baselineOptions); }); From eda75fbfd528875bb23d3eb07cb3afb689d51829 Mon Sep 17 00:00:00 2001 From: tobisek Date: Sun, 15 Nov 2015 15:03:43 +0200 Subject: [PATCH 21/35] added default chrome path for Mac OS X --- tests/webTestServer.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts index 6bd15359e3f..dab552e2619 100644 --- a/tests/webTestServer.ts +++ b/tests/webTestServer.ts @@ -269,6 +269,9 @@ if ((browser && browser === 'chrome')) { case "win64": defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"; break; + case "darwin": + defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; + break; case "linux": defaultChromePath = "/opt/google/chrome/chrome" break; From 078ed3f4856c527cd4cfcfc23166d1f74c041ea8 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 09:49:58 -0800 Subject: [PATCH 22/35] use normalized absolute file names when doing consistency check --- src/compiler/program.ts | 16 +++++++-------- tests/cases/unittests/moduleResolution.ts | 25 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 86fbc2e6259..57207d0564a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -800,12 +800,12 @@ namespace ts { } // Get source file from normalized fileName - function findSourceFile(fileName: string, normalizedAbsolutePath: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile { - if (filesByName.contains(normalizedAbsolutePath)) { - const file = filesByName.get(normalizedAbsolutePath); + function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile { + if (filesByName.contains(path)) { + const file = filesByName.get(path); // try to check if we've already seen this file but with a different casing in path // NOTE: this only makes sense for case-insensitive file systems - if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== normalizedAbsolutePath) { + if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== getNormalizedAbsolutePath(fileName, currentDirectory)) { reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd); } @@ -823,18 +823,18 @@ namespace ts { } }); - filesByName.set(normalizedAbsolutePath, file); + filesByName.set(path, file); if (file) { - file.path = normalizedAbsolutePath; + file.path = path; if (host.useCaseSensitiveFileNames()) { // for case-sensitive file systems check if we've already seen some file with similar filename ignoring case - const existingFile = filesByNameIgnoreCase.get(normalizedAbsolutePath); + const existingFile = filesByNameIgnoreCase.get(path); if (existingFile) { reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd); } else { - filesByNameIgnoreCase.set(normalizedAbsolutePath, file); + filesByNameIgnoreCase.set(path, file); } } diff --git a/tests/cases/unittests/moduleResolution.ts b/tests/cases/unittests/moduleResolution.ts index c53cad5725a..9e316266bf6 100644 --- a/tests/cases/unittests/moduleResolution.ts +++ b/tests/cases/unittests/moduleResolution.ts @@ -354,6 +354,31 @@ export = C; "moduleC.ts": "export var x" }; test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /* useCaseSensitiveFileNames */ false, ["moduleA.ts", "moduleB.ts", "moduleC.ts"], [1149, 1149]); + }); + + it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => { + const files: Map = { + "/a/B/c/moduleA.ts": `import a = require("./ModuleC")`, + "/a/B/c/moduleB.ts": `import a = require("./moduleC")`, + "/a/B/c/moduleC.ts": "export var x", + "/a/B/c/moduleD.ts": ` +import a = require("./moduleA.ts"); +import b = require("./moduleB.ts"); + ` + }; + test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /* useCaseSensitiveFileNames */ false, ["moduleD.ts"], [1149]); + }); + it("should not fail when module names in 'require' calls has consistent casing and current directory has uppercase chars", () => { + const files: Map = { + "/a/B/c/moduleA.ts": `import a = require("./moduleC")`, + "/a/B/c/moduleB.ts": `import a = require("./moduleC")`, + "/a/B/c/moduleC.ts": "export var x", + "/a/B/c/moduleD.ts": ` +import a = require("./moduleA.ts"); +import b = require("./moduleB.ts"); + ` + }; + test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /* useCaseSensitiveFileNames */ false, ["moduleD.ts"], []); }) }); } \ No newline at end of file From 8039909913be85531b09cef6cc31a61542cc5408 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 10:36:13 -0800 Subject: [PATCH 23/35] remove Tao generation --- src/harness/fourslash.ts | 282 +++++---------------------------- src/harness/fourslashRunner.ts | 50 ------ 2 files changed, 37 insertions(+), 295 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index f62e1c58412..88458beaba4 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -48,12 +48,6 @@ namespace FourSlash { ranges: Range[]; } - export interface TestXmlData { - invalidReason: string; - originalName: string; - actions: string[]; - } - interface MemberListData { result: { maybeInaccurate: boolean; @@ -84,14 +78,14 @@ namespace FourSlash { marker?: Marker; } - interface ILocationInformation { + interface LocationInformation { position: number; sourcePosition: number; sourceLine: number; sourceColumn: number; } - interface IRangeLocationInformation extends ILocationInformation { + interface RangeLocationInformation extends LocationInformation { marker?: Marker; } @@ -134,11 +128,6 @@ namespace FourSlash { return settings; } - export let currentTestState: TestState = null; - function assertionMessage(msg: string) { - return "\nMarker: " + currentTestState.lastKnownMarker + "\nChecking: " + msg + "\n\n"; - } - export class TestCancellationToken implements ts.HostCancellationToken { // 0 - cancelled // >0 - not cancelled @@ -216,9 +205,6 @@ namespace FourSlash { public formatCodeOptions: ts.FormatCodeOptions; - private scenarioActions: string[] = []; - private taoInvalidReason: string = null; - private inputFiles: ts.Map = {}; // Map between inputFile's fileName and its content for easily looking up when resolving references // Add input file which has matched file name with the given reference-file path. @@ -338,7 +324,6 @@ namespace FourSlash { this.testData.files.forEach(file => { const fileName = file.fileName.replace(Harness.IO.directoryName(file.fileName), "").substr(1); const fileNameWithoutExtension = fileName.substr(0, fileName.lastIndexOf(".")); - this.scenarioActions.push(""); }); // Open the first file by default @@ -367,21 +352,11 @@ namespace FourSlash { public goToPosition(pos: number) { this.currentCaretPosition = pos; - - const lineStarts = ts.computeLineStarts(this.getFileContent(this.activeFile.fileName)); - const lineCharPos = ts.computeLineAndCharacterOfPosition(lineStarts, pos); - this.scenarioActions.push(``); } public moveCaretRight(count = 1) { this.currentCaretPosition += count; this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length); - if (count > 0) { - this.scenarioActions.push(``); - } - else { - this.scenarioActions.push(``); - } } // Opens a file given its 0-based index or fileName @@ -391,9 +366,6 @@ namespace FourSlash { const fileToOpen: FourSlashFile = this.findFile(indexOrName); fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; - const fileName = fileToOpen.fileName.replace(Harness.IO.directoryName(fileToOpen.fileName), "").substr(1); - this.scenarioActions.push(``); - // Let the host know that this file is now open this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content); } @@ -407,8 +379,6 @@ namespace FourSlash { const exists = this.anyErrorInRange(predicate, startMarker, endMarker); - this.taoInvalidReason = "verifyErrorExistsBetweenMarkers NYI"; - if (exists !== negative) { this.printErrorLog(negative, this.getAllDiagnostics()); throw new Error("Failure between markers: " + startMarkerName + ", " + endMarkerName); @@ -421,7 +391,11 @@ namespace FourSlash { } private messageAtLastKnownMarker(message: string) { - return "Marker: " + currentTestState.lastKnownMarker + "\n" + message; + return "Marker: " + this.lastKnownMarker + "\n" + message; + } + + private assertionMessageAtLastKnownMarker(msg: string) { + return "\nMarker: " + this.lastKnownMarker + "\nChecking: " + msg + "\n\n"; } private getDiagnostics(fileName: string): ts.Diagnostic[] { @@ -461,8 +435,6 @@ namespace FourSlash { }; } - this.taoInvalidReason = "verifyErrorExistsAfterMarker NYI"; - const exists = this.anyErrorInRange(predicate, marker); const diagnostics = this.getAllDiagnostics(); @@ -511,8 +483,6 @@ namespace FourSlash { const errors = this.getDiagnostics(this.activeFile.fileName); const actual = errors.length; - this.scenarioActions.push(``); - if (actual !== expected) { this.printErrorLog(/*expectErrors*/ false, errors); const errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")"; @@ -527,8 +497,6 @@ namespace FourSlash { throw new Error("Expected exactly one output from emit of " + this.activeFile.fileName); } - this.taoInvalidReason = "verifyEval impossible"; - const evaluation = new Function(`${emit.outputFiles[0].text};\r\nreturn (${expr});`)(); if (evaluation !== value) { this.raiseError(`Expected evaluation of expression "${expr}" to equal "${value}", but got "${evaluation}"`); @@ -540,7 +508,6 @@ namespace FourSlash { if (emit.outputFiles.length !== 1) { throw new Error("Expected exactly one output from emit of " + this.activeFile.fileName); } - this.taoInvalidReason = "verifyGetEmitOutputForCurrentFile impossible"; const actual = emit.outputFiles[0].text; if (actual !== expected) { this.raiseError(`Expected emit output to be "${expected}", but got "${actual}"`); @@ -548,13 +515,6 @@ namespace FourSlash { } public verifyMemberListContains(symbol: string, text?: string, documentation?: string, kind?: string) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); - - if (text || documentation || kind) { - this.taoInvalidReason = "verifyMemberListContains only supports the \"symbol\" parameter"; - } - const members = this.getMemberListAtCaret(); if (members) { this.assertItemInCompletionList(members.entries, symbol, text, documentation, kind); @@ -565,18 +525,9 @@ namespace FourSlash { } public verifyMemberListCount(expectedCount: number, negative: boolean) { - if (expectedCount === 0) { - if (negative) { - this.verifyMemberListIsEmpty(/*negative*/ false); - return; - } - else { - this.scenarioActions.push(""); - } - } - else { - this.scenarioActions.push(""); - this.scenarioActions.push(``); + if (expectedCount === 0 && negative) { + this.verifyMemberListIsEmpty(/*negative*/ false); + return; } const members = this.getMemberListAtCaret(); @@ -594,9 +545,6 @@ namespace FourSlash { } public verifyMemberListDoesNotContain(symbol: string) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); - const members = this.getMemberListAtCaret(); if (members && members.entries.filter(e => e.name === symbol).length !== 0) { this.raiseError(`Member list did contain ${symbol}`); @@ -604,8 +552,6 @@ namespace FourSlash { } public verifyCompletionListItemsCountIsGreaterThan(count: number, negative: boolean) { - this.taoInvalidReason = "verifyCompletionListItemsCountIsGreaterThan NYI"; - const completions = this.getCompletionListAtCaret(); const itemsCount = completions.entries.length; @@ -622,13 +568,6 @@ namespace FourSlash { } public verifyMemberListIsEmpty(negative: boolean) { - if (negative) { - this.scenarioActions.push(""); - } - else { - this.scenarioActions.push(""); - } - const members = this.getMemberListAtCaret(); if ((!members || members.entries.length === 0) && negative) { this.raiseError("Member list is empty at Caret"); @@ -647,8 +586,6 @@ namespace FourSlash { } public verifyCompletionListIsEmpty(negative: boolean) { - this.scenarioActions.push(""); - const completions = this.getCompletionListAtCaret(); if ((!completions || completions.entries.length === 0) && negative) { this.raiseError("Completion list is empty at caret at position " + this.activeFile.fileName + " " + this.currentCaretPosition); @@ -716,8 +653,6 @@ namespace FourSlash { // and keep it in the list of filtered entry. return true; } - this.scenarioActions.push(""); - this.scenarioActions.push(``); const completions = this.getCompletionListAtCaret(); if (completions) { @@ -745,24 +680,20 @@ namespace FourSlash { } public verifyCompletionEntryDetails(entryName: string, expectedText: string, expectedDocumentation?: string, kind?: string) { - this.taoInvalidReason = "verifyCompletionEntryDetails NYI"; - const details = this.getCompletionEntryDetails(entryName); - assert.equal(ts.displayPartsToString(details.displayParts), expectedText, assertionMessage("completion entry details text")); + assert.equal(ts.displayPartsToString(details.displayParts), expectedText, this.assertionMessageAtLastKnownMarker("completion entry details text")); if (expectedDocumentation !== undefined) { - assert.equal(ts.displayPartsToString(details.documentation), expectedDocumentation, assertionMessage("completion entry documentation")); + assert.equal(ts.displayPartsToString(details.documentation), expectedDocumentation, this.assertionMessageAtLastKnownMarker("completion entry documentation")); } if (kind !== undefined) { - assert.equal(details.kind, kind, assertionMessage("completion entry kind")); + assert.equal(details.kind, kind, this.assertionMessageAtLastKnownMarker("completion entry kind")); } } public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) { - this.taoInvalidReason = "verifyReferencesAtPositionListContains NYI"; - const references = this.getReferencesAtCaret(); if (!references || references.length === 0) { @@ -784,8 +715,6 @@ namespace FourSlash { } public verifyReferencesCountIs(count: number, localFilesOnly = true) { - this.taoInvalidReason = "verifyReferences NYI"; - const references = this.getReferencesAtCaret(); let referencesCount = 0; @@ -845,13 +774,6 @@ namespace FourSlash { } public verifyQuickInfoString(negative: boolean, expectedText?: string, expectedDocumentation?: string) { - [expectedText, expectedDocumentation].forEach(str => { - if (str) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); - } - }); - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : ""; const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : ""; @@ -871,7 +793,7 @@ namespace FourSlash { } // TODO: should be '==='? if (expectedDocumentation != undefined) { - assert.equal(actualQuickInfoDocumentation, expectedDocumentation, assertionMessage("quick info doc")); + assert.equal(actualQuickInfoDocumentation, expectedDocumentation, this.assertionMessageAtLastKnownMarker("quick info doc")); } } } @@ -879,8 +801,6 @@ namespace FourSlash { public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; }, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); function getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) { let result = ""; @@ -947,8 +867,6 @@ namespace FourSlash { } public verifyQuickInfoExists(negative: boolean) { - this.taoInvalidReason = "verifyQuickInfoExists NYI"; - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (negative) { if (actualQuickInfo) { @@ -963,8 +881,6 @@ namespace FourSlash { } public verifyCurrentSignatureHelpIs(expected: string) { - this.taoInvalidReason = "verifyCurrentSignatureHelpIs NYI"; - const help = this.getActiveSignatureHelpItem(); assert.equal( ts.displayPartsToString(help.prefixDisplayParts) + @@ -973,75 +889,51 @@ namespace FourSlash { } public verifyCurrentParameterIsletiable(isVariable: boolean) { - this.taoInvalidReason = "verifyCurrentParameterIsletiable NYI"; - const signature = this.getActiveSignatureHelpItem(); assert.isNotNull(signature); assert.equal(isVariable, signature.isVariadic); } public verifyCurrentParameterHelpName(name: string) { - this.taoInvalidReason = "verifyCurrentParameterHelpName NYI"; - const activeParameter = this.getActiveParameter(); const activeParameterName = activeParameter.name; assert.equal(activeParameterName, name); } public verifyCurrentParameterSpanIs(parameter: string) { - this.taoInvalidReason = "verifyCurrentParameterSpanIs NYI"; - const activeSignature = this.getActiveSignatureHelpItem(); const activeParameter = this.getActiveParameter(); assert.equal(ts.displayPartsToString(activeParameter.displayParts), parameter); } public verifyCurrentParameterHelpDocComment(docComment: string) { - this.taoInvalidReason = "verifyCurrentParameterHelpDocComment NYI"; - const activeParameter = this.getActiveParameter(); const activeParameterDocComment = activeParameter.documentation; - assert.equal(ts.displayPartsToString(activeParameterDocComment), docComment, assertionMessage("current parameter Help DocComment")); + assert.equal(ts.displayPartsToString(activeParameterDocComment), docComment, this.assertionMessageAtLastKnownMarker("current parameter Help DocComment")); } public verifyCurrentSignatureHelpParameterCount(expectedCount: number) { - this.taoInvalidReason = "verifyCurrentSignatureHelpParameterCount NYI"; - assert.equal(this.getActiveSignatureHelpItem().parameters.length, expectedCount); } - public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) { - this.taoInvalidReason = "verifyCurrentSignatureHelpTypeParameterCount NYI"; - - // assert.equal(this.getActiveSignatureHelpItem().typeParameters.length, expectedCount); - } - public verifyCurrentSignatureHelpDocComment(docComment: string) { - this.taoInvalidReason = "verifyCurrentSignatureHelpDocComment NYI"; - const actualDocComment = this.getActiveSignatureHelpItem().documentation; - assert.equal(ts.displayPartsToString(actualDocComment), docComment, assertionMessage("current signature help doc comment")); + assert.equal(ts.displayPartsToString(actualDocComment), docComment, this.assertionMessageAtLastKnownMarker("current signature help doc comment")); } public verifySignatureHelpCount(expected: number) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); - const help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); const actual = help && help.items ? help.items.length : 0; assert.equal(actual, expected); } public verifySignatureHelpArgumentCount(expected: number) { - this.taoInvalidReason = "verifySignatureHelpArgumentCount NYI"; const signatureHelpItems = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); const actual = signatureHelpItems.argumentCount; assert.equal(actual, expected); } public verifySignatureHelpPresent(shouldBePresent = true) { - this.taoInvalidReason = "verifySignatureHelpPresent NYI"; - const actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); if (shouldBePresent) { if (!actual) { @@ -1184,13 +1076,10 @@ namespace FourSlash { } public getBreakpointStatementLocation(pos: number) { - this.taoInvalidReason = "getBreakpointStatementLocation NYI"; return this.languageService.getBreakpointStatementAtPosition(this.activeFile.fileName, pos); } public baselineCurrentFileBreakpointLocations() { - this.taoInvalidReason = "baselineCurrentFileBreakpointLocations impossible"; - Harness.Baseline.runBaseline( "Breakpoint Locations for " + this.activeFile.fileName, this.testData.globalOptions[metadataOptionNames.baselineFile], @@ -1201,7 +1090,6 @@ namespace FourSlash { } public baselineGetEmitOutput() { - this.taoInvalidReason = "baselineGetEmitOutput impossible"; // Find file to be emitted const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on @@ -1327,8 +1215,6 @@ namespace FourSlash { } public deleteChar(count = 1) { - this.scenarioActions.push(``); - let offset = this.currentCaretPosition; const ch = ""; @@ -1340,7 +1226,7 @@ namespace FourSlash { this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch); if (i % checkCadence === 0) { - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } // Handle post-keystroke formatting @@ -1357,20 +1243,16 @@ namespace FourSlash { this.currentCaretPosition = offset; this.fixCaretPosition(); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } public replace(start: number, length: number, text: string) { - this.taoInvalidReason = "replace NYI"; - this.languageServiceAdapterHost.editScript(this.activeFile.fileName, start, start + length, text); this.updateMarkersForEdit(this.activeFile.fileName, start, start + length, text); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } public deleteCharBehindMarker(count = 1) { - this.scenarioActions.push(``); - let offset = this.currentCaretPosition; const ch = ""; const checkCadence = (count >> 2) + 1; @@ -1382,7 +1264,7 @@ namespace FourSlash { this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch); if (i % checkCadence === 0) { - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } // Handle post-keystroke formatting @@ -1398,18 +1280,11 @@ namespace FourSlash { this.currentCaretPosition = offset; this.fixCaretPosition(); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } // Enters lines of text at the current caret position public type(text: string) { - if (text === "") { - this.taoInvalidReason = "Test used empty-insert workaround."; - } - else { - this.scenarioActions.push(``); - } - return this.typeHighFidelity(text); } @@ -1440,7 +1315,7 @@ namespace FourSlash { } if (i % checkCadence === 0) { - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); // this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); // this.languageService.getSemanticDiagnostics(this.activeFile.fileName); } @@ -1459,18 +1334,16 @@ namespace FourSlash { this.currentCaretPosition = offset; this.fixCaretPosition(); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } // Enters text as if the user had pasted it public paste(text: string) { - this.scenarioActions.push(``); - const start = this.currentCaretPosition; let offset = this.currentCaretPosition; this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, text); this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, text); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); offset += text.length; // Handle formatting @@ -1478,7 +1351,7 @@ namespace FourSlash { const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); if (edits.length) { offset += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } } @@ -1486,10 +1359,10 @@ namespace FourSlash { this.currentCaretPosition = offset; this.fixCaretPosition(); - this.checkPostEditInletiants(); + this.checkPostEditInvariants(); } - private checkPostEditInletiants() { + private checkPostEditInvariants() { if (this.testType !== FourSlashTestType.Native) { // getSourcefile() results can not be serialized. Only perform these verifications // if running against a native LS object. @@ -1560,16 +1433,12 @@ namespace FourSlash { } public formatDocument() { - this.scenarioActions.push(""); - const edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions); this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); } public formatSelection(start: number, end: number) { - this.taoInvalidReason = "formatSelection NYI"; - const edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, end, this.formatCodeOptions); this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, /*isFormattingEdit*/ true); this.fixCaretPosition(); @@ -1603,13 +1472,6 @@ namespace FourSlash { } public goToDefinition(definitionIndex: number) { - if (definitionIndex === 0) { - this.scenarioActions.push(""); - } - else { - this.taoInvalidReason = "GoToDefinition not supported for non-zero definition indices"; - } - const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (!definitions || !definitions.length) { this.raiseError("goToDefinition failed - expected to at least one definition location but got 0"); @@ -1625,13 +1487,6 @@ namespace FourSlash { } public goToTypeDefinition(definitionIndex: number) { - if (definitionIndex === 0) { - this.scenarioActions.push(""); - } - else { - this.taoInvalidReason = "GoToTypeDefinition not supported for non-zero definition indices"; - } - const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (!definitions || !definitions.length) { this.raiseError("goToTypeDefinition failed - expected to at least one definition location but got 0"); @@ -1647,8 +1502,6 @@ namespace FourSlash { } public verifyDefinitionLocationExists(negative: boolean) { - this.taoInvalidReason = "verifyDefinitionLocationExists NYI"; - const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); const foundDefinitions = definitions && definitions.length; @@ -1680,8 +1533,6 @@ namespace FourSlash { } public verifyDefinitionsName(negative: boolean, expectedName: string, expectedContainerName: string) { - this.taoInvalidReason = "verifyDefinititionsInfo NYI"; - const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); const actualDefinitionName = definitions && definitions.length ? definitions[0].name : ""; const actualDefinitionContainerName = definitions && definitions.length ? definitions[0].containerName : ""; @@ -1706,8 +1557,6 @@ namespace FourSlash { } public verifyCaretAtMarker(markerName = "") { - this.taoInvalidReason = "verifyCaretAtMarker NYI"; - const pos = this.getMarkerByName(markerName); if (pos.fileName !== this.activeFile.fileName) { throw new Error(`verifyCaretAtMarker failed - expected to be in file "${pos.fileName}", but was in file "${this.activeFile.fileName}"`); @@ -1726,8 +1575,6 @@ namespace FourSlash { } public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) { - this.taoInvalidReason = "verifyIndentationAtCurrentPosition NYI"; - const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle); const lineCol = this.getLineColStringAtPosition(this.currentCaretPosition); if (actual !== numberOfSpaces) { @@ -1736,8 +1583,6 @@ namespace FourSlash { } public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) { - this.taoInvalidReason = "verifyIndentationAtPosition NYI"; - const actual = this.getIndentation(fileName, position, indentStyle); const lineCol = this.getLineColStringAtPosition(position); if (actual !== numberOfSpaces) { @@ -1746,8 +1591,6 @@ namespace FourSlash { } public verifyCurrentLineContent(text: string) { - this.taoInvalidReason = "verifyCurrentLineContent NYI"; - const actual = this.getCurrentLineContent(); if (actual !== text) { throw new Error("verifyCurrentLineContent\n" + @@ -1757,8 +1600,6 @@ namespace FourSlash { } public verifyCurrentFileContent(text: string) { - this.taoInvalidReason = "verifyCurrentFileContent NYI"; - const actual = this.getFileContent(this.activeFile.fileName); const replaceNewlines = (str: string) => str.replace(/\r\n/g, "\n"); if (replaceNewlines(actual) !== replaceNewlines(text)) { @@ -1769,8 +1610,6 @@ namespace FourSlash { } public verifyTextAtCaretIs(text: string) { - this.taoInvalidReason = "verifyCurrentFileContent NYI"; - const actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length); if (actual !== text) { throw new Error("verifyTextAtCaretIs\n" + @@ -1780,8 +1619,6 @@ namespace FourSlash { } public verifyCurrentNameOrDottedNameSpanText(text: string) { - this.taoInvalidReason = "verifyCurrentNameOrDottedNameSpanText NYI"; - const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition); if (!span) { this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + @@ -1798,13 +1635,10 @@ namespace FourSlash { } private getNameOrDottedNameSpan(pos: number) { - this.taoInvalidReason = "getNameOrDottedNameSpan NYI"; return this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, pos, pos); } public baselineCurrentFileNameOrDottedNameSpans() { - this.taoInvalidReason = "baselineCurrentFileNameOrDottedNameSpans impossible"; - Harness.Baseline.runBaseline( "Name OrDottedNameSpans for " + this.activeFile.fileName, this.testData.globalOptions[metadataOptionNames.baselineFile], @@ -1898,8 +1732,6 @@ namespace FourSlash { } public verifyOutliningSpans(spans: TextSpan[]) { - this.taoInvalidReason = "verifyOutliningSpans NYI"; - const actual = this.languageService.getOutliningSpans(this.activeFile.fileName); if (actual.length !== spans.length) { @@ -1968,8 +1800,6 @@ namespace FourSlash { } public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) { - this.taoInvalidReason = "verifyMatchingBracePosition NYI"; - const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition); if (actual.length !== 2) { @@ -1993,8 +1823,6 @@ namespace FourSlash { } public verifyNoMatchingBracePosition(bracePosition: number) { - this.taoInvalidReason = "verifyNoMatchingBracePosition NYI"; - const actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition); if (actual.length !== 0) { @@ -2007,8 +1835,6 @@ namespace FourSlash { Report an error if expected value and actual value do not match. */ public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string) { - this.taoInvalidReason = "verifyNavigationItemsCount NYI"; - const items = this.languageService.getNavigateToItems(searchValue); let actual = 0; let item: ts.NavigateToItem = null; @@ -2037,8 +1863,6 @@ namespace FourSlash { matchKind: string, fileName?: string, parentName?: string) { - this.taoInvalidReason = "verifyNavigationItemsListContains NYI"; - const items = this.languageService.getNavigateToItems(searchValue); if (!items || items.length === 0) { @@ -2063,8 +1887,6 @@ namespace FourSlash { } public verifyGetScriptLexicalStructureListCount(expected: number) { - this.taoInvalidReason = "verifyNavigationItemsListContains impossible"; - const items = this.languageService.getNavigationBarItems(this.activeFile.fileName); const actual = this.getNavigationBarItemsCount(items); @@ -2086,8 +1908,6 @@ namespace FourSlash { } public verifyGetScriptLexicalStructureListContains(name: string, kind: string) { - this.taoInvalidReason = "verifyGetScriptLexicalStructureListContains impossible"; - const items = this.languageService.getNavigationBarItems(this.activeFile.fileName); if (!items || items.length === 0) { @@ -2148,8 +1968,6 @@ namespace FourSlash { } public verifyOccurrencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) { - this.taoInvalidReason = "verifyOccurrencesAtPositionListContains NYI"; - const occurrences = this.getOccurrencesAtCurrentPosition(); if (!occurrences || occurrences.length === 0) { @@ -2170,8 +1988,6 @@ namespace FourSlash { } public verifyOccurrencesAtPositionListCount(expectedCount: number) { - this.taoInvalidReason = "verifyOccurrencesAtPositionListCount NYI"; - const occurrences = this.getOccurrencesAtCurrentPosition(); const actualCount = occurrences ? occurrences.length : 0; if (expectedCount !== actualCount) { @@ -2185,8 +2001,6 @@ namespace FourSlash { } public verifyDocumentHighlightsAtPositionListContains(fileName: string, start: number, end: number, fileNamesToSearch: string[], kind?: string) { - this.taoInvalidReason = "verifyDocumentHighlightsAtPositionListContains NYI"; - const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); if (!documentHighlights || documentHighlights.length === 0) { @@ -2213,8 +2027,6 @@ namespace FourSlash { } public verifyDocumentHighlightsAtPositionListCount(expectedCount: number, fileNamesToSearch: string[]) { - this.taoInvalidReason = "verifyDocumentHighlightsAtPositionListCount NYI"; - const documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); const actualCount = documentHighlights ? documentHighlights.reduce((currentCount, { highlightSpans }) => currentCount + highlightSpans.length, 0) @@ -2255,13 +2067,6 @@ namespace FourSlash { } private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, text?: string, documentation?: string, kind?: string) { - this.scenarioActions.push(""); - this.scenarioActions.push(``); - - if (text || documentation || kind) { - this.taoInvalidReason = "assertItemInCompletionList only supports the \"name\" parameter"; - } - for (let i = 0; i < items.length; i++) { const item = items[i]; if (item.name === name) { @@ -2269,15 +2074,15 @@ namespace FourSlash { const details = this.getCompletionEntryDetails(item.name); if (documentation !== undefined) { - assert.equal(ts.displayPartsToString(details.documentation), documentation, assertionMessage("completion item documentation for " + name)); + assert.equal(ts.displayPartsToString(details.documentation), documentation, this.assertionMessageAtLastKnownMarker("completion item documentation for " + name)); } if (text !== undefined) { - assert.equal(ts.displayPartsToString(details.displayParts), text, assertionMessage("completion item detail text for " + name)); + assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + name)); } } if (kind !== undefined) { - assert.equal(item.kind, kind, assertionMessage("completion item kind for " + name)); + assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + name)); } return; @@ -2352,14 +2157,6 @@ namespace FourSlash { return text.replace(/ /g, "\u00B7").replace(/\r/g, "\u00B6").replace(/\n/g, "\u2193\n").replace(/\t/g, "\u2192\ "); } - public getTestXmlData(): TestXmlData { - return { - actions: this.scenarioActions, - invalidReason: this.taoInvalidReason, - originalName: "" - }; - } - public setCancelled(numberOfCalls: number): void { this.cancellationToken.setCancelled(numberOfCalls); } @@ -2372,11 +2169,9 @@ namespace FourSlash { // TOOD: should these just use the Harness's stdout/stderr? const fsOutput = new Harness.Compiler.WriterAggregator(); const fsErrors = new Harness.Compiler.WriterAggregator(); - export let xmlData: TestXmlData[] = []; export function runFourSlashTest(basePath: string, testType: FourSlashTestType, fileName: string) { const content = Harness.IO.readFile(fileName); - const xml = runFourSlashTestContent(basePath, testType, content, fileName); - xmlData.push(xml); + runFourSlashTestContent(basePath, testType, content, fileName); } // We don't want to recompile 'fourslash.ts' for every test, so @@ -2398,7 +2193,8 @@ namespace FourSlash { program.emit(host.getSourceFile(Harness.Compiler.fourslashFileName, ts.ScriptTarget.ES3)); } - export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): TestXmlData { + export let currentTestState: TestState; + export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void { // Parse out the files and their metadata const testData = parseTestData(basePath, content, fileName); @@ -2437,10 +2233,6 @@ namespace FourSlash { result = fourslashJsOutput + "\r\n" + result; runCode(result); - - const xmlData = currentTestState.getTestXmlData(); - xmlData.originalName = fileName; - return xmlData; } function runCode(code: string): void { @@ -2619,7 +2411,7 @@ namespace FourSlash { throw new Error(errorMessage); } - function recordObjectMarker(fileName: string, location: ILocationInformation, text: string, markerMap: MarkerMap, markers: Marker[]): Marker { + function recordObjectMarker(fileName: string, location: LocationInformation, text: string, markerMap: MarkerMap, markers: Marker[]): Marker { let markerValue: any = undefined; try { // Attempt to parse the marker value as JSON @@ -2650,7 +2442,7 @@ namespace FourSlash { return marker; } - function recordMarker(fileName: string, location: ILocationInformation, name: string, markerMap: MarkerMap, markers: Marker[]): Marker { + function recordMarker(fileName: string, location: LocationInformation, name: string, markerMap: MarkerMap, markers: Marker[]): Marker { const marker: Marker = { fileName: fileName, position: location.position @@ -2679,10 +2471,10 @@ namespace FourSlash { let output = ""; /// The current marker (or maybe multi-line comment?) we're parsing, possibly - let openMarker: ILocationInformation = null; + let openMarker: LocationInformation = null; /// A stack of the open range markers that are still unclosed - const openRanges: IRangeLocationInformation[] = []; + const openRanges: RangeLocationInformation[] = []; /// A list of ranges we've collected so far */ let localRanges: Range[] = []; diff --git a/src/harness/fourslashRunner.ts b/src/harness/fourslashRunner.ts index 7228f06c20f..84e352359c4 100644 --- a/src/harness/fourslashRunner.ts +++ b/src/harness/fourslashRunner.ts @@ -58,56 +58,6 @@ class FourSlashRunner extends RunnerBase { } }); }); - - describe("Generate Tao XML", () => { - const invalidReasons: any = {}; - FourSlash.xmlData.forEach(xml => { - if (xml.invalidReason !== null) { - invalidReasons[xml.invalidReason] = (invalidReasons[xml.invalidReason] || 0) + 1; - } - }); - const invalidReport: { reason: string; count: number }[] = []; - for (const reason in invalidReasons) { - if (invalidReasons.hasOwnProperty(reason)) { - invalidReport.push({ reason: reason, count: invalidReasons[reason] }); - } - } - invalidReport.sort((lhs, rhs) => lhs.count > rhs.count ? -1 : lhs.count === rhs.count ? 0 : 1); - - const lines: string[] = []; - lines.push(""); - lines.push(""); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - FourSlash.xmlData.forEach(xml => { - if (xml.invalidReason !== null) { - lines.push(""); - } - else { - lines.push(" "); - xml.actions.forEach(action => { - lines.push(" " + action); - }); - lines.push(" "); - } - }); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(" "); - lines.push(""); - Harness.IO.writeFile("built/local/fourslash.xml", lines.join("\r\n")); - }); }); } } From 31bce223d98ed976542c4d2cd654618f10cdfb9c Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 11:50:42 -0800 Subject: [PATCH 24/35] switch fourslash to use local test state --- src/harness/fourslash.ts | 669 ++++++++++++- ...foreSemanticDiagnosticsInArrowFunction1.ts | 12 +- tests/cases/fourslash/fourslash.ts | 902 +++++------------- tests/cases/fourslash/indentationBlock.ts | 2 +- tests/cases/fourslash/indentationNone.ts | 2 +- .../fourslash/recursiveClassReference.ts | 2 +- tests/cases/fourslash/renameModuleToVar.ts | 8 +- 7 files changed, 909 insertions(+), 688 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 88458beaba4..5f48a885395 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2174,31 +2174,11 @@ namespace FourSlash { runFourSlashTestContent(basePath, testType, content, fileName); } - // We don't want to recompile 'fourslash.ts' for every test, so - // here we cache the JS output and reuse it for every test. - let fourslashJsOutput: string; - { - const fourslashFile: Harness.Compiler.TestFile = { - unitName: Harness.Compiler.fourslashFileName, - content: undefined - }; - const host = Harness.Compiler.createCompilerHost([fourslashFile], - (fn, contents) => fourslashJsOutput = contents, - ts.ScriptTarget.Latest, - Harness.IO.useCaseSensitiveFileNames(), - Harness.IO.getCurrentDirectory()); - - const program = ts.createProgram([Harness.Compiler.fourslashFileName], { noResolve: true, target: ts.ScriptTarget.ES3 }, host); - - program.emit(host.getSourceFile(Harness.Compiler.fourslashFileName, ts.ScriptTarget.ES3)); - } - - export let currentTestState: TestState; export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void { // Parse out the files and their metadata const testData = parseTestData(basePath, content, fileName); - currentTestState = new TestState(basePath, testType, testData); + const state = new TestState(basePath, testType, testData); let result = ""; const fourslashFile: Harness.Compiler.TestFile = { @@ -2228,17 +2208,27 @@ namespace FourSlash { } program.emit(sourceFile); - result = result || ""; // Might have an empty fourslash file - result = fourslashJsOutput + "\r\n" + result; - - runCode(result); + ts.Debug.assert(!!result); + runCode(result, state); } - function runCode(code: string): void { + function runCode(code: string, state: TestState): void { // Compile and execute the test + const wrappedCode = +`(function(test, goTo, verify, edit, debug, format, cancellation, classification, verifyOperationIsCancelled) { +${code} +})`; try { - eval(code); + const test = new FourSlashInterface.Test(state); + const goTo = new FourSlashInterface.GoTo(state); + const verify = new FourSlashInterface.Verify(state); + const edit = new FourSlashInterface.Edit(state); + const debug = new FourSlashInterface.Debug(state); + const format = new FourSlashInterface.Format(state); + const cancellation = new FourSlashInterface.Cancellation(state); + const f = eval(wrappedCode); + f(test, goTo, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlash.verifyOperationIsCancelled); } catch (err) { // Debugging: FourSlash.currentTestState.printCurrentFileState(); @@ -2660,3 +2650,628 @@ namespace FourSlash { }; } } + +namespace FourSlashInterface { + export class Test { + constructor(private state: FourSlash.TestState) { + } + + public markers(): FourSlash.Marker[] { + return this.state.getMarkers(); + } + + public marker(name?: string): FourSlash.Marker { + return this.state.getMarkerByName(name); + } + + public ranges(): FourSlash.Range[] { + return this.state.getRanges(); + } + + public markerByName(s: string): FourSlash.Marker { + return this.state.getMarkerByName(s); + } + } + + export class GoTo { + constructor(private state: FourSlash.TestState) { + } + // Moves the caret to the specified marker, + // or the anonymous marker ('/**/') if no name + // is given + public marker(name?: string) { + this.state.goToMarker(name); + } + + public bof() { + this.state.goToBOF(); + } + + public eof() { + this.state.goToEOF(); + } + + public definition(definitionIndex = 0) { + this.state.goToDefinition(definitionIndex); + } + + public type(definitionIndex = 0) { + this.state.goToTypeDefinition(definitionIndex); + } + + public position(position: number, fileIndex?: number): void; + public position(position: number, fileName?: string): void; + public position(position: number, fileNameOrIndex?: any): void { + if (fileNameOrIndex !== undefined) { + this.file(fileNameOrIndex); + } + this.state.goToPosition(position); + } + + // Opens a file, given either its index as it + // appears in the test source, or its filename + // as specified in the test metadata + public file(index: number, content?: string): void; + public file(name: string, content?: string): void; + public file(indexOrName: any, content?: string): void { + this.state.openFile(indexOrName, content); + } + } + + export class VerifyNegatable { + public not: VerifyNegatable; + + constructor(protected state: FourSlash.TestState, private negative = false) { + if (!negative) { + this.not = new VerifyNegatable(state, true); + } + } + + // Verifies the member list contains the specified symbol. The + // member list is brought up if necessary + public memberListContains(symbol: string, text?: string, documenation?: string, kind?: string) { + if (this.negative) { + this.state.verifyMemberListDoesNotContain(symbol); + } + else { + this.state.verifyMemberListContains(symbol, text, documenation, kind); + } + } + + public memberListCount(expectedCount: number) { + this.state.verifyMemberListCount(expectedCount, this.negative); + } + + // Verifies the completion list contains the specified symbol. The + // completion list is brought up if necessary + public completionListContains(symbol: string, text?: string, documentation?: string, kind?: string) { + if (this.negative) { + this.state.verifyCompletionListDoesNotContain(symbol, text, documentation, kind); + } + else { + this.state.verifyCompletionListContains(symbol, text, documentation, kind); + } + } + + // Verifies the completion list items count to be greater than the specified amount. The + // completion list is brought up if necessary + public completionListItemsCountIsGreaterThan(count: number) { + this.state.verifyCompletionListItemsCountIsGreaterThan(count, this.negative); + } + + public completionListIsEmpty() { + this.state.verifyCompletionListIsEmpty(this.negative); + } + + public completionListAllowsNewIdentifier() { + this.state.verifyCompletionListAllowsNewIdentifier(this.negative); + } + + public memberListIsEmpty() { + this.state.verifyMemberListIsEmpty(this.negative); + } + + public referencesCountIs(count: number) { + this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false); + } + + public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) { + this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess); + } + + public signatureHelpPresent() { + this.state.verifySignatureHelpPresent(!this.negative); + } + + public errorExistsBetweenMarkers(startMarker: string, endMarker: string) { + this.state.verifyErrorExistsBetweenMarkers(startMarker, endMarker, !this.negative); + } + + public errorExistsAfterMarker(markerName = "") { + this.state.verifyErrorExistsAfterMarker(markerName, !this.negative, /*after*/ true); + } + + public errorExistsBeforeMarker(markerName = "") { + this.state.verifyErrorExistsAfterMarker(markerName, !this.negative, /*after*/ false); + } + + public quickInfoIs(expectedText?: string, expectedDocumentation?: string) { + this.state.verifyQuickInfoString(this.negative, expectedText, expectedDocumentation); + } + + public quickInfoExists() { + this.state.verifyQuickInfoExists(this.negative); + } + + public definitionCountIs(expectedCount: number) { + this.state.verifyDefinitionsCount(this.negative, expectedCount); + } + + public typeDefinitionCountIs(expectedCount: number) { + this.state.verifyTypeDefinitionsCount(this.negative, expectedCount); + } + + public definitionLocationExists() { + this.state.verifyDefinitionLocationExists(this.negative); + } + + public verifyDefinitionsName(name: string, containerName: string) { + this.state.verifyDefinitionsName(this.negative, name, containerName); + } + } + + export class Verify extends VerifyNegatable { + constructor(state: FourSlash.TestState) { + super(state); + } + + public caretAtMarker(markerName?: string) { + this.state.verifyCaretAtMarker(markerName); + } + + public indentationIs(numberOfSpaces: number) { + this.state.verifyIndentationAtCurrentPosition(numberOfSpaces); + } + + public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart) { + this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle); + } + + public textAtCaretIs(text: string) { + this.state.verifyTextAtCaretIs(text); + } + + /** + * Compiles the current file and evaluates 'expr' in a context containing + * the emitted output, then compares (using ===) the result of that expression + * to 'value'. Do not use this function with external modules as it is not supported. + */ + public eval(expr: string, value: any) { + this.state.verifyEval(expr, value); + } + + public currentLineContentIs(text: string) { + this.state.verifyCurrentLineContent(text); + } + + public currentFileContentIs(text: string) { + this.state.verifyCurrentFileContent(text); + } + + public verifyGetEmitOutputForCurrentFile(expected: string): void { + this.state.verifyGetEmitOutputForCurrentFile(expected); + } + + public currentParameterHelpArgumentNameIs(name: string) { + this.state.verifyCurrentParameterHelpName(name); + } + + public currentParameterSpanIs(parameter: string) { + this.state.verifyCurrentParameterSpanIs(parameter); + } + + public currentParameterHelpArgumentDocCommentIs(docComment: string) { + this.state.verifyCurrentParameterHelpDocComment(docComment); + } + + public currentSignatureHelpDocCommentIs(docComment: string) { + this.state.verifyCurrentSignatureHelpDocComment(docComment); + } + + public signatureHelpCountIs(expected: number) { + this.state.verifySignatureHelpCount(expected); + } + + public signatureHelpArgumentCountIs(expected: number) { + this.state.verifySignatureHelpArgumentCount(expected); + } + + public currentSignatureParameterCountIs(expected: number) { + this.state.verifyCurrentSignatureHelpParameterCount(expected); + } + + public currentSignatureHelpIs(expected: string) { + this.state.verifyCurrentSignatureHelpIs(expected); + } + + public numberOfErrorsInCurrentFile(expected: number) { + this.state.verifyNumberOfErrorsInCurrentFile(expected); + } + + public baselineCurrentFileBreakpointLocations() { + this.state.baselineCurrentFileBreakpointLocations(); + } + + public baselineCurrentFileNameOrDottedNameSpans() { + this.state.baselineCurrentFileNameOrDottedNameSpans(); + } + + public baselineGetEmitOutput() { + this.state.baselineGetEmitOutput(); + } + + public nameOrDottedNameSpanTextIs(text: string) { + this.state.verifyCurrentNameOrDottedNameSpanText(text); + } + + public outliningSpansInCurrentFile(spans: FourSlash.TextSpan[]) { + this.state.verifyOutliningSpans(spans); + } + + public todoCommentsInCurrentFile(descriptors: string[]) { + this.state.verifyTodoComments(descriptors, this.state.getRanges()); + } + + public matchingBracePositionInCurrentFile(bracePosition: number, expectedMatchPosition: number) { + this.state.verifyMatchingBracePosition(bracePosition, expectedMatchPosition); + } + + public noMatchingBracePositionInCurrentFile(bracePosition: number) { + this.state.verifyNoMatchingBracePosition(bracePosition); + } + + public DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean) { + this.state.verifyDocCommentTemplate(empty ? undefined : { newText: expectedText, caretOffset: expectedOffset }); + } + + public noDocCommentTemplate() { + this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true); + } + + public getScriptLexicalStructureListCount(count: number) { + this.state.verifyGetScriptLexicalStructureListCount(count); + } + + // TODO: figure out what to do with the unused arguments. + public getScriptLexicalStructureListContains( + name: string, + kind: string, + fileName?: string, + parentName?: string, + isAdditionalSpan?: boolean, + markerPosition?: number) { + this.state.verifyGetScriptLexicalStructureListContains(name, kind); + } + + public navigationItemsListCount(count: number, searchValue: string, matchKind?: string) { + this.state.verifyNavigationItemsCount(count, searchValue, matchKind); + } + + public navigationItemsListContains( + name: string, + kind: string, + searchValue: string, + matchKind: string, + fileName?: string, + parentName?: string) { + this.state.verifyNavigationItemsListContains( + name, + kind, + searchValue, + matchKind, + fileName, + parentName); + } + + public occurrencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) { + this.state.verifyOccurrencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess); + } + + public occurrencesAtPositionCount(expectedCount: number) { + this.state.verifyOccurrencesAtPositionListCount(expectedCount); + } + + public documentHighlightsAtPositionContains(range: FourSlash.Range, fileNamesToSearch: string[], kind?: string) { + this.state.verifyDocumentHighlightsAtPositionListContains(range.fileName, range.start, range.end, fileNamesToSearch, kind); + } + + public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]) { + this.state.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); + } + + public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string) { + this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind); + } + + /** + * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. + */ + public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { + this.state.verifySyntacticClassifications(classifications); + } + + /** + * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. + */ + public semanticClassificationsAre(...classifications: { classificationType: string; text: string; textSpan?: FourSlash.TextSpan }[]) { + this.state.verifySemanticClassifications(classifications); + } + + public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) { + this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers); + } + + public renameInfoFailed(message?: string) { + this.state.verifyRenameInfoFailed(message); + } + + public renameLocations(findInStrings: boolean, findInComments: boolean) { + this.state.verifyRenameLocations(findInStrings, findInComments); + } + + public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; }, + displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]) { + this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation); + } + + public getSyntacticDiagnostics(expected: string) { + this.state.getSyntacticDiagnostics(expected); + } + + public getSemanticDiagnostics(expected: string) { + this.state.getSemanticDiagnostics(expected); + } + + public ProjectInfo(expected: string []) { + this.state.verifyProjectInfo(expected); + } + } + + export class Edit { + constructor(private state: FourSlash.TestState) { + } + public backspace(count?: number) { + this.state.deleteCharBehindMarker(count); + } + + public deleteAtCaret(times?: number) { + this.state.deleteChar(times); + } + + public replace(start: number, length: number, text: string) { + this.state.replace(start, length, text); + } + + public paste(text: string) { + this.state.paste(text); + } + + public insert(text: string) { + this.insertLines(text); + } + + public insertLine(text: string) { + this.insertLines(text + "\n"); + } + + public insertLines(...lines: string[]) { + this.state.type(lines.join("\n")); + } + + public moveRight(count?: number) { + this.state.moveCaretRight(count); + } + + public moveLeft(count?: number) { + if (typeof count === "undefined") { + count = 1; + } + this.state.moveCaretRight(count * -1); + } + + public enableFormatting() { + this.state.enableFormatting = true; + } + + public disableFormatting() { + this.state.enableFormatting = false; + } + } + + export class Debug { + constructor(private state: FourSlash.TestState) { + } + + public printCurrentParameterHelp() { + this.state.printCurrentParameterHelp(); + } + + public printCurrentFileState() { + this.state.printCurrentFileState(); + } + + public printCurrentFileStateWithWhitespace() { + this.state.printCurrentFileState(/*makeWhitespaceVisible*/true); + } + + public printCurrentFileStateWithoutCaret() { + this.state.printCurrentFileState(/*makeWhitespaceVisible*/false, /*makeCaretVisible*/false); + } + + public printCurrentQuickInfo() { + this.state.printCurrentQuickInfo(); + } + + public printCurrentSignatureHelp() { + this.state.printCurrentSignatureHelp(); + } + + public printMemberListMembers() { + this.state.printMemberListMembers(); + } + + public printCompletionListMembers() { + this.state.printCompletionListMembers(); + } + + public printBreakpointLocation(pos: number) { + this.state.printBreakpointLocation(pos); + } + public printBreakpointAtCurrentLocation() { + this.state.printBreakpointAtCurrentLocation(); + } + + public printNameOrDottedNameSpans(pos: number) { + this.state.printNameOrDottedNameSpans(pos); + } + + public printErrorList() { + this.state.printErrorList(); + } + + public printNavigationItems(searchValue = ".*") { + this.state.printNavigationItems(searchValue); + } + + public printScriptLexicalStructureItems() { + this.state.printScriptLexicalStructureItems(); + } + + public printReferences() { + this.state.printReferences(); + } + + public printContext() { + this.state.printContext(); + } + } + + export class Format { + constructor(private state: FourSlash.TestState) { + } + + public document() { + this.state.formatDocument(); + } + + public copyFormatOptions(): ts.FormatCodeOptions { + return this.state.copyFormatOptions(); + } + + public setFormatOptions(options: ts.FormatCodeOptions) { + return this.state.setFormatOptions(options); + } + + public selection(startMarker: string, endMarker: string) { + this.state.formatSelection(this.state.getMarkerByName(startMarker).position, this.state.getMarkerByName(endMarker).position); + } + + public setOption(name: string, value: number): void; + public setOption(name: string, value: string): void; + public setOption(name: string, value: boolean): void; + public setOption(name: string, value: any): void { + this.state.formatCodeOptions[name] = value; + } + } + + export class Cancellation { + constructor(private state: FourSlash.TestState) { + } + + public resetCancelled() { + this.state.resetCancelled(); + } + + public setCancelled(numberOfCalls = 0) { + this.state.setCancelled(numberOfCalls); + } + } + + export namespace Classification { + export function comment(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("comment", text, position); + } + + export function identifier(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("identifier", text, position); + } + + export function keyword(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("keyword", text, position); + } + + export function numericLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("numericLiteral", text, position); + } + + export function operator(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("operator", text, position); + } + + export function stringLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("stringLiteral", text, position); + } + + export function whiteSpace(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("whiteSpace", text, position); + } + + export function text(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("text", text, position); + } + + export function punctuation(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("punctuation", text, position); + } + + export function docCommentTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("docCommentTagName", text, position); + } + + export function className(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("className", text, position); + } + + export function enumName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("enumName", text, position); + } + + export function interfaceName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("interfaceName", text, position); + } + + export function moduleName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("moduleName", text, position); + } + + export function typeParameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("typeParameterName", text, position); + } + + export function parameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("parameterName", text, position); + } + + export function typeAliasName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } { + return getClassification("typeAliasName", text, position); + } + + function getClassification(type: string, text: string, position?: number) { + return { + classificationType: type, + text: text, + textSpan: position === undefined ? undefined : { start: position, end: position + text.length } + }; + } + } +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionBeforeSemanticDiagnosticsInArrowFunction1.ts b/tests/cases/fourslash/completionBeforeSemanticDiagnosticsInArrowFunction1.ts index 16d2efcd6d4..d66c1620751 100644 --- a/tests/cases/fourslash/completionBeforeSemanticDiagnosticsInArrowFunction1.ts +++ b/tests/cases/fourslash/completionBeforeSemanticDiagnosticsInArrowFunction1.ts @@ -3,16 +3,16 @@ //// var f4 = (x: T/**/ ) => { //// } -fs.goTo.marker(); +goTo.marker(); // Replace the "T" type with the non-existent type 'V'. -fs.edit.backspace(1); -fs.edit.insert("A"); +edit.backspace(1); +edit.insert("A"); // Bring up completion to force a pull resolve. This will end up resolving several symbols and // producing unreported diagnostics (i.e. that 'V' wasn't found). -fs.verify.completionListContains("T"); -fs.verify.completionEntryDetailIs("T", "(type parameter) T in (x: any): void"); +verify.completionListContains("T"); +verify.completionEntryDetailIs("T", "(type parameter) T in (x: any): void"); // There should now be a single error. -fs.verify.numberOfErrorsInCurrentFile(1); \ No newline at end of file +verify.numberOfErrorsInCurrentFile(1); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index f6451e1f1c4..5b8bb94bb48 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -24,10 +24,7 @@ // @Module: Node // @Target: ES5 -// In the imperative section, you can write any valid TypeScript code. If -// you need help finding a something in Intellisense, you can -// type 'fs.' as an alternate way of accessing the top-level objects -// (e.g. 'fs.goTo.eof();') +// In the imperative section, you can write any valid TypeScript code. //--------------------------------------- // For API editors: @@ -45,52 +42,32 @@ // // TODO: figure out a better solution to the API exposure problem. -// /// -// /// - -declare var FourSlash; -module ts { - export interface SymbolDisplayPart { +declare module ts { + interface SymbolDisplayPart { text: string; kind: string; } + + enum IndentStyle { + None = 0, + Block = 1, + Smart = 2, + } } -//--------------------------------------------- - -// Return code used by getEmitOutput function to indicate status of the function -// It is a duplicate of the one in types.ts to expose it to testcases in fourslash -enum EmitReturnStatus { - Succeeded = 0, // All outputs generated if requested (.js, .map, .d.ts), no errors reported - AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated - JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors - DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors - EmitErrorsEncountered = 4 // Emitter errors occurred during emitting process -} - -// This is a duplicate of the indentstyle in services.ts to expose it to testcases in fourslash -enum IndentStyle { - None, - Block, - Smart, -} - -module FourSlashInterface { - - export interface Marker { +declare module FourSlashInterface { + interface Marker { fileName: string; position: number; data?: any; } - - export interface EditorOptions { + interface EditorOptions { IndentSize: number; TabSize: number; NewLineCharacter: string; ConvertTabsToSpaces: boolean; } - - export interface FormatCodeOptions extends EditorOptions { + interface FormatCodeOptions extends EditorOptions { InsertSpaceAfterCommaDelimiter: boolean; InsertSpaceAfterSemicolonInForStatements: boolean; InsertSpaceBeforeAndAfterBinaryOperators: boolean; @@ -100,646 +77,275 @@ module FourSlashInterface { InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean; PlaceOpenBraceOnNewLineForFunctions: boolean; PlaceOpenBraceOnNewLineForControlBlocks: boolean; - [s: string]: boolean | number| string; + [s: string]: boolean | number | string; } - - export interface Range { + interface Range { fileName: string; start: number; end: number; marker?: Marker; } - - export interface TextSpan { + interface TextSpan { start: number; end: number; } - - export class test_ { - public markers(): Marker[] { - return FourSlash.currentTestState.getMarkers(); - } - - public marker(name?: string): Marker { - return FourSlash.currentTestState.getMarkerByName(name); - } - - public ranges(): Range[] { - return FourSlash.currentTestState.getRanges(); - } - - public markerByName(s: string): Marker { - return FourSlash.currentTestState.getMarkerByName(s); - } + class test_ { + markers(): Marker[]; + marker(name?: string): Marker; + ranges(): Range[]; + markerByName(s: string): Marker; } - - export class goTo { - // Moves the caret to the specified marker, - // or the anonymous marker ('/**/') if no name - // is given - public marker(name?: string) { - FourSlash.currentTestState.goToMarker(name); - } - - public bof() { - FourSlash.currentTestState.goToBOF(); - } - - public eof() { - FourSlash.currentTestState.goToEOF(); - } - - public definition(definitionIndex: number = 0) { - FourSlash.currentTestState.goToDefinition(definitionIndex); - } - - public type(definitionIndex: number = 0) { - FourSlash.currentTestState.goToTypeDefinition(definitionIndex); - } - - public position(position: number, fileIndex?: number); - public position(position: number, fileName?: string); - public position(position: number, fileNameOrIndex?: any) { - if (fileNameOrIndex !== undefined) { - this.file(fileNameOrIndex); - } - FourSlash.currentTestState.goToPosition(position); - } - - // Opens a file, given either its index as it - // appears in the test source, or its filename - // as specified in the test metadata - public file(index: number, content?: string); - public file(name: string, content?: string); - public file(indexOrName: any, content?: string) { - FourSlash.currentTestState.openFile(indexOrName, content); - } + class goTo { + marker(name?: string): void; + bof(): void; + eof(): void; + definition(definitionIndex?: number): void; + type(definitionIndex?: number): void; + position(position: number, fileIndex?: number): any; + position(position: number, fileName?: string): any; + file(index: number, content?: string): any; + file(name: string, content?: string): any; } - - export class verifyNegatable { - public not: verifyNegatable; - - constructor(private negative = false) { - if (!negative) { - this.not = new verifyNegatable(true); - } - } - - // Verifies the member list contains the specified symbol. The - // member list is brought up if necessary - public memberListContains(symbol: string, text?: string, documenation?: string, kind?: string) { - if (this.negative) { - FourSlash.currentTestState.verifyMemberListDoesNotContain(symbol); - } else { - FourSlash.currentTestState.verifyMemberListContains(symbol, text, documenation, kind); - } - } - - public memberListCount(expectedCount: number) { - FourSlash.currentTestState.verifyMemberListCount(expectedCount, this.negative); - } - - // Verifies the completion list contains the specified symbol. The - // completion list is brought up if necessary - public completionListContains(symbol: string, text?: string, documentation?: string, kind?: string) { - if (this.negative) { - FourSlash.currentTestState.verifyCompletionListDoesNotContain(symbol, text, documentation, kind); - } else { - FourSlash.currentTestState.verifyCompletionListContains(symbol, text, documentation, kind); - } - } - - // Verifies the completion list items count to be greater than the specified amount. The - // completion list is brought up if necessary - public completionListItemsCountIsGreaterThan(count: number) { - FourSlash.currentTestState.verifyCompletionListItemsCountIsGreaterThan(count, this.negative); - } - - public completionListIsEmpty() { - FourSlash.currentTestState.verifyCompletionListIsEmpty(this.negative); - } - - public completionListAllowsNewIdentifier() { - FourSlash.currentTestState.verifyCompletionListAllowsNewIdentifier(this.negative); - } - - public memberListIsEmpty() { - FourSlash.currentTestState.verifyMemberListIsEmpty(this.negative); - } - - public referencesCountIs(count: number) { - FourSlash.currentTestState.verifyReferencesCountIs(count, /*localFilesOnly*/ false); - } - - public referencesAtPositionContains(range: Range, isWriteAccess?: boolean) { - FourSlash.currentTestState.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess); - } - - public signatureHelpPresent() { - FourSlash.currentTestState.verifySignatureHelpPresent(!this.negative); - } - - public errorExistsBetweenMarkers(startMarker: string, endMarker: string) { - FourSlash.currentTestState.verifyErrorExistsBetweenMarkers(startMarker, endMarker, !this.negative); - } - - public errorExistsAfterMarker(markerName = "") { - FourSlash.currentTestState.verifyErrorExistsAfterMarker(markerName, !this.negative, true); - } - - public errorExistsBeforeMarker(markerName = "") { - FourSlash.currentTestState.verifyErrorExistsAfterMarker(markerName, !this.negative, false); - } - - public quickInfoIs(expectedText?: string, expectedDocumentation?: string) { - FourSlash.currentTestState.verifyQuickInfoString(this.negative, expectedText, expectedDocumentation); - } - - public quickInfoExists() { - FourSlash.currentTestState.verifyQuickInfoExists(this.negative); - } - - public definitionCountIs(expectedCount: number) { - FourSlash.currentTestState.verifyDefinitionsCount(this.negative, expectedCount); - } - - public typeDefinitionCountIs(expectedCount: number) { - FourSlash.currentTestState.verifyTypeDefinitionsCount(this.negative, expectedCount); - } - - public definitionLocationExists() { - FourSlash.currentTestState.verifyDefinitionLocationExists(this.negative); - } - - public verifyDefinitionsName(name: string, containerName: string) { - FourSlash.currentTestState.verifyDefinitionsName(this.negative, name, containerName); - } + class verifyNegatable { + private negative; + not: verifyNegatable; + constructor(negative?: boolean); + memberListContains(symbol: string, text?: string, documenation?: string, kind?: string): void; + memberListCount(expectedCount: number): void; + completionListContains(symbol: string, text?: string, documentation?: string, kind?: string): void; + completionListItemsCountIsGreaterThan(count: number): void; + completionListIsEmpty(): void; + completionListAllowsNewIdentifier(): void; + memberListIsEmpty(): void; + referencesCountIs(count: number): void; + referencesAtPositionContains(range: Range, isWriteAccess?: boolean): void; + signatureHelpPresent(): void; + errorExistsBetweenMarkers(startMarker: string, endMarker: string): void; + errorExistsAfterMarker(markerName?: string): void; + errorExistsBeforeMarker(markerName?: string): void; + quickInfoIs(expectedText?: string, expectedDocumentation?: string): void; + quickInfoExists(): void; + definitionCountIs(expectedCount: number): void; + typeDefinitionCountIs(expectedCount: number): void; + definitionLocationExists(): void; + verifyDefinitionsName(name: string, containerName: string): void; } - - export class verify extends verifyNegatable { - public caretAtMarker(markerName?: string) { - FourSlash.currentTestState.verifyCaretAtMarker(markerName); - } - - public indentationIs(numberOfSpaces: number) { - FourSlash.currentTestState.verifyIndentationAtCurrentPosition(numberOfSpaces); - } - - public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = IndentStyle.Smart) { - FourSlash.currentTestState.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle); - } - - public textAtCaretIs(text: string) { - FourSlash.currentTestState.verifyTextAtCaretIs(text); - } - + class verify extends verifyNegatable { + caretAtMarker(markerName?: string): void; + indentationIs(numberOfSpaces: number): void; + indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle?: IndentStyle): void; + textAtCaretIs(text: string): void; /** * Compiles the current file and evaluates 'expr' in a context containing * the emitted output, then compares (using ===) the result of that expression * to 'value'. Do not use this function with external modules as it is not supported. */ - public eval(expr: string, value: any) { - FourSlash.currentTestState.verifyEval(expr, value); - } - - public currentLineContentIs(text: string) { - FourSlash.currentTestState.verifyCurrentLineContent(text); - } - - public currentFileContentIs(text: string) { - FourSlash.currentTestState.verifyCurrentFileContent(text); - } - - public verifyGetEmitOutputForCurrentFile(expected: string): void { - FourSlash.currentTestState.verifyGetEmitOutputForCurrentFile(expected); - } - - public currentParameterHelpArgumentNameIs(name: string) { - FourSlash.currentTestState.verifyCurrentParameterHelpName(name); - } - - public currentParameterSpanIs(parameter: string) { - FourSlash.currentTestState.verifyCurrentParameterSpanIs(parameter); - } - - public currentParameterHelpArgumentDocCommentIs(docComment: string) { - FourSlash.currentTestState.verifyCurrentParameterHelpDocComment(docComment); - } - - public currentSignatureHelpDocCommentIs(docComment: string) { - FourSlash.currentTestState.verifyCurrentSignatureHelpDocComment(docComment); - } - - public signatureHelpCountIs(expected: number) { - FourSlash.currentTestState.verifySignatureHelpCount(expected); - } - - public signatureHelpArgumentCountIs(expected: number) { - FourSlash.currentTestState.verifySignatureHelpArgumentCount(expected); - } - - public currentSignatureParameterCountIs(expected: number) { - FourSlash.currentTestState.verifyCurrentSignatureHelpParameterCount(expected); - } - - public currentSignatureTypeParameterCountIs(expected: number) { - FourSlash.currentTestState.verifyCurrentSignatureHelpTypeParameterCount(expected); - } - - public currentSignatureHelpIs(expected: string) { - FourSlash.currentTestState.verifyCurrentSignatureHelpIs(expected); - } - - public numberOfErrorsInCurrentFile(expected: number) { - FourSlash.currentTestState.verifyNumberOfErrorsInCurrentFile(expected); - } - - public baselineCurrentFileBreakpointLocations() { - FourSlash.currentTestState.baselineCurrentFileBreakpointLocations(); - } - - public baselineCurrentFileNameOrDottedNameSpans() { - FourSlash.currentTestState.baselineCurrentFileNameOrDottedNameSpans(); - } - - public baselineGetEmitOutput() { - FourSlash.currentTestState.baselineGetEmitOutput(); - } - - public nameOrDottedNameSpanTextIs(text: string) { - FourSlash.currentTestState.verifyCurrentNameOrDottedNameSpanText(text); - } - - public outliningSpansInCurrentFile(spans: TextSpan[]) { - FourSlash.currentTestState.verifyOutliningSpans(spans); - } - - public todoCommentsInCurrentFile(descriptors: string[]) { - FourSlash.currentTestState.verifyTodoComments(descriptors, test.ranges()); - } - - public matchingBracePositionInCurrentFile(bracePosition: number, expectedMatchPosition: number) { - FourSlash.currentTestState.verifyMatchingBracePosition(bracePosition, expectedMatchPosition); - } - - public noMatchingBracePositionInCurrentFile(bracePosition: number) { - FourSlash.currentTestState.verifyNoMatchingBracePosition(bracePosition); - } - - public DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean) { - FourSlash.currentTestState.verifyDocCommentTemplate(empty ? undefined : { newText: expectedText, caretOffset: expectedOffset }); - } - - public noDocCommentTemplate() { - this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, true); - } - - public getScriptLexicalStructureListCount(count: number) { - FourSlash.currentTestState.verifyGetScriptLexicalStructureListCount(count); - } - - // TODO: figure out what to do with the unused arguments. - public getScriptLexicalStructureListContains( - name: string, - kind: string, - fileName?: string, - parentName?: string, - isAdditionalSpan?: boolean, - markerPosition?: number) { - FourSlash.currentTestState.verifyGetScriptLexicalStructureListContains(name, kind); - } - - public navigationItemsListCount(count: number, searchValue: string, matchKind?: string) { - FourSlash.currentTestState.verifyNavigationItemsCount(count, searchValue, matchKind); - } - - public navigationItemsListContains( - name: string, - kind: string, - searchValue: string, - matchKind: string, - fileName?: string, - parentName?: string) { - FourSlash.currentTestState.verifyNavigationItemsListContains( - name, - kind, - searchValue, - matchKind, - fileName, - parentName); - } - - public occurrencesAtPositionContains(range: Range, isWriteAccess?: boolean) { - FourSlash.currentTestState.verifyOccurrencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess); - } - - public occurrencesAtPositionCount(expectedCount: number) { - FourSlash.currentTestState.verifyOccurrencesAtPositionListCount(expectedCount); - } - - public documentHighlightsAtPositionContains(range: Range, fileNamesToSearch: string[], kind?: string) { - FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListContains(range.fileName, range.start, range.end, fileNamesToSearch, kind); - } - - public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]) { - FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); - } - - public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string) { - FourSlash.currentTestState.verifyCompletionEntryDetails(entryName, text, documentation, kind); - } - + eval(expr: string, value: any): void; + currentLineContentIs(text: string): void; + currentFileContentIs(text: string): void; + verifyGetEmitOutputForCurrentFile(expected: string): void; + currentParameterHelpArgumentNameIs(name: string): void; + currentParameterSpanIs(parameter: string): void; + currentParameterHelpArgumentDocCommentIs(docComment: string): void; + currentSignatureHelpDocCommentIs(docComment: string): void; + signatureHelpCountIs(expected: number): void; + signatureHelpArgumentCountIs(expected: number): void; + currentSignatureParameterCountIs(expected: number): void; + currentSignatureTypeParameterCountIs(expected: number): void; + currentSignatureHelpIs(expected: string): void; + numberOfErrorsInCurrentFile(expected: number): void; + baselineCurrentFileBreakpointLocations(): void; + baselineCurrentFileNameOrDottedNameSpans(): void; + baselineGetEmitOutput(): void; + nameOrDottedNameSpanTextIs(text: string): void; + outliningSpansInCurrentFile(spans: TextSpan[]): void; + todoCommentsInCurrentFile(descriptors: string[]): void; + matchingBracePositionInCurrentFile(bracePosition: number, expectedMatchPosition: number): void; + noMatchingBracePositionInCurrentFile(bracePosition: number): void; + DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; + noDocCommentTemplate(): void; + getScriptLexicalStructureListCount(count: number): void; + getScriptLexicalStructureListContains(name: string, kind: string, fileName?: string, parentName?: string, isAdditionalSpan?: boolean, markerPosition?: number): void; + navigationItemsListCount(count: number, searchValue: string, matchKind?: string): void; + navigationItemsListContains(name: string, kind: string, searchValue: string, matchKind: string, fileName?: string, parentName?: string): void; + occurrencesAtPositionContains(range: Range, isWriteAccess?: boolean): void; + occurrencesAtPositionCount(expectedCount: number): void; + documentHighlightsAtPositionContains(range: Range, fileNamesToSearch: string[], kind?: string): void; + documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]): void; + completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string): void; /** * This method *requires* a contiguous, complete, and ordered stream of classifications for a file. */ - public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { - FourSlash.currentTestState.verifySyntacticClassifications(classifications); - } - + syntacticClassificationsAre(...classifications: { + classificationType: string; + text: string; + }[]): void; /** * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. */ - public semanticClassificationsAre(...classifications: { classificationType: string; text: string; textSpan?: TextSpan }[]) { - FourSlash.currentTestState.verifySemanticClassifications(classifications); - } - - public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) { - FourSlash.currentTestState.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers) - } - - public renameInfoFailed(message?: string) { - FourSlash.currentTestState.verifyRenameInfoFailed(message) - } - - public renameLocations(findInStrings: boolean, findInComments: boolean) { - FourSlash.currentTestState.verifyRenameLocations(findInStrings, findInComments); - } - - public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; }, - displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]) { - FourSlash.currentTestState.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation); - } - - public getSyntacticDiagnostics(expected: string) { - FourSlash.currentTestState.getSyntacticDiagnostics(expected); - } - - public getSemanticDiagnostics(expected: string) { - FourSlash.currentTestState.getSemanticDiagnostics(expected); - } - - public ProjectInfo(expected: string []) { - FourSlash.currentTestState.verifyProjectInfo(expected); - } + semanticClassificationsAre(...classifications: { + classificationType: string; + text: string; + textSpan?: TextSpan; + }[]): void; + renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string): void; + renameInfoFailed(message?: string): void; + renameLocations(findInStrings: boolean, findInComments: boolean): void; + verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { + start: number; + length: number; + }, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]): void; + getSyntacticDiagnostics(expected: string): void; + getSemanticDiagnostics(expected: string): void; + ProjectInfo(expected: string[]): void; } - - export class edit { - public backspace(count?: number) { - FourSlash.currentTestState.deleteCharBehindMarker(count); - } - - public deleteAtCaret(times?: number) { - FourSlash.currentTestState.deleteChar(times); - } - - public replace(start: number, length: number, text: string) { - FourSlash.currentTestState.replace(start, length, text); - } - - public paste(text: string) { - FourSlash.currentTestState.paste(text); - } - - public insert(text: string) { - this.insertLines(text); - } - - public insertLine(text: string) { - this.insertLines(text + '\n'); - } - - public insertLines(...lines: string[]) { - FourSlash.currentTestState.type(lines.join('\n')); - } - - public moveRight(count?: number) { - FourSlash.currentTestState.moveCaretRight(count); - } - - public moveLeft(count?: number) { - if (typeof count === 'undefined') { - count = 1; - } - FourSlash.currentTestState.moveCaretRight(count * -1); - } - - public enableFormatting() { - FourSlash.currentTestState.enableFormatting = true; - } - - public disableFormatting() { - FourSlash.currentTestState.enableFormatting = false; - } + class edit { + backspace(count?: number): void; + deleteAtCaret(times?: number): void; + replace(start: number, length: number, text: string): void; + paste(text: string): void; + insert(text: string): void; + insertLine(text: string): void; + insertLines(...lines: string[]): void; + moveRight(count?: number): void; + moveLeft(count?: number): void; + enableFormatting(): void; + disableFormatting(): void; } - - export class debug { - public printCurrentParameterHelp() { - FourSlash.currentTestState.printCurrentParameterHelp(); - } - - public printCurrentFileState() { - FourSlash.currentTestState.printCurrentFileState(); - } - - public printCurrentFileStateWithWhitespace() { - FourSlash.currentTestState.printCurrentFileState(/*withWhiteSpace=*/true); - } - - public printCurrentFileStateWithoutCaret() { - FourSlash.currentTestState.printCurrentFileState(/*withWhiteSpace=*/false, /*withCaret=*/false); - } - - public printCurrentQuickInfo() { - FourSlash.currentTestState.printCurrentQuickInfo(); - } - - public printCurrentSignatureHelp() { - FourSlash.currentTestState.printCurrentSignatureHelp(); - } - - public printMemberListMembers() { - FourSlash.currentTestState.printMemberListMembers(); - } - - public printCompletionListMembers() { - FourSlash.currentTestState.printCompletionListMembers(); - } - - public printBreakpointLocation(pos: number) { - FourSlash.currentTestState.printBreakpointLocation(pos); - } - public printBreakpointAtCurrentLocation() { - FourSlash.currentTestState.printBreakpointAtCurrentLocation(); - } - - public printNameOrDottedNameSpans(pos: number) { - FourSlash.currentTestState.printNameOrDottedNameSpans(pos); - } - - public printErrorList() { - FourSlash.currentTestState.printErrorList(); - } - - public printNavigationItems(searchValue: string = ".*") { - FourSlash.currentTestState.printNavigationItems(searchValue); - } - - public printScriptLexicalStructureItems() { - FourSlash.currentTestState.printScriptLexicalStructureItems(); - } - - public printReferences() { - FourSlash.currentTestState.printReferences(); - } - - public printContext() { - FourSlash.currentTestState.printContext(); - } + class debug { + printCurrentParameterHelp(): void; + printCurrentFileState(): void; + printCurrentFileStateWithWhitespace(): void; + printCurrentFileStateWithoutCaret(): void; + printCurrentQuickInfo(): void; + printCurrentSignatureHelp(): void; + printMemberListMembers(): void; + printCompletionListMembers(): void; + printBreakpointLocation(pos: number): void; + printBreakpointAtCurrentLocation(): void; + printNameOrDottedNameSpans(pos: number): void; + printErrorList(): void; + printNavigationItems(searchValue?: string): void; + printScriptLexicalStructureItems(): void; + printReferences(): void; + printContext(): void; } - - export class format { - public document() { - FourSlash.currentTestState.formatDocument(); - } - - public copyFormatOptions(): FormatCodeOptions { - return FourSlash.currentTestState.copyFormatOptions(); - } - - public setFormatOptions(options: FormatCodeOptions) { - return FourSlash.currentTestState.setFormatOptions(options); - } - - public selection(startMarker: string, endMarker: string) { - FourSlash.currentTestState.formatSelection(FourSlash.currentTestState.getMarkerByName(startMarker).position, FourSlash.currentTestState.getMarkerByName(endMarker).position); - } - - public setOption(name: string, value: number); - public setOption(name: string, value: string); - public setOption(name: string, value: boolean); - public setOption(name: string, value: any) { - FourSlash.currentTestState.formatCodeOptions[name] = value; - } + class format { + document(): void; + copyFormatOptions(): FormatCodeOptions; + setFormatOptions(options: FormatCodeOptions): any; + selection(startMarker: string, endMarker: string): void; + setOption(name: string, value: number): any; + setOption(name: string, value: string): any; + setOption(name: string, value: boolean): any; } - - export class cancellation { - public resetCancelled() { - FourSlash.currentTestState.resetCancelled(); - } - - public setCancelled(numberOfCalls: number = 0) { - FourSlash.currentTestState.setCancelled(numberOfCalls); - } + class cancellation { + resetCancelled(): void; + setCancelled(numberOfCalls?: number): void; } - - export module classification { - export function comment(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("comment", text, position); - } - - export function identifier(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("identifier", text, position); - } - - export function keyword(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("keyword", text, position); - } - - export function numericLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("numericLiteral", text, position); - } - - export function operator(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("operator", text, position); - } - - export function stringLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("stringLiteral", text, position); - } - - export function whiteSpace(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("whiteSpace", text, position); - } - - export function text(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("text", text, position); - } - - export function punctuation(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("punctuation", text, position); - } - - export function docCommentTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("docCommentTagName", text, position); - } - - export function className(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("className", text, position); - } - - export function enumName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("enumName", text, position); - } - - export function interfaceName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("interfaceName", text, position); - } - - export function moduleName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("moduleName", text, position); - } - - export function typeParameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("typeParameterName", text, position); - } - - export function parameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("parameterName", text, position); - } - - export function typeAliasName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } { - return getClassification("typeAliasName", text, position); - } - - function getClassification(type: string, text: string, position?: number) { - return { - classificationType: type, - text: text, - textSpan: position === undefined ? undefined : { start: position, end: position + text.length } - }; - } + module classification { + function comment(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function identifier(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function keyword(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function numericLiteral(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function operator(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function stringLiteral(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function whiteSpace(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function text(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function punctuation(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function docCommentTagName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function className(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function enumName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function interfaceName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function moduleName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function typeParameterName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function parameterName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; + function typeAliasName(text: string, position?: number): { + classificationType: string; + text: string; + textSpan?: TextSpan; + }; } } - -module fs { - export var test = new FourSlashInterface.test_(); - export var goTo = new FourSlashInterface.goTo(); - export var verify = new FourSlashInterface.verify(); - export var edit = new FourSlashInterface.edit(); - export var debug = new FourSlashInterface.debug(); - export var format = new FourSlashInterface.format(); - export var cancellation = new FourSlashInterface.cancellation(); +declare module fs { + var test: FourSlashInterface.test_; + var goTo: FourSlashInterface.goTo; + var verify: FourSlashInterface.verify; + var edit: FourSlashInterface.edit; + var debug: FourSlashInterface.debug; + var format: FourSlashInterface.format; + var cancellation: FourSlashInterface.cancellation; } - -function verifyOperationIsCancelled(f) { - FourSlash.verifyOperationIsCancelled(f); -} - -var test = new FourSlashInterface.test_(); -var goTo = new FourSlashInterface.goTo(); -var verify = new FourSlashInterface.verify(); -var edit = new FourSlashInterface.edit(); -var debug = new FourSlashInterface.debug(); -var format = new FourSlashInterface.format(); -var cancellation = new FourSlashInterface.cancellation(); -var classification = FourSlashInterface.classification; +declare function verifyOperationIsCancelled(f: any): void; +declare var test: FourSlashInterface.test_; +declare var goTo: FourSlashInterface.goTo; +declare var verify: FourSlashInterface.verify; +declare var edit: FourSlashInterface.edit; +declare var debug: FourSlashInterface.debug; +declare var format: FourSlashInterface.format; +declare var cancellation: FourSlashInterface.cancellation; +declare var classification: typeof FourSlashInterface.classification; diff --git a/tests/cases/fourslash/indentationBlock.ts b/tests/cases/fourslash/indentationBlock.ts index e880c4a0957..853ff43b0d6 100644 --- a/tests/cases/fourslash/indentationBlock.ts +++ b/tests/cases/fourslash/indentationBlock.ts @@ -179,5 +179,5 @@ ////{| "indent": 0 |} test.markers().forEach(marker => { - verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, IndentStyle.Block); + verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, ts.IndentStyle.Block); }); diff --git a/tests/cases/fourslash/indentationNone.ts b/tests/cases/fourslash/indentationNone.ts index 078f5ab35f6..610a336cdda 100644 --- a/tests/cases/fourslash/indentationNone.ts +++ b/tests/cases/fourslash/indentationNone.ts @@ -179,5 +179,5 @@ ////{| "indent": 0 |} test.markers().forEach(marker => { - verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, IndentStyle.None); + verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent, ts.IndentStyle.None); }); diff --git a/tests/cases/fourslash/recursiveClassReference.ts b/tests/cases/fourslash/recursiveClassReference.ts index d0e96ac90e3..81843711d65 100644 --- a/tests/cases/fourslash/recursiveClassReference.ts +++ b/tests/cases/fourslash/recursiveClassReference.ts @@ -11,4 +11,4 @@ //// } goTo.marker(); -fs.verify.quickInfoExists(); +verify.quickInfoExists(); diff --git a/tests/cases/fourslash/renameModuleToVar.ts b/tests/cases/fourslash/renameModuleToVar.ts index 023b0fa1c74..fc31f4040e8 100644 --- a/tests/cases/fourslash/renameModuleToVar.ts +++ b/tests/cases/fourslash/renameModuleToVar.ts @@ -10,7 +10,7 @@ //// var z = y + 5; ////} -fs.goTo.marker(); -fs.edit.backspace(6); -fs.edit.insert("var"); -fs.verify.numberOfErrorsInCurrentFile(0); \ No newline at end of file +goTo.marker(); +edit.backspace(6); +edit.insert("var"); +verify.numberOfErrorsInCurrentFile(0); From 076d65e1cf261277692591c33c5f4978c57c36d1 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 16:23:18 -0800 Subject: [PATCH 25/35] addressed PR feedback --- src/harness/compilerRunner.ts | 7 ++++--- src/harness/harness.ts | 24 +++++++++++++----------- tests/cases/fourslash/fourslash.ts | 11 +---------- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 85a51b8f2a4..399f8a272dd 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -250,10 +250,11 @@ class CompilerBaselineRunner extends RunnerBase { // These types are equivalent, but depend on what order the compiler observed // certain parts of the program. - const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)); + const program = result.program; + const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName)); - const fullWalker = new TypeWriterWalker(result.program, /*fullTypeCheck*/ true); - const pullWalker = new TypeWriterWalker(result.program, /*fullTypeCheck*/ false); + const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true); + const pullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ false); const fullResults: ts.Map = {}; const pullResults: ts.Map = {}; diff --git a/src/harness/harness.ts b/src/harness/harness.ts index e58e6635434..ef0f2678e29 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -767,9 +767,9 @@ namespace Harness { } namespace Harness { - const tcServicesFileName = "built/local/typescriptServices.js"; export const libFolder = "built/local/"; - export let tcServicesFile = IO.readFile(tcServicesFileName); + const tcServicesFileName = ts.combinePaths(libFolder, "typescriptServices.js"); + export const tcServicesFile = IO.readFile(tcServicesFileName); export interface SourceMapEmitterCallback { (emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void; @@ -990,7 +990,6 @@ namespace Harness { options.noErrorTruncation = true; options.skipDefaultLibCheck = true; - const newLine = "\r\n"; currentDirectory = currentDirectory || Harness.IO.getCurrentDirectory(); // Parse settings @@ -1002,27 +1001,30 @@ namespace Harness { useCaseSensitiveFileNames = options.useCaseSensitiveFileNames; } + const programFiles: TestFile[] = inputFiles.slice(); // Files from built\local that are requested by test "@includeBuiltFiles" to be in the context. // Treat them as library files, so include them in build, but not in baselines. - const includeBuiltFiles: TestFile[] = []; if (options.includeBuiltFile) { - const builtFileName = libFolder + options.includeBuiltFile; + const builtFileName = ts.combinePaths(libFolder, options.includeBuiltFile); const builtFile: TestFile = { unitName: builtFileName, - content: normalizeLineEndings(IO.readFile(builtFileName), newLine), + content: normalizeLineEndings(IO.readFile(builtFileName), Harness.IO.newLine()), }; - includeBuiltFiles.push(builtFile); + programFiles.push(builtFile); } const fileOutputs: GeneratedFile[] = []; - const programFiles = inputFiles.concat(includeBuiltFiles).map(file => file.unitName); + const programFileNames = programFiles.map(file => file.unitName); const compilerHost = createCompilerHost( - inputFiles.concat(includeBuiltFiles).concat(otherFiles), + programFiles.concat(otherFiles), (fileName, code, writeByteOrderMark) => fileOutputs.push({ fileName, code, writeByteOrderMark }), - options.target, useCaseSensitiveFileNames, currentDirectory, options.newLine); - const program = ts.createProgram(programFiles, options, compilerHost); + options.target, + useCaseSensitiveFileNames, + currentDirectory, + options.newLine); + const program = ts.createProgram(programFileNames, options, compilerHost); const emitResult = program.emit(); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 5b8bb94bb48..f93ac76d6ed 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -55,7 +55,7 @@ declare module ts { } } -declare module FourSlashInterface { +declare namespace FourSlashInterface { interface Marker { fileName: string; position: number; @@ -331,15 +331,6 @@ declare module FourSlashInterface { }; } } -declare module fs { - var test: FourSlashInterface.test_; - var goTo: FourSlashInterface.goTo; - var verify: FourSlashInterface.verify; - var edit: FourSlashInterface.edit; - var debug: FourSlashInterface.debug; - var format: FourSlashInterface.format; - var cancellation: FourSlashInterface.cancellation; -} declare function verifyOperationIsCancelled(f: any): void; declare var test: FourSlashInterface.test_; declare var goTo: FourSlashInterface.goTo; From a275dabe44f1e58fb7676b963190dd70cd729ab6 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Mon, 16 Nov 2015 16:48:57 -0800 Subject: [PATCH 26/35] When constructing signature, include parameter symbol instead of property symbol of parameter-property declaration Fixes #4566 --- src/compiler/checker.ts | 8 +++++++- ...natureHelpConstructorCallParamProperties.ts | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/signatureHelpConstructorCallParamProperties.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f975c110b03..378fd85265f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3829,7 +3829,13 @@ namespace ts { let minArgumentCount = -1; for (let i = 0, n = declaration.parameters.length; i < n; i++) { const param = declaration.parameters[i]; - parameters.push(param.symbol); + let paramSymbol = param.symbol; + // Include parameter symbol instead of property symbol in the signature + if (paramSymbol && !!(paramSymbol.flags & SymbolFlags.Property) && !isBindingPattern(param.name)) { + const resolvedSymbol = resolveName(param, paramSymbol.name, SymbolFlags.Value, undefined, undefined); + paramSymbol = resolvedSymbol; + } + parameters.push(paramSymbol); if (param.type && param.type.kind === SyntaxKind.StringLiteral) { hasStringLiterals = true; } diff --git a/tests/cases/fourslash/signatureHelpConstructorCallParamProperties.ts b/tests/cases/fourslash/signatureHelpConstructorCallParamProperties.ts new file mode 100644 index 00000000000..aab276403fe --- /dev/null +++ b/tests/cases/fourslash/signatureHelpConstructorCallParamProperties.ts @@ -0,0 +1,18 @@ +/// + +////class Circle { +//// /** +//// * Initialize a circle. +//// * @param radius The radius of the circle. +//// */ +//// constructor(private radius: number) { +//// } +////} +////var a = new Circle(/**/ + +goTo.marker(''); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("Circle(radius: number): Circle"); +verify.currentParameterHelpArgumentNameIs("radius"); +verify.currentParameterSpanIs("radius: number"); +verify.currentParameterHelpArgumentDocCommentIs("The radius of the circle."); \ No newline at end of file From 33fc598a8afe3189cf1593c7f081241c0bd43045 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 23:24:25 -0800 Subject: [PATCH 27/35] clean residual state in binder and emitter, clean test data in version cache test --- src/compiler/binder.ts | 2 + src/compiler/emitter.ts | 55 +++++----- tests/cases/unittests/versionCache.ts | 141 +++++++++++++++++--------- 3 files changed, 122 insertions(+), 76 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 8b88da5b749..6b04e22551d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -139,6 +139,8 @@ namespace ts { file.classifiableNames = classifiableNames; } + file = undefined; + options = undefined; parent = undefined; container = undefined; blockScopeContainer = undefined; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index e4cd57542a7..bdeac582bbf 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -516,7 +516,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi let decorateEmitted: boolean; let paramEmitted: boolean; let awaiterEmitted: boolean; - let tempFlags: TempFlags; + let tempFlags: TempFlags = 0; let tempVariables: Identifier[]; let tempParameters: Identifier[]; let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; @@ -584,33 +584,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return doEmit; function doEmit(jsFilePath: string, rootFile?: SourceFile) { - // reset the state - writer.reset(); - currentSourceFile = undefined; - currentText = undefined; - currentLineMap = undefined; - exportFunctionForFile = undefined; generatedNameSet = {}; nodeToGeneratedName = []; - computedPropertyNamesToGeneratedNames = undefined; - convertedLoopState = undefined; - - extendsEmitted = false; - decorateEmitted = false; - paramEmitted = false; - awaiterEmitted = false; - tempFlags = 0; - tempVariables = undefined; - tempParameters = undefined; - externalImports = undefined; - exportSpecifiers = undefined; - exportEquals = undefined; - hasExportStars = undefined; - detachedCommentsInfo = undefined; - sourceMapData = undefined; - isEs6Module = false; - renamedDependencies = undefined; - isCurrentFileExternalModule = false; root = rootFile; if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) { @@ -634,6 +609,34 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); writeEmittedFiles(writer.getText(), jsFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM); + + // reset the state + writer.reset(); + currentSourceFile = undefined; + currentText = undefined; + currentLineMap = undefined; + exportFunctionForFile = undefined; + generatedNameSet = undefined; + nodeToGeneratedName = undefined; + computedPropertyNamesToGeneratedNames = undefined; + convertedLoopState = undefined; + extendsEmitted = false; + decorateEmitted = false; + paramEmitted = false; + awaiterEmitted = false; + tempFlags = 0; + tempVariables = undefined; + tempParameters = undefined; + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = undefined; + detachedCommentsInfo = undefined; + sourceMapData = undefined; + isEs6Module = false; + renamedDependencies = undefined; + isCurrentFileExternalModule = false; + root = undefined; } function emitSourceFile(sourceFile: SourceFile): void { diff --git a/tests/cases/unittests/versionCache.ts b/tests/cases/unittests/versionCache.ts index 06c2cadbfe9..20cb0ea7127 100644 --- a/tests/cases/unittests/versionCache.ts +++ b/tests/cases/unittests/versionCache.ts @@ -20,7 +20,10 @@ module ts { } describe('VersionCache TS code', () => { - var testContent = `/// + let validateEditAtLineCharIndex: (line: number, char: number, deleteLength: number, insertString: string) => void; + + before(() => { + let testContent = `/// var x = 10; var y = { zebra: 12, giraffe: "ell" }; z.a; @@ -31,16 +34,21 @@ k=y; var p:Point=new Point(); var q:Point=p;` - let {lines, lineMap} = server.LineIndex.linesFromText(testContent); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + let {lines, lineMap} = server.LineIndex.linesFromText(testContent); + assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); - let lineIndex = new server.LineIndex(); - lineIndex.load(lines); + let lineIndex = new server.LineIndex(); + lineIndex.load(lines); - function validateEditAtLineCharIndex(line: number, char: number, deleteLength: number, insertString: string): void { - let position = lineColToPosition(lineIndex, line, char); - validateEdit(lineIndex, testContent, position, deleteLength, insertString); - } + validateEditAtLineCharIndex = (line: number, char: number, deleteLength: number, insertString: string) => { + let position = lineColToPosition(lineIndex, line, char); + validateEdit(lineIndex, testContent, position, deleteLength, insertString); + }; + }); + + after(() => { + validateEditAtLineCharIndex = undefined; + }) it('change 9 1 0 1 {"y"}', () => { validateEditAtLineCharIndex(9, 1, 0, "y"); @@ -68,22 +76,35 @@ var q:Point=p;` }); describe('VersionCache simple text', () => { - let testContent = `in this story: + let validateEditAtPosition: (position: number, deleteLength: number, insertString: string) => void; + let testContent: string; + let lines: string[]; + let lineMap: number[]; + before(() => { + testContent = `in this story: the lazy brown fox jumped over the cow that ate the grass that was purple at the tips and grew 1cm per day`; - let {lines, lineMap} = server.LineIndex.linesFromText(testContent); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + ({lines, lineMap} = server.LineIndex.linesFromText(testContent)); + assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); - let lineIndex = new server.LineIndex(); - lineIndex.load(lines); + let lineIndex = new server.LineIndex(); + lineIndex.load(lines); - function validateEditAtPosition(position: number, deleteLength: number, insertString: string): void { - validateEdit(lineIndex, testContent, position, deleteLength, insertString); - } + validateEditAtPosition = (position: number, deleteLength: number, insertString: string) => { + validateEdit(lineIndex, testContent, position, deleteLength, insertString); + } + }); + + after(() => { + validateEditAtPosition = undefined; + testContent = undefined; + lines = undefined; + lineMap = undefined; + }); it('Insert at end of file', () => { validateEditAtPosition(testContent.length, 0, "hmmmm...\r\n"); @@ -159,50 +180,70 @@ and grew 1cm per day`; }); describe('VersionCache stress test', () => { - const iterationCount = 20; - //const interationCount = 20000; // uncomment for testing - - // Use scanner.ts, decent size, does not change frequentlly - let testFileName = "src/compiler/scanner.ts"; - let testContent = Harness.IO.readFile(testFileName); - let totalChars = testContent.length; - assert.isTrue(totalChars > 0, "Failed to read test file."); - - let {lines, lineMap} = server.LineIndex.linesFromText(testContent); - assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); - - let lineIndex = new server.LineIndex(); - lineIndex.load(lines); - let rsa: number[] = []; let la: number[] = []; let las: number[] = []; let elas: number[] = []; let ersa: number[] = []; let ela: number[] = []; - let etotalChars = totalChars; + const iterationCount = 20; + let lines: string[]; + let lineMap: number[]; + let lineIndex: server.LineIndex; + let testContent: string; - for (let j = 0; j < 100000; j++) { - rsa[j] = Math.floor(Math.random() * totalChars); - la[j] = Math.floor(Math.random() * (totalChars - rsa[j])); - if (la[j] > 4) { - las[j] = 4; - } - else { - las[j] = la[j]; - } - if (j < 4000) { - ersa[j] = Math.floor(Math.random() * etotalChars); - ela[j] = Math.floor(Math.random() * (etotalChars - ersa[j])); - if (ela[j] > 4) { - elas[j] = 4; + before(() => { + //const interationCount = 20000; // uncomment for testing + + // Use scanner.ts, decent size, does not change frequentlly + let testFileName = "src/compiler/scanner.ts"; + testContent = Harness.IO.readFile(testFileName); + let totalChars = testContent.length; + assert.isTrue(totalChars > 0, "Failed to read test file."); + + ({lines, lineMap} = server.LineIndex.linesFromText(testContent)); + assert.isTrue(lines.length > 0, "Failed to initialize test text. Expected text to have at least one line"); + + lineIndex = new server.LineIndex(); + lineIndex.load(lines); + + let etotalChars = totalChars; + + for (let j = 0; j < 100000; j++) { + rsa[j] = Math.floor(Math.random() * totalChars); + la[j] = Math.floor(Math.random() * (totalChars - rsa[j])); + if (la[j] > 4) { + las[j] = 4; } else { - elas[j] = ela[j]; + las[j] = la[j]; + } + if (j < 4000) { + ersa[j] = Math.floor(Math.random() * etotalChars); + ela[j] = Math.floor(Math.random() * (etotalChars - ersa[j])); + if (ela[j] > 4) { + elas[j] = 4; + } + else { + elas[j] = ela[j]; + } + etotalChars += (las[j] - elas[j]); } - etotalChars += (las[j] - elas[j]); } - } + }); + + after(() => { + rsa = undefined; + la = undefined; + las = undefined; + elas = undefined; + ersa = undefined; + ela = undefined; + lines = undefined; + lineMap = undefined; + lineIndex = undefined; + testContent = undefined; + }); it("Range (average length 1/4 file size)", () => { for (let i = 0; i < iterationCount; i++) { From a26d89d7a2ebb924f1f1bc519c94ac465899f8fa Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Mon, 16 Nov 2015 23:44:07 -0800 Subject: [PATCH 28/35] addressed PR feedback --- tests/cases/unittests/versionCache.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/cases/unittests/versionCache.ts b/tests/cases/unittests/versionCache.ts index 20cb0ea7127..c1d283ca8cd 100644 --- a/tests/cases/unittests/versionCache.ts +++ b/tests/cases/unittests/versionCache.ts @@ -187,15 +187,14 @@ and grew 1cm per day`; let ersa: number[] = []; let ela: number[] = []; const iterationCount = 20; + //const iterationCount = 20000; // uncomment for testing let lines: string[]; let lineMap: number[]; let lineIndex: server.LineIndex; let testContent: string; before(() => { - //const interationCount = 20000; // uncomment for testing - - // Use scanner.ts, decent size, does not change frequentlly + // Use scanner.ts, decent size, does not change frequently let testFileName = "src/compiler/scanner.ts"; testContent = Harness.IO.readFile(testFileName); let totalChars = testContent.length; From a989595044bf942cef77360e7225622f464e4a6b Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 17 Nov 2015 11:24:17 -0800 Subject: [PATCH 29/35] use getCanonicalFileName on path fragments as in other utility methods --- src/compiler/program.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 80f793cb50f..dc31dfb5213 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -919,9 +919,8 @@ namespace ts { return; } - const caseSensitive = host.useCaseSensitiveFileNames(); for (let i = 0, n = Math.min(commonPathComponents.length, sourcePathComponents.length); i < n; i++) { - if (caseSensitive ? commonPathComponents[i] !== sourcePathComponents[i] : commonPathComponents[i].toLocaleLowerCase() !== sourcePathComponents[i].toLocaleLowerCase()) { + if (getCanonicalFileName(commonPathComponents[i]) !== getCanonicalFileName(sourcePathComponents[i])) { if (i === 0) { // Failed to find any common path component return true; From e0a8af00a78d28c5b929835a5aceb623e032d6ea Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 17 Nov 2015 13:27:52 -0800 Subject: [PATCH 30/35] do not resolve parameters/type parameters if it is requested from restricted locations --- src/compiler/checker.ts | 36 ++++++++++--- ...rameterNamesInTypeParameterList.errors.txt | 44 +++++++++++++++ .../parameterNamesInTypeParameterList.js | 53 +++++++++++++++++++ ...ersAndParametersInComputedNames.errors.txt | 17 ++++++ ...eParametersAndParametersInComputedNames.js | 21 ++++++++ .../parameterNamesInTypeParameterList.ts | 23 ++++++++ ...eParametersAndParametersInComputedNames.ts | 8 +++ 7 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/parameterNamesInTypeParameterList.errors.txt create mode 100644 tests/baselines/reference/parameterNamesInTypeParameterList.js create mode 100644 tests/baselines/reference/typeParametersAndParametersInComputedNames.errors.txt create mode 100644 tests/baselines/reference/typeParametersAndParametersInComputedNames.js create mode 100644 tests/cases/compiler/parameterNamesInTypeParameterList.ts create mode 100644 tests/cases/compiler/typeParametersAndParametersInComputedNames.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 378fd85265f..f9fd563b873 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -476,15 +476,37 @@ namespace ts { // Locals of a source file are not in scope (because they get merged into the global symbol table) if (location.locals && !isGlobalSourceFile(location)) { if (result = getSymbol(location.locals, name, meaning)) { - // Type parameters of a function are in scope in the entire function declaration, including the parameter - // list and return type. However, local types are only in scope in the function body. - if (!(meaning & SymbolFlags.Type) || - !(result.flags & (SymbolFlags.Type & ~SymbolFlags.TypeParameter)) || - !isFunctionLike(location) || - lastLocation === (location).body) { + let useResult = true; + if (isFunctionLike(location) && lastLocation && lastLocation !== (location).body) { + // symbol lookup restrictions for function-like declarations + // - Type parameters of a function are in scope in the entire function declaration, including the parameter + // list and return type. However, local types are only in scope in the function body. + // - parameters are only in the scope of function body + if (meaning & result.flags & SymbolFlags.Type) { + useResult = result.flags & SymbolFlags.TypeParameter + // type parameters are visible in parameter list, return type and type parameter list + ? lastLocation === (location).type || + lastLocation.kind === SyntaxKind.Parameter || + lastLocation.kind === SyntaxKind.TypeParameter + // local types not visible outside the function body + : false; + } + if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) { + // function scoped variables are visible only inside function body and parameter list + // technically here we might mix parameters and variables declared in function, + // however this case is detected separately when checking initializers of parameters + // to make sure that they reference no variables declared after them. + useResult = lastLocation === (location).type || + lastLocation.kind === SyntaxKind.Parameter; + } + } + + if (useResult) { break loop; } - result = undefined; + else { + result = undefined; + } } } switch (location.kind) { diff --git a/tests/baselines/reference/parameterNamesInTypeParameterList.errors.txt b/tests/baselines/reference/parameterNamesInTypeParameterList.errors.txt new file mode 100644 index 00000000000..54ddb963f94 --- /dev/null +++ b/tests/baselines/reference/parameterNamesInTypeParameterList.errors.txt @@ -0,0 +1,44 @@ +tests/cases/compiler/parameterNamesInTypeParameterList.ts(1,30): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parameterNamesInTypeParameterList.ts(5,30): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parameterNamesInTypeParameterList.ts(9,30): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parameterNamesInTypeParameterList.ts(14,22): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parameterNamesInTypeParameterList.ts(17,22): error TS2304: Cannot find name 'a'. +tests/cases/compiler/parameterNamesInTypeParameterList.ts(20,22): error TS2304: Cannot find name 'a'. + + +==== tests/cases/compiler/parameterNamesInTypeParameterList.ts (6 errors) ==== + function f0(a: T) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b; + } + + function f1({a}: {a:T}) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b; + } + + function f2([a]: T[]) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b; + } + + class A { + m0(a: T) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b + } + m1({a}: {a:T}) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b + } + m2([a]: T[]) { + ~ +!!! error TS2304: Cannot find name 'a'. + a.b + } + } \ No newline at end of file diff --git a/tests/baselines/reference/parameterNamesInTypeParameterList.js b/tests/baselines/reference/parameterNamesInTypeParameterList.js new file mode 100644 index 00000000000..2fbd7fad3cb --- /dev/null +++ b/tests/baselines/reference/parameterNamesInTypeParameterList.js @@ -0,0 +1,53 @@ +//// [parameterNamesInTypeParameterList.ts] +function f0(a: T) { + a.b; +} + +function f1({a}: {a:T}) { + a.b; +} + +function f2([a]: T[]) { + a.b; +} + +class A { + m0(a: T) { + a.b + } + m1({a}: {a:T}) { + a.b + } + m2([a]: T[]) { + a.b + } +} + +//// [parameterNamesInTypeParameterList.js] +function f0(a) { + a.b; +} +function f1(_a) { + var a = _a.a; + a.b; +} +function f2(_a) { + var a = _a[0]; + a.b; +} +var A = (function () { + function A() { + } + A.prototype.m0 = function (a) { + a.b; + }; + A.prototype.m1 = function (_a) { + var a = _a.a; + a.b; + }; + A.prototype.m2 = function (_a) { + var a = _a[0]; + a.b; + }; + return A; +})(); diff --git a/tests/baselines/reference/typeParametersAndParametersInComputedNames.errors.txt b/tests/baselines/reference/typeParametersAndParametersInComputedNames.errors.txt new file mode 100644 index 00000000000..872a0a10923 --- /dev/null +++ b/tests/baselines/reference/typeParametersAndParametersInComputedNames.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/typeParametersAndParametersInComputedNames.ts(6,10): error TS2304: Cannot find name 'T'. +tests/cases/compiler/typeParametersAndParametersInComputedNames.ts(6,13): error TS2304: Cannot find name 'a'. + + +==== tests/cases/compiler/typeParametersAndParametersInComputedNames.ts (2 errors) ==== + function foo(a: T) : string { + return ""; + } + + class A { + [foo(a)](a: T) { + ~ +!!! error TS2304: Cannot find name 'T'. + ~ +!!! error TS2304: Cannot find name 'a'. + } + } \ No newline at end of file diff --git a/tests/baselines/reference/typeParametersAndParametersInComputedNames.js b/tests/baselines/reference/typeParametersAndParametersInComputedNames.js new file mode 100644 index 00000000000..1cb53663fbd --- /dev/null +++ b/tests/baselines/reference/typeParametersAndParametersInComputedNames.js @@ -0,0 +1,21 @@ +//// [typeParametersAndParametersInComputedNames.ts] +function foo(a: T) : string { + return ""; +} + +class A { + [foo(a)](a: T) { + } +} + +//// [typeParametersAndParametersInComputedNames.js] +function foo(a) { + return ""; +} +var A = (function () { + function A() { + } + A.prototype[foo(a)] = function (a) { + }; + return A; +})(); diff --git a/tests/cases/compiler/parameterNamesInTypeParameterList.ts b/tests/cases/compiler/parameterNamesInTypeParameterList.ts new file mode 100644 index 00000000000..dba122db866 --- /dev/null +++ b/tests/cases/compiler/parameterNamesInTypeParameterList.ts @@ -0,0 +1,23 @@ +function f0(a: T) { + a.b; +} + +function f1({a}: {a:T}) { + a.b; +} + +function f2([a]: T[]) { + a.b; +} + +class A { + m0(a: T) { + a.b + } + m1({a}: {a:T}) { + a.b + } + m2([a]: T[]) { + a.b + } +} \ No newline at end of file diff --git a/tests/cases/compiler/typeParametersAndParametersInComputedNames.ts b/tests/cases/compiler/typeParametersAndParametersInComputedNames.ts new file mode 100644 index 00000000000..273dcb2a3ea --- /dev/null +++ b/tests/cases/compiler/typeParametersAndParametersInComputedNames.ts @@ -0,0 +1,8 @@ +function foo(a: T) : string { + return ""; +} + +class A { + [foo(a)](a: T) { + } +} \ No newline at end of file From 31039a3fff48b23a40c087e530eaa55f9f092b89 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 17 Nov 2015 15:22:26 -0800 Subject: [PATCH 31/35] disallow references to function locals from return type annotations --- src/compiler/checker.ts | 14 +++++++++----- ...nctionVariableInReturnTypeAnnotation.errors.txt | 10 ++++++++++ .../functionVariableInReturnTypeAnnotation.js | 11 +++++++++++ .../functionVariableInReturnTypeAnnotation.ts | 4 ++++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/functionVariableInReturnTypeAnnotation.errors.txt create mode 100644 tests/baselines/reference/functionVariableInReturnTypeAnnotation.js create mode 100644 tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f9fd563b873..5348d2b19f0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -492,12 +492,16 @@ namespace ts { : false; } if (meaning & SymbolFlags.Value && result.flags & SymbolFlags.FunctionScopedVariable) { - // function scoped variables are visible only inside function body and parameter list - // technically here we might mix parameters and variables declared in function, - // however this case is detected separately when checking initializers of parameters + // parameters are visible only inside function body, parameter list and return type + // technically for parameter list case here we might mix parameters and variables declared in function, + // however it is detected separately when checking initializers of parameters // to make sure that they reference no variables declared after them. - useResult = lastLocation === (location).type || - lastLocation.kind === SyntaxKind.Parameter; + useResult = + lastLocation.kind === SyntaxKind.Parameter || + ( + lastLocation === (location).type && + result.valueDeclaration.kind === SyntaxKind.Parameter + ); } } diff --git a/tests/baselines/reference/functionVariableInReturnTypeAnnotation.errors.txt b/tests/baselines/reference/functionVariableInReturnTypeAnnotation.errors.txt new file mode 100644 index 00000000000..93a35292b70 --- /dev/null +++ b/tests/baselines/reference/functionVariableInReturnTypeAnnotation.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts(1,24): error TS2304: Cannot find name 'b'. + + +==== tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts (1 errors) ==== + function bar(): typeof b { + ~ +!!! error TS2304: Cannot find name 'b'. + var b = 1; + return undefined; + } \ No newline at end of file diff --git a/tests/baselines/reference/functionVariableInReturnTypeAnnotation.js b/tests/baselines/reference/functionVariableInReturnTypeAnnotation.js new file mode 100644 index 00000000000..191255e52c2 --- /dev/null +++ b/tests/baselines/reference/functionVariableInReturnTypeAnnotation.js @@ -0,0 +1,11 @@ +//// [functionVariableInReturnTypeAnnotation.ts] +function bar(): typeof b { + var b = 1; + return undefined; +} + +//// [functionVariableInReturnTypeAnnotation.js] +function bar() { + var b = 1; + return undefined; +} diff --git a/tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts b/tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts new file mode 100644 index 00000000000..c8936034a25 --- /dev/null +++ b/tests/cases/compiler/functionVariableInReturnTypeAnnotation.ts @@ -0,0 +1,4 @@ +function bar(): typeof b { + var b = 1; + return undefined; +} \ No newline at end of file From cf007461b923fa5b826d29daa9ad1d124182d871 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Nov 2015 01:41:41 -0800 Subject: [PATCH 32/35] Fixed invalid code for binding expressions. --- scripts/tslint/preferConstRule.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index e4ffa396fb7..c14264ed7af 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -106,11 +106,23 @@ class PreferConstWalker extends Lint.RuleWalker { if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { const pattern = node as ts.ObjectLiteralExpression; for (const element of pattern.properties) { - if (element.name.kind === ts.SyntaxKind.Identifier) { - this.markAssignment(element.name as ts.Identifier); + const kind = element.kind; + + if (kind === ts.SyntaxKind.ShorthandPropertyAssignment) { + this.markAssignment((element as ts.ShorthandPropertyAssignment).name); } - else if (isBindingPattern(element.name)) { - this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern); + else if (kind === ts.SyntaxKind.PropertyAssignment) { + const rhs = (element as ts.PropertyAssignment).initializer; + + if (rhs.kind === ts.SyntaxKind.Identifier) { + this.markAssignment(rhs as ts.Identifier); + } + else if (rhs.kind === ts.SyntaxKind.ObjectLiteralExpression || rhs.kind === ts.SyntaxKind.ArrayLiteralExpression) { + this.visitBindingLiteralExpression(rhs as ts.ObjectLiteralExpression | ts.ArrayLiteralExpression); + } + else { + // Should be an error, but do nothing for now. + } } } } From 15d689cdcdddb0b926d3e96249cde6f1abe7105c Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Nov 2015 01:46:17 -0800 Subject: [PATCH 33/35] Simplify simplify simplify. --- scripts/tslint/preferConstRule.ts | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index c14264ed7af..a4606481079 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -112,17 +112,10 @@ class PreferConstWalker extends Lint.RuleWalker { this.markAssignment((element as ts.ShorthandPropertyAssignment).name); } else if (kind === ts.SyntaxKind.PropertyAssignment) { - const rhs = (element as ts.PropertyAssignment).initializer; - - if (rhs.kind === ts.SyntaxKind.Identifier) { - this.markAssignment(rhs as ts.Identifier); - } - else if (rhs.kind === ts.SyntaxKind.ObjectLiteralExpression || rhs.kind === ts.SyntaxKind.ArrayLiteralExpression) { - this.visitBindingLiteralExpression(rhs as ts.ObjectLiteralExpression | ts.ArrayLiteralExpression); - } - else { - // Should be an error, but do nothing for now. - } + this.visitLHSExpressions((element as ts.PropertyAssignment).initializer); + } + else { + // Should we throw an exception? } } } From cbb61654fbe95c0d77e7a0ac6c3ba3080ee705c4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Nov 2015 01:52:08 -0800 Subject: [PATCH 34/35] Small refactorings. --- scripts/tslint/preferConstRule.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index a4606481079..2b5b5550c06 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -85,12 +85,12 @@ class PreferConstWalker extends Lint.RuleWalker { visitBinaryExpression(node: ts.BinaryExpression) { if (isAssignmentOperator(node.operatorToken.kind)) { - this.visitLHSExpressions(node.left); + this.visitLeftHandSideExpression(node.left); } super.visitBinaryExpression(node); } - private visitLHSExpressions(node: ts.Expression) { + private visitLeftHandSideExpression(node: ts.Expression) { while (node.kind === ts.SyntaxKind.ParenthesizedExpression) { node = (node as ts.ParenthesizedExpression).expression; } @@ -112,7 +112,7 @@ class PreferConstWalker extends Lint.RuleWalker { this.markAssignment((element as ts.ShorthandPropertyAssignment).name); } else if (kind === ts.SyntaxKind.PropertyAssignment) { - this.visitLHSExpressions((element as ts.PropertyAssignment).initializer); + this.visitLeftHandSideExpression((element as ts.PropertyAssignment).initializer); } else { // Should we throw an exception? @@ -122,7 +122,7 @@ class PreferConstWalker extends Lint.RuleWalker { else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) { const pattern = node as ts.ArrayLiteralExpression; for (const element of pattern.elements) { - this.visitLHSExpressions(element); + this.visitLeftHandSideExpression(element); } } } @@ -150,7 +150,7 @@ class PreferConstWalker extends Lint.RuleWalker { private visitAnyUnaryExpression(node: ts.PrefixUnaryExpression | ts.PostfixUnaryExpression) { if (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken) { - this.visitLHSExpressions(node.operand); + this.visitLeftHandSideExpression(node.operand); } } @@ -216,12 +216,12 @@ class PreferConstWalker extends Lint.RuleWalker { } } - private collectNameIdentifiers(value: ts.VariableDeclaration, node: ts.Identifier | ts.BindingPattern, table: ts.Map) { + private collectNameIdentifiers(declaration: ts.VariableDeclaration, node: ts.Identifier | ts.BindingPattern, table: ts.Map) { if (node.kind === ts.SyntaxKind.Identifier) { - table[(node as ts.Identifier).text] = {declaration: value, usages: 0}; + table[(node as ts.Identifier).text] = { declaration, usages: 0 }; } else { - this.collectBindingPatternIdentifiers(value, node as ts.BindingPattern, table); + this.collectBindingPatternIdentifiers(declaration, node as ts.BindingPattern, table); } } From bd84b844ff8982ee0c2e8a7f9d777925760fea8a Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 18 Nov 2015 10:07:42 -0800 Subject: [PATCH 35/35] Remove unnecessary 'else' block. --- scripts/tslint/preferConstRule.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index 2b5b5550c06..aaa1b0e53d5 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -114,9 +114,6 @@ class PreferConstWalker extends Lint.RuleWalker { else if (kind === ts.SyntaxKind.PropertyAssignment) { this.visitLeftHandSideExpression((element as ts.PropertyAssignment).initializer); } - else { - // Should we throw an exception? - } } } else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) {