From 22eb519b0f6c4c06c71a7c2dd351bbec530f5dd9 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 27 Oct 2017 15:33:30 -0700 Subject: [PATCH 01/25] Return empty doc comment instead of undefined --- src/services/jsDoc.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 3e9913fc6c7..49f13d0b4c3 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -188,24 +188,26 @@ namespace ts.JsDoc { * be performed. */ export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion { + const emptyDocComment = { newText: "", caretOffset: 0 }; + // Check if in a context where we don't want to perform any insertion if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) { - return undefined; + return emptyDocComment; } const tokenAtPos = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); const tokenStart = tokenAtPos.getStart(); if (!tokenAtPos || tokenStart < position) { - return undefined; + return emptyDocComment; } const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos); if (!commentOwnerInfo) { - return undefined; + return emptyDocComment; } const { commentOwner, parameters } = commentOwnerInfo; if (commentOwner.getStart() < position) { - return undefined; + return emptyDocComment; } const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); From b566480aaaf92460b37eb0977b5c07c1c0729c85 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 27 Oct 2017 16:39:33 -0700 Subject: [PATCH 02/25] Update tests to expect empty doc comment template --- src/harness/fourslash.ts | 4 ++-- tests/cases/fourslash/docCommentTemplateEmptyFile.ts | 2 +- tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts | 2 +- .../cases/fourslash/docCommentTemplateInSingleLineComment.ts | 2 +- .../fourslash/docCommentTemplateInsideFunctionDeclaration.ts | 2 +- .../fourslash/docCommentTemplateNamespacesAndModules02.ts | 4 ++-- tests/cases/fourslash/docCommentTemplateRegex.ts | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7ba4e94902d..79cd18da839 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -4050,9 +4050,9 @@ namespace FourSlashInterface { this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, "\r\n"), caretOffset: expectedOffset }); } - public noDocCommentTemplateAt(marker: string | FourSlash.Marker) { + public emptyDocCommentTemplateAt(marker: string | FourSlash.Marker) { this.state.goToMarker(marker); - this.state.verifyDocCommentTemplate(/*expected*/ undefined); + this.state.verifyDocCommentTemplate({ newText: "", caretOffset: 0 }); } public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { diff --git a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts index f04653dc328..6dcb5ef832b 100644 --- a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts +++ b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts @@ -3,4 +3,4 @@ // @Filename: emptyFile.ts /////*0*/ -verify.noDocCommentTemplateAt("0"); +verify.emptyDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts index 6e749782c7d..dc3da4e7599 100644 --- a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts @@ -3,4 +3,4 @@ // @Filename: justAComment.ts //// /* /*0*/ */ -verify.noDocCommentTemplateAt("0"); +verify.emptyDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts index b60fff2d590..472d417a9ff 100644 --- a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts @@ -9,5 +9,5 @@ //// // /*2*/ for (const marker of test.markers()) { - verify.noDocCommentTemplateAt(marker); + verify.emptyDocCommentTemplateAt(marker); } diff --git a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts index e0ebc00dc39..13b6ebc0df6 100644 --- a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts +++ b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts @@ -4,5 +4,5 @@ ////f/*0*/unction /*1*/foo/*2*/(/*3*/) /*4*/{ /*5*/} for (const marker of test.markers()) { - verify.noDocCommentTemplateAt(marker); + verify.emptyDocCommentTemplateAt(marker); } diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts index dad2e9745a9..8bb14bef5df 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts @@ -11,6 +11,6 @@ verify.docCommentTemplateAt("top", /*indentation*/ 8, * */`); -verify.noDocCommentTemplateAt("n2"); +verify.emptyDocCommentTemplateAt("n2"); -verify.noDocCommentTemplateAt("n3"); +verify.emptyDocCommentTemplateAt("n3"); diff --git a/tests/cases/fourslash/docCommentTemplateRegex.ts b/tests/cases/fourslash/docCommentTemplateRegex.ts index 685c1ca5aef..7a6af09aeb5 100644 --- a/tests/cases/fourslash/docCommentTemplateRegex.ts +++ b/tests/cases/fourslash/docCommentTemplateRegex.ts @@ -4,5 +4,5 @@ ////var regex = /*0*///*1*/asdf/*2*/ /*3*///*4*/; for (const marker of test.markers()) { - verify.noDocCommentTemplateAt(marker); + verify.emptyDocCommentTemplateAt(marker); } From 7aeb11b41ea6cdec2fe5994b4a32454876dba8b6 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 27 Oct 2017 16:46:39 -0700 Subject: [PATCH 03/25] Return doc comment template for interfaces and method signatures --- src/services/jsDoc.ts | 4 +++- .../fourslash/docCommentTemplateInterfaces.ts | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/docCommentTemplateInterfaces.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 49f13d0b4c3..0443a950e94 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -266,10 +266,12 @@ namespace ts.JsDoc { case SyntaxKind.FunctionDeclaration: case SyntaxKind.MethodDeclaration: case SyntaxKind.Constructor: - const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration; + case SyntaxKind.MethodSignature: + const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature; return { commentOwner, parameters }; case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: return { commentOwner }; case SyntaxKind.VariableStatement: { diff --git a/tests/cases/fourslash/docCommentTemplateInterfaces.ts b/tests/cases/fourslash/docCommentTemplateInterfaces.ts new file mode 100644 index 00000000000..2faf49351f2 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateInterfaces.ts @@ -0,0 +1,23 @@ +/// + +/////*interfaceFoo*/ +////interface Foo { +//// /*propertybar*/ +//// bar: any; +//// +//// /*methodbaz*/ +//// baz(message: any): void; +////} + +verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 8, +`/** + * + */`); + +verify.emptyDocCommentTemplateAt("propertybar"); + +verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12, + `/** + * + * @param message + */`); \ No newline at end of file From 49772187e51060d0516c0b7644684c13fc05afc7 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 27 Oct 2017 16:53:24 -0700 Subject: [PATCH 04/25] Update comments --- src/services/jsDoc.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 0443a950e94..07db4402cbf 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -177,6 +177,8 @@ namespace ts.JsDoc { * - class declarations * - variable statements * - namespace declarations + * - interface declarations + * - method signatures * * Hosts should ideally check that: * - The line is all whitespace up to 'position' before performing the insertion. @@ -258,7 +260,6 @@ namespace ts.JsDoc { function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { // TODO: add support for: // - enums/enum members - // - interfaces // - property declarations // - potentially property assignments for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { From 976c25c672b9f86129ad1ee549fec7f0b3f0b9fa Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Mon, 30 Oct 2017 15:05:55 -0700 Subject: [PATCH 05/25] Add support for enums and property signatures --- src/services/jsDoc.ts | 5 +- .../fourslash/docCommentTemplateInterfaces.ts | 23 --------- .../docCommentTemplateInterfacesAndEnums.ts | 50 +++++++++++++++++++ 3 files changed, 53 insertions(+), 25 deletions(-) delete mode 100644 tests/cases/fourslash/docCommentTemplateInterfaces.ts create mode 100644 tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 07db4402cbf..622463d96fa 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -259,8 +259,6 @@ namespace ts.JsDoc { } function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { // TODO: add support for: - // - enums/enum members - // - property declarations // - potentially property assignments for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { switch (commentOwner.kind) { @@ -273,6 +271,9 @@ namespace ts.JsDoc { case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.PropertySignature: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.EnumMember: return { commentOwner }; case SyntaxKind.VariableStatement: { diff --git a/tests/cases/fourslash/docCommentTemplateInterfaces.ts b/tests/cases/fourslash/docCommentTemplateInterfaces.ts deleted file mode 100644 index 2faf49351f2..00000000000 --- a/tests/cases/fourslash/docCommentTemplateInterfaces.ts +++ /dev/null @@ -1,23 +0,0 @@ -/// - -/////*interfaceFoo*/ -////interface Foo { -//// /*propertybar*/ -//// bar: any; -//// -//// /*methodbaz*/ -//// baz(message: any): void; -////} - -verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 8, -`/** - * - */`); - -verify.emptyDocCommentTemplateAt("propertybar"); - -verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12, - `/** - * - * @param message - */`); \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts b/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts new file mode 100644 index 00000000000..ed10ba86d98 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts @@ -0,0 +1,50 @@ +/// + +/////*interfaceFoo*/ +////interface Foo { +//// /*propertybar*/ +//// bar: any; +//// +//// /*methodbaz*/ +//// baz(message: any): void; +////} +//// +/////*enumStatus*/ +////const enum Status { +//// /*memberOpen*/ +//// Open, +//// +//// /*memberClosed*/ +//// Closed +////} + +verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 8, +`/** + * + */`); + +verify.docCommentTemplateAt("propertybar", /*expectedOffset*/ 12, + `/** + * + */`); + +verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12, + `/** + * + * @param message + */`); + +verify.docCommentTemplateAt("enumStatus", /*expectedOffset*/ 8, +`/** + * + */`); + +verify.docCommentTemplateAt("memberOpen", /*expectedOffset*/ 12, + `/** + * + */`); + +verify.docCommentTemplateAt("memberClosed", /*expectedOffset*/ 12, + `/** + * + */`); \ No newline at end of file From 509b9ad087c7368d5c27d3fdd4d6feefeae9e8af Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Thu, 2 Nov 2017 09:55:56 -0700 Subject: [PATCH 06/25] Complete to single line jsdoc comment if no params --- src/services/jsDoc.ts | 31 ++++++------ .../docCommentTemplateClassDecl01.ts | 7 +-- .../docCommentTemplateClassDeclMethods01.ts | 14 ++---- .../docCommentTemplateClassDeclMethods02.ts | 7 ++- .../docCommentTemplateIndentation.ts | 13 ++--- .../docCommentTemplateInterfacesAndEnums.ts | 50 ------------------- ...ntTemplateInterfacesEnumsAndTypeAliases.ts | 49 ++++++++++++++++++ ...ocCommentTemplateNamespacesAndModules01.ts | 18 +++---- ...ocCommentTemplateNamespacesAndModules02.ts | 6 +-- ...ocCommentTemplateObjectLiteralMethods01.ts | 7 ++- .../docCommentTemplateVariableStatements01.ts | 6 +-- .../docCommentTemplateVariableStatements02.ts | 6 +-- .../docCommentTemplateVariableStatements03.ts | 12 ++--- 13 files changed, 99 insertions(+), 127 deletions(-) delete mode 100644 tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts create mode 100644 tests/cases/fourslash/docCommentTemplateInterfacesEnumsAndTypeAliases.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 622463d96fa..f1e06a0ffe4 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -212,6 +212,12 @@ namespace ts.JsDoc { return emptyDocComment; } + if (!parameters || parameters.length === 0) { + // if there are no parameters, just complete to a single line JSDoc comment + const singleLineResult = "/** */"; + return { newText: singleLineResult, caretOffset: 3 }; + } + const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); const lineStart = sourceFile.getLineStarts()[posLineAndChar.line]; @@ -220,18 +226,16 @@ namespace ts.JsDoc { const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); let docParams = ""; - if (parameters) { - for (let i = 0; i < parameters.length; i++) { - const currentName = parameters[i].name; - const paramName = currentName.kind === SyntaxKind.Identifier ? - (currentName).escapedText : - "param" + i; - if (isJavaScriptFile) { - docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; - } - else { - docParams += `${indentationStr} * @param ${paramName}${newLine}`; - } + for (let i = 0; i < parameters.length; i++) { + const currentName = parameters[i].name; + const paramName = currentName.kind === SyntaxKind.Identifier ? + (currentName).escapedText : + "param" + i; + if (isJavaScriptFile) { + docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; + } + else { + docParams += `${indentationStr} * @param ${paramName}${newLine}`; } } @@ -258,8 +262,6 @@ namespace ts.JsDoc { readonly parameters?: ReadonlyArray; } function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { - // TODO: add support for: - // - potentially property assignments for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { switch (commentOwner.kind) { case SyntaxKind.FunctionDeclaration: @@ -274,6 +276,7 @@ namespace ts.JsDoc { case SyntaxKind.PropertySignature: case SyntaxKind.EnumDeclaration: case SyntaxKind.EnumMember: + case SyntaxKind.TypeAliasDeclaration: return { commentOwner }; case SyntaxKind.VariableStatement: { diff --git a/tests/cases/fourslash/docCommentTemplateClassDecl01.ts b/tests/cases/fourslash/docCommentTemplateClassDecl01.ts index 5a96f20d2e2..342d35a3b4a 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDecl01.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDecl01.ts @@ -11,8 +11,5 @@ //// } ////} -verify.docCommentTemplateAt("decl", /*newTextOffset*/ 8, -`/** - * - */ -`); +verify.docCommentTemplateAt("decl", /*newTextOffset*/ 3, +"/** */"); diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts index ef4c82e7df7..34e55875676 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts @@ -1,7 +1,7 @@ /// const enum Indentation { - Standard = 8, + Standard = 3, Indented = 12, } @@ -17,15 +17,11 @@ const enum Indentation { ////} verify.docCommentTemplateAt("0", Indentation.Standard, -`/** - * - */`); +"/** */"); -verify.docCommentTemplateAt("1", Indentation.Indented, - `/** - * - */`); +verify.docCommentTemplateAt("1", Indentation.Standard, +"/** */"); verify.docCommentTemplateAt("2", Indentation.Indented, @@ -51,7 +47,7 @@ verify.docCommentTemplateAt("4", Indentation.Indented, * @param param2 */`); -verify.docCommentTemplateAt("5", Indentation.Indented, +verify.docCommentTemplateAt("5", Indentation.Indented, `/** * * @param a diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts index 28da24d381a..a16fbd86064 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts @@ -1,6 +1,7 @@ /// const enum Indentation { + Standard = 3, Indented = 12, } @@ -13,10 +14,8 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -verify.docCommentTemplateAt("0", Indentation.Indented, - `/** - * - */`); +verify.docCommentTemplateAt("0", Indentation.Standard, +"/** */"); verify.docCommentTemplateAt("1", Indentation.Indented, `/** diff --git a/tests/cases/fourslash/docCommentTemplateIndentation.ts b/tests/cases/fourslash/docCommentTemplateIndentation.ts index c3015a6d9dd..bc909aa0265 100644 --- a/tests/cases/fourslash/docCommentTemplateIndentation.ts +++ b/tests/cases/fourslash/docCommentTemplateIndentation.ts @@ -5,13 +5,8 @@ //// /*1*/ /////*0*/ function foo() { } -const noIndentEmptyScaffolding = "/**\r\n * \r\n */"; -const oneIndentEmptyScaffolding = "/**\r\n * \r\n */"; -const twoIndentEmptyScaffolding = "/**\r\n * \r\n */"; -const noIndentOffset = 8; -const oneIndentOffset = noIndentOffset + 4; -const twoIndentOffset = oneIndentOffset + 4; +const singleLineComment = "/** */"; -verify.docCommentTemplateAt("0", noIndentOffset, noIndentEmptyScaffolding); -verify.docCommentTemplateAt("1", oneIndentOffset, oneIndentEmptyScaffolding); -verify.docCommentTemplateAt("2", twoIndentOffset, twoIndentEmptyScaffolding); +verify.docCommentTemplateAt("0", 3, singleLineComment); +verify.docCommentTemplateAt("1", 3, singleLineComment); +verify.docCommentTemplateAt("2", 3, singleLineComment); diff --git a/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts b/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts deleted file mode 100644 index ed10ba86d98..00000000000 --- a/tests/cases/fourslash/docCommentTemplateInterfacesAndEnums.ts +++ /dev/null @@ -1,50 +0,0 @@ -/// - -/////*interfaceFoo*/ -////interface Foo { -//// /*propertybar*/ -//// bar: any; -//// -//// /*methodbaz*/ -//// baz(message: any): void; -////} -//// -/////*enumStatus*/ -////const enum Status { -//// /*memberOpen*/ -//// Open, -//// -//// /*memberClosed*/ -//// Closed -////} - -verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 8, -`/** - * - */`); - -verify.docCommentTemplateAt("propertybar", /*expectedOffset*/ 12, - `/** - * - */`); - -verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12, - `/** - * - * @param message - */`); - -verify.docCommentTemplateAt("enumStatus", /*expectedOffset*/ 8, -`/** - * - */`); - -verify.docCommentTemplateAt("memberOpen", /*expectedOffset*/ 12, - `/** - * - */`); - -verify.docCommentTemplateAt("memberClosed", /*expectedOffset*/ 12, - `/** - * - */`); \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateInterfacesEnumsAndTypeAliases.ts b/tests/cases/fourslash/docCommentTemplateInterfacesEnumsAndTypeAliases.ts new file mode 100644 index 00000000000..d0805d53255 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateInterfacesEnumsAndTypeAliases.ts @@ -0,0 +1,49 @@ +/// + +/////*interfaceFoo*/ +////interface Foo { +//// /*propertybar*/ +//// bar: any; +//// +//// /*methodbaz*/ +//// baz(message: any): void; +//// +//// /*methodUnit*/ +//// unit(): void; +////} +//// +/////*enumStatus*/ +////const enum Status { +//// /*memberOpen*/ +//// Open, +//// +//// /*memberClosed*/ +//// Closed +////} +//// +/////*aliasBar*/ +////type Bar = Foo & any; + +verify.docCommentTemplateAt("interfaceFoo", /*expectedOffset*/ 3, + "/** */"); + +verify.docCommentTemplateAt("propertybar", /*expectedOffset*/ 3, + "/** */"); + +verify.docCommentTemplateAt("methodbaz", /*expectedOffset*/ 12, + `/** + * + * @param message + */`); + +verify.docCommentTemplateAt("methodUnit", /*expectedOffset*/ 3, + "/** */"); + +verify.docCommentTemplateAt("enumStatus", /*expectedOffset*/ 3, + "/** */"); + +verify.docCommentTemplateAt("memberOpen", /*expectedOffset*/ 3, + "/** */"); + +verify.docCommentTemplateAt("memberClosed", /*expectedOffset*/ 3, + "/** */"); \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts index e7e52fd5e94..f3ba46605c4 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts @@ -12,17 +12,11 @@ ////module "ambientModule" { ////} -verify.docCommentTemplateAt("namespaceN", /*indentation*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("namespaceN", /*indentation*/ 3, + "/** */"); -verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("namespaceM", /*indentation*/ 3, + "/** */"); -verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("namespaceM", /*indentation*/ 3, + "/** */"); \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts index 8bb14bef5df..c1b9ed23ad6 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts @@ -6,10 +6,8 @@ //// /*n3*/ n3 { ////} -verify.docCommentTemplateAt("top", /*indentation*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("top", /*indentation*/ 3, +"/** */"); verify.emptyDocCommentTemplateAt("n2"); diff --git a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts index 2ae77d4afac..7fb6156be17 100644 --- a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts @@ -1,6 +1,7 @@ /// const enum Indentation { + Standard = 3, Indented = 12, } @@ -13,10 +14,8 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -verify.docCommentTemplateAt("0", Indentation.Indented, - `/** - * - */`); +verify.docCommentTemplateAt("0", Indentation.Standard, + "/** */"); verify.docCommentTemplateAt("1", Indentation.Indented, `/** diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts index b6243652167..9112c9a8cab 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts @@ -29,10 +29,8 @@ ////} for (const varName of ["a", "b", "c", "d"]) { - verify.docCommentTemplateAt(varName, /*newTextOffset*/ 8, -`/** - * - */`); + verify.docCommentTemplateAt(varName, /*newTextOffset*/ 3, + "/** */"); } verify.docCommentTemplateAt("e", /*newTextOffset*/ 8, diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts index f22e361f63f..8e513780aad 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts @@ -29,8 +29,6 @@ ////}, f2 = null; for (const varName of ["a", "b", "c", "d", "e", "f"]) { - verify.docCommentTemplateAt(varName, /*newTextOffset*/ 8, -`/** - * - */`); + verify.docCommentTemplateAt(varName, /*newTextOffset*/ 3, + "/** */"); } diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts index 195553098f0..6971b86a312 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts @@ -49,10 +49,8 @@ verify.docCommentTemplateAt("c", /*newTextOffset*/ 8, * @param x */`); -verify.docCommentTemplateAt("d", /*newTextOffset*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("d", /*newTextOffset*/ 3, +"/** */"); verify.docCommentTemplateAt("e", /*newTextOffset*/ 8, `/** @@ -60,10 +58,8 @@ verify.docCommentTemplateAt("e", /*newTextOffset*/ 8, * @param param0 */`); -verify.docCommentTemplateAt("f", /*newTextOffset*/ 8, -`/** - * - */`); +verify.docCommentTemplateAt("f", /*newTextOffset*/ 3, +"/** */"); verify.docCommentTemplateAt("g", /*newTextOffset*/ 8, `/** From 12baae6c843044dd03478d04ea862d62368500c2 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Thu, 2 Nov 2017 10:59:58 -0700 Subject: [PATCH 07/25] Revert "Return empty doc comment instead of undefined" This reverts commit 22eb519b0f6c4c06c71a7c2dd351bbec530f5dd9. --- src/services/jsDoc.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index f1e06a0ffe4..c88fe261613 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -190,26 +190,24 @@ namespace ts.JsDoc { * be performed. */ export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion { - const emptyDocComment = { newText: "", caretOffset: 0 }; - // Check if in a context where we don't want to perform any insertion if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) { - return emptyDocComment; + return undefined; } const tokenAtPos = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); const tokenStart = tokenAtPos.getStart(); if (!tokenAtPos || tokenStart < position) { - return emptyDocComment; + return undefined; } const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos); if (!commentOwnerInfo) { - return emptyDocComment; + return undefined; } const { commentOwner, parameters } = commentOwnerInfo; if (commentOwner.getStart() < position) { - return emptyDocComment; + return undefined; } if (!parameters || parameters.length === 0) { From b17b7b9374cbfb7ac2b344b5363eefbac700ddd0 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Thu, 2 Nov 2017 11:00:30 -0700 Subject: [PATCH 08/25] Revert "Update tests to expect empty doc comment template" This reverts commit b566480aaaf92460b37eb0977b5c07c1c0729c85. --- src/harness/fourslash.ts | 4 ++-- tests/cases/fourslash/docCommentTemplateEmptyFile.ts | 2 +- tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts | 2 +- .../cases/fourslash/docCommentTemplateInSingleLineComment.ts | 2 +- .../fourslash/docCommentTemplateInsideFunctionDeclaration.ts | 2 +- .../fourslash/docCommentTemplateNamespacesAndModules02.ts | 4 ++-- tests/cases/fourslash/docCommentTemplateRegex.ts | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 79cd18da839..7ba4e94902d 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -4050,9 +4050,9 @@ namespace FourSlashInterface { this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, "\r\n"), caretOffset: expectedOffset }); } - public emptyDocCommentTemplateAt(marker: string | FourSlash.Marker) { + public noDocCommentTemplateAt(marker: string | FourSlash.Marker) { this.state.goToMarker(marker); - this.state.verifyDocCommentTemplate({ newText: "", caretOffset: 0 }); + this.state.verifyDocCommentTemplate(/*expected*/ undefined); } public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { diff --git a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts index 6dcb5ef832b..f04653dc328 100644 --- a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts +++ b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts @@ -3,4 +3,4 @@ // @Filename: emptyFile.ts /////*0*/ -verify.emptyDocCommentTemplateAt("0"); +verify.noDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts index dc3da4e7599..6e749782c7d 100644 --- a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts @@ -3,4 +3,4 @@ // @Filename: justAComment.ts //// /* /*0*/ */ -verify.emptyDocCommentTemplateAt("0"); +verify.noDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts index 472d417a9ff..b60fff2d590 100644 --- a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts @@ -9,5 +9,5 @@ //// // /*2*/ for (const marker of test.markers()) { - verify.emptyDocCommentTemplateAt(marker); + verify.noDocCommentTemplateAt(marker); } diff --git a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts index 13b6ebc0df6..e0ebc00dc39 100644 --- a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts +++ b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts @@ -4,5 +4,5 @@ ////f/*0*/unction /*1*/foo/*2*/(/*3*/) /*4*/{ /*5*/} for (const marker of test.markers()) { - verify.emptyDocCommentTemplateAt(marker); + verify.noDocCommentTemplateAt(marker); } diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts index c1b9ed23ad6..787e9f04481 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts @@ -9,6 +9,6 @@ verify.docCommentTemplateAt("top", /*indentation*/ 3, "/** */"); -verify.emptyDocCommentTemplateAt("n2"); +verify.noDocCommentTemplateAt("n2"); -verify.emptyDocCommentTemplateAt("n3"); +verify.noDocCommentTemplateAt("n3"); diff --git a/tests/cases/fourslash/docCommentTemplateRegex.ts b/tests/cases/fourslash/docCommentTemplateRegex.ts index 7a6af09aeb5..685c1ca5aef 100644 --- a/tests/cases/fourslash/docCommentTemplateRegex.ts +++ b/tests/cases/fourslash/docCommentTemplateRegex.ts @@ -4,5 +4,5 @@ ////var regex = /*0*///*1*/asdf/*2*/ /*3*///*4*/; for (const marker of test.markers()) { - verify.emptyDocCommentTemplateAt(marker); + verify.noDocCommentTemplateAt(marker); } From b1b611f40adc1ced57f22d9c5ba8abf2569d7502 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Thu, 2 Nov 2017 11:08:26 -0700 Subject: [PATCH 09/25] Add undefined to return type --- src/harness/harnessLanguageService.ts | 2 +- src/services/jsDoc.ts | 3 ++- src/services/services.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 64ef1b552f5..c074b260a1d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -492,7 +492,7 @@ namespace Harness.LanguageService { getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] { return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options))); } - getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion { + getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion | undefined { return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position)); } isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index c88fe261613..78ea0c6b534 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -189,7 +189,8 @@ namespace ts.JsDoc { * @param position The (character-indexed) position in the file where the check should * be performed. */ - export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion { + + export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion | undefined { // Check if in a context where we don't want to perform any insertion if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) { return undefined; diff --git a/src/services/services.ts b/src/services/services.ts index d6e75868852..0df273e8fce 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1791,7 +1791,7 @@ namespace ts { } } - function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion { + function getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion | undefined { return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position); } From 612616a1058d7aa9fc181126f83041549bfbe295 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 3 Nov 2017 09:53:56 -0700 Subject: [PATCH 10/25] Loosen restrictions on jsdoc completion locations --- src/services/jsDoc.ts | 54 ++++++++----------- .../fourslash/docCommentTemplateEmptyFile.ts | 2 +- ...ommentTemplateInsideFunctionDeclaration.ts | 10 ++-- .../fourslash/docCommentTemplateJSXText.ts | 12 +++++ ...ocCommentTemplateNamespacesAndModules02.ts | 4 +- .../fourslash/docCommentTemplateRegex.ts | 8 +-- 6 files changed, 50 insertions(+), 40 deletions(-) create mode 100644 tests/cases/fourslash/docCommentTemplateJSXText.ts diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 78ea0c6b534..109330c177c 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -1,5 +1,6 @@ /* @internal */ namespace ts.JsDoc { + const singleLineTemplate = { newText: "/** */", caretOffset: 3 }; const jsDocTagNames = [ "augments", "author", @@ -170,15 +171,9 @@ namespace ts.JsDoc { /** * Checks if position points to a valid position to add JSDoc comments, and if so, * returns the appropriate template. Otherwise returns an empty string. - * Valid positions are - * - outside of comments, statements, and expressions, and - * - preceding a: - * - function/constructor/method declaration - * - class declarations - * - variable statements - * - namespace declarations - * - interface declarations - * - method signatures + * Invalid positions are + * - within comments, strings (including template literals and regex), and JSXText + * - within a token * * Hosts should ideally check that: * - The line is all whitespace up to 'position' before performing the insertion. @@ -204,17 +199,23 @@ namespace ts.JsDoc { const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos); if (!commentOwnerInfo) { - return undefined; + // if climbing the tree did not find a declaration with parameters, complete to a single line comment + return singleLineTemplate; } const { commentOwner, parameters } = commentOwnerInfo; - if (commentOwner.getStart() < position) { + + if (commentOwner.kind === SyntaxKind.JsxText) { return undefined; } - if (!parameters || parameters.length === 0) { - // if there are no parameters, just complete to a single line JSDoc comment - const singleLineResult = "/** */"; - return { newText: singleLineResult, caretOffset: 3 }; + if (commentOwner.getStart() < position) { + // if climbing the tree found a declaration with parameters but the request was made inside it, complete to a single line comment + return singleLineTemplate; + } + + if (parameters.length === 0) { + // if there are no parameters, complete to a single line comment + return singleLineTemplate; } const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); @@ -258,7 +259,7 @@ namespace ts.JsDoc { interface CommentOwnerInfo { readonly commentOwner: Node; - readonly parameters?: ReadonlyArray; + readonly parameters: ReadonlyArray; } function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { @@ -270,32 +271,18 @@ namespace ts.JsDoc { const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature; return { commentOwner, parameters }; - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.EnumMember: - case SyntaxKind.TypeAliasDeclaration: - return { commentOwner }; - case SyntaxKind.VariableStatement: { const varStatement = commentOwner; const varDeclarations = varStatement.declarationList.declarations; const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer ? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer) : undefined; - return { commentOwner, parameters }; + return parameters ? { commentOwner, parameters } : undefined; } case SyntaxKind.SourceFile: return undefined; - case SyntaxKind.ModuleDeclaration: - // If in walking up the tree, we hit a a nested namespace declaration, - // then we must be somewhere within a dotted namespace name; however we don't - // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'. - return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner }; - case SyntaxKind.BinaryExpression: { const be = commentOwner as BinaryExpression; if (getSpecialPropertyAssignmentKind(be) === ts.SpecialPropertyAssignmentKind.None) { @@ -304,6 +291,11 @@ namespace ts.JsDoc { const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray; return { commentOwner, parameters }; } + + case SyntaxKind.JsxText: { + const parameters: ReadonlyArray = emptyArray; + return { commentOwner, parameters }; + } } } } diff --git a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts index f04653dc328..064306e3fbd 100644 --- a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts +++ b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts @@ -3,4 +3,4 @@ // @Filename: emptyFile.ts /////*0*/ -verify.noDocCommentTemplateAt("0"); +verify.docCommentTemplateAt("0", 3, "/** */"); diff --git a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts index e0ebc00dc39..67a11a27133 100644 --- a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts +++ b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts @@ -3,6 +3,10 @@ // @Filename: functionDecl.ts ////f/*0*/unction /*1*/foo/*2*/(/*3*/) /*4*/{ /*5*/} -for (const marker of test.markers()) { - verify.noDocCommentTemplateAt(marker); -} +verify.noDocCommentTemplateAt("0"); + +verify.docCommentTemplateAt("1", 3, "/** */"); +verify.docCommentTemplateAt("2", 3, "/** */"); +verify.docCommentTemplateAt("3", 3, "/** */"); +verify.docCommentTemplateAt("4", 3, "/** */"); +verify.docCommentTemplateAt("5", 3, "/** */"); diff --git a/tests/cases/fourslash/docCommentTemplateJSXText.ts b/tests/cases/fourslash/docCommentTemplateJSXText.ts new file mode 100644 index 00000000000..845f969f4e3 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateJSXText.ts @@ -0,0 +1,12 @@ +/// + +//@Filename: file.tsx +//// +//// var x =
+//// /*0*/hello/*1*/ +//// /*2*/goodbye/*3*/ +////
; + +for (const marker in test.markers()) { + verify.noDocCommentTemplateAt(marker); +} \ No newline at end of file diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts index 787e9f04481..3beb9368661 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts @@ -9,6 +9,6 @@ verify.docCommentTemplateAt("top", /*indentation*/ 3, "/** */"); -verify.noDocCommentTemplateAt("n2"); +verify.docCommentTemplateAt("n2", 3, "/** */"); -verify.noDocCommentTemplateAt("n3"); +verify.docCommentTemplateAt("n3", 3, "/** */"); diff --git a/tests/cases/fourslash/docCommentTemplateRegex.ts b/tests/cases/fourslash/docCommentTemplateRegex.ts index 685c1ca5aef..c1368190ca2 100644 --- a/tests/cases/fourslash/docCommentTemplateRegex.ts +++ b/tests/cases/fourslash/docCommentTemplateRegex.ts @@ -3,6 +3,8 @@ // @Filename: regex.ts ////var regex = /*0*///*1*/asdf/*2*/ /*3*///*4*/; -for (const marker of test.markers()) { - verify.noDocCommentTemplateAt(marker); -} +verify.docCommentTemplateAt("0", 3, "/** */"); +verify.noDocCommentTemplateAt("1"); +verify.noDocCommentTemplateAt("2"); +verify.noDocCommentTemplateAt("3"); +verify.docCommentTemplateAt("4", 3, "/** */"); \ No newline at end of file From 21093503a8f0fab321c85e9f830219c2bfc4d451 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 3 Nov 2017 11:19:53 -0700 Subject: [PATCH 11/25] Respond to CR --- src/services/jsDoc.ts | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 109330c177c..bb2cfb03e47 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -208,13 +208,9 @@ namespace ts.JsDoc { return undefined; } - if (commentOwner.getStart() < position) { - // if climbing the tree found a declaration with parameters but the request was made inside it, complete to a single line comment - return singleLineTemplate; - } - - if (parameters.length === 0) { - // if there are no parameters, complete to a single line comment + if (commentOwner.getStart() < position || parameters.length === 0) { + // if climbing the tree found a declaration with parameters but the request was made inside it + // or if there are no parameters, complete to a single line comment return singleLineTemplate; } @@ -225,19 +221,11 @@ namespace ts.JsDoc { const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character).replace(/\S/i, () => " "); const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); - let docParams = ""; - for (let i = 0; i < parameters.length; i++) { - const currentName = parameters[i].name; - const paramName = currentName.kind === SyntaxKind.Identifier ? - (currentName).escapedText : - "param" + i; - if (isJavaScriptFile) { - docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; - } - else { - docParams += `${indentationStr} * @param ${paramName}${newLine}`; - } - } + const docParams = parameters.map(({name}, i) => { + const nameText = isIdentifier(name) ? name.text : `param${i}`; + const type = isJavaScriptFile ? "{any} " : ""; + return `${indentationStr} * @param ${type}${nameText}${newLine}`; + }).join(""); // A doc comment consists of the following // * The opening comment line From d2114e1b9eb8cfc6fabeb6b775b1aa3e29625027 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 3 Nov 2017 16:14:47 -0700 Subject: [PATCH 12/25] Rename offsets in tests --- .../docCommentTemplateClassDeclMethods01.ts | 18 ++++++++---------- .../docCommentTemplateClassDeclMethods02.ts | 10 ++++------ ...docCommentTemplateObjectLiteralMethods01.ts | 10 ++++------ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts index 34e55875676..2e729243497 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts @@ -1,9 +1,7 @@ /// -const enum Indentation { - Standard = 3, - Indented = 12, -} +const singleLineOffset = 3; +const multiLineOffset = 12; ////class C { @@ -16,22 +14,22 @@ const enum Indentation { //// } ////} -verify.docCommentTemplateAt("0", Indentation.Standard, +verify.docCommentTemplateAt("0", singleLineOffset, "/** */"); -verify.docCommentTemplateAt("1", Indentation.Standard, +verify.docCommentTemplateAt("1", singleLineOffset, "/** */"); -verify.docCommentTemplateAt("2", Indentation.Indented, +verify.docCommentTemplateAt("2", multiLineOffset, `/** * * @param a */ `); -verify.docCommentTemplateAt("3", Indentation.Indented, +verify.docCommentTemplateAt("3", multiLineOffset, `/** * * @param a @@ -39,7 +37,7 @@ verify.docCommentTemplateAt("3", Indentation.Indented, */ `); -verify.docCommentTemplateAt("4", Indentation.Indented, +verify.docCommentTemplateAt("4", multiLineOffset, `/** * * @param a @@ -47,7 +45,7 @@ verify.docCommentTemplateAt("4", Indentation.Indented, * @param param2 */`); -verify.docCommentTemplateAt("5", Indentation.Indented, +verify.docCommentTemplateAt("5", multiLineOffset, `/** * * @param a diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts index a16fbd86064..7a35e60ae9e 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts @@ -1,9 +1,7 @@ /// -const enum Indentation { - Standard = 3, - Indented = 12, -} +const singleLineOffset = 3; +const multiLineOffset = 12; ////class C { //// /*0*/ @@ -14,10 +12,10 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -verify.docCommentTemplateAt("0", Indentation.Standard, +verify.docCommentTemplateAt("0", singleLineOffset, "/** */"); -verify.docCommentTemplateAt("1", Indentation.Indented, +verify.docCommentTemplateAt("1", multiLineOffset, `/** * * @param x diff --git a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts index 7fb6156be17..5121957a718 100644 --- a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts @@ -1,9 +1,7 @@ /// -const enum Indentation { - Standard = 3, - Indented = 12, -} +const singleLineOffset = 3; +const multiLineOffset = 12; ////var x = { //// /*0*/ @@ -14,10 +12,10 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -verify.docCommentTemplateAt("0", Indentation.Standard, +verify.docCommentTemplateAt("0", singleLineOffset, "/** */"); -verify.docCommentTemplateAt("1", Indentation.Indented, +verify.docCommentTemplateAt("1", multiLineOffset, `/** * * @param x From 45c53e0dccdd20ba181111bcdd4491b3e37779fa Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 08:08:05 -0700 Subject: [PATCH 13/25] Check combined modifiers in mappedTypeRelatedTo --- src/compiler/checker.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b598be408c1..1229a0dcf43 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -529,6 +529,11 @@ namespace ts { Strict, } + const enum MappedTypeModifiers { + Readonly = 1 << 0, + Optional = 1 << 1, + } + const builtinGlobals = createSymbolTable(); builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol); @@ -5875,6 +5880,17 @@ namespace ts { return type.modifiersType; } + function getMappedTypeModifiers(type: MappedType): MappedTypeModifiers { + return (type.declaration.readonlyToken ? MappedTypeModifiers.Readonly : 0) | + (type.declaration.questionToken ? MappedTypeModifiers.Optional : 0); + } + + function getCombinedMappedTypeModifiers(type: MappedType): MappedTypeModifiers { + const modifiersType = getModifiersTypeFromMappedType(type); + return getMappedTypeModifiers(type) | + (isGenericMappedType(modifiersType) ? getMappedTypeModifiers(modifiersType) : 0); + } + function isPartialMappedType(type: Type) { return getObjectFlags(type) & ObjectFlags.Mapped && !!(type).declaration.questionToken; } @@ -9592,13 +9608,10 @@ namespace ts { // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { - const sourceReadonly = !!source.declaration.readonlyToken; - const sourceOptional = !!source.declaration.questionToken; - const targetReadonly = !!target.declaration.readonlyToken; - const targetOptional = !!target.declaration.questionToken; - const modifiersRelated = relation === identityRelation ? - sourceReadonly === targetReadonly && sourceOptional === targetOptional : - relation === comparableRelation || !sourceOptional || targetOptional; + const modifiersRelated = relation === comparableRelation || ( + relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : + !(getCombinedMappedTypeModifiers(source) & MappedTypeModifiers.Optional) || + getCombinedMappedTypeModifiers(target) & MappedTypeModifiers.Optional); if (modifiersRelated) { let result: Ternary; if (result = isRelatedTo(getConstraintTypeFromMappedType(target), getConstraintTypeFromMappedType(source), reportErrors)) { From 9619dc14f963ba48b1e867230809a8233a9dcab5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 08:08:28 -0700 Subject: [PATCH 14/25] Add tests --- .../reference/mappedTypes5.errors.txt | 73 +++++ tests/baselines/reference/mappedTypes5.js | 95 ++++++ .../baselines/reference/mappedTypes5.symbols | 279 +++++++++++++++++ tests/baselines/reference/mappedTypes5.types | 292 ++++++++++++++++++ .../conformance/types/mapped/mappedTypes5.ts | 62 ++++ 5 files changed, 801 insertions(+) create mode 100644 tests/baselines/reference/mappedTypes5.errors.txt create mode 100644 tests/baselines/reference/mappedTypes5.js create mode 100644 tests/baselines/reference/mappedTypes5.symbols create mode 100644 tests/baselines/reference/mappedTypes5.types create mode 100644 tests/cases/conformance/types/mapped/mappedTypes5.ts diff --git a/tests/baselines/reference/mappedTypes5.errors.txt b/tests/baselines/reference/mappedTypes5.errors.txt new file mode 100644 index 00000000000..d0c32cd1dd9 --- /dev/null +++ b/tests/baselines/reference/mappedTypes5.errors.txt @@ -0,0 +1,73 @@ +tests/cases/conformance/types/mapped/mappedTypes5.ts(6,9): error TS2322: Type 'Partial' is not assignable to type 'Readonly'. +tests/cases/conformance/types/mapped/mappedTypes5.ts(8,9): error TS2322: Type 'Partial>' is not assignable to type 'Readonly'. +tests/cases/conformance/types/mapped/mappedTypes5.ts(9,9): error TS2322: Type 'Readonly>' is not assignable to type 'Readonly'. + + +==== tests/cases/conformance/types/mapped/mappedTypes5.ts (3 errors) ==== + function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { + let a1: Partial = p; + let a2: Partial = r; + let a3: Partial = pr; + let a4: Partial = rp; + let b1: Readonly = p; // Error + ~~ +!!! error TS2322: Type 'Partial' is not assignable to type 'Readonly'. + let b2: Readonly = r; + let b3: Readonly = pr; // Error + ~~ +!!! error TS2322: Type 'Partial>' is not assignable to type 'Readonly'. + let b4: Readonly = rp; // Error + ~~ +!!! error TS2322: Type 'Readonly>' is not assignable to type 'Readonly'. + let c1: Partial> = p; + let c2: Partial> = r; + let c3: Partial> = pr; + let c4: Partial> = rp; + let d1: Readonly> = p; + let d2: Readonly> = r; + let d3: Readonly> = pr; + let d4: Readonly> = rp; + } + + // Repro from #17682 + + type State = { + [key: string]: string | boolean | number | null; + }; + + type Args1 = { + readonly previous: Readonly>; + readonly current: Readonly>; + }; + + type Args2 = { + readonly previous: Partial>; + readonly current: Partial>; + }; + + function doit() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args1 = { previous, current }; + let args2: Args2 = { previous, current }; + } + + type State2 = { foo: number, bar: string }; + + type Args3 = { + readonly previous: Readonly>; + readonly current: Readonly>; + }; + + type Args4 = { + readonly previous: Partial>; + readonly current: Partial>; + }; + + function doit2() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args3 = { previous, current }; + let args2: Args4 = { previous, current }; + } + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypes5.js b/tests/baselines/reference/mappedTypes5.js new file mode 100644 index 00000000000..6f20b71ed7b --- /dev/null +++ b/tests/baselines/reference/mappedTypes5.js @@ -0,0 +1,95 @@ +//// [mappedTypes5.ts] +function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { + let a1: Partial = p; + let a2: Partial = r; + let a3: Partial = pr; + let a4: Partial = rp; + let b1: Readonly = p; // Error + let b2: Readonly = r; + let b3: Readonly = pr; // Error + let b4: Readonly = rp; // Error + let c1: Partial> = p; + let c2: Partial> = r; + let c3: Partial> = pr; + let c4: Partial> = rp; + let d1: Readonly> = p; + let d2: Readonly> = r; + let d3: Readonly> = pr; + let d4: Readonly> = rp; +} + +// Repro from #17682 + +type State = { + [key: string]: string | boolean | number | null; +}; + +type Args1 = { + readonly previous: Readonly>; + readonly current: Readonly>; +}; + +type Args2 = { + readonly previous: Partial>; + readonly current: Partial>; +}; + +function doit() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args1 = { previous, current }; + let args2: Args2 = { previous, current }; +} + +type State2 = { foo: number, bar: string }; + +type Args3 = { + readonly previous: Readonly>; + readonly current: Readonly>; +}; + +type Args4 = { + readonly previous: Partial>; + readonly current: Partial>; +}; + +function doit2() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args3 = { previous, current }; + let args2: Args4 = { previous, current }; +} + + +//// [mappedTypes5.js] +"use strict"; +function f(p, r, pr, rp) { + var a1 = p; + var a2 = r; + var a3 = pr; + var a4 = rp; + var b1 = p; // Error + var b2 = r; + var b3 = pr; // Error + var b4 = rp; // Error + var c1 = p; + var c2 = r; + var c3 = pr; + var c4 = rp; + var d1 = p; + var d2 = r; + var d3 = pr; + var d4 = rp; +} +function doit() { + var previous = Object.create(null); + var current = Object.create(null); + var args1 = { previous: previous, current: current }; + var args2 = { previous: previous, current: current }; +} +function doit2() { + var previous = Object.create(null); + var current = Object.create(null); + var args1 = { previous: previous, current: current }; + var args2 = { previous: previous, current: current }; +} diff --git a/tests/baselines/reference/mappedTypes5.symbols b/tests/baselines/reference/mappedTypes5.symbols new file mode 100644 index 00000000000..7a499c4c4e9 --- /dev/null +++ b/tests/baselines/reference/mappedTypes5.symbols @@ -0,0 +1,279 @@ +=== tests/cases/conformance/types/mapped/mappedTypes5.ts === +function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { +>f : Symbol(f, Decl(mappedTypes5.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>p : Symbol(p, Decl(mappedTypes5.ts, 0, 14)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>r : Symbol(r, Decl(mappedTypes5.ts, 0, 28)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>pr : Symbol(pr, Decl(mappedTypes5.ts, 0, 44)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>rp : Symbol(rp, Decl(mappedTypes5.ts, 0, 70)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) + + let a1: Partial = p; +>a1 : Symbol(a1, Decl(mappedTypes5.ts, 1, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>p : Symbol(p, Decl(mappedTypes5.ts, 0, 14)) + + let a2: Partial = r; +>a2 : Symbol(a2, Decl(mappedTypes5.ts, 2, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>r : Symbol(r, Decl(mappedTypes5.ts, 0, 28)) + + let a3: Partial = pr; +>a3 : Symbol(a3, Decl(mappedTypes5.ts, 3, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>pr : Symbol(pr, Decl(mappedTypes5.ts, 0, 44)) + + let a4: Partial = rp; +>a4 : Symbol(a4, Decl(mappedTypes5.ts, 4, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>rp : Symbol(rp, Decl(mappedTypes5.ts, 0, 70)) + + let b1: Readonly = p; // Error +>b1 : Symbol(b1, Decl(mappedTypes5.ts, 5, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>p : Symbol(p, Decl(mappedTypes5.ts, 0, 14)) + + let b2: Readonly = r; +>b2 : Symbol(b2, Decl(mappedTypes5.ts, 6, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>r : Symbol(r, Decl(mappedTypes5.ts, 0, 28)) + + let b3: Readonly = pr; // Error +>b3 : Symbol(b3, Decl(mappedTypes5.ts, 7, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>pr : Symbol(pr, Decl(mappedTypes5.ts, 0, 44)) + + let b4: Readonly = rp; // Error +>b4 : Symbol(b4, Decl(mappedTypes5.ts, 8, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>rp : Symbol(rp, Decl(mappedTypes5.ts, 0, 70)) + + let c1: Partial> = p; +>c1 : Symbol(c1, Decl(mappedTypes5.ts, 9, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>p : Symbol(p, Decl(mappedTypes5.ts, 0, 14)) + + let c2: Partial> = r; +>c2 : Symbol(c2, Decl(mappedTypes5.ts, 10, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>r : Symbol(r, Decl(mappedTypes5.ts, 0, 28)) + + let c3: Partial> = pr; +>c3 : Symbol(c3, Decl(mappedTypes5.ts, 11, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>pr : Symbol(pr, Decl(mappedTypes5.ts, 0, 44)) + + let c4: Partial> = rp; +>c4 : Symbol(c4, Decl(mappedTypes5.ts, 12, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>rp : Symbol(rp, Decl(mappedTypes5.ts, 0, 70)) + + let d1: Readonly> = p; +>d1 : Symbol(d1, Decl(mappedTypes5.ts, 13, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>p : Symbol(p, Decl(mappedTypes5.ts, 0, 14)) + + let d2: Readonly> = r; +>d2 : Symbol(d2, Decl(mappedTypes5.ts, 14, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>r : Symbol(r, Decl(mappedTypes5.ts, 0, 28)) + + let d3: Readonly> = pr; +>d3 : Symbol(d3, Decl(mappedTypes5.ts, 15, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>pr : Symbol(pr, Decl(mappedTypes5.ts, 0, 44)) + + let d4: Readonly> = rp; +>d4 : Symbol(d4, Decl(mappedTypes5.ts, 16, 7)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 0, 11)) +>rp : Symbol(rp, Decl(mappedTypes5.ts, 0, 70)) +} + +// Repro from #17682 + +type State = { +>State : Symbol(State, Decl(mappedTypes5.ts, 17, 1)) + + [key: string]: string | boolean | number | null; +>key : Symbol(key, Decl(mappedTypes5.ts, 22, 5)) + +}; + +type Args1 = { +>Args1 : Symbol(Args1, Decl(mappedTypes5.ts, 23, 2)) +>T : Symbol(T, Decl(mappedTypes5.ts, 25, 11)) +>State : Symbol(State, Decl(mappedTypes5.ts, 17, 1)) + + readonly previous: Readonly>; +>previous : Symbol(previous, Decl(mappedTypes5.ts, 25, 31)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 25, 11)) + + readonly current: Readonly>; +>current : Symbol(current, Decl(mappedTypes5.ts, 26, 44)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 25, 11)) + +}; + +type Args2 = { +>Args2 : Symbol(Args2, Decl(mappedTypes5.ts, 28, 2)) +>T : Symbol(T, Decl(mappedTypes5.ts, 30, 11)) +>State : Symbol(State, Decl(mappedTypes5.ts, 17, 1)) + + readonly previous: Partial>; +>previous : Symbol(previous, Decl(mappedTypes5.ts, 30, 31)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 30, 11)) + + readonly current: Partial>; +>current : Symbol(current, Decl(mappedTypes5.ts, 31, 44)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 30, 11)) + +}; + +function doit() { +>doit : Symbol(doit, Decl(mappedTypes5.ts, 33, 2)) +>T : Symbol(T, Decl(mappedTypes5.ts, 35, 14)) +>State : Symbol(State, Decl(mappedTypes5.ts, 17, 1)) + + let previous: Partial = Object.create(null); +>previous : Symbol(previous, Decl(mappedTypes5.ts, 36, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 35, 14)) +>Object.create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + let current: Partial = Object.create(null); +>current : Symbol(current, Decl(mappedTypes5.ts, 37, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypes5.ts, 35, 14)) +>Object.create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + let args1: Args1 = { previous, current }; +>args1 : Symbol(args1, Decl(mappedTypes5.ts, 38, 7)) +>Args1 : Symbol(Args1, Decl(mappedTypes5.ts, 23, 2)) +>T : Symbol(T, Decl(mappedTypes5.ts, 35, 14)) +>previous : Symbol(previous, Decl(mappedTypes5.ts, 38, 27)) +>current : Symbol(current, Decl(mappedTypes5.ts, 38, 37)) + + let args2: Args2 = { previous, current }; +>args2 : Symbol(args2, Decl(mappedTypes5.ts, 39, 7)) +>Args2 : Symbol(Args2, Decl(mappedTypes5.ts, 28, 2)) +>T : Symbol(T, Decl(mappedTypes5.ts, 35, 14)) +>previous : Symbol(previous, Decl(mappedTypes5.ts, 39, 27)) +>current : Symbol(current, Decl(mappedTypes5.ts, 39, 37)) +} + +type State2 = { foo: number, bar: string }; +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) +>foo : Symbol(foo, Decl(mappedTypes5.ts, 42, 15)) +>bar : Symbol(bar, Decl(mappedTypes5.ts, 42, 28)) + +type Args3 = { +>Args3 : Symbol(Args3, Decl(mappedTypes5.ts, 42, 43)) + + readonly previous: Readonly>; +>previous : Symbol(previous, Decl(mappedTypes5.ts, 44, 14)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) + + readonly current: Readonly>; +>current : Symbol(current, Decl(mappedTypes5.ts, 45, 49)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) + +}; + +type Args4 = { +>Args4 : Symbol(Args4, Decl(mappedTypes5.ts, 47, 2)) + + readonly previous: Partial>; +>previous : Symbol(previous, Decl(mappedTypes5.ts, 49, 14)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) + + readonly current: Partial>; +>current : Symbol(current, Decl(mappedTypes5.ts, 50, 49)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) + +}; + +function doit2() { +>doit2 : Symbol(doit2, Decl(mappedTypes5.ts, 52, 2)) + + let previous: Partial = Object.create(null); +>previous : Symbol(previous, Decl(mappedTypes5.ts, 55, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) +>Object.create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + let current: Partial = Object.create(null); +>current : Symbol(current, Decl(mappedTypes5.ts, 56, 7)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>State2 : Symbol(State2, Decl(mappedTypes5.ts, 40, 1)) +>Object.create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>create : Symbol(ObjectConstructor.create, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + let args1: Args3 = { previous, current }; +>args1 : Symbol(args1, Decl(mappedTypes5.ts, 57, 7)) +>Args3 : Symbol(Args3, Decl(mappedTypes5.ts, 42, 43)) +>previous : Symbol(previous, Decl(mappedTypes5.ts, 57, 24)) +>current : Symbol(current, Decl(mappedTypes5.ts, 57, 34)) + + let args2: Args4 = { previous, current }; +>args2 : Symbol(args2, Decl(mappedTypes5.ts, 58, 7)) +>Args4 : Symbol(Args4, Decl(mappedTypes5.ts, 47, 2)) +>previous : Symbol(previous, Decl(mappedTypes5.ts, 58, 24)) +>current : Symbol(current, Decl(mappedTypes5.ts, 58, 34)) +} + diff --git a/tests/baselines/reference/mappedTypes5.types b/tests/baselines/reference/mappedTypes5.types new file mode 100644 index 00000000000..2cbc66523e2 --- /dev/null +++ b/tests/baselines/reference/mappedTypes5.types @@ -0,0 +1,292 @@ +=== tests/cases/conformance/types/mapped/mappedTypes5.ts === +function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { +>f : (p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) => void +>T : T +>p : Partial +>Partial : Partial +>T : T +>r : Readonly +>Readonly : Readonly +>T : T +>pr : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T +>rp : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T + + let a1: Partial = p; +>a1 : Partial +>Partial : Partial +>T : T +>p : Partial + + let a2: Partial = r; +>a2 : Partial +>Partial : Partial +>T : T +>r : Readonly + + let a3: Partial = pr; +>a3 : Partial +>Partial : Partial +>T : T +>pr : Partial> + + let a4: Partial = rp; +>a4 : Partial +>Partial : Partial +>T : T +>rp : Readonly> + + let b1: Readonly = p; // Error +>b1 : Readonly +>Readonly : Readonly +>T : T +>p : Partial + + let b2: Readonly = r; +>b2 : Readonly +>Readonly : Readonly +>T : T +>r : Readonly + + let b3: Readonly = pr; // Error +>b3 : Readonly +>Readonly : Readonly +>T : T +>pr : Partial> + + let b4: Readonly = rp; // Error +>b4 : Readonly +>Readonly : Readonly +>T : T +>rp : Readonly> + + let c1: Partial> = p; +>c1 : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T +>p : Partial + + let c2: Partial> = r; +>c2 : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T +>r : Readonly + + let c3: Partial> = pr; +>c3 : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T +>pr : Partial> + + let c4: Partial> = rp; +>c4 : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T +>rp : Readonly> + + let d1: Readonly> = p; +>d1 : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T +>p : Partial + + let d2: Readonly> = r; +>d2 : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T +>r : Readonly + + let d3: Readonly> = pr; +>d3 : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T +>pr : Partial> + + let d4: Readonly> = rp; +>d4 : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T +>rp : Readonly> +} + +// Repro from #17682 + +type State = { +>State : State + + [key: string]: string | boolean | number | null; +>key : string +>null : null + +}; + +type Args1 = { +>Args1 : Args1 +>T : T +>State : State + + readonly previous: Readonly>; +>previous : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T + + readonly current: Readonly>; +>current : Readonly> +>Readonly : Readonly +>Partial : Partial +>T : T + +}; + +type Args2 = { +>Args2 : Args2 +>T : T +>State : State + + readonly previous: Partial>; +>previous : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T + + readonly current: Partial>; +>current : Partial> +>Partial : Partial +>Readonly : Readonly +>T : T + +}; + +function doit() { +>doit : () => void +>T : T +>State : State + + let previous: Partial = Object.create(null); +>previous : Partial +>Partial : Partial +>T : T +>Object.create(null) : any +>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>Object : ObjectConstructor +>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>null : null + + let current: Partial = Object.create(null); +>current : Partial +>Partial : Partial +>T : T +>Object.create(null) : any +>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>Object : ObjectConstructor +>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>null : null + + let args1: Args1 = { previous, current }; +>args1 : Args1 +>Args1 : Args1 +>T : T +>{ previous, current } : { previous: Partial; current: Partial; } +>previous : Partial +>current : Partial + + let args2: Args2 = { previous, current }; +>args2 : Args2 +>Args2 : Args2 +>T : T +>{ previous, current } : { previous: Partial; current: Partial; } +>previous : Partial +>current : Partial +} + +type State2 = { foo: number, bar: string }; +>State2 : State2 +>foo : number +>bar : string + +type Args3 = { +>Args3 : Args3 + + readonly previous: Readonly>; +>previous : Readonly> +>Readonly : Readonly +>Partial : Partial +>State2 : State2 + + readonly current: Readonly>; +>current : Readonly> +>Readonly : Readonly +>Partial : Partial +>State2 : State2 + +}; + +type Args4 = { +>Args4 : Args4 + + readonly previous: Partial>; +>previous : Partial> +>Partial : Partial +>Readonly : Readonly +>State2 : State2 + + readonly current: Partial>; +>current : Partial> +>Partial : Partial +>Readonly : Readonly +>State2 : State2 + +}; + +function doit2() { +>doit2 : () => void + + let previous: Partial = Object.create(null); +>previous : Partial +>Partial : Partial +>State2 : State2 +>Object.create(null) : any +>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>Object : ObjectConstructor +>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>null : null + + let current: Partial = Object.create(null); +>current : Partial +>Partial : Partial +>State2 : State2 +>Object.create(null) : any +>Object.create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>Object : ObjectConstructor +>create : { (o: object | null): any; (o: object | null, properties: PropertyDescriptorMap & ThisType): any; } +>null : null + + let args1: Args3 = { previous, current }; +>args1 : Args3 +>Args3 : Args3 +>{ previous, current } : { previous: Partial; current: Partial; } +>previous : Partial +>current : Partial + + let args2: Args4 = { previous, current }; +>args2 : Args4 +>Args4 : Args4 +>{ previous, current } : { previous: Partial; current: Partial; } +>previous : Partial +>current : Partial +} + diff --git a/tests/cases/conformance/types/mapped/mappedTypes5.ts b/tests/cases/conformance/types/mapped/mappedTypes5.ts new file mode 100644 index 00000000000..38a010da0f5 --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypes5.ts @@ -0,0 +1,62 @@ +// @strict: true + +function f(p: Partial, r: Readonly, pr: Partial>, rp: Readonly>) { + let a1: Partial = p; + let a2: Partial = r; + let a3: Partial = pr; + let a4: Partial = rp; + let b1: Readonly = p; // Error + let b2: Readonly = r; + let b3: Readonly = pr; // Error + let b4: Readonly = rp; // Error + let c1: Partial> = p; + let c2: Partial> = r; + let c3: Partial> = pr; + let c4: Partial> = rp; + let d1: Readonly> = p; + let d2: Readonly> = r; + let d3: Readonly> = pr; + let d4: Readonly> = rp; +} + +// Repro from #17682 + +type State = { + [key: string]: string | boolean | number | null; +}; + +type Args1 = { + readonly previous: Readonly>; + readonly current: Readonly>; +}; + +type Args2 = { + readonly previous: Partial>; + readonly current: Partial>; +}; + +function doit() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args1 = { previous, current }; + let args2: Args2 = { previous, current }; +} + +type State2 = { foo: number, bar: string }; + +type Args3 = { + readonly previous: Readonly>; + readonly current: Readonly>; +}; + +type Args4 = { + readonly previous: Partial>; + readonly current: Partial>; +}; + +function doit2() { + let previous: Partial = Object.create(null); + let current: Partial = Object.create(null); + let args1: Args3 = { previous, current }; + let args2: Args4 = { previous, current }; +} From a8160de49c9b74fe536705a1edd35618c1e855e6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 17:26:02 -0700 Subject: [PATCH 15/25] Empty array literal has a non-inferrable element type --- src/compiler/checker.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2e45b2ccb0..5b5bc92350b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -281,6 +281,7 @@ namespace ts { const voidType = createIntrinsicType(TypeFlags.Void, "void"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); + const implicitNeverType = createIntrinsicType(TypeFlags.Never, "never"); const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); @@ -7684,7 +7685,7 @@ namespace ts { function getIndexTypeOrString(type: Type): Type { const indexType = getIndexType(type); - return indexType !== neverType ? indexType : stringType; + return indexType.flags & TypeFlags.Never ? stringType : indexType; } function getTypeFromTypeOperatorNode(node: TypeOperatorNode) { @@ -8861,8 +8862,8 @@ namespace ts { function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map, errorReporter?: ErrorReporter) { const s = source.flags; const t = target.flags; - if (t & TypeFlags.Never) return false; if (t & TypeFlags.Any || s & TypeFlags.Never) return true; + if (t & TypeFlags.Never) return false; if (s & TypeFlags.StringLike && t & TypeFlags.String) return true; if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral && t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) && @@ -10323,7 +10324,7 @@ namespace ts { function isEmptyArrayLiteralType(type: Type): boolean { const elementType = isArrayType(type) ? (type).typeArguments[0] : undefined; - return elementType === undefinedWideningType || elementType === neverType; + return elementType === undefinedWideningType || elementType === implicitNeverType; } function isTupleLikeType(type: Type): boolean { @@ -10880,9 +10881,10 @@ namespace ts { // Because the anyFunctionType is internal, it should not be exposed to the user by adding // it as an inference candidate. Hopefully, a better candidate will come along that does // not contain anyFunctionType when we come back to this argument for its second round - // of inference. Also, we exclude inferences for silentNeverType which is used as a wildcard - // when constructing types from type parameters that had no inference candidates. - if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) { + // of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard + // when constructing types from type parameters that had no inference candidates) and + // implicitNeverType (which is used as the element type for empty array literals). + if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) { return; } const inference = getInferenceInfoForType(target); @@ -13923,7 +13925,7 @@ namespace ts { } return createArrayType(elementTypes.length ? getUnionType(elementTypes, /*subtypeReduction*/ true) : - strictNullChecks ? neverType : undefinedWideningType); + strictNullChecks ? implicitNeverType : undefinedWideningType); } function isNumericName(name: DeclarationName): boolean { From 0a4f60e87b030dfe58a067c671177dad40c89944 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 4 Nov 2017 17:26:12 -0700 Subject: [PATCH 16/25] Add tests --- tests/baselines/reference/neverInference.js | 31 +++++++ .../reference/neverInference.symbols | 76 +++++++++++++++++ .../baselines/reference/neverInference.types | 83 +++++++++++++++++++ .../conformance/types/never/neverInference.ts | 24 ++++++ 4 files changed, 214 insertions(+) create mode 100644 tests/baselines/reference/neverInference.js create mode 100644 tests/baselines/reference/neverInference.symbols create mode 100644 tests/baselines/reference/neverInference.types create mode 100644 tests/cases/conformance/types/never/neverInference.ts diff --git a/tests/baselines/reference/neverInference.js b/tests/baselines/reference/neverInference.js new file mode 100644 index 00000000000..d13e537eba4 --- /dev/null +++ b/tests/baselines/reference/neverInference.js @@ -0,0 +1,31 @@ +//// [neverInference.ts] +declare function f(x: T[]): T; + +let neverArray: never[] = []; + +let a1 = f([]); // {} +let a2 = f(neverArray); // never + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; + +interface LinkedList { + comparator: Comparator, + nodes: Node +} + +type Node = { value: T, next: Node } | null + +declare function compareNumbers(x: number, y: number): number; +declare function mkList(items: T[], comparator: Comparator): LinkedList; + +const list: LinkedList = mkList([], compareNumbers); + + +//// [neverInference.js] +"use strict"; +var neverArray = []; +var a1 = f([]); // {} +var a2 = f(neverArray); // never +var list = mkList([], compareNumbers); diff --git a/tests/baselines/reference/neverInference.symbols b/tests/baselines/reference/neverInference.symbols new file mode 100644 index 00000000000..683e079b2f8 --- /dev/null +++ b/tests/baselines/reference/neverInference.symbols @@ -0,0 +1,76 @@ +=== tests/cases/conformance/types/never/neverInference.ts === +declare function f(x: T[]): T; +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) +>x : Symbol(x, Decl(neverInference.ts, 0, 22)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) +>T : Symbol(T, Decl(neverInference.ts, 0, 19)) + +let neverArray: never[] = []; +>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3)) + +let a1 = f([]); // {} +>a1 : Symbol(a1, Decl(neverInference.ts, 4, 3)) +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) + +let a2 = f(neverArray); // never +>a2 : Symbol(a2, Decl(neverInference.ts, 5, 3)) +>f : Symbol(f, Decl(neverInference.ts, 0, 0)) +>neverArray : Symbol(neverArray, Decl(neverInference.ts, 2, 3)) + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) +>x : Symbol(x, Decl(neverInference.ts, 9, 22)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) +>y : Symbol(y, Decl(neverInference.ts, 9, 27)) +>T : Symbol(T, Decl(neverInference.ts, 9, 16)) + +interface LinkedList { +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) + + comparator: Comparator, +>comparator : Symbol(LinkedList.comparator, Decl(neverInference.ts, 11, 25)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) + + nodes: Node +>nodes : Symbol(LinkedList.nodes, Decl(neverInference.ts, 12, 30)) +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 11, 21)) +} + +type Node = { value: T, next: Node } | null +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) +>value : Symbol(value, Decl(neverInference.ts, 16, 16)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) +>next : Symbol(next, Decl(neverInference.ts, 16, 26)) +>Node : Symbol(Node, Decl(neverInference.ts, 14, 1)) +>T : Symbol(T, Decl(neverInference.ts, 16, 10)) + +declare function compareNumbers(x: number, y: number): number; +>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49)) +>x : Symbol(x, Decl(neverInference.ts, 18, 32)) +>y : Symbol(y, Decl(neverInference.ts, 18, 42)) + +declare function mkList(items: T[], comparator: Comparator): LinkedList; +>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>items : Symbol(items, Decl(neverInference.ts, 19, 27)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>comparator : Symbol(comparator, Decl(neverInference.ts, 19, 38)) +>Comparator : Symbol(Comparator, Decl(neverInference.ts, 5, 23)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>T : Symbol(T, Decl(neverInference.ts, 19, 24)) + +const list: LinkedList = mkList([], compareNumbers); +>list : Symbol(list, Decl(neverInference.ts, 21, 5)) +>LinkedList : Symbol(LinkedList, Decl(neverInference.ts, 9, 44)) +>mkList : Symbol(mkList, Decl(neverInference.ts, 18, 62)) +>compareNumbers : Symbol(compareNumbers, Decl(neverInference.ts, 16, 49)) + diff --git a/tests/baselines/reference/neverInference.types b/tests/baselines/reference/neverInference.types new file mode 100644 index 00000000000..a7dd05a3f8b --- /dev/null +++ b/tests/baselines/reference/neverInference.types @@ -0,0 +1,83 @@ +=== tests/cases/conformance/types/never/neverInference.ts === +declare function f(x: T[]): T; +>f : (x: T[]) => T +>T : T +>x : T[] +>T : T +>T : T + +let neverArray: never[] = []; +>neverArray : never[] +>[] : never[] + +let a1 = f([]); // {} +>a1 : {} +>f([]) : {} +>f : (x: T[]) => T +>[] : never[] + +let a2 = f(neverArray); // never +>a2 : never +>f(neverArray) : never +>f : (x: T[]) => T +>neverArray : never[] + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; +>Comparator : Comparator +>T : T +>x : T +>T : T +>y : T +>T : T + +interface LinkedList { +>LinkedList : LinkedList +>T : T + + comparator: Comparator, +>comparator : Comparator +>Comparator : Comparator +>T : T + + nodes: Node +>nodes : Node +>Node : Node +>T : T +} + +type Node = { value: T, next: Node } | null +>Node : Node +>T : T +>value : T +>T : T +>next : Node +>Node : Node +>T : T +>null : null + +declare function compareNumbers(x: number, y: number): number; +>compareNumbers : (x: number, y: number) => number +>x : number +>y : number + +declare function mkList(items: T[], comparator: Comparator): LinkedList; +>mkList : (items: T[], comparator: Comparator) => LinkedList +>T : T +>items : T[] +>T : T +>comparator : Comparator +>Comparator : Comparator +>T : T +>LinkedList : LinkedList +>T : T + +const list: LinkedList = mkList([], compareNumbers); +>list : LinkedList +>LinkedList : LinkedList +>mkList([], compareNumbers) : LinkedList +>mkList : (items: T[], comparator: Comparator) => LinkedList +>[] : never[] +>compareNumbers : (x: number, y: number) => number + diff --git a/tests/cases/conformance/types/never/neverInference.ts b/tests/cases/conformance/types/never/neverInference.ts new file mode 100644 index 00000000000..1258a35e3d3 --- /dev/null +++ b/tests/cases/conformance/types/never/neverInference.ts @@ -0,0 +1,24 @@ +// @strict: true + +declare function f(x: T[]): T; + +let neverArray: never[] = []; + +let a1 = f([]); // {} +let a2 = f(neverArray); // never + +// Repro from #19576 + +type Comparator = (x: T, y: T) => number; + +interface LinkedList { + comparator: Comparator, + nodes: Node +} + +type Node = { value: T, next: Node } | null + +declare function compareNumbers(x: number, y: number): number; +declare function mkList(items: T[], comparator: Comparator): LinkedList; + +const list: LinkedList = mkList([], compareNumbers); From db9ed00a0f131585fa1ee74118e3ba75328e3024 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 6 Nov 2017 07:48:09 -0800 Subject: [PATCH 17/25] Remove readonly from index signatures of a spread --- src/compiler/checker.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2e45b2ccb0..59964f388bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7993,11 +7993,16 @@ namespace ts { } } - const spread = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); + const spread = createAnonymousType( + symbol, + members, + emptyArray, + emptyArray, + getNonReadonlyIndexSignature(stringIndexInfo), + getNonReadonlyIndexSignature(numberIndexInfo)); spread.flags |= propagatedFlags; spread.flags |= TypeFlags.FreshLiteral | TypeFlags.ContainsObjectLiteral; (spread as ObjectType).objectFlags |= (ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread); - spread.symbol = symbol; return spread; } @@ -8013,6 +8018,13 @@ namespace ts { return result; } + function getNonReadonlyIndexSignature(index: IndexInfo) { + if (index && index.isReadonly) { + return createIndexInfo(index.type, /*isReadonly*/ false, index.declaration); + } + return index; + } + function isClassMethod(prop: Symbol) { return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); } From 7788d293c4d65103f8fef81128d77a44cbb6df09 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 6 Nov 2017 07:53:43 -0800 Subject: [PATCH 18/25] Test:spread removes readonly from index signatures --- .../objectSpreadIndexSignature.errors.txt | 4 ++++ .../reference/objectSpreadIndexSignature.js | 6 ++++++ .../reference/objectSpreadIndexSignature.symbols | 11 +++++++++++ .../reference/objectSpreadIndexSignature.types | 16 ++++++++++++++++ .../types/spread/objectSpreadIndexSignature.ts | 4 ++++ 5 files changed, 41 insertions(+) diff --git a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt index ee7425909c2..dede126d063 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.errors.txt +++ b/tests/baselines/reference/objectSpreadIndexSignature.errors.txt @@ -16,4 +16,8 @@ tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts(6,1): error T declare const b: boolean; indexed3 = { ...b ? indexed3 : undefined }; + + declare var roindex: { readonly [x:string]: number }; + var writable = { ...roindex }; + writable.a = 0; // should be ok. \ No newline at end of file diff --git a/tests/baselines/reference/objectSpreadIndexSignature.js b/tests/baselines/reference/objectSpreadIndexSignature.js index 283129036da..f8663fd836f 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.js +++ b/tests/baselines/reference/objectSpreadIndexSignature.js @@ -11,6 +11,10 @@ ii[1001]; declare const b: boolean; indexed3 = { ...b ? indexed3 : undefined }; + +declare var roindex: { readonly [x:string]: number }; +var writable = { ...roindex }; +writable.a = 0; // should be ok. //// [objectSpreadIndexSignature.js] @@ -30,3 +34,5 @@ var ii = __assign({}, indexed1, indexed2); // both have indexer, so i[1001]: number | boolean ii[1001]; indexed3 = __assign({}, b ? indexed3 : undefined); +var writable = __assign({}, roindex); +writable.a = 0; // should be ok. diff --git a/tests/baselines/reference/objectSpreadIndexSignature.symbols b/tests/baselines/reference/objectSpreadIndexSignature.symbols index d08cfff53ff..439463c4131 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.symbols +++ b/tests/baselines/reference/objectSpreadIndexSignature.symbols @@ -40,3 +40,14 @@ indexed3 = { ...b ? indexed3 : undefined }; >indexed3 : Symbol(indexed3, Decl(objectSpreadIndexSignature.ts, 2, 11)) >undefined : Symbol(undefined) +declare var roindex: { readonly [x:string]: number }; +>roindex : Symbol(roindex, Decl(objectSpreadIndexSignature.ts, 13, 11)) +>x : Symbol(x, Decl(objectSpreadIndexSignature.ts, 13, 33)) + +var writable = { ...roindex }; +>writable : Symbol(writable, Decl(objectSpreadIndexSignature.ts, 14, 3)) +>roindex : Symbol(roindex, Decl(objectSpreadIndexSignature.ts, 13, 11)) + +writable.a = 0; // should be ok. +>writable : Symbol(writable, Decl(objectSpreadIndexSignature.ts, 14, 3)) + diff --git a/tests/baselines/reference/objectSpreadIndexSignature.types b/tests/baselines/reference/objectSpreadIndexSignature.types index eff3b04b8f6..3ce4d00584b 100644 --- a/tests/baselines/reference/objectSpreadIndexSignature.types +++ b/tests/baselines/reference/objectSpreadIndexSignature.types @@ -50,3 +50,19 @@ indexed3 = { ...b ? indexed3 : undefined }; >indexed3 : { [n: string]: number; } >undefined : undefined +declare var roindex: { readonly [x:string]: number }; +>roindex : { readonly [x: string]: number; } +>x : string + +var writable = { ...roindex }; +>writable : { [x: string]: number; } +>{ ...roindex } : { [x: string]: number; } +>roindex : { readonly [x: string]: number; } + +writable.a = 0; // should be ok. +>writable.a = 0 : 0 +>writable.a : number +>writable : { [x: string]: number; } +>a : number +>0 : 0 + diff --git a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts index 83649d465f1..13ddc4f71d3 100644 --- a/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts +++ b/tests/cases/conformance/types/spread/objectSpreadIndexSignature.ts @@ -11,3 +11,7 @@ ii[1001]; declare const b: boolean; indexed3 = { ...b ? indexed3 : undefined }; + +declare var roindex: { readonly [x:string]: number }; +var writable = { ...roindex }; +writable.a = 0; // should be ok. From 0a7b7e07ee9cfae804baaf2bc2435b02e58964ce Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 6 Nov 2017 09:23:47 -0800 Subject: [PATCH 19/25] Apply 'variable-name' tslint rule (#19743) --- Gulpfile.ts | 8 +- .../generateLocalizedDiagnosticMessages.ts | 8 +- scripts/processDiagnosticMessages.ts | 3 +- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 85 +++--- src/compiler/core.ts | 2 +- src/compiler/factory.ts | 1 + src/compiler/parser.ts | 4 + src/compiler/utilities.ts | 4 +- src/harness/fourslash.ts | 6 +- src/harness/harness.ts | 18 +- src/harness/harnessLanguageService.ts | 4 +- src/harness/loggedIO.ts | 2 +- src/harness/parallel/host.ts | 32 +-- src/harness/unittests/compileOnSave.ts | 4 +- src/harness/unittests/extractRanges.ts | 28 +- src/harness/unittests/moduleResolution.ts | 2 +- .../unittests/reuseProgramStructure.ts | 244 +++++++++--------- src/server/editorServices.ts | 4 +- src/server/session.ts | 2 +- src/server/shared.ts | 1 + .../typingsInstaller/nodeTypingsInstaller.ts | 16 +- src/server/utilities.ts | 6 +- src/services/formatting/formatting.ts | 12 +- src/services/formatting/rule.ts | 6 +- src/services/formatting/ruleDescriptor.ts | 6 +- src/services/formatting/ruleOperation.ts | 8 +- .../formatting/ruleOperationContext.ts | 4 +- src/services/formatting/rules.ts | 1 + src/services/formatting/rulesMap.ts | 38 +-- src/services/formatting/tokenRange.ts | 1 + src/services/jsTyping.ts | 6 +- src/services/patternMatcher.ts | 10 +- src/services/refactors/extractSymbol.ts | 96 +++---- src/services/services.ts | 4 +- tslint.json | 2 +- 36 files changed, 349 insertions(+), 331 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 5b35b9f672f..4d6dfdf2862 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -99,12 +99,12 @@ const lclDirectory = "src/loc/lcl"; const builtDirectory = "built/"; const builtLocalDirectory = "built/local/"; -const LKGDirectory = "lib/"; +const lkgDirectory = "lib/"; const copyright = "CopyrightNotice.txt"; const compilerFilename = "tsc.js"; -const LKGCompiler = path.join(LKGDirectory, compilerFilename); +const lkgCompiler = path.join(lkgDirectory, compilerFilename); const builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename); const nodeModulesPathPrefix = path.resolve("./node_modules/.bin/"); @@ -589,7 +589,7 @@ gulp.task("VerifyLKG", /*help*/ false, [], () => { ". The following files are missing:\n" + missingFiles.join("\n")); } // Copy all the targets into the LKG directory - return gulp.src([...expectedFiles, path.join(builtLocalDirectory, "**"), `!${path.join(builtLocalDirectory, "tslint")}`, `!${path.join(builtLocalDirectory, "*.*")}`]).pipe(gulp.dest(LKGDirectory)); + return gulp.src([...expectedFiles, path.join(builtLocalDirectory, "**"), `!${path.join(builtLocalDirectory, "tslint")}`, `!${path.join(builtLocalDirectory, "*.*")}`]).pipe(gulp.dest(lkgDirectory)); }); gulp.task("LKGInternal", /*help*/ false, ["lib", "local"]); @@ -992,7 +992,7 @@ gulp.task(loggedIOJsPath, /*help*/ false, [], (done) => { const temp = path.join(builtLocalDirectory, "temp"); mkdirP(temp, (err) => { if (err) { console.error(err); done(err); process.exit(1); } - exec(host, [LKGCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => { + exec(host, [lkgCompiler, "--types", "--target es5", "--lib es5", "--outdir", temp, loggedIOpath], () => { fs.renameSync(path.join(temp, "/harness/loggedIO.js"), loggedIOJsPath); del(temp).then(() => done(), done); }, done); diff --git a/scripts/generateLocalizedDiagnosticMessages.ts b/scripts/generateLocalizedDiagnosticMessages.ts index 00bd8314a9b..566eb557fd5 100644 --- a/scripts/generateLocalizedDiagnosticMessages.ts +++ b/scripts/generateLocalizedDiagnosticMessages.ts @@ -87,9 +87,9 @@ function main(): void { const out: any = {}; for (const item of o.LCX.Item[0].Item[0].Item) { let ItemId = item.$.ItemId; - let Val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0]; + let val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0]; - if (typeof ItemId !== "string" || typeof Val !== "string") { + if (typeof ItemId !== "string" || typeof val !== "string") { console.error("Unexpected XML file structure"); process.exit(1); } @@ -98,8 +98,8 @@ function main(): void { ItemId = ItemId.slice(1); // remove leading semicolon } - Val = Val.replace(/]5D;/, "]"); // unescape `]` - out[ItemId] = Val; + val = val.replace(/]5D;/, "]"); // unescape `]` + out[ItemId] = val; } return JSON.stringify(out, undefined, 2); } diff --git a/scripts/processDiagnosticMessages.ts b/scripts/processDiagnosticMessages.ts index ff4047d310d..20085022c04 100644 --- a/scripts/processDiagnosticMessages.ts +++ b/scripts/processDiagnosticMessages.ts @@ -63,7 +63,8 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string " function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" + " return { code, category, key, message };\r\n" + " }\r\n" + - ' export const Diagnostics = {\r\n'; + " // tslint:disable-next-line variable-name\r\n" + + " export const Diagnostics = {\r\n"; messageTable.forEach(({ code, category }, name) => { const propName = convertPropertyName(name); result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`; diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 85ca2435974..72cff733b0c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -133,7 +133,7 @@ namespace ts { let symbolCount = 0; - let Symbol: { new (flags: SymbolFlags, name: __String): Symbol }; + let Symbol: { new (flags: SymbolFlags, name: __String): Symbol }; // tslint:disable-line variable-name let classifiableNames: UnderscoreEscapedMap; const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable }; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2e45b2ccb0..b0b014d598a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48,9 +48,11 @@ namespace ts { let requestedExternalEmitHelpers: ExternalEmitHelpers; let externalHelpersModule: Symbol; + // tslint:disable variable-name const Symbol = objectAllocator.getSymbolConstructor(); const Type = objectAllocator.getTypeConstructor(); const Signature = objectAllocator.getSignatureConstructor(); + // tslint:enable variable-name let typeCount = 0; let symbolCount = 0; @@ -488,17 +490,6 @@ namespace ts { /** Things we lazy load from the JSX namespace */ const jsxTypes = createUnderscoreEscapedMap(); - const JsxNames = { - JSX: "JSX" as __String, - IntrinsicElements: "IntrinsicElements" as __String, - ElementClass: "ElementClass" as __String, - ElementAttributesPropertyNameContainer: "ElementAttributesProperty" as __String, - ElementChildrenAttributeNameContainer: "ElementChildrenAttribute" as __String, - Element: "Element" as __String, - IntrinsicAttributes: "IntrinsicAttributes" as __String, - IntrinsicClassAttributes: "IntrinsicClassAttributes" as __String - }; - const subtypeRelation = createMap(); const assignableRelation = createMap(); const comparableRelation = createMap(); @@ -25103,11 +25094,13 @@ namespace ts { } function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) { - const seen = createUnderscoreEscapedMap(); - const Property = 1; - const GetAccessor = 2; - const SetAccessor = 4; - const GetOrSetAccessor = GetAccessor | SetAccessor; + const enum Flags { + Property = 1, + GetAccessor = 2, + SetAccessor = 4, + GetOrSetAccessor = GetAccessor | SetAccessor, + } + const seen = createUnderscoreEscapedMap(); for (const prop of node.properties) { if (prop.kind === SyntaxKind.SpreadAssignment) { @@ -25142,26 +25135,27 @@ namespace ts { // c.IsAccessorDescriptor(previous) is true and IsDataDescriptor(propId.descriptor) is true. // d.IsAccessorDescriptor(previous) is true and IsAccessorDescriptor(propId.descriptor) is true // and either both previous and propId.descriptor have[[Get]] fields or both previous and propId.descriptor have[[Set]] fields - let currentKind: number; - if (prop.kind === SyntaxKind.PropertyAssignment || prop.kind === SyntaxKind.ShorthandPropertyAssignment) { - // Grammar checking for computedPropertyName and shorthandPropertyAssignment - checkGrammarForInvalidQuestionMark((prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); - if (name.kind === SyntaxKind.NumericLiteral) { - checkGrammarNumericLiteral(name); - } - currentKind = Property; - } - else if (prop.kind === SyntaxKind.MethodDeclaration) { - currentKind = Property; - } - else if (prop.kind === SyntaxKind.GetAccessor) { - currentKind = GetAccessor; - } - else if (prop.kind === SyntaxKind.SetAccessor) { - currentKind = SetAccessor; - } - else { - Debug.assertNever(prop, "Unexpected syntax kind:" + (prop).kind); + let currentKind: Flags; + switch (prop.kind) { + case SyntaxKind.PropertyAssignment: + case SyntaxKind.ShorthandPropertyAssignment: + // Grammar checking for computedPropertyName and shorthandPropertyAssignment + checkGrammarForInvalidQuestionMark((prop).questionToken, Diagnostics.An_object_member_cannot_be_declared_optional); + if (name.kind === SyntaxKind.NumericLiteral) { + checkGrammarNumericLiteral(name); + } + // falls through + case SyntaxKind.MethodDeclaration: + currentKind = Flags.Property; + break; + case SyntaxKind.GetAccessor: + currentKind = Flags.GetAccessor; + break; + case SyntaxKind.SetAccessor: + currentKind = Flags.SetAccessor; + break; + default: + Debug.assertNever(prop, "Unexpected syntax kind:" + (prop).kind); } const effectiveName = getPropertyNameForPropertyNameNode(name); @@ -25174,11 +25168,11 @@ namespace ts { seen.set(effectiveName, currentKind); } else { - if (currentKind === Property && existingKind === Property) { + if (currentKind === Flags.Property && existingKind === Flags.Property) { grammarErrorOnNode(name, Diagnostics.Duplicate_identifier_0, getTextOfNode(name)); } - else if ((currentKind & GetOrSetAccessor) && (existingKind & GetOrSetAccessor)) { - if (existingKind !== GetOrSetAccessor && currentKind !== existingKind) { + else if ((currentKind & Flags.GetOrSetAccessor) && (existingKind & Flags.GetOrSetAccessor)) { + if (existingKind !== Flags.GetOrSetAccessor && currentKind !== existingKind) { seen.set(effectiveName, currentKind | existingKind); } else { @@ -25806,4 +25800,17 @@ namespace ts { return false; } } + + namespace JsxNames { + // tslint:disable variable-name + export const JSX = "JSX" as __String; + export const IntrinsicElements = "IntrinsicElements" as __String; + export const ElementClass = "ElementClass" as __String; + export const ElementAttributesPropertyNameContainer = "ElementAttributesProperty" as __String; + export const ElementChildrenAttributeNameContainer = "ElementChildrenAttribute" as __String; + export const Element = "Element" as __String; + export const IntrinsicAttributes = "IntrinsicAttributes" as __String; + export const IntrinsicClassAttributes = "IntrinsicClassAttributes" as __String; + // tslint:enable variable-name + } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 157a0c7fd1d..f2249641ff4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -76,7 +76,7 @@ namespace ts { // The global Map object. This may not be available, so we must test for it. declare const Map: { new(): Map } | undefined; // Internet Explorer's Map doesn't support iteration, so don't use it. - // tslint:disable-next-line:no-in-operator + // tslint:disable-next-line no-in-operator variable-name const MapCtr = typeof Map !== "undefined" && "entries" in Map.prototype ? Map : shimMap(); // Keep the class inside a function so it doesn't get compiled if it's not used. diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index d16903bc300..053672d19df 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2654,6 +2654,7 @@ namespace ts { return node; } + // tslint:disable-next-line variable-name let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; /** diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c2b35bd25c4..9b43a3c991b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -12,10 +12,12 @@ namespace ts { JSDoc = 1 << 5, } + // tslint:disable variable-name let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + // tslint:enable variable-name export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node { if (kind === SyntaxKind.SourceFile) { @@ -524,10 +526,12 @@ namespace ts { const disallowInAndDecoratorContext = NodeFlags.DisallowInContext | NodeFlags.DecoratorContext; // capture constructors in 'initializeState' to avoid null checks + // tslint:disable variable-name let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + // tslint:enable variable-name let sourceFile: SourceFile; let parseDiagnostics: Diagnostic[]; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 10b93ad59cf..456f02c09c6 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1404,8 +1404,8 @@ namespace ts { return charCode === CharacterCodes.singleQuote || charCode === CharacterCodes.doubleQuote; } - export function isStringDoubleQuoted(string: StringLiteral, sourceFile: SourceFile): boolean { - return getSourceTextOfNodeFromSourceFile(sourceFile, string).charCodeAt(0) === CharacterCodes.doubleQuote; + export function isStringDoubleQuoted(str: StringLiteral, sourceFile: SourceFile): boolean { + return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote; } /** diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7852aba28f1..dac8f7b8413 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -126,8 +126,8 @@ namespace FourSlash { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled - private static readonly NotCanceled: number = -1; - private numberOfCallsBeforeCancellation: number = TestCancellationToken.NotCanceled; + private static readonly notCanceled = -1; + private numberOfCallsBeforeCancellation = TestCancellationToken.notCanceled; public isCancellationRequested(): boolean { if (this.numberOfCallsBeforeCancellation < 0) { @@ -148,7 +148,7 @@ namespace FourSlash { } public resetCancelled(): void { - this.numberOfCallsBeforeCancellation = TestCancellationToken.NotCanceled; + this.numberOfCallsBeforeCancellation = TestCancellationToken.notCanceled; } } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index e698839168a..61ea4508363 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1113,11 +1113,11 @@ namespace Harness { case "string": return value; case "number": { - const number = parseInt(value, 10); - if (isNaN(number)) { + const numverValue = parseInt(value, 10); + if (isNaN(numverValue)) { throw new Error(`Value must be a number, got: ${JSON.stringify(value)}`); } - return number; + return numverValue; } // If not a primitive, the possible types are specified in what is effectively a map of options. case "list": @@ -1964,7 +1964,7 @@ namespace Harness { /** Support class for baseline files */ export namespace Baseline { - const NoContent = ""; + const noContent = ""; export interface BaselineOptions { Subfolder?: string; @@ -2023,7 +2023,7 @@ namespace Harness { /* tslint:disable:no-null-keyword */ if (actual === null) { /* tslint:enable:no-null-keyword */ - actual = NoContent; + actual = noContent; } let expected = ""; @@ -2060,13 +2060,13 @@ namespace Harness { IO.deleteFile(actualFileName); } - const encoded_actual = Utils.encodeString(actual); - if (expected !== encoded_actual) { - if (actual === NoContent) { + const encodedActual = Utils.encodeString(actual); + if (expected !== encodedActual) { + if (actual === noContent) { IO.writeFile(actualFileName + ".delete", ""); } else { - IO.writeFile(actualFileName, encoded_actual); + IO.writeFile(actualFileName, encodedActual); } throw new Error(`The baseline file ${relativeFileName} has changed.`); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 185c22db72d..b745a0bfd4f 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -108,7 +108,7 @@ namespace Harness.LanguageService { } class DefaultHostCancellationToken implements ts.HostCancellationToken { - public static readonly Instance = new DefaultHostCancellationToken(); + public static readonly instance = new DefaultHostCancellationToken(); public isCancellationRequested() { return false; @@ -126,7 +126,7 @@ namespace Harness.LanguageService { public typesRegistry: ts.Map | undefined; protected virtualFileSystem: Utils.VirtualFileSystem = new Utils.VirtualFileSystem(virtualFileSystemRoot, /*useCaseSensitiveFilenames*/false); - constructor(protected cancellationToken = DefaultHostCancellationToken.Instance, + constructor(protected cancellationToken = DefaultHostCancellationToken.instance, protected settings = ts.getDefaultCompilerOptions()) { } diff --git a/src/harness/loggedIO.ts b/src/harness/loggedIO.ts index 2be09abcf91..37e8dddb3d7 100644 --- a/src/harness/loggedIO.ts +++ b/src/harness/loggedIO.ts @@ -251,7 +251,7 @@ namespace Playback { let i = 0; const getBase = () => recordLogFileNameBase + i; while (underlying.fileExists(ts.combinePaths(getBase(), "test.json"))) i++; - const newLog = oldStyleLogIntoNewStyleLog(recordLog, (path, string) => underlying.writeFile(path, string), getBase()); + const newLog = oldStyleLogIntoNewStyleLog(recordLog, (path, str) => underlying.writeFile(path, str), getBase()); underlying.writeFile(ts.combinePaths(getBase(), "test.json"), JSON.stringify(newLog, null, 4)); // tslint:disable-line:no-null-keyword const syntheticTsconfig = generateTsconfig(newLog); if (syntheticTsconfig) { diff --git a/src/harness/parallel/host.ts b/src/harness/parallel/host.ts index 40dee0da872..f37a3b1099e 100644 --- a/src/harness/parallel/host.ts +++ b/src/harness/parallel/host.ts @@ -274,15 +274,15 @@ namespace Harness.Parallel.Host { function completeBar() { const isPartitionFail = failingFiles !== 0; const summaryColor = isPartitionFail ? "fail" : "green"; - const summarySymbol = isPartitionFail ? Base.symbols.err : Base.symbols.ok; + const summarySymbol = isPartitionFail ? base.symbols.err : base.symbols.ok; const summaryTests = (isPartitionFail ? totalPassing + "/" + (errorResults.length + totalPassing) : totalPassing) + " passing"; const summaryDuration = "(" + ms(duration) + ")"; - const savedUseColors = Base.useColors; - Base.useColors = !noColors; + const savedUseColors = base.useColors; + base.useColors = !noColors; const summary = color(summaryColor, summarySymbol + " " + summaryTests) + " " + color("light", summaryDuration); - Base.useColors = savedUseColors; + base.useColors = savedUseColors; updateProgress(1, summary); } @@ -307,7 +307,7 @@ namespace Harness.Parallel.Host { completeBar(); progressBars.disable(); - const reporter = new Base(); + const reporter = new base(); const stats = reporter.stats; const failures = reporter.failures; stats.passes = totalPassing; @@ -318,10 +318,10 @@ namespace Harness.Parallel.Host { failures.push(makeMochaTest(failure)); } if (noColors) { - const savedUseColors = Base.useColors; - Base.useColors = false; + const savedUseColors = base.useColors; + base.useColors = false; reporter.epilogue(); - Base.useColors = savedUseColors; + base.useColors = savedUseColors; } else { reporter.epilogue(); @@ -352,8 +352,8 @@ namespace Harness.Parallel.Host { return; } - let Mocha: any; - let Base: any; + let mocha: any; + let base: any; let color: any; let cursor: any; let readline: any; @@ -394,10 +394,10 @@ namespace Harness.Parallel.Host { } function initializeProgressBarsDependencies() { - Mocha = require("mocha"); - Base = Mocha.reporters.Base; - color = Base.color; - cursor = Base.cursor; + mocha = require("mocha"); + base = mocha.reporters.Base; + color = base.color; + cursor = base.cursor; readline = require("readline"); os = require("os"); tty = require("tty"); @@ -414,8 +414,8 @@ namespace Harness.Parallel.Host { const open = options.open || "["; const close = options.close || "]"; const complete = options.complete || "â–¬"; - const incomplete = options.incomplete || Base.symbols.dot; - const maxWidth = Base.window.width - open.length - close.length - 34; + const incomplete = options.incomplete || base.symbols.dot; + const maxWidth = base.window.width - open.length - close.length - 34; const width = minMax(options.width || maxWidth, 10, maxWidth); this._options = { open, diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts index 7be6ab5b323..0a3b5f46f0f 100644 --- a/src/harness/unittests/compileOnSave.ts +++ b/src/harness/unittests/compileOnSave.ts @@ -627,8 +627,8 @@ namespace ts.projectSystem { const mapFileContent = host.readFile(expectedMapFileName); verifyContentHasString(mapFileContent, `"sources":["${inputFileName}"]`); - function verifyContentHasString(content: string, string: string) { - assert.isTrue(content.indexOf(string) !== -1, `Expected "${content}" to have "${string}"`); + function verifyContentHasString(content: string, str: string) { + assert.isTrue(stringContains(content, str), `Expected "${content}" to have "${str}"`); } }); }); diff --git a/src/harness/unittests/extractRanges.ts b/src/harness/unittests/extractRanges.ts index e8e9a918f0d..493c9639c3d 100644 --- a/src/harness/unittests/extractRanges.ts +++ b/src/harness/unittests/extractRanges.ts @@ -191,7 +191,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed2", @@ -210,7 +210,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed3", @@ -229,7 +229,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed4", @@ -248,7 +248,7 @@ function f() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message ]); testExtractRangeFailed("extractRangeFailed5", @@ -269,7 +269,7 @@ function f2() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed6", @@ -290,7 +290,7 @@ function f2() { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalReturnStatement.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message ]); testExtractRangeFailed("extractRangeFailed7", @@ -303,7 +303,7 @@ while (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed8", @@ -316,13 +316,13 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed9", `var x = ([#||]1 + 2);`, [ - refactor.extractSymbol.Messages.CannotExtractEmpty.message + refactor.extractSymbol.Messages.cannotExtractEmpty.message ]); testExtractRangeFailed("extractRangeFailed10", @@ -333,7 +333,7 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRange.message + refactor.extractSymbol.Messages.cannotExtractRange.message ]); testExtractRangeFailed("extractRangeFailed11", @@ -350,21 +350,21 @@ switch (x) { } `, [ - refactor.extractSymbol.Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements.message + refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message ]); testExtractRangeFailed("extractRangeFailed12", `let [#|x|];`, [ - refactor.extractSymbol.Messages.StatementOrExpressionExpected.message + refactor.extractSymbol.Messages.statementOrExpressionExpected.message ]); testExtractRangeFailed("extractRangeFailed13", `[#|return;|]`, [ - refactor.extractSymbol.Messages.CannotExtractRange.message + refactor.extractSymbol.Messages.cannotExtractRange.message ]); - testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.CannotExtractIdentifier.message]); + testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.cannotExtractIdentifier.message]); }); } \ No newline at end of file diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index 32301d6dccf..6f62c78208f 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -803,7 +803,7 @@ import b = require("./moduleB"); function test(hasDirectoryExists: boolean) { const file1: File = { name: "/root/folder1/file1.ts" }; - const file1_1: File = { name: "/root/folder1/file1_1/index.d.ts" }; + const file1_1: File = { name: "/root/folder1/file1_1/index.d.ts" }; // tslint:disable-line variable-name const file2: File = { name: "/root/generated/folder1/file2.ts" }; const file3: File = { name: "/root/generated/folder2/file3.ts" }; const host = createModuleResolutionHost(hasDirectoryExists, file1, file1_1, file2, file3); diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index e0c0e6f80a8..6278742a0bd 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -243,111 +243,111 @@ namespace ts { ]; it("successful if change does not affect imports", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + const program2 = updateProgram(program1, ["a.ts"], { target }, files => { files[0].text = files[0].text.updateProgram("var x = 100"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); - const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("a.ts")); + const program2Diagnostics = program2.getSemanticDiagnostics(program1.getSourceFile("a.ts")); assert.equal(program1Diagnostics.length, program2Diagnostics.length); }); it("successful if change does not affect type reference directives", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + const program2 = updateProgram(program1, ["a.ts"], { target }, files => { files[0].text = files[0].text.updateProgram("var x = 100"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); - const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts")); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("a.ts")); + const program2Diagnostics = program2.getSemanticDiagnostics(program1.getSourceFile("a.ts")); assert.equal(program1Diagnostics.length, program2Diagnostics.length); }); it("fails if change affects tripleslash references", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { const newReferences = `/// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if change affects type references", () => { - const program_1 = newProgram(files, ["a.ts"], { types: ["a"] }); - updateProgram(program_1, ["a.ts"], { types: ["b"] }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { types: ["a"] }); + updateProgram(program1, ["a.ts"], { types: ["b"] }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("succeeds if change doesn't affect type references", () => { - const program_1 = newProgram(files, ["a.ts"], { types: ["a"] }); - updateProgram(program_1, ["a.ts"], { types: ["a"] }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + const program1 = newProgram(files, ["a.ts"], { types: ["a"] }); + updateProgram(program1, ["a.ts"], { types: ["a"] }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); }); it("fails if change affects imports", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { files[2].text = files[2].text.updateImportsAndExports("import x from 'b'"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if change affects type directives", () => { - const program_1 = newProgram(files, ["a.ts"], { target }); - updateProgram(program_1, ["a.ts"], { target }, files => { + const program1 = newProgram(files, ["a.ts"], { target }); + updateProgram(program1, ["a.ts"], { target }, files => { const newReferences = ` /// /// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules); + assert.equal(program1.structureIsReused, StructureIsReused.SafeModules); }); it("fails if module kind changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.AMD }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.AMD }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("fails if rootdir changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("fails if config path changes", () => { - const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); - updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); + const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" }); + updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop); + assert.equal(program1.structureIsReused, StructureIsReused.Not); }); it("succeeds if missing files remain missing", () => { const options: CompilerOptions = { target, noLib: true }; - const program_1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths()); + const program1 = newProgram(files, ["a.ts"], options); + assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); - const program_2 = updateProgram(program_1, ["a.ts"], options, noop); - assert.deepEqual(program_1.getMissingFilePaths(), program_2.getMissingFilePaths()); + const program2 = updateProgram(program1, ["a.ts"], options, noop); + assert.deepEqual(program1.getMissingFilePaths(), program2.getMissingFilePaths()); - assert.equal(StructureIsReused.Completely, program_1.structureIsReused); + assert.equal(StructureIsReused.Completely, program1.structureIsReused); }); it("fails if missing file is created", () => { const options: CompilerOptions = { target, noLib: true }; - const program_1 = newProgram(files, ["a.ts"], options); - assert.notDeepEqual(emptyArray, program_1.getMissingFilePaths()); + const program1 = newProgram(files, ["a.ts"], options); + assert.notDeepEqual(emptyArray, program1.getMissingFilePaths()); const newTexts: NamedSourceText[] = files.concat([{ name: "non-existing-file.ts", text: SourceText.New("", "", `var x = 1`) }]); - const program_2 = updateProgram(program_1, ["a.ts"], options, noop, newTexts); - assert.deepEqual(emptyArray, program_2.getMissingFilePaths()); + const program2 = updateProgram(program1, ["a.ts"], options, noop, newTexts); + assert.deepEqual(emptyArray, program2.getMissingFilePaths()); - assert.equal(StructureIsReused.Not, program_1.structureIsReused); + assert.equal(StructureIsReused.Not, program1.structureIsReused); }); it("resolution cache follows imports", () => { @@ -359,34 +359,34 @@ namespace ts { ]; const options: CompilerOptions = { target }; - const program_1 = newProgram(files, ["a.ts"], options); - checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); - checkResolvedModulesCache(program_1, "b.ts", /*expectedContent*/ undefined); + const program1 = newProgram(files, ["a.ts"], options); + checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); + checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined); - const program_2 = updateProgram(program_1, ["a.ts"], options, files => { + const program2 = updateProgram(program1, ["a.ts"], options, files => { files[0].text = files[0].text.updateProgram("var x = 2"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); // content of resolution cache should not change - checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); - checkResolvedModulesCache(program_1, "b.ts", /*expectedContent*/ undefined); + checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") })); + checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined); // imports has changed - program is not reused - const program_3 = updateProgram(program_2, ["a.ts"], options, files => { + const program3 = updateProgram(program2, ["a.ts"], options, files => { files[0].text = files[0].text.updateImportsAndExports(""); }); - assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules); - checkResolvedModulesCache(program_3, "a.ts", /*expectedContent*/ undefined); + assert.equal(program2.structureIsReused, StructureIsReused.SafeModules); + checkResolvedModulesCache(program3, "a.ts", /*expectedContent*/ undefined); - const program_4 = updateProgram(program_3, ["a.ts"], options, files => { + const program4 = updateProgram(program3, ["a.ts"], options, files => { const newImports = `import x from 'b' import y from 'c' `; files[0].text = files[0].text.updateImportsAndExports(newImports); }); - assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules); - checkResolvedModulesCache(program_4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined })); + assert.equal(program3.structureIsReused, StructureIsReused.SafeModules); + checkResolvedModulesCache(program4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined })); }); it("resolved type directives cache follows type directives", () => { @@ -396,35 +396,35 @@ namespace ts { ]; const options: CompilerOptions = { target, typeRoots: ["/types"] }; - const program_1 = newProgram(files, ["/a.ts"], options); - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); - checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); + const program1 = newProgram(files, ["/a.ts"], options); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); + checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); - const program_2 = updateProgram(program_1, ["/a.ts"], options, files => { + const program2 = updateProgram(program1, ["/a.ts"], options, files => { files[0].text = files[0].text.updateProgram("var x = 2"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); // content of resolution cache should not change - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); - checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); + checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined); // type reference directives has changed - program is not reused - const program_3 = updateProgram(program_2, ["/a.ts"], options, files => { + const program3 = updateProgram(program2, ["/a.ts"], options, files => { files[0].text = files[0].text.updateReferences(""); }); - assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules); - checkResolvedTypeDirectivesCache(program_3, "/a.ts", /*expectedContent*/ undefined); + assert.equal(program2.structureIsReused, StructureIsReused.SafeModules); + checkResolvedTypeDirectivesCache(program3, "/a.ts", /*expectedContent*/ undefined); - updateProgram(program_3, ["/a.ts"], options, files => { + updateProgram(program3, ["/a.ts"], options, files => { const newReferences = `/// /// `; files[0].text = files[0].text.updateReferences(newReferences); }); - assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules); - checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); + assert.equal(program3.structureIsReused, StructureIsReused.SafeModules); + checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } })); }); it("fetches imports after npm install", () => { @@ -529,18 +529,18 @@ namespace ts { "======== Module name 'fs' was not resolved. ========", ], "should look for 'fs'"); - const program_2 = updateProgram(program, program.getRootFileNames(), options, f => { + const program2 = updateProgram(program, program.getRootFileNames(), options, f => { f[0].text = f[0].text.updateProgram("var x = 1;"); }); - assert.deepEqual(program_2.host.getTrace(), [ + assert.deepEqual(program2.host.getTrace(), [ "Module 'fs' was resolved as ambient module declared in '/a/b/node.d.ts' since this file was not modified." ], "should reuse 'fs' since node.d.ts was not changed"); - const program_3 = updateProgram(program_2, program_2.getRootFileNames(), options, f => { + const program3 = updateProgram(program2, program2.getRootFileNames(), options, f => { f[0].text = f[0].text.updateProgram("var y = 1;"); f[1].text = f[1].text.updateProgram("declare var process: any"); }); - assert.deepEqual(program_3.host.getTrace(), + assert.deepEqual(program3.host.getTrace(), [ "======== Resolving module 'fs' from '/a/b/app.ts'. ========", "Module resolution kind is not specified, using 'Classic'.", @@ -598,10 +598,10 @@ namespace ts { ]; const options: CompilerOptions = { target: ScriptTarget.ES2015, traceResolution: true, moduleResolution: ModuleResolutionKind.Classic }; - const program_1 = newProgram(files, files.map(f => f.name), options); + const program1 = newProgram(files, files.map(f => f.name), options); let expectedErrors = 0; { - assert.deepEqual(program_1.host.getTrace(), + assert.deepEqual(program1.host.getTrace(), [ "======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", @@ -626,22 +626,22 @@ namespace ts { "File 'f1.ts' exist - use it as a name resolution result.", "======== Module name './f1' was successfully resolved to 'f1.ts'. ========" ], - "program_1: execute module resolution normally."); + "program1: execute module resolution normally."); - const program_1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("f2.ts")); - assert.lengthOf(program_1Diagnostics, expectedErrors, `initial program should be well-formed`); + const program1Diagnostics = program1.getSemanticDiagnostics(program1.getSourceFile("f2.ts")); + assert.lengthOf(program1Diagnostics, expectedErrors, `initial program should be well-formed`); } const indexOfF1 = 6; - const program_2 = updateProgram(program_1, program_1.getRootFileNames(), options, f => { + const program2 = updateProgram(program1, program1.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(`/// ${newLine}/// `); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_2Diagnostics = program_2.getSemanticDiagnostics(program_2.getSourceFile("f2.ts")); - assert.lengthOf(program_2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`); + const program2Diagnostics = program2.getSemanticDiagnostics(program2.getSourceFile("f2.ts")); + assert.lengthOf(program2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`); - assert.deepEqual(program_2.host.getTrace(), [ + assert.deepEqual(program2.host.getTrace(), [ "======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", "File 'node_modules/@types/typerefs1/package.json' does not exist.", @@ -658,19 +658,19 @@ namespace ts { "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", "Reusing resolution of module './b2' to file 'f2.ts' from old program.", "Reusing resolution of module './f1' to file 'f2.ts' from old program." - ], "program_2: reuse module resolutions in f2 since it is unchanged"); + ], "program2: reuse module resolutions in f2 since it is unchanged"); } - const program_3 = updateProgram(program_2, program_2.getRootFileNames(), options, f => { + const program3 = updateProgram(program2, program2.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(`/// `); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_3Diagnostics = program_3.getSemanticDiagnostics(program_3.getSourceFile("f2.ts")); - assert.lengthOf(program_3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`); + const program3Diagnostics = program3.getSemanticDiagnostics(program3.getSourceFile("f2.ts")); + assert.lengthOf(program3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`); - assert.deepEqual(program_3.host.getTrace(), [ + assert.deepEqual(program3.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -682,20 +682,20 @@ namespace ts { "======== Type reference directive 'typerefs2' was successfully resolved to 'node_modules/@types/typerefs2/index.d.ts', primary: true. ========", "Reusing resolution of module './b2' to file 'f2.ts' from old program.", "Reusing resolution of module './f1' to file 'f2.ts' from old program." - ], "program_3: reuse module resolutions in f2 since it is unchanged"); + ], "program3: reuse module resolutions in f2 since it is unchanged"); } - const program_4 = updateProgram(program_3, program_3.getRootFileNames(), options, f => { + const program4 = updateProgram(program3, program3.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateReferences(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_4Diagnostics = program_4.getSemanticDiagnostics(program_4.getSourceFile("f2.ts")); - assert.lengthOf(program_4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`); + const program4Diagnostics = program4.getSemanticDiagnostics(program4.getSourceFile("f2.ts")); + assert.lengthOf(program4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`); - assert.deepEqual(program_4.host.getTrace(), [ + assert.deepEqual(program4.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -710,16 +710,16 @@ namespace ts { ], "program_4: reuse module resolutions in f2 since it is unchanged"); } - const program_5 = updateProgram(program_4, program_4.getRootFileNames(), options, f => { + const program5 = updateProgram(program4, program4.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateImportsAndExports(`import { B } from './b1';`); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_5Diagnostics = program_5.getSemanticDiagnostics(program_5.getSourceFile("f2.ts")); - assert.lengthOf(program_5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`); + const program5Diagnostics = program5.getSemanticDiagnostics(program5.getSourceFile("f2.ts")); + assert.lengthOf(program5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`); - assert.deepEqual(program_5.host.getTrace(), [ + assert.deepEqual(program5.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -727,16 +727,16 @@ namespace ts { ], "program_5: exports do not affect program structure, so f2's resolutions are silently reused."); } - const program_6 = updateProgram(program_5, program_5.getRootFileNames(), options, f => { + const program6 = updateProgram(program5, program5.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateProgram(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_6Diagnostics = program_6.getSemanticDiagnostics(program_6.getSourceFile("f2.ts")); - assert.lengthOf(program_6Diagnostics, expectedErrors, `import of BB in f1 fails.`); + const program6Diagnostics = program6.getSemanticDiagnostics(program6.getSourceFile("f2.ts")); + assert.lengthOf(program6Diagnostics, expectedErrors, `import of BB in f1 fails.`); - assert.deepEqual(program_6.host.getTrace(), [ + assert.deepEqual(program6.host.getTrace(), [ "======== Resolving module './b1' from 'f1.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "File 'b1.ts' exist - use it as a name resolution result.", @@ -751,16 +751,16 @@ namespace ts { ], "program_6: reuse module resolutions in f2 since it is unchanged"); } - const program_7 = updateProgram(program_6, program_6.getRootFileNames(), options, f => { + const program7 = updateProgram(program6, program6.getRootFileNames(), options, f => { const newSourceText = f[indexOfF1].text.updateImportsAndExports(""); f[indexOfF1] = { name: "f1.ts", text: newSourceText }; }); { - const program_7Diagnostics = program_7.getSemanticDiagnostics(program_7.getSourceFile("f2.ts")); - assert.lengthOf(program_7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`); + const program7Diagnostics = program7.getSemanticDiagnostics(program7.getSourceFile("f2.ts")); + assert.lengthOf(program7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`); - assert.deepEqual(program_7.host.getTrace(), [ + assert.deepEqual(program7.host.getTrace(), [ "======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========", "Resolving with primary search path 'node_modules/@types'.", "File 'node_modules/@types/typerefs2/package.json' does not exist.", @@ -820,47 +820,47 @@ namespace ts { } it("No changes -> redirect not broken", () => { - const program_1 = createRedirectProgram(); + const program1 = createRedirectProgram(); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, root, "const x = 1;"); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Completely); - assert.deepEqual(program_2.getSemanticDiagnostics(), emptyArray); + assert.equal(program1.structureIsReused, StructureIsReused.Completely); + assert.deepEqual(program2.getSemanticDiagnostics(), emptyArray); }); it("Target changes -> redirect broken", () => { - const program_1 = createRedirectProgram(); - assert.deepEqual(program_1.getSemanticDiagnostics(), emptyArray); + const program1 = createRedirectProgram(); + assert.deepEqual(program1.getSemanticDiagnostics(), emptyArray); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }"); updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }')); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.lengthOf(program_2.getSemanticDiagnostics(), 1); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.lengthOf(program2.getSemanticDiagnostics(), 1); }); it("Underlying changes -> redirect broken", () => { - const program_1 = createRedirectProgram(); + const program1 = createRedirectProgram(); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }"); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" })); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.lengthOf(program_2.getSemanticDiagnostics(), 1); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.lengthOf(program2.getSemanticDiagnostics(), 1); }); it("Previously duplicate packages -> program structure not reused", () => { - const program_1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); + const program1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" }); - const program_2 = updateRedirectProgram(program_1, files => { + const program2 = updateRedirectProgram(program1, files => { updateProgramText(files, bxIndex, "export default class X { private x: number; }"); updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" })); }); - assert.equal(program_1.structureIsReused, StructureIsReused.Not); - assert.deepEqual(program_2.getSemanticDiagnostics(), []); + assert.equal(program1.structureIsReused, StructureIsReused.Not); + assert.deepEqual(program2.getSemanticDiagnostics(), []); }); }); }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 9ec190c152f..2511c6c30c3 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -9,10 +9,12 @@ namespace ts.server { export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024; + // tslint:disable variable-name export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground"; export const ConfigFileDiagEvent = "configFileDiag"; export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState"; export const ProjectInfoTelemetryEvent = "projectInfo"; + // tslint:enable variable-name export interface ProjectsUpdatedInBackgroundEvent { eventName: typeof ProjectsUpdatedInBackgroundEvent; @@ -1061,7 +1063,7 @@ namespace ts.server { * Returns true if the configFileExistenceInfo is needed/impacted by open files that are root of inferred project */ private configFileExistenceImpactsRootOfInferredProject(configFileExistenceInfo: ConfigFileExistenceInfo) { - return forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, (isRootOfInferredProject, __key) => isRootOfInferredProject); + return forEachEntry(configFileExistenceInfo.openFilesImpactedByConfigFile, (isRootOfInferredProject) => isRootOfInferredProject); } private setConfigFileExistenceInfoByClosedConfiguredProject(closedProject: ConfiguredProject) { diff --git a/src/server/session.ts b/src/server/session.ts index 3f223b13963..dc9ddab7ae1 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -124,7 +124,7 @@ namespace ts.server { // we want to ensure the value is maintained in the out since the file is // built using --preseveConstEnum. export type CommandNames = protocol.CommandTypes; - export const CommandNames = (protocol).CommandTypes; + export const CommandNames = (protocol).CommandTypes; // tslint:disable-line variable-name export function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); diff --git a/src/server/shared.ts b/src/server/shared.ts index a8a122c3327..99a38eba389 100644 --- a/src/server/shared.ts +++ b/src/server/shared.ts @@ -1,6 +1,7 @@ /// namespace ts.server { + // tslint:disable variable-name export const ActionSet: ActionSet = "action::set"; export const ActionInvalidate: ActionInvalidate = "action::invalidate"; export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry"; diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts index 2a1036010a7..da16d5dde82 100644 --- a/src/server/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts @@ -63,9 +63,9 @@ namespace ts.server.typingsInstaller { } } - const TypesRegistryPackageName = "types-registry"; + const typesRegistryPackageName = "types-registry"; function getTypesRegistryFileLocation(globalTypingsCacheLocation: string): string { - return combinePaths(normalizeSlashes(globalTypingsCacheLocation), `node_modules/${TypesRegistryPackageName}/index.json`); + return combinePaths(normalizeSlashes(globalTypingsCacheLocation), `node_modules/${typesRegistryPackageName}/index.json`); } interface ExecSyncOptions { @@ -105,16 +105,16 @@ namespace ts.server.typingsInstaller { try { if (this.log.isEnabled()) { - this.log.writeLine(`Updating ${TypesRegistryPackageName} npm package...`); + this.log.writeLine(`Updating ${typesRegistryPackageName} npm package...`); } - this.execSyncAndLog(`${this.npmPath} install --ignore-scripts ${TypesRegistryPackageName}`, { cwd: globalTypingsCacheLocation }); + this.execSyncAndLog(`${this.npmPath} install --ignore-scripts ${typesRegistryPackageName}`, { cwd: globalTypingsCacheLocation }); if (this.log.isEnabled()) { - this.log.writeLine(`Updated ${TypesRegistryPackageName} npm package`); + this.log.writeLine(`Updated ${typesRegistryPackageName} npm package`); } } catch (e) { if (this.log.isEnabled()) { - this.log.writeLine(`Error updating ${TypesRegistryPackageName} package: ${(e).message}`); + this.log.writeLine(`Error updating ${typesRegistryPackageName} package: ${(e).message}`); } // store error info to report it later when it is known that server is already listening to events from typings installer this.delayedInitializationError = { @@ -243,7 +243,7 @@ namespace ts.server.typingsInstaller { const installer = new NodeTypingsInstaller(globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, /*throttleLimit*/5, log); installer.listen(); - function indent(newline: string, string: string): string { - return `${newline} ` + string.replace(/\r?\n/, `${newline} `); + function indent(newline: string, str: string): string { + return `${newline} ` + str.replace(/\r?\n/, `${newline} `); } } diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 69399b672b3..096d4484154 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -24,6 +24,7 @@ namespace ts.server { } export namespace Msg { + // tslint:disable variable-name export type Err = "Err"; export const Err: Err = "Err"; export type Info = "Info"; @@ -31,6 +32,7 @@ namespace ts.server { export type Perf = "Perf"; export const Perf: Perf = "Perf"; export type Types = Err | Info | Perf; + // tslint:enable variable-name } function getProjectRootPath(project: Project): Path { @@ -320,8 +322,8 @@ namespace ts.server { } /* @internal */ - export function indent(string: string): string { - return "\n " + string; + export function indent(str: string): string { + return "\n " + str; } /** Put stringified JSON on the next line, indented. */ diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index fdd70cda461..529fdae0545 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -924,7 +924,7 @@ namespace ts.formatting { if (rule) { applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine); - if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) { + if (rule.operation.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) { lineAdded = false; // Handle the case where the next line is moved to be the end of this line. // In this case we don't indent the next line in the next pass. @@ -932,7 +932,7 @@ namespace ts.formatting { dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false); } } - else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) { + else if (rule.operation.action & RuleAction.NewLine && currentStartLine === previousStartLine) { lineAdded = true; // Handle the case where token2 is moved to the new line. // In this case we indent token2 in the next pass but we set @@ -943,7 +943,7 @@ namespace ts.formatting { } // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line - trimTrailingWhitespaces = !(rule.Operation.Action & RuleAction.Delete) && rule.Flag !== RuleFlags.CanDeleteNewLines; + trimTrailingWhitespaces = !(rule.operation.action & RuleAction.Delete) && rule.flag !== RuleFlags.CanDeleteNewLines; } else { trimTrailingWhitespaces = true; @@ -1118,7 +1118,7 @@ namespace ts.formatting { currentRange: TextRangeWithKind, currentStartLine: number): void { - switch (rule.Operation.Action) { + switch (rule.operation.action) { case RuleAction.Ignore: // no action required return; @@ -1132,7 +1132,7 @@ namespace ts.formatting { // exit early if we on different lines and rule cannot change number of newlines // if line1 and line2 are on subsequent lines then no edits are required - ok to exit // if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines - if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { return; } @@ -1144,7 +1144,7 @@ namespace ts.formatting { break; case RuleAction.Space: // exit early if we on different lines and rule cannot change number of newlines - if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { + if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) { return; } diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts index 10987c745c2..8fd432586b4 100644 --- a/src/services/formatting/rule.ts +++ b/src/services/formatting/rule.ts @@ -6,9 +6,9 @@ namespace ts.formatting { // Used for debugging to identify each rule based on the property name it's assigned to. public debugName?: string; constructor( - readonly Descriptor: RuleDescriptor, - readonly Operation: RuleOperation, - readonly Flag: RuleFlags = RuleFlags.None) { + readonly descriptor: RuleDescriptor, + readonly operation: RuleOperation, + readonly flag: RuleFlags = RuleFlags.None) { } } } \ No newline at end of file diff --git a/src/services/formatting/ruleDescriptor.ts b/src/services/formatting/ruleDescriptor.ts index 96506adc3dc..b8529496956 100644 --- a/src/services/formatting/ruleDescriptor.ts +++ b/src/services/formatting/ruleDescriptor.ts @@ -3,12 +3,12 @@ /* @internal */ namespace ts.formatting { export class RuleDescriptor { - constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) { + constructor(public leftTokenRange: Shared.TokenRange, public rightTokenRange: Shared.TokenRange) { } public toString(): string { - return "[leftRange=" + this.LeftTokenRange + "," + - "rightRange=" + this.RightTokenRange + "]"; + return "[leftRange=" + this.leftTokenRange + "," + + "rightRange=" + this.rightTokenRange + "]"; } static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor { diff --git a/src/services/formatting/ruleOperation.ts b/src/services/formatting/ruleOperation.ts index 8ad83b11653..462c27352d8 100644 --- a/src/services/formatting/ruleOperation.ts +++ b/src/services/formatting/ruleOperation.ts @@ -3,15 +3,15 @@ /* @internal */ namespace ts.formatting { export class RuleOperation { - constructor(public Context: RuleOperationContext, public Action: RuleAction) {} + constructor(readonly context: RuleOperationContext, readonly action: RuleAction) {} public toString(): string { - return "[context=" + this.Context + "," + - "action=" + this.Action + "]"; + return "[context=" + this.context + "," + + "action=" + this.action + "]"; } static create1(action: RuleAction) { - return RuleOperation.create2(RuleOperationContext.Any, action); + return RuleOperation.create2(RuleOperationContext.any, action); } static create2(context: RuleOperationContext, action: RuleAction) { diff --git a/src/services/formatting/ruleOperationContext.ts b/src/services/formatting/ruleOperationContext.ts index f03b19516d5..c433d106372 100644 --- a/src/services/formatting/ruleOperationContext.ts +++ b/src/services/formatting/ruleOperationContext.ts @@ -10,10 +10,10 @@ namespace ts.formatting { this.customContextChecks = funcs; } - static readonly Any: RuleOperationContext = new RuleOperationContext(); + static readonly any: RuleOperationContext = new RuleOperationContext(); public IsAny(): boolean { - return this === RuleOperationContext.Any; + return this === RuleOperationContext.any; } public InContext(context: FormattingContext): boolean { diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 32d01eb1a16..c5b59e818eb 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -2,6 +2,7 @@ /* @internal */ namespace ts.formatting { + // tslint:disable variable-name (TODO) export class Rules { public IgnoreBeforeComment: Rule; public IgnoreAfterLineComment: Rule; diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts index d1f6e4724f7..3b04308ebe8 100644 --- a/src/services/formatting/rulesMap.ts +++ b/src/services/formatting/rulesMap.ts @@ -23,10 +23,10 @@ namespace ts.formatting { } private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void { - const specificRule = rule.Descriptor.LeftTokenRange.isSpecific() && rule.Descriptor.RightTokenRange.isSpecific(); + const specificRule = rule.descriptor.leftTokenRange.isSpecific() && rule.descriptor.rightTokenRange.isSpecific(); - rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => { - rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => { + rule.descriptor.leftTokenRange.GetTokens().forEach((left) => { + rule.descriptor.rightTokenRange.GetTokens().forEach((right) => { const rulesBucketIndex = this.GetRuleBucketIndex(left, right); let rulesBucket = this.map[rulesBucketIndex]; @@ -44,7 +44,7 @@ namespace ts.formatting { const bucket = this.map[bucketIndex]; if (bucket) { for (const rule of bucket.Rules()) { - if (rule.Operation.Context.InContext(context)) { + if (rule.operation.context.InContext(context)) { return rule; } } @@ -53,16 +53,16 @@ namespace ts.formatting { } } - const MaskBitSize = 5; - const Mask = 0x1f; + const maskBitSize = 5; + const mask = 0x1f; enum RulesPosition { IgnoreRulesSpecific = 0, - IgnoreRulesAny = MaskBitSize * 1, - ContextRulesSpecific = MaskBitSize * 2, - ContextRulesAny = MaskBitSize * 3, - NoContextRulesSpecific = MaskBitSize * 4, - NoContextRulesAny = MaskBitSize * 5 + IgnoreRulesAny = maskBitSize * 1, + ContextRulesSpecific = maskBitSize * 2, + ContextRulesAny = maskBitSize * 3, + NoContextRulesSpecific = maskBitSize * 4, + NoContextRulesAny = maskBitSize * 5 } export class RulesBucketConstructionState { @@ -94,20 +94,20 @@ namespace ts.formatting { let indexBitmap = this.rulesInsertionIndexBitmap; while (pos <= maskPosition) { - index += (indexBitmap & Mask); - indexBitmap >>= MaskBitSize; - pos += MaskBitSize; + index += (indexBitmap & mask); + indexBitmap >>= maskBitSize; + pos += maskBitSize; } return index; } public IncreaseInsertionIndex(maskPosition: RulesPosition): void { - let value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask; + let value = (this.rulesInsertionIndexBitmap >> maskPosition) & mask; value++; - Debug.assert((value & Mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); + Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules."); - let temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition); + let temp = this.rulesInsertionIndexBitmap & ~(mask << maskPosition); temp |= value << maskPosition; this.rulesInsertionIndexBitmap = temp; @@ -128,12 +128,12 @@ namespace ts.formatting { public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void { let position: RulesPosition; - if (rule.Operation.Action === RuleAction.Ignore) { + if (rule.operation.action === RuleAction.Ignore) { position = specificTokens ? RulesPosition.IgnoreRulesSpecific : RulesPosition.IgnoreRulesAny; } - else if (!rule.Operation.Context.IsAny()) { + else if (!rule.operation.context.IsAny()) { position = specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny; diff --git a/src/services/formatting/tokenRange.ts b/src/services/formatting/tokenRange.ts index 29855279e25..31e15bc738d 100644 --- a/src/services/formatting/tokenRange.ts +++ b/src/services/formatting/tokenRange.ts @@ -95,6 +95,7 @@ namespace ts.formatting { return new TokenAllExceptAccess(token); } + // tslint:disable variable-name (TODO) export const Any: TokenRange = new TokenAllAccess(); export const AnyIncludingMultilineComments = TokenRange.FromTokens([...allTokens, SyntaxKind.MultiLineCommentTrivia]); export const Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword); diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index 572858dd2fd..0c250d75f92 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -257,7 +257,7 @@ namespace ts.JsTyping { NameContainsNonURISafeCharacters } - const MaxPackageNameLength = 214; + const maxPackageNameLength = 214; /** * Validates package name using rules defined at https://docs.npmjs.com/files/package.json @@ -266,7 +266,7 @@ namespace ts.JsTyping { if (!packageName) { return PackageNameValidationResult.EmptyName; } - if (packageName.length > MaxPackageNameLength) { + if (packageName.length > maxPackageNameLength) { return PackageNameValidationResult.NameTooLong; } if (packageName.charCodeAt(0) === CharacterCodes.dot) { @@ -292,7 +292,7 @@ namespace ts.JsTyping { case PackageNameValidationResult.EmptyName: return `Package name '${typing}' cannot be empty`; case PackageNameValidationResult.NameTooLong: - return `Package name '${typing}' should be less than ${MaxPackageNameLength} characters`; + return `Package name '${typing}' should be less than ${maxPackageNameLength} characters`; case PackageNameValidationResult.NameStartsWithDot: return `Package name '${typing}' cannot start with '.'`; case PackageNameValidationResult.NameStartsWithUnderscore: diff --git a/src/services/patternMatcher.ts b/src/services/patternMatcher.ts index 04f9d906d35..db957816146 100644 --- a/src/services/patternMatcher.ts +++ b/src/services/patternMatcher.ts @@ -515,10 +515,10 @@ namespace ts { } // Assumes 'value' is already lowercase. - function indexOfIgnoringCase(string: string, value: string): number { - const n = string.length - value.length; + function indexOfIgnoringCase(str: string, value: string): number { + const n = str.length - value.length; for (let i = 0; i <= n; i++) { - if (startsWithIgnoringCase(string, value, i)) { + if (startsWithIgnoringCase(str, value, i)) { return i; } } @@ -527,9 +527,9 @@ namespace ts { } // Assumes 'value' is already lowercase. - function startsWithIgnoringCase(string: string, value: string, start: number): boolean { + function startsWithIgnoringCase(str: string, value: string, start: number): boolean { for (let i = 0; i < value.length; i++) { - const ch1 = toLowerCase(string.charCodeAt(i + start)); + const ch1 = toLowerCase(str.charCodeAt(i + start)); const ch2 = value.charCodeAt(i); if (ch1 !== ch2) { diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 58e57675459..11f659a8b43 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -122,28 +122,28 @@ namespace ts.refactor.extractSymbol { return { message, code: 0, category: DiagnosticCategory.Message, key: message }; } - export const CannotExtractRange: DiagnosticMessage = createMessage("Cannot extract range."); - export const CannotExtractImport: DiagnosticMessage = createMessage("Cannot extract import statement."); - export const CannotExtractSuper: DiagnosticMessage = createMessage("Cannot extract super call."); - export const CannotExtractEmpty: DiagnosticMessage = createMessage("Cannot extract empty range."); - export const ExpressionExpected: DiagnosticMessage = createMessage("expression expected."); - export const UselessConstantType: DiagnosticMessage = createMessage("No reason to extract constant of type."); - export const StatementOrExpressionExpected: DiagnosticMessage = createMessage("Statement or expression expected."); - export const CannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = createMessage("Cannot extract range containing conditional break or continue statements."); - export const CannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage("Cannot extract range containing conditional return statement."); - export const CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: DiagnosticMessage = createMessage("Cannot extract range containing labeled break or continue with target outside of the range."); - export const CannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators."); - export const TypeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope."); - export const FunctionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); - export const CannotExtractIdentifier = createMessage("Select more than a single identifier."); - export const CannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); - export const CannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression"); - export const CannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); - export const CannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); - export const CannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); - export const CannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function"); - export const CannotExtractToJSClass = createMessage("Cannot extract constant to a class scope in JS"); - export const CannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block"); + export const cannotExtractRange: DiagnosticMessage = createMessage("Cannot extract range."); + export const cannotExtractImport: DiagnosticMessage = createMessage("Cannot extract import statement."); + export const cannotExtractSuper: DiagnosticMessage = createMessage("Cannot extract super call."); + export const cannotExtractEmpty: DiagnosticMessage = createMessage("Cannot extract empty range."); + export const expressionExpected: DiagnosticMessage = createMessage("expression expected."); + export const uselessConstantType: DiagnosticMessage = createMessage("No reason to extract constant of type."); + export const statementOrExpressionExpected: DiagnosticMessage = createMessage("Statement or expression expected."); + export const cannotExtractRangeContainingConditionalBreakOrContinueStatements: DiagnosticMessage = createMessage("Cannot extract range containing conditional break or continue statements."); + export const cannotExtractRangeContainingConditionalReturnStatement: DiagnosticMessage = createMessage("Cannot extract range containing conditional return statement."); + export const cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange: DiagnosticMessage = createMessage("Cannot extract range containing labeled break or continue with target outside of the range."); + export const cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators."); + export const typeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope."); + export const functionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); + export const cannotExtractIdentifier = createMessage("Select more than a single identifier."); + export const cannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); + export const cannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression"); + export const cannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); + export const cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts"); + export const cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes"); + export const cannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function"); + export const cannotExtractToJSClass = createMessage("Cannot extract constant to a class scope in JS"); + export const cannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block"); } enum RangeFacts { @@ -198,7 +198,7 @@ namespace ts.refactor.extractSymbol { const { length } = span; if (length === 0) { - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractEmpty)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractEmpty)] }; } // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span. @@ -215,18 +215,18 @@ namespace ts.refactor.extractSymbol { if (!start || !end) { // cannot find either start or end node - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } if (start.parent !== end.parent) { // start and end nodes belong to different subtrees - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } if (start !== end) { // start and end should be statements and parent should be either block or a source file if (!isBlockLike(start.parent)) { - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } const statements: Statement[] = []; for (const statement of (start.parent).statements) { @@ -246,7 +246,7 @@ namespace ts.refactor.extractSymbol { if (isReturnStatement(start) && !start.expression) { // Makes no sense to extract an expression-less return statement. - return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.CannotExtractRange)] }; + return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] }; } // We have a single node (start) @@ -293,7 +293,7 @@ namespace ts.refactor.extractSymbol { function checkRootNode(node: Node): Diagnostic[] | undefined { if (isIdentifier(isExpressionStatement(node) ? node.expression : node)) { - return [createDiagnosticForNode(node, Messages.CannotExtractIdentifier)]; + return [createDiagnosticForNode(node, Messages.cannotExtractIdentifier)]; } return undefined; } @@ -332,11 +332,11 @@ namespace ts.refactor.extractSymbol { Return = 1 << 2 } if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck))) { - return [createDiagnosticForNode(nodeToCheck, Messages.StatementOrExpressionExpected)]; + return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)]; } if (nodeToCheck.flags & NodeFlags.Ambient) { - return [createDiagnosticForNode(nodeToCheck, Messages.CannotExtractAmbientBlock)]; + return [createDiagnosticForNode(nodeToCheck, Messages.cannotExtractAmbientBlock)]; } // If we're in a class, see whether we're in a static region (static property initializer, static method, class constructor parameter default) @@ -362,7 +362,7 @@ namespace ts.refactor.extractSymbol { if (isDeclaration(node)) { const declaringNode = (node.kind === SyntaxKind.VariableDeclaration) ? node.parent.parent : node; if (hasModifier(declaringNode, ModifierFlags.Export)) { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractExportedEntity)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractExportedEntity)); return true; } declarations.push(node.symbol); @@ -371,7 +371,7 @@ namespace ts.refactor.extractSymbol { // Some things can't be extracted in certain situations switch (node.kind) { case SyntaxKind.ImportDeclaration: - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractImport)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractImport)); return true; case SyntaxKind.SuperKeyword: // For a super *constructor call*, we have to be extracting the entire class, @@ -380,7 +380,7 @@ namespace ts.refactor.extractSymbol { // Super constructor call const containingClass = getContainingClass(node); if (containingClass.pos < span.start || containingClass.end >= (span.start + span.length)) { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractSuper)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractSuper)); return true; } } @@ -396,7 +396,7 @@ namespace ts.refactor.extractSymbol { case SyntaxKind.ClassDeclaration: if (node.parent.kind === SyntaxKind.SourceFile && (node.parent as ts.SourceFile).externalModuleIndicator === undefined) { // You cannot extract global declarations - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.FunctionWillNotBeVisibleInTheNewScope)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope)); } break; } @@ -452,13 +452,13 @@ namespace ts.refactor.extractSymbol { if (label) { if (!contains(seenLabels, label.escapedText)) { // attempts to jump to label that is not in range to be extracted - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange)); } } else { if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { // attempt to break or continue in a forbidden context - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements)); } } break; @@ -474,7 +474,7 @@ namespace ts.refactor.extractSymbol { rangeFacts |= RangeFacts.HasReturn; } else { - (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingConditionalReturnStatement)); + (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalReturnStatement)); } break; default: @@ -1455,10 +1455,10 @@ namespace ts.refactor.extractSymbol { const statements = targetRange.range as ReadonlyArray; const start = first(statements).getStart(); const end = last(statements).end; - expressionDiagnostic = createFileDiagnostic(sourceFile, start, end - start, Messages.ExpressionExpected); + expressionDiagnostic = createFileDiagnostic(sourceFile, start, end - start, Messages.expressionExpected); } else if (checker.getTypeAtLocation(expression).flags & (TypeFlags.Void | TypeFlags.Never)) { - expressionDiagnostic = createDiagnosticForNode(expression, Messages.UselessConstantType); + expressionDiagnostic = createDiagnosticForNode(expression, Messages.uselessConstantType); } // initialize results @@ -1468,7 +1468,7 @@ namespace ts.refactor.extractSymbol { functionErrorsPerScope.push( isFunctionLikeDeclaration(scope) && scope.kind !== SyntaxKind.FunctionDeclaration - ? [createDiagnosticForNode(scope, Messages.CannotExtractToOtherFunctionLike)] + ? [createDiagnosticForNode(scope, Messages.cannotExtractToOtherFunctionLike)] : []); const constantErrors = []; @@ -1476,11 +1476,11 @@ namespace ts.refactor.extractSymbol { constantErrors.push(expressionDiagnostic); } if (isClassLike(scope) && isInJavaScriptFile(scope)) { - constantErrors.push(createDiagnosticForNode(scope, Messages.CannotExtractToJSClass)); + constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToJSClass)); } if (isArrowFunction(scope) && !isBlock(scope.body)) { // TODO (https://github.com/Microsoft/TypeScript/issues/18924): allow this - constantErrors.push(createDiagnosticForNode(scope, Messages.CannotExtractToExpressionArrowFunction)); + constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToExpressionArrowFunction)); } constantErrorsPerScope.push(constantErrors); } @@ -1548,7 +1548,7 @@ namespace ts.refactor.extractSymbol { // local will actually be declared at the same level as the extracted expression). if (i > 0 && (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0)) { const errorNode = isReadonlyArray(targetRange.range) ? targetRange.range[0] : targetRange.range; - constantErrorsPerScope[i].push(createDiagnosticForNode(errorNode, Messages.CannotAccessVariablesFromNestedScopes)); + constantErrorsPerScope[i].push(createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes)); } let hasWrite = false; @@ -1568,17 +1568,17 @@ namespace ts.refactor.extractSymbol { Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0); if (hasWrite && !isReadonlyArray(targetRange.range)) { - const diag = createDiagnosticForNode(targetRange.range, Messages.CannotWriteInExpression); + const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } else if (readonlyClassPropertyWrite && i > 0) { - const diag = createDiagnosticForNode(readonlyClassPropertyWrite, Messages.CannotExtractReadonlyPropertyInitializerOutsideConstructor); + const diag = createDiagnosticForNode(readonlyClassPropertyWrite, Messages.cannotExtractReadonlyPropertyInitializerOutsideConstructor); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } else if (firstExposedNonVariableDeclaration) { - const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.CannotExtractExportedEntity); + const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.cannotExtractExportedEntity); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } @@ -1710,7 +1710,7 @@ namespace ts.refactor.extractSymbol { if (targetRange.facts & RangeFacts.IsGenerator && usage === Usage.Write) { // this is write to a reference located outside of the target scope and range is extracted into generator // currently this is unsupported scenario - const diag = createDiagnosticForNode(identifier, Messages.CannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators); + const diag = createDiagnosticForNode(identifier, Messages.cannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators); for (const errors of functionErrorsPerScope) { errors.push(diag); } @@ -1733,7 +1733,7 @@ namespace ts.refactor.extractSymbol { // If the symbol is a type parameter that won't be in scope, we'll pass it as a type argument // so there's no problem. if (!(symbol.flags & SymbolFlags.TypeParameter)) { - const diag = createDiagnosticForNode(identifier, Messages.TypeWillNotBeVisibleInTheNewScope); + const diag = createDiagnosticForNode(identifier, Messages.typeWillNotBeVisibleInTheNewScope); functionErrorsPerScope[i].push(diag); constantErrorsPerScope[i].push(diag); } diff --git a/src/services/services.ts b/src/services/services.ts index 178d949990d..6345dae2d1f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1997,9 +1997,7 @@ namespace ts { } function isNodeModulesFile(path: string): boolean { - const node_modulesFolderName = "/node_modules/"; - - return stringContains(path, node_modulesFolderName); + return stringContains(path, "/node_modules/"); } } diff --git a/tslint.json b/tslint.json index 299a1049e4c..9ad752e6094 100644 --- a/tslint.json +++ b/tslint.json @@ -74,6 +74,7 @@ // Config different from tslint:latest "no-implicit-dependencies": [true, "dev"], + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"], // TODO "arrow-parens": false, // [true, "ban-single-arg-parens"] @@ -102,7 +103,6 @@ "space-before-function-paren": false, "trailing-comma": false, "unified-signatures": false, - "variable-name": false, // These should be done automatically by a formatter. https://github.com/Microsoft/TypeScript/issues/18340 "align": false, From a287ddc93bda8043ca4c6b5f1cbf15f25c50791c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 6 Nov 2017 09:25:41 -0800 Subject: [PATCH 20/25] Fix invariant generic error elaboration logic --- src/compiler/checker.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e2e45b2ccb0..4d5449a9526 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9432,6 +9432,7 @@ namespace ts { function structuredTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { let result: Ternary; + let originalErrorInfo: DiagnosticMessageChain; const saveErrorInfo = errorInfo; if (target.flags & TypeFlags.TypeParameter) { // A source type { [P in keyof T]: X } is related to a target type T if X is related to T[P]. @@ -9511,6 +9512,7 @@ namespace ts { // if we have indexed access types with identical index types, see if relationship holds for // the two object types. if (result = isRelatedTo((source).objectType, (target).objectType, reportErrors)) { + errorInfo = saveErrorInfo; return result; } } @@ -9542,6 +9544,10 @@ namespace ts { if (!(reportErrors && some(variances, v => v === Variance.Invariant))) { return Ternary.False; } + // We remember the original error information so we can restore it in case the structural + // comparison unexpectedly succeeds. This can happen when the structural comparison result + // is a Ternary.Maybe for example caused by the recursion depth limiter. + originalErrorInfo = errorInfo; errorInfo = saveErrorInfo; } } @@ -9580,8 +9586,11 @@ namespace ts { } } if (result) { - errorInfo = saveErrorInfo; - return result; + if (!originalErrorInfo) { + errorInfo = saveErrorInfo; + return result; + } + errorInfo = originalErrorInfo; } } } From baafe5157eb273d1c87d71ff9e270e25e15d7b05 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 6 Nov 2017 09:25:51 -0800 Subject: [PATCH 21/25] Add regression test --- ...nvariantGenericErrorElaboration.errors.txt | 54 +++++++++++++ .../invariantGenericErrorElaboration.js | 30 +++++++ .../invariantGenericErrorElaboration.symbols | 76 ++++++++++++++++++ .../invariantGenericErrorElaboration.types | 78 +++++++++++++++++++ .../invariantGenericErrorElaboration.ts | 24 ++++++ 5 files changed, 262 insertions(+) create mode 100644 tests/baselines/reference/invariantGenericErrorElaboration.errors.txt create mode 100644 tests/baselines/reference/invariantGenericErrorElaboration.js create mode 100644 tests/baselines/reference/invariantGenericErrorElaboration.symbols create mode 100644 tests/baselines/reference/invariantGenericErrorElaboration.types create mode 100644 tests/cases/compiler/invariantGenericErrorElaboration.ts diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt b/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt new file mode 100644 index 00000000000..5142b665d71 --- /dev/null +++ b/tests/baselines/reference/invariantGenericErrorElaboration.errors.txt @@ -0,0 +1,54 @@ +tests/cases/compiler/invariantGenericErrorElaboration.ts(3,7): error TS2322: Type 'Num' is not assignable to type 'Runtype'. + Types of property 'constraint' are incompatible. + Type 'Constraint' is not assignable to type 'Constraint>'. + Types of property 'constraint' are incompatible. + Type 'Constraint>' is not assignable to type 'Constraint>>'. + Types of property 'constraint' are incompatible. + Type 'Constraint>>' is not assignable to type 'Constraint>>>'. + Type 'Constraint>>' is not assignable to type 'Constraint>'. + Types of property 'underlying' are incompatible. + Type 'Constraint>' is not assignable to type 'Constraint'. +tests/cases/compiler/invariantGenericErrorElaboration.ts(4,17): error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype; }'. + Property 'foo' is incompatible with index signature. + Type 'Num' is not assignable to type 'Runtype'. + + +==== tests/cases/compiler/invariantGenericErrorElaboration.ts (2 errors) ==== + // Repro from #19746 + + const wat: Runtype = Num; + ~~~ +!!! error TS2322: Type 'Num' is not assignable to type 'Runtype'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint' is not assignable to type 'Constraint>'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint>>'. +!!! error TS2322: Types of property 'constraint' are incompatible. +!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>>>'. +!!! error TS2322: Type 'Constraint>>' is not assignable to type 'Constraint>'. +!!! error TS2322: Types of property 'underlying' are incompatible. +!!! error TS2322: Type 'Constraint>' is not assignable to type 'Constraint'. + const Foo = Obj({ foo: Num }) + ~~~~~~~~~~~~ +!!! error TS2345: Argument of type '{ foo: Num; }' is not assignable to parameter of type '{ [_: string]: Runtype; }'. +!!! error TS2345: Property 'foo' is incompatible with index signature. +!!! error TS2345: Type 'Num' is not assignable to type 'Runtype'. + + interface Runtype { + constraint: Constraint + witness: A + } + + interface Num extends Runtype { + tag: 'number' + } + declare const Num: Num + + interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} + declare function Obj }>(fields: O): Obj; + + interface Constraint> extends Runtype { + underlying: A, + check: (x: A['witness']) => void, + } + \ No newline at end of file diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.js b/tests/baselines/reference/invariantGenericErrorElaboration.js new file mode 100644 index 00000000000..253c4ab03b7 --- /dev/null +++ b/tests/baselines/reference/invariantGenericErrorElaboration.js @@ -0,0 +1,30 @@ +//// [invariantGenericErrorElaboration.ts] +// Repro from #19746 + +const wat: Runtype = Num; +const Foo = Obj({ foo: Num }) + +interface Runtype { + constraint: Constraint + witness: A +} + +interface Num extends Runtype { + tag: 'number' +} +declare const Num: Num + +interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} +declare function Obj }>(fields: O): Obj; + +interface Constraint> extends Runtype { + underlying: A, + check: (x: A['witness']) => void, +} + + +//// [invariantGenericErrorElaboration.js] +"use strict"; +// Repro from #19746 +var wat = Num; +var Foo = Obj({ foo: Num }); diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.symbols b/tests/baselines/reference/invariantGenericErrorElaboration.symbols new file mode 100644 index 00000000000..9c141e5c27f --- /dev/null +++ b/tests/baselines/reference/invariantGenericErrorElaboration.symbols @@ -0,0 +1,76 @@ +=== tests/cases/compiler/invariantGenericErrorElaboration.ts === +// Repro from #19746 + +const wat: Runtype = Num; +>wat : Symbol(wat, Decl(invariantGenericErrorElaboration.ts, 2, 5)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13)) + +const Foo = Obj({ foo: Num }) +>Foo : Symbol(Foo, Decl(invariantGenericErrorElaboration.ts, 3, 5)) +>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111)) +>foo : Symbol(foo, Decl(invariantGenericErrorElaboration.ts, 3, 17)) +>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13)) + +interface Runtype { +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18)) + + constraint: Constraint +>constraint : Symbol(Runtype.constraint, Decl(invariantGenericErrorElaboration.ts, 5, 22)) +>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81)) + + witness: A +>witness : Symbol(Runtype.witness, Decl(invariantGenericErrorElaboration.ts, 6, 30)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 5, 18)) +} + +interface Num extends Runtype { +>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) + + tag: 'number' +>tag : Symbol(Num.tag, Decl(invariantGenericErrorElaboration.ts, 10, 39)) +} +declare const Num: Num +>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13)) +>Num : Symbol(Num, Decl(invariantGenericErrorElaboration.ts, 8, 1), Decl(invariantGenericErrorElaboration.ts, 13, 13)) + +interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} +>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14)) +>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 15, 27)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 15, 14)) +>K : Symbol(K, Decl(invariantGenericErrorElaboration.ts, 15, 75)) + +declare function Obj }>(fields: O): Obj; +>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21)) +>_ : Symbol(_, Decl(invariantGenericErrorElaboration.ts, 16, 34)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>fields : Symbol(fields, Decl(invariantGenericErrorElaboration.ts, 16, 62)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21)) +>Obj : Symbol(Obj, Decl(invariantGenericErrorElaboration.ts, 13, 22), Decl(invariantGenericErrorElaboration.ts, 15, 111)) +>O : Symbol(O, Decl(invariantGenericErrorElaboration.ts, 16, 21)) + +interface Constraint> extends Runtype { +>Constraint : Symbol(Constraint, Decl(invariantGenericErrorElaboration.ts, 16, 81)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>Runtype : Symbol(Runtype, Decl(invariantGenericErrorElaboration.ts, 3, 29)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21)) + + underlying: A, +>underlying : Symbol(Constraint.underlying, Decl(invariantGenericErrorElaboration.ts, 18, 76)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21)) + + check: (x: A['witness']) => void, +>check : Symbol(Constraint.check, Decl(invariantGenericErrorElaboration.ts, 19, 16)) +>x : Symbol(x, Decl(invariantGenericErrorElaboration.ts, 20, 10)) +>A : Symbol(A, Decl(invariantGenericErrorElaboration.ts, 18, 21)) +} + diff --git a/tests/baselines/reference/invariantGenericErrorElaboration.types b/tests/baselines/reference/invariantGenericErrorElaboration.types new file mode 100644 index 00000000000..2120c06d5fa --- /dev/null +++ b/tests/baselines/reference/invariantGenericErrorElaboration.types @@ -0,0 +1,78 @@ +=== tests/cases/compiler/invariantGenericErrorElaboration.ts === +// Repro from #19746 + +const wat: Runtype = Num; +>wat : Runtype +>Runtype : Runtype +>Num : Num + +const Foo = Obj({ foo: Num }) +>Foo : any +>Obj({ foo: Num }) : any +>Obj : ; }>(fields: O) => Obj +>{ foo: Num } : { foo: Num; } +>foo : Num +>Num : Num + +interface Runtype { +>Runtype : Runtype +>A : A + + constraint: Constraint +>constraint : Constraint +>Constraint : Constraint + + witness: A +>witness : A +>A : A +} + +interface Num extends Runtype { +>Num : Num +>Runtype : Runtype + + tag: 'number' +>tag : "number" +} +declare const Num: Num +>Num : Num +>Num : Num + +interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} +>Obj : Obj +>O : O +>_ : _ +>Runtype : Runtype +>Runtype : Runtype +>K : K +>O : O +>O : O +>K : K + +declare function Obj }>(fields: O): Obj; +>Obj : ; }>(fields: O) => Obj +>O : O +>_ : string +>Runtype : Runtype +>fields : O +>O : O +>Obj : Obj +>O : O + +interface Constraint> extends Runtype { +>Constraint : Constraint +>A : A +>Runtype : Runtype +>Runtype : Runtype +>A : A + + underlying: A, +>underlying : A +>A : A + + check: (x: A['witness']) => void, +>check : (x: A["witness"]) => void +>x : A["witness"] +>A : A +} + diff --git a/tests/cases/compiler/invariantGenericErrorElaboration.ts b/tests/cases/compiler/invariantGenericErrorElaboration.ts new file mode 100644 index 00000000000..6191949dd8c --- /dev/null +++ b/tests/cases/compiler/invariantGenericErrorElaboration.ts @@ -0,0 +1,24 @@ +// @strict: true + +// Repro from #19746 + +const wat: Runtype = Num; +const Foo = Obj({ foo: Num }) + +interface Runtype { + constraint: Constraint + witness: A +} + +interface Num extends Runtype { + tag: 'number' +} +declare const Num: Num + +interface Obj }> extends Runtype<{[K in keyof O]: O[K]['witness'] }> {} +declare function Obj }>(fields: O): Obj; + +interface Constraint> extends Runtype { + underlying: A, + check: (x: A['witness']) => void, +} From d97335e4e719c28d8e80431a42aad4e772454916 Mon Sep 17 00:00:00 2001 From: micbou Date: Mon, 6 Nov 2017 18:45:52 +0100 Subject: [PATCH 22/25] Silence NPM warnings when installing typings (#19749) --- src/server/typingsInstaller/typingsInstaller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index c45275d0b3d..eacbebbf4ab 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -248,7 +248,7 @@ namespace ts.server.typingsInstaller { this.log.writeLine(`Npm config file: '${npmConfigPath}' is missing, creating new one...`); } this.ensureDirectoryExists(directory, this.installTypingHost); - this.installTypingHost.writeFile(npmConfigPath, '{ "description": "", "repository": "", "license": "" }'); + this.installTypingHost.writeFile(npmConfigPath, '{ "private": true }'); } } From 445001e1717f201255277dc48dcaf890577de86b Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 6 Nov 2017 10:24:21 -0800 Subject: [PATCH 23/25] Port generated lib files (#19772) --- src/lib/dom.generated.d.ts | 2 +- src/lib/webworker.generated.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index 5c7600624e8..ec488bb069e 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -15135,7 +15135,7 @@ type MouseWheelEvent = WheelEvent; type ScrollRestoration = "auto" | "manual"; type FormDataEntryValue = string | File; type InsertPosition = "beforebegin" | "afterbegin" | "beforeend" | "afterend"; -type HeadersInit = string[][] | { [key: string]: string }; +type HeadersInit = Headers | string[][] | { [key: string]: string }; type AppendMode = "segments" | "sequence"; type AudioContextState = "suspended" | "running" | "closed"; type BiquadFilterType = "lowpass" | "highpass" | "bandpass" | "lowshelf" | "highshelf" | "peaking" | "notch" | "allpass"; diff --git a/src/lib/webworker.generated.d.ts b/src/lib/webworker.generated.d.ts index 509c4b776c9..6eb17c33c5e 100644 --- a/src/lib/webworker.generated.d.ts +++ b/src/lib/webworker.generated.d.ts @@ -1890,7 +1890,7 @@ type USVString = string; type IDBValidKey = number | string | Date | IDBArrayKey; type BufferSource = ArrayBuffer | ArrayBufferView; type FormDataEntryValue = string | File; -type HeadersInit = string[][] | { [key: string]: string }; +type HeadersInit = Headers | string[][] | { [key: string]: string }; type IDBCursorDirection = "next" | "nextunique" | "prev" | "prevunique"; type IDBRequestReadyState = "pending" | "done"; type IDBTransactionMode = "readonly" | "readwrite" | "versionchange"; From c4bf21b9cb26c8936bf51636ac14cabf2cc44fe6 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 6 Nov 2017 10:59:39 -0800 Subject: [PATCH 24/25] Improvements to checkUnusedIdentifiers (#19607) --- src/compiler/checker.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 532eee363d7..eb5442a7996 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20430,21 +20430,20 @@ namespace ts { case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: - checkUnusedTypeParameters(node); - break; case SyntaxKind.TypeAliasDeclaration: - checkUnusedTypeParameters(node); + checkUnusedTypeParameters(node); break; + default: + Debug.fail("Node should not have been registered for unused identifiers check"); } } } } function checkUnusedLocalsAndParameters(node: Node): void { - if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) { + if (noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { if (!local.isReferenced) { if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) { From c016f5b9b0713d727ba3c07e59a2c97d3d148137 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 6 Nov 2017 11:24:17 -0800 Subject: [PATCH 25/25] Split runner selection from test selection (#19729) * Split runner selection from test selection * Continue to support old behavior --- Gulpfile.ts | 16 ++++++++++------ Jakefile.js | 13 ++++++++----- src/harness/runner.ts | 6 ++++-- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Gulpfile.ts b/Gulpfile.ts index 4d6dfdf2862..fd353083433 100644 --- a/Gulpfile.ts +++ b/Gulpfile.ts @@ -50,6 +50,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), { d: "debug", "debug-brk": "debug", i: "inspect", "inspect-brk": "inspect", t: "tests", test: "tests", + ru: "runners", runner: "runners", r: "reporter", c: "colors", color: "colors", f: "files", file: "files", @@ -64,6 +65,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), { browser: process.env.browser || process.env.b || "IE", timeout: process.env.timeout || 40000, tests: process.env.test || process.env.tests || process.env.t, + runners: process.env.runners || process.env.runner || process.env.ru, light: process.env.light === undefined || process.env.light !== "false", reporter: process.env.reporter || process.env.r, lint: process.env.lint || true, @@ -648,6 +650,7 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: const debug = cmdLineOptions.debug; const inspect = cmdLineOptions.inspect; const tests = cmdLineOptions.tests; + const runners = cmdLineOptions.runners; const light = cmdLineOptions.light; const stackTraceLimit = cmdLineOptions.stackTraceLimit; const testConfigFile = "test.config"; @@ -668,8 +671,8 @@ function runConsoleTests(defaultReporter: string, runInParallel: boolean, done: workerCount = cmdLineOptions.workers; } - if (tests || light || taskConfigsFolder) { - writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit); + if (tests || runners || light || taskConfigsFolder) { + writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit); } if (tests && tests.toLocaleLowerCase() === "rwc") { @@ -860,8 +863,8 @@ function cleanTestDirs(done: (e?: any) => void) { } // used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) { - const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions.colors }); +function writeTestConfigFile(tests: string, runners: string, light: boolean, taskConfigsFolder?: string, workerCount?: number, stackTraceLimit?: string) { + const testConfigContents = JSON.stringify({ test: tests ? [tests] : undefined, runner: runners ? runners.split(",") : undefined, light, workerCount, stackTraceLimit, taskConfigsFolder, noColor: !cmdLineOptions.colors }); console.log("Running tests with config: " + testConfigContents); fs.writeFileSync("test.config", testConfigContents); } @@ -872,13 +875,14 @@ gulp.task("runtests-browser", "Runs the tests using the built run.js file like ' if (err) { console.error(err); done(err); process.exit(1); } host = "node"; const tests = cmdLineOptions.tests; + const runners = cmdLineOptions.runners; const light = cmdLineOptions.light; const testConfigFile = "test.config"; if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } - if (tests || light) { - writeTestConfigFile(tests, light); + if (tests || runners || light) { + writeTestConfigFile(tests, runners, light); } const args = [nodeServerOutFile]; diff --git a/Jakefile.js b/Jakefile.js index 13607f7b40f..7f0915ad7e9 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -844,8 +844,9 @@ function cleanTestDirs() { } // used to pass data from jake command line directly to run.js -function writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) { +function writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors) { var testConfigContents = JSON.stringify({ + runners: runners ? runners.split(",") : undefined, test: tests ? [tests] : undefined, light: light, workerCount: workerCount, @@ -871,6 +872,7 @@ function runConsoleTests(defaultReporter, runInParallel) { var debug = process.env.debug || process.env["debug-brk"] || process.env.d; var inspect = process.env.inspect || process.env["inspect-brk"] || process.env.i; var testTimeout = process.env.timeout || defaultTestTimeout; + var runners = process.env.runners || process.env.runner || process.env.ru; var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light === undefined || process.env.light !== "false"; var stackTraceLimit = process.env.stackTraceLimit; @@ -892,8 +894,8 @@ function runConsoleTests(defaultReporter, runInParallel) { workerCount = process.env.workerCount || process.env.p || os.cpus().length; } - if (tests || light || taskConfigsFolder) { - writeTestConfigFile(tests, light, taskConfigsFolder, workerCount, stackTraceLimit, colors); + if (tests || runners || light || taskConfigsFolder) { + writeTestConfigFile(tests, runners, light, taskConfigsFolder, workerCount, stackTraceLimit, colors); } if (tests && tests.toLocaleLowerCase() === "rwc") { @@ -1028,14 +1030,15 @@ task("runtests-browser", ["browserify", nodeServerOutFile], function () { cleanTestDirs(); host = "node"; var browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE"); + var runners = process.env.runners || process.env.runner || process.env.ru; var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; var testConfigFile = 'test.config'; if (fs.existsSync(testConfigFile)) { fs.unlinkSync(testConfigFile); } - if (tests || light) { - writeTestConfigFile(tests, light); + if (tests || runners || light) { + writeTestConfigFile(tests, runners, light); } tests = tests ? tests : ''; diff --git a/src/harness/runner.ts b/src/harness/runner.ts index b538f90bc39..70954e9e853 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -95,6 +95,7 @@ interface TestConfig { workerCount?: number; stackTraceLimit?: number | "full"; test?: string[]; + runners?: string[]; runUnitTests?: boolean; noColors?: boolean; } @@ -132,8 +133,9 @@ function handleTestConfig() { return true; } - if (testConfig.test && testConfig.test.length > 0) { - for (const option of testConfig.test) { + const runnerConfig = testConfig.runners || testConfig.test; + if (runnerConfig && runnerConfig.length > 0) { + for (const option of runnerConfig) { if (!option) { continue; }