From 9cbe4eb6144c0bc6b7527210eb18e648d73032ae Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Mon, 20 Nov 2017 18:30:28 -0800 Subject: [PATCH 01/39] Convert legacy safe list keys to lowercase on construction --- src/harness/unittests/tsserverProjectSystem.ts | 6 +++++- src/server/editorServices.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 2ca7d4e21dd..caeb3a81963 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1561,7 +1561,11 @@ namespace ts.projectSystem { path: "/a/b/foo.js", content: "" }; - const host = createServerHost([file1, file2, customTypesMap]); + const file3 = { + path: "/a/b/Bacon.js", + content: "let y = 5" + }; + const host = createServerHost([file1, file2, file3, customTypesMap]); const projectService = createProjectService(host); try { projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index bda540d6b39..e57f76d2ea0 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -527,7 +527,9 @@ namespace ts.server { } // raw is now fixed and ready this.safelist = raw.typesMap; - this.legacySafelist = raw.simpleMap; + for (const key in raw.simpleMap) { + this.legacySafelist[key] = raw.simpleMap[key].toLowerCase(); + } } catch (e) { this.logger.info(`Error loading types map: ${e}`); From 71e07df817905fcabb51d2a2ecb7de0f27c37178 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Mon, 20 Nov 2017 18:43:14 -0800 Subject: [PATCH 02/39] Check hasOwnProperty before copying property --- src/server/editorServices.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index e57f76d2ea0..f0bb81f3256 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -528,7 +528,9 @@ namespace ts.server { // raw is now fixed and ready this.safelist = raw.typesMap; for (const key in raw.simpleMap) { - this.legacySafelist[key] = raw.simpleMap[key].toLowerCase(); + if (raw.simpleMap.hasOwnProperty(key)) { + this.legacySafelist[key] = raw.simpleMap[key].toLowerCase(); + } } } catch (e) { From 1793652373c4dad232b2a32df4d65fff312a48f9 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Mon, 20 Nov 2017 18:51:07 -0800 Subject: [PATCH 03/39] Correct project root path passed to Typings Installer `createInstallTypingsRequest` has its own logic for extracting the project root path from the project name and it disagrees with the versions in the project flavors. In particular, it only drops the last component of the name if it exists. For folder projects and JS-only contexts, this will not be the case, but the last entry should still be dropped. TL;DR: stop creating filewatchers for "c:/foo/foo.csproj*jscontent/node_modules" --- src/server/utilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/utilities.ts b/src/server/utilities.ts index c57d3b40dee..d76ff1bf6d0 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -43,7 +43,7 @@ namespace ts.server { return ""; case ProjectKind.External: const projectName = normalizeSlashes(project.getProjectName()); - return project.projectService.host.fileExists(projectName) ? getDirectoryPath(projectName) : projectName; + return getDirectoryPath(projectName); } } From ee2d436999bb3fa10d27bc0f30656e2b249f4af4 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Mon, 20 Nov 2017 14:43:25 -0800 Subject: [PATCH 04/39] Always send a response to installTypings even if all types are cached --- src/harness/unittests/typingsInstaller.ts | 2 +- src/server/typingsInstaller/typingsInstaller.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index 393d55a5ea4..d0038902ae7 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -1018,7 +1018,7 @@ namespace ts.projectSystem { } }; session.executeCommand(changeRequest); - host.checkTimeoutQueueLengthAndRun(0); // This enqueues the updategraph and refresh inferred projects + host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion(); assert.equal(version1, version2, "set of unresolved imports should not change"); }); diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index 63bbc219789..3e8f79d0f1d 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -257,8 +257,9 @@ namespace ts.server.typingsInstaller { const filteredTypings = this.filterTypings(typingsToInstall); if (filteredTypings.length === 0) { if (this.log.isEnabled()) { - this.log.writeLine(`All typings are known to be missing or invalid - no need to go any further`); + this.log.writeLine(`All typings are known to be missing or invalid - no need to install more typings`); } + this.sendResponse(this.createSetTypings(req, currentlyCachedTypings)); return; } From 7c5a0ec9c600d618687745cd86532b3bec3ede37 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 21 Nov 2017 14:27:26 -0500 Subject: [PATCH 05/39] Clean up outliningElementsCollector (#20143) * Clean up outliningElementsCollector * Use depthRemaining instead of maxDepth --- src/services/outliningElementsCollector.ts | 359 ++++++++---------- tests/cases/fourslash/getOutliningSpans.ts | 10 +- .../fourslash/shims-pp/getOutliningSpans.ts | 10 +- .../fourslash/shims/getOutliningSpans.ts | 10 +- 4 files changed, 164 insertions(+), 225 deletions(-) diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index bd294209088..f3f91724a9c 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -1,227 +1,166 @@ /* @internal */ namespace ts.OutliningElementsCollector { - const collapseText = "..."; - const maxDepth = 40; - const defaultLabel = "#region"; - const regionMatch = new RegExp("^\\s*//\\s*#(end)?region(?:\\s+(.*))?$"); - export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] { - const elements: OutliningSpan[] = []; - let depth = 0; - const regions: OutliningSpan[] = []; + const res: OutliningSpan[] = []; + addNodeOutliningSpans(sourceFile, cancellationToken, res); + addRegionOutliningSpans(sourceFile, res); + return res.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start); + } - walk(sourceFile); - gatherRegions(); - return elements.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start); - - /** If useFullStart is true, then the collapsing span includes leading whitespace, including linebreaks. */ - function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean, useFullStart: boolean) { - if (hintSpanNode && startElement && endElement) { - const span: OutliningSpan = { - textSpan: createTextSpanFromBounds(useFullStart ? startElement.getFullStart() : startElement.getStart(), endElement.getEnd()), - hintSpan: createTextSpanFromNode(hintSpanNode, sourceFile), - bannerText: collapseText, - autoCollapse, - }; - elements.push(span); - } - } - - function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) { - if (commentSpan) { - const span: OutliningSpan = { - textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), - hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), - bannerText: collapseText, - autoCollapse, - }; - elements.push(span); - } - } - - function addOutliningForLeadingCommentsForNode(n: Node) { - const comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); - - if (comments) { - let firstSingleLineCommentStart = -1; - let lastSingleLineCommentEnd = -1; - let isFirstSingleLineComment = true; - let singleLineCommentCount = 0; - - for (const currentComment of comments) { - cancellationToken.throwIfCancellationRequested(); - - // For single line comments, combine consecutive ones (2 or more) into - // a single span from the start of the first till the end of the last - if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) { - if (isFirstSingleLineComment) { - firstSingleLineCommentStart = currentComment.pos; - } - isFirstSingleLineComment = false; - lastSingleLineCommentEnd = currentComment.end; - singleLineCommentCount++; - } - else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) { - combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); - addOutliningSpanComments(currentComment, /*autoCollapse*/ false); - - singleLineCommentCount = 0; - lastSingleLineCommentEnd = -1; - isFirstSingleLineComment = true; - } - } - - combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); - } - } - - function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) { - - // Only outline spans of two or more consecutive single line comments - if (count > 1) { - const multipleSingleLineComments: CommentRange = { - kind: SyntaxKind.SingleLineCommentTrivia, - pos: start, - end, - }; - - addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false); - } - } - - function autoCollapse(node: Node) { - return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; - } - - function gatherRegions(): void { - const lineStarts = sourceFile.getLineStarts(); - - for (let i = 0; i < lineStarts.length; i++) { - const currentLineStart = lineStarts[i]; - const lineEnd = lineStarts[i + 1] - 1 || sourceFile.getEnd(); - const comment = sourceFile.text.substring(currentLineStart, lineEnd); - const result = comment.match(regionMatch); - - if (result && !isInComment(sourceFile, currentLineStart)) { - if (!result[1]) { - const start = sourceFile.getFullText().indexOf("//", currentLineStart); - const textSpan = createTextSpanFromBounds(start, lineEnd); - const region: OutliningSpan = { - textSpan, - hintSpan: textSpan, - bannerText: result[2] || defaultLabel, - autoCollapse: false - }; - regions.push(region); - } - else { - const region = regions.pop(); - if (region) { - region.textSpan.length = lineEnd - region.textSpan.start; - region.hintSpan.length = lineEnd - region.textSpan.start; - elements.push(region); - } - } - } - } - } - - function walk(n: Node): void { + function addNodeOutliningSpans(sourceFile: SourceFile, cancellationToken: CancellationToken, out: Push): void { + let depthRemaining = 40; + sourceFile.forEachChild(function walk(n) { + if (depthRemaining === 0) return; cancellationToken.throwIfCancellationRequested(); - if (depth > maxDepth) { - return; - } if (isDeclaration(n)) { - addOutliningForLeadingCommentsForNode(n); + addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out); } - switch (n.kind) { - case SyntaxKind.Block: - if (!isFunctionBlock(n)) { - const parent = n.parent; - const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + const span = getOutliningSpanForNode(n, sourceFile); + if (span) out.push(span); - // Check if the block is standalone, or 'attached' to some parent statement. - // If the latter, we want to collapse the block, but consider its hint span - // to be the entire span of the parent. - if (parent.kind === SyntaxKind.DoStatement || - parent.kind === SyntaxKind.ForInStatement || - parent.kind === SyntaxKind.ForOfStatement || - parent.kind === SyntaxKind.ForStatement || - parent.kind === SyntaxKind.IfStatement || - parent.kind === SyntaxKind.WhileStatement || - parent.kind === SyntaxKind.WithStatement || - parent.kind === SyntaxKind.CatchClause) { + depthRemaining--; + n.forEachChild(walk); + depthRemaining++; + }); + } - addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true); - break; - } + function addRegionOutliningSpans(sourceFile: SourceFile, out: Push): void { + const regions: OutliningSpan[] = []; + const lineStarts = sourceFile.getLineStarts(); + for (let i = 0; i < lineStarts.length; i++) { + const currentLineStart = lineStarts[i]; + const lineEnd = i + 1 === lineStarts.length ? sourceFile.getEnd() : lineStarts[i + 1] - 1; + const lineText = sourceFile.text.substring(currentLineStart, lineEnd); + const result = lineText.match(/^\s*\/\/\s*#(end)?region(?:\s+(.*))?$/); + if (!result || isInComment(sourceFile, currentLineStart)) { + continue; + } - if (parent.kind === SyntaxKind.TryStatement) { - // Could be the try-block, or the finally-block. - const tryStatement = parent; - if (tryStatement.tryBlock === n) { - addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true); - break; - } - else if (tryStatement.finallyBlock === n) { - const finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); - if (finallyKeyword) { - addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true); - break; - } - } - - // fall through. - } - - // Block was a standalone block. In this case we want to only collapse - // the span of the block, independent of any parent span. - const span = createTextSpanFromNode(n); - elements.push({ - textSpan: span, - hintSpan: span, - bannerText: collapseText, - autoCollapse: autoCollapse(n) - }); - break; - } - // falls through - - case SyntaxKind.ModuleBlock: { - const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true); - break; - } - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.CaseBlock: { - const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ true); - break; + if (!result[1]) { + const span = createTextSpanFromBounds(sourceFile.text.indexOf("//", currentLineStart), lineEnd); + regions.push(createOutliningSpan(span, span, /*autoCollapse*/ false, result[2] || "#region")); + } + else { + const region = regions.pop(); + if (region) { + region.textSpan.length = lineEnd - region.textSpan.start; + region.hintSpan.length = lineEnd - region.textSpan.start; + out.push(region); } - // If the block has no leading keywords and is inside an array literal, - // we only want to collapse the span of the block. - // Otherwise, the collapsed section will include the end of the previous line. - case SyntaxKind.ObjectLiteralExpression: - const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n), /*useFullStart*/ !isArrayLiteralExpression(n.parent)); - break; - case SyntaxKind.ArrayLiteralExpression: - const openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile); - const closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile); - addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n), /*useFullStart*/ !isArrayLiteralExpression(n.parent)); - break; } - depth++; - forEachChild(n, walk); - depth--; } } + + function addOutliningForLeadingCommentsForNode(n: Node, sourceFile: SourceFile, cancellationToken: CancellationToken, out: Push): void { + const comments = getLeadingCommentRangesOfNode(n, sourceFile); + if (!comments) return; + let firstSingleLineCommentStart = -1; + let lastSingleLineCommentEnd = -1; + let singleLineCommentCount = 0; + for (const { kind, pos, end } of comments) { + cancellationToken.throwIfCancellationRequested(); + switch (kind) { + case SyntaxKind.SingleLineCommentTrivia: + // For single line comments, combine consecutive ones (2 or more) into + // a single span from the start of the first till the end of the last + if (singleLineCommentCount === 0) { + firstSingleLineCommentStart = pos; + } + lastSingleLineCommentEnd = end; + singleLineCommentCount++; + break; + case SyntaxKind.MultiLineCommentTrivia: + combineAndAddMultipleSingleLineComments(); + out.push(createOutliningSpanFromBounds(pos, end)); + singleLineCommentCount = 0; + break; + default: + Debug.assertNever(kind); + } + } + combineAndAddMultipleSingleLineComments(); + + function combineAndAddMultipleSingleLineComments(): void { + // Only outline spans of two or more consecutive single line comments + if (singleLineCommentCount > 1) { + out.push(createOutliningSpanFromBounds(firstSingleLineCommentStart, lastSingleLineCommentEnd)); + } + } + } + + function createOutliningSpanFromBounds(pos: number, end: number): OutliningSpan { + return createOutliningSpan(createTextSpanFromBounds(pos, end)); + } + + function getOutliningSpanForNode(n: Node, sourceFile: SourceFile): OutliningSpan | undefined { + switch (n.kind) { + case SyntaxKind.Block: + if (isFunctionBlock(n)) { + return spanForNode(n.parent, /*autoCollapse*/ n.parent.kind !== SyntaxKind.ArrowFunction); + } + // Check if the block is standalone, or 'attached' to some parent statement. + // If the latter, we want to collapse the block, but consider its hint span + // to be the entire span of the parent. + switch (n.parent.kind) { + case SyntaxKind.DoStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.IfStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.CatchClause: + return spanForNode(n.parent); + case SyntaxKind.TryStatement: + // Could be the try-block, or the finally-block. + const tryStatement = n.parent; + if (tryStatement.tryBlock === n) { + return spanForNode(n.parent); + } + else if (tryStatement.finallyBlock === n) { + return spanForNode(findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile)!); + } + // falls through + default: + // Block was a standalone block. In this case we want to only collapse + // the span of the block, independent of any parent span. + return createOutliningSpan(createTextSpanFromNode(n, sourceFile)); + } + case SyntaxKind.ModuleBlock: + return spanForNode(n.parent); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.CaseBlock: + return spanForNode(n); + case SyntaxKind.ObjectLiteralExpression: + return spanForObjectOrArrayLiteral(n); + case SyntaxKind.ArrayLiteralExpression: + return spanForObjectOrArrayLiteral(n, SyntaxKind.OpenBracketToken); + } + + function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined { + // If the block has no leading keywords and is inside an array literal, + // we only want to collapse the span of the block. + // Otherwise, the collapsed section will include the end of the previous line. + return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent), open); + } + + function spanForNode(hintSpanNode: Node, autoCollapse = false, useFullStart = true, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined { + const openToken = findChildOfKind(n, open, sourceFile); + const close = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken : SyntaxKind.CloseBracketToken; + const closeToken = findChildOfKind(n, close, sourceFile); + if (!openToken || !closeToken) { + return undefined; + } + const textSpan = createTextSpanFromBounds(useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), closeToken.getEnd()); + return createOutliningSpan(textSpan, createTextSpanFromNode(hintSpanNode, sourceFile), autoCollapse); + } + } + + function createOutliningSpan(textSpan: TextSpan, hintSpan: TextSpan = textSpan, autoCollapse = false, bannerText = "..."): OutliningSpan { + return { textSpan, hintSpan, bannerText, autoCollapse }; + } } \ No newline at end of file diff --git a/tests/cases/fourslash/getOutliningSpans.ts b/tests/cases/fourslash/getOutliningSpans.ts index 4e2a58c9acb..63e8becfc4f 100644 --- a/tests/cases/fourslash/getOutliningSpans.ts +++ b/tests/cases/fourslash/getOutliningSpans.ts @@ -1,6 +1,6 @@ /// -////// interface +////// interface ////interface IFoo[| { //// getDist(): number; ////}|] @@ -63,9 +63,9 @@ ////}|]) //// ////// trivia handeling -////class ClassFooWithTrivia[| /* some comments */ +////class ClassFooWithTrivia[| /* some comments */ //// /* more trivia */ { -//// +//// //// //// /*some trailing trivia */ ////}|] /* even more */ @@ -85,8 +85,8 @@ //// [ //// [ //// [ -//// 1,2,3 -//// ] +//// 1,2,3 +//// ] //// ] //// ] //// ] diff --git a/tests/cases/fourslash/shims-pp/getOutliningSpans.ts b/tests/cases/fourslash/shims-pp/getOutliningSpans.ts index 4e2a58c9acb..63e8becfc4f 100644 --- a/tests/cases/fourslash/shims-pp/getOutliningSpans.ts +++ b/tests/cases/fourslash/shims-pp/getOutliningSpans.ts @@ -1,6 +1,6 @@ /// -////// interface +////// interface ////interface IFoo[| { //// getDist(): number; ////}|] @@ -63,9 +63,9 @@ ////}|]) //// ////// trivia handeling -////class ClassFooWithTrivia[| /* some comments */ +////class ClassFooWithTrivia[| /* some comments */ //// /* more trivia */ { -//// +//// //// //// /*some trailing trivia */ ////}|] /* even more */ @@ -85,8 +85,8 @@ //// [ //// [ //// [ -//// 1,2,3 -//// ] +//// 1,2,3 +//// ] //// ] //// ] //// ] diff --git a/tests/cases/fourslash/shims/getOutliningSpans.ts b/tests/cases/fourslash/shims/getOutliningSpans.ts index 4e2a58c9acb..63e8becfc4f 100644 --- a/tests/cases/fourslash/shims/getOutliningSpans.ts +++ b/tests/cases/fourslash/shims/getOutliningSpans.ts @@ -1,6 +1,6 @@ /// -////// interface +////// interface ////interface IFoo[| { //// getDist(): number; ////}|] @@ -63,9 +63,9 @@ ////}|]) //// ////// trivia handeling -////class ClassFooWithTrivia[| /* some comments */ +////class ClassFooWithTrivia[| /* some comments */ //// /* more trivia */ { -//// +//// //// //// /*some trailing trivia */ ////}|] /* even more */ @@ -85,8 +85,8 @@ //// [ //// [ //// [ -//// 1,2,3 -//// ] +//// 1,2,3 +//// ] //// ] //// ] //// ] From 6e57c2630f147cde2ad92a8782d94c0e0287edf9 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 21 Nov 2017 14:29:52 -0500 Subject: [PATCH 06/39] Support getJSDocCommentsAndTags for special property assignments (#20193) --- src/compiler/utilities.ts | 11 +++++++---- .../fourslash/quickInfoSpecialPropertyAssignment.ts | 10 ++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/quickInfoSpecialPropertyAssignment.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 46835bd94d5..28520919e1e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1463,7 +1463,7 @@ namespace ts { /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder - export function getSpecialPropertyAssignmentKind(expr: ts.BinaryExpression): SpecialPropertyAssignmentKind { + export function getSpecialPropertyAssignmentKind(expr: BinaryExpression): SpecialPropertyAssignmentKind { if (!isInJavaScriptFile(expr)) { return SpecialPropertyAssignmentKind.None; } @@ -1609,15 +1609,15 @@ namespace ts { function getJSDocCommentsAndTagsWorker(node: Node): void { const parent = node.parent; + if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) { + getJSDocCommentsAndTagsWorker(parent); + } // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. // /** // * @param {number} name // * @returns {number} // */ // var x = function(name) { return name.length; } - if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) { - getJSDocCommentsAndTagsWorker(parent); - } if (parent && parent.parent && (getSingleVariableOfVariableStatement(parent.parent, node) || getSourceOfAssignment(parent.parent))) { getJSDocCommentsAndTagsWorker(parent.parent); @@ -1625,6 +1625,9 @@ namespace ts { if (parent && parent.parent && parent.parent.parent && getSingleInitializerOfVariableStatement(parent.parent.parent, node)) { getJSDocCommentsAndTagsWorker(parent.parent.parent); } + if (isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) !== SpecialPropertyAssignmentKind.None) { + getJSDocCommentsAndTagsWorker(parent); + } // Pull parameter comments from declaring function as well if (node.kind === SyntaxKind.Parameter) { diff --git a/tests/cases/fourslash/quickInfoSpecialPropertyAssignment.ts b/tests/cases/fourslash/quickInfoSpecialPropertyAssignment.ts new file mode 100644 index 00000000000..817e68f6782 --- /dev/null +++ b/tests/cases/fourslash/quickInfoSpecialPropertyAssignment.ts @@ -0,0 +1,10 @@ +// @allowJs: true +// @Filename: /a.js +////class C { +//// constructor() { +//// /** Doc */ +//// this./**/x = 0; +//// } +////} + +verify.quickInfoAt("", "(property) C.x: number", "Doc "); From 8c6863aff8686a9d022f3edb82e6883221bbb3cb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 21 Nov 2017 13:08:04 -0800 Subject: [PATCH 07/39] Add dt baseline folder to gitignore (#20205) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 40c473d13dd..19d96d0b046 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ tests/cases/user/*/**/*.d.ts !tests/cases/user/zone.js/ !tests/cases/user/bignumber.js/ !tests/cases/user/discord.js/ +tests/baselines/reference/dt \ No newline at end of file From 50866e114ab5dfe38ff49dea6bc9a557e6bbf817 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 21 Nov 2017 15:06:27 -0800 Subject: [PATCH 08/39] Fix visibility checking of mutually recursive exports (#19929) * Do visibility painting from collectLinkedAliases in checker to remove statefullness in declaration emit * Fix #17085 * Add deeply destructured array to test * Add test case for #18634 * Add PR feedback --- src/compiler/checker.ts | 22 +++- src/compiler/declarationEmitter.ts | 18 ++- .../reference/destructuredDeclarationEmit.js | 77 +++++++++++++ .../destructuredDeclarationEmit.symbols | 73 +++++++++++++ .../destructuredDeclarationEmit.types | 103 ++++++++++++++++++ .../mutuallyRecursiveInterfaceDeclaration.js | 23 ++++ ...uallyRecursiveInterfaceDeclaration.symbols | 20 ++++ ...utuallyRecursiveInterfaceDeclaration.types | 20 ++++ .../compiler/destructuredDeclarationEmit.ts | 21 ++++ .../mutuallyRecursiveInterfaceDeclaration.ts | 9 ++ 10 files changed, 376 insertions(+), 10 deletions(-) create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.js create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.symbols create mode 100644 tests/baselines/reference/destructuredDeclarationEmit.types create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols create mode 100644 tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types create mode 100644 tests/cases/compiler/destructuredDeclarationEmit.ts create mode 100644 tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8c1835b5a2a..cc04bd02d9b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4047,15 +4047,15 @@ namespace ts { } } - function collectLinkedAliases(node: Identifier): Node[] { + function collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined { let exportSymbol: Symbol; if (node.parent && node.parent.kind === SyntaxKind.ExportAssignment) { - exportSymbol = resolveName(node.parent, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, Diagnostics.Cannot_find_name_0, node, /*isUse*/ false); + exportSymbol = resolveName(node, node.escapedText, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias, /*nameNotFoundMessage*/ undefined, node, /*isUse*/ false); } else if (node.parent.kind === SyntaxKind.ExportSpecifier) { exportSymbol = getTargetOfExportSpecifier(node.parent, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias); } - const result: Node[] = []; + let result: Node[]; if (exportSymbol) { buildVisibleNodeList(exportSymbol.declarations); } @@ -4063,9 +4063,14 @@ namespace ts { function buildVisibleNodeList(declarations: Declaration[]) { forEach(declarations, declaration => { - getNodeLinks(declaration).isVisible = true; const resultNode = getAnyImportSyntax(declaration) || declaration; - pushIfUnique(result, resultNode); + if (setVisibility) { + getNodeLinks(declaration).isVisible = true; + } + else { + result = result || []; + pushIfUnique(result, resultNode); + } if (isInternalModuleImportEqualsDeclaration(declaration)) { // Add the referenced top container visible @@ -23328,6 +23333,9 @@ namespace ts { function checkExportSpecifier(node: ExportSpecifier) { checkAliasSymbol(node); + if (compilerOptions.declaration) { + collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); // Collect linked aliases to set visibility links + } if (!(node.parent.parent).moduleSpecifier) { const exportedName = node.propertyName || node.name; // find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases) @@ -23365,6 +23373,10 @@ namespace ts { } if (node.expression.kind === SyntaxKind.Identifier) { markExportAsReferenced(node); + + if (compilerOptions.declaration) { + collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes + } } else { checkExpressionCached(node.expression); diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index ebd2985dd45..dc76e0ddf50 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -1249,10 +1249,18 @@ namespace ts { writeLine(); } + function bindingNameContainsVisibleBindingElement(node: BindingName): boolean { + return !!node && isBindingPattern(node) && some(node.elements, elem => !isOmittedExpression(elem) && isVariableDeclarationVisible(elem)); + } + + function isVariableDeclarationVisible(node: VariableDeclaration | BindingElement) { + return resolver.isDeclarationVisible(node) || bindingNameContainsVisibleBindingElement(node.name); + } + function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) { // If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted // so there is no check needed to see if declaration is visible - if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) { + if (node.kind !== SyntaxKind.VariableDeclaration || isVariableDeclarationVisible(node)) { if (isBindingPattern(node.name)) { emitBindingPattern(node.name); } @@ -1324,14 +1332,14 @@ namespace ts { } function emitBindingPattern(bindingPattern: BindingPattern) { - // Only select non-omitted expression from the bindingPattern's elements. + // Only select visible, non-omitted expression from the bindingPattern's elements. // We have to do this to avoid emitting trailing commas. // For example: // original: var [, c,,] = [ 2,3,4] // emitted: declare var c: number; // instead of declare var c:number, ; const elements: Node[] = []; for (const element of bindingPattern.elements) { - if (element.kind !== SyntaxKind.OmittedExpression) { + if (element.kind !== SyntaxKind.OmittedExpression && isVariableDeclarationVisible(element)) { elements.push(element); } } @@ -1371,7 +1379,7 @@ namespace ts { } function isVariableStatementVisible(node: VariableStatement) { - return forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); + return forEach(node.declarationList.declarations, varDeclaration => isVariableDeclarationVisible(varDeclaration)); } function writeVariableStatement(node: VariableStatement) { @@ -1390,7 +1398,7 @@ namespace ts { else { write("var "); } - emitCommaList(node.declarationList.declarations, emitVariableDeclaration, resolver.isDeclarationVisible); + emitCommaList(node.declarationList.declarations, emitVariableDeclaration, isVariableDeclarationVisible); write(";"); writeLine(); } diff --git a/tests/baselines/reference/destructuredDeclarationEmit.js b/tests/baselines/reference/destructuredDeclarationEmit.js new file mode 100644 index 00000000000..d4197652581 --- /dev/null +++ b/tests/baselines/reference/destructuredDeclarationEmit.js @@ -0,0 +1,77 @@ +//// [tests/cases/compiler/destructuredDeclarationEmit.ts] //// + +//// [foo.ts] +const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } }; +const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]]; +export { foo, arr }; +//// [index.ts] +import { foo, arr } from './foo'; +export { foo, arr }; + +const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo; +export { baz, ibaz }; + +const [ , one, , [, bee, , [, {sec} ]]] = arr; +export { one, bee, sec }; + +const getFoo = () => ({ + foo: 'foo' +}); + +const { foo: foo2 } = getFoo(); +export { foo2 }; + + +//// [foo.js] +"use strict"; +exports.__esModule = true; +var foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } }; +exports.foo = foo; +var arr = [0, 1, 2, ['a', 'b', 'c', [{ def: 'def' }, { sec: 'sec' }]]]; +exports.arr = arr; +//// [index.js] +"use strict"; +exports.__esModule = true; +var foo_1 = require("./foo"); +exports.foo = foo_1.foo; +exports.arr = foo_1.arr; +var baz = foo_1.foo.bar, bat = foo_1.foo.bat, _a = foo_1.foo.bam.bork, ibar = _a.bar, ibaz = _a.baz; +exports.baz = baz; +exports.ibaz = ibaz; +var one = foo_1.arr[1], _b = foo_1.arr[3], bee = _b[1], _c = _b[3], sec = _c[1].sec; +exports.one = one; +exports.bee = bee; +exports.sec = sec; +var getFoo = function () { return ({ + foo: 'foo' +}); }; +var foo2 = getFoo().foo; +exports.foo2 = foo2; + + +//// [foo.d.ts] +declare const foo: { + bar: string; + bat: string; + bam: { + bork: { + bar: string; + baz: string; + }; + }; +}; +declare const arr: [0, 1, 2, ['a', 'b', 'c', [{ + def: 'def'; +}, { + sec: 'sec'; +}]]]; +export { foo, arr }; +//// [index.d.ts] +import { foo, arr } from './foo'; +export { foo, arr }; +declare const baz: string, ibaz: string; +export { baz, ibaz }; +declare const one: 1, bee: "b", sec: "sec"; +export { one, bee, sec }; +declare const foo2: string; +export { foo2 }; diff --git a/tests/baselines/reference/destructuredDeclarationEmit.symbols b/tests/baselines/reference/destructuredDeclarationEmit.symbols new file mode 100644 index 00000000000..daeed5befd7 --- /dev/null +++ b/tests/baselines/reference/destructuredDeclarationEmit.symbols @@ -0,0 +1,73 @@ +=== tests/cases/compiler/foo.ts === +const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } }; +>foo : Symbol(foo, Decl(foo.ts, 0, 5)) +>bar : Symbol(bar, Decl(foo.ts, 0, 13)) +>bat : Symbol(bat, Decl(foo.ts, 0, 27)) +>bam : Symbol(bam, Decl(foo.ts, 0, 41)) +>bork : Symbol(bork, Decl(foo.ts, 0, 48)) +>bar : Symbol(bar, Decl(foo.ts, 0, 56)) +>baz : Symbol(baz, Decl(foo.ts, 0, 66)) + +const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]]; +>arr : Symbol(arr, Decl(foo.ts, 1, 5)) +>def : Symbol(def, Decl(foo.ts, 1, 39)) +>sec : Symbol(sec, Decl(foo.ts, 1, 53)) +>def : Symbol(def, Decl(foo.ts, 1, 98)) +>sec : Symbol(sec, Decl(foo.ts, 1, 112)) + +export { foo, arr }; +>foo : Symbol(foo, Decl(foo.ts, 2, 8)) +>arr : Symbol(arr, Decl(foo.ts, 2, 13)) + +=== tests/cases/compiler/index.ts === +import { foo, arr } from './foo'; +>foo : Symbol(foo, Decl(index.ts, 0, 8)) +>arr : Symbol(arr, Decl(index.ts, 0, 13)) + +export { foo, arr }; +>foo : Symbol(foo, Decl(index.ts, 1, 8)) +>arr : Symbol(arr, Decl(index.ts, 1, 13)) + +const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo; +>bar : Symbol(bar, Decl(foo.ts, 0, 13)) +>baz : Symbol(baz, Decl(index.ts, 3, 7)) +>bat : Symbol(bat, Decl(index.ts, 3, 17)) +>bam : Symbol(bam, Decl(foo.ts, 0, 41)) +>bork : Symbol(bork, Decl(foo.ts, 0, 48)) +>bar : Symbol(bar, Decl(foo.ts, 0, 56)) +>ibar : Symbol(ibar, Decl(index.ts, 3, 37)) +>baz : Symbol(baz, Decl(foo.ts, 0, 66)) +>ibaz : Symbol(ibaz, Decl(index.ts, 3, 48)) +>foo : Symbol(foo, Decl(index.ts, 0, 8)) + +export { baz, ibaz }; +>baz : Symbol(baz, Decl(index.ts, 4, 8)) +>ibaz : Symbol(ibaz, Decl(index.ts, 4, 13)) + +const [ , one, , [, bee, , [, {sec} ]]] = arr; +>one : Symbol(one, Decl(index.ts, 6, 9)) +>bee : Symbol(bee, Decl(index.ts, 6, 19)) +>sec : Symbol(sec, Decl(index.ts, 6, 31)) +>arr : Symbol(arr, Decl(index.ts, 0, 13)) + +export { one, bee, sec }; +>one : Symbol(one, Decl(index.ts, 7, 8)) +>bee : Symbol(bee, Decl(index.ts, 7, 13)) +>sec : Symbol(sec, Decl(index.ts, 7, 18)) + +const getFoo = () => ({ +>getFoo : Symbol(getFoo, Decl(index.ts, 9, 5)) + + foo: 'foo' +>foo : Symbol(foo, Decl(index.ts, 9, 23)) + +}); + +const { foo: foo2 } = getFoo(); +>foo : Symbol(foo, Decl(index.ts, 9, 23)) +>foo2 : Symbol(foo2, Decl(index.ts, 13, 7)) +>getFoo : Symbol(getFoo, Decl(index.ts, 9, 5)) + +export { foo2 }; +>foo2 : Symbol(foo2, Decl(index.ts, 14, 8)) + diff --git a/tests/baselines/reference/destructuredDeclarationEmit.types b/tests/baselines/reference/destructuredDeclarationEmit.types new file mode 100644 index 00000000000..94845f94885 --- /dev/null +++ b/tests/baselines/reference/destructuredDeclarationEmit.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/foo.ts === +const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } }; +>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } +>{ bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } } : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } +>bar : string +>'hello' : "hello" +>bat : string +>'world' : "world" +>bam : { bork: { bar: string; baz: string; }; } +>{ bork: { bar: 'a', baz: 'b' } } : { bork: { bar: string; baz: string; }; } +>bork : { bar: string; baz: string; } +>{ bar: 'a', baz: 'b' } : { bar: string; baz: string; } +>bar : string +>'a' : "a" +>baz : string +>'b' : "b" + +const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]]; +>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] +>def : "def" +>sec : "sec" +>[0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] +>0 : 0 +>1 : 1 +>2 : 2 +>['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]] : ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]] +>'a' : "a" +>'b' : "b" +>'c' : "c" +>[{def: 'def'}, {sec: 'sec'}] : [{ def: "def"; }, { sec: "sec"; }] +>{def: 'def'} : { def: "def"; } +>def : string +>'def' : "def" +>{sec: 'sec'} : { sec: "sec"; } +>sec : string +>'sec' : "sec" + +export { foo, arr }; +>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } +>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] + +=== tests/cases/compiler/index.ts === +import { foo, arr } from './foo'; +>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } +>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] + +export { foo, arr }; +>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } +>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] + +const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo; +>bar : any +>baz : string +>bat : string +>bam : any +>bork : any +>bar : any +>ibar : string +>baz : any +>ibaz : string +>foo : { bar: string; bat: string; bam: { bork: { bar: string; baz: string; }; }; } + +export { baz, ibaz }; +>baz : string +>ibaz : string + +const [ , one, , [, bee, , [, {sec} ]]] = arr; +> : undefined +>one : 1 +> : undefined +> : undefined +>bee : "b" +> : undefined +> : undefined +>sec : "sec" +>arr : [0, 1, 2, ["a", "b", "c", [{ def: "def"; }, { sec: "sec"; }]]] + +export { one, bee, sec }; +>one : 1 +>bee : "b" +>sec : "sec" + +const getFoo = () => ({ +>getFoo : () => { foo: string; } +>() => ({ foo: 'foo'}) : () => { foo: string; } +>({ foo: 'foo'}) : { foo: string; } +>{ foo: 'foo'} : { foo: string; } + + foo: 'foo' +>foo : string +>'foo' : "foo" + +}); + +const { foo: foo2 } = getFoo(); +>foo : any +>foo2 : string +>getFoo() : { foo: string; } +>getFoo : () => { foo: string; } + +export { foo2 }; +>foo2 : string + diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js new file mode 100644 index 00000000000..567cb71cafb --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.js @@ -0,0 +1,23 @@ +//// [mutuallyRecursiveInterfaceDeclaration.ts] +interface A { + b: B +} + +interface B { + a: A +} +export {A, B} + +//// [mutuallyRecursiveInterfaceDeclaration.js] +"use strict"; +exports.__esModule = true; + + +//// [mutuallyRecursiveInterfaceDeclaration.d.ts] +interface A { + b: B; +} +interface B { + a: A; +} +export { A, B }; diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols new file mode 100644 index 00000000000..b0ac456859c --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts === +interface A { +>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 0)) + + b: B +>b : Symbol(A.b, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 13)) +>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 2, 1)) +} + +interface B { +>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 2, 1)) + + a: A +>a : Symbol(B.a, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 4, 13)) +>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 0, 0)) +} +export {A, B} +>A : Symbol(A, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 7, 8)) +>B : Symbol(B, Decl(mutuallyRecursiveInterfaceDeclaration.ts, 7, 10)) + diff --git a/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types new file mode 100644 index 00000000000..807687160b2 --- /dev/null +++ b/tests/baselines/reference/mutuallyRecursiveInterfaceDeclaration.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts === +interface A { +>A : A + + b: B +>b : B +>B : B +} + +interface B { +>B : B + + a: A +>a : A +>A : A +} +export {A, B} +>A : any +>B : any + diff --git a/tests/cases/compiler/destructuredDeclarationEmit.ts b/tests/cases/compiler/destructuredDeclarationEmit.ts new file mode 100644 index 00000000000..99435aff5b1 --- /dev/null +++ b/tests/cases/compiler/destructuredDeclarationEmit.ts @@ -0,0 +1,21 @@ +// @declaration: true +// @filename: foo.ts +const foo = { bar: 'hello', bat: 'world', bam: { bork: { bar: 'a', baz: 'b' } } }; +const arr: [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]] = [0, 1, 2, ['a', 'b', 'c', [{def: 'def'}, {sec: 'sec'}]]]; +export { foo, arr }; +// @filename: index.ts +import { foo, arr } from './foo'; +export { foo, arr }; + +const { bar: baz, bat, bam: { bork: { bar: ibar, baz: ibaz } } } = foo; +export { baz, ibaz }; + +const [ , one, , [, bee, , [, {sec} ]]] = arr; +export { one, bee, sec }; + +const getFoo = () => ({ + foo: 'foo' +}); + +const { foo: foo2 } = getFoo(); +export { foo2 }; diff --git a/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts b/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts new file mode 100644 index 00000000000..e9609605c69 --- /dev/null +++ b/tests/cases/compiler/mutuallyRecursiveInterfaceDeclaration.ts @@ -0,0 +1,9 @@ +// @declaration: true +interface A { + b: B +} + +interface B { + a: A +} +export {A, B} \ No newline at end of file From 3fd6f3aa99012b3ed40ffb3bb5ba3cd80099c78f Mon Sep 17 00:00:00 2001 From: csigs Date: Tue, 21 Nov 2017 23:10:31 +0000 Subject: [PATCH 09/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 179 ++++++++++++++---- .../diagnosticMessages.generated.json.lcl | 22 ++- 2 files changed, 159 insertions(+), 42 deletions(-) diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index 20ef6bead25..e0cd6400e2e 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -150,48 +150,33 @@ - + - - - - + - + - - - - + - + - - - - + - + - - - - + - + - - - - + @@ -528,6 +513,18 @@ + + + + + + + + + + + + @@ -774,6 +771,12 @@ + + + + + + @@ -2586,6 +2589,12 @@ + + + + + + @@ -2796,6 +2805,12 @@ + + + + + + @@ -2934,12 +2949,9 @@ - + - - - - + @@ -2970,12 +2982,9 @@ - + - - - - + @@ -4131,6 +4140,15 @@ + + + + + + + + + @@ -4500,6 +4518,18 @@ + + + + + + + + + + + + @@ -5424,6 +5454,12 @@ + + + + + + @@ -5544,6 +5580,12 @@ + + + + + + @@ -5643,6 +5685,24 @@ + + + + + + + + + + + + + + + + + + @@ -5670,6 +5730,24 @@ + + + + + + + + + + + + + + + + + + @@ -6456,6 +6534,12 @@ + + + + + + @@ -6678,12 +6762,9 @@ - + - - - - + @@ -8733,6 +8814,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index e1edb303ec2..009275302b1 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -2796,6 +2796,12 @@ + + + + + + @@ -5439,6 +5445,12 @@ + + + + + + @@ -5473,7 +5485,7 @@ - + @@ -5559,6 +5571,12 @@ + + + + + + @@ -8017,7 +8035,7 @@ - + From 39e6a0005469240becd98fe189aeca4f2846df96 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 21 Nov 2017 15:58:11 -0800 Subject: [PATCH 10/39] Unswap arguments --- src/server/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server.ts b/src/server/server.ts index fb0b3b781af..5330b5721c2 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -573,7 +573,7 @@ namespace ts.server { } private writeToEventSocket(body: any, eventName: string): void { - this.eventSocket.write(formatMessage(toEvent(body, eventName), this.logger, this.byteLength, this.host.newLine), "utf8"); + this.eventSocket.write(formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8"); } exit() { From 35545d4a0a9e0e11348bf76d715584c51aef9210 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 21 Nov 2017 15:05:21 -0800 Subject: [PATCH 11/39] Update project on PackageInstalledResponse As with `SetTypings`, new typings have been installed so the project should be updated and the client should be notified (via event). Changed PackageInstalledResponse from "event" to "action" for the sake of explicitness. Fixes #20084. --- src/server/editorServices.ts | 2 +- src/server/project.ts | 2 +- src/server/server.ts | 9 +++++++-- src/server/shared.ts | 2 +- src/server/types.ts | 11 +++++------ src/server/typingsCache.ts | 7 ++++--- src/server/typingsInstaller/nodeTypingsInstaller.ts | 6 +++--- 7 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index f0bb81f3256..a5b09c6a63f 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -540,7 +540,7 @@ namespace ts.server { } } - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings): void { + updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse): void { const project = this.findProject(response.projectName); if (!project) { return; diff --git a/src/server/project.ts b/src/server/project.ts index 8988e8b1bec..ce750c78e23 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -249,7 +249,7 @@ namespace ts.server { return this.typingsCache.isKnownTypesPackageName(name); } installPackage(options: InstallPackageOptions): Promise { - return this.typingsCache.installPackage({ ...options, projectRootPath: this.toPath(this.currentDirectory) }); + return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) }); } private get typingsCache(): TypingsCache { return this.projectService.typingsCache; diff --git a/src/server/server.ts b/src/server/server.ts index 5330b5721c2..fac7651a7e3 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -290,7 +290,7 @@ namespace ts.server { return false; } - installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise { + installPackage(options: InstallPackageOptionsWithProject): Promise { const rq: InstallPackageRequest = { kind: "installPackage", ...options }; this.send(rq); Debug.assert(this.packageInstalledPromise === undefined); @@ -392,7 +392,7 @@ namespace ts.server { case EventTypesRegistry: this.typesRegistryCache = ts.createMapFromTemplate(response.typesRegistry); break; - case EventPackageInstalled: { + case ActionPackageInstalled: { const { success, message } = response; if (success) { this.packageInstalledPromise.resolve({ successMessage: message }); @@ -401,6 +401,11 @@ namespace ts.server { this.packageInstalledPromise.reject(message); } this.packageInstalledPromise = undefined; + + this.projectService.updateTypingsForProject(response); + + // The behavior is the same as for setTypings, so send the same event. + this.event(response, "setTypings"); break; } case EventInitializationFailed: diff --git a/src/server/shared.ts b/src/server/shared.ts index 99a38eba389..e8b64ce06ec 100644 --- a/src/server/shared.ts +++ b/src/server/shared.ts @@ -4,8 +4,8 @@ namespace ts.server { // tslint:disable variable-name export const ActionSet: ActionSet = "action::set"; export const ActionInvalidate: ActionInvalidate = "action::invalidate"; + export const ActionPackageInstalled: ActionPackageInstalled = "action::packageInstalled"; export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry"; - export const EventPackageInstalled: EventPackageInstalled = "event::packageInstalled"; export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes"; export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes"; export const EventInitializationFailed: EventInitializationFailed = "event::initializationFailed"; diff --git a/src/server/types.ts b/src/server/types.ts index af5e121278e..32132ed278b 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -53,7 +53,7 @@ declare namespace ts.server { readonly kind: "typesRegistry"; } - export interface InstallPackageRequest { + export interface InstallPackageRequest extends TypingInstallerRequestWithProjectName { readonly kind: "installPackage"; readonly fileName: Path; readonly packageName: string; @@ -62,14 +62,14 @@ declare namespace ts.server { export type ActionSet = "action::set"; export type ActionInvalidate = "action::invalidate"; + export type ActionPackageInstalled = "action::packageInstalled"; export type EventTypesRegistry = "event::typesRegistry"; - export type EventPackageInstalled = "event::packageInstalled"; export type EventBeginInstallTypes = "event::beginInstallTypes"; export type EventEndInstallTypes = "event::endInstallTypes"; export type EventInitializationFailed = "event::initializationFailed"; export interface TypingInstallerResponse { - readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | EventPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed; + readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed; } /* @internal */ export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse; @@ -80,9 +80,8 @@ declare namespace ts.server { readonly typesRegistry: MapLike; } - /* @internal */ - export interface PackageInstalledResponse extends TypingInstallerResponse { - readonly kind: EventPackageInstalled; + export interface PackageInstalledResponse extends ProjectResponse { + readonly kind: ActionPackageInstalled; readonly success: boolean; readonly message: string; } diff --git a/src/server/typingsCache.ts b/src/server/typingsCache.ts index cde303bfd39..a1d8f65f6e0 100644 --- a/src/server/typingsCache.ts +++ b/src/server/typingsCache.ts @@ -1,14 +1,15 @@ /// namespace ts.server { - export interface InstallPackageOptionsWithProjectRootPath extends InstallPackageOptions { + export interface InstallPackageOptionsWithProject extends InstallPackageOptions { + projectName: string; projectRootPath: Path; } // tslint:disable-next-line interface-name (for backwards-compatibility) export interface ITypingsInstaller { isKnownTypesPackageName(name: string): boolean; - installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise; + installPackage(options: InstallPackageOptionsWithProject): Promise; enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray): void; attach(projectService: ProjectService): void; onProjectClosed(p: Project): void; @@ -91,7 +92,7 @@ namespace ts.server { return this.installer.isKnownTypesPackageName(name); } - installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise { + installPackage(options: InstallPackageOptionsWithProject): Promise { return this.installer.installPackage(options); } diff --git a/src/server/typingsInstaller/nodeTypingsInstaller.ts b/src/server/typingsInstaller/nodeTypingsInstaller.ts index da16d5dde82..36f5adab400 100644 --- a/src/server/typingsInstaller/nodeTypingsInstaller.ts +++ b/src/server/typingsInstaller/nodeTypingsInstaller.ts @@ -150,17 +150,17 @@ namespace ts.server.typingsInstaller { break; } case "installPackage": { - const { fileName, packageName, projectRootPath } = req; + const { fileName, packageName, projectName, projectRootPath } = req; const cwd = getDirectoryOfPackageJson(fileName, this.installTypingHost) || projectRootPath; if (cwd) { this.installWorker(-1, [packageName], cwd, success => { const message = success ? `Package ${packageName} installed.` : `There was an error installing ${packageName}.`; - const response: PackageInstalledResponse = { kind: EventPackageInstalled, success, message }; + const response: PackageInstalledResponse = { kind: ActionPackageInstalled, projectName, success, message }; this.sendResponse(response); }); } else { - const response: PackageInstalledResponse = { kind: EventPackageInstalled, success: false, message: "Could not determine a project root path." }; + const response: PackageInstalledResponse = { kind: ActionPackageInstalled, projectName, success: false, message: "Could not determine a project root path." }; this.sendResponse(response); } break; From 82aa518ec01f3a7ec60de5e1b45ecab244eda7c0 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 21 Nov 2017 15:21:51 -0800 Subject: [PATCH 12/39] Update public API baseline --- .../reference/api/tsserverlibrary.d.ts | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 354f239eeb9..32d35138c7f 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4716,7 +4716,7 @@ declare namespace ts.server { interface TypesRegistryRequest { readonly kind: "typesRegistry"; } - interface InstallPackageRequest { + interface InstallPackageRequest extends TypingInstallerRequestWithProjectName { readonly kind: "installPackage"; readonly fileName: Path; readonly packageName: string; @@ -4724,13 +4724,18 @@ declare namespace ts.server { } type ActionSet = "action::set"; type ActionInvalidate = "action::invalidate"; + type ActionPackageInstalled = "action::packageInstalled"; type EventTypesRegistry = "event::typesRegistry"; - type EventPackageInstalled = "event::packageInstalled"; type EventBeginInstallTypes = "event::beginInstallTypes"; type EventEndInstallTypes = "event::endInstallTypes"; type EventInitializationFailed = "event::initializationFailed"; interface TypingInstallerResponse { - readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | EventPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed; + readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed; + } + interface PackageInstalledResponse extends ProjectResponse { + readonly kind: ActionPackageInstalled; + readonly success: boolean; + readonly message: string; } interface InitializationFailedResponse extends TypingInstallerResponse { readonly kind: EventInitializationFailed; @@ -4766,8 +4771,8 @@ declare namespace ts.server { declare namespace ts.server { const ActionSet: ActionSet; const ActionInvalidate: ActionInvalidate; + const ActionPackageInstalled: ActionPackageInstalled; const EventTypesRegistry: EventTypesRegistry; - const EventPackageInstalled: EventPackageInstalled; const EventBeginInstallTypes: EventBeginInstallTypes; const EventEndInstallTypes: EventEndInstallTypes; const EventInitializationFailed: EventInitializationFailed; @@ -7125,12 +7130,13 @@ declare namespace ts.server { } } declare namespace ts.server { - interface InstallPackageOptionsWithProjectRootPath extends InstallPackageOptions { + interface InstallPackageOptionsWithProject extends InstallPackageOptions { + projectName: string; projectRootPath: Path; } interface ITypingsInstaller { isKnownTypesPackageName(name: string): boolean; - installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise; + installPackage(options: InstallPackageOptionsWithProject): Promise; enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray): void; attach(projectService: ProjectService): void; onProjectClosed(p: Project): void; @@ -7142,7 +7148,7 @@ declare namespace ts.server { private readonly perProjectCache; constructor(installer: ITypingsInstaller); isKnownTypesPackageName(name: string): boolean; - installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise; + installPackage(options: InstallPackageOptionsWithProject): Promise; getTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray, forceRefresh: boolean): SortedReadonlyArray; updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray, newTypings: string[]): void; deleteTypingsForProject(projectName: string): void; @@ -7566,7 +7572,7 @@ declare namespace ts.server { private createWatcherLog(watchType, project); toPath(fileName: string): Path; private loadTypesMap(); - updateTypingsForProject(response: SetTypings | InvalidateCachedTypings): void; + updateTypingsForProject(response: SetTypings | InvalidateCachedTypings | PackageInstalledResponse): void; private delayInferredProjectsRefresh(); private delayUpdateProjectGraph(project); private sendProjectsUpdatedInBackgroundEvent(); From f483495408b403b34dddbe43684727cb959784fa Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 21 Nov 2017 16:24:05 -0800 Subject: [PATCH 13/39] Use {} instead of any to improve type checking --- src/server/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server.ts b/src/server/server.ts index 5330b5721c2..06d9d50a8dc 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -572,7 +572,7 @@ namespace ts.server { } } - private writeToEventSocket(body: any, eventName: string): void { + private writeToEventSocket(body: {}, eventName: string): void { this.eventSocket.write(formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8"); } From 5ed31cff8c5ebd9059ccc14506fa510a09e41ace Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 21 Nov 2017 16:38:58 -0800 Subject: [PATCH 14/39] Use stricter types for event bodies --- src/harness/unittests/tsserverProjectSystem.ts | 2 +- src/server/server.ts | 6 +++--- src/server/session.ts | 6 +++--- tests/baselines/reference/api/tsserverlibrary.d.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index caeb3a81963..ff2db0f9ee6 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -232,7 +232,7 @@ namespace ts.projectSystem { return this.executeCommand(request); } - public event(body: T, eventName: string) { + public event(body: T, eventName: string) { this.events.push(server.toEvent(eventName, body)); super.event(body, eventName); } diff --git a/src/server/server.ts b/src/server/server.ts index 06d9d50a8dc..3bad4d0e852 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -502,7 +502,7 @@ namespace ts.server { constructor(options: IoSessionOptions) { const { host, eventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents } = options; - const event: Event | undefined = (body: {}, eventName: string) => { + const event: Event | undefined = (body: object, eventName: string) => { if (this.constructed) { this.event(body, eventName); } @@ -551,7 +551,7 @@ namespace ts.server { this.constructed = true; } - event(body: T, eventName: string): void { + event(body: T, eventName: string): void { Debug.assert(this.constructed, "Should only call `IOSession.prototype.event` on an initialized IOSession"); if (this.canUseEvents && this.eventPort) { @@ -572,7 +572,7 @@ namespace ts.server { } } - private writeToEventSocket(body: {}, eventName: string): void { + private writeToEventSocket(body: object, eventName: string): void { this.eventSocket.write(formatMessage(toEvent(eventName, body), this.logger, this.byteLength, this.host.newLine), "utf8"); } diff --git a/src/server/session.ts b/src/server/session.ts index 9e6378ebebf..309a6aef0ca 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -239,14 +239,14 @@ namespace ts.server { } } - export type Event = (body: T, eventName: string) => void; + export type Event = (body: T, eventName: string) => void; export interface EventSender { event: Event; } /** @internal */ - export function toEvent(eventName: string, body: {}): protocol.Event { + export function toEvent(eventName: string, body: object): protocol.Event { return { seq: 0, type: "event", @@ -409,7 +409,7 @@ namespace ts.server { this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine)); } - public event(body: T, eventName: string): void { + public event(body: T, eventName: string): void { this.send(toEvent(eventName, body)); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 354f239eeb9..4831a20f134 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6930,7 +6930,7 @@ declare namespace ts.server { type CommandNames = protocol.CommandTypes; const CommandNames: any; function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string; - type Event = (body: T, eventName: string) => void; + type Event = (body: T, eventName: string) => void; interface EventSender { event: Event; } @@ -6973,7 +6973,7 @@ declare namespace ts.server { private projectsUpdatedInBackgroundEvent(openFiles); logError(err: Error, cmd: string): void; send(msg: protocol.Message): void; - event(body: T, eventName: string): void; + event(body: T, eventName: string): void; /** @deprecated */ output(info: any, cmdName: string, reqSeq?: number, errorMsg?: string): void; private doOutput(info, cmdName, reqSeq, success, message?); From 013ce8e36d8fbf6fd271ab2e6e720338091f07f2 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 21 Nov 2017 21:36:08 -0500 Subject: [PATCH 15/39] Catch illegal jsdoc tags on constructors (#20045) --- src/compiler/checker.ts | 11 +++++++---- .../reference/jsdocIllegalTags.errors.txt | 18 ++++++++++++++++++ .../reference/jsdocIllegalTags.symbols | 14 ++++++++++++++ .../baselines/reference/jsdocIllegalTags.types | 14 ++++++++++++++ tests/cases/compiler/jsdocIllegalTags.ts | 13 +++++++++++++ 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/jsdocIllegalTags.errors.txt create mode 100644 tests/baselines/reference/jsdocIllegalTags.symbols create mode 100644 tests/baselines/reference/jsdocIllegalTags.types create mode 100644 tests/cases/compiler/jsdocIllegalTags.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cc04bd02d9b..2c471b9818e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26248,14 +26248,17 @@ namespace ts { } function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) { - if (node.typeParameters) { - return grammarErrorAtPos(node, node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); + const typeParameters = getEffectiveTypeParameterDeclarations(node); + if (typeParameters) { + const { pos, end } = isNodeArray(typeParameters) ? typeParameters : first(typeParameters); + return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration); } } function checkGrammarConstructorTypeAnnotation(node: ConstructorDeclaration) { - if (node.type) { - return grammarErrorOnNode(node.type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); + const type = getEffectiveReturnTypeNode(node); + if (type) { + return grammarErrorOnNode(type, Diagnostics.Type_annotation_cannot_appear_on_a_constructor_declaration); } } diff --git a/tests/baselines/reference/jsdocIllegalTags.errors.txt b/tests/baselines/reference/jsdocIllegalTags.errors.txt new file mode 100644 index 00000000000..485d01b12d9 --- /dev/null +++ b/tests/baselines/reference/jsdocIllegalTags.errors.txt @@ -0,0 +1,18 @@ +/a.js(2,19): error TS1092: Type parameters cannot appear on a constructor declaration. +/a.js(6,18): error TS1093: Type annotation cannot appear on a constructor declaration. + + +==== /a.js (2 errors) ==== + class C { + /** @template T */ + ~ +!!! error TS1092: Type parameters cannot appear on a constructor declaration. + constructor() { } + } + class D { + /** @return {number} */ + ~~~~~~ +!!! error TS1093: Type annotation cannot appear on a constructor declaration. + constructor() {} + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocIllegalTags.symbols b/tests/baselines/reference/jsdocIllegalTags.symbols new file mode 100644 index 00000000000..615bdc2facd --- /dev/null +++ b/tests/baselines/reference/jsdocIllegalTags.symbols @@ -0,0 +1,14 @@ +=== /a.js === +class C { +>C : Symbol(C, Decl(a.js, 0, 0)) + + /** @template T */ + constructor() { } +} +class D { +>D : Symbol(D, Decl(a.js, 3, 1)) + + /** @return {number} */ + constructor() {} +} + diff --git a/tests/baselines/reference/jsdocIllegalTags.types b/tests/baselines/reference/jsdocIllegalTags.types new file mode 100644 index 00000000000..c40302f11d3 --- /dev/null +++ b/tests/baselines/reference/jsdocIllegalTags.types @@ -0,0 +1,14 @@ +=== /a.js === +class C { +>C : C + + /** @template T */ + constructor() { } +} +class D { +>D : D + + /** @return {number} */ + constructor() {} +} + diff --git a/tests/cases/compiler/jsdocIllegalTags.ts b/tests/cases/compiler/jsdocIllegalTags.ts new file mode 100644 index 00000000000..a59a70dda87 --- /dev/null +++ b/tests/cases/compiler/jsdocIllegalTags.ts @@ -0,0 +1,13 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @Filename: /a.js + +class C { + /** @template T */ + constructor() { } +} +class D { + /** @return {number} */ + constructor() {} +} From b4b9edc04ca081d0bca04cd7f851a83ea3f6888c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 21 Nov 2017 18:39:01 -0800 Subject: [PATCH 16/39] Make sure 'async' isn't treated as a parameter modifier --- src/compiler/parser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b13aaac792f..cb28be4677a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3281,7 +3281,7 @@ namespace ts { // Check for "(xxx yyy", where xxx is a modifier and yyy is an identifier. This // isn't actually allowed, but we want to treat it as a lambda so we can provide // a good error message. - if (isModifierKind(second) && lookAhead(nextTokenIsIdentifier)) { + if (isModifierKind(second) && second !== SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsIdentifier)) { return Tristate.True; } @@ -3298,7 +3298,7 @@ namespace ts { return Tristate.True; case SyntaxKind.QuestionToken: nextToken(); - // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lamnda. + // If we have "(a?:" or "(a?," or "(a?=" or "(a?)" then it is definitely a lambda. if (token() === SyntaxKind.ColonToken || token() === SyntaxKind.CommaToken || token() === SyntaxKind.EqualsToken || token() === SyntaxKind.CloseParenToken) { return Tristate.True; } From 332a61ee8b40a6afd87525e47bee03ae23247833 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 21 Nov 2017 20:22:26 -0800 Subject: [PATCH 17/39] Removes redundant comments (#20214) --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2c471b9818e..bc9906f2054 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23334,7 +23334,7 @@ namespace ts { function checkExportSpecifier(node: ExportSpecifier) { checkAliasSymbol(node); if (compilerOptions.declaration) { - collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); // Collect linked aliases to set visibility links + collectLinkedAliases(node.propertyName || node.name, /*setVisibility*/ true); } if (!(node.parent.parent).moduleSpecifier) { const exportedName = node.propertyName || node.name; @@ -23375,7 +23375,7 @@ namespace ts { markExportAsReferenced(node); if (compilerOptions.declaration) { - collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); // Sets visibility flags on refernced nodes + collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); } } else { From 208eea156b3581e42df814d7bc761e2551f5c366 Mon Sep 17 00:00:00 2001 From: csigs Date: Wed, 22 Nov 2017 11:10:25 +0000 Subject: [PATCH 18/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 2524f29e99e..6f757cd12d4 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -1425,7 +1425,7 @@ - + @@ -1434,7 +1434,7 @@ - + @@ -2004,7 +2004,7 @@ - + @@ -2052,7 +2052,7 @@ - + @@ -2637,7 +2637,7 @@ - + @@ -2780,6 +2780,12 @@ + + + + + + @@ -3135,7 +3141,7 @@ - + @@ -4896,7 +4902,7 @@ - + @@ -5417,6 +5423,12 @@ + + + + + + @@ -5537,6 +5549,12 @@ + + + + + + From 8c52e4ea677fa198cb0ba9b0604e24135c052adc Mon Sep 17 00:00:00 2001 From: csigs Date: Wed, 22 Nov 2017 17:10:08 +0000 Subject: [PATCH 19/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 03965fb2b07..31ccdc9e17a 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -765,6 +792,9 @@ + + + @@ -2583,6 +2613,9 @@ + + + @@ -2796,6 +2829,15 @@ + + + + + + + + + @@ -2937,6 +2979,9 @@ + + + @@ -2970,6 +3015,9 @@ + + + @@ -4506,12 +4554,18 @@ + + + + + + @@ -5439,6 +5493,15 @@ + + + + + + + + + @@ -5559,6 +5622,15 @@ + + + + + + + + + @@ -5661,18 +5733,27 @@ + + + + + + + + + @@ -5706,18 +5787,27 @@ + + + + + + + + + @@ -6510,6 +6600,9 @@ + + + @@ -6738,6 +6831,9 @@ + + + @@ -8790,18 +8886,27 @@ + + + + + + + + + From 3a00b76cff12c8eaf5061a412588d4495dba57b4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 22 Nov 2017 10:50:49 -0800 Subject: [PATCH 20/39] Add regression test --- tests/cases/compiler/parenthesizedAsyncArrowFunction.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/cases/compiler/parenthesizedAsyncArrowFunction.ts diff --git a/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts b/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts new file mode 100644 index 00000000000..00c1aca6533 --- /dev/null +++ b/tests/cases/compiler/parenthesizedAsyncArrowFunction.ts @@ -0,0 +1,3 @@ +// Repro from #20096 + +let foo = (async bar => bar); From c8c46f6d45f82a30f64d55e055585201deb1764c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 22 Nov 2017 10:50:58 -0800 Subject: [PATCH 21/39] Accept new baselines --- .../parenthesizedAsyncArrowFunction.js | 47 +++++++++++++++++++ .../parenthesizedAsyncArrowFunction.symbols | 8 ++++ .../parenthesizedAsyncArrowFunction.types | 10 ++++ 3 files changed, 65 insertions(+) create mode 100644 tests/baselines/reference/parenthesizedAsyncArrowFunction.js create mode 100644 tests/baselines/reference/parenthesizedAsyncArrowFunction.symbols create mode 100644 tests/baselines/reference/parenthesizedAsyncArrowFunction.types diff --git a/tests/baselines/reference/parenthesizedAsyncArrowFunction.js b/tests/baselines/reference/parenthesizedAsyncArrowFunction.js new file mode 100644 index 00000000000..1f2cbc722e0 --- /dev/null +++ b/tests/baselines/reference/parenthesizedAsyncArrowFunction.js @@ -0,0 +1,47 @@ +//// [parenthesizedAsyncArrowFunction.ts] +// Repro from #20096 + +let foo = (async bar => bar); + + +//// [parenthesizedAsyncArrowFunction.js] +// Repro from #20096 +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var _this = this; +var foo = (function (bar) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { + return [2 /*return*/, bar]; +}); }); }); diff --git a/tests/baselines/reference/parenthesizedAsyncArrowFunction.symbols b/tests/baselines/reference/parenthesizedAsyncArrowFunction.symbols new file mode 100644 index 00000000000..a6428c3e998 --- /dev/null +++ b/tests/baselines/reference/parenthesizedAsyncArrowFunction.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/parenthesizedAsyncArrowFunction.ts === +// Repro from #20096 + +let foo = (async bar => bar); +>foo : Symbol(foo, Decl(parenthesizedAsyncArrowFunction.ts, 2, 3)) +>bar : Symbol(bar, Decl(parenthesizedAsyncArrowFunction.ts, 2, 16)) +>bar : Symbol(bar, Decl(parenthesizedAsyncArrowFunction.ts, 2, 16)) + diff --git a/tests/baselines/reference/parenthesizedAsyncArrowFunction.types b/tests/baselines/reference/parenthesizedAsyncArrowFunction.types new file mode 100644 index 00000000000..cb1461764cb --- /dev/null +++ b/tests/baselines/reference/parenthesizedAsyncArrowFunction.types @@ -0,0 +1,10 @@ +=== tests/cases/compiler/parenthesizedAsyncArrowFunction.ts === +// Repro from #20096 + +let foo = (async bar => bar); +>foo : (bar: any) => Promise +>(async bar => bar) : (bar: any) => Promise +>async bar => bar : (bar: any) => Promise +>bar : any +>bar : any + From 643e9fc1e410f8bd4a7cc2b23d96b9e946c957ea Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 22 Nov 2017 14:25:31 -0800 Subject: [PATCH 22/39] Offer global completions in all blocks --- src/services/completions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/completions.ts b/src/services/completions.ts index 6bbdfacac4c..bfa03ef4a9f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -942,6 +942,7 @@ namespace ts.Completions { scopeNode.kind === SyntaxKind.SourceFile || scopeNode.kind === SyntaxKind.TemplateExpression || scopeNode.kind === SyntaxKind.JsxExpression || + scopeNode.kind === SyntaxKind.Block || // Some blocks aren't statements, but all get global completions isStatement(scopeNode); } From dc3b4166b2d8e72ebca66c4f6c8576c97b5cbac1 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 22 Nov 2017 15:11:38 -0800 Subject: [PATCH 23/39] Update test baseline --- tests/cases/fourslash/completionListIsGlobalCompletion.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts index 49196bdabd4..121ab940d65 100644 --- a/tests/cases/fourslash/completionListIsGlobalCompletion.ts +++ b/tests/cases/fourslash/completionListIsGlobalCompletion.ts @@ -47,7 +47,7 @@ verify.completionListIsGlobal(true); goTo.marker("6"); verify.completionListIsGlobal(false); goTo.marker("7"); -verify.completionListIsGlobal(false); +verify.completionListIsGlobal(true); goTo.marker("8"); verify.completionListIsGlobal(false); goTo.marker("9"); From d62a8beea05fe159fdbca74f34520e17ff9f9506 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Nov 2017 15:42:04 -0800 Subject: [PATCH 24/39] Port generated lib files (#20213) --- src/lib/dom.generated.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index c5e5e713ad2..001c63b44a1 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -15029,6 +15029,8 @@ interface SVGElementTagNameMap { "view": SVGViewElement; } +interface ElementTagNameMap extends HTMLElementTagNameMap, SVGElementTagNameMap { } + declare var Audio: { new(src?: string): HTMLAudioElement; }; declare var Image: { new(width?: number, height?: number): HTMLImageElement; }; declare var Option: { new(text?: string, value?: string, defaultSelected?: boolean, selected?: boolean): HTMLOptionElement; }; From ac2de119081361015f7bc379e384b716f815765c Mon Sep 17 00:00:00 2001 From: csigs Date: Thu, 23 Nov 2017 05:10:07 +0000 Subject: [PATCH 25/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 87 +++++++ .../diagnosticMessages.generated.json.lcl | 225 ++++++++++++++++-- 2 files changed, 288 insertions(+), 24 deletions(-) diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index e0cd6400e2e..de3f3987097 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -153,30 +153,45 @@ + + + + + + + + + + + + + + + @@ -300,6 +315,12 @@ + + + + + + @@ -516,12 +537,18 @@ + + + + + + @@ -774,6 +801,9 @@ + + + @@ -2592,6 +2622,9 @@ + + + @@ -2808,6 +2841,9 @@ + + + @@ -2952,6 +2988,9 @@ + + + @@ -2985,6 +3024,9 @@ + + + @@ -4521,12 +4563,18 @@ + + + + + + @@ -5457,6 +5505,9 @@ + + + @@ -5583,6 +5634,9 @@ + + + @@ -5688,18 +5742,27 @@ + + + + + + + + + @@ -5733,18 +5796,27 @@ + + + + + + + + + @@ -6537,6 +6609,9 @@ + + + @@ -6765,6 +6840,9 @@ + + + @@ -8817,18 +8895,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index c8ff92b6a88..ad747f8665a 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -134,47 +134,47 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -299,6 +299,12 @@ + + + + + + @@ -512,6 +518,24 @@ + + + + + + + + + + + + + + + + + + @@ -755,6 +779,15 @@ + + + + + + + + + @@ -2561,6 +2594,15 @@ + + + + + + + + + @@ -2771,6 +2813,15 @@ + + + + + + + + + @@ -2909,11 +2960,11 @@ - + - + - + @@ -2945,11 +2996,11 @@ - + - + - + @@ -4481,6 +4532,24 @@ + + + + + + + + + + + + + + + + + + @@ -5402,6 +5471,15 @@ + + + + + + + + + @@ -5522,6 +5600,15 @@ + + + + + + + + + @@ -5621,6 +5708,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5648,6 +5762,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6428,6 +6569,15 @@ + + + + + + + + + @@ -6650,11 +6800,11 @@ - + - + - + @@ -8705,6 +8855,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 975914477733b2e1998bed6d23edf82a20aaa0a4 Mon Sep 17 00:00:00 2001 From: csigs Date: Thu, 23 Nov 2017 17:10:10 +0000 Subject: [PATCH 26/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 105 ++++++++ .../diagnosticMessages.generated.json.lcl | 225 ++++++++++++++++-- .../diagnosticMessages.generated.json.lcl | 105 ++++++++ .../diagnosticMessages.generated.json.lcl | 105 ++++++++ 4 files changed, 516 insertions(+), 24 deletions(-) diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index 425b451c38c..fb159e922b7 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -765,6 +792,9 @@ + + + @@ -2583,6 +2613,9 @@ + + + @@ -2796,6 +2829,15 @@ + + + + + + + + + @@ -2937,6 +2979,9 @@ + + + @@ -2970,6 +3015,9 @@ + + + @@ -4506,12 +4554,18 @@ + + + + + + @@ -5439,6 +5493,15 @@ + + + + + + + + + @@ -5559,6 +5622,15 @@ + + + + + + + + + @@ -5661,18 +5733,27 @@ + + + + + + + + + @@ -5706,18 +5787,27 @@ + + + + + + + + + @@ -6510,6 +6600,9 @@ + + + @@ -6738,6 +6831,9 @@ + + + @@ -8790,18 +8886,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index 67025087ec8..b77e815dfd5 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -150,47 +150,47 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -315,6 +315,12 @@ + + + + + + @@ -528,6 +534,24 @@ + + + + + + + + + + + + + + + + + + @@ -774,6 +798,15 @@ + + + + + + + + + @@ -2586,6 +2619,15 @@ + + + + + + + + + @@ -2796,6 +2838,15 @@ + + + + + + + + + @@ -2934,11 +2985,11 @@ - + - + - + @@ -2970,11 +3021,11 @@ - + - + - + @@ -4509,6 +4560,24 @@ + + + + + + + + + + + + + + + + + + @@ -5433,6 +5502,15 @@ + + + + + + + + + @@ -5553,6 +5631,15 @@ + + + + + + + + + @@ -5652,6 +5739,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5679,6 +5793,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6465,6 +6606,15 @@ + + + + + + + + + @@ -6687,11 +6837,11 @@ - + - + - + @@ -8742,6 +8892,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 3a589da079d..36d9a4f8e94 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -765,6 +792,9 @@ + + + @@ -2583,6 +2613,9 @@ + + + @@ -2796,6 +2829,15 @@ + + + + + + + + + @@ -2937,6 +2979,9 @@ + + + @@ -2970,6 +3015,9 @@ + + + @@ -4506,12 +4554,18 @@ + + + + + + @@ -5439,6 +5493,15 @@ + + + + + + + + + @@ -5559,6 +5622,15 @@ + + + + + + + + + @@ -5661,18 +5733,27 @@ + + + + + + + + + @@ -5706,18 +5787,27 @@ + + + + + + + + + @@ -6510,6 +6600,9 @@ + + + @@ -6738,6 +6831,9 @@ + + + @@ -8790,18 +8886,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1034ed53292..da7275f5844 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -765,6 +792,9 @@ + + + @@ -2583,6 +2613,9 @@ + + + @@ -2796,6 +2829,15 @@ + + + + + + + + + @@ -2937,6 +2979,9 @@ + + + @@ -2970,6 +3015,9 @@ + + + @@ -4506,12 +4554,18 @@ + + + + + + @@ -5439,6 +5493,15 @@ + + + + + + + + + @@ -5559,6 +5622,15 @@ + + + + + + + + + @@ -5661,18 +5733,27 @@ + + + + + + + + + @@ -5706,18 +5787,27 @@ + + + + + + + + + @@ -6510,6 +6600,9 @@ + + + @@ -6738,6 +6831,9 @@ + + + @@ -8790,18 +8886,27 @@ + + + + + + + + + From 5465670b49da6517dd0c4d8c29e741b415603a26 Mon Sep 17 00:00:00 2001 From: csigs Date: Thu, 23 Nov 2017 23:10:09 +0000 Subject: [PATCH 27/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 87 +++++++++++++++ .../diagnosticMessages.generated.json.lcl | 87 +++++++++++++++ .../diagnosticMessages.generated.json.lcl | 105 ++++++++++++++++++ .../diagnosticMessages.generated.json.lcl | 105 ++++++++++++++++++ 4 files changed, 384 insertions(+) diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 009275302b1..98c3cbfc1f5 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -765,6 +792,9 @@ + + + @@ -2583,6 +2613,9 @@ + + + @@ -2799,6 +2832,9 @@ + + + @@ -2943,6 +2979,9 @@ + + + @@ -2976,6 +3015,9 @@ + + + @@ -4512,12 +4554,18 @@ + + + + + + @@ -5448,6 +5496,9 @@ + + + @@ -5574,6 +5625,9 @@ + + + @@ -5679,18 +5733,27 @@ + + + + + + + + + @@ -5724,18 +5787,27 @@ + + + + + + + + + @@ -6528,6 +6600,9 @@ + + + @@ -6756,6 +6831,9 @@ + + + @@ -8808,18 +8886,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 6f757cd12d4..b0d10a6fd79 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -137,30 +137,45 @@ + + + + + + + + + + + + + + + @@ -284,6 +299,12 @@ + + + + + + @@ -500,12 +521,18 @@ + + + + + + @@ -755,6 +782,9 @@ + + + @@ -2567,6 +2597,9 @@ + + + @@ -2783,6 +2816,9 @@ + + + @@ -2927,6 +2963,9 @@ + + + @@ -2960,6 +2999,9 @@ + + + @@ -4493,12 +4535,18 @@ + + + + + + @@ -5426,6 +5474,9 @@ + + + @@ -5552,6 +5603,9 @@ + + + @@ -5657,18 +5711,27 @@ + + + + + + + + + @@ -5702,18 +5765,27 @@ + + + + + + + + + @@ -6500,6 +6572,9 @@ + + + @@ -6728,6 +6803,9 @@ + + + @@ -8780,18 +8858,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index ff50a731206..543639d56e9 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -143,30 +143,45 @@ + + + + + + + + + + + + + + + @@ -290,6 +305,12 @@ + + + + + + @@ -506,12 +527,18 @@ + + + + + + @@ -764,6 +791,9 @@ + + + @@ -2582,6 +2612,9 @@ + + + @@ -2795,6 +2828,15 @@ + + + + + + + + + @@ -2936,6 +2978,9 @@ + + + @@ -2969,6 +3014,9 @@ + + + @@ -4505,12 +4553,18 @@ + + + + + + @@ -5438,6 +5492,15 @@ + + + + + + + + + @@ -5558,6 +5621,15 @@ + + + + + + + + + @@ -5660,18 +5732,27 @@ + + + + + + + + + @@ -5705,18 +5786,27 @@ + + + + + + + + + @@ -6509,6 +6599,9 @@ + + + @@ -6737,6 +6830,9 @@ + + + @@ -8789,18 +8885,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 44970d1fc65..5bf19ff41b3 100644 --- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -137,30 +137,45 @@ + + + + + + + + + + + + + + + @@ -284,6 +299,12 @@ + + + + + + @@ -500,12 +521,18 @@ + + + + + + @@ -758,6 +785,9 @@ + + + @@ -2576,6 +2606,9 @@ + + + @@ -2789,6 +2822,15 @@ + + + + + + + + + @@ -2930,6 +2972,9 @@ + + + @@ -2963,6 +3008,9 @@ + + + @@ -4499,12 +4547,18 @@ + + + + + + @@ -5432,6 +5486,15 @@ + + + + + + + + + @@ -5552,6 +5615,15 @@ + + + + + + + + + @@ -5654,18 +5726,27 @@ + + + + + + + + + @@ -5699,18 +5780,27 @@ + + + + + + + + + @@ -6503,6 +6593,9 @@ + + + @@ -6731,6 +6824,9 @@ + + + @@ -8783,18 +8879,27 @@ + + + + + + + + + From df81cf87ed32fa7a9979b5303b18fe7e514fb55a Mon Sep 17 00:00:00 2001 From: csigs Date: Fri, 24 Nov 2017 23:10:11 +0000 Subject: [PATCH 28/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 105 ++++++++ .../diagnosticMessages.generated.json.lcl | 225 ++++++++++++++++-- 2 files changed, 306 insertions(+), 24 deletions(-) diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl index dfba55014e0..958d9774e8e 100644 --- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -144,30 +144,45 @@ + + + + + + + + + + + + + + + @@ -291,6 +306,12 @@ + + + + + + @@ -507,12 +528,18 @@ + + + + + + @@ -762,6 +789,9 @@ + + + @@ -2574,6 +2604,9 @@ + + + @@ -2787,6 +2820,15 @@ + + + + + + + + + @@ -2928,6 +2970,9 @@ + + + @@ -2961,6 +3006,9 @@ + + + @@ -4494,12 +4542,18 @@ + + + + + + @@ -5424,6 +5478,15 @@ + + + + + + + + + @@ -5544,6 +5607,15 @@ + + + + + + + + + @@ -5646,18 +5718,27 @@ + + + + + + + + + @@ -5691,18 +5772,27 @@ + + + + + + + + + @@ -6489,6 +6579,9 @@ + + + @@ -6717,6 +6810,9 @@ + + + @@ -8769,18 +8865,27 @@ + + + + + + + + + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index d22a3ecd34c..b824720c3e3 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -150,47 +150,47 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -315,6 +315,12 @@ + + + + + + @@ -528,6 +534,24 @@ + + + + + + + + + + + + + + + + + + @@ -774,6 +798,15 @@ + + + + + + + + + @@ -2586,6 +2619,15 @@ + + + + + + + + + @@ -2796,6 +2838,15 @@ + + + + + + + + + @@ -2934,11 +2985,11 @@ - + - + - + @@ -2970,11 +3021,11 @@ - + - + - + @@ -4509,6 +4560,24 @@ + + + + + + + + + + + + + + + + + + @@ -5433,6 +5502,15 @@ + + + + + + + + + @@ -5553,6 +5631,15 @@ + + + + + + + + + @@ -5652,6 +5739,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5679,6 +5793,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6465,6 +6606,15 @@ + + + + + + + + + @@ -6687,11 +6837,11 @@ - + - + - + @@ -8742,6 +8892,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 6b3cfc70080fa8a1f86fe774ec0c6e50bf032c97 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 24 Nov 2017 22:02:48 -0800 Subject: [PATCH 29/39] Fix #19959 and #19958: Remove un-localizable messages (#20019) * Fix #19959 and #19958: Remove un-localizable messages * Update message * Update diagnostic messages --- src/compiler/diagnosticMessages.json | 10 +--------- src/services/codefixes/importFixes.ts | 8 +------- ...mpletionsImport_default_alreadyExistedWithRename.ts | 2 +- .../fourslash/completionsImport_default_anonymous.ts | 2 +- .../completionsImport_default_didNotExistBefore.ts | 2 +- .../fourslash/completionsImport_fromAmbientModule.ts | 2 +- .../completionsImport_multipleWithSameName.ts | 2 +- .../completionsImport_named_namespaceImportExists.ts | 2 +- tests/cases/fourslash/completionsImport_ofAlias.ts | 2 +- .../completionsImport_ofAlias_preferShortPath.ts | 2 +- tests/cases/fourslash/completionsImport_require.ts | 4 ++-- 11 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 09319589da7..cd65bf945f4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3766,7 +3766,7 @@ "category": "Error", "code": 90010 }, - "Import '{0}' from \"{1}\".": { + "Import '{0}' from module \"{1}\".": { "category": "Message", "code": 90013 }, @@ -3886,13 +3886,5 @@ "Install '{0}'": { "category": "Message", "code": 95014 - }, - "Import '{0}' = require(\"{1}\").": { - "category": "Message", - "code": 95015 - }, - "Import * as '{0}' from \"{1}\".": { - "category": "Message", - "code": 95016 } } diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index ec56a08656c..dae997fc2e7 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -276,17 +276,11 @@ namespace ts.codefix { } }); - const actionFormat = kind === ImportKind.Equals - ? Diagnostics.Import_0_require_1 - : kind === ImportKind.Namespace - ? Diagnostics.Import_Asterisk_as_0_from_1 - : Diagnostics.Import_0_from_1; - // if this file doesn't have any import statements, insert an import statement and then insert a new line // between the only import statement and user code. Otherwise just insert the statement because chances // are there are already a new line seperating code and import statements. return createCodeAction( - actionFormat, + Diagnostics.Import_0_from_module_1, [symbolName, moduleSpecifierWithoutQuotes], changes, "NewImport", diff --git a/tests/cases/fourslash/completionsImport_default_alreadyExistedWithRename.ts b/tests/cases/fourslash/completionsImport_default_alreadyExistedWithRename.ts index d8cb53167f5..c8908ab2ebd 100644 --- a/tests/cases/fourslash/completionsImport_default_alreadyExistedWithRename.ts +++ b/tests/cases/fourslash/completionsImport_default_alreadyExistedWithRename.ts @@ -16,7 +16,7 @@ verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): vo verify.applyCodeActionFromCompletion("", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import f_o_o from "./a"; import foo from "./a";\r diff --git a/tests/cases/fourslash/completionsImport_default_anonymous.ts b/tests/cases/fourslash/completionsImport_default_anonymous.ts index 4be0184d9fa..297567d1c19 100644 --- a/tests/cases/fourslash/completionsImport_default_anonymous.ts +++ b/tests/cases/fourslash/completionsImport_default_anonymous.ts @@ -21,7 +21,7 @@ verify.completionListContains({ name: "fooBar", source: "/src/foo-bar" }, "(prop verify.applyCodeActionFromCompletion("1", { name: "fooBar", source: "/src/foo-bar", - description: `Import 'fooBar' from "./foo-bar".`, + description: `Import 'fooBar' from module "./foo-bar".`, // TODO: GH#18445 newFileContent: `import fooBar from "./foo-bar";\r \r diff --git a/tests/cases/fourslash/completionsImport_default_didNotExistBefore.ts b/tests/cases/fourslash/completionsImport_default_didNotExistBefore.ts index a4f943f68ee..dcdffc10907 100644 --- a/tests/cases/fourslash/completionsImport_default_didNotExistBefore.ts +++ b/tests/cases/fourslash/completionsImport_default_didNotExistBefore.ts @@ -17,7 +17,7 @@ verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): vo verify.applyCodeActionFromCompletion("", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import foo from "./a";\r \r diff --git a/tests/cases/fourslash/completionsImport_fromAmbientModule.ts b/tests/cases/fourslash/completionsImport_fromAmbientModule.ts index 05e7601c690..3b202ee33d6 100644 --- a/tests/cases/fourslash/completionsImport_fromAmbientModule.ts +++ b/tests/cases/fourslash/completionsImport_fromAmbientModule.ts @@ -11,7 +11,7 @@ verify.applyCodeActionFromCompletion("", { name: "x", source: "m", - description: `Import 'x' from "m".`, + description: `Import 'x' from module "m".`, // TODO: GH#18445 newFileContent: `import { x } from "m";\r \r diff --git a/tests/cases/fourslash/completionsImport_multipleWithSameName.ts b/tests/cases/fourslash/completionsImport_multipleWithSameName.ts index 81a054e3d23..50f20d60bf2 100644 --- a/tests/cases/fourslash/completionsImport_multipleWithSameName.ts +++ b/tests/cases/fourslash/completionsImport_multipleWithSameName.ts @@ -22,7 +22,7 @@ verify.completionListContains({ name: "foo", source: "/b" }, "const foo: 1", "", verify.applyCodeActionFromCompletion("", { name: "foo", source: "/b", - description: `Import 'foo' from "./b".`, + description: `Import 'foo' from module "./b".`, // TODO: GH#18445 newFileContent: `import { foo } from "./b";\r \r diff --git a/tests/cases/fourslash/completionsImport_named_namespaceImportExists.ts b/tests/cases/fourslash/completionsImport_named_namespaceImportExists.ts index 17b909b48ed..4f547259ee8 100644 --- a/tests/cases/fourslash/completionsImport_named_namespaceImportExists.ts +++ b/tests/cases/fourslash/completionsImport_named_namespaceImportExists.ts @@ -16,7 +16,7 @@ verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): vo verify.applyCodeActionFromCompletion("", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import * as a from "./a"; import { foo } from "./a";\r diff --git a/tests/cases/fourslash/completionsImport_ofAlias.ts b/tests/cases/fourslash/completionsImport_ofAlias.ts index cb4f1255a3e..1eb730df84f 100644 --- a/tests/cases/fourslash/completionsImport_ofAlias.ts +++ b/tests/cases/fourslash/completionsImport_ofAlias.ts @@ -28,7 +28,7 @@ verify.not.completionListContains({ name: "foo", source: "/a_reexport_2" }, unde verify.applyCodeActionFromCompletion("", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import { foo } from "./a";\r \r diff --git a/tests/cases/fourslash/completionsImport_ofAlias_preferShortPath.ts b/tests/cases/fourslash/completionsImport_ofAlias_preferShortPath.ts index a1eba5981db..fae8a4abf52 100644 --- a/tests/cases/fourslash/completionsImport_ofAlias_preferShortPath.ts +++ b/tests/cases/fourslash/completionsImport_ofAlias_preferShortPath.ts @@ -23,7 +23,7 @@ verify.not.completionListContains({ name: "foo", source: "/foo/index" }, undefin verify.applyCodeActionFromCompletion("", { name: "foo", source: "/foo/lib/foo", - description: `Import 'foo' from "./foo".`, + description: `Import 'foo' from module "./foo".`, // TODO: GH#18445 newFileContent: `import { foo } from "./foo";\r \r diff --git a/tests/cases/fourslash/completionsImport_require.ts b/tests/cases/fourslash/completionsImport_require.ts index 8ec750d2c48..2913bac27b0 100644 --- a/tests/cases/fourslash/completionsImport_require.ts +++ b/tests/cases/fourslash/completionsImport_require.ts @@ -22,7 +22,7 @@ verify.completionListContains({ name: "foo", source: "/a" }, "const foo: 0", "", verify.applyCodeActionFromCompletion("b", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import { foo } from "./a";\r \r @@ -39,7 +39,7 @@ verify.completionListContains({ name: "foo", source: "/a" }, "const foo: 0", "", verify.applyCodeActionFromCompletion("c", { name: "foo", source: "/a", - description: `Import 'foo' from "./a".`, + description: `Import 'foo' from module "./a".`, // TODO: GH#18445 newFileContent: `import { foo } from "./a";\r \r From 0da30253d6267e45922991d6aa2c4d6c380115ac Mon Sep 17 00:00:00 2001 From: csigs Date: Sat, 25 Nov 2017 11:10:31 +0000 Subject: [PATCH 30/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index b0d10a6fd79..be3889c2dd4 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -111,7 +111,7 @@ - + @@ -201,7 +201,7 @@ - + @@ -408,7 +408,7 @@ - + @@ -702,7 +702,7 @@ - + @@ -1083,7 +1083,7 @@ - + @@ -1335,7 +1335,7 @@ - + @@ -1728,7 +1728,7 @@ - + @@ -1737,7 +1737,7 @@ - + @@ -1998,7 +1998,7 @@ - + @@ -2007,7 +2007,7 @@ - + @@ -2016,7 +2016,7 @@ - + @@ -2025,7 +2025,7 @@ - + @@ -2163,7 +2163,7 @@ - + @@ -2889,7 +2889,7 @@ - + @@ -2898,7 +2898,7 @@ - + @@ -2919,7 +2919,7 @@ - + @@ -3858,7 +3858,7 @@ - + @@ -3876,7 +3876,7 @@ - + @@ -3957,7 +3957,7 @@ - + @@ -4176,7 +4176,7 @@ - + @@ -4491,7 +4491,7 @@ - + @@ -4563,7 +4563,7 @@ - + @@ -4581,7 +4581,7 @@ - + @@ -4731,7 +4731,7 @@ - + @@ -4758,7 +4758,7 @@ - + @@ -4767,7 +4767,7 @@ - + @@ -4866,7 +4866,7 @@ - + @@ -6516,7 +6516,7 @@ - + @@ -6978,7 +6978,7 @@ - + @@ -7146,7 +7146,7 @@ - + @@ -7497,7 +7497,7 @@ - + @@ -7506,7 +7506,7 @@ - + @@ -7515,7 +7515,7 @@ - + @@ -8184,7 +8184,7 @@ - + @@ -8388,7 +8388,7 @@ - + @@ -8397,7 +8397,7 @@ - + @@ -8688,7 +8688,7 @@ - + @@ -8715,7 +8715,7 @@ - + @@ -8742,7 +8742,7 @@ - + @@ -8751,7 +8751,7 @@ - + From b36379c5970533c56c068f2aaf1197d9f5680f90 Mon Sep 17 00:00:00 2001 From: Cameron Taggart Date: Mon, 27 Nov 2017 15:10:55 -0300 Subject: [PATCH 31/39] replaced @parm typo with @param (#20277) --- lib/typescript.d.ts | 4 ++-- lib/typescriptServices.d.ts | 4 ++-- src/services/documentRegistry.ts | 4 ++-- tests/baselines/reference/api/tsserverlibrary.d.ts | 4 ++-- tests/baselines/reference/api/typescript.d.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/typescript.d.ts b/lib/typescript.d.ts index b6598e9f617..815cc7bf24a 100644 --- a/lib/typescript.d.ts +++ b/lib/typescript.d.ts @@ -4487,9 +4487,9 @@ declare namespace ts { * @param compilationSettings Some compilation settings like target affects the * shape of a the resulting SourceFile. This allows the DocumentRegistry to store * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found + * @param scriptSnapshot Text of the file. Only used if the file was not found * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found + * @param version Current version of the file. Only used if the file was not found * in the registry and a new one was created. */ acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile; diff --git a/lib/typescriptServices.d.ts b/lib/typescriptServices.d.ts index 4bce953f667..cbf7ad062d2 100644 --- a/lib/typescriptServices.d.ts +++ b/lib/typescriptServices.d.ts @@ -4487,9 +4487,9 @@ declare namespace ts { * @param compilationSettings Some compilation settings like target affects the * shape of a the resulting SourceFile. This allows the DocumentRegistry to store * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found + * @param scriptSnapshot Text of the file. Only used if the file was not found * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found + * @param version Current version of the file. Only used if the file was not found * in the registry and a new one was created. */ acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile; diff --git a/src/services/documentRegistry.ts b/src/services/documentRegistry.ts index 0c3d4d1cb48..81742018fb7 100644 --- a/src/services/documentRegistry.ts +++ b/src/services/documentRegistry.ts @@ -24,9 +24,9 @@ namespace ts { * @param compilationSettings Some compilation settings like target affects the * shape of a the resulting SourceFile. This allows the DocumentRegistry to store * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found + * @param scriptSnapshot Text of the file. Only used if the file was not found * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found + * @param version Current version of the file. Only used if the file was not found * in the registry and a new one was created. */ acquireDocument( diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 231d7bae3f2..0de484e36b5 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4586,9 +4586,9 @@ declare namespace ts { * @param compilationSettings Some compilation settings like target affects the * shape of a the resulting SourceFile. This allows the DocumentRegistry to store * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found + * @param scriptSnapshot Text of the file. Only used if the file was not found * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found + * @param version Current version of the file. Only used if the file was not found * in the registry and a new one was created. */ acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 6b2db71b140..810a16e6c6b 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4586,9 +4586,9 @@ declare namespace ts { * @param compilationSettings Some compilation settings like target affects the * shape of a the resulting SourceFile. This allows the DocumentRegistry to store * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found + * @param scriptSnapshot Text of the file. Only used if the file was not found * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found + * @param version Current version of the file. Only used if the file was not found * in the registry and a new one was created. */ acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile; From 1fe9fc00ab62c0118fbbd98974e3d9f65cfce260 Mon Sep 17 00:00:00 2001 From: csigs Date: Tue, 28 Nov 2017 05:10:03 +0000 Subject: [PATCH 32/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- 3 files changed, 18 insertions(+), 72 deletions(-) diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index b824720c3e3..e2a933198cf 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -318,6 +318,9 @@ + + + @@ -3774,32 +3777,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 36d9a4f8e94..e204b688ed7 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -309,6 +309,9 @@ + + + @@ -3765,32 +3768,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index ad747f8665a..38902fa6734 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -302,6 +302,9 @@ + + + @@ -3746,32 +3749,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + From 835fae264ff8ecee828d49b24b941cf76b9557f1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 27 Nov 2017 23:16:21 -0800 Subject: [PATCH 33/39] Allow possibly undefined destructuring in ambient parameter declarations (#20230) --- src/compiler/checker.ts | 6 +++- ...edParameterBeforeNonoptionalNotOptional.js | 11 ++++++ ...ameterBeforeNonoptionalNotOptional.symbols | 34 ++++++++++++++++++ ...arameterBeforeNonoptionalNotOptional.types | 35 +++++++++++++++++++ ...edParameterBeforeNonoptionalNotOptional.ts | 12 +++++++ 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.js create mode 100644 tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.symbols create mode 100644 tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.types create mode 100644 tests/cases/compiler/initializedParameterBeforeNonoptionalNotOptional.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bc9906f2054..d8cbbe5f758 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4229,7 +4229,7 @@ namespace ts { /** Return the inferred type for a binding element */ function getTypeForBindingElement(declaration: BindingElement): Type { const pattern = declaration.parent; - const parentType = getTypeForBindingElementParent(pattern.parent); + let parentType = getTypeForBindingElementParent(pattern.parent); // If parent has the unknown (error) type, then so does this binding element if (parentType === unknownType) { return unknownType; @@ -4271,6 +4271,10 @@ namespace ts { // or otherwise the type of the string index signature. const text = getTextOfPropertyName(name); + // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation + if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { + parentType = getNonNullableType(parentType); + } const declaredType = getTypeOfPropertyOfType(parentType, text); type = declaredType && getFlowTypeOfReference(declaration, declaredType) || isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || diff --git a/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.js b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.js new file mode 100644 index 00000000000..8a6a602d6d7 --- /dev/null +++ b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.js @@ -0,0 +1,11 @@ +//// [initializedParameterBeforeNonoptionalNotOptional.ts] +export declare function foo({a}?: { + a?: string; +}): void; +export declare function foo2({a}: { + a?: string | undefined; +} | undefined, b: string): void; + +//// [initializedParameterBeforeNonoptionalNotOptional.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.symbols b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.symbols new file mode 100644 index 00000000000..9e91e2bd3aa --- /dev/null +++ b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.symbols @@ -0,0 +1,34 @@ +=== tests/cases/compiler/index.d.ts === +export declare function foo({a}?: { +>foo : Symbol(foo, Decl(index.d.ts, 0, 0)) +>a : Symbol(a, Decl(index.d.ts, 0, 29)) + + a?: string; +>a : Symbol(a, Decl(index.d.ts, 0, 35)) + +}): void; +export declare function foo2({a}: { +>foo2 : Symbol(foo2, Decl(index.d.ts, 2, 9)) +>a : Symbol(a, Decl(index.d.ts, 3, 30)) + + a?: string | undefined; +>a : Symbol(a, Decl(index.d.ts, 3, 35)) + +} | undefined, b: string): void; +>b : Symbol(b, Decl(index.d.ts, 5, 14)) + +export declare function foo3({a, b: {c}}: { +>foo3 : Symbol(foo3, Decl(index.d.ts, 5, 32)) +>a : Symbol(a, Decl(index.d.ts, 6, 30)) +>c : Symbol(c, Decl(index.d.ts, 6, 37)) + + a?: string | undefined; +>a : Symbol(a, Decl(index.d.ts, 6, 43)) + + b?: {c?: string | undefined;} | undefined; +>b : Symbol(b, Decl(index.d.ts, 7, 27)) +>c : Symbol(c, Decl(index.d.ts, 8, 9)) + +} | undefined, b: string): void; +>b : Symbol(b, Decl(index.d.ts, 9, 14)) + diff --git a/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.types b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.types new file mode 100644 index 00000000000..798b5268337 --- /dev/null +++ b/tests/baselines/reference/initializedParameterBeforeNonoptionalNotOptional.types @@ -0,0 +1,35 @@ +=== tests/cases/compiler/index.d.ts === +export declare function foo({a}?: { +>foo : ({ a }?: { a?: string | undefined; } | undefined) => void +>a : string | undefined + + a?: string; +>a : string | undefined + +}): void; +export declare function foo2({a}: { +>foo2 : ({ a }: { a?: string | undefined; } | undefined, b: string) => void +>a : string | undefined + + a?: string | undefined; +>a : string | undefined + +} | undefined, b: string): void; +>b : string + +export declare function foo3({a, b: {c}}: { +>foo3 : ({ a, b: { c } }: { a?: string | undefined; b?: { c?: string | undefined; } | undefined; } | undefined, b: string) => void +>a : string | undefined +>b : any +>c : string | undefined + + a?: string | undefined; +>a : string | undefined + + b?: {c?: string | undefined;} | undefined; +>b : { c?: string | undefined; } | undefined +>c : string | undefined + +} | undefined, b: string): void; +>b : string + diff --git a/tests/cases/compiler/initializedParameterBeforeNonoptionalNotOptional.ts b/tests/cases/compiler/initializedParameterBeforeNonoptionalNotOptional.ts new file mode 100644 index 00000000000..327849ae80e --- /dev/null +++ b/tests/cases/compiler/initializedParameterBeforeNonoptionalNotOptional.ts @@ -0,0 +1,12 @@ +// @strict: true +// @filename: index.d.ts +export declare function foo({a}?: { + a?: string; +}): void; +export declare function foo2({a}: { + a?: string | undefined; +} | undefined, b: string): void; +export declare function foo3({a, b: {c}}: { + a?: string | undefined; + b?: {c?: string | undefined;} | undefined; +} | undefined, b: string): void; \ No newline at end of file From f43230a12284fc7f93f48c36fd89b02be21d4af6 Mon Sep 17 00:00:00 2001 From: csigs Date: Tue, 28 Nov 2017 17:10:08 +0000 Subject: [PATCH 34/39] LEGO: check in for master to temporary branch. --- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- .../diagnosticMessages.generated.json.lcl | 30 ++++--------------- 4 files changed, 24 insertions(+), 96 deletions(-) diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 31ccdc9e17a..83479d879c5 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -309,6 +309,9 @@ + + + @@ -3765,32 +3768,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl index fb159e922b7..fb4dfda449c 100644 --- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -309,6 +309,9 @@ + + + @@ -3765,32 +3768,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index da7275f5844..861d10e5028 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -309,6 +309,9 @@ + + + @@ -3765,32 +3768,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 98c3cbfc1f5..9c099aeb990 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -309,6 +309,9 @@ + + + @@ -3765,32 +3768,11 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - + From 6df0575acd874cdade57ee30f66006f0bfa4172e Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 28 Nov 2017 12:37:30 -0500 Subject: [PATCH 35/39] Remove length limit on spelling suggestions; use levenshteinWithMax for performance (#19937) * Remove length limit on spelling suggestions; use levenshteinWithMax for performance * Remove suggestion exceptions * Move to checker.ts * Reintroduce candidateName max length --- src/compiler/checker.ts | 120 ++++++++++++++++++++++++-------------- src/compiler/utilities.ts | 23 -------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d8cbbe5f758..ffb2b673210 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15748,61 +15748,95 @@ namespace ts { * except for candidates: * * With no name * * Whose meaning doesn't match the `meaning` parameter. - * * Whose length differs from the target name by more than 0.3 of the length of the name. + * * Whose length differs from the target name by more than 0.34 of the length of the name. * * Whose levenshtein distance is more than 0.4 of the length of the name * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) - * Names longer than 30 characters don't get suggestions because Levenshtein distance is an n**2 algorithm. */ function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { - const worstDistance = name.length * 0.4; - const maximumLengthDifference = Math.min(3, name.length * 0.34); - let bestDistance = Number.MAX_VALUE; - let bestCandidate = undefined; + const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34)); + let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother. + let bestCandidate: Symbol | undefined; let justCheckExactMatches = false; - if (name.length > 30) { - return undefined; - } - name = name.toLowerCase(); + const nameLowerCase = name.toLowerCase(); for (const candidate of symbols) { - let candidateName = symbolName(candidate); - if (candidate.flags & meaning && - candidateName && - Math.abs(candidateName.length - name.length) < maximumLengthDifference) { - candidateName = candidateName.toLowerCase(); - if (candidateName === name) { - return candidate; - } - if (justCheckExactMatches) { - continue; - } - if (candidateName.length < 3 || - name.length < 3 || - candidateName === "eval" || - candidateName === "intl" || - candidateName === "undefined" || - candidateName === "map" || - candidateName === "nan" || - candidateName === "set") { - continue; - } - const distance = levenshtein(name, candidateName); - if (distance > worstDistance) { - continue; - } - if (distance < 3) { - justCheckExactMatches = true; - bestCandidate = candidate; - } - else if (distance < bestDistance) { - bestDistance = distance; - bestCandidate = candidate; - } + const candidateName = symbolName(candidate); + if (!(candidate.flags & meaning && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference)) { + continue; + } + const candidateNameLowerCase = candidateName.toLowerCase(); + if (candidateNameLowerCase === nameLowerCase) { + return candidate; + } + if (justCheckExactMatches) { + continue; + } + if (candidateName.length < 3) { + // Don't bother, user would have noticed a 2-character name having an extra character + continue; + } + // Only care about a result better than the best so far. + const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1); + if (distance === undefined) { + continue; + } + if (distance < 3) { + justCheckExactMatches = true; + bestCandidate = candidate; + } + else { + Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined + bestDistance = distance; + bestCandidate = candidate; } } return bestCandidate; } + function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined { + let previous = new Array(s2.length + 1); + let current = new Array(s2.length + 1); + /** Represents any value > max. We don't care about the particular value. */ + const big = max + 1; + + for (let i = 0; i <= s2.length; i++) { + previous[i] = i; + } + + for (let i = 1; i <= s1.length; i++) { + const c1 = s1.charCodeAt(i - 1); + const minJ = i > max ? i - max : 1; + const maxJ = s2.length > max + i ? max + i : s2.length; + current[0] = i; + /** Smallest value of the matrix in the ith column. */ + let colMin = i; + for (let j = 1; j < minJ; j++) { + current[j] = big; + } + for (let j = minJ; j <= maxJ; j++) { + const dist = c1 === s2.charCodeAt(j - 1) + ? previous[j - 1] + : Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2); + current[j] = dist; + colMin = Math.min(colMin, dist); + } + for (let j = maxJ + 1; j <= s2.length; j++) { + current[j] = big; + } + if (colMin > max) { + // Give up -- everything in this column is > max and it can't get better in future columns. + return undefined; + } + + const temp = previous; + previous = current; + current = temp; + } + + const res = previous[s2.length]; + return res > max ? undefined : res; + } + function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) { if (prop && noUnusedIdentifiers && diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 28520919e1e..366c4bc229c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3518,29 +3518,6 @@ namespace ts { return 0; } - export function levenshtein(s1: string, s2: string): number { - let previous: number[] = new Array(s2.length + 1); - let current: number[] = new Array(s2.length + 1); - for (let i = 0; i < s2.length + 1; i++) { - previous[i] = i; - current[i] = -1; - } - for (let i = 1; i < s1.length + 1; i++) { - current[0] = i; - for (let j = 1; j < s2.length + 1; j++) { - current[j] = Math.min( - previous[j] + 1, - current[j - 1] + 1, - previous[j - 1] + (s1[i - 1] === s2[j - 1] ? 0 : 2)); - } - // shift current back to previous, and then reuse previous' array - const tmp = previous; - previous = current; - current = tmp; - } - return previous[previous.length - 1]; - } - export function skipAlias(symbol: Symbol, checker: TypeChecker) { return symbol.flags & SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol; } From 185f15d2af8e082aab7ce79482cf0a59842f1f4d Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 28 Nov 2017 14:01:51 -0500 Subject: [PATCH 36/39] Support both baseUrl and relative paths when adding missing import (#19724) * Support both baseUrl and relative paths when adding missing import * Code review * Always use getRelativePathNParents, not getRelativePathLength --- src/services/codefixes/importFixes.ts | 151 ++++++++++++------ src/services/completions.ts | 2 +- .../importNameCodeFixNewImportBaseUrl0.ts | 3 + .../importNameCodeFixNewImportBaseUrl1.ts | 25 +++ .../importNameCodeFixNewImportBaseUrl2.ts | 25 +++ 5 files changed, 154 insertions(+), 52 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFixNewImportBaseUrl1.ts create mode 100644 tests/cases/fourslash/importNameCodeFixNewImportBaseUrl2.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index dae997fc2e7..41515265862 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -209,8 +209,7 @@ namespace ts.codefix { } } } - actions.push(getCodeActionForAddImport(moduleSymbols, context, declarations)); - return actions; + return [...actions, ...getCodeActionsForAddImport(moduleSymbols, context, declarations)]; } function getNamespaceImportName(declaration: AnyImportSyntax): Identifier { @@ -309,19 +308,84 @@ namespace ts.codefix { } } - export function getModuleSpecifierForNewImport(sourceFile: SourceFile, moduleSymbols: ReadonlyArray, options: CompilerOptions, getCanonicalFileName: (file: string) => string, host: LanguageServiceHost): string | undefined { - const choices = mapIterator(arrayIterator(moduleSymbols), moduleSymbol => { + export function getModuleSpecifiersForNewImport( + sourceFile: SourceFile, + moduleSymbols: ReadonlyArray, + options: CompilerOptions, + getCanonicalFileName: (file: string) => string, + host: LanguageServiceHost, + ): string[] { + const { baseUrl, paths, rootDirs } = options; + const choicesForEachExportingModule = mapIterator(arrayIterator(moduleSymbols), moduleSymbol => { const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName; const sourceDirectory = getDirectoryPath(sourceFile.fileName); + const global = tryGetModuleNameFromAmbientModule(moduleSymbol) + || tryGetModuleNameFromTypeRoots(options, host, getCanonicalFileName, moduleFileName) + || tryGetModuleNameAsNodeModule(options, moduleFileName, host, getCanonicalFileName, sourceDirectory) + || rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName); + if (global) { + return [global]; + } - return tryGetModuleNameFromAmbientModule(moduleSymbol) || - tryGetModuleNameFromTypeRoots(options, host, getCanonicalFileName, moduleFileName) || - tryGetModuleNameAsNodeModule(options, moduleFileName, host, getCanonicalFileName, sourceDirectory) || - tryGetModuleNameFromBaseUrl(options, moduleFileName, getCanonicalFileName) || - options.rootDirs && tryGetModuleNameFromRootDirs(options.rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) || - removeExtensionAndIndexPostFix(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName), options); + const relativePath = removeExtensionAndIndexPostFix(getRelativePath(moduleFileName, sourceDirectory, getCanonicalFileName), options); + if (!baseUrl) { + return [relativePath]; + } + + const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName); + if (!relativeToBaseUrl) { + return [relativePath]; + } + + const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, options); + if (paths) { + const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths); + if (fromPaths) { + return [fromPaths]; + } + } + + /* + Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl. + + Suppose we have: + baseUrl = /base + sourceDirectory = /base/a/b + moduleFileName = /base/foo/bar + Then: + relativePath = ../../foo/bar + getRelativePathNParents(relativePath) = 2 + pathFromSourceToBaseUrl = ../../ + getRelativePathNParents(pathFromSourceToBaseUrl) = 2 + 2 < 2 = false + In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar". + + Suppose we have: + baseUrl = /base + sourceDirectory = /base/foo/a + moduleFileName = /base/foo/bar + Then: + relativePath = ../a + getRelativePathNParents(relativePath) = 1 + pathFromSourceToBaseUrl = ../../ + getRelativePathNParents(pathFromSourceToBaseUrl) = 2 + 1 < 2 = true + In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a". + */ + const pathFromSourceToBaseUrl = getRelativePath(baseUrl, sourceDirectory, getCanonicalFileName); + const relativeFirst = getRelativePathNParents(pathFromSourceToBaseUrl) < getRelativePathNParents(relativePath); + return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath]; }); - return best(choices, (a, b) => a.length < b.length); + // Only return results for the re-export with the shortest possible path (and also give the other path even if that's long.) + return best(choicesForEachExportingModule, (a, b) => a[0].length < b[0].length); + } + + function getRelativePathNParents(relativePath: string): number { + let count = 0; + for (let i = 0; i + 3 <= relativePath.length && relativePath.slice(i, i + 3) === "../"; i += 3) { + count++; + } + return count; } function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined { @@ -331,44 +395,28 @@ namespace ts.codefix { } } - function tryGetModuleNameFromBaseUrl(options: CompilerOptions, moduleFileName: string, getCanonicalFileName: (file: string) => string): string | undefined { - if (!options.baseUrl) { - return undefined; - } - - let relativeName = getRelativePathIfInDirectory(moduleFileName, options.baseUrl, getCanonicalFileName); - if (!relativeName) { - return undefined; - } - - const relativeNameWithIndex = removeFileExtension(relativeName); - relativeName = removeExtensionAndIndexPostFix(relativeName, options); - - if (options.paths) { - for (const key in options.paths) { - for (const pattern of options.paths[key]) { - const indexOfStar = pattern.indexOf("*"); - if (indexOfStar === 0 && pattern.length === 1) { - continue; - } - else if (indexOfStar !== -1) { - const prefix = pattern.substr(0, indexOfStar); - const suffix = pattern.substr(indexOfStar + 1); - if (relativeName.length >= prefix.length + suffix.length && - startsWith(relativeName, prefix) && - endsWith(relativeName, suffix)) { - const matchedStar = relativeName.substr(prefix.length, relativeName.length - suffix.length); - return key.replace("\*", matchedStar); - } - } - else if (pattern === relativeName || pattern === relativeNameWithIndex) { - return key; + function tryGetModuleNameFromPaths(relativeNameWithIndex: string, relativeName: string, paths: MapLike>): string | undefined { + for (const key in paths) { + for (const pattern of paths[key]) { + const indexOfStar = pattern.indexOf("*"); + if (indexOfStar === 0 && pattern.length === 1) { + continue; + } + else if (indexOfStar !== -1) { + const prefix = pattern.substr(0, indexOfStar); + const suffix = pattern.substr(indexOfStar + 1); + if (relativeName.length >= prefix.length + suffix.length && + startsWith(relativeName, prefix) && + endsWith(relativeName, suffix)) { + const matchedStar = relativeName.substr(prefix.length, relativeName.length - suffix.length); + return key.replace("\*", matchedStar); } } + else if (pattern === relativeName || pattern === relativeNameWithIndex) { + return key; + } } } - - return relativeName; } function tryGetModuleNameFromRootDirs(rootDirs: ReadonlyArray, moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string): string | undefined { @@ -541,10 +589,11 @@ namespace ts.codefix { return !pathIsRelative(relativePath) ? "./" + relativePath : relativePath; } - function getCodeActionForAddImport( + function getCodeActionsForAddImport( moduleSymbols: ReadonlyArray, ctx: ImportCodeFixOptions, - declarations: ReadonlyArray): ImportCodeAction { + declarations: ReadonlyArray + ): ImportCodeAction[] { const fromExistingImport = firstDefined(declarations, declaration => { if (declaration.kind === SyntaxKind.ImportDeclaration && declaration.importClause) { const changes = tryUpdateExistingImport(ctx, isImportClause(declaration.importClause) && declaration.importClause || undefined); @@ -560,12 +609,12 @@ namespace ts.codefix { } }); if (fromExistingImport) { - return fromExistingImport; + return [fromExistingImport]; } - const moduleSpecifier = firstDefined(declarations, moduleSpecifierFromAnyImport) - || getModuleSpecifierForNewImport(ctx.sourceFile, moduleSymbols, ctx.compilerOptions, ctx.getCanonicalFileName, ctx.host); - return getCodeActionForNewImport(ctx, moduleSpecifier); + const existingDeclaration = firstDefined(declarations, moduleSpecifierFromAnyImport); + const moduleSpecifiers = existingDeclaration ? [existingDeclaration] : getModuleSpecifiersForNewImport(ctx.sourceFile, moduleSymbols, ctx.compilerOptions, ctx.getCanonicalFileName, ctx.host); + return moduleSpecifiers.map(spec => getCodeActionForNewImport(ctx, spec)); } function moduleSpecifierFromAnyImport(node: AnyImportSyntax): string | undefined { diff --git a/src/services/completions.ts b/src/services/completions.ts index bfa03ef4a9f..a3b94acd4c0 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -488,7 +488,7 @@ namespace ts.Completions { const moduleSymbols = getAllReExportingModules(exportedSymbol, checker, allSourceFiles); Debug.assert(contains(moduleSymbols, moduleSymbol)); - const sourceDisplay = [textPart(codefix.getModuleSpecifierForNewImport(sourceFile, moduleSymbols, compilerOptions, getCanonicalFileName, host))]; + const sourceDisplay = [textPart(first(codefix.getModuleSpecifiersForNewImport(sourceFile, moduleSymbols, compilerOptions, getCanonicalFileName, host)))]; const codeActions = codefix.getCodeActionForImport(moduleSymbols, { host, checker, diff --git a/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl0.ts b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl0.ts index a48b381df68..bc852b5c47c 100644 --- a/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl0.ts +++ b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl0.ts @@ -13,6 +13,9 @@ //// export function f1() { }; verify.importFixAtPosition([ +`import { f1 } from "./a/b"; + +f1();`, `import { f1 } from "b"; f1();` diff --git a/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl1.ts b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl1.ts new file mode 100644 index 00000000000..e690cfd3dbb --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl1.ts @@ -0,0 +1,25 @@ +/// + +// @Filename: /tsconfig.json +////{ +//// "compilerOptions": { +//// "baseUrl": "./a" +//// } +////} + +// @Filename: /a/b/x.ts +////export function f1() { }; + +// @Filename: /a/b/y.ts +////[|f1/*0*/();|] + +goTo.file("/a/b/y.ts"); +// Order the local import first because it's simpler. +verify.importFixAtPosition([ +`import { f1 } from "./x"; + +f1();`, +`import { f1 } from "b/x"; + +f1();` +]); diff --git a/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl2.ts b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl2.ts new file mode 100644 index 00000000000..658bd25823f --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixNewImportBaseUrl2.ts @@ -0,0 +1,25 @@ +/// + +// @Filename: /tsconfig.json +////{ +//// "compilerOptions": { +//// "baseUrl": "./a" +//// } +////} + +// @Filename: /a/b/x.ts +////export function f1() { }; + +// @Filename: /a/c/y.ts +////[|f1/*0*/();|] + +goTo.file("/a/c/y.ts"); +// Order the baseUrl import first, because the relative import climbs up to the base url. +verify.importFixAtPosition([ +`import { f1 } from "b/x"; + +f1();`, +`import { f1 } from "../b/x"; + +f1();` +]); From bbb56fed118b392e91dc3d098f08dd7596fab889 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 28 Nov 2017 14:12:28 -0500 Subject: [PATCH 37/39] Support parameter properties in `getRelatedSymbol` (#20202) --- src/services/findAllReferences.ts | 28 ++++++++++++----- ...arameterPropertyDeclaration_inheritance.ts | 31 +++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 0f64321f1be..86db21e3225 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1427,10 +1427,7 @@ namespace ts.FindAllReferences.Core { // we should include both parameter declaration symbol and property declaration symbol // Parameter Declaration symbol is only visible within function scope, so the symbol is stored in constructor.locals. // Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members - if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter && - isParameterPropertyDeclaration(symbol.valueDeclaration)) { - addRange(result, checker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)); - } + addRange(result, getParameterPropertySymbols(symbol, checker)); // If this is symbol of binding element without propertyName declaration in Object binding pattern // Include the property in the search @@ -1460,6 +1457,12 @@ namespace ts.FindAllReferences.Core { } } + function getParameterPropertySymbols(symbol: Symbol, checker: TypeChecker): Symbol[] { + return symbol.valueDeclaration && isParameter(symbol.valueDeclaration) && isParameterPropertyDeclaration(symbol.valueDeclaration) + ? checker.getSymbolsOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name) + : undefined; + } + /** * Find symbol of the given property-name and add the symbol to the given result array * @param symbol a symbol to start searching for the given propertyName @@ -1519,17 +1522,26 @@ namespace ts.FindAllReferences.Core { } function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined { + const { checker } = state; if (search.includes(referenceSymbol)) { return referenceSymbol; } + if (referenceSymbol.flags & SymbolFlags.FunctionScopedVariable) { + Debug.assert(!(referenceSymbol.flags & SymbolFlags.Property)); + const paramProps = getParameterPropertySymbols(referenceSymbol, checker); + if (paramProps) { + return getRelatedSymbol(search, find(paramProps, x => !!(x.flags & SymbolFlags.Property))!, referenceLocation, state); + } + } + // If the reference location is in an object literal, try to get the contextual type for the // object literal, lookup the property symbol in the contextual type, and use this symbol to // compare to our searchSymbol const containingObjectLiteralElement = getContainingObjectLiteralElement(referenceLocation); if (containingObjectLiteralElement) { - const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, state.checker), contextualSymbol => - find(state.checker.getRootSymbols(contextualSymbol), search.includes)); + const contextualSymbol = forEach(getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker), contextualSymbol => + find(checker.getRootSymbols(contextualSymbol), search.includes)); if (contextualSymbol) { return contextualSymbol; @@ -1539,7 +1551,7 @@ namespace ts.FindAllReferences.Core { // Get the property symbol from the object literal's type and look if thats the search symbol // In below eg. get 'property' from type of elems iterating type // for ( { property: p2 } of elems) { } - const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, state.checker); + const propertySymbol = getPropertySymbolOfDestructuringAssignment(referenceLocation, checker); if (propertySymbol && search.includes(propertySymbol)) { return propertySymbol; } @@ -1548,7 +1560,7 @@ namespace ts.FindAllReferences.Core { // If the reference location is the binding element and doesn't have property name // then include the binding element in the related symbols // let { a } : { a }; - const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker); + const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, checker); if (bindingElementPropertySymbol) { const fromBindingElement = findRootSymbol(bindingElementPropertySymbol); if (fromBindingElement) return fromBindingElement; diff --git a/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts b/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts new file mode 100644 index 00000000000..3002cd4d3e7 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsParameterPropertyDeclaration_inheritance.ts @@ -0,0 +1,31 @@ +/// + +////class C { +//// constructor(public [|{| "isWriteAccess": true, "isDefinition": true |}x|]: string) { +//// [|x|]; +//// } +////} +////class D extends C { +//// constructor(public [|{| "isWriteAccess": true, "isDefinition": true |}x|]: string) { +//// super([|x|]); +//// } +////} + +const [r0, r1, r2, r3] = test.ranges(); +verify.referenceGroups(r0, [ + { definition: "(property) C.x: string", ranges: [r0, r2, r3] }, + { definition: "(parameter) x: string", ranges: [r1] }, +]); +verify.referenceGroups(r1, [ + { definition: "(property) C.x: string", ranges: [r0] }, + { definition: "(parameter) x: string", ranges: [r1] }, +]); +verify.referenceGroups(r2, [ + { definition: "(property) C.x: string", ranges: [r0, r1] }, + { definition: "(property) D.x: string", ranges: [r2] }, + { definition: "(parameter) x: string", ranges: [r3] }, +]); +verify.referenceGroups(r3, [ + { definition: "(property) D.x: string", ranges: [r2] }, + { definition: "(parameter) x: string", ranges: [r3] }, +]); From cb5fd537311ca15aad1b83513636ac220291c969 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 28 Nov 2017 15:41:59 -0500 Subject: [PATCH 38/39] Handle shebang in import code fix (#20306) --- src/services/utilities.ts | 22 +++++++++++-------- .../fourslash/importNameCodeFixShebang.ts | 18 +++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFixShebang.ts diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 3837763cee5..e76fcd93492 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1329,13 +1329,17 @@ namespace ts { return getTokenAtPosition(sourceFile, declaration.members.pos - 1, /*includeJsDocComment*/ false); } - export function getSourceFileImportLocation(node: SourceFile) { - // For a source file, it is possible there are detached comments we should not skip - const text = node.text; - const textLength = text.length; - let ranges = getLeadingCommentRanges(text, 0); - if (!ranges) return 0; + export function getSourceFileImportLocation({ text }: SourceFile) { + const shebang = getShebang(text); let position = 0; + if (shebang !== undefined) { + position = shebang.length; + advancePastLineBreak(); + } + + // For a source file, it is possible there are detached comments we should not skip + let ranges = getLeadingCommentRanges(text, position); + if (!ranges) return position; // However we should still skip a pinned comment at the top if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) { position = ranges[0].end; @@ -1344,7 +1348,7 @@ namespace ts { } // As well as any triple slash references for (const range of ranges) { - if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) { + if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(text, range.pos, range.end)) { position = range.end; advancePastLineBreak(); continue; @@ -1354,12 +1358,12 @@ namespace ts { return position; function advancePastLineBreak() { - if (position < textLength) { + if (position < text.length) { const charCode = text.charCodeAt(position); if (isLineBreak(charCode)) { position++; - if (position < textLength && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) { + if (position < text.length && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) { position++; } } diff --git a/tests/cases/fourslash/importNameCodeFixShebang.ts b/tests/cases/fourslash/importNameCodeFixShebang.ts new file mode 100644 index 00000000000..1ef7be11625 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixShebang.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: /a.ts +////export const foo = 0; + +// @Filename: /b.ts +////[|#!/usr/bin/env node +////foo/**/|] + +goTo.file("/a.ts"); +goTo.file("/b.ts"); + +verify.importFixAtPosition([ +`#!/usr/bin/env node +import { foo } from "./a"; + +foo`, +]); From 5ee640d2b633f584e1574c7e202860060a35637a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 28 Nov 2017 13:37:42 -0800 Subject: [PATCH 39/39] Move utilities for getting type parameter constraints and defaults from public lazy members to services (#20162) --- src/compiler/checker.ts | 1 + src/compiler/types.ts | 11 +++++++---- src/services/services.ts | 6 ++++++ src/services/types.ts | 2 ++ tests/baselines/reference/api/tsserverlibrary.d.ts | 7 ++++--- tests/baselines/reference/api/typescript.d.ts | 7 ++++--- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ffb2b673210..cd4eeed7522 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -251,6 +251,7 @@ namespace ts { getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type), getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning), getBaseConstraintOfType, + getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined, resolveName(name, location, meaning) { return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false); }, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 53c36ac6caa..c7803c35ee0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2771,7 +2771,8 @@ namespace ts { getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; - /* @internal */ getBaseConstraintOfType(type: Type): Type | undefined; + getBaseConstraintOfType(type: Type): Type | undefined; + getDefaultFromTypeParameter(type: Type): Type | undefined; /* @internal */ getAnyType(): Type; /* @internal */ getStringType(): Type; @@ -3575,15 +3576,17 @@ namespace ts { export interface TypeVariable extends Type { /* @internal */ - resolvedBaseConstraint: Type; + resolvedBaseConstraint?: Type; /* @internal */ - resolvedIndexType: IndexType; + resolvedIndexType?: IndexType; } // Type parameters (TypeFlags.TypeParameter) export interface TypeParameter extends TypeVariable { /** Retrieve using getConstraintFromTypeParameter */ - constraint: Type; // Constraint + /* @internal */ + constraint?: Type; // Constraint + /* @internal */ default?: Type; /* @internal */ target?: TypeParameter; // Instantiation target diff --git a/src/services/services.ts b/src/services/services.ts index d62fc88a649..0d5e4680312 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -472,6 +472,12 @@ namespace ts { getNonNullableType(): Type { return this.checker.getNonNullableType(this); } + getConstraint(): Type | undefined { + return this.checker.getBaseConstraintOfType(this); + } + getDefault(): Type | undefined { + return this.checker.getDefaultFromTypeParameter(this); + } } class SignatureObject implements Signature { diff --git a/src/services/types.ts b/src/services/types.ts index 28de0566a50..e74b830cc45 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -50,6 +50,8 @@ namespace ts { getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; getNonNullableType(): Type; + getConstraint(): Type | undefined; + getDefault(): Type | undefined; } export interface Signature { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 0de484e36b5..c01647f7b4e 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1783,6 +1783,8 @@ declare namespace ts { getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + getBaseConstraintOfType(type: Type): Type | undefined; + getDefaultFromTypeParameter(type: Type): Type | undefined; } enum NodeBuilderFlags { None = 0, @@ -2119,9 +2121,6 @@ declare namespace ts { interface TypeVariable extends Type { } interface TypeParameter extends TypeVariable { - /** Retrieve using getConstraintFromTypeParameter */ - constraint: Type; - default?: Type; } interface IndexedAccessType extends TypeVariable { objectType: Type; @@ -3843,6 +3842,8 @@ declare namespace ts { getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; getNonNullableType(): Type; + getConstraint(): Type | undefined; + getDefault(): Type | undefined; } interface Signature { getDeclaration(): SignatureDeclaration; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 810a16e6c6b..1e843eee60d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1783,6 +1783,8 @@ declare namespace ts { getApparentType(type: Type): Type; getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined; getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; + getBaseConstraintOfType(type: Type): Type | undefined; + getDefaultFromTypeParameter(type: Type): Type | undefined; } enum NodeBuilderFlags { None = 0, @@ -2119,9 +2121,6 @@ declare namespace ts { interface TypeVariable extends Type { } interface TypeParameter extends TypeVariable { - /** Retrieve using getConstraintFromTypeParameter */ - constraint: Type; - default?: Type; } interface IndexedAccessType extends TypeVariable { objectType: Type; @@ -3843,6 +3842,8 @@ declare namespace ts { getNumberIndexType(): Type | undefined; getBaseTypes(): BaseType[] | undefined; getNonNullableType(): Type; + getConstraint(): Type | undefined; + getDefault(): Type | undefined; } interface Signature { getDeclaration(): SignatureDeclaration;