From 0255adc4076b7b963e2db2b0c8bba4e330fbfd01 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Tue, 8 Aug 2017 10:08:48 +0800 Subject: [PATCH 01/74] fix #16567: better coloring on light theme terminal --- src/compiler/program.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 64e8eb0c803..db83f740253 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -243,7 +243,7 @@ namespace ts { const redForegroundEscapeSequence = "\u001b[91m"; const yellowForegroundEscapeSequence = "\u001b[93m"; const blueForegroundEscapeSequence = "\u001b[93m"; - const gutterStyleSequence = "\u001b[100;30m"; + const gutterStyleSequence = "\u001b[30;47m"; const gutterSeparator = " "; const resetEscapeSequence = "\u001b[0m"; const ellipsis = "..."; From 16ccb6637785724c2b215cb26ac2f7d727591130 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 28 Aug 2017 16:09:09 -0700 Subject: [PATCH 02/74] Provide jsdoc type code fixes for all variable-like decls This includes 3 SyntaxKinds I missed earlier: Parameter, PropertyDeclaration and PropertyAssignment. --- src/services/codefixes/fixJSDocTypes.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 249bc32dbf7..27c0edac628 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -8,11 +8,16 @@ namespace ts.codefix { function getActionsForJSDocTypes(context: CodeFixContext): CodeAction[] | undefined { const sourceFile = context.sourceFile; const node = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); - const decl = ts.findAncestor(node, n => n.kind === SyntaxKind.VariableDeclaration); + const decl = ts.findAncestor(node, + n => n.kind === SyntaxKind.VariableDeclaration || + n.kind === SyntaxKind.Parameter || + n.kind === SyntaxKind.PropertyDeclaration || + n.kind === SyntaxKind.PropertyAssignment); if (!decl) return; const checker = context.program.getTypeChecker(); const jsdocType = (decl as VariableDeclaration).type; + if (!jsdocType) return; const original = getTextOfNode(jsdocType); const type = checker.getTypeFromTypeNode(jsdocType); const actions = [createAction(jsdocType, sourceFile.fileName, original, checker.typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.NoTruncation))]; From b082c27fbeb1b46b5a27838aba82edd64a50705e Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 28 Aug 2017 16:10:03 -0700 Subject: [PATCH 03/74] Test:jsdoc codefix for variable-like declarations --- tests/cases/fourslash/codeFixChangeJSDocSyntax10.ts | 5 +++++ tests/cases/fourslash/codeFixChangeJSDocSyntax11.ts | 5 +++++ tests/cases/fourslash/codeFixChangeJSDocSyntax12.ts | 6 ++++++ tests/cases/fourslash/codeFixChangeJSDocSyntax13.ts | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax10.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax11.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax12.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax13.ts diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax10.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax10.ts new file mode 100644 index 00000000000..3e6754588fd --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax10.ts @@ -0,0 +1,5 @@ +// @strict: true +/// +//// function f(x: [|number?|]) { +//// } +verify.rangeAfterCodeFix("number | null", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax11.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax11.ts new file mode 100644 index 00000000000..7ac80125775 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax11.ts @@ -0,0 +1,5 @@ +// @strict: true +/// +//// var f = function f(x: [|string?|]) { +//// } +verify.rangeAfterCodeFix("string | null | undefined", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 1); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax12.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax12.ts new file mode 100644 index 00000000000..37eb5df41ee --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax12.ts @@ -0,0 +1,6 @@ +// @strict: true +/// +////class C { +//// p: [|*|] +////} +verify.rangeAfterCodeFix("any", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax13.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax13.ts new file mode 100644 index 00000000000..5b374b508f1 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax13.ts @@ -0,0 +1,6 @@ +// @strict: true +/// +////class C { +//// p: [|*|] = 12 +////} +verify.rangeAfterCodeFix("any", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); From 63cb84f3d1e09fc62229945556b022432d0ccbc9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 29 Aug 2017 10:38:16 -0700 Subject: [PATCH 04/74] Codefix jsdoc types for anything with a .type That means type parameters and type arguments are still not handled. --- src/services/codefixes/fixJSDocTypes.ts | 20 +++++++++++++++++-- .../fourslash/codeFixChangeJSDocSyntax14.ts | 5 +++++ .../fourslash/codeFixChangeJSDocSyntax15.ts | 5 +++++ .../fourslash/codeFixChangeJSDocSyntax16.ts | 4 ++++ .../fourslash/codeFixChangeJSDocSyntax17.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax18.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax19.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax20.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax21.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax22.ts | 3 +++ .../fourslash/codeFixChangeJSDocSyntax23.ts | 6 ++++++ .../fourslash/codeFixChangeJSDocSyntax24.ts | 5 +++++ .../fourslash/codeFixChangeJSDocSyntax25.ts | 5 +++++ .../fourslash/codeFixChangeJSDocSyntax26.ts | 5 +++++ .../fourslash/codeFixChangeJSDocSyntax27.ts | 4 ++++ 15 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax14.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax15.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax16.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax17.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax18.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax19.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax20.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax22.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax23.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax24.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax25.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax26.ts create mode 100644 tests/cases/fourslash/codeFixChangeJSDocSyntax27.ts diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 27c0edac628..8d5cd562497 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -8,11 +8,27 @@ namespace ts.codefix { function getActionsForJSDocTypes(context: CodeFixContext): CodeAction[] | undefined { const sourceFile = context.sourceFile; const node = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); + + // NOTE: Some locations are not handled yet: + // MappedTypeNode.typeParameters and SignatureDeclaration.typeParameters, as well as CallExpression.typeArguments const decl = ts.findAncestor(node, - n => n.kind === SyntaxKind.VariableDeclaration || + n => + n.kind === SyntaxKind.AsExpression || + n.kind === SyntaxKind.CallSignature || + n.kind === SyntaxKind.ConstructSignature || + n.kind === SyntaxKind.FunctionDeclaration || + n.kind === SyntaxKind.GetAccessor || + n.kind === SyntaxKind.IndexSignature || + n.kind === SyntaxKind.MappedType || + n.kind === SyntaxKind.MethodDeclaration || + n.kind === SyntaxKind.MethodSignature || n.kind === SyntaxKind.Parameter || n.kind === SyntaxKind.PropertyDeclaration || - n.kind === SyntaxKind.PropertyAssignment); + n.kind === SyntaxKind.PropertySignature || + n.kind === SyntaxKind.SetAccessor || + n.kind === SyntaxKind.TypeAliasDeclaration || + n.kind === SyntaxKind.TypeAssertionExpression || + n.kind === SyntaxKind.VariableDeclaration); if (!decl) return; const checker = context.program.getTypeChecker(); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax14.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax14.ts new file mode 100644 index 00000000000..69478fc3abc --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax14.ts @@ -0,0 +1,5 @@ +// @strict: true +/// +//// var x = 12 as [|number?|]; + +verify.rangeAfterCodeFix("number | null", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax15.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax15.ts new file mode 100644 index 00000000000..9482830c19d --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax15.ts @@ -0,0 +1,5 @@ +/// +//// var f = <[|function(number?): number|]>(x => x); + +// note: without --strict, number? --> number, not number | null +verify.rangeAfterCodeFix("(arg0: number) => number", /*includeWhiteSpace*/ false, /*errorCode*/ 8020, 0); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax16.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax16.ts new file mode 100644 index 00000000000..111aec1dce7 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax16.ts @@ -0,0 +1,4 @@ +/// +//// var f: { [K in keyof number]: [|*|] }; + +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax17.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax17.ts new file mode 100644 index 00000000000..6a3ce2ed3df --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax17.ts @@ -0,0 +1,3 @@ +/// +//// declare function index(ix: number): [|*|]; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax18.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax18.ts new file mode 100644 index 00000000000..30a3815516a --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax18.ts @@ -0,0 +1,3 @@ +/// +//// var index: { (ix: number): [|?|] }; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax19.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax19.ts new file mode 100644 index 00000000000..e6344881227 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax19.ts @@ -0,0 +1,3 @@ +/// +//// var index: { new (ix: number): [|?|] }; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax20.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax20.ts new file mode 100644 index 00000000000..dc153730841 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax20.ts @@ -0,0 +1,3 @@ +/// +//// var index = { get p(): [|*|] { return 12 } }; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts new file mode 100644 index 00000000000..442414e4577 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts @@ -0,0 +1,3 @@ +/// +//// var index = { set p(x: [|*|]) { } }; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax22.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax22.ts new file mode 100644 index 00000000000..c575f1ca7ce --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax22.ts @@ -0,0 +1,3 @@ +/// +//// var index: { [s: string]: [|*|] }; +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax23.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax23.ts new file mode 100644 index 00000000000..7ab70e18ee7 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax23.ts @@ -0,0 +1,6 @@ +/// +////class C { +//// m(): [|*|] { +//// } +////} +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax24.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax24.ts new file mode 100644 index 00000000000..7ea2d1f6faf --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax24.ts @@ -0,0 +1,5 @@ +/// +////declare class C { +//// m(): [|*|]; +////} +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax25.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax25.ts new file mode 100644 index 00000000000..6486a70417e --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax25.ts @@ -0,0 +1,5 @@ +/// +////declare class C { +//// p: [|*|]; +////} +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax26.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax26.ts new file mode 100644 index 00000000000..dc31f1dfffd --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax26.ts @@ -0,0 +1,5 @@ +/// +////class C { +//// p: [|*|] = 12; +////} +verify.rangeAfterCodeFix("any"); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax27.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax27.ts new file mode 100644 index 00000000000..255976c7767 --- /dev/null +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax27.ts @@ -0,0 +1,4 @@ +// @strict: true +/// +////type T = [|...number?|]; +verify.rangeAfterCodeFix("(number | null)[]"); From 3f090114fff2473e9b2ec8e340e7b3dba93266bd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 30 Aug 2017 09:44:51 -0700 Subject: [PATCH 05/74] Optimize array operations to reduce memory footprint --- src/compiler/binder.ts | 6 ++- src/compiler/parser.ts | 114 +++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 69 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a7e94da09d9..67782ece962 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -203,9 +203,11 @@ namespace ts { node.symbol = symbol; if (!symbol.declarations) { - symbol.declarations = []; + symbol.declarations = [node]; + } + else { + symbol.declarations.push(node); } - symbol.declarations.push(node); if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) { symbol.exports = createSymbolTable(); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7486c7541be..bf066b6143e 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -940,10 +940,6 @@ namespace ts { return scanner.getStartPos(); } - function getNodeEnd(): number { - return scanner.getStartPos(); - } - // Use this function to access the current token instead of reading the currentToken // variable. Since function results aren't narrowed in control flow analysis, this ensures // that the type checker doesn't make wrong assumptions about the type of the current @@ -1135,13 +1131,14 @@ namespace ts { new TokenConstructor(kind, pos, pos); } - function createNodeArray(elements?: T[], pos?: number): MutableNodeArray { - const array = >(elements || []); - if (!(pos >= 0)) { - pos = getNodePos(); - } + function createNodeArray(elements: T[], pos: number, end?: number): NodeArray { + // Since the element list of a node array is typically created by starting with an empty array and + // repeatedly calling push(), the list may not have the optimal memory layout. We invoke slice() for + // small arrays (1 to 4 elements) to give the VM a chance to allocate an optimal representation. + const length = elements.length; + const array = >(length >= 1 && length <= 4 ? elements.slice() : elements); array.pos = pos; - array.end = pos; + array.end = end === undefined ? scanner.getStartPos() : end; return array; } @@ -1527,12 +1524,13 @@ namespace ts { function parseList(kind: ParsingContext, parseElement: () => T): NodeArray { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; - const result = createNodeArray(); + const list = []; + const listPos = getNodePos(); while (!isListTerminator(kind)) { if (isListElement(kind, /*inErrorRecovery*/ false)) { const element = parseListElement(kind, parseElement); - result.push(element); + list.push(element); continue; } @@ -1542,9 +1540,8 @@ namespace ts { } } - result.end = getNodeEnd(); parsingContext = saveParsingContext; - return result; + return createNodeArray(list, listPos); } function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T { @@ -1874,13 +1871,14 @@ namespace ts { function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray { const saveParsingContext = parsingContext; parsingContext |= 1 << kind; - const result = createNodeArray(); + const list = []; + const listPos = getNodePos(); let commaStart = -1; // Meaning the previous token was not a comma while (true) { if (isListElement(kind, /*inErrorRecovery*/ false)) { const startPos = scanner.getStartPos(); - result.push(parseListElement(kind, parseElement)); + list.push(parseListElement(kind, parseElement)); commaStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.CommaToken)) { @@ -1924,6 +1922,8 @@ namespace ts { } } + parsingContext = saveParsingContext; + const result = createNodeArray(list, listPos); // Recording the trailing comma is deliberately done after the previous // loop, and not just if we see a list terminator. This is because the list // may have ended incorrectly, but it is still important to know if there @@ -1933,14 +1933,11 @@ namespace ts { // Always preserve a trailing comma by marking it on the NodeArray result.hasTrailingComma = true; } - - result.end = getNodeEnd(); - parsingContext = saveParsingContext; return result; } function createMissingList(): NodeArray { - return createNodeArray(); + return createNodeArray([], getNodePos()); } function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { @@ -2015,15 +2012,15 @@ namespace ts { template.head = parseTemplateHead(); Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind"); - const templateSpans = createNodeArray(); + const list = []; + const listPos = getNodePos(); do { - templateSpans.push(parseTemplateSpan()); + list.push(parseTemplateSpan()); } - while (lastOrUndefined(templateSpans).literal.kind === SyntaxKind.TemplateMiddle); + while (lastOrUndefined(list).literal.kind === SyntaxKind.TemplateMiddle); - templateSpans.end = getNodeEnd(); - template.templateSpans = templateSpans; + template.templateSpans = createNodeArray(list, listPos); return finishNode(template); } @@ -2802,13 +2799,12 @@ namespace ts { parseOptional(operator); let type = parseConstituentType(); if (token() === operator) { - const types = createNodeArray([type], type.pos); + const types = [type]; while (parseOptional(operator)) { types.push(parseConstituentType()); } - types.end = getNodeEnd(); const node = createNode(kind, type.pos); - node.types = types; + node.types = createNodeArray(types, type.pos); type = finishNode(node); } return type; @@ -3174,8 +3170,7 @@ namespace ts { parameter.name = identifier; finishNode(parameter); - node.parameters = createNodeArray([parameter], parameter.pos); - node.parameters.end = parameter.end; + node.parameters = createNodeArray([parameter], parameter.pos, parameter.end); node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>"); node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier); @@ -4025,7 +4020,8 @@ namespace ts { } function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray { - const result = createNodeArray(); + const list = []; + const listPos = getNodePos(); const saveParsingContext = parsingContext; parsingContext |= 1 << ParsingContext.JsxChildren; @@ -4046,15 +4042,13 @@ namespace ts { } const child = parseJsxChild(); if (child) { - result.push(child); + list.push(child); } } - result.end = scanner.getTokenPos(); - parsingContext = saveParsingContext; - return result; + return createNodeArray(list, listPos); } function parseJsxAttributes(): JsxAttributes { @@ -5447,27 +5441,19 @@ namespace ts { } function parseDecorators(): NodeArray { - let decorators: NodeArray & Decorator[]; + let list: Decorator[]; + const listPos = getNodePos(); while (true) { const decoratorStart = getNodePos(); if (!parseOptional(SyntaxKind.AtToken)) { break; } - const decorator = createNode(SyntaxKind.Decorator, decoratorStart); decorator.expression = doInDecoratorContext(parseLeftHandSideExpressionOrHigher); finishNode(decorator); - if (!decorators) { - decorators = createNodeArray([decorator], decoratorStart); - } - else { - decorators.push(decorator); - } + (list || (list = [])).push(decorator); } - if (decorators) { - decorators.end = getNodeEnd(); - } - return decorators; + return list && createNodeArray(list, listPos); } /* @@ -5478,7 +5464,8 @@ namespace ts { * In such situations, 'permitInvalidConstAsModifier' should be set to true. */ function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray | undefined { - let modifiers: MutableNodeArray | undefined; + let list: Modifier[]; + const listPos = getNodePos(); while (true) { const modifierStart = scanner.getStartPos(); const modifierKind = token(); @@ -5497,17 +5484,9 @@ namespace ts { } const modifier = finishNode(createNode(modifierKind, modifierStart)); - if (!modifiers) { - modifiers = createNodeArray([modifier], modifierStart); - } - else { - modifiers.push(modifier); - } + (list || (list = [])).push(modifier); } - if (modifiers) { - modifiers.end = scanner.getStartPos(); - } - return modifiers; + return list && createNodeArray(list, listPos); } function parseModifiersForArrowFunction(): NodeArray { @@ -5518,9 +5497,7 @@ namespace ts { nextToken(); const modifier = finishNode(createNode(modifierKind, modifierStart)); modifiers = createNodeArray([modifier], modifierStart); - modifiers.end = scanner.getStartPos(); } - return modifiers; } @@ -6222,7 +6199,9 @@ namespace ts { Debug.assert(start <= end); Debug.assert(end <= content.length); - let tags: MutableNodeArray; + let tags: JSDocTag[]; + let tagsPos: number; + let tagsEnd: number; const comments: string[] = []; let result: JSDoc; @@ -6355,7 +6334,7 @@ namespace ts { function createJSDocComment(): JSDoc { const result = createNode(SyntaxKind.JSDocComment, start); - result.tags = tags; + result.tags = tags && createNodeArray(tags, tagsPos, tagsEnd); result.comment = comments.length ? comments.join("") : undefined; return finishNode(result, end); } @@ -6495,12 +6474,13 @@ namespace ts { tag.comment = comments.join(""); if (!tags) { - tags = createNodeArray([tag], tag.pos); + tags = [tag]; + tagsPos = tag.pos; } else { tags.push(tag); } - tags.end = tag.end; + tagsEnd = tag.end; } function tryParseTypeExpression(): JSDocTypeExpression | undefined { @@ -6800,7 +6780,8 @@ namespace ts { } // Type parameter list looks like '@template T,U,V' - const typeParameters = createNodeArray(); + const typeParameters = []; + const typeParametersPos = getNodePos(); while (true) { const name = parseJSDocIdentifierName(); @@ -6828,9 +6809,8 @@ namespace ts { const result = createNode(SyntaxKind.JSDocTemplateTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; - result.typeParameters = typeParameters; + result.typeParameters = createNodeArray(typeParameters, typeParametersPos); finishNode(result); - typeParameters.end = result.end; return result; } From c9d081eed49aa1e8cb5d33feabf9a3714cdd10a4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 1 Sep 2017 09:55:38 -0700 Subject: [PATCH 06/74] Expand type references recursively in cache key This means that `A>>` will include the keys for `B` and `C` now. --- src/compiler/checker.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 269666d7b94..22abe7cd57e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9782,8 +9782,8 @@ namespace ts { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } - function isTypeReferenceWithGenericArguments(type: Type) { - return getObjectFlags(type) & ObjectFlags.Reference && some((type).typeArguments, isUnconstrainedTypeParameter); + function isTypeReferenceWithGenericArguments(type: Type): type is TypeReference { + return getObjectFlags(type) & ObjectFlags.Reference && some((type).typeArguments, t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); } /** @@ -9801,6 +9801,9 @@ namespace ts { } result += "=" + index; } + else if (isTypeReferenceWithGenericArguments(t)) { + result += "<" + getTypeReferenceId(t, typeParameters) + ">"; + } else { result += "-" + t.id; } @@ -10050,7 +10053,7 @@ namespace ts { getUnionType(types, /*subtypeReduction*/ true); } - function isArrayType(type: Type): boolean { + function isArrayType(type: Type): type is TypeReference { return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalArrayType; } From 520d7fff49d96ba71b9b441e25ff00c772070dff Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 1 Sep 2017 14:19:12 -0700 Subject: [PATCH 07/74] Add depth limit to recursive type reference id generation 4 is the limit. --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 22abe7cd57e..764307de7a9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9790,7 +9790,7 @@ namespace ts { * getTypeReferenceId(A) returns "111=0-12=1" * where A.id=111 and number.id=12 */ - function getTypeReferenceId(type: TypeReference, typeParameters: Type[]) { + function getTypeReferenceId(type: TypeReference, typeParameters: Type[], depth = 0) { let result = "" + type.target.id; for (const t of type.typeArguments) { if (isUnconstrainedTypeParameter(t)) { @@ -9801,8 +9801,8 @@ namespace ts { } result += "=" + index; } - else if (isTypeReferenceWithGenericArguments(t)) { - result += "<" + getTypeReferenceId(t, typeParameters) + ">"; + else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) { + result += "<" + getTypeReferenceId(t, typeParameters, depth + 1) + ">"; } else { result += "-" + t.id; From b65ff647c1debc58aa66b20359d644f54048fd56 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 2 Sep 2017 10:27:48 -0700 Subject: [PATCH 08/74] Improved caching scheme for anonymous types --- src/compiler/checker.ts | 281 +++++++++++++--------------------- src/compiler/types.ts | 5 +- src/services/signatureHelp.ts | 2 +- 3 files changed, 107 insertions(+), 181 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 269666d7b94..7a9931f19a4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4794,22 +4794,39 @@ namespace ts { return typeParameters; } - // Appends the outer type parameters of a node to a set of type parameters and returns the resulting set. The function - // allocates a new array if the input type parameter set is undefined, but otherwise it modifies the set in-place and - // returns the same array. - function appendOuterTypeParameters(typeParameters: TypeParameter[], node: Node): TypeParameter[] { + // Return the outer type parameters of a node or undefined if the node has no outer type parameters. + function getOuterTypeParameters(node: Node, includeThisTypes?: boolean): TypeParameter[] { while (true) { node = node.parent; if (!node) { - return typeParameters; + return undefined; } - if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || - node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.ArrowFunction) { - const declarations = (node).typeParameters; - if (declarations) { - return appendTypeParameters(appendOuterTypeParameters(typeParameters, node), declarations); - } + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.JSDocFunctionType: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.JSDocTemplateTag: + case SyntaxKind.MappedType: + const outerTypeParameters = getOuterTypeParameters(node, includeThisTypes); + if (node.kind === SyntaxKind.MappedType) { + return append(outerTypeParameters, getDeclaredTypeOfTypeParameter(getSymbolOfNode((node).typeParameter))); + } + const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node) || emptyArray); + const thisType = includeThisTypes && + (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration) && + getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node)).thisType; + return thisType ? append(outerAndOwnTypeParameters, thisType) : outerAndOwnTypeParameters; } } } @@ -4817,7 +4834,7 @@ namespace ts { // The outer type parameters are those defined by enclosing generic classes, methods, or functions. function getOuterTypeParametersOfClassOrInterface(symbol: Symbol): TypeParameter[] { const declaration = symbol.flags & SymbolFlags.Class ? symbol.valueDeclaration : getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); - return appendOuterTypeParameters(/*typeParameters*/ undefined, declaration); + return getOuterTypeParameters(declaration); } // The local type parameters are the combined set of type parameters from all declarations of the class, @@ -6800,7 +6817,7 @@ namespace ts { const id = getTypeListId(typeArguments); let instantiation = links.instantiations.get(id); if (!instantiation) { - links.instantiations.set(id, instantiation = instantiateTypeNoAlias(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters))))); + links.instantiations.set(id, instantiation = instantiateType(type, createTypeMapper(typeParameters, fillMissingTypeArguments(typeArguments, typeParameters, getMinTypeArgumentCount(typeParameters))))); } return instantiation; } @@ -8024,11 +8041,6 @@ namespace ts { return instantiateList(signatures, mapper, instantiateSignature); } - function instantiateCached(type: T, mapper: TypeMapper, instantiator: (item: T, mapper: TypeMapper) => T): T { - const instantiations = mapper.instantiations || (mapper.instantiations = []); - return instantiations[type.id] || (instantiations[type.id] = instantiator(type, mapper)); - } - function makeUnaryTypeMapper(source: Type, target: Type) { return (t: Type) => t === source ? target : t; } @@ -8050,11 +8062,9 @@ namespace ts { function createTypeMapper(sources: TypeParameter[], targets: Type[]): TypeMapper { Debug.assert(targets === undefined || sources.length === targets.length); - const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : + return sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : - makeArrayTypeMapper(sources, targets); - mapper.mappedTypes = sources; - return mapper; + makeArrayTypeMapper(sources, targets); } function createTypeEraser(sources: TypeParameter[]): TypeMapper { @@ -8065,10 +8075,8 @@ namespace ts { * Maps forward-references to later types parameters to the empty object type. * This is used during inference when instantiating type parameter defaults. */ - function createBackreferenceMapper(typeParameters: TypeParameter[], index: number) { - const mapper: TypeMapper = t => indexOf(typeParameters, t) >= index ? emptyObjectType : t; - mapper.mappedTypes = typeParameters; - return mapper; + function createBackreferenceMapper(typeParameters: TypeParameter[], index: number): TypeMapper { + return t => indexOf(typeParameters, t) >= index ? emptyObjectType : t; } function isInferenceContext(mapper: TypeMapper): mapper is InferenceContext { @@ -8086,15 +8094,11 @@ namespace ts { } function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { - const mapper: TypeMapper = t => instantiateType(mapper1(t), mapper2); - mapper.mappedTypes = concatenate(mapper1.mappedTypes, mapper2.mappedTypes); - return mapper; + return t => instantiateType(mapper1(t), mapper2); } - function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper) { - const mapper: TypeMapper = t => t === source ? target : baseMapper(t); - mapper.mappedTypes = baseMapper.mappedTypes; - return mapper; + function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper): TypeMapper { + return t => t === source ? target : baseMapper(t); } function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter { @@ -8174,13 +8178,39 @@ namespace ts { return result; } - function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType { - const result = createObjectType(ObjectFlags.Anonymous | ObjectFlags.Instantiated, type.symbol); - result.target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type; - result.mapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper; - result.aliasSymbol = type.aliasSymbol; - result.aliasTypeArguments = instantiateTypes(type.aliasTypeArguments, mapper); - return result; + function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) { + if (type.objectFlags & ObjectFlags.Instantiated) { + mapper = combineTypeMappers(type.mapper, mapper); + type = type.target; + } + const symbol = type.symbol; + const links = getSymbolLinks(symbol); + if (!links.typeParameters) { + // This first time an anonymous type is instantiated we compute and store a list of the type + // parameters that are in scope (and therefore potentially referenced). + const typeParameters = getOuterTypeParameters(symbol.declarations[0], /*includeThisTypes*/ true); + links.typeParameters = typeParameters || emptyArray; + if (typeParameters) { + links.instantiations = createMap(); + links.instantiations.set(getTypeListId(typeParameters), type); + } + } + const typeParameters = links.typeParameters; + if (typeParameters.length) { + // We are instantiating an anonymous type that has one or more type parameters in scope. Apply the + // mapper to the type parameters to produce the effective list of type arguments, and compute the + // instantiation cache key from the type IDs of the type arguments. + const typeArguments = map(typeParameters, mapper); + const id = getTypeListId(typeArguments); + let result = links.instantiations.get(id); + if (!result) { + const newMapper = createTypeMapper(typeParameters, typeArguments); + result = type.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(type, newMapper) : instantiateAnonymousType(type, newMapper); + links.instantiations.set(id, result); + } + return result; + } + return type; } function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type { @@ -8197,164 +8227,64 @@ namespace ts { if (typeVariable !== mappedTypeVariable) { return mapType(mappedTypeVariable, t => { if (isMappableType(t)) { - return instantiateMappedObjectType(type, createReplacementMapper(typeVariable, t, mapper)); + return instantiateAnonymousType(type, createReplacementMapper(typeVariable, t, mapper)); } return t; }); } } } - return instantiateMappedObjectType(type, mapper); + return instantiateAnonymousType(type, mapper); } function isMappableType(type: Type) { return type.flags & (TypeFlags.TypeParameter | TypeFlags.Object | TypeFlags.Intersection | TypeFlags.IndexedAccess); } - function instantiateMappedObjectType(type: MappedType, mapper: TypeMapper): Type { - const result = createObjectType(ObjectFlags.Mapped | ObjectFlags.Instantiated, type.symbol); - result.declaration = type.declaration; - result.mapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper; + function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType { + const result = createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol); + if (type.objectFlags & ObjectFlags.Mapped) { + (result).declaration = (type).declaration; + } + result.target = type; + result.mapper = mapper; result.aliasSymbol = type.aliasSymbol; result.aliasTypeArguments = instantiateTypes(type.aliasTypeArguments, mapper); return result; } - function isSymbolInScopeOfMappedTypeParameter(symbol: Symbol, mapper: TypeMapper) { - if (!(symbol.declarations && symbol.declarations.length)) { - return false; - } - const mappedTypes = mapper.mappedTypes; - // Starting with the parent of the symbol's declaration, check if the mapper maps any of - // the type parameters introduced by enclosing declarations. We just pick the first - // declaration since multiple declarations will all have the same parent anyway. - return !!findAncestor(symbol.declarations[0], node => { - if (node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.SourceFile) { - return "quit"; - } - switch (node.kind) { - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.Constructor: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.TypeAliasDeclaration: - const typeParameters = getEffectiveTypeParameterDeclarations(node as DeclarationWithTypeParameters); - if (typeParameters) { - for (const d of typeParameters) { - if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode(d)))) { - return true; - } - } - } - if (isClassLike(node) || node.kind === SyntaxKind.InterfaceDeclaration) { - const thisType = getDeclaredTypeOfClassOrInterface(getSymbolOfNode(node)).thisType; - if (thisType && contains(mappedTypes, thisType)) { - return true; - } - } - break; - case SyntaxKind.MappedType: - if (contains(mappedTypes, getDeclaredTypeOfTypeParameter(getSymbolOfNode((node).typeParameter)))) { - return true; - } - break; - case SyntaxKind.JSDocFunctionType: - const func = node as JSDocFunctionType; - for (const p of func.parameters) { - if (contains(mappedTypes, getTypeOfNode(p))) { - return true; - } - } - break; - } - }); - } - - function isTopLevelTypeAlias(symbol: Symbol) { - if (symbol.declarations && symbol.declarations.length) { - const parentKind = symbol.declarations[0].parent.kind; - return parentKind === SyntaxKind.SourceFile || parentKind === SyntaxKind.ModuleBlock; - } - return false; - } - function instantiateType(type: Type, mapper: TypeMapper): Type { if (type && mapper !== identityMapper) { - // If we are instantiating a type that has a top-level type alias, obtain the instantiation through - // the type alias instead in order to share instantiations for the same type arguments. This can - // dramatically reduce the number of structurally identical types we generate. Note that we can only - // perform this optimization for top-level type aliases. Consider: - // - // function f1(x: T) { - // type Foo = { x: X, t: T }; - // let obj: Foo = { x: x }; - // return obj; - // } - // function f2(x: U) { return f1(x); } - // let z = f2(42); - // - // Above, the declaration of f2 has an inferred return type that is an instantiation of f1's Foo - // equivalent to { x: U, t: U }. When instantiating this return type, we can't go back to Foo's - // cache because all cached instantiations are of the form { x: ???, t: T }, i.e. they have not been - // instantiated for T. Instead, we need to further instantiate the { x: U, t: U } form. - if (type.aliasSymbol && isTopLevelTypeAlias(type.aliasSymbol)) { - if (type.aliasTypeArguments) { - return getTypeAliasInstantiation(type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); + if (type.flags & TypeFlags.TypeParameter) { + return mapper(type); + } + if (type.flags & TypeFlags.Object) { + if ((type).objectFlags & ObjectFlags.Anonymous) { + // If the anonymous type originates in a declaration of a function, method, class, or + // interface, in an object type literal, or in an object literal expression, we may need + // to instantiate the type because it might reference a type parameter. + return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ? + getAnonymousTypeInstantiation(type, mapper) : type; + } + if ((type).objectFlags & ObjectFlags.Mapped) { + return getAnonymousTypeInstantiation(type, mapper); + } + if ((type).objectFlags & ObjectFlags.Reference) { + return createTypeReference((type).target, instantiateTypes((type).typeArguments, mapper)); } - return type; } - return instantiateTypeNoAlias(type, mapper); - } - return type; - } - - function instantiateTypeNoAlias(type: Type, mapper: TypeMapper): Type { - if (type.flags & TypeFlags.TypeParameter) { - return mapper(type); - } - if (type.flags & TypeFlags.Object) { - if ((type).objectFlags & ObjectFlags.Anonymous) { - // If the anonymous type originates in a declaration of a function, method, class, or - // interface, in an object type literal, or in an object literal expression, we may need - // to instantiate the type because it might reference a type parameter. We skip instantiation - // if none of the type parameters that are in scope in the type's declaration are mapped by - // the given mapper, however we can only do that analysis if the type isn't itself an - // instantiation. - return type.symbol && - type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && - ((type).objectFlags & ObjectFlags.Instantiated || isSymbolInScopeOfMappedTypeParameter(type.symbol, mapper)) ? - instantiateCached(type, mapper, instantiateAnonymousType) : type; + if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) { + return getUnionType(instantiateTypes((type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); } - if ((type).objectFlags & ObjectFlags.Mapped) { - return instantiateCached(type, mapper, instantiateMappedType); + if (type.flags & TypeFlags.Intersection) { + return getIntersectionType(instantiateTypes((type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); } - if ((type).objectFlags & ObjectFlags.Reference) { - return createTypeReference((type).target, instantiateTypes((type).typeArguments, mapper)); + if (type.flags & TypeFlags.Index) { + return getIndexType(instantiateType((type).type, mapper)); + } + if (type.flags & TypeFlags.IndexedAccess) { + return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper)); } - } - if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) { - return getUnionType(instantiateTypes((type).types, mapper), /*subtypeReduction*/ false, type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); - } - if (type.flags & TypeFlags.Intersection) { - return getIntersectionType(instantiateTypes((type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper)); - } - if (type.flags & TypeFlags.Index) { - return getIndexType(instantiateType((type).type, mapper)); - } - if (type.flags & TypeFlags.IndexedAccess) { - return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper)); } return type; } @@ -10368,7 +10298,6 @@ namespace ts { function createInferenceContext(signature: Signature, flags: InferenceFlags, compareTypes?: TypeComparer, baseInferences?: InferenceInfo[]): InferenceContext { const inferences = baseInferences ? map(baseInferences, cloneInferenceInfo) : map(signature.typeParameters, createInferenceInfo); const context = mapper as InferenceContext; - context.mappedTypes = signature.typeParameters; context.signature = signature; context.inferences = inferences; context.flags = flags; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 64444693acf..99afe5e6e4e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3331,13 +3331,12 @@ namespace ts { } /* @internal */ - export interface MappedType extends ObjectType { + export interface MappedType extends AnonymousType { declaration: MappedTypeNode; typeParameter?: TypeParameter; constraintType?: Type; templateType?: Type; modifiersType?: Type; - mapper?: TypeMapper; // Instantiation mapper } export interface EvolvingArrayType extends ObjectType { @@ -3469,8 +3468,6 @@ namespace ts { /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; - mappedTypes?: TypeParameter[]; // Types mapped by this mapper - instantiations?: Type[]; // Cache of instantiations created using this type mapper. } export const enum InferencePriority { diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 2976b0d28ee..10d5dda7966 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -373,7 +373,7 @@ namespace ts.SignatureHelp { isVariadic = false; // type parameter lists are not variadic prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken)); // Use `.mapper` to ensure we get the generic type arguments even if this is an instantiated version of the signature. - const typeParameters = candidateSignature.mapper ? candidateSignature.mapper.mappedTypes : candidateSignature.typeParameters; + const typeParameters = candidateSignature.typeParameters; // !!! candidateSignature.mapper ? candidateSignature.mapper.mappedTypes : candidateSignature.typeParameters; signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); const parameterParts = mapToDisplayParts(writer => From 601a21c77b3af323b293cbcb3483936443bc50b7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 2 Sep 2017 15:39:14 -0700 Subject: [PATCH 09/74] Fix signature help --- src/services/signatureHelp.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 10d5dda7966..7e8e748bb17 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -372,8 +372,7 @@ namespace ts.SignatureHelp { if (isTypeParameterList) { isVariadic = false; // type parameter lists are not variadic prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken)); - // Use `.mapper` to ensure we get the generic type arguments even if this is an instantiated version of the signature. - const typeParameters = candidateSignature.typeParameters; // !!! candidateSignature.mapper ? candidateSignature.mapper.mappedTypes : candidateSignature.typeParameters; + const typeParameters = (candidateSignature.target || candidateSignature).typeParameters; signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); const parameterParts = mapToDisplayParts(writer => From 319617c5d8f7e496402b1ae746d0d9135bf880b4 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Sep 2017 08:53:04 -0700 Subject: [PATCH 10/74] Optimize caching of type literals --- src/compiler/checker.ts | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a9931f19a4..112bbbf1c0a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8179,33 +8179,37 @@ namespace ts { } function getAnonymousTypeInstantiation(type: AnonymousType, mapper: TypeMapper) { - if (type.objectFlags & ObjectFlags.Instantiated) { - mapper = combineTypeMappers(type.mapper, mapper); - type = type.target; - } - const symbol = type.symbol; + const target = type.objectFlags & ObjectFlags.Instantiated ? type.target : type; + const symbol = target.symbol; const links = getSymbolLinks(symbol); - if (!links.typeParameters) { - // This first time an anonymous type is instantiated we compute and store a list of the type - // parameters that are in scope (and therefore potentially referenced). - const typeParameters = getOuterTypeParameters(symbol.declarations[0], /*includeThisTypes*/ true); - links.typeParameters = typeParameters || emptyArray; - if (typeParameters) { + let typeParameters = links.typeParameters; + if (!typeParameters) { + // The first time an anonymous type is instantiated we compute and store a list of the type + // parameters that are in scope (and therefore potentially referenced). For type literals that + // aren't the right hand side of a generic type alias declaration we optimize by reducing the + // set of type parameters to those that are actually referenced somewhere in the literal. + const declaration = symbol.declarations[0]; + const outerTypeParameters = getOuterTypeParameters(declaration, /*includeThisTypes*/ true) || emptyArray; + typeParameters = symbol.flags & SymbolFlags.TypeLiteral && !target.aliasTypeArguments ? + filter(outerTypeParameters, tp => isTypeParameterReferencedWithin(tp, declaration)) : + outerTypeParameters; + links.typeParameters = typeParameters; + if (typeParameters.length) { links.instantiations = createMap(); - links.instantiations.set(getTypeListId(typeParameters), type); + links.instantiations.set(getTypeListId(typeParameters), target); } } - const typeParameters = links.typeParameters; if (typeParameters.length) { // We are instantiating an anonymous type that has one or more type parameters in scope. Apply the // mapper to the type parameters to produce the effective list of type arguments, and compute the // instantiation cache key from the type IDs of the type arguments. - const typeArguments = map(typeParameters, mapper); + const combinedMapper = type.objectFlags & ObjectFlags.Instantiated ? combineTypeMappers(type.mapper, mapper) : mapper; + const typeArguments = map(typeParameters, combinedMapper); const id = getTypeListId(typeArguments); let result = links.instantiations.get(id); if (!result) { const newMapper = createTypeMapper(typeParameters, typeArguments); - result = type.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(type, newMapper) : instantiateAnonymousType(type, newMapper); + result = target.objectFlags & ObjectFlags.Mapped ? instantiateMappedType(target, newMapper) : instantiateAnonymousType(target, newMapper); links.instantiations.set(id, result); } return result; @@ -8213,6 +8217,16 @@ namespace ts { return type; } + function isTypeParameterReferencedWithin(tp: TypeParameter, node: Node) { + return tp.isThisType ? forEachChild(node, checkThis) : forEachChild(node, checkIdentifier); + function checkThis(node: Node): boolean { + return node.kind === SyntaxKind.ThisType || forEachChild(node, checkThis); + } + function checkIdentifier(node: Node): boolean { + return node.kind === SyntaxKind.Identifier && isPartOfTypeNode(node) && getTypeFromTypeNode(node) === tp || forEachChild(node, checkIdentifier); + } + } + function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type { // Check if we have a homomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some // type variable T. If so, the mapped type is distributive over a union type and when T is instantiated @@ -10420,6 +10434,7 @@ namespace ts { function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) { let symbolStack: Symbol[]; let visited: Map; + //sys.write(typeToString(originalSource) + " ==> " + typeToString(originalTarget) + "\n"); inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type) { @@ -10487,6 +10502,7 @@ namespace ts { const inference = getInferenceInfoForType(target); if (inference) { if (!inference.isFixed) { + //sys.write(" " + typeToString(source) + "\n"); if (!inference.candidates || priority < inference.priority) { inference.candidates = [source]; inference.priority = priority; From a0c40943feaa4afb1fbbe038d2cf5daf9d642f48 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Sep 2017 08:53:19 -0700 Subject: [PATCH 11/74] Accept new baselines --- .../reference/functionConstraintSatisfaction2.errors.txt | 4 ---- tests/baselines/reference/limitDeepInstantiations.errors.txt | 4 ++-- tests/baselines/reference/promisePermutations.errors.txt | 2 -- tests/baselines/reference/promisePermutations2.errors.txt | 2 -- tests/baselines/reference/promisePermutations3.errors.txt | 2 -- 5 files changed, 2 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/functionConstraintSatisfaction2.errors.txt b/tests/baselines/reference/functionConstraintSatisfaction2.errors.txt index f87312634f8..7558a97511f 100644 --- a/tests/baselines/reference/functionConstraintSatisfaction2.errors.txt +++ b/tests/baselines/reference/functionConstraintSatisfaction2.errors.txt @@ -22,8 +22,6 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/functionConstrain Type 'void' is not assignable to type 'string'. tests/cases/conformance/types/typeParameters/typeArgumentLists/functionConstraintSatisfaction2.ts(38,10): error TS2345: Argument of type 'U' is not assignable to parameter of type '(x: string) => string'. Type 'T' is not assignable to type '(x: string) => string'. - Type '() => void' is not assignable to type '(x: string) => string'. - Type 'void' is not assignable to type 'string'. ==== tests/cases/conformance/types/typeParameters/typeArgumentLists/functionConstraintSatisfaction2.ts (13 errors) ==== @@ -102,7 +100,5 @@ tests/cases/conformance/types/typeParameters/typeArgumentLists/functionConstrain ~ !!! error TS2345: Argument of type 'U' is not assignable to parameter of type '(x: string) => string'. !!! error TS2345: Type 'T' is not assignable to type '(x: string) => string'. -!!! error TS2345: Type '() => void' is not assignable to type '(x: string) => string'. -!!! error TS2345: Type 'void' is not assignable to type 'string'. } \ No newline at end of file diff --git a/tests/baselines/reference/limitDeepInstantiations.errors.txt b/tests/baselines/reference/limitDeepInstantiations.errors.txt index 330e5fbc8e4..70718199d2b 100644 --- a/tests/baselines/reference/limitDeepInstantiations.errors.txt +++ b/tests/baselines/reference/limitDeepInstantiations.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2550: Generic type instantiation is excessively deep and possibly infinite. +tests/cases/compiler/limitDeepInstantiations.ts(3,35): error TS2502: '"true"' is referenced directly or indirectly in its own type annotation. tests/cases/compiler/limitDeepInstantiations.ts(5,13): error TS2344: Type '"false"' does not satisfy the constraint '"true"'. @@ -7,7 +7,7 @@ tests/cases/compiler/limitDeepInstantiations.ts(5,13): error TS2344: Type '"fals type Foo = { "true": Foo> }[T]; ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2550: Generic type instantiation is excessively deep and possibly infinite. +!!! error TS2502: '"true"' is referenced directly or indirectly in its own type annotation. let f1: Foo<"true", {}>; let f2: Foo<"false", {}>; ~~~~~~~ diff --git a/tests/baselines/reference/promisePermutations.errors.txt b/tests/baselines/reference/promisePermutations.errors.txt index a876345ffa1..c5527d5aa67 100644 --- a/tests/baselines/reference/promisePermutations.errors.txt +++ b/tests/baselines/reference/promisePermutations.errors.txt @@ -45,7 +45,6 @@ tests/cases/compiler/promisePermutations.ts(134,19): error TS2345: Argument of t tests/cases/compiler/promisePermutations.ts(137,33): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations.ts(144,35): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations.ts(152,36): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Type 'IPromise' is not assignable to type 'Promise'. Types of property 'then' are incompatible. @@ -290,7 +289,6 @@ tests/cases/compiler/promisePermutations.ts(160,21): error TS2345: Argument of t var r10d = r10.then(testFunction, sIPromise, nIPromise); // ok ~~~~~~~~~ !!! error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. -!!! error TS2345: Type 'IPromise' is not assignable to type 'IPromise'. var r10e = r10.then(testFunction, nIPromise, sIPromise).then(sIPromise, sIPromise, sIPromise); // ok var s10 = testFunction10P(x => x); var s10a = s10.then(testFunction10, testFunction10, testFunction10); // ok diff --git a/tests/baselines/reference/promisePermutations2.errors.txt b/tests/baselines/reference/promisePermutations2.errors.txt index 871ee2ae2c3..955063797c0 100644 --- a/tests/baselines/reference/promisePermutations2.errors.txt +++ b/tests/baselines/reference/promisePermutations2.errors.txt @@ -45,7 +45,6 @@ tests/cases/compiler/promisePermutations2.ts(133,19): error TS2345: Argument of tests/cases/compiler/promisePermutations2.ts(136,33): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations2.ts(143,35): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations2.ts(151,36): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Type 'IPromise' is not assignable to type 'Promise'. Types of property 'then' are incompatible. @@ -289,7 +288,6 @@ tests/cases/compiler/promisePermutations2.ts(159,21): error TS2345: Argument of var r10d = r10.then(testFunction, sIPromise, nIPromise); // error ~~~~~~~~~ !!! error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. -!!! error TS2345: Type 'IPromise' is not assignable to type 'IPromise'. var r10e = r10.then(testFunction, nIPromise, sIPromise).then(sIPromise, sIPromise, sIPromise); // ok var s10 = testFunction10P(x => x); var s10a = s10.then(testFunction10, testFunction10, testFunction10); // ok diff --git a/tests/baselines/reference/promisePermutations3.errors.txt b/tests/baselines/reference/promisePermutations3.errors.txt index 9d09559c5d3..89a4cffe688 100644 --- a/tests/baselines/reference/promisePermutations3.errors.txt +++ b/tests/baselines/reference/promisePermutations3.errors.txt @@ -48,7 +48,6 @@ tests/cases/compiler/promisePermutations3.ts(133,19): error TS2345: Argument of tests/cases/compiler/promisePermutations3.ts(136,33): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations3.ts(143,35): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. - Type 'IPromise' is not assignable to type 'IPromise'. tests/cases/compiler/promisePermutations3.ts(151,36): error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => Promise'. Type 'IPromise' is not assignable to type 'Promise'. Types of property 'then' are incompatible. @@ -301,7 +300,6 @@ tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of var r10d = r10.then(testFunction, sIPromise, nIPromise); // error ~~~~~~~~~ !!! error TS2345: Argument of type '(x: any) => IPromise' is not assignable to parameter of type '(error: any) => IPromise'. -!!! error TS2345: Type 'IPromise' is not assignable to type 'IPromise'. var r10e = r10.then(testFunction, nIPromise, sIPromise).then(sIPromise, sIPromise, sIPromise); // ok var s10 = testFunction10P(x => x); var s10a = s10.then(testFunction10, testFunction10, testFunction10); // ok From 82281d9910e9d5dd3289368dad63b18fb87dbc29 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Sep 2017 11:00:03 -0700 Subject: [PATCH 12/74] Fix linting errors --- src/compiler/checker.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 112bbbf1c0a..42b15d1a0ac 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10434,7 +10434,6 @@ namespace ts { function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0) { let symbolStack: Symbol[]; let visited: Map; - //sys.write(typeToString(originalSource) + " ==> " + typeToString(originalTarget) + "\n"); inferFromTypes(originalSource, originalTarget); function inferFromTypes(source: Type, target: Type) { @@ -10502,7 +10501,6 @@ namespace ts { const inference = getInferenceInfoForType(target); if (inference) { if (!inference.isFixed) { - //sys.write(" " + typeToString(source) + "\n"); if (!inference.candidates || priority < inference.priority) { inference.candidates = [source]; inference.priority = priority; From 2fc14d8ae81ceee5046f1be05c6d5536183d8ef9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 5 Sep 2017 10:39:32 -0700 Subject: [PATCH 13/74] Remove added type predicates I forgot that 'f(x): x is T' implies that x is *not* T if f returns false. --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85ac20b4114..8f1f4808741 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9781,7 +9781,7 @@ namespace ts { return type.flags & TypeFlags.TypeParameter && !getConstraintFromTypeParameter(type); } - function isTypeReferenceWithGenericArguments(type: Type): type is TypeReference { + function isTypeReferenceWithGenericArguments(type: Type): boolean { return getObjectFlags(type) & ObjectFlags.Reference && some((type).typeArguments, t => isUnconstrainedTypeParameter(t) || isTypeReferenceWithGenericArguments(t)); } @@ -9801,7 +9801,7 @@ namespace ts { result += "=" + index; } else if (depth < 4 && isTypeReferenceWithGenericArguments(t)) { - result += "<" + getTypeReferenceId(t, typeParameters, depth + 1) + ">"; + result += "<" + getTypeReferenceId(t as TypeReference, typeParameters, depth + 1) + ">"; } else { result += "-" + t.id; @@ -10052,7 +10052,7 @@ namespace ts { getUnionType(types, /*subtypeReduction*/ true); } - function isArrayType(type: Type): type is TypeReference { + function isArrayType(type: Type): boolean { return getObjectFlags(type) & ObjectFlags.Reference && (type).target === globalArrayType; } From 3a164b955b11fb82025a8636d57d8a94740381f8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 5 Sep 2017 12:55:18 -0700 Subject: [PATCH 14/74] Improve baseline of complexRecursiveCollections By adding @lib:es6, which gets rid of tons of bogus errors. The point of the test is compile time, but it's more confidence-inspiring to know that basic ES6 collections are getting resolved and typechecked too. --- .../complexRecursiveCollections.errors.txt | 287 +----------------- .../compiler/complexRecursiveCollections.ts | 1 + 2 files changed, 2 insertions(+), 286 deletions(-) diff --git a/tests/baselines/reference/complexRecursiveCollections.errors.txt b/tests/baselines/reference/complexRecursiveCollections.errors.txt index 38f66b7456a..495fca2e651 100644 --- a/tests/baselines/reference/complexRecursiveCollections.errors.txt +++ b/tests/baselines/reference/complexRecursiveCollections.errors.txt @@ -1,110 +1,15 @@ -tests/cases/compiler/immutable.d.ts(25,39): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(46,20): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(47,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(48,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(49,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(50,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(51,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(52,26): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(58,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(60,63): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(68,41): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(69,38): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(69,47): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(78,21): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(79,21): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(89,20): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(90,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(91,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(92,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(93,23): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(94,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(95,26): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(101,42): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(106,58): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(113,48): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(114,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(114,54): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(120,42): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(125,58): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(134,33): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(134,42): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(135,29): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(135,38): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(139,38): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(155,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(157,62): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(169,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(172,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(174,62): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(188,40): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(195,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(198,19): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(205,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(207,63): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(217,30): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(218,34): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(226,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(227,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(234,48): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(235,52): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(236,109): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(237,109): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(242,22): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(243,25): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(244,24): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(245,28): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(246,25): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(247,25): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(258,8): error TS2304: Cannot find name 'Symbol'. -tests/cases/compiler/immutable.d.ts(258,28): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(266,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(274,44): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(279,60): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(288,44): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(293,47): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(295,65): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(304,40): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(309,47): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(311,64): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(320,38): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(329,58): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(339,45): error TS2304: Cannot find name 'Iterable'. tests/cases/compiler/immutable.d.ts(341,22): error TS2430: Interface 'Keyed' incorrectly extends interface 'Collection'. Types of property 'toSeq' are incompatible. Type '() => Keyed' is not assignable to type '() => this'. Type 'Keyed' is not assignable to type 'this'. -tests/cases/compiler/immutable.d.ts(347,44): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(352,60): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(355,8): error TS2304: Cannot find name 'Symbol'. -tests/cases/compiler/immutable.d.ts(355,28): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(358,44): error TS2304: Cannot find name 'Iterable'. tests/cases/compiler/immutable.d.ts(359,22): error TS2430: Interface 'Indexed' incorrectly extends interface 'Collection'. Types of property 'toSeq' are incompatible. Type '() => Indexed' is not assignable to type '() => this'. Type 'Indexed' is not assignable to type 'this'. -tests/cases/compiler/immutable.d.ts(382,47): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(384,65): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(387,8): error TS2304: Cannot find name 'Symbol'. -tests/cases/compiler/immutable.d.ts(387,28): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(390,40): error TS2304: Cannot find name 'Iterable'. tests/cases/compiler/immutable.d.ts(391,22): error TS2430: Interface 'Set' incorrectly extends interface 'Collection'. Types of property 'toSeq' are incompatible. Type '() => Set' is not assignable to type '() => this'. Type 'Set' is not assignable to type 'this'. -tests/cases/compiler/immutable.d.ts(396,47): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(398,64): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(401,8): error TS2304: Cannot find name 'Symbol'. -tests/cases/compiler/immutable.d.ts(401,28): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(405,45): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(420,26): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(421,26): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(442,13): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(443,15): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(444,16): error TS2304: Cannot find name 'IterableIterator'. -tests/cases/compiler/immutable.d.ts(476,58): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(503,20): error TS2304: Cannot find name 'Iterable'. -tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Iterable'. ==== tests/cases/compiler/complex.d.ts (0 errors) ==== @@ -128,7 +33,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite flatMap(mapper: (value: T, key: void, iter: this) => Ara, context?: any): N2; toSeq(): N2; } -==== tests/cases/compiler/immutable.d.ts (98 errors) ==== +==== tests/cases/compiler/immutable.d.ts (3 errors) ==== // Test that complex recursive collections can pass the `extends` assignability check without // running out of memory. This bug was exposed in Typescript 2.4 when more generic signatures // started being checked. @@ -154,8 +59,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function List(): List; export function List(): List; export function List(collection: Iterable): List; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface List extends Collection.Indexed { // Persistent changes set(index: number, value: T): List; @@ -177,38 +80,20 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite setSize(size: number): List; // Deep persistent changes setIn(keyPath: Iterable, value: any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. deleteIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. removeIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. updateIn(keyPath: Iterable, notSetValue: any, updater: (value: any) => any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. updateIn(keyPath: Iterable, updater: (value: any) => any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeDeepIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Transient changes withMutations(mutator: (mutable: this) => any): this; asMutable(): this; asImmutable(): this; // Sequence algorithms concat(...valuesOrCollections: Array | C>): List; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: number, iter: this) => M, context?: any): List; flatMap(mapper: (value: T, key: number, iter: this) => Iterable, context?: any): List; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, index: number, iter: this) => value is F, context?: any): List; filter(predicate: (value: T, index: number, iter: this) => any, context?: any): this; } @@ -217,13 +102,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite function of(...keyValues: Array): Map; } export function Map(collection: Iterable<[K, V]>): Map; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Map(collection: Iterable>): Map; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Map(obj: {[key: string]: V}): Map; export function Map(): Map; export function Map(): Map; @@ -233,11 +112,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite delete(key: K): this; remove(key: K): this; deleteAll(keys: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. removeAll(keys: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. clear(): this; update(key: K, notSetValue: V, updater: (value: V) => V): this; update(key: K, updater: (value: V) => V): this; @@ -248,41 +123,23 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite mergeDeepWith(merger: (oldVal: V, newVal: V, key: K) => V, ...collections: Array | {[key: string]: V}>): this; // Deep persistent changes setIn(keyPath: Iterable, value: any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. deleteIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. removeIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. updateIn(keyPath: Iterable, notSetValue: any, updater: (value: any) => any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. updateIn(keyPath: Iterable, updater: (value: any) => any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeDeepIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Transient changes withMutations(mutator: (mutable: this) => any): this; asMutable(): this; asImmutable(): this; // Sequence algorithms concat(...collections: Array>): Map; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. concat(...collections: Array<{[key: string]: C}>): Map; map(mapper: (value: V, key: K, iter: this) => M, context?: any): Map; mapKeys(mapper: (key: K, value: V, iter: this) => M, context?: any): Map; mapEntries(mapper: (entry: [K, V], index: number, iter: this) => [KM, VM], context?: any): Map; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): Map; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: V, key: K, iter: this) => value is F, context?: any): Map; filter(predicate: (value: V, key: K, iter: this) => any, context?: any): this; } @@ -290,28 +147,18 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite function isOrderedMap(maybeOrderedMap: any): maybeOrderedMap is OrderedMap; } export function OrderedMap(collection: Iterable<[K, V]>): OrderedMap; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function OrderedMap(collection: Iterable>): OrderedMap; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function OrderedMap(obj: {[key: string]: V}): OrderedMap; export function OrderedMap(): OrderedMap; export function OrderedMap(): OrderedMap; export interface OrderedMap extends Map { // Sequence algorithms concat(...collections: Array>): OrderedMap; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. concat(...collections: Array<{[key: string]: C}>): OrderedMap; map(mapper: (value: V, key: K, iter: this) => M, context?: any): OrderedMap; mapKeys(mapper: (key: K, value: V, iter: this) => M, context?: any): OrderedMap; mapEntries(mapper: (entry: [K, V], index: number, iter: this) => [KM, VM], context?: any): OrderedMap; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): OrderedMap; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: V, key: K, iter: this) => value is F, context?: any): OrderedMap; filter(predicate: (value: V, key: K, iter: this) => any, context?: any): this; } @@ -321,21 +168,11 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite function fromKeys(iter: Collection): Set; function fromKeys(obj: {[key: string]: any}): Set; function intersect(sets: Iterable>): Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. function union(sets: Iterable>): Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. } export function Set(): Set; export function Set(): Set; export function Set(collection: Iterable): Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Set extends Collection.Set { // Persistent changes add(value: T): this; @@ -352,12 +189,8 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite asImmutable(): this; // Sequence algorithms concat(...valuesOrCollections: Array | C>): Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: never, iter: this) => M, context?: any): Set; flatMap(mapper: (value: T, key: never, iter: this) => Iterable, context?: any): Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, key: never, iter: this) => value is F, context?: any): Set; filter(predicate: (value: T, key: never, iter: this) => any, context?: any): this; } @@ -370,17 +203,11 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function OrderedSet(): OrderedSet; export function OrderedSet(): OrderedSet; export function OrderedSet(collection: Iterable): OrderedSet; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface OrderedSet extends Set { // Sequence algorithms concat(...valuesOrCollections: Array | C>): OrderedSet; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: never, iter: this) => M, context?: any): OrderedSet; flatMap(mapper: (value: T, key: never, iter: this) => Iterable, context?: any): OrderedSet; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, key: never, iter: this) => value is F, context?: any): OrderedSet; filter(predicate: (value: T, key: never, iter: this) => any, context?: any): this; zip(...collections: Array>): OrderedSet; @@ -395,8 +222,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function Stack(): Stack; export function Stack(): Stack; export function Stack(collection: Iterable): Stack; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Stack extends Collection.Indexed { // Reading values peek(): T | undefined; @@ -404,13 +229,9 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite clear(): Stack; unshift(...values: Array): Stack; unshiftAll(iter: Iterable): Stack; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. shift(): Stack; push(...values: Array): Stack; pushAll(iter: Iterable): Stack; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. pop(): Stack; // Transient changes withMutations(mutator: (mutable: this) => any): this; @@ -418,12 +239,8 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite asImmutable(): this; // Sequence algorithms concat(...valuesOrCollections: Array | C>): Stack; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: number, iter: this) => M, context?: any): Stack; flatMap(mapper: (value: T, key: number, iter: this) => Iterable, context?: any): Stack; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, index: number, iter: this) => value is F, context?: any): Set; filter(predicate: (value: T, index: number, iter: this) => any, context?: any): this; } @@ -434,11 +251,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function getDescriptiveName(record: Instance): string; export interface Class { (values?: Partial | Iterable<[string, any]>): Instance & Readonly; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. new (values?: Partial | Iterable<[string, any]>): Instance & Readonly; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. } export interface Instance { readonly size: number; @@ -447,11 +260,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite get(key: K): T[K]; // Reading deep values hasIn(keyPath: Iterable): boolean; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. getIn(keyPath: Iterable): any; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Value equality equals(other: any): boolean; hashCode(): number; @@ -459,39 +268,19 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite set(key: K, value: T[K]): this; update(key: K, updater: (value: T[K]) => T[K]): this; merge(...collections: Array | Iterable<[string, any]>>): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeDeep(...collections: Array | Iterable<[string, any]>>): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeWith(merger: (oldVal: any, newVal: any, key: keyof T) => any, ...collections: Array | Iterable<[string, any]>>): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeDeepWith(merger: (oldVal: any, newVal: any, key: any) => any, ...collections: Array | Iterable<[string, any]>>): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. delete(key: K): this; remove(key: K): this; clear(): this; // Deep persistent changes setIn(keyPath: Iterable, value: any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. updateIn(keyPath: Iterable, updater: (value: any) => any): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. mergeDeepIn(keyPath: Iterable, ...collections: Array): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. deleteIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. removeIn(keyPath: Iterable): this; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Conversion to JavaScript types toJS(): { [K in keyof T]: any }; toJSON(): T; @@ -503,10 +292,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite // Sequence algorithms toSeq(): Seq.Keyed; [Symbol.iterator](): IterableIterator<[keyof T, T[keyof T]]>; - ~~~~~~ -!!! error TS2304: Cannot find name 'Symbol'. - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. } } export function Record(defaultValues: T, name?: string): Record.Class; @@ -515,8 +300,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite function of(...values: Array): Seq.Indexed; export module Keyed {} export function Keyed(collection: Iterable<[K, V]>): Seq.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Keyed(obj: {[key: string]: V}): Seq.Keyed; export function Keyed(): Seq.Keyed; export function Keyed(): Seq.Keyed; @@ -525,15 +308,11 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite toJSON(): { [key: string]: V }; toSeq(): this; concat(...collections: Array>): Seq.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. concat(...collections: Array<{[key: string]: C}>): Seq.Keyed; map(mapper: (value: V, key: K, iter: this) => M, context?: any): Seq.Keyed; mapKeys(mapper: (key: K, value: V, iter: this) => M, context?: any): Seq.Keyed; mapEntries(mapper: (entry: [K, V], index: number, iter: this) => [KM, VM], context?: any): Seq.Keyed; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): Seq.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: V, key: K, iter: this) => value is F, context?: any): Seq.Keyed; filter(predicate: (value: V, key: K, iter: this) => any, context?: any): this; } @@ -543,19 +322,13 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function Indexed(): Seq.Indexed; export function Indexed(): Seq.Indexed; export function Indexed(collection: Iterable): Seq.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Indexed extends Seq, Collection.Indexed { toJS(): Array; toJSON(): Array; toSeq(): this; concat(...valuesOrCollections: Array | C>): Seq.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: number, iter: this) => M, context?: any): Seq.Indexed; flatMap(mapper: (value: T, key: number, iter: this) => Iterable, context?: any): Seq.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, index: number, iter: this) => value is F, context?: any): Seq.Indexed; filter(predicate: (value: T, index: number, iter: this) => any, context?: any): this; } @@ -565,19 +338,13 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function Set(): Seq.Set; export function Set(): Seq.Set; export function Set(collection: Iterable): Seq.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Set extends Seq, Collection.Set { toJS(): Array; toJSON(): Array; toSeq(): this; concat(...valuesOrCollections: Array | C>): Seq.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: never, iter: this) => M, context?: any): Seq.Set; flatMap(mapper: (value: T, key: never, iter: this) => Iterable, context?: any): Seq.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, key: never, iter: this) => value is F, context?: any): Seq.Set; filter(predicate: (value: T, key: never, iter: this) => any, context?: any): this; } @@ -587,8 +354,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite export function Seq(collection: Collection.Indexed): Seq.Indexed; export function Seq(collection: Collection.Set): Seq.Set; export function Seq(collection: Iterable): Seq.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Seq(obj: {[key: string]: V}): Seq.Keyed; export function Seq(): Seq; export interface Seq extends Collection { @@ -598,8 +363,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite // Sequence algorithms map(mapper: (value: V, key: K, iter: this) => M, context?: any): Seq; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): Seq; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: V, key: K, iter: this) => value is F, context?: any): Seq; filter(predicate: (value: V, key: K, iter: this) => any, context?: any): this; } @@ -610,8 +373,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite function isOrdered(maybeOrdered: any): boolean; export module Keyed {} export function Keyed(collection: Iterable<[K, V]>): Collection.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Keyed(obj: {[key: string]: V}): Collection.Keyed; export interface Keyed extends Collection { ~~~~~ @@ -625,27 +386,17 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite // Sequence functions flip(): this; concat(...collections: Array>): Collection.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. concat(...collections: Array<{[key: string]: C}>): Collection.Keyed; map(mapper: (value: V, key: K, iter: this) => M, context?: any): Collection.Keyed; mapKeys(mapper: (key: K, value: V, iter: this) => M, context?: any): Collection.Keyed; mapEntries(mapper: (entry: [K, V], index: number, iter: this) => [KM, VM], context?: any): Collection.Keyed; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): Collection.Keyed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: V, key: K, iter: this) => value is F, context?: any): Collection.Keyed; filter(predicate: (value: V, key: K, iter: this) => any, context?: any): this; [Symbol.iterator](): IterableIterator<[K, V]>; - ~~~~~~ -!!! error TS2304: Cannot find name 'Symbol'. - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. } export module Indexed {} export function Indexed(collection: Iterable): Collection.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Indexed extends Collection { ~~~~~~~ !!! error TS2430: Interface 'Indexed' incorrectly extends interface 'Collection'. @@ -675,24 +426,14 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite findLastIndex(predicate: (value: T, index: number, iter: this) => boolean, context?: any): number; // Sequence algorithms concat(...valuesOrCollections: Array | C>): Collection.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: number, iter: this) => M, context?: any): Collection.Indexed; flatMap(mapper: (value: T, key: number, iter: this) => Iterable, context?: any): Collection.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, index: number, iter: this) => value is F, context?: any): Collection.Indexed; filter(predicate: (value: T, index: number, iter: this) => any, context?: any): this; [Symbol.iterator](): IterableIterator; - ~~~~~~ -!!! error TS2304: Cannot find name 'Symbol'. - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. } export module Set {} export function Set(collection: Iterable): Collection.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export interface Set extends Collection { ~~~ !!! error TS2430: Interface 'Set' incorrectly extends interface 'Collection'. @@ -704,25 +445,15 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite toSeq(): Seq.Set; // Sequence algorithms concat(...valuesOrCollections: Array | C>): Collection.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. map(mapper: (value: T, key: never, iter: this) => M, context?: any): Collection.Set; flatMap(mapper: (value: T, key: never, iter: this) => Iterable, context?: any): Collection.Set; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. filter(predicate: (value: T, key: never, iter: this) => value is F, context?: any): Collection.Set; filter(predicate: (value: T, key: never, iter: this) => any, context?: any): this; [Symbol.iterator](): IterableIterator; - ~~~~~~ -!!! error TS2304: Cannot find name 'Symbol'. - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. } } export function Collection>(collection: I): I; export function Collection(collection: Iterable): Collection.Indexed; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. export function Collection(obj: {[key: string]: V}): Collection.Keyed; export interface Collection extends ValueObject { // Value equality @@ -738,11 +469,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite last(): V | undefined; // Reading deep values getIn(searchKeyPath: Iterable, notSetValue?: any): any; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. hasIn(searchKeyPath: Iterable): boolean; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Persistent changes update(updater: (value: this) => R): R; // Conversion to JavaScript types @@ -764,14 +491,8 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite toSetSeq(): Seq.Set; // Iterators keys(): IterableIterator; - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. values(): IterableIterator; - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. entries(): IterableIterator<[K, V]>; - ~~~~~~~~~~~~~~~~ -!!! error TS2304: Cannot find name 'IterableIterator'. // Collections (Seq) keySeq(): Seq.Indexed; valueSeq(): Seq.Indexed; @@ -804,8 +525,6 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite flatten(depth?: number): Collection; flatten(shallow?: boolean): Collection; flatMap(mapper: (value: V, key: K, iter: this) => Iterable, context?: any): Collection; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. // Reducing a value reduce(reducer: (reduction: R, value: V, key: K, iter: this) => R, initialReduction: R, context?: any): R; reduce(reducer: (reduction: V | R, value: V, key: K, iter: this) => R): R; @@ -833,11 +552,7 @@ tests/cases/compiler/immutable.d.ts(504,22): error TS2304: Cannot find name 'Ite minBy(comparatorValueMapper: (value: V, key: K, iter: this) => C, comparator?: (valueA: C, valueB: C) => number): V | undefined; // Comparison isSubset(iter: Iterable): boolean; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. isSuperset(iter: Iterable): boolean; - ~~~~~~~~ -!!! error TS2304: Cannot find name 'Iterable'. readonly size: number; } } diff --git a/tests/cases/compiler/complexRecursiveCollections.ts b/tests/cases/compiler/complexRecursiveCollections.ts index a79b429f204..68054aac0f9 100644 --- a/tests/cases/compiler/complexRecursiveCollections.ts +++ b/tests/cases/compiler/complexRecursiveCollections.ts @@ -1,3 +1,4 @@ +// @lib: es6 // @Filename: complex.d.ts interface Ara { t: T } interface Collection { From 6ae761720e7c532185940166f0b9ea5afba89599 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 5 Sep 2017 13:37:51 -0700 Subject: [PATCH 15/74] Add test for #14574 (#18024) --- tests/cases/fourslash/quickInfoForSyntaxErrorNoError.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/cases/fourslash/quickInfoForSyntaxErrorNoError.ts diff --git a/tests/cases/fourslash/quickInfoForSyntaxErrorNoError.ts b/tests/cases/fourslash/quickInfoForSyntaxErrorNoError.ts new file mode 100644 index 00000000000..147483cfe58 --- /dev/null +++ b/tests/cases/fourslash/quickInfoForSyntaxErrorNoError.ts @@ -0,0 +1,9 @@ +/// + +//// namespace X { +//// export = +//// } +//// X.add/*1*/ + +// verify there is no crash +verify.quickInfoAt("1", "any"); From 9c6765d5cf697b5cb2fcda3d21bb2c2985ecdaf9 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 5 Sep 2017 15:47:54 -0700 Subject: [PATCH 16/74] Document ThrottledOperations.schedule --- src/server/utilities.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 700a1e12fee..cde6329bf07 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -179,6 +179,12 @@ namespace ts.server { constructor(private readonly host: ServerHost) { } + /** + * Wait `number` milliseconds and then invoke `cb`. If, while waiting, schedule + * is called again with the same `operationId`, cancel this operation in favor + * of the new one. (Note that the amount of time the canceled operation had been + * waiting does not affect the amount of time that the new operation waits.) + */ public schedule(operationId: string, delay: number, cb: () => void) { const pendingTimeout = this.pendingTimeouts.get(operationId); if (pendingTimeout) { From 95bf71f08c114dc22979cfbeed5f1bcddfc6bbbd Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 5 Sep 2017 17:17:04 -0700 Subject: [PATCH 17/74] Use canonicalized forms when comparing signatures --- src/compiler/checker.ts | 31 ++++++++++++++++++++++++++----- src/compiler/types.ts | 2 ++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fa5441f6841..bf0d7655309 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6632,11 +6632,31 @@ namespace ts { } function getErasedSignature(signature: Signature): Signature { - if (!signature.typeParameters) return signature; - if (!signature.erasedSignatureCache) { - signature.erasedSignatureCache = instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true); - } - return signature.erasedSignatureCache; + return signature.typeParameters ? + signature.erasedSignatureCache || (signature.erasedSignatureCache = createErasedSignature(signature)) : + signature; + } + + function createErasedSignature(signature: Signature) { + // Create an instantiation of the signature where all type arguments are the any type. + return instantiateSignature(signature, createTypeEraser(signature.typeParameters), /*eraseTypeParameters*/ true); + } + + function getCanonicalSignature(signature: Signature): Signature { + return signature.typeParameters ? + signature.canonicalSignatureCache || (signature.canonicalSignatureCache = createCanonicalSignature(signature)) : + signature; + } + + function createCanonicalSignature(signature: Signature) { + // Create an instantiation of the signature where each unconstrained type parameter is replaced with + // its original. When a generic class or interface is instantiated, each generic method in the class or + // interface is instantiated with a fresh set of cloned type parameters (which we need to handle scenarios + // where different generations of the same type parameter are in scope). This leads to a lot of new type + // identities, and potentially a lot of work comparing those identities, so here we create an instantiation + // that reverts back to the original type identities for all unconstrained type parameters. + const canonicalTypeArguments = map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp); + return instantiateSignature(signature, createTypeMapper(signature.typeParameters, canonicalTypeArguments), /*eraseTypeParameters*/ true); } function getOrCreateTypeFromSignature(signature: Signature): ObjectType { @@ -8473,6 +8493,7 @@ namespace ts { return Ternary.False; } + target = getCanonicalSignature(target); if (source.typeParameters) { source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e2d9977f302..9d5bbf5b08e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3447,6 +3447,8 @@ namespace ts { /* @internal */ erasedSignatureCache?: Signature; // Erased version of signature (deferred) /* @internal */ + canonicalSignatureCache?: Signature; // Canonical version of signature (deferred) + /* @internal */ isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison /* @internal */ typePredicate?: TypePredicate; From 482e802e83598da9bb3c02adb7af71cffa2331aa Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Tue, 5 Sep 2017 16:00:19 -0700 Subject: [PATCH 18/74] Limit the number of unanswered typings installer requests If we send them all at once, we (apparently) hit a buffer limit in the node IPC channel and both TS Server and the typings installer become unresponsive. --- src/server/server.ts | 62 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index f70e2d0faf7..7f6daa92d5e 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -236,25 +236,35 @@ namespace ts.server { return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}.${d.getMilliseconds()}`; } + interface QueuedOperation { + operationId: string; + operation: () => void; + } + class NodeTypingsInstaller implements ITypingsInstaller { private installer: NodeChildProcess; private installerPidReported = false; private socket: NodeSocket; private projectService: ProjectService; - private throttledOperations: ThrottledOperations; private eventSender: EventSender; + private activeRequestCount = 0; + private requestQueue: QueuedOperation[] = []; + private requestMap = createMap(); // Maps operation ID to newest requestQueue entry with that ID + + private static readonly maxActiveRequestCount = 10; + private static readonly requestDelayMillis = 100; + constructor( private readonly telemetryEnabled: boolean, private readonly logger: server.Logger, - host: ServerHost, + private readonly host: ServerHost, eventPort: number, readonly globalTypingsCacheLocation: string, readonly typingSafeListLocation: string, readonly typesMapLocation: string, private readonly npmLocation: string | undefined, private newLine: string) { - this.throttledOperations = new ThrottledOperations(host); if (eventPort) { const s = net.connect({ port: eventPort }, () => { this.socket = s; @@ -338,12 +348,26 @@ namespace ts.server { this.logger.info(`Scheduling throttled operation: ${JSON.stringify(request)}`); } } - this.throttledOperations.schedule(project.getProjectName(), /*ms*/ 250, () => { + + const operationId = project.getProjectName(); + const operation = () => { if (this.logger.hasLevel(LogLevel.verbose)) { this.logger.info(`Sending request: ${JSON.stringify(request)}`); } this.installer.send(request); - }); + }; + const queuedRequest: QueuedOperation = { operationId, operation }; + + if (this.activeRequestCount < NodeTypingsInstaller.maxActiveRequestCount) { + this.scheduleRequest(queuedRequest); + } + else { + if (this.logger.hasLevel(LogLevel.verbose)) { + this.logger.info(`Deferring request for: ${operationId}`); + } + this.requestQueue.push(queuedRequest); + this.requestMap.set(operationId, queuedRequest); + } } private handleMessage(response: SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) { @@ -404,11 +428,39 @@ namespace ts.server { return; } + if (this.activeRequestCount > 0) { + this.activeRequestCount--; + } + else { + Debug.fail("Received too many responses"); + } + + while (this.requestQueue.length > 0) { + const queuedRequest = this.requestQueue.shift(); + if (this.requestMap.get(queuedRequest.operationId) == queuedRequest) { + this.requestMap.delete(queuedRequest.operationId); + this.scheduleRequest(queuedRequest); + break; + } + + if (this.logger.hasLevel(LogLevel.verbose)) { + this.logger.info(`Skipping defunct request for: ${queuedRequest.operationId}`); + } + } + this.projectService.updateTypingsForProject(response); if (response.kind === ActionSet && this.socket) { this.sendEvent(0, "setTypings", response); } } + + private scheduleRequest(request: QueuedOperation) { + if(this.logger.hasLevel(LogLevel.verbose)) { + this.logger.info(`Scheduling request for: ${request.operationId}`); + } + this.activeRequestCount++; + this.host.setTimeout(request.operation, NodeTypingsInstaller.requestDelayMillis); + } } class IOSession extends Session { From fc163300435e4dce17312fe5b7a74ade4d621afb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 6 Sep 2017 09:48:00 -0700 Subject: [PATCH 19/74] Minor changes --- src/compiler/checker.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf0d7655309..1bbd710e327 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6654,9 +6654,8 @@ namespace ts { // interface is instantiated with a fresh set of cloned type parameters (which we need to handle scenarios // where different generations of the same type parameter are in scope). This leads to a lot of new type // identities, and potentially a lot of work comparing those identities, so here we create an instantiation - // that reverts back to the original type identities for all unconstrained type parameters. - const canonicalTypeArguments = map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp); - return instantiateSignature(signature, createTypeMapper(signature.typeParameters, canonicalTypeArguments), /*eraseTypeParameters*/ true); + // that uses the original type identities for all unconstrained type parameters. + return getSignatureInstantiation(signature, map(signature.typeParameters, tp => tp.target && !getConstraintOfTypeParameter(tp.target) ? tp.target : tp)); } function getOrCreateTypeFromSignature(signature: Signature): ObjectType { @@ -8493,8 +8492,8 @@ namespace ts { return Ternary.False; } - target = getCanonicalSignature(target); - if (source.typeParameters) { + if (source.typeParameters && source.typeParameters !== target.typeParameters) { + target = getCanonicalSignature(target); source = instantiateSignatureInContextOf(source, target, /*contextualMapper*/ undefined, compareTypes); } From 7c69dd84b9996d631cd0ad47bf97a496dec18b17 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 6 Sep 2017 13:11:35 -0700 Subject: [PATCH 20/74] Disable lookahead in isStartOfParameter/isStartOfType --- src/compiler/core.ts | 2 +- src/compiler/parser.ts | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 20f757c3df8..a9138e0ab5c 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1283,7 +1283,7 @@ namespace ts { args[i] = arguments[i]; } - return t => reduceLeft<(t: T) => T, T>(args, (u, f) => f(u), t); + return t => reduceLeft(args, (u, f) => f(u), t); } else if (d) { return t => d(c(b(a(t)))); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 71c7d3aac49..e4847517252 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2237,7 +2237,14 @@ namespace ts { return token() === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifierKind(token()) || - token() === SyntaxKind.AtToken || isStartOfType(); + token() === SyntaxKind.AtToken || + // a jsdoc parameter can start directly with a type, but shouldn't look ahead + // in order to avoid confusion between parenthesized types and arrow functions + // eg + // declare function f(cb: function(number): void): void; + // vs + // f((n) => console.log(n)); + isStartOfType(/*disableLookahead*/ true); } function parseParameter(): ParameterDeclaration { @@ -2698,7 +2705,7 @@ namespace ts { } } - function isStartOfType(): boolean { + function isStartOfType(disableLookahead?: boolean): boolean { switch (token()) { case SyntaxKind.AnyKeyword: case SyntaxKind.StringKeyword: @@ -2728,11 +2735,11 @@ namespace ts { case SyntaxKind.DotDotDotToken: return true; case SyntaxKind.MinusToken: - return lookAhead(nextTokenIsNumericLiteral); + return !disableLookahead && lookAhead(nextTokenIsNumericLiteral); case SyntaxKind.OpenParenToken: // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, // or something that starts a type. We don't want to consider things like '(1)' a type. - return lookAhead(isStartOfParenthesizedOrFunctionType); + return !disableLookahead && lookAhead(isStartOfParenthesizedOrFunctionType); default: return isIdentifier(); } From 36607e1bde77ba57bb09023ded321f18516abaf5 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 6 Sep 2017 14:39:53 -0700 Subject: [PATCH 21/74] Allow quoted names in completions (#18162) * Allow quoted names in completions * Don't allow string literal completions if not in an object literal; and use string literals for number keys * Add TODO --- src/harness/fourslash.ts | 14 ++++-- src/services/completions.ts | 46 +++++++++++-------- ...nForQuotedPropertyInPropertyAssignment1.ts | 11 +---- ...nForQuotedPropertyInPropertyAssignment2.ts | 11 +---- ...nForQuotedPropertyInPropertyAssignment3.ts | 15 ++---- .../completionListInvalidMemberNames.ts | 15 ++---- .../completionListInvalidMemberNames2.ts | 9 ++-- ...entifiers-should-not-show-in-completion.ts | 10 +--- tests/cases/fourslash/fourslash.ts | 2 +- 9 files changed, 57 insertions(+), 76 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 3010fc53533..c224fd210ea 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -762,7 +762,7 @@ namespace FourSlash { } } - public verifyCompletionsAt(markerName: string, expected: string[]) { + public verifyCompletionsAt(markerName: string, expected: string[], options?: FourSlashInterface.CompletionsAtOptions) { this.goToMarker(markerName); const actualCompletions = this.getCompletionListAtCaret(); @@ -770,6 +770,10 @@ namespace FourSlash { this.raiseError(`No completions at position '${this.currentCaretPosition}'.`); } + if (options && options.isNewIdentifierLocation !== undefined && actualCompletions.isNewIdentifierLocation !== options.isNewIdentifierLocation) { + this.raiseError(`Expected 'isNewIdentifierLocation' to be ${options.isNewIdentifierLocation}, got ${actualCompletions.isNewIdentifierLocation}`); + } + const actual = actualCompletions.entries; if (actual.length !== expected.length) { @@ -3705,8 +3709,8 @@ namespace FourSlashInterface { super(state); } - public completionsAt(markerName: string, completions: string[]) { - this.state.verifyCompletionsAt(markerName, completions); + public completionsAt(markerName: string, completions: string[], options?: CompletionsAtOptions) { + this.state.verifyCompletionsAt(markerName, completions, options); } public quickInfoIs(expectedText: string, expectedDocumentation?: string) { @@ -4314,4 +4318,8 @@ namespace FourSlashInterface { actionName: string; actionDescription: string; } + + export interface CompletionsAtOptions { + isNewIdentifierLocation?: boolean; + } } diff --git a/src/services/completions.ts b/src/services/completions.ts index fde07aa78f6..300ade2da48 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -24,7 +24,7 @@ namespace ts.Completions { return undefined; } - const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, request, keywordFilters } = completionData; + const { symbols, isGlobalCompletion, isMemberCompletion, allowStringLiteral, isNewIdentifierLocation, location, request, keywordFilters } = completionData; if (sourceFile.languageVariant === LanguageVariant.JSX && location && location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) { @@ -56,7 +56,7 @@ namespace ts.Completions { const entries: CompletionEntry[] = []; if (isSourceFileJavaScript(sourceFile)) { - const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log); + const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log, allowStringLiteral); getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target, entries); } else { @@ -64,7 +64,7 @@ namespace ts.Completions { return undefined; } - getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log); + getCompletionEntriesFromSymbols(symbols, entries, location, /*performCharacterChecks*/ true, typeChecker, compilerOptions.target, log, allowStringLiteral); } // TODO add filter for keyword based on type/value/namespace and also location @@ -97,7 +97,7 @@ namespace ts.Completions { } uniqueNames.set(realName, true); - const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true); + const displayName = getCompletionEntryDisplayName(realName, target, /*performCharacterChecks*/ true, /*allowStringLiteral*/ false); if (displayName) { entries.push({ name: displayName, @@ -109,11 +109,11 @@ namespace ts.Completions { }); } - function createCompletionEntry(symbol: Symbol, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget): CompletionEntry { + function createCompletionEntry(symbol: Symbol, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget, allowStringLiteral: boolean): CompletionEntry { // Try to get a valid display name for this symbol, if we could not find one, then ignore it. // We would like to only show things that can be added after a dot, so for instance numeric properties can // not be accessed with a dot (a.1 <- invalid) - const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks); + const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks, allowStringLiteral); if (!displayName) { return undefined; } @@ -134,12 +134,12 @@ namespace ts.Completions { }; } - function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: Push, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget, log: Log): Map { + function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: Push, location: Node, performCharacterChecks: boolean, typeChecker: TypeChecker, target: ScriptTarget, log: Log, allowStringLiteral: boolean): Map { const start = timestamp(); const uniqueNames = createMap(); if (symbols) { for (const symbol of symbols) { - const entry = createCompletionEntry(symbol, location, performCharacterChecks, typeChecker, target); + const entry = createCompletionEntry(symbol, location, performCharacterChecks, typeChecker, target, allowStringLiteral); if (entry) { const id = entry.name; if (!uniqueNames.has(id)) { @@ -224,7 +224,7 @@ namespace ts.Completions { const type = typeChecker.getContextualType((element.parent)); const entries: CompletionEntry[] = []; if (type) { - getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/ false, typeChecker, target, log); + getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/ false, typeChecker, target, log, /*allowStringLiteral*/ true); if (entries.length) { return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries }; } @@ -253,7 +253,7 @@ namespace ts.Completions { const type = typeChecker.getTypeAtLocation(node.expression); const entries: CompletionEntry[] = []; if (type) { - getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/ false, typeChecker, target, log); + getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/ false, typeChecker, target, log, /*allowStringLiteral*/ true); if (entries.length) { return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries }; } @@ -302,13 +302,13 @@ namespace ts.Completions { // Compute all the completion symbols again. const completionData = getCompletionData(typeChecker, log, sourceFile, position); if (completionData) { - const { symbols, location } = completionData; + const { symbols, location, allowStringLiteral } = completionData; // Find the symbol with the matching entry name. // We don't need to perform character checks here because we're only comparing the // name against 'entryName' (which is known to be good), not building a new // completion entry. - const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined); + const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false, allowStringLiteral) === entryName ? s : undefined); if (symbol) { const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All); @@ -345,17 +345,22 @@ namespace ts.Completions { export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol | undefined { // Compute all the completion symbols again. const completionData = getCompletionData(typeChecker, log, sourceFile, position); + if (!completionData) { + return undefined; + } + const { symbols, allowStringLiteral } = completionData; // Find the symbol with the matching entry name. // We don't need to perform character checks here because we're only comparing the // name against 'entryName' (which is known to be good), not building a new // completion entry. - return completionData && forEach(completionData.symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false) === entryName ? s : undefined); + return forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false, allowStringLiteral) === entryName ? s : undefined); } interface CompletionData { symbols: Symbol[]; isGlobalCompletion: boolean; isMemberCompletion: boolean; + allowStringLiteral: boolean; isNewIdentifierLocation: boolean; location: Node; isRightOfDot: boolean; @@ -436,7 +441,7 @@ namespace ts.Completions { } if (request) { - return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, request, keywordFilters: KeywordCompletionFilters.None }; + return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, allowStringLiteral: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, request, keywordFilters: KeywordCompletionFilters.None }; } if (!insideJsDocTagTypeExpression) { @@ -534,6 +539,7 @@ namespace ts.Completions { const semanticStart = timestamp(); let isGlobalCompletion = false; let isMemberCompletion: boolean; + let allowStringLiteral = false; let isNewIdentifierLocation: boolean; let keywordFilters = KeywordCompletionFilters.None; let symbols: Symbol[] = []; @@ -573,7 +579,7 @@ namespace ts.Completions { log("getCompletionData: Semantic work: " + (timestamp() - semanticStart)); - return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), request, keywordFilters }; + return { symbols, isGlobalCompletion, isMemberCompletion, allowStringLiteral, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), request, keywordFilters }; type JSDocTagWithTypeExpression = JSDocAugmentsTag | JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag; @@ -961,6 +967,7 @@ namespace ts.Completions { function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | ObjectBindingPattern): boolean { // We're looking up possible property names from contextual/inferred/declared type. isMemberCompletion = true; + allowStringLiteral = true; let typeMembers: Symbol[]; let existingMembers: ReadonlyArray; @@ -1609,7 +1616,7 @@ namespace ts.Completions { * * @return undefined if the name is of external module */ - function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string | undefined { + function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean, allowStringLiteral: boolean): string | undefined { const name = symbol.name; if (!name) return undefined; @@ -1623,20 +1630,21 @@ namespace ts.Completions { } } - return getCompletionEntryDisplayName(name, target, performCharacterChecks); + return getCompletionEntryDisplayName(name, target, performCharacterChecks, allowStringLiteral); } /** * Get a displayName from a given for completion list, performing any necessary quotes stripping * and checking whether the name is valid identifier name. */ - function getCompletionEntryDisplayName(name: string, target: ScriptTarget, performCharacterChecks: boolean): string { + function getCompletionEntryDisplayName(name: string, target: ScriptTarget, performCharacterChecks: boolean, allowStringLiteral: boolean): string { // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name. // e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid. // We, thus, need to check if whatever was inside the quotes is actually a valid identifier name. if (performCharacterChecks && !isIdentifierText(name, target)) { - return undefined; + // TODO: GH#18169 + return allowStringLiteral ? JSON.stringify(name) : undefined; } return name; diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts index 15f5901113b..ab218cea93d 100644 --- a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment1.ts @@ -13,12 +13,5 @@ //// '/*1*/': '' //// } -goTo.marker('0'); -verify.completionListContains("jspm"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(1); - -goTo.marker('1'); -verify.completionListContains("jspm:dev"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(4); +verify.completionsAt("0", ["jspm", '"jspm:browser"', '"jspm:dev"', '"jspm:node"'], { isNewIdentifierLocation: true }); +verify.completionsAt("1", ["jspm", "jspm:browser", "jspm:dev", "jspm:node"], { isNewIdentifierLocation: true }); diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts index 1d20b57e2a1..66ba4ada241 100644 --- a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment2.ts @@ -19,12 +19,5 @@ //// } //// } -goTo.marker('0'); -verify.completionListContains("jspm"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(1); - -goTo.marker('1'); -verify.completionListContains("jspm:dev"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(4); +verify.completionsAt("0", ["jspm", '"jspm:browser"', '"jspm:dev"', '"jspm:node"'], { isNewIdentifierLocation: true }); +verify.completionsAt("1", ["jspm", "jspm:browser", "jspm:dev", "jspm:node"], { isNewIdentifierLocation: true }); diff --git a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts index 764011d90c1..1ab9aa4a8cf 100644 --- a/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts +++ b/tests/cases/fourslash/completionForQuotedPropertyInPropertyAssignment3.ts @@ -4,7 +4,7 @@ //// jspm: string; //// 'jspm:browser': string; //// } = { -//// /*0*/: "", +//// /*0*/: "", //// } //// let configFiles2: { @@ -12,15 +12,8 @@ //// 'jspm:browser': string; //// } = { //// jspm: "", -//// '/*1*/': "" +//// '/*1*/': "" //// } -goTo.marker('0'); -verify.completionListContains("jspm"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(1); - -goTo.marker('1'); -verify.completionListContains("jspm:browser"); -verify.completionListAllowsNewIdentifier(); -verify.completionListCount(2); +verify.completionsAt("0", ["jspm", '"jspm:browser"'], { isNewIdentifierLocation: true }); +verify.completionsAt("1", ["jspm", "jspm:browser"], { isNewIdentifierLocation: true }); diff --git a/tests/cases/fourslash/completionListInvalidMemberNames.ts b/tests/cases/fourslash/completionListInvalidMemberNames.ts index e0a65bfca4d..8e62ba2fb67 100644 --- a/tests/cases/fourslash/completionListInvalidMemberNames.ts +++ b/tests/cases/fourslash/completionListInvalidMemberNames.ts @@ -11,15 +11,8 @@ //// "\u0031\u0062": "invalid unicode identifer name (1b)" ////}; //// -////x./**/ +////x./*a*/; +////x["/*b*/"]; -goTo.marker(); - -verify.completionListContains("bar"); -verify.completionListContains("break"); -verify.completionListContains("any"); -verify.completionListContains("$"); -verify.completionListContains("b"); - -// Nothing else should show up -verify.completionListCount(5); +verify.completionsAt("a", ["bar", "break", "any", "$", "b"]); +verify.completionsAt("b", ["foo ", "bar", "break", "any", "#", "$", "b", "\u0031\u0062"]); diff --git a/tests/cases/fourslash/completionListInvalidMemberNames2.ts b/tests/cases/fourslash/completionListInvalidMemberNames2.ts index 6b25cf1f5d9..753f9bbcb30 100644 --- a/tests/cases/fourslash/completionListInvalidMemberNames2.ts +++ b/tests/cases/fourslash/completionListInvalidMemberNames2.ts @@ -3,9 +3,8 @@ ////enum Foo { //// X, Y, '☆' ////} -////var x = Foo./**/ +////Foo./*a*/; +////Foo["/*b*/"]; -goTo.marker(); -verify.completionListContains("X"); -verify.completionListContains("Y"); -verify.completionListCount(2); \ No newline at end of file +verify.completionsAt("a", ["X", "Y"]); +verify.completionsAt("b", ["X", "Y", "☆"]); diff --git a/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts b/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts index d01856a54fb..6d5b3167198 100644 --- a/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts +++ b/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts @@ -7,13 +7,7 @@ //// a, //// b //// } -//// +//// //// e./**/ -goTo.marker(); -verify.not.completionListContains('1'); -verify.not.completionListContains('"1"'); -verify.not.completionListContains('2'); -verify.not.completionListContains('3'); -verify.completionListContains('a'); -verify.completionListContains('b'); \ No newline at end of file +verify.completionsAt("", ["a", "b"]); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 652ed4812c0..5150fa16ae9 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -164,7 +164,7 @@ declare namespace FourSlashInterface { class verify extends verifyNegatable { assertHasRanges(ranges: Range[]): void; caretAtMarker(markerName?: string): void; - completionsAt(markerName: string, completions: string[]): void; + completionsAt(markerName: string, completions: string[], options?: { isNewIdentifierLocation?: boolean }): void; indentationIs(numberOfSpaces: number): void; indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle?: ts.IndentStyle, baseIndentSize?: number): void; textAtCaretIs(text: string): void; From 73eff819b589c9a8fdf0e9e866221fa15fe3f885 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 14:44:29 -0700 Subject: [PATCH 22/74] Fix 18224 (#18259) * Probably fix 18224 * Corrected test --- src/compiler/checker.ts | 2 +- tests/baselines/reference/jsdocTypecastNoTypeNoCrash.js | 8 ++++++++ .../reference/jsdocTypecastNoTypeNoCrash.symbols | 8 ++++++++ .../baselines/reference/jsdocTypecastNoTypeNoCrash.types | 9 +++++++++ tests/cases/compiler/jsdocTypecastNoTypeNoCrash.ts | 5 +++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/jsdocTypecastNoTypeNoCrash.js create mode 100644 tests/baselines/reference/jsdocTypecastNoTypeNoCrash.symbols create mode 100644 tests/baselines/reference/jsdocTypecastNoTypeNoCrash.types create mode 100644 tests/cases/compiler/jsdocTypecastNoTypeNoCrash.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1bbd710e327..9fcd0b593f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18017,7 +18017,7 @@ namespace ts { function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { if (isInJavaScriptFile(node) && node.jsDoc) { - const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag)); + const typecasts = flatMap(node.jsDoc, doc => filter(doc.tags, tag => tag.kind === SyntaxKind.JSDocTypeTag && !!(tag as JSDocTypeTag).typeExpression && !!(tag as JSDocTypeTag).typeExpression.type)); if (typecasts && typecasts.length) { // We should have already issued an error if there were multiple type jsdocs const cast = typecasts[0] as JSDocTypeTag; diff --git a/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.js b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.js new file mode 100644 index 00000000000..06c7924440b --- /dev/null +++ b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.js @@ -0,0 +1,8 @@ +//// [index.js] +function Foo() {} +const a = /* @type string */(Foo); + + +//// [index.js] +function Foo() { } +var a = (Foo); diff --git a/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.symbols b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.symbols new file mode 100644 index 00000000000..7a9d98e39ec --- /dev/null +++ b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/index.js === +function Foo() {} +>Foo : Symbol(Foo, Decl(index.js, 0, 0)) + +const a = /* @type string */(Foo); +>a : Symbol(a, Decl(index.js, 1, 5)) +>Foo : Symbol(Foo, Decl(index.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.types b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.types new file mode 100644 index 00000000000..590940b51ff --- /dev/null +++ b/tests/baselines/reference/jsdocTypecastNoTypeNoCrash.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/index.js === +function Foo() {} +>Foo : () => void + +const a = /* @type string */(Foo); +>a : () => void +>(Foo) : () => void +>Foo : () => void + diff --git a/tests/cases/compiler/jsdocTypecastNoTypeNoCrash.ts b/tests/cases/compiler/jsdocTypecastNoTypeNoCrash.ts new file mode 100644 index 00000000000..8c5e52d34f0 --- /dev/null +++ b/tests/cases/compiler/jsdocTypecastNoTypeNoCrash.ts @@ -0,0 +1,5 @@ +// @allowJS: true +// @outDir: ./out +// @filename: index.js +function Foo() {} +const a = /* @type string */(Foo); From 697c4d33530646440dd8c22d75523761da23549b Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 6 Sep 2017 14:46:47 -0700 Subject: [PATCH 23/74] Add `debugName` property to `Rule` (#18289) --- src/services/formatting/rule.ts | 14 +++++--------- src/services/formatting/rules.ts | 22 ++++++++++------------ src/services/formatting/rulesProvider.ts | 10 +--------- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts index 543295f364f..10987c745c2 100644 --- a/src/services/formatting/rule.ts +++ b/src/services/formatting/rule.ts @@ -3,16 +3,12 @@ /* @internal */ namespace ts.formatting { export class Rule { + // Used for debugging to identify each rule based on the property name it's assigned to. + public debugName?: string; constructor( - public Descriptor: RuleDescriptor, - public Operation: RuleOperation, - public Flag: RuleFlags = RuleFlags.None) { - } - - public toString() { - return "[desc=" + this.Descriptor + "," + - "operation=" + this.Operation + "," + - "flag=" + this.Flag + "]"; + readonly Descriptor: RuleDescriptor, + readonly Operation: RuleOperation, + readonly Flag: RuleFlags = RuleFlags.None) { } } } \ No newline at end of file diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 2daf8d9d284..07c2804ee83 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -3,18 +3,6 @@ /* @internal */ namespace ts.formatting { export class Rules { - public getRuleName(rule: Rule) { - const o: ts.MapLike = this; - for (const name in o) { - if (o[name] === rule) { - return name; - } - } - throw new Error("Unknown rule"); - } - - [name: string]: any; - public IgnoreBeforeComment: Rule; public IgnoreAfterLineComment: Rule; @@ -569,6 +557,16 @@ namespace ts.formatting { this.SpaceAfterSemicolon, this.SpaceBetweenStatements, this.SpaceAfterTryFinally ]; + + if (Debug.isDebugging) { + const o: ts.MapLike = this; + for (const name in o) { + const rule = o[name]; + if (rule instanceof Rule) { + rule.debugName = name; + } + } + } } /// diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 790bce054b0..1dd7acbdc64 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -9,18 +9,10 @@ namespace ts.formatting { constructor() { this.globalRules = new Rules(); - const activeRules = this.globalRules.HighPriorityCommonRules.slice(0).concat(this.globalRules.UserConfigurableRules).concat(this.globalRules.LowPriorityCommonRules); + const activeRules = this.globalRules.HighPriorityCommonRules.concat(this.globalRules.UserConfigurableRules).concat(this.globalRules.LowPriorityCommonRules); this.rulesMap = RulesMap.create(activeRules); } - public getRuleName(rule: Rule): string { - return this.globalRules.getRuleName(rule); - } - - public getRuleByName(name: string): Rule { - return this.globalRules[name]; - } - public getRulesMap() { return this.rulesMap; } From 0b1bad8421c2a252e89731d056649fe7673414e3 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 6 Sep 2017 15:44:00 -0700 Subject: [PATCH 24/74] Fix lint issues --- src/server/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index 7f6daa92d5e..96368fb9e54 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -437,7 +437,7 @@ namespace ts.server { while (this.requestQueue.length > 0) { const queuedRequest = this.requestQueue.shift(); - if (this.requestMap.get(queuedRequest.operationId) == queuedRequest) { + if (this.requestMap.get(queuedRequest.operationId) === queuedRequest) { this.requestMap.delete(queuedRequest.operationId); this.scheduleRequest(queuedRequest); break; @@ -455,7 +455,7 @@ namespace ts.server { } private scheduleRequest(request: QueuedOperation) { - if(this.logger.hasLevel(LogLevel.verbose)) { + if (this.logger.hasLevel(LogLevel.verbose)) { this.logger.info(`Scheduling request for: ${request.operationId}`); } this.activeRequestCount++; From 9692ce86db3fb81c31c64c7716b9afe2c6cd4128 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 6 Sep 2017 15:46:59 -0700 Subject: [PATCH 25/74] Add explanatory comment --- src/server/server.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/server/server.ts b/src/server/server.ts index 96368fb9e54..6b6535c8cac 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -251,6 +251,11 @@ namespace ts.server { private requestQueue: QueuedOperation[] = []; private requestMap = createMap(); // Maps operation ID to newest requestQueue entry with that ID + // This number is essentially arbitrary. Processing more than one typings request + // at a time makes sense, but having too many in the pipe results in a hang + // (see https://github.com/nodejs/node/issues/7657). + // It would be preferable to base our limit on the amount of space left in the + // buffer, but we have yet to find a way to retrieve that value. private static readonly maxActiveRequestCount = 10; private static readonly requestDelayMillis = 100; From a5c2eac2ee533fa3e71a6be3e5d320107e2614e8 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 6 Sep 2017 15:54:14 -0700 Subject: [PATCH 26/74] Test:disable lookahead in isStartOfParameter --- src/compiler/parser.ts | 6 ------ ...arrowfunctionsOptionalArgsErrors2.errors.txt | 17 +++++++++++++---- .../fatarrowfunctionsOptionalArgsErrors2.js | 6 ++---- .../baselines/reference/parser512325.errors.txt | 17 +++++++++++++---- tests/baselines/reference/parser512325.js | 6 ++---- .../parserArrowFunctionExpression5.errors.txt | 15 +++++++++++++++ .../reference/parserArrowFunctionExpression5.js | 10 ++++++++++ .../parserArrowFunctionExpression5.ts | 5 +++++ 8 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 tests/baselines/reference/parserArrowFunctionExpression5.errors.txt create mode 100644 tests/baselines/reference/parserArrowFunctionExpression5.js create mode 100644 tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e4847517252..1740bad2d34 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2238,12 +2238,6 @@ namespace ts { isIdentifierOrPattern() || isModifierKind(token()) || token() === SyntaxKind.AtToken || - // a jsdoc parameter can start directly with a type, but shouldn't look ahead - // in order to avoid confusion between parenthesized types and arrow functions - // eg - // declare function f(cb: function(number): void): void; - // vs - // f((n) => console.log(n)); isStartOfType(/*disableLookahead*/ true); } diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.errors.txt b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.errors.txt index 51db9c7391e..b435e7773f5 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.errors.txt +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.errors.txt @@ -1,7 +1,10 @@ -tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,15): error TS1003: Identifier expected. +tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,12): error TS2304: Cannot find name 'a'. +tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,12): error TS2695: Left side of comma operator is unused and has no side effects. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,16): error TS2304: Cannot find name 'b'. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,16): error TS2695: Left side of comma operator is unused and has no side effects. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,19): error TS2304: Cannot find name 'c'. +tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,23): error TS1005: ';' expected. +tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,26): error TS2304: Cannot find name 'a'. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,28): error TS2304: Cannot find name 'b'. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(1,30): error TS2304: Cannot find name 'c'. tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(2,12): error TS2695: Left side of comma operator is unused and has no side effects. @@ -18,16 +21,22 @@ tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(4,17): error TS1005 tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts(4,20): error TS2304: Cannot find name 'a'. -==== tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts (18 errors) ==== +==== tests/cases/compiler/fatarrowfunctionsOptionalArgsErrors2.ts (21 errors) ==== var tt1 = (a, (b, c)) => a+b+c; - ~ -!!! error TS1003: Identifier expected. + ~ +!!! error TS2304: Cannot find name 'a'. + ~ +!!! error TS2695: Left side of comma operator is unused and has no side effects. ~ !!! error TS2304: Cannot find name 'b'. ~ !!! error TS2695: Left side of comma operator is unused and has no side effects. ~ !!! error TS2304: Cannot find name 'c'. + ~~ +!!! error TS1005: ';' expected. + ~ +!!! error TS2304: Cannot find name 'a'. ~ !!! error TS2304: Cannot find name 'b'. ~ diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.js b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.js index a1c68ea4476..b51003b62df 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.js +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors2.js @@ -5,10 +5,8 @@ var tt2 = ((a), b, c) => a+b+c; var tt3 = ((a)) => a; //// [fatarrowfunctionsOptionalArgsErrors2.js] -var tt1 = function (a, ) { - if ( === void 0) { = (b, c); } - return a + b + c; -}; +var tt1 = (a, (b, c)); +a + b + c; var tt2 = ((a), b, c); a + b + c; var tt3 = ((a)); diff --git a/tests/baselines/reference/parser512325.errors.txt b/tests/baselines/reference/parser512325.errors.txt index f54d9f2110a..e6a47fbf226 100644 --- a/tests/baselines/reference/parser512325.errors.txt +++ b/tests/baselines/reference/parser512325.errors.txt @@ -1,21 +1,30 @@ -tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,14): error TS1003: Identifier expected. +tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,11): error TS2304: Cannot find name 'a'. +tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,11): error TS2695: Left side of comma operator is unused and has no side effects. tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,15): error TS2304: Cannot find name 'b'. tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,15): error TS2695: Left side of comma operator is unused and has no side effects. tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,18): error TS2304: Cannot find name 'c'. +tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,22): error TS1005: ';' expected. +tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,25): error TS2304: Cannot find name 'a'. tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,27): error TS2304: Cannot find name 'b'. tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts(1,29): error TS2304: Cannot find name 'c'. -==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts (6 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser512325.ts (9 errors) ==== var tt = (a, (b, c)) => a+b+c; - ~ -!!! error TS1003: Identifier expected. + ~ +!!! error TS2304: Cannot find name 'a'. + ~ +!!! error TS2695: Left side of comma operator is unused and has no side effects. ~ !!! error TS2304: Cannot find name 'b'. ~ !!! error TS2695: Left side of comma operator is unused and has no side effects. ~ !!! error TS2304: Cannot find name 'c'. + ~~ +!!! error TS1005: ';' expected. + ~ +!!! error TS2304: Cannot find name 'a'. ~ !!! error TS2304: Cannot find name 'b'. ~ diff --git a/tests/baselines/reference/parser512325.js b/tests/baselines/reference/parser512325.js index 75af6b9f39a..14cbcddd86b 100644 --- a/tests/baselines/reference/parser512325.js +++ b/tests/baselines/reference/parser512325.js @@ -2,7 +2,5 @@ var tt = (a, (b, c)) => a+b+c; //// [parser512325.js] -var tt = function (a, ) { - if ( === void 0) { = (b, c); } - return a + b + c; -}; +var tt = (a, (b, c)); +a + b + c; diff --git a/tests/baselines/reference/parserArrowFunctionExpression5.errors.txt b/tests/baselines/reference/parserArrowFunctionExpression5.errors.txt new file mode 100644 index 00000000000..220c4d42279 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression5.errors.txt @@ -0,0 +1,15 @@ +tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts(1,2): error TS2304: Cannot find name 'bar'. +tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts(1,6): error TS2304: Cannot find name 'x'. + + +==== tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts (2 errors) ==== + (bar(x, + ~~~ +!!! error TS2304: Cannot find name 'bar'. + ~ +!!! error TS2304: Cannot find name 'x'. + () => {}, + () => {} + ) + ) + \ No newline at end of file diff --git a/tests/baselines/reference/parserArrowFunctionExpression5.js b/tests/baselines/reference/parserArrowFunctionExpression5.js new file mode 100644 index 00000000000..b25d77a4b02 --- /dev/null +++ b/tests/baselines/reference/parserArrowFunctionExpression5.js @@ -0,0 +1,10 @@ +//// [parserArrowFunctionExpression5.ts] +(bar(x, + () => {}, + () => {} + ) +) + + +//// [parserArrowFunctionExpression5.js] +(bar(x, function () { }, function () { })); diff --git a/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts new file mode 100644 index 00000000000..d4ab2adefba --- /dev/null +++ b/tests/cases/conformance/parser/ecmascript5/ArrowFunctionExpressions/parserArrowFunctionExpression5.ts @@ -0,0 +1,5 @@ +(bar(x, + () => {}, + () => {} + ) +) From 5c779b1edbc17d03491fee4e73b9c4d9a45cd2eb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 21:56:16 -0700 Subject: [PATCH 27/74] Allow singleline string writer to be recursively used (#18297) * Allow singleline string writer to be recursively used * Add unit test exposing issue * Fix lints --- Jakefile.js | 1 + src/compiler/utilities.ts | 6 +-- src/harness/tsconfig.json | 1 + src/harness/unittests/languageService.ts | 49 ++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 src/harness/unittests/languageService.ts diff --git a/Jakefile.js b/Jakefile.js index b3e18e8cb1a..ad853238111 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -143,6 +143,7 @@ var harnessSources = harnessCoreSources.concat([ "customTransforms.ts", "programMissingFiles.ts", "symbolWalker.ts", + "languageService.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2a07d2b6560..725070c02bf 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -32,7 +32,6 @@ namespace ts { } const stringWriter = createSingleLineStringWriter(); - let stringWriterAcquired = false; function createSingleLineStringWriter(): StringSymbolWriter { let str = ""; @@ -62,15 +61,14 @@ namespace ts { } export function usingSingleLineStringWriter(action: (writer: StringSymbolWriter) => void): string { + const oldString = stringWriter.string(); try { - Debug.assert(!stringWriterAcquired); - stringWriterAcquired = true; action(stringWriter); return stringWriter.string(); } finally { stringWriter.clear(); - stringWriterAcquired = false; + stringWriter.writeKeyword(oldString); } } diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 1469079bcaa..bd7c9bc2ffa 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -128,6 +128,7 @@ "./unittests/extractMethods.ts", "./unittests/textChanges.ts", "./unittests/telemetry.ts", + "./unittests/languageService.ts", "./unittests/programMissingFiles.ts" ] } diff --git a/src/harness/unittests/languageService.ts b/src/harness/unittests/languageService.ts new file mode 100644 index 00000000000..9c838845c20 --- /dev/null +++ b/src/harness/unittests/languageService.ts @@ -0,0 +1,49 @@ +/// + +namespace ts { + describe("languageService", () => { + const files: {[index: string]: string} = { + "foo.ts": `import Vue from "./vue"; +import Component from "./vue-class-component"; +import { vueTemplateHtml } from "./variables"; + +@Component({ + template: vueTemplateHtml, +}) +class Carousel extends Vue { +}`, + "variables.ts": `export const vueTemplateHtml = \`
\`;`, + "vue.d.ts": `export namespace Vue { export type Config = { template: string }; }`, + "vue-class-component.d.ts": `import Vue from "./vue"; +export function Component(x: Config): any;` +}; + it("should be able to create a language service which can respond to deinition requests without throwing", () => { + const languageService = ts.createLanguageService({ + getCompilationSettings() { + return {}; + }, + getScriptFileNames() { + return ["foo.ts", "variables.ts", "vue.d.ts", "vue-class-component.d.ts"]; + }, + getScriptVersion(_fileName) { + return ""; + }, + getScriptSnapshot(fileName) { + if (fileName === ".ts") { + return ts.ScriptSnapshot.fromString(""); + } + return ts.ScriptSnapshot.fromString(files[fileName] || ""); + }, + getCurrentDirectory: () => ".", + getDefaultLibFileName(options) { + return ts.getDefaultLibFilePath(options); + }, + fileExists: noop as any, + readFile: noop as any, + readDirectory: noop as any, + }); + const definitions = languageService.getDefinitionAtPosition("foo.ts", 160); // 160 is the latter `vueTemplateHtml` position + expect(definitions).to.exist; + }); + }); +} \ No newline at end of file From ed61d2d803a99e8891fa306face099a6a4290b29 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 21:58:04 -0700 Subject: [PATCH 28/74] Emit updated export declarations when transformed from export * (#18017) * Failing test for missing transform output * dont elide all export stars * Remove comment from test * Refuse to perform ellision on transformed nodes --- src/compiler/transformers/ts.ts | 20 +++++++- src/harness/unittests/transform.ts | 49 +++++++++++++++---- ...sformsCorrectly.transformAwayExportStar.js | 1 + 3 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 tests/baselines/reference/transformApi/transformsCorrectly.transformAwayExportStar.js diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 692c758bc75..42c25ca34a5 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -208,6 +208,24 @@ namespace ts { * @param node The node to visit. */ function sourceElementVisitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ExportDeclaration: + return visitEllidableStatement(node); + default: + return visitorWorker(node); + } + } + + function visitEllidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult { + const parsed = getParseTreeNode(node); + if (parsed !== node) { + // If the node has been transformed by a `before` transformer, perform no ellision on it + // As the type information we would attempt to lookup to perform ellision is potentially unavailable for the synthesized nodes + return node; + } switch (node.kind) { case SyntaxKind.ImportDeclaration: return visitImportDeclaration(node); @@ -218,7 +236,7 @@ namespace ts { case SyntaxKind.ExportDeclaration: return visitExportDeclaration(node); default: - return visitorWorker(node); + Debug.fail("Unhandled ellided statement"); } } diff --git a/src/harness/unittests/transform.ts b/src/harness/unittests/transform.ts index 27e41a96dfc..bcdca3e3b60 100644 --- a/src/harness/unittests/transform.ts +++ b/src/harness/unittests/transform.ts @@ -57,7 +57,7 @@ namespace ts { testBaseline("types", () => { return transformSourceFile(`let a: () => void`, [ - context => file => visitNode(file, function visitor(node: Node): VisitResult { + context => file => visitNode(file, function visitor(node: Node): VisitResult { return visitEachChild(node, visitor, context); }) ]); @@ -91,14 +91,14 @@ namespace ts { class C { foo = 10; static bar = 20 } namespace C { export let x = 10; } `, { - transformers: { - before: [forceNamespaceRewrite], - }, - compilerOptions: { - target: ts.ScriptTarget.ESNext, - newLine: NewLineKind.CarriageReturnLineFeed, - } - }).outputText; + transformers: { + before: [forceNamespaceRewrite], + }, + compilerOptions: { + target: ts.ScriptTarget.ESNext, + newLine: NewLineKind.CarriageReturnLineFeed, + } + }).outputText; }); testBaseline("synthesizedClassAndNamespaceCombination", () => { @@ -138,6 +138,37 @@ namespace ts { } }; } + + testBaseline("transformAwayExportStar", () => { + return ts.transpileModule("export * from './helper';", { + transformers: { + before: [expandExportStar], + }, + compilerOptions: { + target: ts.ScriptTarget.ESNext, + newLine: NewLineKind.CarriageReturnLineFeed, + } + }).outputText; + + function expandExportStar(context: ts.TransformationContext) { + return (sourceFile: ts.SourceFile): ts.SourceFile => { + return visitNode(sourceFile); + + function visitNode(node: T): T { + if (node.kind === ts.SyntaxKind.ExportDeclaration) { + const ed = node as ts.Node as ts.ExportDeclaration; + const exports = [{ name: "x" }]; + const exportSpecifiers = exports.map(e => ts.createExportSpecifier(e.name, e.name)); + const exportClause = ts.createNamedExports(exportSpecifiers); + const newEd = ts.updateExportDeclaration(ed, ed.decorators, ed.modifiers, exportClause, ed.moduleSpecifier); + + return newEd as ts.Node as T; + } + return ts.visitEachChild(node, visitNode, context); + } + }; + } + }); }); } diff --git a/tests/baselines/reference/transformApi/transformsCorrectly.transformAwayExportStar.js b/tests/baselines/reference/transformApi/transformsCorrectly.transformAwayExportStar.js new file mode 100644 index 00000000000..7a05a90c1f8 --- /dev/null +++ b/tests/baselines/reference/transformApi/transformsCorrectly.transformAwayExportStar.js @@ -0,0 +1 @@ +export { x as x } from './helper'; From 72884b8f27abb8bfe8d8ec0f4368d09f1a4c80bf Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 21:59:06 -0700 Subject: [PATCH 29/74] Emit comments on system export default expressions on the surrounding export call epxression instead (#17970) --- src/compiler/emitter.ts | 2 +- src/compiler/transformers/module/system.ts | 3 ++- .../systemDefaultExportCommentValidity.js | 20 +++++++++++++++++++ ...systemDefaultExportCommentValidity.symbols | 8 ++++++++ .../systemDefaultExportCommentValidity.types | 9 +++++++++ .../systemDefaultExportCommentValidity.ts | 5 +++++ 6 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/systemDefaultExportCommentValidity.js create mode 100644 tests/baselines/reference/systemDefaultExportCommentValidity.symbols create mode 100644 tests/baselines/reference/systemDefaultExportCommentValidity.types create mode 100644 tests/cases/compiler/systemDefaultExportCommentValidity.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5444c618353..166e4751983 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2519,7 +2519,7 @@ namespace ts { // 2 // /* end of element 2 */ // ]; - if (previousSibling && delimiter && previousSibling.end !== parentNode.end) { + if (previousSibling && delimiter && previousSibling.end !== parentNode.end && !(getEmitFlags(previousSibling) & EmitFlags.NoTrailingComments)) { emitLeadingCommentsOfPosition(previousSibling.end); } diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index e1c239736d5..8c47ec82f70 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -1132,7 +1132,8 @@ namespace ts { */ function createExportExpression(name: Identifier | StringLiteral, value: Expression) { const exportName = isIdentifier(name) ? createLiteral(name) : name; - return createCall(exportFunction, /*typeArguments*/ undefined, [exportName, value]); + setEmitFlags(value, getEmitFlags(value) | EmitFlags.NoComments); + return setCommentRange(createCall(exportFunction, /*typeArguments*/ undefined, [exportName, value]), value); } // diff --git a/tests/baselines/reference/systemDefaultExportCommentValidity.js b/tests/baselines/reference/systemDefaultExportCommentValidity.js new file mode 100644 index 00000000000..a56110b0de9 --- /dev/null +++ b/tests/baselines/reference/systemDefaultExportCommentValidity.js @@ -0,0 +1,20 @@ +//// [systemDefaultExportCommentValidity.ts] +const Home = {} + +export default Home +// There is intentionally no semicolon on the prior line, this comment should not break emit + +//// [systemDefaultExportCommentValidity.js] +System.register([], function (exports_1, context_1) { + "use strict"; + var __moduleName = context_1 && context_1.id; + var Home; + return { + setters: [], + execute: function () { + Home = {}; + exports_1("default", Home); + // There is intentionally no semicolon on the prior line, this comment should not break emit + } + }; +}); diff --git a/tests/baselines/reference/systemDefaultExportCommentValidity.symbols b/tests/baselines/reference/systemDefaultExportCommentValidity.symbols new file mode 100644 index 00000000000..39abe3a6685 --- /dev/null +++ b/tests/baselines/reference/systemDefaultExportCommentValidity.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/systemDefaultExportCommentValidity.ts === +const Home = {} +>Home : Symbol(Home, Decl(systemDefaultExportCommentValidity.ts, 0, 5)) + +export default Home +>Home : Symbol(Home, Decl(systemDefaultExportCommentValidity.ts, 0, 5)) + +// There is intentionally no semicolon on the prior line, this comment should not break emit diff --git a/tests/baselines/reference/systemDefaultExportCommentValidity.types b/tests/baselines/reference/systemDefaultExportCommentValidity.types new file mode 100644 index 00000000000..d8b89394ed6 --- /dev/null +++ b/tests/baselines/reference/systemDefaultExportCommentValidity.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/systemDefaultExportCommentValidity.ts === +const Home = {} +>Home : {} +>{} : {} + +export default Home +>Home : {} + +// There is intentionally no semicolon on the prior line, this comment should not break emit diff --git a/tests/cases/compiler/systemDefaultExportCommentValidity.ts b/tests/cases/compiler/systemDefaultExportCommentValidity.ts new file mode 100644 index 00000000000..df1d0283978 --- /dev/null +++ b/tests/cases/compiler/systemDefaultExportCommentValidity.ts @@ -0,0 +1,5 @@ +// @module: system +const Home = {} + +export default Home +// There is intentionally no semicolon on the prior line, this comment should not break emit \ No newline at end of file From c3e090695ec59cd79536ea892f4351fbb3674489 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 22:07:30 -0700 Subject: [PATCH 30/74] Do not consider UMD alias symbols as visible within external modules (#18049) * Do not consider UMD alias symbols as visible within external modules in the symbol writer * Minimal repro --- src/compiler/checker.ts | 5 ++++ .../reference/exportAsNamespace.d.types | 2 +- ...mportShouldNotBeElidedInDeclarationEmit.js | 26 +++++++++++++++++++ ...ShouldNotBeElidedInDeclarationEmit.symbols | 23 ++++++++++++++++ ...rtShouldNotBeElidedInDeclarationEmit.types | 24 +++++++++++++++++ .../reference/umd-augmentation-1.types | 2 +- .../reference/umd-augmentation-2.types | 2 +- .../reference/umd-augmentation-3.symbols | 2 +- .../reference/umd-augmentation-3.types | 4 +-- .../reference/umd-augmentation-4.symbols | 2 +- .../reference/umd-augmentation-4.types | 4 +-- tests/baselines/reference/umd1.types | 2 +- tests/baselines/reference/umd3.types | 2 +- tests/baselines/reference/umd4.types | 2 +- .../reference/umdGlobalConflict.types | 2 +- ...mportShouldNotBeElidedInDeclarationEmit.ts | 12 +++++++++ 16 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js create mode 100644 tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.symbols create mode 100644 tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.types create mode 100644 tests/cases/compiler/importShouldNotBeElidedInDeclarationEmit.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9fcd0b593f8..e7e66ed5f2d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2095,6 +2095,10 @@ namespace ts { canQualifySymbol(symbolFromSymbolTable, meaning); } + function isUMDExportSymbol(symbol: Symbol) { + return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]); + } + function trySymbolTable(symbols: SymbolTable) { // If symbol is directly available by its name in the symbol table if (isAccessible(symbols.get(symbol.escapedName))) { @@ -2106,6 +2110,7 @@ namespace ts { if (symbolFromSymbolTable.flags & SymbolFlags.Alias && symbolFromSymbolTable.escapedName !== "export=" && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier) + && !(isUMDExportSymbol(symbolFromSymbolTable) && isExternalModule(getSourceFileOfNode(enclosingDeclaration))) // If `!useOnlyExternalAliasing`, we can use any type of alias to get the name && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))) { diff --git a/tests/baselines/reference/exportAsNamespace.d.types b/tests/baselines/reference/exportAsNamespace.d.types index 706857bf8ed..4952cb8863b 100644 --- a/tests/baselines/reference/exportAsNamespace.d.types +++ b/tests/baselines/reference/exportAsNamespace.d.types @@ -5,5 +5,5 @@ export var X; >X : any export as namespace N ->N : typeof N +>N : typeof "tests/cases/compiler/exportAsNamespace" diff --git a/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js new file mode 100644 index 00000000000..a1316dbdd46 --- /dev/null +++ b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/importShouldNotBeElidedInDeclarationEmit.ts] //// + +//// [umd.d.ts] +export as namespace UMD; + +export type Thing = { + a: number; +} + +export declare function makeThing(): Thing; +//// [index.ts] +import { makeThing } from "umd"; +export const thing = makeThing(); + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var umd_1 = require("umd"); +exports.thing = umd_1.makeThing(); + + +//// [index.d.ts] +export declare const thing: { + a: number; +}; diff --git a/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.symbols b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.symbols new file mode 100644 index 00000000000..4ac0f4928b0 --- /dev/null +++ b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.symbols @@ -0,0 +1,23 @@ +=== tests/cases/compiler/node_modules/umd.d.ts === +export as namespace UMD; +>UMD : Symbol(UMD, Decl(umd.d.ts, 0, 0)) + +export type Thing = { +>Thing : Symbol(Thing, Decl(umd.d.ts, 0, 24)) + + a: number; +>a : Symbol(a, Decl(umd.d.ts, 2, 21)) +} + +export declare function makeThing(): Thing; +>makeThing : Symbol(makeThing, Decl(umd.d.ts, 4, 1)) +>Thing : Symbol(Thing, Decl(umd.d.ts, 0, 24)) + +=== tests/cases/compiler/index.ts === +import { makeThing } from "umd"; +>makeThing : Symbol(makeThing, Decl(index.ts, 0, 8)) + +export const thing = makeThing(); +>thing : Symbol(thing, Decl(index.ts, 1, 12)) +>makeThing : Symbol(makeThing, Decl(index.ts, 0, 8)) + diff --git a/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.types b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.types new file mode 100644 index 00000000000..2531654f80b --- /dev/null +++ b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/node_modules/umd.d.ts === +export as namespace UMD; +>UMD : typeof "tests/cases/compiler/node_modules/umd" + +export type Thing = { +>Thing : Thing + + a: number; +>a : number +} + +export declare function makeThing(): Thing; +>makeThing : () => Thing +>Thing : Thing + +=== tests/cases/compiler/index.ts === +import { makeThing } from "umd"; +>makeThing : () => { a: number; } + +export const thing = makeThing(); +>thing : { a: number; } +>makeThing() : { a: number; } +>makeThing : () => { a: number; } + diff --git a/tests/baselines/reference/umd-augmentation-1.types b/tests/baselines/reference/umd-augmentation-1.types index 5324e58f68e..9d89e0c4537 100644 --- a/tests/baselines/reference/umd-augmentation-1.types +++ b/tests/baselines/reference/umd-augmentation-1.types @@ -47,7 +47,7 @@ var t = p.x; === tests/cases/conformance/externalModules/node_modules/math2d/index.d.ts === export as namespace Math2d; ->Math2d : typeof Math2d +>Math2d : typeof "tests/cases/conformance/externalModules/node_modules/math2d/index" export interface Point { >Point : Point diff --git a/tests/baselines/reference/umd-augmentation-2.types b/tests/baselines/reference/umd-augmentation-2.types index 4ead8d611ca..b8d04ecd643 100644 --- a/tests/baselines/reference/umd-augmentation-2.types +++ b/tests/baselines/reference/umd-augmentation-2.types @@ -45,7 +45,7 @@ var t = p.x; === tests/cases/conformance/externalModules/node_modules/math2d/index.d.ts === export as namespace Math2d; ->Math2d : typeof Math2d +>Math2d : typeof "tests/cases/conformance/externalModules/node_modules/math2d/index" export interface Point { >Point : Point diff --git a/tests/baselines/reference/umd-augmentation-3.symbols b/tests/baselines/reference/umd-augmentation-3.symbols index acb2f471faf..7cbe3ac803b 100644 --- a/tests/baselines/reference/umd-augmentation-3.symbols +++ b/tests/baselines/reference/umd-augmentation-3.symbols @@ -44,7 +44,7 @@ export = M2D; >M2D : Symbol(M2D, Decl(index.d.ts, 2, 13)) declare namespace M2D { ->M2D : Symbol(Math2d, Decl(index.d.ts, 2, 13), Decl(math2d-augment.d.ts, 0, 33)) +>M2D : Symbol(M2D, Decl(index.d.ts, 2, 13), Decl(math2d-augment.d.ts, 0, 33)) interface Point { >Point : Symbol(Point, Decl(index.d.ts, 4, 23)) diff --git a/tests/baselines/reference/umd-augmentation-3.types b/tests/baselines/reference/umd-augmentation-3.types index 4802d159e18..5efafd780a0 100644 --- a/tests/baselines/reference/umd-augmentation-3.types +++ b/tests/baselines/reference/umd-augmentation-3.types @@ -47,13 +47,13 @@ var t = p.x; === tests/cases/conformance/externalModules/node_modules/math2d/index.d.ts === export as namespace Math2d; ->Math2d : typeof Math2d +>Math2d : typeof M2D export = M2D; >M2D : typeof M2D declare namespace M2D { ->M2D : typeof Math2d +>M2D : typeof M2D interface Point { >Point : Point diff --git a/tests/baselines/reference/umd-augmentation-4.symbols b/tests/baselines/reference/umd-augmentation-4.symbols index 12696ab51f7..eabb2e15898 100644 --- a/tests/baselines/reference/umd-augmentation-4.symbols +++ b/tests/baselines/reference/umd-augmentation-4.symbols @@ -42,7 +42,7 @@ export = M2D; >M2D : Symbol(M2D, Decl(index.d.ts, 2, 13)) declare namespace M2D { ->M2D : Symbol(Math2d, Decl(index.d.ts, 2, 13), Decl(math2d-augment.d.ts, 0, 33)) +>M2D : Symbol(M2D, Decl(index.d.ts, 2, 13), Decl(math2d-augment.d.ts, 0, 33)) interface Point { >Point : Symbol(Point, Decl(index.d.ts, 4, 23)) diff --git a/tests/baselines/reference/umd-augmentation-4.types b/tests/baselines/reference/umd-augmentation-4.types index 324de384183..f71928f5afc 100644 --- a/tests/baselines/reference/umd-augmentation-4.types +++ b/tests/baselines/reference/umd-augmentation-4.types @@ -45,13 +45,13 @@ var t = p.x; === tests/cases/conformance/externalModules/node_modules/math2d/index.d.ts === export as namespace Math2d; ->Math2d : typeof Math2d +>Math2d : typeof M2D export = M2D; >M2D : typeof M2D declare namespace M2D { ->M2D : typeof Math2d +>M2D : typeof M2D interface Point { >Point : Point diff --git a/tests/baselines/reference/umd1.types b/tests/baselines/reference/umd1.types index 9ccc0d2cd8e..b84aaf3ad70 100644 --- a/tests/baselines/reference/umd1.types +++ b/tests/baselines/reference/umd1.types @@ -30,5 +30,5 @@ export interface Thing { n: typeof x } >x : number export as namespace Foo; ->Foo : typeof Foo +>Foo : typeof "tests/cases/conformance/externalModules/foo" diff --git a/tests/baselines/reference/umd3.types b/tests/baselines/reference/umd3.types index ab7978545ba..ef54806a174 100644 --- a/tests/baselines/reference/umd3.types +++ b/tests/baselines/reference/umd3.types @@ -32,5 +32,5 @@ export interface Thing { n: typeof x } >x : number export as namespace Foo; ->Foo : typeof Foo +>Foo : typeof "tests/cases/conformance/externalModules/foo" diff --git a/tests/baselines/reference/umd4.types b/tests/baselines/reference/umd4.types index c9144af7a18..3b6ebfa6ca7 100644 --- a/tests/baselines/reference/umd4.types +++ b/tests/baselines/reference/umd4.types @@ -32,5 +32,5 @@ export interface Thing { n: typeof x } >x : number export as namespace Foo; ->Foo : typeof Foo +>Foo : typeof "tests/cases/conformance/externalModules/foo" diff --git a/tests/baselines/reference/umdGlobalConflict.types b/tests/baselines/reference/umdGlobalConflict.types index d23d42e702a..0bb26b47918 100644 --- a/tests/baselines/reference/umdGlobalConflict.types +++ b/tests/baselines/reference/umdGlobalConflict.types @@ -1,6 +1,6 @@ === tests/cases/compiler/v1/index.d.ts === export as namespace Alpha; ->Alpha : typeof Alpha +>Alpha : typeof "tests/cases/compiler/v1/index" export var x: string; >x : string diff --git a/tests/cases/compiler/importShouldNotBeElidedInDeclarationEmit.ts b/tests/cases/compiler/importShouldNotBeElidedInDeclarationEmit.ts new file mode 100644 index 00000000000..a6d77a51567 --- /dev/null +++ b/tests/cases/compiler/importShouldNotBeElidedInDeclarationEmit.ts @@ -0,0 +1,12 @@ +// @declaration: true +// @filename: node_modules/umd.d.ts +export as namespace UMD; + +export type Thing = { + a: number; +} + +export declare function makeThing(): Thing; +// @filename: index.ts +import { makeThing } from "umd"; +export const thing = makeThing(); From 72cbc12c9a5cb49ff331f3a3828a83c4ae4c5991 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 6 Sep 2017 22:08:42 -0700 Subject: [PATCH 31/74] Allow undefined/null to override all parameters (#18058) --- src/compiler/commandLineParser.ts | 32 ++++++++++------ src/compiler/types.ts | 2 +- .../unittests/configurationExtension.ts | 37 ++++++++++++++++++- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index c92d147f9a9..dc9c2ad35ed 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1057,7 +1057,7 @@ namespace ts { errors.push(createDiagnosticForNodeInSourceFile(sourceFile, element.name, extraKeyDiagnosticMessage, keyText)); } const value = convertPropertyValueToJson(element.initializer, option); - if (typeof keyText !== "undefined" && typeof value !== "undefined") { + if (typeof keyText !== "undefined") { result[keyText] = value; // Notify key value set, if user asked for it if (jsonConversionNotifier && @@ -1104,7 +1104,7 @@ namespace ts { return false; case SyntaxKind.NullKeyword: - reportInvalidOptionValue(!!option); + reportInvalidOptionValue(option && option.name === "extends"); // "extends" is the only option we don't allow null/undefined for return null; // tslint:disable-line:no-null-keyword case SyntaxKind.StringLiteral: @@ -1189,6 +1189,7 @@ namespace ts { function isCompilerOptionsValue(option: CommandLineOption, value: any): value is CompilerOptionsValue { if (option) { + if (isNullOrUndefined(value)) return true; // All options are undefinable/nullable if (option.type === "list") { return isArray(value); } @@ -1379,6 +1380,11 @@ namespace ts { } } + function isNullOrUndefined(x: any): x is null | undefined { + // tslint:disable-next-line:no-null-keyword + return x === undefined || x === null; + } + /** * Parse the contents of a config file from json or json source file (tsconfig.json). * @param json The contents of the config file to parse @@ -1419,7 +1425,7 @@ namespace ts { function getFileNames(): ExpandResult { let fileNames: ReadonlyArray; - if (hasProperty(raw, "files")) { + if (hasProperty(raw, "files") && !isNullOrUndefined(raw["files"])) { if (isArray(raw["files"])) { fileNames = >raw["files"]; if (fileNames.length === 0) { @@ -1432,7 +1438,7 @@ namespace ts { } let includeSpecs: ReadonlyArray; - if (hasProperty(raw, "include")) { + if (hasProperty(raw, "include") && !isNullOrUndefined(raw["include"])) { if (isArray(raw["include"])) { includeSpecs = >raw["include"]; } @@ -1442,7 +1448,7 @@ namespace ts { } let excludeSpecs: ReadonlyArray; - if (hasProperty(raw, "exclude")) { + if (hasProperty(raw, "exclude") && !isNullOrUndefined(raw["exclude"])) { if (isArray(raw["exclude"])) { excludeSpecs = >raw["exclude"]; } @@ -1461,7 +1467,7 @@ namespace ts { includeSpecs = ["**/*"]; } - const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors, extraFileExtensions, sourceFile); + const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, configFileName ? getDirectoryPath(toPath(configFileName, basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames))) : basePath, options, host, errors, extraFileExtensions, sourceFile); if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0) { errors.push( @@ -1552,7 +1558,7 @@ namespace ts { host: ParseConfigHost, basePath: string, getCanonicalFileName: (fileName: string) => string, - configFileName: string, + configFileName: string | undefined, errors: Push ): ParsedTsconfig { if (hasProperty(json, "excludes")) { @@ -1571,7 +1577,8 @@ namespace ts { errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string")); } else { - extendedConfigPath = getExtendsConfigPath(json.extends, host, basePath, getCanonicalFileName, errors, createCompilerDiagnostic); + const newBase = configFileName ? getDirectoryPath(toPath(configFileName, basePath, getCanonicalFileName)) : basePath; + extendedConfigPath = getExtendsConfigPath(json.extends, host, newBase, getCanonicalFileName, errors, createCompilerDiagnostic); } } return { raw: json, options, typeAcquisition, extendedConfigPath }; @@ -1582,7 +1589,7 @@ namespace ts { host: ParseConfigHost, basePath: string, getCanonicalFileName: (fileName: string) => string, - configFileName: string, + configFileName: string | undefined, errors: Push ): ParsedTsconfig { const options = getDefaultCompilerOptions(configFileName); @@ -1603,10 +1610,11 @@ namespace ts { onSetValidOptionKeyValueInRoot(key: string, _keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression) { switch (key) { case "extends": + const newBase = configFileName ? getDirectoryPath(toPath(configFileName, basePath, getCanonicalFileName)) : basePath; extendedConfigPath = getExtendsConfigPath( value, host, - basePath, + newBase, getCanonicalFileName, errors, (message, arg0) => @@ -1803,6 +1811,7 @@ namespace ts { } function normalizeOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue { + if (isNullOrUndefined(value)) return undefined; if (option.type === "list") { const listOption = option; if (listOption.element.isFilePath || typeof listOption.element.type !== "string") { @@ -1827,6 +1836,7 @@ namespace ts { } function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Push) { + if (isNullOrUndefined(value)) return undefined; const key = value.toLowerCase(); const val = opt.type.get(key); if (val !== undefined) { @@ -1977,7 +1987,7 @@ namespace ts { // remove a literal file. if (fileNames) { for (const fileName of fileNames) { - const file = combinePaths(basePath, fileName); + const file = getNormalizedAbsolutePath(fileName, basePath); literalFileMap.set(keyMapper(file), file); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9d5bbf5b08e..b9d8d7a6319 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3583,7 +3583,7 @@ namespace ts { name: string; } - export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[]; + export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | null | undefined; export interface CompilerOptions { /*@internal*/ all?: boolean; diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts index 2d50d2cb2af..b46d98f1524 100644 --- a/src/harness/unittests/configurationExtension.ts +++ b/src/harness/unittests/configurationExtension.ts @@ -78,6 +78,23 @@ namespace ts { }, include: ["../supplemental.*"] }, + "/dev/configs/third.json": { + extends: "./second", + compilerOptions: { + // tslint:disable-next-line:no-null-keyword + module: null + }, + include: ["../supplemental.*"] + }, + "/dev/configs/fourth.json": { + extends: "./third", + compilerOptions: { + module: "system" + }, + // tslint:disable-next-line:no-null-keyword + include: null, + files: ["../main.ts"] + }, "/dev/extends.json": { extends: 42 }, "/dev/extends2.json": { extends: "configs/base" }, "/dev/main.ts": "", @@ -106,7 +123,7 @@ namespace ts { } } - describe("Configuration Extension", () => { + describe("configurationExtension", () => { forEach<[string, string, Utils.MockParseConfigHost], void>([ ["under a case insensitive host", caseInsensitiveBasePath, caseInsensitiveHost], ["under a case sensitive host", caseSensitiveBasePath, caseSensitiveHost] @@ -206,6 +223,24 @@ namespace ts { category: DiagnosticCategory.Error, messageText: `A path in an 'extends' option must be relative or rooted, but 'configs/base' is not.` }]); + + testSuccess("can overwrite compiler options using extended 'null'", "configs/third.json", { + allowJs: true, + noImplicitAny: true, + strictNullChecks: true, + module: undefined // Technically, this is distinct from the key never being set; but within the compiler we don't make the distinction + }, [ + combinePaths(basePath, "supplemental.ts") + ]); + + testSuccess("can overwrite top-level options using extended 'null'", "configs/fourth.json", { + allowJs: true, + noImplicitAny: true, + strictNullChecks: true, + module: ModuleKind.System + }, [ + combinePaths(basePath, "main.ts") + ]); }); }); }); From 53b5abe5bbb88edaaa6634999e7f1c6480262b63 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:19:00 -0700 Subject: [PATCH 32/74] Update `fromCodeFixContext` (#18290) --- .../correctQualifiedNameToIndexedAccessType.ts | 2 +- src/services/codefixes/fixAddMissingMember.ts | 10 +++++----- .../codefixes/fixClassSuperMustPrecedeThisAccess.ts | 2 +- .../codefixes/fixConstructorForDerivedNeedSuperCall.ts | 2 +- .../codefixes/fixExtendsInterfaceBecomesImplements.ts | 2 +- .../codefixes/fixForgottenThisPropertyAccess.ts | 2 +- src/services/codefixes/fixUnusedIdentifier.ts | 10 +++++----- src/services/codefixes/helpers.ts | 2 +- src/services/codefixes/importFixes.ts | 2 +- src/services/refactors/convertFunctionToEs6Class.ts | 2 +- src/services/refactors/extractMethod.ts | 2 +- src/services/textChanges.ts | 2 +- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts index 3087d73276d..e18190d6f6a 100644 --- a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -15,7 +15,7 @@ namespace ts.codefix { const replacement = createIndexedAccessTypeNode( createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined), createLiteralTypeNode(createLiteral(rightText))); - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); changeTracker.replaceNode(sourceFile, qualifiedName, replacement); return [{ diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 1587b47c01b..97e209fe89a 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -87,7 +87,7 @@ namespace ts.codefix { createPropertyAccess(createIdentifier(className), tokenName), createIdentifier("undefined"))); - const staticInitializationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const staticInitializationChangeTracker = textChanges.ChangeTracker.fromContext(context); staticInitializationChangeTracker.insertNodeAfter( classDeclarationSourceFile, classDeclaration, @@ -111,7 +111,7 @@ namespace ts.codefix { createPropertyAccess(createThis(), tokenName), createIdentifier("undefined"))); - const propertyInitializationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const propertyInitializationChangeTracker = textChanges.ChangeTracker.fromContext(context); propertyInitializationChangeTracker.insertNodeAt( classDeclarationSourceFile, classConstructor.body.getEnd() - 1, @@ -153,7 +153,7 @@ namespace ts.codefix { /*questionToken*/ undefined, typeNode, /*initializer*/ undefined); - const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const propertyChangeTracker = textChanges.ChangeTracker.fromContext(context); propertyChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, property, { suffix: context.newLineCharacter }); (actions || (actions = [])).push({ @@ -178,7 +178,7 @@ namespace ts.codefix { [indexingParameter], typeNode); - const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const indexSignatureChangeTracker = textChanges.ChangeTracker.fromContext(context); indexSignatureChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, indexSignature, { suffix: context.newLineCharacter }); actions.push({ @@ -195,7 +195,7 @@ namespace ts.codefix { const callExpression = token.parent.parent; const methodDeclaration = createMethodFromCallExpression(callExpression, tokenName, includeTypeScriptSyntax, makeStatic); - const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const methodDeclarationChangeTracker = textChanges.ChangeTracker.fromContext(context); methodDeclarationChangeTracker.insertNodeAfter(classDeclarationSourceFile, classOpenBrace, methodDeclaration, { suffix: context.newLineCharacter }); return { description: formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 937afee340e..bc92cd8e0d1 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -26,7 +26,7 @@ namespace ts.codefix { } } } - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); changeTracker.insertNodeAfter(sourceFile, getOpenBrace(constructor, sourceFile), superCall, { suffix: context.newLineCharacter }); changeTracker.deleteNode(sourceFile, superCall); diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 517a79e39bd..24f44a877b3 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -10,7 +10,7 @@ namespace ts.codefix { return undefined; } - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray)); changeTracker.insertNodeAfter(sourceFile, getOpenBrace(token.parent, sourceFile), superCall, { suffix: context.newLineCharacter }); diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts index d23f61d0f92..57bf2dd2795 100644 --- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts +++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts @@ -21,7 +21,7 @@ namespace ts.codefix { return undefined; } - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); changeTracker.replaceNode(sourceFile, extendsToken, createToken(SyntaxKind.ImplementsKeyword)); // We replace existing keywords with commas. diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index 6925b557755..5ac4f035f73 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -8,7 +8,7 @@ namespace ts.codefix { if (token.kind !== SyntaxKind.Identifier) { return undefined; } - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); changeTracker.replaceNode(sourceFile, token, createPropertyAccess(createThis(), token)); return [{ diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 18491aaba26..530a4543ec4 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -175,23 +175,23 @@ namespace ts.codefix { } function deleteNode(n: Node) { - return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNode(sourceFile, n)); + return makeChange(textChanges.ChangeTracker.fromContext(context).deleteNode(sourceFile, n)); } function deleteRange(range: TextRange) { - return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteRange(sourceFile, range)); + return makeChange(textChanges.ChangeTracker.fromContext(context).deleteRange(sourceFile, range)); } function deleteNodeInList(n: Node) { - return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNodeInList(sourceFile, n)); + return makeChange(textChanges.ChangeTracker.fromContext(context).deleteNodeInList(sourceFile, n)); } function deleteNodeRange(start: Node, end: Node) { - return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).deleteNodeRange(sourceFile, start, end)); + return makeChange(textChanges.ChangeTracker.fromContext(context).deleteNodeRange(sourceFile, start, end)); } function replaceNode(n: Node, newNode: Node) { - return makeChange(textChanges.ChangeTracker.fromCodeFixContext(context).replaceNode(sourceFile, n, newNode)); + return makeChange(textChanges.ChangeTracker.fromContext(context).replaceNode(sourceFile, n, newNode)); } function makeChange(changeTracker: textChanges.ChangeTracker): CodeAction { diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 7b69e12a19a..685c6832f13 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -4,7 +4,7 @@ namespace ts.codefix { export function newNodesToChanges(newNodes: Node[], insertAfter: Node, context: CodeFixContext) { const sourceFile = context.sourceFile; - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); for (const newNode of newNodes) { changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode, { suffix: context.newLineCharacter }); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index d0b52184031..99b677ebd3d 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -692,7 +692,7 @@ namespace ts.codefix { } function createChangeTracker() { - return textChanges.ChangeTracker.fromCodeFixContext(context); + return textChanges.ChangeTracker.fromContext(context); } function createCodeAction( diff --git a/src/services/refactors/convertFunctionToEs6Class.ts b/src/services/refactors/convertFunctionToEs6Class.ts index bf0e4e22658..40ef4ed2a2e 100644 --- a/src/services/refactors/convertFunctionToEs6Class.ts +++ b/src/services/refactors/convertFunctionToEs6Class.ts @@ -63,7 +63,7 @@ namespace ts.refactor.convertFunctionToES6Class { } const ctorDeclaration = ctorSymbol.valueDeclaration; - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context as { newLineCharacter: string, rulesProvider: formatting.RulesProvider }); + const changeTracker = textChanges.ChangeTracker.fromContext(context); let precedingNode: Node; let newClassDeclaration: ClassDeclaration; diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index 1a96857b73e..6fe664e6c81 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -708,7 +708,7 @@ namespace ts.refactor.extractMethod { ); } - const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + const changeTracker = textChanges.ChangeTracker.fromContext(context); // insert function at the end of the scope changeTracker.insertNodeBefore(context.file, scope.getLastToken(), newFunction, { prefix: context.newLineCharacter, suffix: context.newLineCharacter }); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 6462b64e226..7909d2d3adb 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -186,7 +186,7 @@ namespace ts.textChanges { private changes: Change[] = []; private readonly newLineCharacter: string; - public static fromCodeFixContext(context: { newLineCharacter: string, rulesProvider?: formatting.RulesProvider }) { + public static fromContext(context: RefactorContext | CodeFixContext) { return new ChangeTracker(getNewlineKind(context), context.rulesProvider); } From 8c714c3651c7c3b7a2a0ba37f59835bf3b68e439 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:21:47 -0700 Subject: [PATCH 33/74] Support special JS property assignments in doc comment templates (#18193) --- src/harness/fourslash.ts | 12 +- src/services/jsDoc.ts | 111 ++++++++++-------- .../docCommentTemplateClassDecl01.ts | 22 +--- .../docCommentTemplateClassDeclMethods01.ts | 32 ++--- .../docCommentTemplateClassDeclMethods02.ts | 25 +--- .../docCommentTemplateConstructor01.ts | 22 +--- .../fourslash/docCommentTemplateEmptyFile.ts | 3 +- ...ocCommentTemplateFunctionWithParameters.ts | 6 +- .../docCommentTemplateInMultiLineComment.ts | 3 +- .../docCommentTemplateInSingleLineComment.ts | 4 +- .../docCommentTemplateIndentation.ts | 11 +- ...ommentTemplateInsideFunctionDeclaration.ts | 4 +- ...mentTemplateJsSpecialPropertyAssignment.ts | 20 ++++ ...ocCommentTemplateNamespacesAndModules01.ts | 30 +---- ...ocCommentTemplateNamespacesAndModules02.ts | 28 +---- ...ocCommentTemplateObjectLiteralMethods01.ts | 23 +--- .../fourslash/docCommentTemplateRegex.ts | 4 +- .../docCommentTemplateVariableStatements01.ts | 32 ++--- .../docCommentTemplateVariableStatements02.ts | 24 +--- .../docCommentTemplateVariableStatements03.ts | 46 +++----- tests/cases/fourslash/fourslash.ts | 4 +- 21 files changed, 157 insertions(+), 309 deletions(-) create mode 100644 tests/cases/fourslash/docCommentTemplateJsSpecialPropertyAssignment.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index c224fd210ea..598cfc2fd7e 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2414,7 +2414,7 @@ namespace FourSlash { } } - public verifyDocCommentTemplate(expected?: ts.TextInsertion) { + public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined) { const name = "verifyDocCommentTemplate"; const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition); @@ -3908,12 +3908,14 @@ namespace FourSlashInterface { this.state.verifyNoMatchingBracePosition(bracePosition); } - public DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean) { - this.state.verifyDocCommentTemplate(empty ? undefined : { newText: expectedText, caretOffset: expectedOffset }); + public docCommentTemplateAt(marker: string | FourSlash.Marker, expectedOffset: number, expectedText: string) { + this.state.goToMarker(marker); + this.state.verifyDocCommentTemplate({ newText: expectedText.replace(/\r?\n/g, "\r\n"), caretOffset: expectedOffset }); } - public noDocCommentTemplate() { - this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true); + public noDocCommentTemplateAt(marker: string | FourSlash.Marker) { + this.state.goToMarker(marker); + this.state.verifyDocCommentTemplate(/*expected*/ undefined); } public rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void { diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index ee3ae7c868f..a135a9e8eef 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -173,38 +173,15 @@ namespace ts.JsDoc { return undefined; } - // TODO: add support for: - // - enums/enum members - // - interfaces - // - property declarations - // - potentially property assignments - let commentOwner: Node; - findOwner: for (commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { - switch (commentOwner.kind) { - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.Constructor: - case SyntaxKind.ClassDeclaration: - case SyntaxKind.VariableStatement: - break findOwner; - case SyntaxKind.SourceFile: - return undefined; - case SyntaxKind.ModuleDeclaration: - // If in walking up the tree, we hit a a nested namespace declaration, - // then we must be somewhere within a dotted namespace name; however we don't - // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'. - if (commentOwner.parent.kind === SyntaxKind.ModuleDeclaration) { - return undefined; - } - break findOwner; - } + const commentOwnerInfo = getCommentOwnerInfo(tokenAtPos); + if (!commentOwnerInfo) { + return undefined; } - - if (!commentOwner || commentOwner.getStart() < position) { + const { commentOwner, parameters } = commentOwnerInfo; + if (commentOwner.getStart() < position) { return undefined; } - const parameters = getParametersForJsDocOwningNode(commentOwner); const posLineAndChar = sourceFile.getLineAndCharacterOfPosition(position); const lineStart = sourceFile.getLineStarts()[posLineAndChar.line]; @@ -213,16 +190,18 @@ namespace ts.JsDoc { const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName); let docParams = ""; - for (let i = 0; i < parameters.length; i++) { - const currentName = parameters[i].name; - const paramName = currentName.kind === SyntaxKind.Identifier ? - (currentName).escapedText : - "param" + i; - if (isJavaScriptFile) { - docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; - } - else { - docParams += `${indentationStr} * @param ${paramName}${newLine}`; + if (parameters) { + for (let i = 0; i < parameters.length; i++) { + const currentName = parameters[i].name; + const paramName = currentName.kind === SyntaxKind.Identifier ? + (currentName).escapedText : + "param" + i; + if (isJavaScriptFile) { + docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`; + } + else { + docParams += `${indentationStr} * @param ${paramName}${newLine}`; + } } } @@ -244,21 +223,55 @@ namespace ts.JsDoc { return { newText: result, caretOffset: preamble.length }; } - function getParametersForJsDocOwningNode(commentOwner: Node): ReadonlyArray { - if (isFunctionLike(commentOwner)) { - return commentOwner.parameters; - } + interface CommentOwnerInfo { + readonly commentOwner: Node; + readonly parameters?: ReadonlyArray; + } + function getCommentOwnerInfo(tokenAtPos: Node): CommentOwnerInfo | undefined { + // TODO: add support for: + // - enums/enum members + // - interfaces + // - property declarations + // - potentially property assignments + for (let commentOwner = tokenAtPos; commentOwner; commentOwner = commentOwner.parent) { + switch (commentOwner.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.Constructor: + const { parameters } = commentOwner as FunctionDeclaration | MethodDeclaration | ConstructorDeclaration; + return { commentOwner, parameters }; - if (commentOwner.kind === SyntaxKind.VariableStatement) { - const varStatement = commentOwner; - const varDeclarations = varStatement.declarationList.declarations; + case SyntaxKind.ClassDeclaration: + return { commentOwner }; - if (varDeclarations.length === 1 && varDeclarations[0].initializer) { - return getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer); + case SyntaxKind.VariableStatement: { + const varStatement = commentOwner; + const varDeclarations = varStatement.declarationList.declarations; + const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer + ? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer) + : undefined; + return { commentOwner, parameters }; + } + + case SyntaxKind.SourceFile: + return undefined; + + case SyntaxKind.ModuleDeclaration: + // If in walking up the tree, we hit a a nested namespace declaration, + // then we must be somewhere within a dotted namespace name; however we don't + // want to give back a JSDoc template for the 'b' or 'c' in 'namespace a.b.c { }'. + return commentOwner.parent.kind === SyntaxKind.ModuleDeclaration ? undefined : { commentOwner }; + + case SyntaxKind.BinaryExpression: { + const be = commentOwner as BinaryExpression; + if (getSpecialPropertyAssignmentKind(be) === ts.SpecialPropertyAssignmentKind.None) { + return undefined; + } + const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray; + return { commentOwner, parameters }; + } } } - - return emptyArray; } /** diff --git a/tests/cases/fourslash/docCommentTemplateClassDecl01.ts b/tests/cases/fourslash/docCommentTemplateClassDecl01.ts index 958a8c60fa4..5a96f20d2e2 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDecl01.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDecl01.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, newTextOffset); -} - /////*decl*/class C { //// private p; //// constructor(a, b, c, d); @@ -29,8 +11,8 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ //// } ////} -confirmNormalizedJsDoc("decl", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("decl", /*newTextOffset*/ 8, +`/** * */ `); diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts index da407b632ef..ef4c82e7df7 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods01.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, indentation: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, indentation); -} - const enum Indentation { Standard = 8, Indented = 12, @@ -34,26 +16,26 @@ const enum Indentation { //// } ////} -confirmNormalizedJsDoc("0", Indentation.Standard, ` -/** +verify.docCommentTemplateAt("0", Indentation.Standard, +`/** * */`); -confirmNormalizedJsDoc("1", Indentation.Indented, +verify.docCommentTemplateAt("1", Indentation.Indented, `/** * */`); -confirmNormalizedJsDoc("2", Indentation.Indented, +verify.docCommentTemplateAt("2", Indentation.Indented, `/** * * @param a */ `); -confirmNormalizedJsDoc("3", Indentation.Indented, +verify.docCommentTemplateAt("3", Indentation.Indented, `/** * * @param a @@ -61,7 +43,7 @@ confirmNormalizedJsDoc("3", Indentation.Indented, */ `); -confirmNormalizedJsDoc("4", Indentation.Indented, +verify.docCommentTemplateAt("4", Indentation.Indented, `/** * * @param a @@ -69,7 +51,7 @@ confirmNormalizedJsDoc("4", Indentation.Indented, * @param param2 */`); -confirmNormalizedJsDoc("5", Indentation.Indented, +verify.docCommentTemplateAt("5", Indentation.Indented, `/** * * @param a diff --git a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts index 99392cf3855..28da24d381a 100644 --- a/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts +++ b/tests/cases/fourslash/docCommentTemplateClassDeclMethods02.ts @@ -1,28 +1,9 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, indentation: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, indentation); -} - const enum Indentation { Indented = 12, } - ////class C { //// /*0*/ //// [Symbol.iterator]() { @@ -32,15 +13,15 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -confirmNormalizedJsDoc("0", Indentation.Indented, +verify.docCommentTemplateAt("0", Indentation.Indented, `/** * */`); -confirmNormalizedJsDoc("1", Indentation.Indented, +verify.docCommentTemplateAt("1", Indentation.Indented, `/** * * @param x * @param y * @param z - */`); \ No newline at end of file + */`); diff --git a/tests/cases/fourslash/docCommentTemplateConstructor01.ts b/tests/cases/fourslash/docCommentTemplateConstructor01.ts index b26ece7a5e6..6c9eedb773d 100644 --- a/tests/cases/fourslash/docCommentTemplateConstructor01.ts +++ b/tests/cases/fourslash/docCommentTemplateConstructor01.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, newTextOffset); -} - ////class C { //// private p; //// /*0*/ @@ -32,7 +14,7 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ ////} const newTextOffset = 12; -confirmNormalizedJsDoc("0", /*newTextOffset*/ newTextOffset, +verify.docCommentTemplateAt("0", /*newTextOffset*/ newTextOffset, `/** * * @param a @@ -41,7 +23,7 @@ confirmNormalizedJsDoc("0", /*newTextOffset*/ newTextOffset, * @param d */`); -confirmNormalizedJsDoc("1", /*newTextOffset*/ newTextOffset, +verify.docCommentTemplateAt("1", /*newTextOffset*/ newTextOffset, `/** * * @param a diff --git a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts index 76e888ea2cb..f04653dc328 100644 --- a/tests/cases/fourslash/docCommentTemplateEmptyFile.ts +++ b/tests/cases/fourslash/docCommentTemplateEmptyFile.ts @@ -3,5 +3,4 @@ // @Filename: emptyFile.ts /////*0*/ -goTo.marker("0"); -verify.noDocCommentTemplate(); \ No newline at end of file +verify.noDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateFunctionWithParameters.ts b/tests/cases/fourslash/docCommentTemplateFunctionWithParameters.ts index f4410d5d454..b1955d98417 100644 --- a/tests/cases/fourslash/docCommentTemplateFunctionWithParameters.ts +++ b/tests/cases/fourslash/docCommentTemplateFunctionWithParameters.ts @@ -11,7 +11,5 @@ const noIndentOffset = 8; const oneIndentOffset = noIndentOffset + 4; goTo.marker("0"); -verify.DocCommentTemplate(noIndentScaffolding, noIndentOffset); - -goTo.marker("1"); -verify.DocCommentTemplate(oneIndentScaffolding, oneIndentOffset); \ No newline at end of file +verify.docCommentTemplateAt("0", noIndentOffset, noIndentScaffolding); +verify.docCommentTemplateAt("1", oneIndentOffset, oneIndentScaffolding); diff --git a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts index 131f722a9af..6e749782c7d 100644 --- a/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInMultiLineComment.ts @@ -3,5 +3,4 @@ // @Filename: justAComment.ts //// /* /*0*/ */ -goTo.marker("0"); -verify.noDocCommentTemplate(); \ No newline at end of file +verify.noDocCommentTemplateAt("0"); diff --git a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts index 65e9c17014e..b60fff2d590 100644 --- a/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts +++ b/tests/cases/fourslash/docCommentTemplateInSingleLineComment.ts @@ -8,4 +8,6 @@ //// // We also want to check EOF handling at the end of a comment //// // /*2*/ -goTo.eachMarker(() => verify.noDocCommentTemplate()); +for (const marker of test.markers()) { + verify.noDocCommentTemplateAt(marker); +} diff --git a/tests/cases/fourslash/docCommentTemplateIndentation.ts b/tests/cases/fourslash/docCommentTemplateIndentation.ts index 3f84a73b81f..c3015a6d9dd 100644 --- a/tests/cases/fourslash/docCommentTemplateIndentation.ts +++ b/tests/cases/fourslash/docCommentTemplateIndentation.ts @@ -12,11 +12,6 @@ const noIndentOffset = 8; const oneIndentOffset = noIndentOffset + 4; const twoIndentOffset = oneIndentOffset + 4; -goTo.marker("0"); -verify.DocCommentTemplate(noIndentEmptyScaffolding, noIndentOffset); - -goTo.marker("1"); -verify.DocCommentTemplate(oneIndentEmptyScaffolding, oneIndentOffset); - -goTo.marker("2"); -verify.DocCommentTemplate(twoIndentEmptyScaffolding, twoIndentOffset); +verify.docCommentTemplateAt("0", noIndentOffset, noIndentEmptyScaffolding); +verify.docCommentTemplateAt("1", oneIndentOffset, oneIndentEmptyScaffolding); +verify.docCommentTemplateAt("2", twoIndentOffset, twoIndentEmptyScaffolding); diff --git a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts index dd58a1bfd5f..e0ebc00dc39 100644 --- a/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts +++ b/tests/cases/fourslash/docCommentTemplateInsideFunctionDeclaration.ts @@ -3,4 +3,6 @@ // @Filename: functionDecl.ts ////f/*0*/unction /*1*/foo/*2*/(/*3*/) /*4*/{ /*5*/} -goTo.eachMarker(() => verify.noDocCommentTemplate()); +for (const marker of test.markers()) { + verify.noDocCommentTemplateAt(marker); +} diff --git a/tests/cases/fourslash/docCommentTemplateJsSpecialPropertyAssignment.ts b/tests/cases/fourslash/docCommentTemplateJsSpecialPropertyAssignment.ts new file mode 100644 index 00000000000..6a15ce133e4 --- /dev/null +++ b/tests/cases/fourslash/docCommentTemplateJsSpecialPropertyAssignment.ts @@ -0,0 +1,20 @@ +/// + +// @Filename: /a.js +/////*0*/module.exports = function(a) {}; +////const myNamespace = {}; +/////*1*/myNamespace.myExport = function(x) {}; + +verify.docCommentTemplateAt("0", 8, +`/** + * + * @param {any} a + */ +`); + +verify.docCommentTemplateAt("1", 8, +`/** + * + * @param {any} x + */ +`); diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts index 4d9fb987be5..e7e52fd5e94 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules01.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, charOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, charOffset); -} - /////*namespaceN*/ ////namespace n { ////} @@ -30,17 +12,17 @@ function confirmNormalizedJsDoc(markerName: string, charOffset: number, template ////module "ambientModule" { ////} -confirmNormalizedJsDoc("namespaceN", /*indentation*/ 8, ` -/** +verify.docCommentTemplateAt("namespaceN", /*indentation*/ 8, +`/** * */`); -confirmNormalizedJsDoc("namespaceM", /*indentation*/ 8, ` -/** +verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8, +`/** * */`); -confirmNormalizedJsDoc("namespaceM", /*indentation*/ 8, ` -/** +verify.docCommentTemplateAt("namespaceM", /*indentation*/ 8, +`/** * */`); diff --git a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts index e59b16d6163..dad2e9745a9 100644 --- a/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts +++ b/tests/cases/fourslash/docCommentTemplateNamespacesAndModules02.ts @@ -1,36 +1,16 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, charOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, charOffset); -} - /////*top*/ ////namespace n1. //// /*n2*/ n2. //// /*n3*/ n3 { ////} -confirmNormalizedJsDoc("top", /*indentation*/ 8, ` -/** +verify.docCommentTemplateAt("top", /*indentation*/ 8, +`/** * */`); -goTo.marker("n2"); -verify.noDocCommentTemplate(); +verify.noDocCommentTemplateAt("n2"); -goTo.marker("n3"); -verify.noDocCommentTemplate(); \ No newline at end of file +verify.noDocCommentTemplateAt("n3"); diff --git a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts index 4af1b60c698..2ae77d4afac 100644 --- a/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts +++ b/tests/cases/fourslash/docCommentTemplateObjectLiteralMethods01.ts @@ -1,28 +1,9 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, indentation: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, indentation); -} - const enum Indentation { Indented = 12, } - ////var x = { //// /*0*/ //// foo() { @@ -32,12 +13,12 @@ const enum Indentation { //// [1 + 2 + 3 + Math.rand()](x: number, y: string, z = true) { } ////} -confirmNormalizedJsDoc("0", Indentation.Indented, +verify.docCommentTemplateAt("0", Indentation.Indented, `/** * */`); -confirmNormalizedJsDoc("1", Indentation.Indented, +verify.docCommentTemplateAt("1", Indentation.Indented, `/** * * @param x diff --git a/tests/cases/fourslash/docCommentTemplateRegex.ts b/tests/cases/fourslash/docCommentTemplateRegex.ts index 62d200dee10..685c1ca5aef 100644 --- a/tests/cases/fourslash/docCommentTemplateRegex.ts +++ b/tests/cases/fourslash/docCommentTemplateRegex.ts @@ -3,4 +3,6 @@ // @Filename: regex.ts ////var regex = /*0*///*1*/asdf/*2*/ /*3*///*4*/; -goTo.eachMarker(() => verify.noDocCommentTemplate()); +for (const marker of test.markers()) { + verify.noDocCommentTemplateAt(marker); +} diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts index b901919fa1f..b6243652167 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements01.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, newTextOffset); -} - /////*a*/ ////var a = 10; //// @@ -46,23 +28,23 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ //// } ////} -for (const varName of "abcd".split("")) { - confirmNormalizedJsDoc(varName, /*newTextOffset*/ 8, ` -/** +for (const varName of ["a", "b", "c", "d"]) { + verify.docCommentTemplateAt(varName, /*newTextOffset*/ 8, +`/** * */`); } -confirmNormalizedJsDoc("e", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("e", /*newTextOffset*/ 8, +`/** * * @param x * @param y * @param z */`); -confirmNormalizedJsDoc("f", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("f", /*newTextOffset*/ 8, +`/** * * @param a * @param b diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts index 9339e703570..f22e361f63f 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements02.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, newTextOffset); -} - /////*a*/ ////var a1 = 10, a2 = 20; //// @@ -46,9 +28,9 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ //// bar: "20" ////}, f2 = null; -for (const varName of "abcdef".split("")) { - confirmNormalizedJsDoc(varName, /*newTextOffset*/ 8, ` -/** +for (const varName of ["a", "b", "c", "d", "e", "f"]) { + verify.docCommentTemplateAt(varName, /*newTextOffset*/ 8, +`/** * */`); } diff --git a/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts index e473cb798b7..195553098f0 100644 --- a/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts +++ b/tests/cases/fourslash/docCommentTemplateVariableStatements03.ts @@ -1,23 +1,5 @@ /// -const CRLF = "\r\n"; -/** - * @returns the given value with '\n' normalized to '\r\n' and with no leading newline - */ -function useCRLFAndStripLeadingNewline(str: string): string { - str = str.replace(/\r?\n/g, CRLF); - if (str.indexOf(CRLF) === 0) { - str = str.slice(CRLF.length); - } - return str; -} - -function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, template: string): void { - goTo.marker(markerName); - const normalized = useCRLFAndStripLeadingNewline(template); - verify.DocCommentTemplate(normalized, newTextOffset); -} - /////*a*/ ////var a = x => x //// @@ -47,44 +29,44 @@ function confirmNormalizedJsDoc(markerName: string, newTextOffset: number, templ //// } ////})) -confirmNormalizedJsDoc("a", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("a", /*newTextOffset*/ 8, +`/** * * @param x */`); -confirmNormalizedJsDoc("b", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("b", /*newTextOffset*/ 8, +`/** * * @param x * @param y * @param z */`); -confirmNormalizedJsDoc("c", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("c", /*newTextOffset*/ 8, +`/** * * @param x */`); -confirmNormalizedJsDoc("d", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("d", /*newTextOffset*/ 8, +`/** * */`); -confirmNormalizedJsDoc("e", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("e", /*newTextOffset*/ 8, +`/** * * @param param0 */`); -confirmNormalizedJsDoc("f", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("f", /*newTextOffset*/ 8, +`/** * */`); -confirmNormalizedJsDoc("g", /*newTextOffset*/ 8, ` -/** +verify.docCommentTemplateAt("g", /*newTextOffset*/ 8, +`/** * * @param x */`); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 5150fa16ae9..119780872e9 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -242,8 +242,8 @@ declare namespace FourSlashInterface { todoCommentsInCurrentFile(descriptors: string[]): void; matchingBracePositionInCurrentFile(bracePosition: number, expectedMatchPosition: number): void; noMatchingBracePositionInCurrentFile(bracePosition: number): void; - DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; - noDocCommentTemplate(): void; + docCommentTemplateAt(markerName: string | FourSlashInterface.Marker, expectedOffset: number, expectedText: string): void; + noDocCommentTemplateAt(markerName: string | FourSlashInterface.Marker): void; rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void; fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: FormatCodeOptions): void; rangeIs(expectedText: string, includeWhiteSpace?: boolean): void; From 0434fe797a0fe0b63f117dc811912e8312e62365 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:22:39 -0700 Subject: [PATCH 34/74] Get quickInfo from a contextual type if possible (#18119) --- src/compiler/types.ts | 3 ++ src/services/services.ts | 17 ++++++++++- tests/cases/fourslash/contextualTyping.ts | 28 +++++++++---------- .../fourslash/quickInfoFromContextualType.ts | 10 +++++++ .../quickInfoOnClassMergedWithFunction.ts | 22 +++++++-------- tests/cases/fourslash/quickInfoTypeError.ts | 4 +-- 6 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 tests/cases/fourslash/quickInfoFromContextualType.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b9d8d7a6319..83fc699c844 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -744,6 +744,7 @@ namespace ts { ; export interface PropertyAssignment extends ObjectLiteralElement { + parent: ObjectLiteralExpression; kind: SyntaxKind.PropertyAssignment; name: PropertyName; questionToken?: QuestionToken; @@ -751,6 +752,7 @@ namespace ts { } export interface ShorthandPropertyAssignment extends ObjectLiteralElement { + parent: ObjectLiteralExpression; kind: SyntaxKind.ShorthandPropertyAssignment; name: Identifier; questionToken?: QuestionToken; @@ -761,6 +763,7 @@ namespace ts { } export interface SpreadAssignment extends ObjectLiteralElement { + parent: ObjectLiteralExpression; kind: SyntaxKind.SpreadAssignment; expression: Expression; } diff --git a/src/services/services.ts b/src/services/services.ts index bada7ff021d..c22229fd089 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1398,7 +1398,7 @@ namespace ts { } const typeChecker = program.getTypeChecker(); - const symbol = typeChecker.getSymbolAtLocation(node); + const symbol = getSymbolAtLocationForQuickInfo(node, typeChecker); if (!symbol || typeChecker.isUnknownSymbol(symbol)) { // Try getting just type at this position and show @@ -1437,6 +1437,21 @@ namespace ts { }; } + function getSymbolAtLocationForQuickInfo(node: Node, checker: TypeChecker): Symbol | undefined { + if ((isIdentifier(node) || isStringLiteral(node)) + && isPropertyAssignment(node.parent) + && node.parent.name === node) { + const type = checker.getContextualType(node.parent.parent); + if (type) { + const property = checker.getPropertyOfType(type, getTextOfIdentifierOrLiteral(node)); + if (property) { + return property; + } + } + } + return checker.getSymbolAtLocation(node); + } + /// Goto definition function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { synchronizeHostData(); diff --git a/tests/cases/fourslash/contextualTyping.ts b/tests/cases/fourslash/contextualTyping.ts index 7819db20d92..9e9bce6dfaa 100644 --- a/tests/cases/fourslash/contextualTyping.ts +++ b/tests/cases/fourslash/contextualTyping.ts @@ -32,7 +32,7 @@ ////var /*13*/c3t5: (n: number) => IFoo = function(/*14*/n) { return ({}) }; ////var /*15*/c3t6: (n: number, s: string) => IFoo = function(/*16*/n, /*17*/s) { return ({}) }; ////var /*18*/c3t7: { -//// (n: number): number; +//// (n: number): number; //// (s1: string): number; ////}; ////var /*20*/c3t8: (n: number, s: string) => number = function(/*21*/n) { return n; }; @@ -79,7 +79,7 @@ //// t5: (n: number) => IFoo; //// t6: (n: number, s: string) => IFoo; //// t7: { -//// (n: number, s: string): number; +//// (n: number, s: string): number; //// //(s1: string, s2: string): number; //// }; //// t8: (n: number, s: string) => number; @@ -98,7 +98,7 @@ //// t5: (n: number) => IFoo; //// t6: (n: number, s: string) => IFoo; //// t7: { -//// (n: number, s: string): number; +//// (n: number, s: string): number; //// //(s1: string, s2: string): number; //// }; //// t8: (n: number, s: string) => number; @@ -152,7 +152,7 @@ ////var /*80*/c12t5 = <(n: number) => IFoo> function(/*81*/n) { return ({}) }; ////var /*82*/c12t6 = <(n: number, s: string) => IFoo> function(/*83*/n, /*84*/s) { return ({}) }; ////var /*85*/c12t7 = <{ -//// (n: number, s: string): number; +//// (n: number, s: string): number; //// //(s1: string, s2: string): number; ////}> function(n:number) { return n }; ////var /*86*/c12t8 = <(n: number, s: string) => number> function (/*87*/n) { return n; }; @@ -221,13 +221,13 @@ verify.quickInfos({ 25: "(parameter) n: number", 26: "(parameter) s: string", 27: "var c3t12: IBar", - 28: "(property) foo: IFoo", + 28: "(property) IBar.foo: IFoo", 29: "var c3t13: IFoo", - 30: "(property) f: (i: number, s: string) => string", + 30: "(method) IFoo.f(i: number, s: string): string", 31: "(parameter) i: number", 32: "(parameter) s: string", 33: "var c3t14: IFoo", - 34: "(property) a: undefined[]", + 34: "(property) IFoo.a: number[]", 35: "(property) C4T5.foo: (i: number, s: string) => string", 36: "(parameter) i: number", 37: "(parameter) s: string", @@ -257,13 +257,13 @@ verify.quickInfos({ 61: "(parameter) n: number", 62: "(parameter) s: string", 63: "(property) t12: IBar", - 64: "(property) foo: IFoo", + 64: "(property) IBar.foo: IFoo", 65: "(property) t13: IFoo", - 66: "(property) f: (i: number, s: string) => string", + 66: "(method) IFoo.f(i: number, s: string): string", 67: "(parameter) i: number", 68: "(parameter) s: string", 69: "(property) t14: IFoo", - 70: "(property) a: undefined[]", + 70: "(property) IFoo.a: number[]", 71: "(parameter) n: number", 72: "var c10t5: () => (n: number) => IFoo", 73: "(parameter) n: number", @@ -287,13 +287,13 @@ verify.quickInfos({ 91: "(parameter) n: number", 92: "(parameter) s: string", 93: "var c12t12: IBar", - 94: "(property) foo: IFoo", + 94: "(property) IBar.foo: IFoo", 95: "var c12t13: IFoo", - 96: "(property) f: (i: number, s: string) => string", + 96: "(method) IFoo.f(i: number, s: string): string", 97: "(parameter) i: number", 98: "(parameter) s: string", 99: "var c12t14: IFoo", - 100: "(property) a: undefined[]", + 100: "(property) IFoo.a: number[]", 101: "function EF1(a: number, b: number): number", 102: "(parameter) a: any", 103: "(parameter) b: any", @@ -302,7 +302,7 @@ verify.quickInfos({ 112: "(method) Point.add(dx: number, dy: number): Point", 113: "(parameter) dx: number", 114: "(parameter) dy: number", - 115: "(property) add: (dx: number, dy: number) => Point", + 115: "(method) Point.add(dx: number, dy: number): Point", 116: "(parameter) dx: number", 117: "(parameter) dy: number" }); diff --git a/tests/cases/fourslash/quickInfoFromContextualType.ts b/tests/cases/fourslash/quickInfoFromContextualType.ts new file mode 100644 index 00000000000..020681cd022 --- /dev/null +++ b/tests/cases/fourslash/quickInfoFromContextualType.ts @@ -0,0 +1,10 @@ +/// + +// @Filename: quickInfoExportAssignmentOfGenericInterface_0.ts +////interface I { +//// /** Documentation */ +//// x: number; +////} +////const i: I = { /**/x: 0 }; + +verify.quickInfoAt("", "(property) I.x: number", "Documentation "); diff --git a/tests/cases/fourslash/quickInfoOnClassMergedWithFunction.ts b/tests/cases/fourslash/quickInfoOnClassMergedWithFunction.ts index ef735fdfe3f..4a4f4e5fc17 100644 --- a/tests/cases/fourslash/quickInfoOnClassMergedWithFunction.ts +++ b/tests/cases/fourslash/quickInfoOnClassMergedWithFunction.ts @@ -1,16 +1,16 @@ /// ////module Test { -//// class Mocked { -//// myProp: string; -//// } -//// class Tester { -//// willThrowError() { -//// Mocked = Mocked || function () { // => Error: Invalid left-hand side of assignment expression. -//// return { /**/myProp: "test" }; -//// }; -//// } -//// } +//// class Mocked { +//// myProp: string; +//// } +//// class Tester { +//// willThrowError() { +//// Mocked = Mocked || function () { // => Error: Invalid left-hand side of assignment expression. +//// return { /**/myProp: "test" }; +//// }; +//// } +//// } ////} -verify.quickInfoAt("", "(property) myProp: string"); \ No newline at end of file +verify.quickInfoAt("", "(property) myProp: string"); diff --git a/tests/cases/fourslash/quickInfoTypeError.ts b/tests/cases/fourslash/quickInfoTypeError.ts index 7e0c9b20303..a4fa64e49d6 100644 --- a/tests/cases/fourslash/quickInfoTypeError.ts +++ b/tests/cases/fourslash/quickInfoTypeError.ts @@ -5,6 +5,6 @@ //// f() {} ////}); -// The symbol indicates that this is a funciton, but the type is `any`. +// The symbol indicates that this is a function, but the type is `any`. // Regression test that we don't crash (by trying to get signatures from `any`). -verify.quickInfoAt("", "(method) f"); +verify.quickInfoAt("", "(method) f(): void"); From 23f793fc3e804b43c2c6f6781913f025fe396221 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:23:06 -0700 Subject: [PATCH 35/74] findAllReferences: Handle root symbols of binding element property symbol (#17738) --- src/services/findAllReferences.ts | 78 +++++++++++-------- .../findAllRefsDestructureGeneric.ts | 15 ++++ ...OccurrencesIsDefinitionOfBindingPattern.ts | 11 ++- 3 files changed, 67 insertions(+), 37 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsDestructureGeneric.ts diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 04d383748c8..2de7eeb0210 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1435,22 +1435,27 @@ namespace ts.FindAllReferences.Core { const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker); if (bindingElementPropertySymbol) { result.push(bindingElementPropertySymbol); + addRootSymbols(bindingElementPropertySymbol); } - // If this is a union property, add all the symbols from all its source symbols in all unioned types. - // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list - for (const rootSymbol of checker.getRootSymbols(symbol)) { - if (rootSymbol !== symbol) { - result.push(rootSymbol); - } - - // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions - if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker); - } - } + addRootSymbols(symbol); return result; + + function addRootSymbols(sym: Symbol): void { + // If this is a union property, add all the symbols from all its source symbols in all unioned types. + // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list + for (const rootSymbol of checker.getRootSymbols(sym)) { + if (rootSymbol !== sym) { + result.push(rootSymbol); + } + + // Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions + if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), checker); + } + } + } } /** @@ -1542,34 +1547,39 @@ namespace ts.FindAllReferences.Core { // then include the binding element in the related symbols // let { a } : { a }; const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(referenceSymbol, state.checker); - if (bindingElementPropertySymbol && search.includes(bindingElementPropertySymbol)) { - return bindingElementPropertySymbol; + if (bindingElementPropertySymbol) { + const fromBindingElement = findRootSymbol(bindingElementPropertySymbol); + if (fromBindingElement) return fromBindingElement; } - // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) - // Or a union property, use its underlying unioned symbols - return forEach(state.checker.getRootSymbols(referenceSymbol), rootSymbol => { - // if it is in the list, then we are done - if (search.includes(rootSymbol)) { - return rootSymbol; - } + return findRootSymbol(referenceSymbol); - // Finally, try all properties with the same name in any type the containing type extended or implemented, and - // see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the - // parent symbol - if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { - // Parents will only be defined if implementations is true - if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) { - return undefined; + function findRootSymbol(sym: Symbol): Symbol | undefined { + // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) + // Or a union property, use its underlying unioned symbols + return forEach(state.checker.getRootSymbols(sym), rootSymbol => { + // if it is in the list, then we are done + if (search.includes(rootSymbol)) { + return rootSymbol; } - const result: Symbol[] = []; - getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker); - return find(result, search.includes); - } + // Finally, try all properties with the same name in any type the containing type extended or implemented, and + // see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the + // parent symbol + if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { + // Parents will only be defined if implementations is true + if (search.parents && !some(search.parents, parent => explicitlyInheritsFrom(rootSymbol.parent, parent, state.inheritsFromCache, state.checker))) { + return undefined; + } - return undefined; - }); + const result: Symbol[] = []; + getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, result, /*previousIterationSymbolsCache*/ createSymbolTable(), state.checker); + return find(result, search.includes); + } + + return undefined; + }); + } } function getNameFromObjectLiteralElement(node: ObjectLiteralElement): string { diff --git a/tests/cases/fourslash/findAllRefsDestructureGeneric.ts b/tests/cases/fourslash/findAllRefsDestructureGeneric.ts new file mode 100644 index 00000000000..f3d4635cebd --- /dev/null +++ b/tests/cases/fourslash/findAllRefsDestructureGeneric.ts @@ -0,0 +1,15 @@ +/// + +////interface I { +//// [|{| "isWriteAccess": true, "isDefinition": true |}x|]: boolean; +////} +////declare const i: I; +////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } = i; + +const [r0, r1] = test.ranges(); + +verify.referenceGroups(r0, [{ definition: "(property) I.x: boolean", ranges: [r0, r1] }]); +verify.referenceGroups(r1, [ + { definition: "(property) I.x: boolean", ranges: [r0] }, + { definition: "const x: boolean", ranges: [r1] } +]); diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts index 7725b2e94f8..58814b45e99 100644 --- a/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts +++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts @@ -1,5 +1,10 @@ /// -////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { x: 1, y: 2 }; -////const z = [|{| "isDefinition": false |}x|]; +////const { [|{| "isWriteAccess": true, "isDefinition": true |}x|], y } = { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: 1, y: 2 }; +////const z = [|x|]; -verify.singleReferenceGroup("const x: number"); +const [r0, r1, r2] = test.ranges(); +verify.referenceGroups([r0, r2], [ + { definition: "const x: number", ranges: [r0, r2] }, + { definition: "(property) x: number", ranges: [r1] }, +]); +verify.referenceGroups(r1, [{ definition: "(property) x: number", ranges: [r0, r1, r2] }]); From 817c329667947afd780a69551b93fb4224e331dc Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:23:53 -0700 Subject: [PATCH 36/74] getFormattingScanner: Ensure scanner is closed, and avoid global variables (#18293) --- src/services/formatting/formatting.ts | 14 +++++------ src/services/formatting/formattingScanner.ts | 25 +++++++------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 83f87483194..443ce13d6a4 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -339,17 +339,17 @@ namespace ts.formatting { /* @internal */ export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] { const range = { pos: 0, end: sourceFileLike.text.length }; - return formatSpanWorker( + return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker( range, node, initialIndentation, delta, - getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end), + scanner, rulesProvider.getFormatOptions(), rulesProvider, FormattingRequestKind.FormatSelection, _ => false, // assume that node does not have any errors - sourceFileLike); + sourceFileLike)); } function formatNodeLines(node: Node, sourceFile: SourceFile, options: FormatCodeSettings, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] { @@ -372,17 +372,17 @@ namespace ts.formatting { requestKind: FormattingRequestKind): TextChange[] { // find the smallest node that fully wraps the range and compute the initial indentation for the node const enclosingNode = findEnclosingNode(originalRange, sourceFile); - return formatSpanWorker( + return getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, scanner => formatSpanWorker( originalRange, enclosingNode, SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options), getOwnOrInheritedDelta(enclosingNode, options, sourceFile), - getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end), + scanner, options, rulesProvider, requestKind, prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange), - sourceFile); + sourceFile)); } function formatSpanWorker(originalRange: TextRange, @@ -427,8 +427,6 @@ namespace ts.formatting { } } - formattingScanner.close(); - return edits; // local functions diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index 52df6477ed0..9b4e1be323b 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -6,11 +6,6 @@ namespace ts.formatting { const standardScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard); const jsxScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.JSX); - /** - * Scanner that is currently used for formatting - */ - let scanner: Scanner; - export interface FormattingScanner { advance(): void; isOnToken(): boolean; @@ -18,7 +13,6 @@ namespace ts.formatting { getCurrentLeadingTrivia(): TextRangeWithKind[]; lastTrailingTriviaWasNewLine(): boolean; skipToEndOf(node: Node): void; - close(): void; } const enum ScanAction { @@ -30,9 +24,8 @@ namespace ts.formatting { RescanJsxText, } - export function getFormattingScanner(text: string, languageVariant: LanguageVariant, startPos: number, endPos: number): FormattingScanner { - Debug.assert(scanner === undefined, "Scanner should be undefined"); - scanner = languageVariant === LanguageVariant.JSX ? jsxScanner : standardScanner; + export function getFormattingScanner(text: string, languageVariant: LanguageVariant, startPos: number, endPos: number, cb: (scanner: FormattingScanner) => T): T { + const scanner = languageVariant === LanguageVariant.JSX ? jsxScanner : standardScanner; scanner.setText(text); scanner.setTextPos(startPos); @@ -45,21 +38,19 @@ namespace ts.formatting { let lastScanAction: ScanAction | undefined; let lastTokenInfo: TokenInfo | undefined; - return { + const res = cb({ advance, readTokenInfo, isOnToken, getCurrentLeadingTrivia: () => leadingTrivia, lastTrailingTriviaWasNewLine: () => wasNewLine, skipToEndOf, - close: () => { - Debug.assert(scanner !== undefined); + }); - lastTokenInfo = undefined; - scanner.setText(undefined); - scanner = undefined; - } - }; + lastTokenInfo = undefined; + scanner.setText(undefined); + + return res; function advance(): void { Debug.assert(scanner !== undefined, "Scanner should be present"); From b3c87aa919a24196e95ab1f5552ca19fcf3be247 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:26:22 -0700 Subject: [PATCH 37/74] Support find-all-references for `default` keyword (#17992) * Support find-all-references for anonymous default exports * Also handle re-exported default exports * Add test for using `export =` with `--allowSyntheticDefaultExports` --- src/compiler/checker.ts | 3 + src/services/findAllReferences.ts | 11 ++- src/services/importTracker.ts | 69 +++++++++++-------- .../findAllRefsForDefaultExport04.ts | 21 ++++-- .../findAllRefsForDefaultExportAnonymous.ts | 22 ++++++ .../findAllRefsForDefaultExport_reExport.ts | 30 ++++++++ ...t_reExport_allowSyntheticDefaultImports.ts | 32 +++++++++ tests/cases/fourslash/findAllRefsReExports.ts | 15 ++-- 8 files changed, 159 insertions(+), 44 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsForDefaultExportAnonymous.ts create mode 100644 tests/cases/fourslash/findAllRefsForDefaultExport_reExport.ts create mode 100644 tests/cases/fourslash/findAllRefsForDefaultExport_reExport_allowSyntheticDefaultImports.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e7e66ed5f2d..1c8bc7846d0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22987,6 +22987,9 @@ namespace ts { : undefined; return objectType && getPropertyOfType(objectType, escapeLeadingUnderscores((node as StringLiteral | NumericLiteral).text)); + case SyntaxKind.DefaultKeyword: + return getSymbolOfNode(node.parent); + default: return undefined; } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 2de7eeb0210..b12b0f85fda 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -176,7 +176,9 @@ namespace ts.FindAllReferences { fileName: node.getSourceFile().fileName, textSpan: getTextSpan(node), isWriteAccess: isWriteAccess(node), - isDefinition: isAnyDeclarationName(node) || isLiteralComputedPropertyDeclarationName(node), + isDefinition: node.kind === SyntaxKind.DefaultKeyword + || isAnyDeclarationName(node) + || isLiteralComputedPropertyDeclarationName(node), isInString }; } @@ -243,7 +245,7 @@ namespace ts.FindAllReferences { /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */ function isWriteAccess(node: Node): boolean { - if (isAnyDeclarationName(node)) { + if (node.kind === SyntaxKind.DefaultKeyword || isAnyDeclarationName(node)) { return true; } @@ -743,7 +745,7 @@ namespace ts.FindAllReferences.Core { function isValidReferencePosition(node: Node, searchSymbolName: string): boolean { // Compare the length so we filter out strict superstrings of the symbol we are looking for - switch (node && node.kind) { + switch (node.kind) { case SyntaxKind.Identifier: return (node as Identifier).text.length === searchSymbolName.length; @@ -754,6 +756,9 @@ namespace ts.FindAllReferences.Core { case SyntaxKind.NumericLiteral: return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral) && (node as NumericLiteral).text.length === searchSymbolName.length; + case SyntaxKind.DefaultKeyword: + return "default".length === searchSymbolName.length; + default: return false; } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index d4301db2f83..65b504e7bd8 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -180,7 +180,6 @@ namespace ts.FindAllReferences { * But re-exports will be placed in 'singleReferences' since they cannot be locally referenced. */ function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick { - const exportName = exportSymbol.escapedName; const importSearches: Array<[Identifier, Symbol]> = []; const singleReferences: Identifier[] = []; function addSearch(location: Identifier, symbol: Symbol): void { @@ -218,12 +217,11 @@ namespace ts.FindAllReferences { return; } - if (!decl.importClause) { + const { importClause } = decl; + if (!importClause) { return; } - const { importClause } = decl; - const { namedBindings } = importClause; if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { handleNamespaceImportLike(namedBindings.name); @@ -245,7 +243,6 @@ namespace ts.FindAllReferences { // 'default' might be accessed as a named import `{ default as foo }`. if (!isForRename && exportKind === ExportKind.Default) { - Debug.assert(exportName === "default"); searchForNamedImport(namedBindings as NamedImports | undefined); } } @@ -258,36 +255,43 @@ namespace ts.FindAllReferences { */ function handleNamespaceImportLike(importName: Identifier): void { // Don't rename an import that already has a different name than the export. - if (exportKind === ExportKind.ExportEquals && (!isForRename || importName.escapedText === exportName)) { + if (exportKind === ExportKind.ExportEquals && (!isForRename || isNameMatch(importName.escapedText))) { addSearch(importName, checker.getSymbolAtLocation(importName)); } } function searchForNamedImport(namedBindings: NamedImportsOrExports | undefined): void { - if (namedBindings) { - for (const element of namedBindings.elements) { - const { name, propertyName } = element; - if ((propertyName || name).escapedText !== exportName) { - continue; - } + if (!namedBindings) { + return; + } - if (propertyName) { - // This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference. - singleReferences.push(propertyName); - if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`. - // Search locally for `bar`. - addSearch(name, checker.getSymbolAtLocation(name)); - } - } - else { - const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName - ? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol. - : checker.getSymbolAtLocation(name); - addSearch(name, localSymbol); + for (const element of namedBindings.elements) { + const { name, propertyName } = element; + if (!isNameMatch((propertyName || name).escapedText)) { + continue; + } + + if (propertyName) { + // This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference. + singleReferences.push(propertyName); + if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`. + // Search locally for `bar`. + addSearch(name, checker.getSymbolAtLocation(name)); } } + else { + const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName + ? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol. + : checker.getSymbolAtLocation(name); + addSearch(name, localSymbol); + } } } + + function isNameMatch(name: __String): boolean { + // Use name of "default" even in `export =` case because we may have allowSyntheticDefaultImports + return name === exportSymbol.escapedName || exportKind !== ExportKind.Named && name === "default"; + } } /** Returns 'true' is the namespace 'name' is re-exported from this module, and 'false' if it is only used locally. */ @@ -413,7 +417,7 @@ namespace ts.FindAllReferences { case SyntaxKind.ExternalModuleReference: return (decl as ExternalModuleReference).parent; default: - Debug.fail(`Unexpected module specifier parent: ${decl.kind}`); + Debug.fail("Unexpected module specifier parent: " + decl.kind); } } @@ -468,11 +472,11 @@ namespace ts.FindAllReferences { return exportInfo(symbol, getExportKindForDeclaration(exportNode)); } } - // If we are in `export = a;`, `parent` is the export assignment. + // If we are in `export = a;` or `export default a;`, `parent` is the export assignment. else if (isExportAssignment(parent)) { return getExportAssignmentExport(parent); } - // If we are in `export = class A {};` at `A`, `parent.parent` is the export assignment. + // If we are in `export = class A {};` (or `export = class A {};`) at `A`, `parent.parent` is the export assignment. else if (isExportAssignment(parent.parent)) { return getExportAssignmentExport(parent.parent); } @@ -489,7 +493,8 @@ namespace ts.FindAllReferences { // Get the symbol for the `export =` node; its parent is the module it's the export of. const exportingModuleSymbol = ex.symbol.parent; Debug.assert(!!exportingModuleSymbol); - return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } }; + const exportKind = ex.isExportEquals ? ExportKind.ExportEquals : ExportKind.Default; + return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind } }; } function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined { @@ -525,7 +530,11 @@ namespace ts.FindAllReferences { importedSymbol = getExportEqualsLocalSymbol(importedSymbol, checker); } - if (symbolName(importedSymbol) === symbol.escapedName) { // If this is a rename import, do not continue searching. + // If the import has a different name than the export, do not continue searching. + // If `importedName` is undefined, do continue searching as the export is anonymous. + // (All imports returned from this function will be ignored anyway if we are in rename and this is a not a named export.) + const importedName = symbolName(importedSymbol); + if (importedName === undefined || importedName === "default" || importedName === symbol.escapedName) { return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport }; } } diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport04.ts b/tests/cases/fourslash/findAllRefsForDefaultExport04.ts index c8fdb0a6149..1b5eb7a282d 100644 --- a/tests/cases/fourslash/findAllRefsForDefaultExport04.ts +++ b/tests/cases/fourslash/findAllRefsForDefaultExport04.ts @@ -2,15 +2,24 @@ // @Filename: /a.ts ////const [|{| "isWriteAccess": true, "isDefinition": true |}a|] = 0; -////export default [|a|]; +////export [|{| "isWriteAccess": true, "isDefinition": true |}default|] [|a|]; // @Filename: /b.ts ////import [|{| "isWriteAccess": true, "isDefinition": true |}a|] from "./a"; ////[|a|]; -const [r0, r1, r2, r3] = test.ranges(); -verify.referenceGroups([r0, r1], [ - { definition: "const a: 0", ranges: [r0, r1] }, - { definition: "import a", ranges: [r2, r3] } +const [r0, r1, r2, r3, r4] = test.ranges(); +verify.referenceGroups([r0, r2], [ + { definition: "const a: 0", ranges: [r0, r2] }, + { definition: "import a", ranges: [r3, r4] } +]); +verify.referenceGroups(r1, [ + // TODO:GH#17990 + { definition: "import default", ranges: [r1] }, + { definition: "import a", ranges: [r3, r4] }, +]); +verify.referenceGroups([r3, r4], [ + { definition: "import a", ranges: [r3, r4] }, + // TODO:GH#17990 + { definition: "import default", ranges: [r1] }, ]); -verify.singleReferenceGroup("import a", [r2, r3]); diff --git a/tests/cases/fourslash/findAllRefsForDefaultExportAnonymous.ts b/tests/cases/fourslash/findAllRefsForDefaultExportAnonymous.ts new file mode 100644 index 00000000000..3beb5b59424 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForDefaultExportAnonymous.ts @@ -0,0 +1,22 @@ +/// + +// @Filename: /a.ts +////export [|{| "isWriteAccess": true, "isDefinition": true |}default|] function() {} + +// @Filename: /b.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}f|] from "./a"; + +const [r0, r1] = test.ranges(); +verify.referenceGroups(r0, [ + { definition: "function default(): void", ranges: [r0] }, + { definition: "import f", ranges: [r1] }, +]); +verify.referenceGroups(r1, [ + { definition: "import f", ranges: [r1] }, + { definition: "function default(): void", ranges: [r0] }, +]); + +// Verify that it doesn't try to rename "default" +goTo.rangeStart(r0); +verify.renameInfoFailed(); +verify.renameLocations(r1, [r1]); diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport_reExport.ts b/tests/cases/fourslash/findAllRefsForDefaultExport_reExport.ts new file mode 100644 index 00000000000..401db1a8033 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForDefaultExport_reExport.ts @@ -0,0 +1,30 @@ +/// + +// @Filename: /export.ts +////const [|{| "isWriteAccess": true, "isDefinition": true |}foo|] = 1; +////export default [|foo|]; + +// @Filename: /re-export.ts +////export { [|{| "isWriteAccess": true, "isDefinition": true |}default|] } from "./export"; + +// @Filename: /re-export-dep.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}fooDefault|] from "./re-export"; + +verify.noErrors(); + +const [r0, r1, r2, r3] = test.ranges(); +verify.referenceGroups([r0, r1], [ + { definition: "const foo: 1", ranges: [r0, r1] }, + { definition: "import default", ranges: [r2], }, + { definition: "import fooDefault", ranges: [r3] }, +]); +verify.referenceGroups(r2, [ + { definition: "import default", ranges: [r2] }, + { definition: "import fooDefault", ranges: [r3] }, + { definition: "const foo: 1", ranges: [r0, r1] }, +]); +verify.referenceGroups(r3, [ + { definition: "import fooDefault", ranges: [r3] }, + { definition: "import default", ranges: [r2] }, + { definition: "const foo: 1", ranges: [r0, r1] }, +]); diff --git a/tests/cases/fourslash/findAllRefsForDefaultExport_reExport_allowSyntheticDefaultImports.ts b/tests/cases/fourslash/findAllRefsForDefaultExport_reExport_allowSyntheticDefaultImports.ts new file mode 100644 index 00000000000..26a05f2e12e --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForDefaultExport_reExport_allowSyntheticDefaultImports.ts @@ -0,0 +1,32 @@ +/// + +// @allowSyntheticDefaultImports: true + +// @Filename: /export.ts +////const [|{| "isWriteAccess": true, "isDefinition": true |}foo|] = 1; +////export = [|foo|]; + +// @Filename: /re-export.ts +////export { [|{| "isWriteAccess": true, "isDefinition": true |}default|] } from "./export"; + +// @Filename: /re-export-dep.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}fooDefault|] from "./re-export"; + +verify.noErrors(); + +const [r0, r1, r2, r3] = test.ranges(); +verify.referenceGroups([r0, r1], [ + { definition: "const foo: 1", ranges: [r0, r1] }, + { definition: "import default", ranges: [r2], }, + { definition: "import fooDefault", ranges: [r3] }, +]); +verify.referenceGroups(r2, [ + { definition: "import default", ranges: [r2] }, + { definition: "import fooDefault", ranges: [r3] }, + { definition: "const foo: 1", ranges: [r0, r1] }, +]); +verify.referenceGroups(r3, [ + { definition: "import fooDefault", ranges: [r3] }, + { definition: "import default", ranges: [r2] }, + { definition: "const foo: 1", ranges: [r0, r1] }, +]); diff --git a/tests/cases/fourslash/findAllRefsReExports.ts b/tests/cases/fourslash/findAllRefsReExports.ts index a4cced049b9..e9936867604 100644 --- a/tests/cases/fourslash/findAllRefsReExports.ts +++ b/tests/cases/fourslash/findAllRefsReExports.ts @@ -39,14 +39,19 @@ verify.referenceGroups(bar2, [{ ...eBar, definition: "(alias) bar(): void\nimpor verify.referenceGroups([defaultC], [c, d, eBoom, eBaz, eBang]); verify.referenceGroups(defaultD, [d, eBoom, a, b, eBar,c, eBaz, eBang]); verify.referenceGroups(defaultE, [c, d, eBoom, eBaz, eBang]); -verify.referenceGroups(baz0, [eBaz]); -verify.referenceGroups(baz1, [{ ...eBaz, definition: "(alias) baz(): void\nimport baz" }]); +verify.referenceGroups(baz0, [eBaz, c, d, eBoom, eBang]); +verify.referenceGroups(baz1, [ + { ...eBaz, definition: "(alias) baz(): void\nimport baz" }, + c, d, eBoom, eBang, +]); verify.referenceGroups(bang0, [eBang]); verify.referenceGroups(bang1, [{ ...eBang, definition: "(alias) bang(): void\nimport bang" }]); - -verify.referenceGroups(boom0, [eBoom]); -verify.referenceGroups(boom1, [{ ...eBoom, definition: "(alias) boom(): void\nimport boom" }]); +verify.referenceGroups(boom0, [eBoom, d, a, b, eBar, c, eBaz, eBang]); +verify.referenceGroups(boom1, [ + { ...eBoom, definition: "(alias) boom(): void\nimport boom" }, + d, a, b, eBar, c, eBaz, eBang, +]); test.rangesByText().forEach((ranges, text) => { if (text === "default") { From b533b24686d5f2c799e2c5edf6283243b6a8d2df Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:28:12 -0700 Subject: [PATCH 38/74] extractMethod: Don't try to extract a single token (#18090) * extractMethod: Don't try to extract a single token * Update tests --- src/services/refactors/extractMethod.ts | 4 ++-- tests/cases/fourslash/extract-method-not-for-token.ts | 6 ++++++ tests/cases/fourslash/extract-method13.ts | 8 ++++---- tests/cases/fourslash/extract-method5.ts | 5 +++-- tests/cases/fourslash/extract-method7.ts | 4 ++-- 5 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/extract-method-not-for-token.ts diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index 6fe664e6c81..b76ab9376dc 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -95,7 +95,7 @@ namespace ts.refactor.extractMethod { export const CannotExtractRangeThatContainsWritesToReferencesLocatedOutsideOfTheTargetRangeInGenerators: DiagnosticMessage = createMessage("Cannot extract range containing writes to references located outside of the target range in generators."); export const TypeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope."); export const FunctionWillNotBeVisibleInTheNewScope = createMessage("Function will not visible in the new scope."); - export const InsufficientSelection = createMessage("Select more than a single identifier."); + export const InsufficientSelection = createMessage("Select more than a single token."); export const CannotExtractExportedEntity = createMessage("Cannot extract exported declaration"); export const CannotCombineWritesAndReturns = createMessage("Cannot combine writes and returns"); export const CannotExtractReadonlyPropertyInitializerOutsideConstructor = createMessage("Cannot move initialization of read-only class property outside of the constructor"); @@ -239,7 +239,7 @@ namespace ts.refactor.extractMethod { } function checkRootNode(node: Node): Diagnostic[] | undefined { - if (isIdentifier(node)) { + if (isToken(node)) { return [createDiagnosticForNode(node, Messages.InsufficientSelection)]; } return undefined; diff --git a/tests/cases/fourslash/extract-method-not-for-token.ts b/tests/cases/fourslash/extract-method-not-for-token.ts new file mode 100644 index 00000000000..756716441cd --- /dev/null +++ b/tests/cases/fourslash/extract-method-not-for-token.ts @@ -0,0 +1,6 @@ +/// + +////"/**/foo"; + +goTo.marker(""); +verify.not.refactorAvailable('Extract Method'); diff --git a/tests/cases/fourslash/extract-method13.ts b/tests/cases/fourslash/extract-method13.ts index 14a146a80c5..94ad86e4399 100644 --- a/tests/cases/fourslash/extract-method13.ts +++ b/tests/cases/fourslash/extract-method13.ts @@ -4,8 +4,8 @@ // Also checks that we correctly find non-conflicting names in static contexts. //// class C { -//// static j = /*c*/100/*d*/; -//// constructor(q: string = /*a*/"hello"/*b*/) { +//// static j = /*c*/1 + 1/*d*/; +//// constructor(q: string = /*a*/"a" + "b"/*b*/) { //// } //// } @@ -29,10 +29,10 @@ verify.currentFileContentIs(`class C { } private static newFunction(): string { - return "hello"; + return "a" + "b"; } private static newFunction_1() { - return 100; + return 1 + 1; } }`); \ No newline at end of file diff --git a/tests/cases/fourslash/extract-method5.ts b/tests/cases/fourslash/extract-method5.ts index 10294298b08..d1e70d10716 100644 --- a/tests/cases/fourslash/extract-method5.ts +++ b/tests/cases/fourslash/extract-method5.ts @@ -5,7 +5,7 @@ // annotation in the extracted function //// function f() { -//// var x: 1 | 2 | 3 = /*start*/2/*end*/; +//// var x: 1 | 2 | 3 = /*start*/1 + 1 === 2 ? 1 : 2/*end*/; //// } goTo.select('start', 'end'); @@ -14,11 +14,12 @@ edit.applyRefactor({ actionName: "scope_0", actionDescription: "Extract function into function 'f'", }); +// TODO: GH#18091 (fix formatting to use `2 ? 1 :` and not `2?1:`) verify.currentFileContentIs( `function f() { var x: 1 | 2 | 3 = newFunction(); function newFunction(): 1 | 2 | 3 { - return 2; + return 1 + 1 === 2?1: 2; } }`); \ No newline at end of file diff --git a/tests/cases/fourslash/extract-method7.ts b/tests/cases/fourslash/extract-method7.ts index 95c9cbe9897..d10c7c3136e 100644 --- a/tests/cases/fourslash/extract-method7.ts +++ b/tests/cases/fourslash/extract-method7.ts @@ -3,7 +3,7 @@ // You cannot extract a function initializer into the function's body. // The innermost scope (scope_0) is the sibling of the function, not the function itself. -//// function fn(x = /*a*/3/*b*/) { +//// function fn(x = /*a*/1 + 1/*b*/) { //// } goTo.select('a', 'b'); @@ -15,6 +15,6 @@ edit.applyRefactor({ verify.currentFileContentIs(`function fn(x = newFunction()) { } function newFunction() { - return 3; + return 1 + 1; } `); From 7541c705bfe9fd3247f5a3471b45c727d5484bca Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 07:45:11 -0700 Subject: [PATCH 39/74] Support navTo for special assignment kinds (#18154) * Support navTo for special assignment kinds * Return ScriptElementKind.unknown --- src/compiler/core.ts | 2 ++ src/services/services.ts | 6 +++++ src/services/utilities.ts | 22 +++++++++++++++++++ ...avigationItemsSpecialPropertyAssignment.ts | 20 +++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 tests/cases/fourslash/navigationItemsSpecialPropertyAssignment.ts diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 20f757c3df8..f7ff8c27bf7 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2628,4 +2628,6 @@ namespace ts { export function and(f: (arg: T) => boolean, g: (arg: T) => boolean) { return (arg: T) => f(arg) && g(arg); } + + export function assertTypeIsNever(_: never): void {} } diff --git a/src/services/services.ts b/src/services/services.ts index c22229fd089..e0e3bea79ff 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -722,6 +722,12 @@ namespace ts { } break; + case SyntaxKind.BinaryExpression: + if (getSpecialPropertyAssignmentKind(node as BinaryExpression) !== SpecialPropertyAssignmentKind.None) { + addDeclaration(node as BinaryExpression); + } + // falls through + default: forEachChild(node, visit); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index c7f5b5909f0..c3a1d5d571d 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -343,6 +343,28 @@ namespace ts { return ScriptElementKind.alias; case SyntaxKind.JSDocTypedefTag: return ScriptElementKind.typeElement; + case SyntaxKind.BinaryExpression: + const kind = getSpecialPropertyAssignmentKind(node as BinaryExpression); + const { right } = node as BinaryExpression; + switch (kind) { + case SpecialPropertyAssignmentKind.None: + return ScriptElementKind.unknown; + case SpecialPropertyAssignmentKind.ExportsProperty: + case SpecialPropertyAssignmentKind.ModuleExports: + const rightKind = getNodeKind(right); + return rightKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : rightKind; + case SpecialPropertyAssignmentKind.PrototypeProperty: + return ScriptElementKind.memberFunctionElement; // instance method + case SpecialPropertyAssignmentKind.ThisProperty: + return ScriptElementKind.memberVariableElement; // property + case SpecialPropertyAssignmentKind.Property: + // static method / property + return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement; + default: { + assertTypeIsNever(kind); + return ScriptElementKind.unknown; + } + } default: return ScriptElementKind.unknown; } diff --git a/tests/cases/fourslash/navigationItemsSpecialPropertyAssignment.ts b/tests/cases/fourslash/navigationItemsSpecialPropertyAssignment.ts new file mode 100644 index 00000000000..4618d34b954 --- /dev/null +++ b/tests/cases/fourslash/navigationItemsSpecialPropertyAssignment.ts @@ -0,0 +1,20 @@ +/// + +// @allowJs: true +// @Filename: /a.js +////exports.{| "name": "x", "kind": "const" |}x = 0; +////exports.{| "name": "y", "kind": "function" |}y = function() {}; +////function Cls() { +//// this.{| "name": "prop", "kind": "property" |}prop = 0; +////} +////Cls.{| "name": "staticMethod", "kind": "method" |}staticMethod = function() {}; +////Cls.{| "name": "staticProperty", "kind": "property" |}staticProperty = 0; +////Cls.prototype.{| "name": "instance", "kind": "method" |}instance = function() {}; + +for (const marker of test.markers()) { + verify.navigationItemsListContains( + marker.data.name, + marker.data.kind, + marker.data.name, + "exact"); +} From 90d9f3d4ba2b45c28fa3361725002f31c75d8403 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 09:07:59 -0700 Subject: [PATCH 40/74] Rename isStartOfType parameter used by isStartOfParameter --- src/compiler/parser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 1740bad2d34..d25bb3efd50 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2238,7 +2238,7 @@ namespace ts { isIdentifierOrPattern() || isModifierKind(token()) || token() === SyntaxKind.AtToken || - isStartOfType(/*disableLookahead*/ true); + isStartOfType(/*inStartOfParameter*/ true); } function parseParameter(): ParameterDeclaration { @@ -2699,7 +2699,7 @@ namespace ts { } } - function isStartOfType(disableLookahead?: boolean): boolean { + function isStartOfType(inStartOfParameter?: boolean): boolean { switch (token()) { case SyntaxKind.AnyKeyword: case SyntaxKind.StringKeyword: @@ -2729,11 +2729,11 @@ namespace ts { case SyntaxKind.DotDotDotToken: return true; case SyntaxKind.MinusToken: - return !disableLookahead && lookAhead(nextTokenIsNumericLiteral); + return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral); case SyntaxKind.OpenParenToken: // Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier, // or something that starts a type. We don't want to consider things like '(1)' a type. - return !disableLookahead && lookAhead(isStartOfParenthesizedOrFunctionType); + return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType); default: return isIdentifier(); } From be0633825cd4c82c279dd8f6ee8d432e0b757521 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 09:13:46 -0700 Subject: [PATCH 41/74] Don't provide string literal completions for string enums (#18288) * Don't provide string literal completions for string enums * Rename test --- src/services/completions.ts | 2 +- ...tringLiteralCompletionsForStringEnumContextualType.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/stringLiteralCompletionsForStringEnumContextualType.ts diff --git a/src/services/completions.ts b/src/services/completions.ts index 300ade2da48..97998ec724b 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -284,7 +284,7 @@ namespace ts.Completions { addStringLiteralCompletionsFromType(t, result, typeChecker, uniques); } } - else if (type.flags & TypeFlags.StringLiteral) { + else if (type.flags & TypeFlags.StringLiteral && !(type.flags & TypeFlags.EnumLiteral)) { const name = (type).value; if (!uniques.has(name)) { uniques.set(name, true); diff --git a/tests/cases/fourslash/stringLiteralCompletionsForStringEnumContextualType.ts b/tests/cases/fourslash/stringLiteralCompletionsForStringEnumContextualType.ts new file mode 100644 index 00000000000..664bfbac369 --- /dev/null +++ b/tests/cases/fourslash/stringLiteralCompletionsForStringEnumContextualType.ts @@ -0,0 +1,9 @@ +/// + +////const enum E { +//// A = "A", +////} +////const e: E = "/**/"; + +goTo.marker(""); +verify.completionListIsEmpty(); From 193f4be355168145ede3a8186b9b7ff13339c3ca Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 09:14:59 -0700 Subject: [PATCH 42/74] Enable interface-over-type-literal lint rule (#17733) --- src/compiler/checker.ts | 2 +- src/harness/unittests/convertTypeAcquisitionFromJson.ts | 2 +- src/server/protocol.ts | 8 ++++---- src/server/typingsInstaller/typingsInstaller.ts | 4 ++-- src/services/navigateTo.ts | 8 +++++++- src/services/types.ts | 9 ++++----- tslint.json | 1 + 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c8bc7846d0..b7f0894d284 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21516,7 +21516,7 @@ namespace ts { return true; } - type InheritanceInfoMap = { prop: Symbol; containingType: Type }; + interface InheritanceInfoMap { prop: Symbol; containingType: Type; } const seen = createUnderscoreEscapedMap(); forEach(resolveDeclaredMembers(type).declaredProperties, p => { seen.set(p.escapedName, { prop: p, containingType: type }); }); let ok = true; diff --git a/src/harness/unittests/convertTypeAcquisitionFromJson.ts b/src/harness/unittests/convertTypeAcquisitionFromJson.ts index aae4ee38382..67646de3680 100644 --- a/src/harness/unittests/convertTypeAcquisitionFromJson.ts +++ b/src/harness/unittests/convertTypeAcquisitionFromJson.ts @@ -2,7 +2,7 @@ /// namespace ts { - type ExpectedResult = { typeAcquisition: TypeAcquisition, errors: Diagnostic[] }; + interface ExpectedResult { typeAcquisition: TypeAcquisition; errors: Diagnostic[]; } describe("convertTypeAcquisitionFromJson", () => { function assertTypeAcquisition(json: any, configFileName: string, expectedResult: ExpectedResult) { assertTypeAcquisitionWithJson(json, configFileName, expectedResult); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 37bf79837c9..3fdbd8fd7f7 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -466,7 +466,7 @@ namespace ts.server.protocol { * Represents a single refactoring action - for example, the "Extract Method..." refactor might * offer several actions, each corresponding to a surround class or closure to extract into. */ - export type RefactorActionInfo = { + export interface RefactorActionInfo { /** * The programmatic name of the refactoring action */ @@ -478,7 +478,7 @@ namespace ts.server.protocol { * so this description should make sense by itself if the parent is inlineable=true */ description: string; - }; + } export interface GetEditsForRefactorRequest extends Request { command: CommandTypes.GetEditsForRefactor; @@ -501,7 +501,7 @@ namespace ts.server.protocol { body?: RefactorEditInfo; } - export type RefactorEditInfo = { + export interface RefactorEditInfo { edits: FileCodeEdits[]; /** @@ -510,7 +510,7 @@ namespace ts.server.protocol { */ renameLocation?: Location; renameFilename?: string; - }; + } /** * Request for the available codefixes at a specific position. diff --git a/src/server/typingsInstaller/typingsInstaller.ts b/src/server/typingsInstaller/typingsInstaller.ts index c6423bc3c7b..3eae0755747 100644 --- a/src/server/typingsInstaller/typingsInstaller.ts +++ b/src/server/typingsInstaller/typingsInstaller.ts @@ -73,12 +73,12 @@ namespace ts.server.typingsInstaller { } export type RequestCompletedAction = (success: boolean) => void; - type PendingRequest = { + interface PendingRequest { requestId: number; args: string[]; cwd: string; onRequestCompleted: RequestCompletedAction; - }; + } export abstract class TypingsInstaller { private readonly packageNameToTypingLocation: Map = createMap(); diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 6d84769082d..ec7b011456f 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -1,6 +1,12 @@ /* @internal */ namespace ts.NavigateTo { - type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration }; + interface RawNavigateToItem { + name: string; + fileName: string; + matchKind: PatternMatchKind; + isCaseSensitive: boolean; + declaration: Declaration; + } export function getNavigateToItems(sourceFiles: ReadonlyArray, checker: TypeChecker, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number, excludeDtsFiles: boolean): NavigateToItem[] { const patternMatcher = createPatternMatcher(searchValue); diff --git a/src/services/types.ts b/src/services/types.ts index 609eaf11de5..8a23bfec1c5 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -394,7 +394,7 @@ namespace ts { * Represents a single refactoring action - for example, the "Extract Method..." refactor might * offer several actions, each corresponding to a surround class or closure to extract into. */ - export type RefactorActionInfo = { + export interface RefactorActionInfo { /** * The programmatic name of the refactoring action */ @@ -406,18 +406,17 @@ namespace ts { * so this description should make sense by itself if the parent is inlineable=true */ description: string; - }; + } /** * A set of edits to make in response to a refactor action, plus an optional * location where renaming should be invoked from */ - export type RefactorEditInfo = { + export interface RefactorEditInfo { edits: FileTextChanges[]; renameFilename?: string; renameLocation?: number; - }; - + } export interface TextInsertion { newText: string; diff --git a/tslint.json b/tslint.json index de60ad7683a..30e71eb5e0d 100644 --- a/tslint.json +++ b/tslint.json @@ -11,6 +11,7 @@ "indent": [true, "spaces" ], + "interface-over-type-literal": true, "jsdoc-format": true, "linebreak-style": [true, "CRLF"], "next-line": [true, From 59aa29b85470809af10616aa92a2df460ac3b4c6 Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Thu, 7 Sep 2017 21:45:07 +0530 Subject: [PATCH 43/74] Added only the source file (#18175) --- src/lib/es2017.object.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/es2017.object.d.ts b/src/lib/es2017.object.d.ts index 1f090a8fef2..1d8a52da758 100644 --- a/src/lib/es2017.object.d.ts +++ b/src/lib/es2017.object.d.ts @@ -22,4 +22,10 @@ interface ObjectConstructor { * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. */ entries(o: any): [string, any][]; + + /** + * Returns an object containing all own property descriptors of an object + * @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object. + */ + getOwnPropertyDescriptors(o: T): {[P in keyof T]: TypedPropertyDescriptor} & { [x: string]: PropertyDescriptor }; } From 7b12b7955873fb0a937e3538b8fee2460fd63c64 Mon Sep 17 00:00:00 2001 From: Adrian Leonhard Date: Thu, 7 Sep 2017 18:17:47 +0200 Subject: [PATCH 44/74] ts.server.ProjectService.closeConfiguredProject returns true on success. (#18180) Fixes #17892 The if condition around the return value of that method in closeExternalProject indicates that this was the expected behavior. --- 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 d849226a35b..3f5b76ae39d 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1686,11 +1686,13 @@ namespace ts.server { } } - private closeConfiguredProject(configFile: NormalizedPath): void { + private closeConfiguredProject(configFile: NormalizedPath): boolean { const configuredProject = this.findConfiguredProjectByProjectName(configFile); if (configuredProject && configuredProject.deleteOpenRef() === 0) { this.removeProject(configuredProject); + return true; } + return false; } closeExternalProject(uncheckedFileName: string, suppressRefresh = false): void { From a8dfdf2fa111c709cb4d1262ad559e70efaec6c5 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Thu, 7 Sep 2017 18:22:26 +0200 Subject: [PATCH 45/74] Add and fix some AST Node parent types (#18200) --- src/compiler/types.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 83fc699c844..6c48fc90f0e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -636,6 +636,7 @@ namespace ts { export interface Decorator extends Node { kind: SyntaxKind.Decorator; + parent?: NamedDeclaration; expression: LeftHandSideExpression; } @@ -765,6 +766,7 @@ namespace ts { export interface SpreadAssignment extends ObjectLiteralElement { parent: ObjectLiteralExpression; kind: SyntaxKind.SpreadAssignment; + parent?: ObjectLiteralExpression; expression: Expression; } @@ -781,7 +783,7 @@ namespace ts { export interface VariableLikeDeclaration extends NamedDeclaration { propertyName?: PropertyName; dotDotDotToken?: DotDotDotToken; - name?: DeclarationName; // May be missing for ParameterDeclaration, see comment there + name: DeclarationName; questionToken?: QuestionToken; type?: TypeNode; initializer?: Expression; @@ -945,6 +947,7 @@ namespace ts { export interface TypePredicateNode extends TypeNode { kind: SyntaxKind.TypePredicate; + parent?: SignatureDeclaration; parameterName: Identifier | ThisTypeNode; type: TypeNode; } @@ -1001,7 +1004,6 @@ namespace ts { export interface MappedTypeNode extends TypeNode, Declaration { kind: SyntaxKind.MappedType; - parent?: TypeAliasDeclaration; readonlyToken?: ReadonlyToken; typeParameter: TypeParameterDeclaration; questionToken?: QuestionToken; @@ -1453,6 +1455,7 @@ namespace ts { export interface SpreadElement extends Expression { kind: SyntaxKind.SpreadElement; + parent?: ArrayLiteralExpression | CallExpression | NewExpression; expression: Expression; } From c82881f36ef412cacfe62e3394284e34cd9c4388 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 7 Sep 2017 09:36:31 -0700 Subject: [PATCH 46/74] Fix build break --- src/compiler/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6c48fc90f0e..75e1cb05bc9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -766,7 +766,6 @@ namespace ts { export interface SpreadAssignment extends ObjectLiteralElement { parent: ObjectLiteralExpression; kind: SyntaxKind.SpreadAssignment; - parent?: ObjectLiteralExpression; expression: Expression; } From 69933bd4d134250247175b00acc8e1e371331a7e Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Thu, 7 Sep 2017 18:46:58 +0200 Subject: [PATCH 47/74] expose isExternalModuleNameRelative and moduleHasNonRelativeName (#17971) * expose isExternalModuleNameRelative and moduleHasNonRelativeName Fixes: #17890 * only expose isExternalModuleNameRelative --- src/compiler/core.ts | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index f7ff8c27bf7..c76cd24f1b0 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -9,6 +9,15 @@ namespace ts { export const version = `${versionMajorMinor}.0`; } +namespace ts { + export function isExternalModuleNameRelative(moduleName: string): boolean { + // TypeScript 1.0 spec (April 2014): 11.2.1 + // An external module name is "relative" if the first term is "." or "..". + // Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module. + return pathIsRelative(moduleName) || isRootedDiskPath(moduleName); + } +} + /* @internal */ namespace ts { @@ -40,7 +49,6 @@ namespace ts { return new MapCtr() as UnderscoreEscapedMap; } - /* @internal */ export function createSymbolTable(symbols?: ReadonlyArray): SymbolTable { const result = createMap() as SymbolTable; if (symbols) { @@ -1604,18 +1612,10 @@ namespace ts { return path && !isRootedDiskPath(path) && path.indexOf("://") !== -1; } - /* @internal */ export function pathIsRelative(path: string): boolean { return /^\.\.?($|[\\/])/.test(path); } - export function isExternalModuleNameRelative(moduleName: string): boolean { - // TypeScript 1.0 spec (April 2014): 11.2.1 - // An external module name is "relative" if the first term is "." or "..". - // Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module. - return pathIsRelative(moduleName) || isRootedDiskPath(moduleName); - } - /** @deprecated Use `!isExternalModuleNameRelative(moduleName)` instead. */ export function moduleHasNonRelativeName(moduleName: string): boolean { return !isExternalModuleNameRelative(moduleName); @@ -1639,7 +1639,6 @@ namespace ts { return moduleResolution; } - /* @internal */ export function hasZeroOrOneAsteriskCharacter(str: string): boolean { let seenAsterisk = false; for (let i = 0; i < str.length; i++) { @@ -1864,17 +1863,14 @@ namespace ts { return true; } - /* @internal */ export function startsWith(str: string, prefix: string): boolean { return str.lastIndexOf(prefix, 0) === 0; } - /* @internal */ export function removePrefix(str: string, prefix: string): string { return startsWith(str, prefix) ? str.substr(prefix.length) : str; } - /* @internal */ export function endsWith(str: string, suffix: string): boolean { const expectedPos = str.length - suffix.length; return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos; @@ -1888,7 +1884,6 @@ namespace ts { return path.length > extension.length && endsWith(path, extension); } - /* @internal */ export function fileExtensionIsOneOf(path: string, extensions: ReadonlyArray): boolean { for (const extension of extensions) { if (fileExtensionIs(path, extension)) { @@ -1905,7 +1900,6 @@ namespace ts { const reservedCharacterPattern = /[^\w\s\/]/g; const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question]; - /* @internal */ export const commonPackageFolders: ReadonlyArray = ["node_modules", "bower_components", "jspm_packages"]; const implicitExcludePathRegexPattern = `(?!(${commonPackageFolders.join("|")})(/|$))`; @@ -2523,7 +2517,6 @@ namespace ts { * Return an exact match if possible, or a pattern match, or undefined. * (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.) */ - /* @internal */ export function matchPatternOrExact(patternStrings: ReadonlyArray, candidate: string): string | Pattern | undefined { const patterns: Pattern[] = []; for (const patternString of patternStrings) { @@ -2540,7 +2533,6 @@ namespace ts { return findBestPatternMatch(patterns, _ => _, candidate); } - /* @internal */ export function patternText({prefix, suffix}: Pattern): string { return `${prefix}*${suffix}`; } @@ -2549,14 +2541,12 @@ namespace ts { * Given that candidate matches pattern, returns the text matching the '*'. * E.g.: matchedText(tryParsePattern("foo*baz"), "foobarbaz") === "bar" */ - /* @internal */ export function matchedText(pattern: Pattern, candidate: string): string { Debug.assert(isPatternMatch(pattern, candidate)); return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length); } /** Return the object corresponding to the best pattern to match `candidate`. */ - /* @internal */ export function findBestPatternMatch(values: ReadonlyArray, getPattern: (value: T) => Pattern, candidate: string): T | undefined { let matchedValue: T | undefined = undefined; // use length of prefix as betterness criteria @@ -2579,7 +2569,6 @@ namespace ts { endsWith(candidate, suffix); } - /* @internal */ export function tryParsePattern(pattern: string): Pattern | undefined { // This should be verified outside of here and a proper error thrown. Debug.assert(hasZeroOrOneAsteriskCharacter(pattern)); From 39d0590869de4d94a16f9aa06334698d76fef5f9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Sep 2017 09:54:50 -0700 Subject: [PATCH 48/74] Adds comment --- src/harness/unittests/languageService.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/harness/unittests/languageService.ts b/src/harness/unittests/languageService.ts index 9c838845c20..fd0a95c167f 100644 --- a/src/harness/unittests/languageService.ts +++ b/src/harness/unittests/languageService.ts @@ -17,6 +17,8 @@ class Carousel extends Vue { "vue-class-component.d.ts": `import Vue from "./vue"; export function Component(x: Config): any;` }; + // Regression test for GH #18245 - bug in single line comment writer caused a debug assertion when attempting + // to write an alias to a module's default export was referrenced across files and had no default export it("should be able to create a language service which can respond to deinition requests without throwing", () => { const languageService = ts.createLanguageService({ getCompilationSettings() { From c1f2afd64587042dc8094bb12ecdbde9d1731523 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Sep 2017 10:28:58 -0700 Subject: [PATCH 49/74] Add typedef declaration space, unify typedef name gathering (#18172) * Add typedef declaration space, unify typedef name gathering, strengthen errorUnusedLocal * Bonus round: make jsdoc presence way mroe typesafe * Be exhaustive in nameForNamelessJSDocTypedef * Remove nonrequired casts * Replace more casts with guards * Cannot be internal * Debug.fail returns never, assert never no longer needs unreachable throw to satisfy checker * Rename type * Add replacement message as in 18287 --- src/compiler/binder.ts | 17 +-- src/compiler/checker.ts | 9 +- src/compiler/core.ts | 6 +- src/compiler/parser.ts | 16 +- src/compiler/types.ts | 143 +++++++++++------- src/compiler/utilities.ts | 82 +++++++++- src/services/classifier.ts | 3 +- src/services/completions.ts | 2 +- src/services/navigationBar.ts | 14 +- src/services/services.ts | 2 +- .../reference/jsdocTypedefNoCrash.js | 13 ++ .../reference/jsdocTypedefNoCrash.symbols | 8 + .../reference/jsdocTypedefNoCrash.types | 9 ++ .../reference/jsdocTypedefNoCrash2.errors.txt | 12 ++ .../reference/jsdocTypedefNoCrash2.js | 14 ++ tests/cases/compiler/jsdocTypedefNoCrash.ts | 9 ++ tests/cases/compiler/jsdocTypedefNoCrash2.ts | 11 ++ 17 files changed, 279 insertions(+), 91 deletions(-) create mode 100644 tests/baselines/reference/jsdocTypedefNoCrash.js create mode 100644 tests/baselines/reference/jsdocTypedefNoCrash.symbols create mode 100644 tests/baselines/reference/jsdocTypedefNoCrash.types create mode 100644 tests/baselines/reference/jsdocTypedefNoCrash2.errors.txt create mode 100644 tests/baselines/reference/jsdocTypedefNoCrash2.js create mode 100644 tests/cases/compiler/jsdocTypedefNoCrash.ts create mode 100644 tests/cases/compiler/jsdocTypedefNoCrash2.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a7e94da09d9..d6d253e1d77 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -282,17 +282,8 @@ namespace ts { const index = indexOf(functionType.parameters, node); return "arg" + index as __String; case SyntaxKind.JSDocTypedefTag: - const parentNode = node.parent && node.parent.parent; - let nameFromParentNode: __String; - if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { - if ((parentNode).declarationList.declarations.length > 0) { - const nameIdentifier = (parentNode).declarationList.declarations[0].name; - if (isIdentifier(nameIdentifier)) { - nameFromParentNode = nameIdentifier.escapedText; - } - } - } - return nameFromParentNode; + const name = getNameOfJSDocTypedef(node as JSDocTypedefTag); + return typeof name !== "undefined" ? name.escapedText : undefined; } } @@ -598,7 +589,7 @@ namespace ts { // Binding of JsDocComment should be done before the current block scope container changes. // because the scope of JsDocComment should not be affected by whether the current node is a // container or not. - if (node.jsDoc) { + if (hasJSDocNodes(node)) { if (isInJavaScriptFile(node)) { for (const j of node.jsDoc) { bind(j); @@ -1931,7 +1922,7 @@ namespace ts { } function bindJSDocTypedefTagIfAny(node: Node) { - if (!node.jsDoc) { + if (!hasJSDocNodes(node)) { return; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7f0894d284..91653c140c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19158,6 +19158,8 @@ namespace ts { switch (d.kind) { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.TypeAliasDeclaration: + // A jsdoc typedef is, by definition, a type alias + case SyntaxKind.JSDocTypedefTag: return DeclarationSpaces.ExportType; case SyntaxKind.ModuleDeclaration: return isAmbientModule(d) || getModuleInstanceState(d) !== ModuleInstanceState.NonInstantiated @@ -19827,7 +19829,7 @@ namespace ts { } } else if (compilerOptions.noUnusedLocals) { - forEach(local.declarations, d => errorUnusedLocal(getNameOfDeclaration(d) || d, unescapeLeadingUnderscores(local.escapedName))); + forEach(local.declarations, d => errorUnusedLocal(d, unescapeLeadingUnderscores(local.escapedName))); } } }); @@ -19842,7 +19844,8 @@ namespace ts { return false; } - function errorUnusedLocal(node: Node, name: string) { + function errorUnusedLocal(declaration: Declaration, name: string) { + const node = getNameOfDeclaration(declaration) || declaration; if (isIdentifierThatStartsWithUnderScore(node)) { const declaration = getRootDeclaration(node.parent); if (declaration.kind === SyntaxKind.VariableDeclaration && isForInOrOfStatement(declaration.parent.parent)) { @@ -19909,7 +19912,7 @@ namespace ts { if (!local.isReferenced && !local.exportSymbol) { for (const declaration of local.declarations) { if (!isAmbientModule(declaration)) { - errorUnusedLocal(getNameOfDeclaration(declaration), unescapeLeadingUnderscores(local.escapedName)); + errorUnusedLocal(declaration, unescapeLeadingUnderscores(local.escapedName)); } } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index c76cd24f1b0..2c0416c0711 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2441,7 +2441,7 @@ namespace ts { } } - export function fail(message?: string, stackCrawlMark?: Function): void { + export function fail(message?: string, stackCrawlMark?: Function): never { debugger; const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure."); if ((Error).captureStackTrace) { @@ -2450,6 +2450,10 @@ namespace ts { throw e; } + export function assertNever(member: never, message?: string, stackCrawlMark?: Function): never { + return fail(message || `Illegal value: ${member}`, stackCrawlMark || assertNever); + } + export function getFunctionName(func: Function) { if (typeof func !== "function") { return ""; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 71c7d3aac49..e30d5dbe1e4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -729,7 +729,7 @@ namespace ts { } - function addJSDocComment(node: T): T { + function addJSDocComment(node: T): T { const comments = getJSDocCommentRanges(node, sourceFile.text); if (comments) { for (const comment of comments) { @@ -768,7 +768,7 @@ namespace ts { const saveParent = parent; parent = n; forEachChild(n, visitNode); - if (n.jsDoc) { + if (hasJSDocNodes(n)) { for (const jsDoc of n.jsDoc) { jsDoc.parent = n; parent = jsDoc; @@ -2158,7 +2158,7 @@ namespace ts { const result = createNode(SyntaxKind.JSDocFunctionType); nextToken(); fillSignature(SyntaxKind.ColonToken, SignatureFlags.Type | SignatureFlags.JSDoc, result); - return finishNode(result); + return addJSDocComment(finishNode(result)); } const node = createNode(SyntaxKind.TypeReference); node.typeName = parseIdentifierName(); @@ -2365,7 +2365,7 @@ namespace ts { parseSemicolon(); } - function parseSignatureMember(kind: SyntaxKind): CallSignatureDeclaration | ConstructSignatureDeclaration { + function parseSignatureMember(kind: SyntaxKind.CallSignature | SyntaxKind.ConstructSignature): CallSignatureDeclaration | ConstructSignatureDeclaration { const node = createNode(kind); if (kind === SyntaxKind.ConstructSignature) { parseExpected(SyntaxKind.NewKeyword); @@ -2445,7 +2445,7 @@ namespace ts { node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); node.type = parseTypeAnnotation(); parseTypeMemberSemicolon(); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parsePropertyOrMethodSignature(fullStart: number, modifiers: NodeArray): PropertySignature | MethodSignature { @@ -2605,7 +2605,7 @@ namespace ts { parseExpected(SyntaxKind.NewKeyword); } fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseKeywordAndNoDot(): TypeNode | undefined { @@ -6182,7 +6182,7 @@ namespace ts { return jsDoc ? { jsDoc, diagnostics } : undefined; } - export function parseJSDocComment(parent: Node, start: number, length: number): JSDoc { + export function parseJSDocComment(parent: HasJSDoc, start: number, length: number): JSDoc { const saveToken = currentToken; const saveParseDiagnosticsLength = parseDiagnostics.length; const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; @@ -6997,7 +6997,7 @@ namespace ts { } forEachChild(node, visitNode, visitArray); - if (node.jsDoc) { + if (hasJSDocNodes(node)) { for (const jsDocComment of node.jsDoc) { forEachChild(jsDocComment, visitNode, visitArray); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 75e1cb05bc9..55baf9763c2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -516,8 +516,6 @@ namespace ts { parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). - /* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node - /* @internal */ jsDocCache?: ReadonlyArray; // Cache for getJSDocTags /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) /* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding) @@ -528,6 +526,44 @@ namespace ts { /* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type } + export interface JSDocContainer { + /* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node + /* @internal */ jsDocCache?: ReadonlyArray; // Cache for getJSDocTags + } + + export type HasJSDoc = + | ParameterDeclaration + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | MethodSignature + | PropertySignature + | ArrowFunction + | ParenthesizedExpression + | SpreadAssignment + | ShorthandPropertyAssignment + | PropertyAssignment + | FunctionExpression + | LabeledStatement + | ExpressionStatement + | VariableStatement + | FunctionDeclaration + | ConstructorDeclaration + | MethodDeclaration + | PropertyDeclaration + | AccessorDeclaration + | ClassLikeDeclaration + | InterfaceDeclaration + | TypeAliasDeclaration + | EnumMember + | EnumDeclaration + | ModuleDeclaration + | ImportEqualsDeclaration + | IndexSignatureDeclaration + | FunctionTypeNode + | ConstructorTypeNode + | JSDocFunctionType + | EndOfFileToken; + /* @internal */ export type MutableNodeArray = NodeArray & T[]; @@ -546,7 +582,7 @@ namespace ts { export type EqualsToken = Token; export type AsteriskToken = Token; export type EqualsGreaterThanToken = Token; - export type EndOfFileToken = Token; + export type EndOfFileToken = Token & JSDocContainer; export type AtToken = Token; export type ReadonlyToken = Token; export type AwaitKeywordToken = Token; @@ -651,32 +687,34 @@ namespace ts { expression?: Expression; } - export interface SignatureDeclaration extends NamedDeclaration { - kind: SyntaxKind.CallSignature - | SyntaxKind.ConstructSignature - | SyntaxKind.MethodSignature - | SyntaxKind.IndexSignature - | SyntaxKind.FunctionType - | SyntaxKind.ConstructorType - | SyntaxKind.JSDocFunctionType - | SyntaxKind.FunctionDeclaration - | SyntaxKind.MethodDeclaration - | SyntaxKind.Constructor - | SyntaxKind.GetAccessor - | SyntaxKind.SetAccessor - | SyntaxKind.FunctionExpression - | SyntaxKind.ArrowFunction; + export interface SignatureDeclarationBase extends NamedDeclaration, JSDocContainer { + kind: SignatureDeclaration["kind"]; name?: PropertyName; typeParameters?: NodeArray; parameters: NodeArray; type: TypeNode | undefined; } - export interface CallSignatureDeclaration extends SignatureDeclaration, TypeElement { + export type SignatureDeclaration = + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | MethodSignature + | IndexSignatureDeclaration + | FunctionTypeNode + | ConstructorTypeNode + | JSDocFunctionType + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | AccessorDeclaration + | FunctionExpression + | ArrowFunction; + + export interface CallSignatureDeclaration extends SignatureDeclarationBase, TypeElement { kind: SyntaxKind.CallSignature; } - export interface ConstructSignatureDeclaration extends SignatureDeclaration, TypeElement { + export interface ConstructSignatureDeclaration extends SignatureDeclarationBase, TypeElement { kind: SyntaxKind.ConstructSignature; } @@ -696,7 +734,7 @@ namespace ts { declarations: NodeArray; } - export interface ParameterDeclaration extends NamedDeclaration { + export interface ParameterDeclaration extends NamedDeclaration, JSDocContainer { kind: SyntaxKind.Parameter; parent?: SignatureDeclaration; dotDotDotToken?: DotDotDotToken; // Present on rest parameter @@ -715,7 +753,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - export interface PropertySignature extends TypeElement { + export interface PropertySignature extends TypeElement, JSDocContainer { kind: SyntaxKind.PropertySignature; name: PropertyName; // Declared property name questionToken?: QuestionToken; // Present on optional property @@ -723,7 +761,7 @@ namespace ts { initializer?: Expression; // Optional initializer } - export interface PropertyDeclaration extends ClassElement { + export interface PropertyDeclaration extends ClassElement, JSDocContainer { kind: SyntaxKind.PropertyDeclaration; questionToken?: QuestionToken; // Present for use with reporting a grammar error name: PropertyName; @@ -744,7 +782,7 @@ namespace ts { | AccessorDeclaration ; - export interface PropertyAssignment extends ObjectLiteralElement { + export interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer { parent: ObjectLiteralExpression; kind: SyntaxKind.PropertyAssignment; name: PropertyName; @@ -752,7 +790,7 @@ namespace ts { initializer: Expression; } - export interface ShorthandPropertyAssignment extends ObjectLiteralElement { + export interface ShorthandPropertyAssignment extends ObjectLiteralElement, JSDocContainer { parent: ObjectLiteralExpression; kind: SyntaxKind.ShorthandPropertyAssignment; name: Identifier; @@ -763,7 +801,7 @@ namespace ts { objectAssignmentInitializer?: Expression; } - export interface SpreadAssignment extends ObjectLiteralElement { + export interface SpreadAssignment extends ObjectLiteralElement, JSDocContainer { parent: ObjectLiteralExpression; kind: SyntaxKind.SpreadAssignment; expression: Expression; @@ -816,7 +854,7 @@ namespace ts { * - MethodDeclaration * - AccessorDeclaration */ - export interface FunctionLikeDeclarationBase extends SignatureDeclaration { + export interface FunctionLikeDeclarationBase extends SignatureDeclarationBase { _functionLikeDeclarationBrand: any; asteriskToken?: AsteriskToken; @@ -847,7 +885,7 @@ namespace ts { body?: FunctionBody; } - export interface MethodSignature extends SignatureDeclaration, TypeElement { + export interface MethodSignature extends SignatureDeclarationBase, TypeElement { kind: SyntaxKind.MethodSignature; name: PropertyName; } @@ -861,13 +899,13 @@ namespace ts { // Because of this, it may be necessary to determine what sort of MethodDeclaration you have // at later stages of the compiler pipeline. In that case, you can either check the parent kind // of the method, or use helpers like isObjectLiteralMethodDeclaration - export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement { + export interface MethodDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer { kind: SyntaxKind.MethodDeclaration; name: PropertyName; body?: FunctionBody; } - export interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement { + export interface ConstructorDeclaration extends FunctionLikeDeclarationBase, ClassElement, JSDocContainer { kind: SyntaxKind.Constructor; parent?: ClassDeclaration | ClassExpression; body?: FunctionBody; @@ -881,7 +919,7 @@ namespace ts { // See the comment on MethodDeclaration for the intuition behind GetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. - export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement { + export interface GetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer { kind: SyntaxKind.GetAccessor; parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression; name: PropertyName; @@ -890,7 +928,7 @@ namespace ts { // See the comment on MethodDeclaration for the intuition behind SetAccessorDeclaration being a // ClassElement and an ObjectLiteralElement. - export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement { + export interface SetAccessorDeclaration extends FunctionLikeDeclarationBase, ClassElement, ObjectLiteralElement, JSDocContainer { kind: SyntaxKind.SetAccessor; parent?: ClassDeclaration | ClassExpression | ObjectLiteralExpression; name: PropertyName; @@ -899,7 +937,7 @@ namespace ts { export type AccessorDeclaration = GetAccessorDeclaration | SetAccessorDeclaration; - export interface IndexSignatureDeclaration extends SignatureDeclaration, ClassElement, TypeElement { + export interface IndexSignatureDeclaration extends SignatureDeclarationBase, ClassElement, TypeElement { kind: SyntaxKind.IndexSignature; parent?: ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeLiteralNode; } @@ -928,11 +966,11 @@ namespace ts { export type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode; - export interface FunctionTypeNode extends TypeNode, SignatureDeclaration { + export interface FunctionTypeNode extends TypeNode, SignatureDeclarationBase { kind: SyntaxKind.FunctionType; } - export interface ConstructorTypeNode extends TypeNode, SignatureDeclaration { + export interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase { kind: SyntaxKind.ConstructorType; } @@ -1355,13 +1393,13 @@ namespace ts { export type FunctionBody = Block; export type ConciseBody = FunctionBody | Expression; - export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase { + export interface FunctionExpression extends PrimaryExpression, FunctionLikeDeclarationBase, JSDocContainer { kind: SyntaxKind.FunctionExpression; name?: Identifier; body: FunctionBody; // Required, whereas the member inherited from FunctionDeclaration is optional } - export interface ArrowFunction extends Expression, FunctionLikeDeclarationBase { + export interface ArrowFunction extends Expression, FunctionLikeDeclarationBase, JSDocContainer { kind: SyntaxKind.ArrowFunction; equalsGreaterThanToken: EqualsGreaterThanToken; body: ConciseBody; @@ -1440,7 +1478,7 @@ namespace ts { literal: TemplateMiddle | TemplateTail; } - export interface ParenthesizedExpression extends PrimaryExpression { + export interface ParenthesizedExpression extends PrimaryExpression, JSDocContainer { kind: SyntaxKind.ParenthesizedExpression; expression: Expression; } @@ -1696,12 +1734,12 @@ namespace ts { /*@internal*/ multiLine?: boolean; } - export interface VariableStatement extends Statement { + export interface VariableStatement extends Statement, JSDocContainer { kind: SyntaxKind.VariableStatement; declarationList: VariableDeclarationList; } - export interface ExpressionStatement extends Statement { + export interface ExpressionStatement extends Statement, JSDocContainer { kind: SyntaxKind.ExpressionStatement; expression: Expression; } @@ -1807,7 +1845,7 @@ namespace ts { export type CaseOrDefaultClause = CaseClause | DefaultClause; - export interface LabeledStatement extends Statement { + export interface LabeledStatement extends Statement, JSDocContainer { kind: SyntaxKind.LabeledStatement; label: Identifier; statement: Statement; @@ -1834,7 +1872,7 @@ namespace ts { export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag; - export interface ClassLikeDeclaration extends NamedDeclaration { + export interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer { kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression; name?: Identifier; typeParameters?: NodeArray; @@ -1842,15 +1880,17 @@ namespace ts { members: NodeArray; } - export interface ClassDeclaration extends ClassLikeDeclaration, DeclarationStatement { + export interface ClassDeclaration extends ClassLikeDeclarationBase, DeclarationStatement { kind: SyntaxKind.ClassDeclaration; name?: Identifier; } - export interface ClassExpression extends ClassLikeDeclaration, PrimaryExpression { + export interface ClassExpression extends ClassLikeDeclarationBase, PrimaryExpression { kind: SyntaxKind.ClassExpression; } + export type ClassLikeDeclaration = ClassDeclaration | ClassExpression; + export interface ClassElement extends NamedDeclaration { _classElementBrand: any; name?: PropertyName; @@ -1862,7 +1902,7 @@ namespace ts { questionToken?: QuestionToken; } - export interface InterfaceDeclaration extends DeclarationStatement { + export interface InterfaceDeclaration extends DeclarationStatement, JSDocContainer { kind: SyntaxKind.InterfaceDeclaration; name: Identifier; typeParameters?: NodeArray; @@ -1877,14 +1917,14 @@ namespace ts { types: NodeArray; } - export interface TypeAliasDeclaration extends DeclarationStatement { + export interface TypeAliasDeclaration extends DeclarationStatement, JSDocContainer { kind: SyntaxKind.TypeAliasDeclaration; name: Identifier; typeParameters?: NodeArray; type: TypeNode; } - export interface EnumMember extends NamedDeclaration { + export interface EnumMember extends NamedDeclaration, JSDocContainer { kind: SyntaxKind.EnumMember; parent?: EnumDeclaration; // This does include ComputedPropertyName, but the parser will give an error @@ -1893,7 +1933,7 @@ namespace ts { initializer?: Expression; } - export interface EnumDeclaration extends DeclarationStatement { + export interface EnumDeclaration extends DeclarationStatement, JSDocContainer { kind: SyntaxKind.EnumDeclaration; name: Identifier; members: NodeArray; @@ -1903,7 +1943,7 @@ namespace ts { export type ModuleBody = NamespaceBody | JSDocNamespaceBody; - export interface ModuleDeclaration extends DeclarationStatement { + export interface ModuleDeclaration extends DeclarationStatement, JSDocContainer { kind: SyntaxKind.ModuleDeclaration; parent?: ModuleBody | SourceFile; name: ModuleName; @@ -1937,7 +1977,7 @@ namespace ts { * - import x = require("mod"); * - import x = M.x; */ - export interface ImportEqualsDeclaration extends DeclarationStatement { + export interface ImportEqualsDeclaration extends DeclarationStatement, JSDocContainer { kind: SyntaxKind.ImportEqualsDeclaration; parent?: SourceFile | ModuleBlock; name: Identifier; @@ -2090,7 +2130,7 @@ namespace ts { type: TypeNode; } - export interface JSDocFunctionType extends JSDocType, SignatureDeclaration { + export interface JSDocFunctionType extends JSDocType, SignatureDeclarationBase { kind: SyntaxKind.JSDocFunctionType; } @@ -2103,6 +2143,7 @@ namespace ts { export interface JSDoc extends Node { kind: SyntaxKind.JSDocComment; + parent?: HasJSDoc; tags: NodeArray | undefined; comment: string | undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 725070c02bf..11c30a2d8ab 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -277,7 +277,7 @@ namespace ts { return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); } - if (includeJsDoc && node.jsDoc && node.jsDoc.length > 0) { + if (includeJsDoc && hasJSDocNodes(node)) { return getTokenPosOfNode(node.jsDoc[0]); } @@ -1510,10 +1510,10 @@ namespace ts { } export function getJSDocTags(node: Node): ReadonlyArray | undefined { - let tags = node.jsDocCache; + let tags = (node as JSDocContainer).jsDocCache; // If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing. if (tags === undefined) { - node.jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j); + (node as JSDocContainer).jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j); } return tags; } @@ -1567,11 +1567,13 @@ namespace ts { result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration)); } - if (isVariableLike(node) && node.initializer) { + if (isVariableLike(node) && node.initializer && hasJSDocNodes(node.initializer)) { result = addRange(result, node.initializer.jsDoc); } - result = addRange(result, node.jsDoc); + if (hasJSDocNodes(node)) { + result = addRange(result, node.jsDoc); + } } } @@ -3958,7 +3960,66 @@ namespace ts { return id; } - export function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined { + /** + * A JSDocTypedef tag has an _optional_ name field - if a name is not directly present, we should + * attempt to draw the name from the node the declaration is on (as that declaration is what its' symbol + * will be merged with) + */ + function nameForNamelessJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { + const hostNode = declaration.parent.parent; + if (!hostNode) { + return undefined; + } + // Covers classes, functions - any named declaration host node + if (isDeclaration(hostNode)) { + return getDeclarationIdentifier(hostNode); + } + // Covers remaining cases + switch (hostNode.kind) { + case SyntaxKind.VariableStatement: + if ((hostNode as VariableStatement).declarationList && + (hostNode as VariableStatement).declarationList.declarations[0]) { + return getDeclarationIdentifier((hostNode as VariableStatement).declarationList.declarations[0]); + } + return undefined; + case SyntaxKind.ExpressionStatement: + const expr = (hostNode as ExpressionStatement).expression; + switch (expr.kind) { + case SyntaxKind.PropertyAccessExpression: + return (expr as PropertyAccessExpression).name; + case SyntaxKind.ElementAccessExpression: + const arg = (expr as ElementAccessExpression).argumentExpression; + if (isIdentifier(arg)) { + return arg; + } + } + return undefined; + case SyntaxKind.EndOfFileToken: + return undefined; + case SyntaxKind.ParenthesizedExpression: { + return getDeclarationIdentifier(hostNode.expression); + } + case SyntaxKind.LabeledStatement: { + if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) { + return getDeclarationIdentifier(hostNode.statement); + } + return undefined; + } + default: + Debug.assertNever(hostNode, "Found typedef tag attached to node which it should not be!"); + } + } + + function getDeclarationIdentifier(node: Declaration | Expression) { + const name = getNameOfDeclaration(node); + return isIdentifier(name) ? name : undefined; + } + + export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined { + return declaration.name || nameForNamelessJSDocTypedef(declaration as JSDocTypedefTag); + } + + export function getNameOfDeclaration(declaration: Declaration | Expression): DeclarationName | undefined { if (!declaration) { return undefined; } @@ -3977,6 +4038,9 @@ namespace ts { return undefined; } } + else if (declaration.kind === SyntaxKind.JSDocTypedefTag) { + return getNameOfJSDocTypedef(declaration as JSDocTypedefTag); + } else { return (declaration as NamedDeclaration).name; } @@ -5365,4 +5429,10 @@ namespace ts { export function isJSDocTag(node: Node): boolean { return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode; } + + /** True if has jsdoc nodes attached to it. */ + /* @internal */ + export function hasJSDocNodes(node: Node): node is HasJSDoc { + return !!(node as JSDocContainer).jsDoc && (node as JSDocContainer).jsDoc.length > 0; + } } diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 4552d8bf985..18eec066ea2 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -699,7 +699,8 @@ namespace ts { // specially. const docCommentAndDiagnostics = parseIsolatedJSDocComment(sourceFile.text, start, width); if (docCommentAndDiagnostics && docCommentAndDiagnostics.jsDoc) { - docCommentAndDiagnostics.jsDoc.parent = token; + // TODO: This should be predicated on `token["kind"]` being compatible with `HasJSDoc["kind"]` + docCommentAndDiagnostics.jsDoc.parent = token as HasJSDoc; classifyJSDocComment(docCommentAndDiagnostics.jsDoc); return; } diff --git a/src/services/completions.ts b/src/services/completions.ts index 97998ec724b..15a20798508 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1739,7 +1739,7 @@ namespace ts.Completions { /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined { - const { jsDoc } = getJsDocHavingNode(node); + const { jsDoc } = getJsDocHavingNode(node) as JSDocContainer; if (!jsDoc) return undefined; for (const { pos, end, tags } of jsDoc) { diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 35357b9331a..f7ed515a18f 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -263,13 +263,15 @@ namespace ts.NavigationBar { break; default: - forEach(node.jsDoc, jsDoc => { - forEach(jsDoc.tags, tag => { - if (tag.kind === SyntaxKind.JSDocTypedefTag) { - addLeafNode(tag); - } + if (hasJSDocNodes(node)) { + forEach(node.jsDoc, jsDoc => { + forEach(jsDoc.tags, tag => { + if (tag.kind === SyntaxKind.JSDocTypedefTag) { + addLeafNode(tag); + } + }); }); - }); + } forEachChild(node, addChildrenRecursively); } diff --git a/src/services/services.ts b/src/services/services.ts index e0e3bea79ff..1feafdd55f5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2111,7 +2111,7 @@ namespace ts { } forEachChild(node, walk); - if (node.jsDoc) { + if (hasJSDocNodes(node)) { for (const jsDoc of node.jsDoc) { forEachChild(jsDoc, walk); } diff --git a/tests/baselines/reference/jsdocTypedefNoCrash.js b/tests/baselines/reference/jsdocTypedefNoCrash.js new file mode 100644 index 00000000000..803f6b1bb85 --- /dev/null +++ b/tests/baselines/reference/jsdocTypedefNoCrash.js @@ -0,0 +1,13 @@ +//// [export.js] +/** + * @typedef {{ + * }} + */ +export const foo = 5; + +//// [export.js] +/** + * @typedef {{ + * }} + */ +export const foo = 5; diff --git a/tests/baselines/reference/jsdocTypedefNoCrash.symbols b/tests/baselines/reference/jsdocTypedefNoCrash.symbols new file mode 100644 index 00000000000..8724c9da8d1 --- /dev/null +++ b/tests/baselines/reference/jsdocTypedefNoCrash.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/export.js === +/** + * @typedef {{ + * }} + */ +export const foo = 5; +>foo : Symbol(foo, Decl(export.js, 4, 12)) + diff --git a/tests/baselines/reference/jsdocTypedefNoCrash.types b/tests/baselines/reference/jsdocTypedefNoCrash.types new file mode 100644 index 00000000000..e05c4421a79 --- /dev/null +++ b/tests/baselines/reference/jsdocTypedefNoCrash.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/export.js === +/** + * @typedef {{ + * }} + */ +export const foo = 5; +>foo : 5 +>5 : 5 + diff --git a/tests/baselines/reference/jsdocTypedefNoCrash2.errors.txt b/tests/baselines/reference/jsdocTypedefNoCrash2.errors.txt new file mode 100644 index 00000000000..6c4a15e5947 --- /dev/null +++ b/tests/baselines/reference/jsdocTypedefNoCrash2.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/export.js(1,13): error TS8008: 'type aliases' can only be used in a .ts file. + + +==== tests/cases/compiler/export.js (1 errors) ==== + export type foo = 5; + ~~~ +!!! error TS8008: 'type aliases' can only be used in a .ts file. + /** + * @typedef {{ + * }} + */ + export const foo = 5; \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTypedefNoCrash2.js b/tests/baselines/reference/jsdocTypedefNoCrash2.js new file mode 100644 index 00000000000..397ca973d1e --- /dev/null +++ b/tests/baselines/reference/jsdocTypedefNoCrash2.js @@ -0,0 +1,14 @@ +//// [export.js] +export type foo = 5; +/** + * @typedef {{ + * }} + */ +export const foo = 5; + +//// [export.js] +/** + * @typedef {{ + * }} + */ +export const foo = 5; diff --git a/tests/cases/compiler/jsdocTypedefNoCrash.ts b/tests/cases/compiler/jsdocTypedefNoCrash.ts new file mode 100644 index 00000000000..cb8f5df09ef --- /dev/null +++ b/tests/cases/compiler/jsdocTypedefNoCrash.ts @@ -0,0 +1,9 @@ +// @target: es6 +// @allowJs: true +// @outDir: ./dist +// @filename: export.js +/** + * @typedef {{ + * }} + */ +export const foo = 5; \ No newline at end of file diff --git a/tests/cases/compiler/jsdocTypedefNoCrash2.ts b/tests/cases/compiler/jsdocTypedefNoCrash2.ts new file mode 100644 index 00000000000..d41fb62e446 --- /dev/null +++ b/tests/cases/compiler/jsdocTypedefNoCrash2.ts @@ -0,0 +1,11 @@ +// @target: es6 +// @allowJs: true +// @outDir: ./dist +// @filename: export.js + +export type foo = 5; +/** + * @typedef {{ + * }} + */ +export const foo = 5; \ No newline at end of file From de313ff1bd11daf484aa421a5d9fde954b8e6fc7 Mon Sep 17 00:00:00 2001 From: Alex Chugaev Date: Thu, 7 Sep 2017 20:58:05 +0300 Subject: [PATCH 50/74] Object.getOwnPropertyDescriptor() returns 'undefined' if property descriptor not found. (#18148) --- src/lib/es2015.core.d.ts | 2 +- src/lib/es2015.reflect.d.ts | 2 +- src/lib/es5.d.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 0deef59a47d..42d3d1543a0 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -327,7 +327,7 @@ interface ObjectConstructor { * @param o Object that contains the property. * @param p Name of the property. */ - getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor; + getOwnPropertyDescriptor(o: any, propertyKey: PropertyKey): PropertyDescriptor | undefined; /** * Adds a property to an object, or modifies attributes of an existing property. diff --git a/src/lib/es2015.reflect.d.ts b/src/lib/es2015.reflect.d.ts index 83755e4c791..aab3da993dc 100644 --- a/src/lib/es2015.reflect.d.ts +++ b/src/lib/es2015.reflect.d.ts @@ -4,7 +4,7 @@ declare namespace Reflect { function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean; function deleteProperty(target: object, propertyKey: PropertyKey): boolean; function get(target: object, propertyKey: PropertyKey, receiver?: any): any; - function getOwnPropertyDescriptor(target: object, propertyKey: PropertyKey): PropertyDescriptor; + function getOwnPropertyDescriptor(target: object, propertyKey: PropertyKey): PropertyDescriptor | undefined; function getPrototypeOf(target: object): object; function has(target: object, propertyKey: PropertyKey): boolean; function isExtensible(target: object): boolean; diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index 4dae997ffb4..6033a8fd989 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -127,7 +127,7 @@ interface ObjectConstructor { * @param o Object that contains the property. * @param p Name of the property. */ - getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor; + getOwnPropertyDescriptor(o: any, p: string): PropertyDescriptor | undefined; /** * Returns the names of the own properties of an object. The own properties of an object are those that are defined directly From 097b094082827c2055a401686a4b5aec30afbfe6 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 7 Sep 2017 10:58:50 -0700 Subject: [PATCH 51/74] Don't get typings for projects with disabled language services --- src/server/project.ts | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 623c43e8d3a..c8e9e1b4833 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -547,33 +547,32 @@ namespace ts.server { this.cachedUnresolvedImportsPerFile.remove(file); } - // 1. no changes in structure, no changes in unresolved imports - do nothing - // 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files - // (can reuse cached imports for files that were not changed) - // 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files - // (can reuse cached imports for files that were not changed) - // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch - let unresolvedImports: SortedReadonlyArray; - if (hasChanges || changedFiles.length) { - const result: string[] = []; - for (const sourceFile of this.program.getSourceFiles()) { - this.extractUnresolvedImportsFromSourceFile(sourceFile, result); - } - this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result); - } - unresolvedImports = this.lastCachedUnresolvedImportsList; - - const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this, unresolvedImports, hasChanges); - if (this.setTypings(cachedTypings)) { - hasChanges = this.updateGraphWorker() || hasChanges; - } - // update builder only if language service is enabled // otherwise tell it to drop its internal state if (this.languageServiceEnabled) { + // 1. no changes in structure, no changes in unresolved imports - do nothing + // 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files + // (can reuse cached imports for files that were not changed) + // 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files + // (can reuse cached imports for files that were not changed) + // 4. compilation settings were changed in the way that might affect module resolution - drop all caches and collect all data from the scratch + if (hasChanges || changedFiles.length) { + const result: string[] = []; + for (const sourceFile of this.program.getSourceFiles()) { + this.extractUnresolvedImportsFromSourceFile(sourceFile, result); + } + this.lastCachedUnresolvedImportsList = toDeduplicatedSortedArray(result); + } + + const cachedTypings = this.projectService.typingsCache.getTypingsForProject(this, this.lastCachedUnresolvedImportsList, hasChanges); + if (this.setTypings(cachedTypings)) { + hasChanges = this.updateGraphWorker() || hasChanges; + } + this.builder.onProjectUpdateGraph(); } else { + this.lastCachedUnresolvedImportsList = undefined; this.builder.clear(); } From ac58751b6239aeb2c4a980644c4db48ee4bf3c27 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 11:30:38 -0700 Subject: [PATCH 52/74] Object literals computed property names allow literal-typed expressions --- src/compiler/checker.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b7f0894d284..d33fc9ced56 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13526,6 +13526,7 @@ namespace ts { for (let i = 0; i < node.properties.length; i++) { const memberDecl = node.properties[i]; let member = memberDecl.symbol; + let literalName: __String | undefined; if (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || isObjectLiteralMethod(memberDecl)) { @@ -13536,6 +13537,12 @@ namespace ts { let type: Type; if (memberDecl.kind === SyntaxKind.PropertyAssignment) { + if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) { + const t = checkComputedPropertyName(memberDecl.name); + if (t.flags & TypeFlags.Literal) { + literalName = escapeLeadingUnderscores("" + (t as LiteralType).value); + } + } type = checkPropertyAssignment(memberDecl, checkMode); } else if (memberDecl.kind === SyntaxKind.MethodDeclaration) { @@ -13552,7 +13559,7 @@ namespace ts { } typeFlags |= type.flags; - const prop = createSymbol(SymbolFlags.Property | member.flags, member.escapedName); + const prop = createSymbol(SymbolFlags.Property | member.flags, literalName || member.escapedName); if (inDestructuringPattern) { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. @@ -13562,7 +13569,7 @@ namespace ts { if (isOptional) { prop.flags |= SymbolFlags.Optional; } - if (hasDynamicName(memberDecl)) { + if (!literalName && hasDynamicName(memberDecl)) { patternWithComputedProperties = true; } } @@ -13620,7 +13627,7 @@ namespace ts { checkNodeDeferred(memberDecl); } - if (hasDynamicName(memberDecl)) { + if (!literalName && hasDynamicName(memberDecl)) { if (isNumericName(memberDecl.name)) { hasComputedNumberProperty = true; } From 3c5b2a5e9d43c3f8b0f92e61208775ad9ffb5c05 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 11:41:13 -0700 Subject: [PATCH 53/74] Test Literal-typed computed property names in obj literals --- .../computedPropertyNames46_ES5.types | 4 +- .../computedPropertyNames46_ES6.types | 4 +- .../computedPropertyNames47_ES5.types | 4 +- .../computedPropertyNames47_ES6.types | 4 +- .../computedPropertyNames48_ES5.types | 4 +- .../computedPropertyNames48_ES6.types | 4 +- .../computedPropertyNames4_ES5.types | 4 +- .../computedPropertyNames4_ES6.types | 4 +- .../computedPropertyNames7_ES5.types | 4 +- .../computedPropertyNames7_ES6.types | 4 +- .../objectLiteralEnumPropertyNames.js | 108 +++++++++++ .../objectLiteralEnumPropertyNames.symbols | 144 ++++++++++++++ .../objectLiteralEnumPropertyNames.types | 177 ++++++++++++++++++ .../objectLiteralEnumPropertyNames.ts | 52 +++++ 14 files changed, 501 insertions(+), 20 deletions(-) create mode 100644 tests/baselines/reference/objectLiteralEnumPropertyNames.js create mode 100644 tests/baselines/reference/objectLiteralEnumPropertyNames.symbols create mode 100644 tests/baselines/reference/objectLiteralEnumPropertyNames.types create mode 100644 tests/cases/compiler/objectLiteralEnumPropertyNames.ts diff --git a/tests/baselines/reference/computedPropertyNames46_ES5.types b/tests/baselines/reference/computedPropertyNames46_ES5.types index 7ea3ffda244..e90d1a6c498 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES5.types +++ b/tests/baselines/reference/computedPropertyNames46_ES5.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES5.ts === var o = { ->o : { [x: number]: number; } ->{ ["" || 0]: 0} : { [x: number]: number; } +>o : { ["" || 0]: number; } +>{ ["" || 0]: 0} : { ["" || 0]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames46_ES6.types b/tests/baselines/reference/computedPropertyNames46_ES6.types index 3914f6facef..34aac7489c9 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES6.types +++ b/tests/baselines/reference/computedPropertyNames46_ES6.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES6.ts === var o = { ->o : { [x: number]: number; } ->{ ["" || 0]: 0} : { [x: number]: number; } +>o : { ["" || 0]: number; } +>{ ["" || 0]: 0} : { ["" || 0]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames47_ES5.types b/tests/baselines/reference/computedPropertyNames47_ES5.types index 137f3d63d38..9c01db09846 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES5.types +++ b/tests/baselines/reference/computedPropertyNames47_ES5.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { [x: number]: number; } ->{ [E1.x || E2.x]: 0} : { [x: number]: number; } +>o : { [E1.x || E2.x]: number; } +>{ [E1.x || E2.x]: 0} : { [E1.x || E2.x]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames47_ES6.types b/tests/baselines/reference/computedPropertyNames47_ES6.types index 04c18df83a7..c2e65523e46 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES6.types +++ b/tests/baselines/reference/computedPropertyNames47_ES6.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { [x: number]: number; } ->{ [E1.x || E2.x]: 0} : { [x: number]: number; } +>o : { [E1.x || E2.x]: number; } +>{ [E1.x || E2.x]: 0} : { [E1.x || E2.x]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames48_ES5.types b/tests/baselines/reference/computedPropertyNames48_ES5.types index 545dc641434..25818fff967 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES5.types +++ b/tests/baselines/reference/computedPropertyNames48_ES5.types @@ -28,7 +28,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ [E.x]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ [E.x]: ""} : { [x: number]: string; } +>{ [E.x]: ""} : { [E.x]: string; } [E.x]: "" >E.x : E @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { [x: number]: string; } +>{ ["" || 0]: ""} : { ["" || 0]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames48_ES6.types b/tests/baselines/reference/computedPropertyNames48_ES6.types index 0f352b57d24..65f93239f30 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES6.types +++ b/tests/baselines/reference/computedPropertyNames48_ES6.types @@ -28,7 +28,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ [E.x]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ [E.x]: ""} : { [x: number]: string; } +>{ [E.x]: ""} : { [E.x]: string; } [E.x]: "" >E.x : E @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { [x: number]: string; } +>{ ["" || 0]: ""} : { ["" || 0]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.types b/tests/baselines/reference/computedPropertyNames4_ES5.types index fc883aa2833..f0e105be4a7 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.types +++ b/tests/baselines/reference/computedPropertyNames4_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames4_ES6.types b/tests/baselines/reference/computedPropertyNames4_ES6.types index 5704841b97f..178eca88a72 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES6.types +++ b/tests/baselines/reference/computedPropertyNames4_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames7_ES5.types b/tests/baselines/reference/computedPropertyNames7_ES5.types index fbc070e3951..01c0117bd02 100644 --- a/tests/baselines/reference/computedPropertyNames7_ES5.types +++ b/tests/baselines/reference/computedPropertyNames7_ES5.types @@ -6,8 +6,8 @@ enum E { >member : E } var v = { ->v : { [x: number]: number; } ->{ [E.member]: 0} : { [x: number]: number; } +>v : { [E.member]: number; } +>{ [E.member]: 0} : { [E.member]: number; } [E.member]: 0 >E.member : E diff --git a/tests/baselines/reference/computedPropertyNames7_ES6.types b/tests/baselines/reference/computedPropertyNames7_ES6.types index f8f1dd7f791..80433c94ab3 100644 --- a/tests/baselines/reference/computedPropertyNames7_ES6.types +++ b/tests/baselines/reference/computedPropertyNames7_ES6.types @@ -6,8 +6,8 @@ enum E { >member : E } var v = { ->v : { [x: number]: number; } ->{ [E.member]: 0} : { [x: number]: number; } +>v : { [E.member]: number; } +>{ [E.member]: 0} : { [E.member]: number; } [E.member]: 0 >E.member : E diff --git a/tests/baselines/reference/objectLiteralEnumPropertyNames.js b/tests/baselines/reference/objectLiteralEnumPropertyNames.js new file mode 100644 index 00000000000..4a6f7128159 --- /dev/null +++ b/tests/baselines/reference/objectLiteralEnumPropertyNames.js @@ -0,0 +1,108 @@ +//// [objectLiteralEnumPropertyNames.ts] +// Fixes #16887 +enum Strs { + A = 'a', + B = 'b' +} +type TestStrs = { [key in Strs]: string } +const x: TestStrs = { + [Strs.A]: 'xo', + [Strs.B]: 'xe' +} +const ux = { + [Strs.A]: 'xo', + [Strs.B]: 'xe' +} +const y: TestStrs = { + ['a']: 'yo', + ['b']: 'ye' +} +const a = 'a'; +const b = 'b'; +const z: TestStrs = { + [a]: 'zo', + [b]: 'ze' +} +const uz = { + [a]: 'zo', + [b]: 'ze' +} + +enum Nums { + A, + B +} +type TestNums = { 0: number, 1: number } +const n: TestNums = { + [Nums.A]: 1, + [Nums.B]: 2 +} +const un = { + [Nums.A]: 3, + [Nums.B]: 4 +} +const an = 0; +const bn = 1; +const m: TestNums = { + [an]: 5, + [bn]: 6 +} +const um = { + [an]: 7, + [bn]: 8 +} + + +//// [objectLiteralEnumPropertyNames.js] +// Fixes #16887 +var Strs; +(function (Strs) { + Strs["A"] = "a"; + Strs["B"] = "b"; +})(Strs || (Strs = {})); +var x = (_a = {}, + _a[Strs.A] = 'xo', + _a[Strs.B] = 'xe', + _a); +var ux = (_b = {}, + _b[Strs.A] = 'xo', + _b[Strs.B] = 'xe', + _b); +var y = (_c = {}, + _c['a'] = 'yo', + _c['b'] = 'ye', + _c); +var a = 'a'; +var b = 'b'; +var z = (_d = {}, + _d[a] = 'zo', + _d[b] = 'ze', + _d); +var uz = (_e = {}, + _e[a] = 'zo', + _e[b] = 'ze', + _e); +var Nums; +(function (Nums) { + Nums[Nums["A"] = 0] = "A"; + Nums[Nums["B"] = 1] = "B"; +})(Nums || (Nums = {})); +var n = (_f = {}, + _f[Nums.A] = 1, + _f[Nums.B] = 2, + _f); +var un = (_g = {}, + _g[Nums.A] = 3, + _g[Nums.B] = 4, + _g); +var an = 0; +var bn = 1; +var m = (_h = {}, + _h[an] = 5, + _h[bn] = 6, + _h); +var um = (_j = {}, + _j[an] = 7, + _j[bn] = 8, + _j); +var _a, _b, _c, _d, _e, _f, _g, _h, _j; diff --git a/tests/baselines/reference/objectLiteralEnumPropertyNames.symbols b/tests/baselines/reference/objectLiteralEnumPropertyNames.symbols new file mode 100644 index 00000000000..594af3c3f99 --- /dev/null +++ b/tests/baselines/reference/objectLiteralEnumPropertyNames.symbols @@ -0,0 +1,144 @@ +=== tests/cases/compiler/objectLiteralEnumPropertyNames.ts === +// Fixes #16887 +enum Strs { +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) + + A = 'a', +>A : Symbol(Strs.A, Decl(objectLiteralEnumPropertyNames.ts, 1, 11)) + + B = 'b' +>B : Symbol(Strs.B, Decl(objectLiteralEnumPropertyNames.ts, 2, 12)) +} +type TestStrs = { [key in Strs]: string } +>TestStrs : Symbol(TestStrs, Decl(objectLiteralEnumPropertyNames.ts, 4, 1)) +>key : Symbol(key, Decl(objectLiteralEnumPropertyNames.ts, 5, 19)) +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) + +const x: TestStrs = { +>x : Symbol(x, Decl(objectLiteralEnumPropertyNames.ts, 6, 5)) +>TestStrs : Symbol(TestStrs, Decl(objectLiteralEnumPropertyNames.ts, 4, 1)) + + [Strs.A]: 'xo', +>Strs.A : Symbol(Strs.A, Decl(objectLiteralEnumPropertyNames.ts, 1, 11)) +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) +>A : Symbol(Strs.A, Decl(objectLiteralEnumPropertyNames.ts, 1, 11)) + + [Strs.B]: 'xe' +>Strs.B : Symbol(Strs.B, Decl(objectLiteralEnumPropertyNames.ts, 2, 12)) +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) +>B : Symbol(Strs.B, Decl(objectLiteralEnumPropertyNames.ts, 2, 12)) +} +const ux = { +>ux : Symbol(ux, Decl(objectLiteralEnumPropertyNames.ts, 10, 5)) + + [Strs.A]: 'xo', +>Strs.A : Symbol(Strs.A, Decl(objectLiteralEnumPropertyNames.ts, 1, 11)) +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) +>A : Symbol(Strs.A, Decl(objectLiteralEnumPropertyNames.ts, 1, 11)) + + [Strs.B]: 'xe' +>Strs.B : Symbol(Strs.B, Decl(objectLiteralEnumPropertyNames.ts, 2, 12)) +>Strs : Symbol(Strs, Decl(objectLiteralEnumPropertyNames.ts, 0, 0)) +>B : Symbol(Strs.B, Decl(objectLiteralEnumPropertyNames.ts, 2, 12)) +} +const y: TestStrs = { +>y : Symbol(y, Decl(objectLiteralEnumPropertyNames.ts, 14, 5)) +>TestStrs : Symbol(TestStrs, Decl(objectLiteralEnumPropertyNames.ts, 4, 1)) + + ['a']: 'yo', +>'a' : Symbol(['a'], Decl(objectLiteralEnumPropertyNames.ts, 14, 21)) + + ['b']: 'ye' +>'b' : Symbol(['b'], Decl(objectLiteralEnumPropertyNames.ts, 15, 16)) +} +const a = 'a'; +>a : Symbol(a, Decl(objectLiteralEnumPropertyNames.ts, 18, 5)) + +const b = 'b'; +>b : Symbol(b, Decl(objectLiteralEnumPropertyNames.ts, 19, 5)) + +const z: TestStrs = { +>z : Symbol(z, Decl(objectLiteralEnumPropertyNames.ts, 20, 5)) +>TestStrs : Symbol(TestStrs, Decl(objectLiteralEnumPropertyNames.ts, 4, 1)) + + [a]: 'zo', +>a : Symbol(a, Decl(objectLiteralEnumPropertyNames.ts, 18, 5)) + + [b]: 'ze' +>b : Symbol(b, Decl(objectLiteralEnumPropertyNames.ts, 19, 5)) +} +const uz = { +>uz : Symbol(uz, Decl(objectLiteralEnumPropertyNames.ts, 24, 5)) + + [a]: 'zo', +>a : Symbol(a, Decl(objectLiteralEnumPropertyNames.ts, 18, 5)) + + [b]: 'ze' +>b : Symbol(b, Decl(objectLiteralEnumPropertyNames.ts, 19, 5)) +} + +enum Nums { +>Nums : Symbol(Nums, Decl(objectLiteralEnumPropertyNames.ts, 27, 1)) + + A, +>A : Symbol(Nums.A, Decl(objectLiteralEnumPropertyNames.ts, 29, 11)) + + B +>B : Symbol(Nums.B, Decl(objectLiteralEnumPropertyNames.ts, 30, 6)) +} +type TestNums = { 0: number, 1: number } +>TestNums : Symbol(TestNums, Decl(objectLiteralEnumPropertyNames.ts, 32, 1)) + +const n: TestNums = { +>n : Symbol(n, Decl(objectLiteralEnumPropertyNames.ts, 34, 5)) +>TestNums : Symbol(TestNums, Decl(objectLiteralEnumPropertyNames.ts, 32, 1)) + + [Nums.A]: 1, +>Nums.A : Symbol(Nums.A, Decl(objectLiteralEnumPropertyNames.ts, 29, 11)) +>Nums : Symbol(Nums, Decl(objectLiteralEnumPropertyNames.ts, 27, 1)) +>A : Symbol(Nums.A, Decl(objectLiteralEnumPropertyNames.ts, 29, 11)) + + [Nums.B]: 2 +>Nums.B : Symbol(Nums.B, Decl(objectLiteralEnumPropertyNames.ts, 30, 6)) +>Nums : Symbol(Nums, Decl(objectLiteralEnumPropertyNames.ts, 27, 1)) +>B : Symbol(Nums.B, Decl(objectLiteralEnumPropertyNames.ts, 30, 6)) +} +const un = { +>un : Symbol(un, Decl(objectLiteralEnumPropertyNames.ts, 38, 5)) + + [Nums.A]: 3, +>Nums.A : Symbol(Nums.A, Decl(objectLiteralEnumPropertyNames.ts, 29, 11)) +>Nums : Symbol(Nums, Decl(objectLiteralEnumPropertyNames.ts, 27, 1)) +>A : Symbol(Nums.A, Decl(objectLiteralEnumPropertyNames.ts, 29, 11)) + + [Nums.B]: 4 +>Nums.B : Symbol(Nums.B, Decl(objectLiteralEnumPropertyNames.ts, 30, 6)) +>Nums : Symbol(Nums, Decl(objectLiteralEnumPropertyNames.ts, 27, 1)) +>B : Symbol(Nums.B, Decl(objectLiteralEnumPropertyNames.ts, 30, 6)) +} +const an = 0; +>an : Symbol(an, Decl(objectLiteralEnumPropertyNames.ts, 42, 5)) + +const bn = 1; +>bn : Symbol(bn, Decl(objectLiteralEnumPropertyNames.ts, 43, 5)) + +const m: TestNums = { +>m : Symbol(m, Decl(objectLiteralEnumPropertyNames.ts, 44, 5)) +>TestNums : Symbol(TestNums, Decl(objectLiteralEnumPropertyNames.ts, 32, 1)) + + [an]: 5, +>an : Symbol(an, Decl(objectLiteralEnumPropertyNames.ts, 42, 5)) + + [bn]: 6 +>bn : Symbol(bn, Decl(objectLiteralEnumPropertyNames.ts, 43, 5)) +} +const um = { +>um : Symbol(um, Decl(objectLiteralEnumPropertyNames.ts, 48, 5)) + + [an]: 7, +>an : Symbol(an, Decl(objectLiteralEnumPropertyNames.ts, 42, 5)) + + [bn]: 8 +>bn : Symbol(bn, Decl(objectLiteralEnumPropertyNames.ts, 43, 5)) +} + diff --git a/tests/baselines/reference/objectLiteralEnumPropertyNames.types b/tests/baselines/reference/objectLiteralEnumPropertyNames.types new file mode 100644 index 00000000000..460d96bc56d --- /dev/null +++ b/tests/baselines/reference/objectLiteralEnumPropertyNames.types @@ -0,0 +1,177 @@ +=== tests/cases/compiler/objectLiteralEnumPropertyNames.ts === +// Fixes #16887 +enum Strs { +>Strs : Strs + + A = 'a', +>A : Strs.A +>'a' : "a" + + B = 'b' +>B : Strs.B +>'b' : "b" +} +type TestStrs = { [key in Strs]: string } +>TestStrs : TestStrs +>key : key +>Strs : Strs + +const x: TestStrs = { +>x : TestStrs +>TestStrs : TestStrs +>{ [Strs.A]: 'xo', [Strs.B]: 'xe'} : { [Strs.A]: string; [Strs.B]: string; } + + [Strs.A]: 'xo', +>Strs.A : Strs.A +>Strs : typeof Strs +>A : Strs.A +>'xo' : "xo" + + [Strs.B]: 'xe' +>Strs.B : Strs.B +>Strs : typeof Strs +>B : Strs.B +>'xe' : "xe" +} +const ux = { +>ux : { [Strs.A]: string; [Strs.B]: string; } +>{ [Strs.A]: 'xo', [Strs.B]: 'xe'} : { [Strs.A]: string; [Strs.B]: string; } + + [Strs.A]: 'xo', +>Strs.A : Strs.A +>Strs : typeof Strs +>A : Strs.A +>'xo' : "xo" + + [Strs.B]: 'xe' +>Strs.B : Strs.B +>Strs : typeof Strs +>B : Strs.B +>'xe' : "xe" +} +const y: TestStrs = { +>y : TestStrs +>TestStrs : TestStrs +>{ ['a']: 'yo', ['b']: 'ye'} : { ['a']: string; ['b']: string; } + + ['a']: 'yo', +>'a' : "a" +>'yo' : "yo" + + ['b']: 'ye' +>'b' : "b" +>'ye' : "ye" +} +const a = 'a'; +>a : "a" +>'a' : "a" + +const b = 'b'; +>b : "b" +>'b' : "b" + +const z: TestStrs = { +>z : TestStrs +>TestStrs : TestStrs +>{ [a]: 'zo', [b]: 'ze'} : { [a]: string; [b]: string; } + + [a]: 'zo', +>a : "a" +>'zo' : "zo" + + [b]: 'ze' +>b : "b" +>'ze' : "ze" +} +const uz = { +>uz : { [a]: string; [b]: string; } +>{ [a]: 'zo', [b]: 'ze'} : { [a]: string; [b]: string; } + + [a]: 'zo', +>a : "a" +>'zo' : "zo" + + [b]: 'ze' +>b : "b" +>'ze' : "ze" +} + +enum Nums { +>Nums : Nums + + A, +>A : Nums.A + + B +>B : Nums.B +} +type TestNums = { 0: number, 1: number } +>TestNums : TestNums + +const n: TestNums = { +>n : TestNums +>TestNums : TestNums +>{ [Nums.A]: 1, [Nums.B]: 2} : { [Nums.A]: number; [Nums.B]: number; } + + [Nums.A]: 1, +>Nums.A : Nums.A +>Nums : typeof Nums +>A : Nums.A +>1 : 1 + + [Nums.B]: 2 +>Nums.B : Nums.B +>Nums : typeof Nums +>B : Nums.B +>2 : 2 +} +const un = { +>un : { [Nums.A]: number; [Nums.B]: number; } +>{ [Nums.A]: 3, [Nums.B]: 4} : { [Nums.A]: number; [Nums.B]: number; } + + [Nums.A]: 3, +>Nums.A : Nums.A +>Nums : typeof Nums +>A : Nums.A +>3 : 3 + + [Nums.B]: 4 +>Nums.B : Nums.B +>Nums : typeof Nums +>B : Nums.B +>4 : 4 +} +const an = 0; +>an : 0 +>0 : 0 + +const bn = 1; +>bn : 1 +>1 : 1 + +const m: TestNums = { +>m : TestNums +>TestNums : TestNums +>{ [an]: 5, [bn]: 6} : { [an]: number; [bn]: number; } + + [an]: 5, +>an : 0 +>5 : 5 + + [bn]: 6 +>bn : 1 +>6 : 6 +} +const um = { +>um : { [an]: number; [bn]: number; } +>{ [an]: 7, [bn]: 8} : { [an]: number; [bn]: number; } + + [an]: 7, +>an : 0 +>7 : 7 + + [bn]: 8 +>bn : 1 +>8 : 8 +} + diff --git a/tests/cases/compiler/objectLiteralEnumPropertyNames.ts b/tests/cases/compiler/objectLiteralEnumPropertyNames.ts new file mode 100644 index 00000000000..0f698d9c51d --- /dev/null +++ b/tests/cases/compiler/objectLiteralEnumPropertyNames.ts @@ -0,0 +1,52 @@ +// Fixes #16887 +enum Strs { + A = 'a', + B = 'b' +} +type TestStrs = { [key in Strs]: string } +const x: TestStrs = { + [Strs.A]: 'xo', + [Strs.B]: 'xe' +} +const ux = { + [Strs.A]: 'xo', + [Strs.B]: 'xe' +} +const y: TestStrs = { + ['a']: 'yo', + ['b']: 'ye' +} +const a = 'a'; +const b = 'b'; +const z: TestStrs = { + [a]: 'zo', + [b]: 'ze' +} +const uz = { + [a]: 'zo', + [b]: 'ze' +} + +enum Nums { + A, + B +} +type TestNums = { 0: number, 1: number } +const n: TestNums = { + [Nums.A]: 1, + [Nums.B]: 2 +} +const un = { + [Nums.A]: 3, + [Nums.B]: 4 +} +const an = 0; +const bn = 1; +const m: TestNums = { + [an]: 5, + [bn]: 6 +} +const um = { + [an]: 7, + [bn]: 8 +} From 727facb55c9dc2f5e924d1303d82fb3e63264dd3 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Thu, 7 Sep 2017 21:15:28 +0200 Subject: [PATCH 54/74] fix initialization of shouldCreateNewSourceFiles (#17686) --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 1feafdd55f5..197f76b607f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1143,7 +1143,7 @@ namespace ts { oldSettings.noResolve !== newSettings.noResolve || oldSettings.jsx !== newSettings.jsx || oldSettings.allowJs !== newSettings.allowJs || - oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit || + oldSettings.disableSizeLimit !== newSettings.disableSizeLimit || oldSettings.baseUrl !== newSettings.baseUrl || !equalOwnProperties(oldSettings.paths, newSettings.paths)); From de940af23bdf88893cad7eb3e163335d03ae44d9 Mon Sep 17 00:00:00 2001 From: Zeeshan Ahmed Date: Thu, 7 Sep 2017 12:20:56 -0700 Subject: [PATCH 55/74] Update README.md (#17714) --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 23829a74d39..4cd1efe2fb0 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ For the latest stable version: -``` +```bash npm install -g typescript ``` For our nightly builds: -``` +```bash npm install -g typescript@next ``` @@ -50,26 +50,26 @@ In order to build the TypeScript compiler, ensure that you have [Git](https://gi Clone a copy of the repo: -``` +```bash git clone https://github.com/Microsoft/TypeScript.git ``` Change to the TypeScript directory: -``` +```bash cd TypeScript ``` Install Gulp tools and dev dependencies: -``` +```bash npm install -g gulp npm install ``` Use one of the following to build and test: -``` +```bash gulp local # Build the compiler into built/local gulp clean # Delete the built compiler gulp LKG # Replace the last known good with the built one. @@ -88,7 +88,7 @@ gulp help # List the above commands. ## Usage -```shell +```bash node built/local/tsc.js hello.ts ``` From b29e0c9e3ab247199eed6b69674a2c992c3a05a6 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 7 Sep 2017 12:21:33 -0700 Subject: [PATCH 56/74] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cd1efe2fb0..fd9926d2dfa 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ npm install Use one of the following to build and test: -```bash +``` gulp local # Build the compiler into built/local gulp clean # Delete the built compiler gulp LKG # Replace the last known good with the built one. From 6695255d8610a475260cded3535b00fddc2f32eb Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Sep 2017 12:26:23 -0700 Subject: [PATCH 57/74] Allow trailing newline to have fake position (#18298) * Actually support baselining pretty in the harness * Test case from 18216 * Use host newline in formatDiagnosticsWithColorAndContext * Merge statements --- src/compiler/program.ts | 16 ++++++++-------- src/compiler/scanner.ts | 2 +- src/harness/compilerRunner.ts | 2 +- src/harness/harness.ts | 13 +++++++------ .../prettyContextNotDebugAssertion.errors.txt | 12 ++++++++++++ .../reference/prettyContextNotDebugAssertion.js | 7 +++++++ .../compiler/prettyContextNotDebugAssertion.ts | 3 +++ 7 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt create mode 100644 tests/baselines/reference/prettyContextNotDebugAssertion.js create mode 100644 tests/cases/compiler/prettyContextNotDebugAssertion.ts diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ec220ad248e..7932c6874d9 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -268,7 +268,7 @@ namespace ts { return s; } - export function formatDiagnosticsWithColorAndContext(diagnostics: Diagnostic[], host: FormatDiagnosticsHost): string { + export function formatDiagnosticsWithColorAndContext(diagnostics: ReadonlyArray, host: FormatDiagnosticsHost): string { let output = ""; for (const diagnostic of diagnostics) { if (diagnostic.file) { @@ -284,12 +284,12 @@ namespace ts { gutterWidth = Math.max(ellipsis.length, gutterWidth); } - output += sys.newLine; + output += host.getNewLine(); for (let i = firstLine; i <= lastLine; i++) { // If the error spans over 5 lines, we'll only show the first 2 and last 2 lines, // so we'll skip ahead to the second-to-last line. if (hasMoreThanFiveLines && firstLine + 1 < i && i < lastLine - 1) { - output += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + sys.newLine; + output += formatAndReset(padLeft(ellipsis, gutterWidth), gutterStyleSequence) + gutterSeparator + host.getNewLine(); i = lastLine - 1; } @@ -301,7 +301,7 @@ namespace ts { // Output the gutter and the actual contents of the line. output += formatAndReset(padLeft(i + 1 + "", gutterWidth), gutterStyleSequence) + gutterSeparator; - output += lineContent + sys.newLine; + output += lineContent + host.getNewLine(); // Output the gutter and the error span for the line using tildes. output += formatAndReset(padLeft("", gutterWidth), gutterStyleSequence) + gutterSeparator; @@ -323,17 +323,17 @@ namespace ts { } output += resetEscapeSequence; - output += sys.newLine; + output += host.getNewLine(); } - output += sys.newLine; + output += host.getNewLine(); output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `; } const categoryColor = getCategoryFormat(diagnostic.category); const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`; - output += sys.newLine; + output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()) }`; + output += host.getNewLine(); } return output; } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index a130d8427da..c9c14198279 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -337,7 +337,7 @@ namespace ts { Debug.assert(res < lineStarts[line + 1]); } else if (debugText !== undefined) { - Debug.assert(res < debugText.length); + Debug.assert(res <= debugText.length); // Allow single character overflow for trailing newline } return res; } diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 170a23e34f2..a600c7dd857 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -141,7 +141,7 @@ class CompilerBaselineRunner extends RunnerBase { // check errors it("Correct errors for " + fileName, () => { - Harness.Compiler.doErrorBaseline(justName, tsConfigFiles.concat(toBeCompiled, otherFiles), result.errors); + Harness.Compiler.doErrorBaseline(justName, tsConfigFiles.concat(toBeCompiled, otherFiles), result.errors, !!options.pretty); }); it (`Correct module resolution tracing for ${fileName}`, () => { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 9443844cf9a..2fc1aac2d83 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1284,11 +1284,12 @@ namespace Harness { return normalized; } - export function minimalDiagnosticsToString(diagnostics: ReadonlyArray) { - return ts.formatDiagnostics(diagnostics, { getCanonicalFileName, getCurrentDirectory: () => "", getNewLine: () => Harness.IO.newLine() }); + export function minimalDiagnosticsToString(diagnostics: ReadonlyArray, pretty?: boolean) { + const host = { getCanonicalFileName, getCurrentDirectory: () => "", getNewLine: () => Harness.IO.newLine() }; + return (pretty ? ts.formatDiagnosticsWithColorAndContext : ts.formatDiagnostics)(diagnostics, host); } - export function getErrorBaseline(inputFiles: ReadonlyArray, diagnostics: ReadonlyArray) { + export function getErrorBaseline(inputFiles: ReadonlyArray, diagnostics: ReadonlyArray, pretty?: boolean) { diagnostics = diagnostics.slice().sort(ts.compareDiagnostics); let outputLines = ""; // Count up all errors that were found in files other than lib.d.ts so we don't miss any @@ -1408,18 +1409,18 @@ namespace Harness { // Verify we didn't miss any errors in total assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors"); - return minimalDiagnosticsToString(diagnostics) + + return minimalDiagnosticsToString(diagnostics, pretty) + Harness.IO.newLine() + Harness.IO.newLine() + outputLines; } - export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) { + export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[], pretty?: boolean) { Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => { if (!errors || (errors.length === 0)) { /* tslint:disable:no-null-keyword */ return null; /* tslint:enable:no-null-keyword */ } - return getErrorBaseline(inputFiles, errors); + return getErrorBaseline(inputFiles, errors, pretty); }); } diff --git a/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt new file mode 100644 index 00000000000..7b7e3fea3e3 --- /dev/null +++ b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt @@ -0,0 +1,12 @@ + +2 +   + +tests/cases/compiler/index.ts(2,1): error TS1005: '}' expected. + + +==== tests/cases/compiler/index.ts (1 errors) ==== + if (true) { + + +!!! error TS1005: '}' expected. \ No newline at end of file diff --git a/tests/baselines/reference/prettyContextNotDebugAssertion.js b/tests/baselines/reference/prettyContextNotDebugAssertion.js new file mode 100644 index 00000000000..1051f76864c --- /dev/null +++ b/tests/baselines/reference/prettyContextNotDebugAssertion.js @@ -0,0 +1,7 @@ +//// [index.ts] +if (true) { + + +//// [index.js] +if (true) { +} diff --git a/tests/cases/compiler/prettyContextNotDebugAssertion.ts b/tests/cases/compiler/prettyContextNotDebugAssertion.ts new file mode 100644 index 00000000000..d65b02d472f --- /dev/null +++ b/tests/cases/compiler/prettyContextNotDebugAssertion.ts @@ -0,0 +1,3 @@ +// @pretty: true +// @filename: index.ts +if (true) { From 508cde0ea12a86668d8c893a0356cf2c7320619a Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 12:39:13 -0700 Subject: [PATCH 58/74] Document assignment to aliasSymbol in getUnionTypeFromSortedList (#17434) * Document assignment to aliasSymbol in getUnionTypeFromSortedList * Update wording --- src/compiler/checker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 91653c140c8..8547fc7e176 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7435,6 +7435,12 @@ namespace ts { type = createType(TypeFlags.Union | propagatedFlags); unionTypes.set(id, type); type.types = types; + /* + Note: This is the alias symbol (or lack thereof) that we see when we first encounter this union type. + For aliases of identical unions, eg `type T = A | B; type U = A | B`, the symbol of the first alias encountered is the aliasSymbol. + (In the language service, the order may depend on the order in which a user takes actions, such as hovering over symbols.) + It's important that we create equivalent union types only once, so that's an unfortunate side effect. + */ type.aliasSymbol = aliasSymbol; type.aliasTypeArguments = aliasTypeArguments; } @@ -7528,7 +7534,7 @@ namespace ts { type = createType(TypeFlags.Intersection | propagatedFlags); intersectionTypes.set(id, type); type.types = typeSet; - type.aliasSymbol = aliasSymbol; + type.aliasSymbol = aliasSymbol; // See comment in `getUnionTypeFromSortedList`. type.aliasTypeArguments = aliasTypeArguments; } return type; From 1b5a0aed93f617d63627cb6d7c5c104d4f4dfdc9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Sep 2017 12:47:09 -0700 Subject: [PATCH 59/74] Update pretty baseline changed by #17675 (#18320) --- .../reference/prettyContextNotDebugAssertion.errors.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt index 7b7e3fea3e3..9cac1423f3f 100644 --- a/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt +++ b/tests/baselines/reference/prettyContextNotDebugAssertion.errors.txt @@ -1,6 +1,6 @@ -2 -   +2 +   tests/cases/compiler/index.ts(2,1): error TS1005: '}' expected. From ed4e2e6e3b66e43ce3e4807be342f3b235e0bb73 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 14:30:19 -0700 Subject: [PATCH 60/74] Ensure that emitter calls callbacks (#18284) * Ensure that emitter calls calbacks * Move new parameter to end of parameters * Fix for ConditionalExpression * Make suggested changes to emitter * Fix parameter ordering * Respond to minor comments * Remove potentially expensive assertion * More emitter cleanup --- src/compiler/emitter.ts | 123 ++++++++-------- src/compiler/factory.ts | 60 +++++++- src/compiler/transformers/es2017.ts | 3 +- src/compiler/transformers/esnext.ts | 3 +- src/compiler/transformers/ts.ts | 3 +- src/compiler/types.ts | 9 +- src/compiler/utilities.ts | 3 +- src/compiler/visitor.ts | 3 + src/services/formatting/formatting.ts | 1 + src/services/refactors/extractMethod.ts | 6 +- src/services/textChanges.ts | 28 ++-- .../reference/extractMethod/extractMethod4.ts | 24 ++-- .../sourceMapValidationStatements.js.map | 2 +- ...ourceMapValidationStatements.sourcemap.txt | 132 +++++++++++------- .../ternaryExpressionSourceMap.js.map | 2 +- .../ternaryExpressionSourceMap.sourcemap.txt | 90 ++++++------ ...ypeGuardsInRightOperandOfAndAndOperator.js | 2 + .../typeGuardsInRightOperandOfOrOrOperator.js | 2 + .../fourslash/extract-method-formatting.ts | 24 ++++ tests/cases/fourslash/extract-method5.ts | 2 +- 20 files changed, 325 insertions(+), 197 deletions(-) create mode 100644 tests/cases/fourslash/extract-method-formatting.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 166e4751983..5abeecd4107 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -406,6 +406,14 @@ namespace ts { setWriter(/*output*/ undefined); } + // TODO: Should this just be `emit`? + // See https://github.com/Microsoft/TypeScript/pull/18284#discussion_r137611034 + function emitIfPresent(node: Node | undefined) { + if (node) { + emit(node); + } + } + function emit(node: Node) { pipelineEmitWithNotification(EmitHint.Unspecified, node); } @@ -451,6 +459,7 @@ namespace ts { case EmitHint.SourceFile: return pipelineEmitSourceFile(node); case EmitHint.IdentifierName: return pipelineEmitIdentifierName(node); case EmitHint.Expression: return pipelineEmitExpression(node); + case EmitHint.MappedTypeParameter: return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); case EmitHint.Unspecified: return pipelineEmitUnspecified(node); } } @@ -465,6 +474,12 @@ namespace ts { emitIdentifier(node); } + function emitMappedTypeParameter(node: TypeParameterDeclaration): void { + emit(node.name); + write(" in "); + emit(node.constraint); + } + function pipelineEmitUnspecified(node: Node): void { const kind = node.kind; @@ -898,9 +913,9 @@ namespace ts { function emitParameter(node: ParameterDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - writeIfPresent(node.dotDotDotToken, "..."); + emitIfPresent(node.dotDotDotToken); emit(node.name); - writeIfPresent(node.questionToken, "?"); + emitIfPresent(node.questionToken); emitWithPrefix(": ", node.type); emitExpressionWithPrefix(" = ", node.initializer); } @@ -918,7 +933,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); - writeIfPresent(node.questionToken, "?"); + emitIfPresent(node.questionToken); emitWithPrefix(": ", node.type); write(";"); } @@ -927,7 +942,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); - writeIfPresent(node.questionToken, "?"); + emitIfPresent(node.questionToken); emitWithPrefix(": ", node.type); emitExpressionWithPrefix(" = ", node.initializer); write(";"); @@ -937,7 +952,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); - writeIfPresent(node.questionToken, "?"); + emitIfPresent(node.questionToken); emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitWithPrefix(": ", node.type); @@ -947,9 +962,9 @@ namespace ts { function emitMethodDeclaration(node: MethodDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - writeIfPresent(node.asteriskToken, "*"); + emitIfPresent(node.asteriskToken); emit(node.name); - writeIfPresent(node.questionToken, "?"); + emitIfPresent(node.questionToken); emitSignatureAndBody(node, emitSignatureHead); } @@ -1035,10 +1050,8 @@ namespace ts { function emitTypeLiteral(node: TypeLiteralNode) { write("{"); - // If the literal is empty, do not add spaces between braces. - if (node.members.length > 0) { - emitList(node, node.members, getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers); - } + const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTypeLiteralMembers : ListFormat.MultiLineTypeLiteralMembers; + emitList(node, node.members, flags | ListFormat.NoSpaceIfEmpty); write("}"); } @@ -1094,13 +1107,16 @@ namespace ts { writeLine(); increaseIndent(); } - writeIfPresent(node.readonlyToken, "readonly "); + if (node.readonlyToken) { + emit(node.readonlyToken); + write(" "); + } + write("["); - emit(node.typeParameter.name); - write(" in "); - emit(node.typeParameter.constraint); + pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter); write("]"); - writeIfPresent(node.questionToken, "?"); + + emitIfPresent(node.questionToken); write(": "); emit(node.type); write(";"); @@ -1148,7 +1164,7 @@ namespace ts { function emitBindingElement(node: BindingElement) { emitWithSuffix(node.propertyName, ": "); - writeIfPresent(node.dotDotDotToken, "..."); + emitIfPresent(node.dotDotDotToken); emit(node.name); emitExpressionWithPrefix(" = ", node.initializer); } @@ -1159,33 +1175,22 @@ namespace ts { function emitArrayLiteralExpression(node: ArrayLiteralExpression) { const elements = node.elements; - if (elements.length === 0) { - write("[]"); - } - else { - const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); - } + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); } function emitObjectLiteralExpression(node: ObjectLiteralExpression) { - const properties = node.properties; - if (properties.length === 0) { - write("{}"); + const indentedFlag = getEmitFlags(node) & EmitFlags.Indented; + if (indentedFlag) { + increaseIndent(); } - else { - const indentedFlag = getEmitFlags(node) & EmitFlags.Indented; - if (indentedFlag) { - increaseIndent(); - } - const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; - const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; - emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; + emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); - if (indentedFlag) { - decreaseIndent(); - } + if (indentedFlag) { + decreaseIndent(); } } @@ -1286,7 +1291,8 @@ namespace ts { emitTypeParameters(node, node.typeParameters); emitParametersForArrow(node, node.parameters); emitWithPrefix(": ", node.type); - write(" =>"); + write(" "); + emit(node.equalsGreaterThanToken); } function emitDeleteExpression(node: DeleteExpression) { @@ -1364,13 +1370,13 @@ namespace ts { emitExpression(node.condition); increaseIndentIf(indentBeforeQuestion, " "); - write("?"); + emit(node.questionToken); increaseIndentIf(indentAfterQuestion, " "); emitExpression(node.whenTrue); decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion); increaseIndentIf(indentBeforeColon, " "); - write(":"); + emit(node.colonToken); increaseIndentIf(indentAfterColon, " "); emitExpression(node.whenFalse); decreaseIndentIf(indentBeforeColon, indentAfterColon); @@ -1382,7 +1388,8 @@ namespace ts { } function emitYieldExpression(node: YieldExpression) { - write(node.asteriskToken ? "yield*" : "yield"); + write("yield"); + emit(node.asteriskToken); emitExpressionWithPrefix(" ", node.expression); } @@ -1662,7 +1669,9 @@ namespace ts { function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - write(node.asteriskToken ? "function* " : "function "); + write("function"); + emitIfPresent(node.asteriskToken); + write(" "); emitIdentifierName(node.name); emitSignatureAndBody(node, emitSignatureHead); } @@ -2068,9 +2077,7 @@ namespace ts { function emitJsxExpression(node: JsxExpression) { if (node.expression) { write("{"); - if (node.dotDotDotToken) { - write("..."); - } + emitIfPresent(node.dotDotDotToken); emitExpression(node.expression); write("}"); } @@ -2128,13 +2135,12 @@ namespace ts { emitTrailingCommentsOfPosition(statements.pos); } + let format = ListFormat.CaseOrDefaultClauseStatements; if (emitAsSingleStatement) { write(" "); - emit(statements[0]); - } - else { - emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements); + format &= ~(ListFormat.MultiLine | ListFormat.Indented); } + emitList(parentNode, statements, format); } function emitHeritageClause(node: HeritageClause) { @@ -2384,7 +2390,7 @@ namespace ts { function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { if (canEmitSimpleArrowHead(parentNode, parameters)) { - emit(parameters[0]); + emitList(parentNode, parameters, ListFormat.Parameters & ~ListFormat.Parenthesis); } else { emitParameters(parentNode, parameters); @@ -2427,7 +2433,7 @@ namespace ts { if (format & ListFormat.MultiLine) { writeLine(); } - else if (format & ListFormat.SpaceBetweenBraces) { + else if (format & ListFormat.SpaceBetweenBraces && !(format & ListFormat.NoSpaceIfEmpty)) { write(" "); } } @@ -2568,12 +2574,6 @@ namespace ts { } } - function writeIfPresent(node: Node, text: string) { - if (node) { - write(text); - } - } - function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) { return onEmitSourceMapOfToken ? onEmitSourceMapOfToken(contextNode, token, pos, writeTokenText) @@ -2584,7 +2584,7 @@ namespace ts { if (onBeforeEmitToken) { onBeforeEmitToken(node); } - writeTokenText(node.kind); + write(tokenToString(node.kind)); if (onAfterEmitToken) { onAfterEmitToken(node); } @@ -3107,6 +3107,9 @@ namespace ts { NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list. NoInterveningComments = 1 << 17, // Do not emit comments between each node + NoSpaceIfEmpty = 1 << 18, // If the literal is empty, do not add spaces between braces. + SingleElement = 1 << 19, + // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings | NoInterveningComments, HeritageClauses = SingleLine | SpaceBetweenSiblings, @@ -3118,7 +3121,7 @@ namespace ts { IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings, ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, - ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces, + ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces | NoSpaceIfEmpty, ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets, CommaListElements = CommaDelimited | SpaceBetweenSiblings | SingleLine, CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 4492c3ed474..2bf6d6e879d 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -281,7 +281,7 @@ namespace ts { || node.questionToken !== questionToken || node.type !== type || node.initializer !== initializer - ? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer), node) + ? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, questionToken, type, initializer), node) : node; } @@ -1016,19 +1016,49 @@ namespace ts { return node; } + /* @deprecated */ export function updateArrowFunction( + node: ArrowFunction, + modifiers: ReadonlyArray | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + body: ConciseBody): ArrowFunction; export function updateArrowFunction( node: ArrowFunction, modifiers: ReadonlyArray | undefined, typeParameters: ReadonlyArray | undefined, parameters: ReadonlyArray, type: TypeNode | undefined, - body: ConciseBody) { + equalsGreaterThanToken: Token, + body: ConciseBody): ArrowFunction; + export function updateArrowFunction( + node: ArrowFunction, + modifiers: ReadonlyArray | undefined, + typeParameters: ReadonlyArray | undefined, + parameters: ReadonlyArray, + type: TypeNode | undefined, + equalsGreaterThanTokenOrBody: Token | ConciseBody, + bodyOrUndefined?: ConciseBody, + ): ArrowFunction { + let equalsGreaterThanToken: Token; + let body: ConciseBody; + if (bodyOrUndefined === undefined) { + equalsGreaterThanToken = node.equalsGreaterThanToken; + body = cast(equalsGreaterThanTokenOrBody, isConciseBody); + } + else { + equalsGreaterThanToken = cast(equalsGreaterThanTokenOrBody, (n): n is Token => + n.kind === SyntaxKind.EqualsGreaterThanToken); + body = bodyOrUndefined; + } + return node.modifiers !== modifiers || node.typeParameters !== typeParameters || node.parameters !== parameters || node.type !== type + || node.equalsGreaterThanToken !== equalsGreaterThanToken || node.body !== body - ? updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, node.equalsGreaterThanToken, body), node) + ? updateNode(createArrowFunction(modifiers, typeParameters, parameters, type, equalsGreaterThanToken, body), node) : node; } @@ -1135,11 +1165,31 @@ namespace ts { return node; } - export function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression) { + /* @deprecated */ export function updateConditional( + node: ConditionalExpression, + condition: Expression, + whenTrue: Expression, + whenFalse: Expression): ConditionalExpression; + export function updateConditional( + node: ConditionalExpression, + condition: Expression, + questionToken: Token, + whenTrue: Expression, + colonToken: Token, + whenFalse: Expression): ConditionalExpression; + export function updateConditional(node: ConditionalExpression, condition: Expression, ...args: any[]) { + if (args.length === 2) { + const [whenTrue, whenFalse] = args; + return updateConditional(node, condition, node.questionToken, whenTrue, node.colonToken, whenFalse); + } + Debug.assert(args.length === 4); + const [questionToken, whenTrue, colonToken, whenFalse] = args; return node.condition !== condition + || node.questionToken !== questionToken || node.whenTrue !== whenTrue + || node.colonToken !== colonToken || node.whenFalse !== whenFalse - ? updateNode(createConditional(condition, node.questionToken, whenTrue, node.colonToken, whenFalse), node) + ? updateNode(createConditional(condition, questionToken, whenTrue, colonToken, whenFalse), node) : node; } diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 43058358ee5..85a44e35983 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -197,9 +197,10 @@ namespace ts { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, + node.equalsGreaterThanToken, getFunctionFlags(node) & FunctionFlags.Async ? transformAsyncFunctionBody(node) - : visitFunctionBody(node.body, visitor, context) + : visitFunctionBody(node.body, visitor, context), ); } diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 3bdcc9e9ee7..0fca09b4540 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -595,7 +595,8 @@ namespace ts { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - transformFunctionBody(node) + node.equalsGreaterThanToken, + transformFunctionBody(node), ); enclosingFunctionFlags = savedEnclosingFunctionFlags; return updated; diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 42c25ca34a5..ebce55aa7e5 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2309,7 +2309,8 @@ namespace ts { /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, - visitFunctionBody(node.body, visitor, context) + node.equalsGreaterThanToken, + visitFunctionBody(node.body, visitor, context), ); return updated; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 55baf9763c2..1b5a0164585 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4299,10 +4299,11 @@ namespace ts { } export const enum EmitHint { - SourceFile, // Emitting a SourceFile - Expression, // Emitting an Expression - IdentifierName, // Emitting an IdentifierName - Unspecified, // Emitting an otherwise unspecified node + SourceFile, // Emitting a SourceFile + Expression, // Emitting an Expression + IdentifierName, // Emitting an IdentifierName + MappedTypeParameter, // Emitting a TypeParameterDeclaration inside of a MappedTypeNode + Unspecified, // Emitting an otherwise unspecified node } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 11c30a2d8ab..160d81d04da 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4728,8 +4728,7 @@ namespace ts { /* @internal */ export function isNodeArray(array: ReadonlyArray): array is NodeArray { - return array.hasOwnProperty("pos") - && array.hasOwnProperty("end"); + return array.hasOwnProperty("pos") && array.hasOwnProperty("end"); } // Literals diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 1ce42199372..7d46630e227 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -488,6 +488,7 @@ namespace ts { nodesVisitor((node).typeParameters, visitor, isTypeParameterDeclaration), visitParameterList((node).parameters, visitor, context, nodesVisitor), visitNode((node).type, visitor, isTypeNode), + visitNode((node).equalsGreaterThanToken, visitor, isToken), visitFunctionBody((node).body, visitor, context)); case SyntaxKind.DeleteExpression: @@ -523,7 +524,9 @@ namespace ts { case SyntaxKind.ConditionalExpression: return updateConditional(node, visitNode((node).condition, visitor, isExpression), + visitNode((node).questionToken, visitor, isToken), visitNode((node).whenTrue, visitor, isExpression), + visitNode((node).colonToken, visitor, isToken), visitNode((node).whenFalse, visitor, isExpression)); case SyntaxKind.TemplateExpression: diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 443ce13d6a4..5f26990d3a4 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -726,6 +726,7 @@ namespace ts.formatting { parent: Node, parentStartLine: number, parentDynamicIndentation: DynamicIndentation): void { + Debug.assert(isNodeArray(nodes)); const listStartToken = getOpenTokenForList(parent, nodes); const listEndToken = getCloseTokenForOpenToken(listStartToken); diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index b76ab9376dc..25a995dc231 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -656,11 +656,13 @@ namespace ts.refactor.extractMethod { const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ type, declaration: getFirstDeclaration(type) })); const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder); - const typeParameters: ReadonlyArray = sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration); + const typeParameters: ReadonlyArray | undefined = sortedTypeParametersAndDeclarations.length === 0 + ? undefined + : sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration); // Strictly speaking, we should check whether each name actually binds to the appropriate type // parameter. In cases of shadowing, they may not. - const callTypeArguments: ReadonlyArray | undefined = typeParameters.length > 0 + const callTypeArguments: ReadonlyArray | undefined = typeParameters !== undefined ? typeParameters.map(decl => createTypeReferenceNode(decl.name, /*typeArguments*/ undefined)) : undefined; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 7909d2d3adb..42c1d1e9a4f 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -5,19 +5,25 @@ namespace ts.textChanges { * Currently for simplicity we store recovered positions on the node itself. * It can be changed to side-table later if we decide that current design is too invasive. */ - function getPos(n: TextRange) { - return (n)["__pos"]; + function getPos(n: TextRange): number { + const result = (n)["__pos"]; + Debug.assert(typeof result === "number"); + return result; } - function setPos(n: TextRange, pos: number) { + function setPos(n: TextRange, pos: number): void { + Debug.assert(typeof pos === "number"); (n)["__pos"] = pos; } - function getEnd(n: TextRange) { - return (n)["__end"]; + function getEnd(n: TextRange): number { + const result = (n)["__end"]; + Debug.assert(typeof result === "number"); + return result; } - function setEnd(n: TextRange, end: number) { + function setEnd(n: TextRange, end: number): void { + Debug.assert(typeof end === "number"); (n)["__end"] = end; } @@ -582,7 +588,7 @@ namespace ts.textChanges { readonly node: Node; } - export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLine: NewLineKind): NonFormattedText { + function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLine: NewLineKind): NonFormattedText { const options = { newLine, target: sourceFile && sourceFile.languageVersion }; const writer = new Writer(getNewLineCharacter(options)); const printer = createPrinter(options, writer); @@ -590,7 +596,7 @@ namespace ts.textChanges { return { text: writer.getText(), node: assignPositionsToNode(node) }; } - export function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, rulesProvider: formatting.RulesProvider) { + function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, rulesProvider: formatting.RulesProvider) { const lineMap = computeLineStarts(nonFormattedText.text); const file: SourceFileLike = { text: nonFormattedText.text, @@ -616,14 +622,10 @@ namespace ts.textChanges { function assignPositionsToNode(node: Node): Node { const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); // create proxy node for non synthesized nodes - const newNode = nodeIsSynthesized(visited) - ? visited - : (Proxy.prototype = visited, new (Proxy)()); + const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited) as Node; newNode.pos = getPos(node); newNode.end = getEnd(node); return newNode; - - function Proxy() { } } function assignPositionsToNodeArray(nodes: NodeArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number) { diff --git a/tests/baselines/reference/extractMethod/extractMethod4.ts b/tests/baselines/reference/extractMethod/extractMethod4.ts index 107f99e669b..4e9811501f4 100644 --- a/tests/baselines/reference/extractMethod/extractMethod4.ts +++ b/tests/baselines/reference/extractMethod/extractMethod4.ts @@ -24,9 +24,9 @@ namespace A { async function newFunction() { let y = 5; - if(z) { - await z1; - } + if (z) { + await z1; + } return foo(); } } @@ -44,9 +44,9 @@ namespace A { async function newFunction(z: number, z1: any) { let y = 5; - if(z) { - await z1; - } + if (z) { + await z1; + } return foo(); } } @@ -64,9 +64,9 @@ namespace A { async function newFunction(z: number, z1: any) { let y = 5; - if(z) { - await z1; - } + if (z) { + await z1; + } return foo(); } } @@ -83,8 +83,8 @@ namespace A { } async function newFunction(z: number, z1: any, foo: () => void) { let y = 5; - if(z) { - await z1; -} + if (z) { + await z1; + } return foo(); } diff --git a/tests/baselines/reference/sourceMapValidationStatements.js.map b/tests/baselines/reference/sourceMapValidationStatements.js.map index 5841f329e5e..40d65e0106c 100644 --- a/tests/baselines/reference/sourceMapValidationStatements.js.map +++ b/tests/baselines/reference/sourceMapValidationStatements.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationStatements.js.map] -{"version":3,"file":"sourceMapValidationStatements.js","sourceRoot":"","sources":["sourceMapValidationStatements.ts"],"names":[],"mappings":"AAAA;IACI,IAAI,CAAC,CAAC;IACN,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,CAAC,IAAI,CAAC,CAAC;QACP,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACT,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,CAAC,IAAI,EAAE,CAAC;QACR,CAAC,EAAE,CAAC;IACR,CAAC;IACD,IAAI,CAAC,GAAG;QACJ,CAAC;QACD,CAAC;QACD,CAAC;KACJ,CAAC;IACF,IAAI,GAAG,GAAG;QACN,CAAC,EAAE,CAAC;QACJ,CAAC,EAAE,OAAO;KACb,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACD,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IACnB,CAAC;IAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACT,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACb,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACf,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;QAClB,CAAC;IACL,CAAC;IACD,IAAI,CAAC;QACD,MAAM,IAAI,KAAK,EAAE,CAAC;IACtB,CAAC;IAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACV,IAAI,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;YAAS,CAAC;QACP,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,GAAG,EAAE,CAAC;QACR,CAAC,GAAG,CAAC,CAAC;QACN,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACZ,KAAK,CAAC,EAAE,CAAC;YACL,CAAC,EAAE,CAAC;YACJ,KAAK,CAAC;QAEV,CAAC;QACD,KAAK,CAAC,EAAE,CAAC;YACL,CAAC,EAAE,CAAC;YACJ,KAAK,CAAC;QAEV,CAAC;QACD,SAAS,CAAC;YACN,CAAC,IAAI,CAAC,CAAC;YACP,CAAC,GAAG,EAAE,CAAC;YACP,KAAK,CAAC;QAEV,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QACZ,CAAC,EAAE,CAAC;IACR,CAAC;IACD,GAAG,CAAC;QACA,CAAC,EAAE,CAAC;IACR,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAC;IACf,CAAC,GAAG,CAAC,CAAC;IACN,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC,KAAK,CAAC,CAAC;IACR,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC;AACX,CAAC;AACD,IAAI,CAAC,GAAG;IACJ,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC,CAAC;AACF,CAAC,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationStatements.js","sourceRoot":"","sources":["sourceMapValidationStatements.ts"],"names":[],"mappings":"AAAA;IACI,IAAI,CAAC,CAAC;IACN,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,CAAC,IAAI,CAAC,CAAC;QACP,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;IACD,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACT,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,CAAC,IAAI,EAAE,CAAC;QACR,CAAC,EAAE,CAAC;IACR,CAAC;IACD,IAAI,CAAC,GAAG;QACJ,CAAC;QACD,CAAC;QACD,CAAC;KACJ,CAAC;IACF,IAAI,GAAG,GAAG;QACN,CAAC,EAAE,CAAC;QACJ,CAAC,EAAE,OAAO;KACb,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACd,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACD,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;IACnB,CAAC;IAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACT,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACb,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACf,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;QAClB,CAAC;IACL,CAAC;IACD,IAAI,CAAC;QACD,MAAM,IAAI,KAAK,EAAE,CAAC;IACtB,CAAC;IAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACV,IAAI,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;YAAS,CAAC;QACP,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,GAAG,EAAE,CAAC;QACR,CAAC,GAAG,CAAC,CAAC;QACN,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACZ,KAAK,CAAC,EAAE,CAAC;YACL,CAAC,EAAE,CAAC;YACJ,KAAK,CAAC;QAEV,CAAC;QACD,KAAK,CAAC,EAAE,CAAC;YACL,CAAC,EAAE,CAAC;YACJ,KAAK,CAAC;QAEV,CAAC;QACD,SAAS,CAAC;YACN,CAAC,IAAI,CAAC,CAAC;YACP,CAAC,GAAG,EAAE,CAAC;YACP,KAAK,CAAC;QAEV,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QACZ,CAAC,EAAE,CAAC;IACR,CAAC;IACD,GAAG,CAAC;QACA,CAAC,EAAE,CAAC;IACR,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAC;IACf,CAAC,GAAG,CAAC,CAAC;IACN,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC,KAAK,CAAC,CAAC;IACR,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IACX,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,CAAC;AACX,CAAC;AACD,IAAI,CAAC,GAAG;IACJ,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC,CAAC;AACF,CAAC,EAAE,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt b/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt index 7c5c5bfcfeb..aec7eaafc06 100644 --- a/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt @@ -1251,15 +1251,19 @@ sourceFile:sourceMapValidationStatements.ts 7 > ^^^^ 8 > ^ 9 > ^ -10> ^^^ -11> ^ -12> ^^^ -13> ^ -14> ^^^ -15> ^ -16> ^^^ -17> ^ -18> ^ +10> ^ +11> ^ +12> ^ +13> ^ +14> ^^^ +15> ^ +16> ^ +17> ^ +18> ^ +19> ^ +20> ^^^ +21> ^ +22> ^ 1-> > 2 > var @@ -1270,15 +1274,19 @@ sourceFile:sourceMapValidationStatements.ts 7 > == 8 > 1 9 > ) -10> ? -11> x -12> + -13> 1 -14> : -15> x -16> - -17> 1 -18> ; +10> +11> ? +12> +13> x +14> + +15> 1 +16> +17> : +18> +19> x +20> - +21> 1 +22> ; 1->Emitted(74, 5) Source(72, 5) + SourceIndex(0) 2 >Emitted(74, 9) Source(72, 9) + SourceIndex(0) 3 >Emitted(74, 10) Source(72, 10) + SourceIndex(0) @@ -1288,15 +1296,19 @@ sourceFile:sourceMapValidationStatements.ts 7 >Emitted(74, 19) Source(72, 19) + SourceIndex(0) 8 >Emitted(74, 20) Source(72, 20) + SourceIndex(0) 9 >Emitted(74, 21) Source(72, 21) + SourceIndex(0) -10>Emitted(74, 24) Source(72, 24) + SourceIndex(0) -11>Emitted(74, 25) Source(72, 25) + SourceIndex(0) -12>Emitted(74, 28) Source(72, 28) + SourceIndex(0) -13>Emitted(74, 29) Source(72, 29) + SourceIndex(0) -14>Emitted(74, 32) Source(72, 32) + SourceIndex(0) -15>Emitted(74, 33) Source(72, 33) + SourceIndex(0) -16>Emitted(74, 36) Source(72, 36) + SourceIndex(0) -17>Emitted(74, 37) Source(72, 37) + SourceIndex(0) -18>Emitted(74, 38) Source(72, 38) + SourceIndex(0) +10>Emitted(74, 22) Source(72, 22) + SourceIndex(0) +11>Emitted(74, 23) Source(72, 23) + SourceIndex(0) +12>Emitted(74, 24) Source(72, 24) + SourceIndex(0) +13>Emitted(74, 25) Source(72, 25) + SourceIndex(0) +14>Emitted(74, 28) Source(72, 28) + SourceIndex(0) +15>Emitted(74, 29) Source(72, 29) + SourceIndex(0) +16>Emitted(74, 30) Source(72, 30) + SourceIndex(0) +17>Emitted(74, 31) Source(72, 31) + SourceIndex(0) +18>Emitted(74, 32) Source(72, 32) + SourceIndex(0) +19>Emitted(74, 33) Source(72, 33) + SourceIndex(0) +20>Emitted(74, 36) Source(72, 36) + SourceIndex(0) +21>Emitted(74, 37) Source(72, 37) + SourceIndex(0) +22>Emitted(74, 38) Source(72, 38) + SourceIndex(0) --- >>> (x == 1) ? x + 1 : x - 1; 1 >^^^^ @@ -1305,15 +1317,19 @@ sourceFile:sourceMapValidationStatements.ts 4 > ^^^^ 5 > ^ 6 > ^ -7 > ^^^ -8 > ^ -9 > ^^^ -10> ^ -11> ^^^ -12> ^ -13> ^^^ -14> ^ -15> ^ +7 > ^ +8 > ^ +9 > ^ +10> ^ +11> ^^^ +12> ^ +13> ^ +14> ^ +15> ^ +16> ^ +17> ^^^ +18> ^ +19> ^ 1 > > 2 > ( @@ -1321,30 +1337,38 @@ sourceFile:sourceMapValidationStatements.ts 4 > == 5 > 1 6 > ) -7 > ? -8 > x -9 > + -10> 1 -11> : -12> x -13> - -14> 1 -15> ; +7 > +8 > ? +9 > +10> x +11> + +12> 1 +13> +14> : +15> +16> x +17> - +18> 1 +19> ; 1 >Emitted(75, 5) Source(73, 5) + SourceIndex(0) 2 >Emitted(75, 6) Source(73, 6) + SourceIndex(0) 3 >Emitted(75, 7) Source(73, 7) + SourceIndex(0) 4 >Emitted(75, 11) Source(73, 11) + SourceIndex(0) 5 >Emitted(75, 12) Source(73, 12) + SourceIndex(0) 6 >Emitted(75, 13) Source(73, 13) + SourceIndex(0) -7 >Emitted(75, 16) Source(73, 16) + SourceIndex(0) -8 >Emitted(75, 17) Source(73, 17) + SourceIndex(0) -9 >Emitted(75, 20) Source(73, 20) + SourceIndex(0) -10>Emitted(75, 21) Source(73, 21) + SourceIndex(0) -11>Emitted(75, 24) Source(73, 24) + SourceIndex(0) -12>Emitted(75, 25) Source(73, 25) + SourceIndex(0) -13>Emitted(75, 28) Source(73, 28) + SourceIndex(0) -14>Emitted(75, 29) Source(73, 29) + SourceIndex(0) -15>Emitted(75, 30) Source(73, 30) + SourceIndex(0) +7 >Emitted(75, 14) Source(73, 14) + SourceIndex(0) +8 >Emitted(75, 15) Source(73, 15) + SourceIndex(0) +9 >Emitted(75, 16) Source(73, 16) + SourceIndex(0) +10>Emitted(75, 17) Source(73, 17) + SourceIndex(0) +11>Emitted(75, 20) Source(73, 20) + SourceIndex(0) +12>Emitted(75, 21) Source(73, 21) + SourceIndex(0) +13>Emitted(75, 22) Source(73, 22) + SourceIndex(0) +14>Emitted(75, 23) Source(73, 23) + SourceIndex(0) +15>Emitted(75, 24) Source(73, 24) + SourceIndex(0) +16>Emitted(75, 25) Source(73, 25) + SourceIndex(0) +17>Emitted(75, 28) Source(73, 28) + SourceIndex(0) +18>Emitted(75, 29) Source(73, 29) + SourceIndex(0) +19>Emitted(75, 30) Source(73, 30) + SourceIndex(0) --- >>> x === 1; 1 >^^^^ diff --git a/tests/baselines/reference/ternaryExpressionSourceMap.js.map b/tests/baselines/reference/ternaryExpressionSourceMap.js.map index 9340c972274..27160910378 100644 --- a/tests/baselines/reference/ternaryExpressionSourceMap.js.map +++ b/tests/baselines/reference/ternaryExpressionSourceMap.js.map @@ -1,2 +1,2 @@ //// [ternaryExpressionSourceMap.js.map] -{"version":3,"file":"ternaryExpressionSourceMap.js","sourceRoot":"","sources":["ternaryExpressionSourceMap.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,CAAC,CAAC;AACV,IAAI,GAAG,GAAG,CAAC,GAAG,cAAM,OAAA,CAAC,EAAD,CAAC,GAAG,cAAM,OAAA,CAAC,EAAD,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"ternaryExpressionSourceMap.js","sourceRoot":"","sources":["ternaryExpressionSourceMap.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,CAAC,CAAC;AACV,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,cAAM,OAAA,CAAC,EAAD,CAAC,CAAC,CAAC,CAAC,cAAM,OAAA,CAAC,EAAD,CAAC,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/ternaryExpressionSourceMap.sourcemap.txt b/tests/baselines/reference/ternaryExpressionSourceMap.sourcemap.txt index d46e703e357..87e3ce02304 100644 --- a/tests/baselines/reference/ternaryExpressionSourceMap.sourcemap.txt +++ b/tests/baselines/reference/ternaryExpressionSourceMap.sourcemap.txt @@ -35,55 +35,67 @@ sourceFile:ternaryExpressionSourceMap.ts 3 > ^^^ 4 > ^^^ 5 > ^ -6 > ^^^ -7 > ^^^^^^^^^^^^^^ -8 > ^^^^^^^ -9 > ^ -10> ^^ -11> ^ -12> ^^^ -13> ^^^^^^^^^^^^^^ -14> ^^^^^^^ -15> ^ -16> ^^ -17> ^ -18> ^ +6 > ^ +7 > ^ +8 > ^ +9 > ^^^^^^^^^^^^^^ +10> ^^^^^^^ +11> ^ +12> ^^ +13> ^ +14> ^ +15> ^ +16> ^ +17> ^^^^^^^^^^^^^^ +18> ^^^^^^^ +19> ^ +20> ^^ +21> ^ +22> ^ 1-> > 2 >var 3 > foo 4 > = 5 > x -6 > ? -7 > () => -8 > -9 > 0 -10> -11> 0 -12> : -13> () => -14> -15> 0 -16> -17> 0 -18> ; +6 > +7 > ? +8 > +9 > () => +10> +11> 0 +12> +13> 0 +14> +15> : +16> +17> () => +18> +19> 0 +20> +21> 0 +22> ; 1->Emitted(2, 1) Source(2, 1) + SourceIndex(0) 2 >Emitted(2, 5) Source(2, 5) + SourceIndex(0) 3 >Emitted(2, 8) Source(2, 8) + SourceIndex(0) 4 >Emitted(2, 11) Source(2, 11) + SourceIndex(0) 5 >Emitted(2, 12) Source(2, 12) + SourceIndex(0) -6 >Emitted(2, 15) Source(2, 15) + SourceIndex(0) -7 >Emitted(2, 29) Source(2, 21) + SourceIndex(0) -8 >Emitted(2, 36) Source(2, 21) + SourceIndex(0) -9 >Emitted(2, 37) Source(2, 22) + SourceIndex(0) -10>Emitted(2, 39) Source(2, 21) + SourceIndex(0) -11>Emitted(2, 40) Source(2, 22) + SourceIndex(0) -12>Emitted(2, 43) Source(2, 25) + SourceIndex(0) -13>Emitted(2, 57) Source(2, 31) + SourceIndex(0) -14>Emitted(2, 64) Source(2, 31) + SourceIndex(0) -15>Emitted(2, 65) Source(2, 32) + SourceIndex(0) -16>Emitted(2, 67) Source(2, 31) + SourceIndex(0) -17>Emitted(2, 68) Source(2, 32) + SourceIndex(0) -18>Emitted(2, 69) Source(2, 33) + SourceIndex(0) +6 >Emitted(2, 13) Source(2, 13) + SourceIndex(0) +7 >Emitted(2, 14) Source(2, 14) + SourceIndex(0) +8 >Emitted(2, 15) Source(2, 15) + SourceIndex(0) +9 >Emitted(2, 29) Source(2, 21) + SourceIndex(0) +10>Emitted(2, 36) Source(2, 21) + SourceIndex(0) +11>Emitted(2, 37) Source(2, 22) + SourceIndex(0) +12>Emitted(2, 39) Source(2, 21) + SourceIndex(0) +13>Emitted(2, 40) Source(2, 22) + SourceIndex(0) +14>Emitted(2, 41) Source(2, 23) + SourceIndex(0) +15>Emitted(2, 42) Source(2, 24) + SourceIndex(0) +16>Emitted(2, 43) Source(2, 25) + SourceIndex(0) +17>Emitted(2, 57) Source(2, 31) + SourceIndex(0) +18>Emitted(2, 64) Source(2, 31) + SourceIndex(0) +19>Emitted(2, 65) Source(2, 32) + SourceIndex(0) +20>Emitted(2, 67) Source(2, 31) + SourceIndex(0) +21>Emitted(2, 68) Source(2, 32) + SourceIndex(0) +22>Emitted(2, 69) Source(2, 33) + SourceIndex(0) --- >>>//# sourceMappingURL=ternaryExpressionSourceMap.js.map \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js index be1c497e3ea..5483f314fb9 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.js @@ -85,6 +85,8 @@ function foo7(x) { return typeof x !== "string" && ((z = x) // number | boolean && (typeof x === "number" + // change value of x ? ((x = 10) && x.toString()) // x is number + // do not change value : ((y = x) && x.toString()))); // x is boolean } diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js index a8d66dc5fa2..c3143999d3a 100644 --- a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.js @@ -87,6 +87,8 @@ function foo7(x) { return typeof x === "string" || ((z = x) // number | boolean || (typeof x === "number" + // change value of x ? ((x = 10) && x.toString()) // number | boolean | string + // do not change value : ((y = x) && x.toString()))); // number | boolean | string } diff --git a/tests/cases/fourslash/extract-method-formatting.ts b/tests/cases/fourslash/extract-method-formatting.ts new file mode 100644 index 00000000000..1342e5632e8 --- /dev/null +++ b/tests/cases/fourslash/extract-method-formatting.ts @@ -0,0 +1,24 @@ +/// + +////function f(x: number): number { +//// /*start*/switch (x) {case 0: +////return 0;}/*end*/ +////} + +goTo.select('start', 'end') +edit.applyRefactor({ + refactorName: "Extract Method", + actionName: "scope_1", + actionDescription: "Extract function into global scope", +}); +verify.currentFileContentIs( +`function f(x: number): number { + return newFunction(x); +} +function newFunction(x: number) { + switch (x) { + case 0: + return 0; + } +} +`); diff --git a/tests/cases/fourslash/extract-method5.ts b/tests/cases/fourslash/extract-method5.ts index d1e70d10716..8b0bd4fec6d 100644 --- a/tests/cases/fourslash/extract-method5.ts +++ b/tests/cases/fourslash/extract-method5.ts @@ -20,6 +20,6 @@ verify.currentFileContentIs( var x: 1 | 2 | 3 = newFunction(); function newFunction(): 1 | 2 | 3 { - return 1 + 1 === 2?1: 2; + return 1 + 1 === 2 ? 1 : 2; } }`); \ No newline at end of file From 2e027789606a7b5bcd015cf1173823ed8f83023b Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 7 Sep 2017 14:31:20 -0700 Subject: [PATCH 61/74] When loading a module from node_modules, get packageId even in the `loadModuleFromFile` case (#18185) * When loading a module from node_modules, get packageId even in the `loadModuleFromFile` case * Support packageId for too --- src/compiler/moduleNameResolver.ts | 103 +++++++++++------- src/compiler/program.ts | 14 +-- src/compiler/types.ts | 6 + src/compiler/utilities.ts | 2 +- src/harness/unittests/moduleResolution.ts | 31 +++--- .../unittests/reuseProgramStructure.ts | 20 ++-- .../unittests/tsserverProjectSystem.ts | 2 +- ...icatePackage_packageIdIncludesSubModule.js | 22 ++++ ...Package_packageIdIncludesSubModule.symbols | 20 ++++ ...tePackage_packageIdIncludesSubModule.types | 20 ++++ .../duplicatePackage_referenceTypes.js | 31 ++++++ .../duplicatePackage_referenceTypes.symbols | 33 ++++++ .../duplicatePackage_referenceTypes.types | 33 ++++++ .../reference/duplicatePackage_subModule.js | 34 ++++++ .../duplicatePackage_subModule.symbols | 38 +++++++ .../duplicatePackage_subModule.types | 38 +++++++ .../reference/library-reference-11.trace.json | 2 +- .../reference/library-reference-12.trace.json | 2 +- .../reference/library-reference-3.trace.json | 2 +- .../reference/library-reference-4.trace.json | 8 +- .../reference/library-reference-5.trace.json | 8 +- .../reference/library-reference-7.trace.json | 2 +- ...brary-reference-scoped-packages.trace.json | 2 +- ...NodeModuleJsDepthDefaultsToZero.trace.json | 4 +- ...lutionWithExtensions_unexpected.trace.json | 4 +- ...utionWithExtensions_unexpected2.trace.json | 4 +- ...thExtensions_withAmbientPresent.trace.json | 4 +- .../moduleResolutionWithSymlinks.trace.json | 2 +- ...onWithSymlinks_preserveSymlinks.trace.json | 10 +- ...tionWithSymlinks_referenceTypes.trace.json | 6 +- ...solutionWithSymlinks_withOutDir.trace.json | 2 +- .../reference/packageJsonMain.trace.json | 12 +- .../packageJsonMain_isNonRecursive.trace.json | 4 +- ...pingBasedModuleResolution3_node.trace.json | 2 +- ...pingBasedModuleResolution4_node.trace.json | 2 +- .../reference/scopedPackages.trace.json | 5 +- .../scopedPackagesClassic.trace.json | 2 +- .../reference/typingsLookup4.trace.json | 8 +- .../reference/typingsLookupAmd.trace.json | 4 +- ...icatePackage_packageIdIncludesSubModule.ts | 17 +++ .../duplicatePackage_referenceTypes.ts | 24 ++++ .../compiler/duplicatePackage_subModule.ts | 27 +++++ 42 files changed, 493 insertions(+), 123 deletions(-) create mode 100644 tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.js create mode 100644 tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.symbols create mode 100644 tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.types create mode 100644 tests/baselines/reference/duplicatePackage_referenceTypes.js create mode 100644 tests/baselines/reference/duplicatePackage_referenceTypes.symbols create mode 100644 tests/baselines/reference/duplicatePackage_referenceTypes.types create mode 100644 tests/baselines/reference/duplicatePackage_subModule.js create mode 100644 tests/baselines/reference/duplicatePackage_subModule.symbols create mode 100644 tests/baselines/reference/duplicatePackage_subModule.types create mode 100644 tests/cases/compiler/duplicatePackage_packageIdIncludesSubModule.ts create mode 100644 tests/cases/compiler/duplicatePackage_referenceTypes.ts create mode 100644 tests/cases/compiler/duplicatePackage_subModule.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 5fdac504896..ddffe876d80 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -51,13 +51,17 @@ namespace ts { DtsOnly /** Only '.d.ts' */ } + interface PathAndPackageId { + readonly fileName: string; + readonly packageId: PackageId; + } /** Used with `Extensions.DtsOnly` to extract the path from TypeScript results. */ - function resolvedTypeScriptOnly(resolved: Resolved | undefined): string | undefined { + function resolvedTypeScriptOnly(resolved: Resolved | undefined): PathAndPackageId | undefined { if (!resolved) { return undefined; } Debug.assert(extensionIsTypeScript(resolved.extension)); - return resolved.path; + return { fileName: resolved.path, packageId: resolved.packageId }; } function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations { @@ -201,18 +205,18 @@ namespace ts { let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined; if (resolved) { if (!options.preserveSymlinks) { - resolved = realPath(resolved, host, traceEnabled); + resolved = { ...resolved, fileName: realPath(resolved.fileName, host, traceEnabled) }; } if (traceEnabled) { - trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved, primary); + trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved.fileName, primary); } - resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved }; + resolvedTypeReferenceDirective = { primary, resolvedFileName: resolved.fileName, packageId: resolved.packageId }; } return { resolvedTypeReferenceDirective, failedLookupLocations }; - function primaryLookup(): string | undefined { + function primaryLookup(): PathAndPackageId | undefined { // Check primary library paths if (typeRoots && typeRoots.length) { if (traceEnabled) { @@ -237,8 +241,8 @@ namespace ts { } } - function secondaryLookup(): string | undefined { - let resolvedFile: string; + function secondaryLookup(): PathAndPackageId | undefined { + let resolvedFile: PathAndPackageId; const initialLocationForSecondaryLookup = containingFile && getDirectoryPath(containingFile); if (initialLocationForSecondaryLookup !== undefined) { @@ -675,7 +679,7 @@ namespace ts { if (extension !== undefined) { const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state); if (path !== undefined) { - return { path, extension, packageId: undefined }; + return noPackageId({ path, ext: extension }); } } @@ -875,38 +879,49 @@ namespace ts { return undefined; } - function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined { - const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host); + function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) { + const { packageJsonContent, packageId } = considerPackageJson + ? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state) + : { packageJsonContent: undefined, packageId: undefined }; + return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent)); + } - let packageId: PackageId | undefined; - - if (considerPackageJson) { - const packageJsonPath = pathToPackageJson(candidate); - if (directoryExists && state.host.fileExists(packageJsonPath)) { - if (state.traceEnabled) { - trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath); - } - const jsonContent = readJson(packageJsonPath, state.host); - - if (typeof jsonContent.name === "string" && typeof jsonContent.version === "string") { - packageId = { name: jsonContent.name, version: jsonContent.version }; - } - - const fromPackageJson = loadModuleFromPackageJson(jsonContent, extensions, candidate, failedLookupLocations, state); - if (fromPackageJson) { - return withPackageId(packageId, fromPackageJson); - } - } - else { - if (directoryExists && state.traceEnabled) { - trace(state.host, Diagnostics.File_0_does_not_exist, packageJsonPath); - } - // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results - failedLookupLocations.push(packageJsonPath); - } + function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJson | undefined): PathAndExtension | undefined { + const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state); + if (fromPackageJson) { + return fromPackageJson; } + const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host); + return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state); + } - return withPackageId(packageId, loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state)); + function getPackageJsonInfo( + nodeModuleDirectory: string, + subModuleName: string, + failedLookupLocations: Push, + onlyRecordFailures: boolean, + { host, traceEnabled }: ModuleResolutionState, + ): { packageJsonContent: PackageJson | undefined, packageId: PackageId | undefined } { + const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host); + const packageJsonPath = pathToPackageJson(nodeModuleDirectory); + if (directoryExists && host.fileExists(packageJsonPath)) { + if (traceEnabled) { + trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath); + } + const packageJsonContent = readJson(packageJsonPath, host); + const packageId: PackageId = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string" + ? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version } + : undefined; + return { packageJsonContent, packageId }; + } + else { + if (directoryExists && traceEnabled) { + trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath); + } + // record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results + failedLookupLocations.push(packageJsonPath); + return { packageJsonContent: undefined, packageId: undefined }; + } } function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push, state: ModuleResolutionState): PathAndExtension | undefined { @@ -961,10 +976,18 @@ namespace ts { } function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push, state: ModuleResolutionState): Resolved | undefined { + const { top, rest } = getNameOfTopDirectory(moduleName); + const packageRootPath = combinePaths(nodeModulesFolder, top); + const { packageJsonContent, packageId } = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state); const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName)); + const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) || + loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent); + return withPackageId(packageId, pathAndExtension); + } - return loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) || - loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state); + function getNameOfTopDirectory(name: string): { top: string, rest: string } { + const idx = name.indexOf(directorySeparator); + return idx === -1 ? { top: name, rest: "" } : { top: name.slice(0, idx), rest: name.slice(idx + 1) }; } function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache): SearchResult { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 89c23598c58..00e933d680a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1427,7 +1427,7 @@ namespace ts { } function processRootFile(fileName: string, isDefaultLib: boolean) { - processSourceFile(normalizePath(fileName), isDefaultLib); + processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined); } function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean { @@ -1591,9 +1591,9 @@ namespace ts { } /** This has side effects through `findSourceFile`. */ - function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void { + function processSourceFile(fileName: string, isDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void { getSourceFileFromReferenceWorker(fileName, - fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, /*packageId*/ undefined), + fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, packageId), (diagnostic, ...args) => { fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined ? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args) @@ -1675,7 +1675,7 @@ namespace ts { }); if (packageId) { - const packageIdKey = `${packageId.name}@${packageId.version}`; + const packageIdKey = `${packageId.name}/${packageId.subModuleName}@${packageId.version}`; const fileFromPackageId = packageIdToSourceFile.get(packageIdKey); if (fileFromPackageId) { // Some other SourceFile already exists with this package name and version. @@ -1735,7 +1735,7 @@ namespace ts { function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) { forEach(file.referencedFiles, ref => { const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName); - processSourceFile(referencedFileName, isDefaultLib, file, ref.pos, ref.end); + processSourceFile(referencedFileName, isDefaultLib, /*packageId*/ undefined, file, ref.pos, ref.end); }); } @@ -1766,7 +1766,7 @@ namespace ts { if (resolvedTypeReferenceDirective) { if (resolvedTypeReferenceDirective.primary) { // resolved from the primary path - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, refFile, refPos, refEnd); + processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); } else { // If we already resolved to this file, it must have been a secondary reference. Check file contents @@ -1789,7 +1789,7 @@ namespace ts { } else { // First resolution of this library - processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, refFile, refPos, refEnd); + processSourceFile(resolvedTypeReferenceDirective.resolvedFileName, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1b5a0164585..c9ba56506a4 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4055,6 +4055,11 @@ namespace ts { * If accessing a non-index file, this should include its name e.g. "foo/bar". */ name: string; + /** + * Name of a submodule within this package. + * May be "". + */ + subModuleName: string; /** Version of the package, e.g. "1.2.3" */ version: string; } @@ -4078,6 +4083,7 @@ namespace ts { primary: boolean; // The location of the .d.ts file we located, or undefined if resolution failed resolvedFileName?: string; + packageId?: PackageId; } export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 160d81d04da..06b8437f76b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -104,7 +104,7 @@ namespace ts { } function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean { - return a === b || a && b && a.name === b.name && a.version === b.version; + return a === b || a && b && a.name === b.name && a.subModuleName === b.subModuleName && a.version === b.version; } export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean { diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts index ed8dcf0c7b4..0acbe9450bb 100644 --- a/src/harness/unittests/moduleResolution.ts +++ b/src/harness/unittests/moduleResolution.ts @@ -198,33 +198,34 @@ namespace ts { const moduleFile = { name: "/a/b/node_modules/foo.ts" }; const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [ + "/a/b/c/d/node_modules/foo/package.json", "/a/b/c/d/node_modules/foo.ts", "/a/b/c/d/node_modules/foo.tsx", "/a/b/c/d/node_modules/foo.d.ts", - "/a/b/c/d/node_modules/foo/package.json", "/a/b/c/d/node_modules/foo/index.ts", "/a/b/c/d/node_modules/foo/index.tsx", "/a/b/c/d/node_modules/foo/index.d.ts", - "/a/b/c/d/node_modules/@types/foo.d.ts", "/a/b/c/d/node_modules/@types/foo/package.json", + "/a/b/c/d/node_modules/@types/foo.d.ts", "/a/b/c/d/node_modules/@types/foo/index.d.ts", + "/a/b/c/node_modules/foo/package.json", "/a/b/c/node_modules/foo.ts", "/a/b/c/node_modules/foo.tsx", "/a/b/c/node_modules/foo.d.ts", - "/a/b/c/node_modules/foo/package.json", "/a/b/c/node_modules/foo/index.ts", "/a/b/c/node_modules/foo/index.tsx", "/a/b/c/node_modules/foo/index.d.ts", - "/a/b/c/node_modules/@types/foo.d.ts", "/a/b/c/node_modules/@types/foo/package.json", + "/a/b/c/node_modules/@types/foo.d.ts", "/a/b/c/node_modules/@types/foo/index.d.ts", + "/a/b/node_modules/foo/package.json", ]); } }); @@ -250,52 +251,52 @@ namespace ts { const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" }; const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile)); checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [ + "/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json", "/a/node_modules/b/c/node_modules/d/node_modules/foo.ts", "/a/node_modules/b/c/node_modules/d/node_modules/foo.tsx", "/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json", "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.ts", "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.tsx", "/a/node_modules/b/c/node_modules/d/node_modules/foo/index.d.ts", - "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts", "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/package.json", + "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo.d.ts", "/a/node_modules/b/c/node_modules/d/node_modules/@types/foo/index.d.ts", + "/a/node_modules/b/c/node_modules/foo/package.json", "/a/node_modules/b/c/node_modules/foo.ts", "/a/node_modules/b/c/node_modules/foo.tsx", "/a/node_modules/b/c/node_modules/foo.d.ts", - "/a/node_modules/b/c/node_modules/foo/package.json", "/a/node_modules/b/c/node_modules/foo/index.ts", "/a/node_modules/b/c/node_modules/foo/index.tsx", "/a/node_modules/b/c/node_modules/foo/index.d.ts", - "/a/node_modules/b/c/node_modules/@types/foo.d.ts", "/a/node_modules/b/c/node_modules/@types/foo/package.json", + "/a/node_modules/b/c/node_modules/@types/foo.d.ts", "/a/node_modules/b/c/node_modules/@types/foo/index.d.ts", + "/a/node_modules/b/node_modules/foo/package.json", "/a/node_modules/b/node_modules/foo.ts", "/a/node_modules/b/node_modules/foo.tsx", "/a/node_modules/b/node_modules/foo.d.ts", - "/a/node_modules/b/node_modules/foo/package.json", "/a/node_modules/b/node_modules/foo/index.ts", "/a/node_modules/b/node_modules/foo/index.tsx", "/a/node_modules/b/node_modules/foo/index.d.ts", - "/a/node_modules/b/node_modules/@types/foo.d.ts", "/a/node_modules/b/node_modules/@types/foo/package.json", + "/a/node_modules/b/node_modules/@types/foo.d.ts", "/a/node_modules/b/node_modules/@types/foo/index.d.ts", + "/a/node_modules/foo/package.json", "/a/node_modules/foo.ts", "/a/node_modules/foo.tsx", "/a/node_modules/foo.d.ts", - "/a/node_modules/foo/package.json", "/a/node_modules/foo/index.ts", "/a/node_modules/foo/index.tsx" @@ -707,21 +708,23 @@ import b = require("./moduleB"); "/root/generated/file6/index.d.ts", // fallback to standard node behavior + "/root/folder1/node_modules/file6/package.json", + // load from file "/root/folder1/node_modules/file6.ts", "/root/folder1/node_modules/file6.tsx", "/root/folder1/node_modules/file6.d.ts", // load from folder - "/root/folder1/node_modules/file6/package.json", "/root/folder1/node_modules/file6/index.ts", "/root/folder1/node_modules/file6/index.tsx", "/root/folder1/node_modules/file6/index.d.ts", - "/root/folder1/node_modules/@types/file6.d.ts", - "/root/folder1/node_modules/@types/file6/package.json", + "/root/folder1/node_modules/@types/file6.d.ts", "/root/folder1/node_modules/@types/file6/index.d.ts", + + "/root/node_modules/file6/package.json", // success on /root/node_modules/file6.ts ], /*isExternalLibraryImport*/ true); diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts index 0c2a4a7052b..8c8c1034677 100644 --- a/src/harness/unittests/reuseProgramStructure.ts +++ b/src/harness/unittests/reuseProgramStructure.ts @@ -441,20 +441,20 @@ namespace ts { "======== Resolving module 'a' from 'file1.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'a' from 'node_modules' folder, target file type 'TypeScript'.", + "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a.ts' does not exist.", "File 'node_modules/a.tsx' does not exist.", "File 'node_modules/a.d.ts' does not exist.", - "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a/index.ts' does not exist.", "File 'node_modules/a/index.tsx' does not exist.", "File 'node_modules/a/index.d.ts' does not exist.", - "File 'node_modules/@types/a.d.ts' does not exist.", "File 'node_modules/@types/a/package.json' does not exist.", + "File 'node_modules/@types/a.d.ts' does not exist.", "File 'node_modules/@types/a/index.d.ts' does not exist.", "Loading module 'a' from 'node_modules' folder, target file type 'JavaScript'.", + "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a.js' does not exist.", "File 'node_modules/a.jsx' does not exist.", - "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a/index.js' does not exist.", "File 'node_modules/a/index.jsx' does not exist.", "======== Module name 'a' was not resolved. ========" @@ -474,10 +474,10 @@ namespace ts { "======== Resolving module 'a' from 'file1.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'a' from 'node_modules' folder, target file type 'TypeScript'.", + "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a.ts' does not exist.", "File 'node_modules/a.tsx' does not exist.", "File 'node_modules/a.d.ts' does not exist.", - "File 'node_modules/a/package.json' does not exist.", "File 'node_modules/a/index.ts' does not exist.", "File 'node_modules/a/index.tsx' does not exist.", "File 'node_modules/a/index.d.ts' exist - use it as a name resolution result.", @@ -510,14 +510,14 @@ namespace ts { "File '/fs.ts' does not exist.", "File '/fs.tsx' does not exist.", "File '/fs.d.ts' does not exist.", - "File '/a/b/node_modules/@types/fs.d.ts' does not exist.", "File '/a/b/node_modules/@types/fs/package.json' does not exist.", + "File '/a/b/node_modules/@types/fs.d.ts' does not exist.", "File '/a/b/node_modules/@types/fs/index.d.ts' does not exist.", - "File '/a/node_modules/@types/fs.d.ts' does not exist.", "File '/a/node_modules/@types/fs/package.json' does not exist.", + "File '/a/node_modules/@types/fs.d.ts' does not exist.", "File '/a/node_modules/@types/fs/index.d.ts' does not exist.", - "File '/node_modules/@types/fs.d.ts' does not exist.", "File '/node_modules/@types/fs/package.json' does not exist.", + "File '/node_modules/@types/fs.d.ts' does not exist.", "File '/node_modules/@types/fs/index.d.ts' does not exist.", "File '/a/b/fs.js' does not exist.", "File '/a/b/fs.jsx' does not exist.", @@ -552,14 +552,14 @@ namespace ts { "File '/fs.ts' does not exist.", "File '/fs.tsx' does not exist.", "File '/fs.d.ts' does not exist.", - "File '/a/b/node_modules/@types/fs.d.ts' does not exist.", "File '/a/b/node_modules/@types/fs/package.json' does not exist.", + "File '/a/b/node_modules/@types/fs.d.ts' does not exist.", "File '/a/b/node_modules/@types/fs/index.d.ts' does not exist.", - "File '/a/node_modules/@types/fs.d.ts' does not exist.", "File '/a/node_modules/@types/fs/package.json' does not exist.", + "File '/a/node_modules/@types/fs.d.ts' does not exist.", "File '/a/node_modules/@types/fs/index.d.ts' does not exist.", - "File '/node_modules/@types/fs.d.ts' does not exist.", "File '/node_modules/@types/fs/package.json' does not exist.", + "File '/node_modules/@types/fs.d.ts' does not exist.", "File '/node_modules/@types/fs/index.d.ts' does not exist.", "File '/a/b/fs.js' does not exist.", "File '/a/b/fs.jsx' does not exist.", diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index c9a74310977..651dbae7142 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -2510,8 +2510,8 @@ namespace ts.projectSystem { "======== Module name 'lib' was not resolved. ========", `Auto discovery for typings is enabled in project '${proj.getProjectName()}'. Running extra resolution pass for module 'lib' using cache location '/a/cache'.`, "File '/a/cache/node_modules/lib.d.ts' does not exist.", - "File '/a/cache/node_modules/@types/lib.d.ts' does not exist.", "File '/a/cache/node_modules/@types/lib/package.json' does not exist.", + "File '/a/cache/node_modules/@types/lib.d.ts' does not exist.", "File '/a/cache/node_modules/@types/lib/index.d.ts' exist - use it as a name resolution result.", ]); checkProjectActualFiles(proj, [file1.path, lib.path]); diff --git a/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.js b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.js new file mode 100644 index 00000000000..9817641484e --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/duplicatePackage_packageIdIncludesSubModule.ts] //// + +//// [Foo.d.ts] +export default class Foo { + protected source: boolean; +} + +//// [Bar.d.ts] +// This is *not* the same! +export const x: number; + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [index.ts] +import Foo from "foo/Foo"; +import { x } from "foo/Bar"; + + +//// [index.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.symbols b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.symbols new file mode 100644 index 00000000000..2174580394b --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.symbols @@ -0,0 +1,20 @@ +=== /index.ts === +import Foo from "foo/Foo"; +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) + +import { x } from "foo/Bar"; +>x : Symbol(x, Decl(index.ts, 1, 8)) + +=== /node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Symbol(Foo, Decl(Foo.d.ts, 0, 0)) + + protected source: boolean; +>source : Symbol(Foo.source, Decl(Foo.d.ts, 0, 26)) +} + +=== /node_modules/foo/Bar.d.ts === +// This is *not* the same! +export const x: number; +>x : Symbol(x, Decl(Bar.d.ts, 1, 12)) + diff --git a/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.types b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.types new file mode 100644 index 00000000000..8b0501d46c3 --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_packageIdIncludesSubModule.types @@ -0,0 +1,20 @@ +=== /index.ts === +import Foo from "foo/Foo"; +>Foo : typeof Foo + +import { x } from "foo/Bar"; +>x : number + +=== /node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Foo + + protected source: boolean; +>source : boolean +} + +=== /node_modules/foo/Bar.d.ts === +// This is *not* the same! +export const x: number; +>x : number + diff --git a/tests/baselines/reference/duplicatePackage_referenceTypes.js b/tests/baselines/reference/duplicatePackage_referenceTypes.js new file mode 100644 index 00000000000..2abd8090e07 --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_referenceTypes.js @@ -0,0 +1,31 @@ +//// [tests/cases/compiler/duplicatePackage_referenceTypes.ts] //// + +//// [index.d.ts] +/// +import { Foo } from "foo"; +export const foo: Foo; + +//// [index.d.ts] +export class Foo { private x; } + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [index.d.ts] +export class Foo { private x; } + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [index.ts] +import * as a from "a"; +import { Foo } from "foo"; + +let foo: Foo = a.foo; + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var a = require("a"); +var foo = a.foo; diff --git a/tests/baselines/reference/duplicatePackage_referenceTypes.symbols b/tests/baselines/reference/duplicatePackage_referenceTypes.symbols new file mode 100644 index 00000000000..164da1c61d0 --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_referenceTypes.symbols @@ -0,0 +1,33 @@ +=== /index.ts === +import * as a from "a"; +>a : Symbol(a, Decl(index.ts, 0, 6)) + +import { Foo } from "foo"; +>Foo : Symbol(Foo, Decl(index.ts, 1, 8)) + +let foo: Foo = a.foo; +>foo : Symbol(foo, Decl(index.ts, 3, 3)) +>Foo : Symbol(Foo, Decl(index.ts, 1, 8)) +>a.foo : Symbol(a.foo, Decl(index.d.ts, 2, 12)) +>a : Symbol(a, Decl(index.ts, 0, 6)) +>foo : Symbol(a.foo, Decl(index.d.ts, 2, 12)) + +=== /node_modules/a/index.d.ts === +/// +import { Foo } from "foo"; +>Foo : Symbol(Foo, Decl(index.d.ts, 1, 8)) + +export const foo: Foo; +>foo : Symbol(foo, Decl(index.d.ts, 2, 12)) +>Foo : Symbol(Foo, Decl(index.d.ts, 1, 8)) + +=== /node_modules/a/node_modules/foo/index.d.ts === +export class Foo { private x; } +>Foo : Symbol(Foo, Decl(index.d.ts, 0, 0)) +>x : Symbol(Foo.x, Decl(index.d.ts, 0, 18)) + +=== /node_modules/@types/foo/index.d.ts === +export class Foo { private x; } +>Foo : Symbol(Foo, Decl(index.d.ts, 0, 0)) +>x : Symbol(Foo.x, Decl(index.d.ts, 0, 18)) + diff --git a/tests/baselines/reference/duplicatePackage_referenceTypes.types b/tests/baselines/reference/duplicatePackage_referenceTypes.types new file mode 100644 index 00000000000..b7159e299f0 --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_referenceTypes.types @@ -0,0 +1,33 @@ +=== /index.ts === +import * as a from "a"; +>a : typeof a + +import { Foo } from "foo"; +>Foo : typeof Foo + +let foo: Foo = a.foo; +>foo : Foo +>Foo : Foo +>a.foo : Foo +>a : typeof a +>foo : Foo + +=== /node_modules/a/index.d.ts === +/// +import { Foo } from "foo"; +>Foo : typeof Foo + +export const foo: Foo; +>foo : Foo +>Foo : Foo + +=== /node_modules/a/node_modules/foo/index.d.ts === +export class Foo { private x; } +>Foo : Foo +>x : any + +=== /node_modules/@types/foo/index.d.ts === +export class Foo { private x; } +>Foo : Foo +>x : any + diff --git a/tests/baselines/reference/duplicatePackage_subModule.js b/tests/baselines/reference/duplicatePackage_subModule.js new file mode 100644 index 00000000000..0a5793a79a2 --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_subModule.js @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/duplicatePackage_subModule.ts] //// + +//// [index.d.ts] +import Foo from "foo/Foo"; +export const o: Foo; + +//// [Foo.d.ts] +export default class Foo { + protected source: boolean; +} + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [Foo.d.ts] +export default class Foo { + protected source: boolean; +} + +//// [package.json] +{ "name": "foo", "version": "1.2.3" } + +//// [index.ts] +import Foo from "foo/Foo"; +import * as a from "a"; + +const o: Foo = a.o; + + +//// [index.js] +"use strict"; +exports.__esModule = true; +var a = require("a"); +var o = a.o; diff --git a/tests/baselines/reference/duplicatePackage_subModule.symbols b/tests/baselines/reference/duplicatePackage_subModule.symbols new file mode 100644 index 00000000000..538cd0d827d --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_subModule.symbols @@ -0,0 +1,38 @@ +=== /index.ts === +import Foo from "foo/Foo"; +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) + +import * as a from "a"; +>a : Symbol(a, Decl(index.ts, 1, 6)) + +const o: Foo = a.o; +>o : Symbol(o, Decl(index.ts, 3, 5)) +>Foo : Symbol(Foo, Decl(index.ts, 0, 6)) +>a.o : Symbol(a.o, Decl(index.d.ts, 1, 12)) +>a : Symbol(a, Decl(index.ts, 1, 6)) +>o : Symbol(a.o, Decl(index.d.ts, 1, 12)) + +=== /node_modules/a/index.d.ts === +import Foo from "foo/Foo"; +>Foo : Symbol(Foo, Decl(index.d.ts, 0, 6)) + +export const o: Foo; +>o : Symbol(o, Decl(index.d.ts, 1, 12)) +>Foo : Symbol(Foo, Decl(index.d.ts, 0, 6)) + +=== /node_modules/a/node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Symbol(Foo, Decl(Foo.d.ts, 0, 0)) + + protected source: boolean; +>source : Symbol(Foo.source, Decl(Foo.d.ts, 0, 26)) +} + +=== /node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Symbol(Foo, Decl(Foo.d.ts, 0, 0)) + + protected source: boolean; +>source : Symbol(Foo.source, Decl(Foo.d.ts, 0, 26)) +} + diff --git a/tests/baselines/reference/duplicatePackage_subModule.types b/tests/baselines/reference/duplicatePackage_subModule.types new file mode 100644 index 00000000000..047f16d37ab --- /dev/null +++ b/tests/baselines/reference/duplicatePackage_subModule.types @@ -0,0 +1,38 @@ +=== /index.ts === +import Foo from "foo/Foo"; +>Foo : typeof Foo + +import * as a from "a"; +>a : typeof a + +const o: Foo = a.o; +>o : Foo +>Foo : Foo +>a.o : Foo +>a : typeof a +>o : Foo + +=== /node_modules/a/index.d.ts === +import Foo from "foo/Foo"; +>Foo : typeof Foo + +export const o: Foo; +>o : Foo +>Foo : Foo + +=== /node_modules/a/node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Foo + + protected source: boolean; +>source : boolean +} + +=== /node_modules/foo/Foo.d.ts === +export default class Foo { +>Foo : Foo + + protected source: boolean; +>source : boolean +} + diff --git a/tests/baselines/reference/library-reference-11.trace.json b/tests/baselines/reference/library-reference-11.trace.json index 053dc497065..ef99bb8912f 100644 --- a/tests/baselines/reference/library-reference-11.trace.json +++ b/tests/baselines/reference/library-reference-11.trace.json @@ -3,8 +3,8 @@ "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/a/b'.", "Directory '/a/b/node_modules' does not exist, skipping all lookups in it.", - "File '/a/node_modules/jquery.d.ts' does not exist.", "Found 'package.json' at '/a/node_modules/jquery/package.json'.", + "File '/a/node_modules/jquery.d.ts' does not exist.", "'package.json' has 'typings' field 'jquery.d.ts' that references '/a/node_modules/jquery/jquery.d.ts'.", "File '/a/node_modules/jquery/jquery.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/a/node_modules/jquery/jquery.d.ts', result '/a/node_modules/jquery/jquery.d.ts'.", diff --git a/tests/baselines/reference/library-reference-12.trace.json b/tests/baselines/reference/library-reference-12.trace.json index d990709cac8..22b1232d30b 100644 --- a/tests/baselines/reference/library-reference-12.trace.json +++ b/tests/baselines/reference/library-reference-12.trace.json @@ -3,8 +3,8 @@ "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/a/b'.", "Directory '/a/b/node_modules' does not exist, skipping all lookups in it.", - "File '/a/node_modules/jquery.d.ts' does not exist.", "Found 'package.json' at '/a/node_modules/jquery/package.json'.", + "File '/a/node_modules/jquery.d.ts' does not exist.", "'package.json' does not have a 'typings' field.", "'package.json' has 'types' field 'dist/jquery.d.ts' that references '/a/node_modules/jquery/dist/jquery.d.ts'.", "File '/a/node_modules/jquery/dist/jquery.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/library-reference-3.trace.json b/tests/baselines/reference/library-reference-3.trace.json index 22747738c10..5b084f13738 100644 --- a/tests/baselines/reference/library-reference-3.trace.json +++ b/tests/baselines/reference/library-reference-3.trace.json @@ -2,8 +2,8 @@ "======== Resolving type reference directive 'jquery', containing file '/src/consumer.ts', root directory not set. ========", "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/src'.", - "File '/src/node_modules/jquery.d.ts' does not exist.", "File '/src/node_modules/jquery/package.json' does not exist.", + "File '/src/node_modules/jquery.d.ts' does not exist.", "File '/src/node_modules/jquery/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/src/node_modules/jquery/index.d.ts', result '/src/node_modules/jquery/index.d.ts'.", "======== Type reference directive 'jquery' was successfully resolved to '/src/node_modules/jquery/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/library-reference-4.trace.json b/tests/baselines/reference/library-reference-4.trace.json index 03fdfa0e863..ceeb754bb0b 100644 --- a/tests/baselines/reference/library-reference-4.trace.json +++ b/tests/baselines/reference/library-reference-4.trace.json @@ -3,8 +3,8 @@ "Resolving with primary search path '/src'.", "Looking up in 'node_modules' folder, initial location '/src'.", "Directory '/src/node_modules' does not exist, skipping all lookups in it.", - "File '/node_modules/foo.d.ts' does not exist.", "File '/node_modules/foo/package.json' does not exist.", + "File '/node_modules/foo.d.ts' does not exist.", "File '/node_modules/foo/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/foo/index.d.ts', result '/node_modules/foo/index.d.ts'.", "======== Type reference directive 'foo' was successfully resolved to '/node_modules/foo/index.d.ts', primary: false. ========", @@ -12,24 +12,24 @@ "Resolving with primary search path '/src'.", "Looking up in 'node_modules' folder, initial location '/src'.", "Directory '/src/node_modules' does not exist, skipping all lookups in it.", - "File '/node_modules/bar.d.ts' does not exist.", "File '/node_modules/bar/package.json' does not exist.", + "File '/node_modules/bar.d.ts' does not exist.", "File '/node_modules/bar/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/bar/index.d.ts', result '/node_modules/bar/index.d.ts'.", "======== Type reference directive 'bar' was successfully resolved to '/node_modules/bar/index.d.ts', primary: false. ========", "======== Resolving type reference directive 'alpha', containing file '/node_modules/foo/index.d.ts', root directory '/src'. ========", "Resolving with primary search path '/src'.", "Looking up in 'node_modules' folder, initial location '/node_modules/foo'.", - "File '/node_modules/foo/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/foo/node_modules/alpha/package.json' does not exist.", + "File '/node_modules/foo/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/foo/node_modules/alpha/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/foo/node_modules/alpha/index.d.ts', result '/node_modules/foo/node_modules/alpha/index.d.ts'.", "======== Type reference directive 'alpha' was successfully resolved to '/node_modules/foo/node_modules/alpha/index.d.ts', primary: false. ========", "======== Resolving type reference directive 'alpha', containing file '/node_modules/bar/index.d.ts', root directory '/src'. ========", "Resolving with primary search path '/src'.", "Looking up in 'node_modules' folder, initial location '/node_modules/bar'.", - "File '/node_modules/bar/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/bar/node_modules/alpha/package.json' does not exist.", + "File '/node_modules/bar/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/bar/node_modules/alpha/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/bar/node_modules/alpha/index.d.ts', result '/node_modules/bar/node_modules/alpha/index.d.ts'.", "======== Type reference directive 'alpha' was successfully resolved to '/node_modules/bar/node_modules/alpha/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/library-reference-5.trace.json b/tests/baselines/reference/library-reference-5.trace.json index cb14078670a..0cac2a8fec6 100644 --- a/tests/baselines/reference/library-reference-5.trace.json +++ b/tests/baselines/reference/library-reference-5.trace.json @@ -4,8 +4,8 @@ "Directory 'types' does not exist, skipping all lookups in it.", "Looking up in 'node_modules' folder, initial location '/src'.", "Directory '/src/node_modules' does not exist, skipping all lookups in it.", - "File '/node_modules/foo.d.ts' does not exist.", "File '/node_modules/foo/package.json' does not exist.", + "File '/node_modules/foo.d.ts' does not exist.", "File '/node_modules/foo/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/foo/index.d.ts', result '/node_modules/foo/index.d.ts'.", "======== Type reference directive 'foo' was successfully resolved to '/node_modules/foo/index.d.ts', primary: false. ========", @@ -14,8 +14,8 @@ "Directory 'types' does not exist, skipping all lookups in it.", "Looking up in 'node_modules' folder, initial location '/src'.", "Directory '/src/node_modules' does not exist, skipping all lookups in it.", - "File '/node_modules/bar.d.ts' does not exist.", "File '/node_modules/bar/package.json' does not exist.", + "File '/node_modules/bar.d.ts' does not exist.", "File '/node_modules/bar/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/bar/index.d.ts', result '/node_modules/bar/index.d.ts'.", "======== Type reference directive 'bar' was successfully resolved to '/node_modules/bar/index.d.ts', primary: false. ========", @@ -23,8 +23,8 @@ "Resolving with primary search path 'types'.", "Directory 'types' does not exist, skipping all lookups in it.", "Looking up in 'node_modules' folder, initial location '/node_modules/foo'.", - "File '/node_modules/foo/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/foo/node_modules/alpha/package.json' does not exist.", + "File '/node_modules/foo/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/foo/node_modules/alpha/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/foo/node_modules/alpha/index.d.ts', result '/node_modules/foo/node_modules/alpha/index.d.ts'.", "======== Type reference directive 'alpha' was successfully resolved to '/node_modules/foo/node_modules/alpha/index.d.ts', primary: false. ========", @@ -32,8 +32,8 @@ "Resolving with primary search path 'types'.", "Directory 'types' does not exist, skipping all lookups in it.", "Looking up in 'node_modules' folder, initial location '/node_modules/bar'.", - "File '/node_modules/bar/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/bar/node_modules/alpha/package.json' does not exist.", + "File '/node_modules/bar/node_modules/alpha.d.ts' does not exist.", "File '/node_modules/bar/node_modules/alpha/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/bar/node_modules/alpha/index.d.ts', result '/node_modules/bar/node_modules/alpha/index.d.ts'.", "======== Type reference directive 'alpha' was successfully resolved to '/node_modules/bar/node_modules/alpha/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/library-reference-7.trace.json b/tests/baselines/reference/library-reference-7.trace.json index 22747738c10..5b084f13738 100644 --- a/tests/baselines/reference/library-reference-7.trace.json +++ b/tests/baselines/reference/library-reference-7.trace.json @@ -2,8 +2,8 @@ "======== Resolving type reference directive 'jquery', containing file '/src/consumer.ts', root directory not set. ========", "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/src'.", - "File '/src/node_modules/jquery.d.ts' does not exist.", "File '/src/node_modules/jquery/package.json' does not exist.", + "File '/src/node_modules/jquery.d.ts' does not exist.", "File '/src/node_modules/jquery/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/src/node_modules/jquery/index.d.ts', result '/src/node_modules/jquery/index.d.ts'.", "======== Type reference directive 'jquery' was successfully resolved to '/src/node_modules/jquery/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/library-reference-scoped-packages.trace.json b/tests/baselines/reference/library-reference-scoped-packages.trace.json index 54dcf95fe50..cfc88198201 100644 --- a/tests/baselines/reference/library-reference-scoped-packages.trace.json +++ b/tests/baselines/reference/library-reference-scoped-packages.trace.json @@ -4,8 +4,8 @@ "Directory 'types/@beep' does not exist, skipping all lookups in it.", "Looking up in 'node_modules' folder, initial location '/'.", "Scoped package detected, looking in 'beep__boop'", - "File '/node_modules/@types/beep__boop.d.ts' does not exist.", "File '/node_modules/@types/beep__boop/package.json' does not exist.", + "File '/node_modules/@types/beep__boop.d.ts' does not exist.", "File '/node_modules/@types/beep__boop/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/beep__boop/index.d.ts', result '/node_modules/@types/beep__boop/index.d.ts'.", "======== Type reference directive '@beep/boop' was successfully resolved to '/node_modules/@types/beep__boop/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/maxNodeModuleJsDepthDefaultsToZero.trace.json b/tests/baselines/reference/maxNodeModuleJsDepthDefaultsToZero.trace.json index 46f03d1e8c4..56bbee705bf 100644 --- a/tests/baselines/reference/maxNodeModuleJsDepthDefaultsToZero.trace.json +++ b/tests/baselines/reference/maxNodeModuleJsDepthDefaultsToZero.trace.json @@ -2,18 +2,18 @@ "======== Resolving module 'shortid' from '/index.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'shortid' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/node_modules/shortid/package.json' does not exist.", "File '/node_modules/shortid.ts' does not exist.", "File '/node_modules/shortid.tsx' does not exist.", "File '/node_modules/shortid.d.ts' does not exist.", - "File '/node_modules/shortid/package.json' does not exist.", "File '/node_modules/shortid/index.ts' does not exist.", "File '/node_modules/shortid/index.tsx' does not exist.", "File '/node_modules/shortid/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'shortid' from 'node_modules' folder, target file type 'JavaScript'.", + "File '/node_modules/shortid/package.json' does not exist.", "File '/node_modules/shortid.js' does not exist.", "File '/node_modules/shortid.jsx' does not exist.", - "File '/node_modules/shortid/package.json' does not exist.", "File '/node_modules/shortid/index.js' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/shortid/index.js', result '/node_modules/shortid/index.js'.", "======== Module name 'shortid' was successfully resolved to '/node_modules/shortid/index.js'. ========" diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json index 8c820e07e48..b619535487b 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json @@ -2,10 +2,10 @@ "======== Resolving module 'normalize.css' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'normalize.css' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/normalize.css/package.json'.", "File '/node_modules/normalize.css.ts' does not exist.", "File '/node_modules/normalize.css.tsx' does not exist.", "File '/node_modules/normalize.css.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/normalize.css/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", "File '/node_modules/normalize.css/index.ts' does not exist.", @@ -13,9 +13,9 @@ "File '/node_modules/normalize.css/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'normalize.css' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/normalize.css/package.json'.", "File '/node_modules/normalize.css.js' does not exist.", "File '/node_modules/normalize.css.jsx' does not exist.", - "Found 'package.json' at '/node_modules/normalize.css/package.json'.", "'package.json' has 'main' field 'normalize.css' that references '/node_modules/normalize.css/normalize.css'.", "File '/node_modules/normalize.css/normalize.css' exist - use it as a name resolution result.", "File '/node_modules/normalize.css/normalize.css' has an unsupported extension, so skipping it.", diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json index 3632a5c2242..50e7fa685a6 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json @@ -2,10 +2,10 @@ "======== Resolving module 'foo' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.ts' does not exist.", "File '/node_modules/foo.tsx' does not exist.", "File '/node_modules/foo.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' has 'types' field 'foo.js' that references '/node_modules/foo/foo.js'.", "File '/node_modules/foo/foo.js' exist - use it as a name resolution result.", @@ -24,9 +24,9 @@ "File '/node_modules/foo/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'foo' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.js' does not exist.", "File '/node_modules/foo.jsx' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' does not have a 'main' field.", "File '/node_modules/foo/index.js' does not exist.", "File '/node_modules/foo/index.jsx' does not exist.", diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_withAmbientPresent.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_withAmbientPresent.trace.json index 6cfdb8b567e..9a0d5e095a5 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions_withAmbientPresent.trace.json +++ b/tests/baselines/reference/moduleResolutionWithExtensions_withAmbientPresent.trace.json @@ -2,18 +2,18 @@ "======== Resolving module 'js' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'js' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/node_modules/js/package.json' does not exist.", "File '/node_modules/js.ts' does not exist.", "File '/node_modules/js.tsx' does not exist.", "File '/node_modules/js.d.ts' does not exist.", - "File '/node_modules/js/package.json' does not exist.", "File '/node_modules/js/index.ts' does not exist.", "File '/node_modules/js/index.tsx' does not exist.", "File '/node_modules/js/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'js' from 'node_modules' folder, target file type 'JavaScript'.", + "File '/node_modules/js/package.json' does not exist.", "File '/node_modules/js.js' does not exist.", "File '/node_modules/js.jsx' does not exist.", - "File '/node_modules/js/package.json' does not exist.", "File '/node_modules/js/index.js' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/js/index.js', result '/node_modules/js/index.js'.", "======== Module name 'js' was successfully resolved to '/node_modules/js/index.js'. ========" diff --git a/tests/baselines/reference/moduleResolutionWithSymlinks.trace.json b/tests/baselines/reference/moduleResolutionWithSymlinks.trace.json index 2dd33953680..19e44e72d61 100644 --- a/tests/baselines/reference/moduleResolutionWithSymlinks.trace.json +++ b/tests/baselines/reference/moduleResolutionWithSymlinks.trace.json @@ -20,10 +20,10 @@ "======== Resolving module 'library-a' from '/src/library-b/index.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'library-a' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/src/library-b/node_modules/library-a/package.json' does not exist.", "File '/src/library-b/node_modules/library-a.ts' does not exist.", "File '/src/library-b/node_modules/library-a.tsx' does not exist.", "File '/src/library-b/node_modules/library-a.d.ts' does not exist.", - "File '/src/library-b/node_modules/library-a/package.json' does not exist.", "File '/src/library-b/node_modules/library-a/index.ts' exist - use it as a name resolution result.", "Resolving real path for '/src/library-b/node_modules/library-a/index.ts', result '/src/library-a/index.ts'.", "======== Module name 'library-a' was successfully resolved to '/src/library-a/index.ts'. ========" diff --git a/tests/baselines/reference/moduleResolutionWithSymlinks_preserveSymlinks.trace.json b/tests/baselines/reference/moduleResolutionWithSymlinks_preserveSymlinks.trace.json index 837b740ffee..73e6a1df996 100644 --- a/tests/baselines/reference/moduleResolutionWithSymlinks_preserveSymlinks.trace.json +++ b/tests/baselines/reference/moduleResolutionWithSymlinks_preserveSymlinks.trace.json @@ -2,18 +2,18 @@ "======== Resolving type reference directive 'linked', containing file '/app/app.ts', root directory not set. ========", "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/app'.", - "File '/app/node_modules/linked.d.ts' does not exist.", "File '/app/node_modules/linked/package.json' does not exist.", + "File '/app/node_modules/linked.d.ts' does not exist.", "File '/app/node_modules/linked/index.d.ts' exist - use it as a name resolution result.", "======== Type reference directive 'linked' was successfully resolved to '/app/node_modules/linked/index.d.ts', primary: false. ========", "======== Resolving module 'real' from '/app/node_modules/linked/index.d.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'real' from 'node_modules' folder, target file type 'TypeScript'.", "Directory '/app/node_modules/linked/node_modules' does not exist, skipping all lookups in it.", + "File '/app/node_modules/real/package.json' does not exist.", "File '/app/node_modules/real.ts' does not exist.", "File '/app/node_modules/real.tsx' does not exist.", "File '/app/node_modules/real.d.ts' does not exist.", - "File '/app/node_modules/real/package.json' does not exist.", "File '/app/node_modules/real/index.ts' does not exist.", "File '/app/node_modules/real/index.tsx' does not exist.", "File '/app/node_modules/real/index.d.ts' exist - use it as a name resolution result.", @@ -21,10 +21,10 @@ "======== Resolving module 'linked' from '/app/app.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'linked' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/app/node_modules/linked/package.json' does not exist.", "File '/app/node_modules/linked.ts' does not exist.", "File '/app/node_modules/linked.tsx' does not exist.", "File '/app/node_modules/linked.d.ts' does not exist.", - "File '/app/node_modules/linked/package.json' does not exist.", "File '/app/node_modules/linked/index.ts' does not exist.", "File '/app/node_modules/linked/index.tsx' does not exist.", "File '/app/node_modules/linked/index.d.ts' exist - use it as a name resolution result.", @@ -32,10 +32,10 @@ "======== Resolving module 'linked2' from '/app/app.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'linked2' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/app/node_modules/linked2/package.json' does not exist.", "File '/app/node_modules/linked2.ts' does not exist.", "File '/app/node_modules/linked2.tsx' does not exist.", "File '/app/node_modules/linked2.d.ts' does not exist.", - "File '/app/node_modules/linked2/package.json' does not exist.", "File '/app/node_modules/linked2/index.ts' does not exist.", "File '/app/node_modules/linked2/index.tsx' does not exist.", "File '/app/node_modules/linked2/index.d.ts' exist - use it as a name resolution result.", @@ -44,10 +44,10 @@ "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'real' from 'node_modules' folder, target file type 'TypeScript'.", "Directory '/app/node_modules/linked2/node_modules' does not exist, skipping all lookups in it.", + "File '/app/node_modules/real/package.json' does not exist.", "File '/app/node_modules/real.ts' does not exist.", "File '/app/node_modules/real.tsx' does not exist.", "File '/app/node_modules/real.d.ts' does not exist.", - "File '/app/node_modules/real/package.json' does not exist.", "File '/app/node_modules/real/index.ts' does not exist.", "File '/app/node_modules/real/index.tsx' does not exist.", "File '/app/node_modules/real/index.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/moduleResolutionWithSymlinks_referenceTypes.trace.json b/tests/baselines/reference/moduleResolutionWithSymlinks_referenceTypes.trace.json index 65d89ed7458..48be1a4cda8 100644 --- a/tests/baselines/reference/moduleResolutionWithSymlinks_referenceTypes.trace.json +++ b/tests/baselines/reference/moduleResolutionWithSymlinks_referenceTypes.trace.json @@ -3,8 +3,8 @@ "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/'.", "File '/node_modules/library-a.d.ts' does not exist.", - "File '/node_modules/@types/library-a.d.ts' does not exist.", "File '/node_modules/@types/library-a/package.json' does not exist.", + "File '/node_modules/@types/library-a.d.ts' does not exist.", "File '/node_modules/@types/library-a/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/library-a/index.d.ts', result '/node_modules/@types/library-a/index.d.ts'.", "======== Type reference directive 'library-a' was successfully resolved to '/node_modules/@types/library-a/index.d.ts', primary: false. ========", @@ -12,8 +12,8 @@ "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/'.", "File '/node_modules/library-b.d.ts' does not exist.", - "File '/node_modules/@types/library-b.d.ts' does not exist.", "File '/node_modules/@types/library-b/package.json' does not exist.", + "File '/node_modules/@types/library-b.d.ts' does not exist.", "File '/node_modules/@types/library-b/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/library-b/index.d.ts', result '/node_modules/@types/library-b/index.d.ts'.", "======== Type reference directive 'library-b' was successfully resolved to '/node_modules/@types/library-b/index.d.ts', primary: false. ========", @@ -21,8 +21,8 @@ "Root directory cannot be determined, skipping primary search paths.", "Looking up in 'node_modules' folder, initial location '/node_modules/@types/library-b'.", "File '/node_modules/@types/library-b/node_modules/library-a.d.ts' does not exist.", - "File '/node_modules/@types/library-b/node_modules/@types/library-a.d.ts' does not exist.", "File '/node_modules/@types/library-b/node_modules/@types/library-a/package.json' does not exist.", + "File '/node_modules/@types/library-b/node_modules/@types/library-a.d.ts' does not exist.", "File '/node_modules/@types/library-b/node_modules/@types/library-a/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/library-b/node_modules/@types/library-a/index.d.ts', result '/node_modules/@types/library-a/index.d.ts'.", "======== Type reference directive 'library-a' was successfully resolved to '/node_modules/@types/library-a/index.d.ts', primary: false. ========" diff --git a/tests/baselines/reference/moduleResolutionWithSymlinks_withOutDir.trace.json b/tests/baselines/reference/moduleResolutionWithSymlinks_withOutDir.trace.json index 2dd33953680..19e44e72d61 100644 --- a/tests/baselines/reference/moduleResolutionWithSymlinks_withOutDir.trace.json +++ b/tests/baselines/reference/moduleResolutionWithSymlinks_withOutDir.trace.json @@ -20,10 +20,10 @@ "======== Resolving module 'library-a' from '/src/library-b/index.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'library-a' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/src/library-b/node_modules/library-a/package.json' does not exist.", "File '/src/library-b/node_modules/library-a.ts' does not exist.", "File '/src/library-b/node_modules/library-a.tsx' does not exist.", "File '/src/library-b/node_modules/library-a.d.ts' does not exist.", - "File '/src/library-b/node_modules/library-a/package.json' does not exist.", "File '/src/library-b/node_modules/library-a/index.ts' exist - use it as a name resolution result.", "Resolving real path for '/src/library-b/node_modules/library-a/index.ts', result '/src/library-a/index.ts'.", "======== Module name 'library-a' was successfully resolved to '/src/library-a/index.ts'. ========" diff --git a/tests/baselines/reference/packageJsonMain.trace.json b/tests/baselines/reference/packageJsonMain.trace.json index 08daccbe479..842f70c3a02 100644 --- a/tests/baselines/reference/packageJsonMain.trace.json +++ b/tests/baselines/reference/packageJsonMain.trace.json @@ -2,10 +2,10 @@ "======== Resolving module 'foo' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.ts' does not exist.", "File '/node_modules/foo.tsx' does not exist.", "File '/node_modules/foo.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", "File '/node_modules/foo/index.ts' does not exist.", @@ -13,9 +13,9 @@ "File '/node_modules/foo/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'foo' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.js' does not exist.", "File '/node_modules/foo.jsx' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' has 'main' field 'oof' that references '/node_modules/foo/oof'.", "File '/node_modules/foo/oof' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/foo/oof', target file type 'JavaScript'.", @@ -25,10 +25,10 @@ "======== Resolving module 'bar' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'bar' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/bar/package.json'.", "File '/node_modules/bar.ts' does not exist.", "File '/node_modules/bar.tsx' does not exist.", "File '/node_modules/bar.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/bar/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", "File '/node_modules/bar/index.ts' does not exist.", @@ -36,9 +36,9 @@ "File '/node_modules/bar/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'bar' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/bar/package.json'.", "File '/node_modules/bar.js' does not exist.", "File '/node_modules/bar.jsx' does not exist.", - "Found 'package.json' at '/node_modules/bar/package.json'.", "'package.json' has 'main' field 'rab.js' that references '/node_modules/bar/rab.js'.", "File '/node_modules/bar/rab.js' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/bar/rab.js', result '/node_modules/bar/rab.js'.", @@ -46,10 +46,10 @@ "======== Resolving module 'baz' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'baz' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/baz/package.json'.", "File '/node_modules/baz.ts' does not exist.", "File '/node_modules/baz.tsx' does not exist.", "File '/node_modules/baz.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/baz/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", "File '/node_modules/baz/index.ts' does not exist.", @@ -57,9 +57,9 @@ "File '/node_modules/baz/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'baz' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/baz/package.json'.", "File '/node_modules/baz.js' does not exist.", "File '/node_modules/baz.jsx' does not exist.", - "Found 'package.json' at '/node_modules/baz/package.json'.", "'package.json' has 'main' field 'zab' that references '/node_modules/baz/zab'.", "File '/node_modules/baz/zab' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/baz/zab', target file type 'JavaScript'.", diff --git a/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json b/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json index 53e1ad25605..763c86730ba 100644 --- a/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json +++ b/tests/baselines/reference/packageJsonMain_isNonRecursive.trace.json @@ -2,10 +2,10 @@ "======== Resolving module 'foo' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.ts' does not exist.", "File '/node_modules/foo.tsx' does not exist.", "File '/node_modules/foo.d.ts' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' does not have a 'typings' field.", "'package.json' does not have a 'types' field.", "File '/node_modules/foo/index.ts' does not exist.", @@ -13,9 +13,9 @@ "File '/node_modules/foo/index.d.ts' does not exist.", "Directory '/node_modules/@types' does not exist, skipping all lookups in it.", "Loading module 'foo' from 'node_modules' folder, target file type 'JavaScript'.", + "Found 'package.json' at '/node_modules/foo/package.json'.", "File '/node_modules/foo.js' does not exist.", "File '/node_modules/foo.jsx' does not exist.", - "Found 'package.json' at '/node_modules/foo/package.json'.", "'package.json' has 'main' field 'oof' that references '/node_modules/foo/oof'.", "File '/node_modules/foo/oof' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/foo/oof', target file type 'JavaScript'.", diff --git a/tests/baselines/reference/pathMappingBasedModuleResolution3_node.trace.json b/tests/baselines/reference/pathMappingBasedModuleResolution3_node.trace.json index 6ac06e1dda1..ef2cb3b367f 100644 --- a/tests/baselines/reference/pathMappingBasedModuleResolution3_node.trace.json +++ b/tests/baselines/reference/pathMappingBasedModuleResolution3_node.trace.json @@ -23,10 +23,10 @@ "Loading module 'file4' from 'node_modules' folder, target file type 'TypeScript'.", "Directory 'c:/root/folder2/node_modules' does not exist, skipping all lookups in it.", "Directory 'c:/root/node_modules' does not exist, skipping all lookups in it.", + "File 'c:/node_modules/file4/package.json' does not exist.", "File 'c:/node_modules/file4.ts' does not exist.", "File 'c:/node_modules/file4.tsx' does not exist.", "File 'c:/node_modules/file4.d.ts' does not exist.", - "File 'c:/node_modules/file4/package.json' does not exist.", "File 'c:/node_modules/file4/index.ts' does not exist.", "File 'c:/node_modules/file4/index.tsx' does not exist.", "File 'c:/node_modules/file4/index.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/pathMappingBasedModuleResolution4_node.trace.json b/tests/baselines/reference/pathMappingBasedModuleResolution4_node.trace.json index 6ac06e1dda1..ef2cb3b367f 100644 --- a/tests/baselines/reference/pathMappingBasedModuleResolution4_node.trace.json +++ b/tests/baselines/reference/pathMappingBasedModuleResolution4_node.trace.json @@ -23,10 +23,10 @@ "Loading module 'file4' from 'node_modules' folder, target file type 'TypeScript'.", "Directory 'c:/root/folder2/node_modules' does not exist, skipping all lookups in it.", "Directory 'c:/root/node_modules' does not exist, skipping all lookups in it.", + "File 'c:/node_modules/file4/package.json' does not exist.", "File 'c:/node_modules/file4.ts' does not exist.", "File 'c:/node_modules/file4.tsx' does not exist.", "File 'c:/node_modules/file4.d.ts' does not exist.", - "File 'c:/node_modules/file4/package.json' does not exist.", "File 'c:/node_modules/file4/index.ts' does not exist.", "File 'c:/node_modules/file4/index.tsx' does not exist.", "File 'c:/node_modules/file4/index.d.ts' exist - use it as a name resolution result.", diff --git a/tests/baselines/reference/scopedPackages.trace.json b/tests/baselines/reference/scopedPackages.trace.json index 20df3bec172..a2b8af48266 100644 --- a/tests/baselines/reference/scopedPackages.trace.json +++ b/tests/baselines/reference/scopedPackages.trace.json @@ -2,10 +2,10 @@ "======== Resolving module '@cow/boy' from '/a.ts'. ========", "Module resolution kind is not specified, using 'NodeJs'.", "Loading module '@cow/boy' from 'node_modules' folder, target file type 'TypeScript'.", + "File '/node_modules/@cow/package.json' does not exist.", "File '/node_modules/@cow/boy.ts' does not exist.", "File '/node_modules/@cow/boy.tsx' does not exist.", "File '/node_modules/@cow/boy.d.ts' does not exist.", - "File '/node_modules/@cow/boy/package.json' does not exist.", "File '/node_modules/@cow/boy/index.ts' does not exist.", "File '/node_modules/@cow/boy/index.tsx' does not exist.", "File '/node_modules/@cow/boy/index.d.ts' exist - use it as a name resolution result.", @@ -15,8 +15,8 @@ "Module resolution kind is not specified, using 'NodeJs'.", "Loading module '@be/bop' from 'node_modules' folder, target file type 'TypeScript'.", "Scoped package detected, looking in 'be__bop'", - "File '/node_modules/@types/be__bop.d.ts' does not exist.", "File '/node_modules/@types/be__bop/package.json' does not exist.", + "File '/node_modules/@types/be__bop.d.ts' does not exist.", "File '/node_modules/@types/be__bop/index.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/be__bop/index.d.ts', result '/node_modules/@types/be__bop/index.d.ts'.", "======== Module name '@be/bop' was successfully resolved to '/node_modules/@types/be__bop/index.d.ts'. ========", @@ -24,6 +24,7 @@ "Module resolution kind is not specified, using 'NodeJs'.", "Loading module '@be/bop/e/z' from 'node_modules' folder, target file type 'TypeScript'.", "Scoped package detected, looking in 'be__bop/e/z'", + "File '/node_modules/@types/be__bop/package.json' does not exist.", "File '/node_modules/@types/be__bop/e/z.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/be__bop/e/z.d.ts', result '/node_modules/@types/be__bop/e/z.d.ts'.", "======== Module name '@be/bop/e/z' was successfully resolved to '/node_modules/@types/be__bop/e/z.d.ts'. ========" diff --git a/tests/baselines/reference/scopedPackagesClassic.trace.json b/tests/baselines/reference/scopedPackagesClassic.trace.json index c58c7d2ed10..b28156d1c33 100644 --- a/tests/baselines/reference/scopedPackagesClassic.trace.json +++ b/tests/baselines/reference/scopedPackagesClassic.trace.json @@ -2,8 +2,8 @@ "======== Resolving module '@see/saw' from '/a.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", "Scoped package detected, looking in 'see__saw'", - "File '/node_modules/@types/see__saw.d.ts' does not exist.", "File '/node_modules/@types/see__saw/package.json' does not exist.", + "File '/node_modules/@types/see__saw.d.ts' does not exist.", "File '/node_modules/@types/see__saw/index.d.ts' exist - use it as a name resolution result.", "======== Module name '@see/saw' was successfully resolved to '/node_modules/@types/see__saw/index.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/typingsLookup4.trace.json b/tests/baselines/reference/typingsLookup4.trace.json index d2087308d8e..133ea49c22a 100644 --- a/tests/baselines/reference/typingsLookup4.trace.json +++ b/tests/baselines/reference/typingsLookup4.trace.json @@ -5,8 +5,8 @@ "File '/node_modules/jquery.ts' does not exist.", "File '/node_modules/jquery.tsx' does not exist.", "File '/node_modules/jquery.d.ts' does not exist.", - "File '/node_modules/@types/jquery.d.ts' does not exist.", "Found 'package.json' at '/node_modules/@types/jquery/package.json'.", + "File '/node_modules/@types/jquery.d.ts' does not exist.", "'package.json' has 'typings' field 'jquery.d.ts' that references '/node_modules/@types/jquery/jquery.d.ts'.", "File '/node_modules/@types/jquery/jquery.d.ts' exist - use it as a name resolution result.", "Resolving real path for '/node_modules/@types/jquery/jquery.d.ts', result '/node_modules/@types/jquery/jquery.d.ts'.", @@ -17,8 +17,8 @@ "File '/node_modules/kquery.ts' does not exist.", "File '/node_modules/kquery.tsx' does not exist.", "File '/node_modules/kquery.d.ts' does not exist.", - "File '/node_modules/@types/kquery.d.ts' does not exist.", "Found 'package.json' at '/node_modules/@types/kquery/package.json'.", + "File '/node_modules/@types/kquery.d.ts' does not exist.", "'package.json' has 'typings' field 'kquery' that references '/node_modules/@types/kquery/kquery'.", "File '/node_modules/@types/kquery/kquery' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/@types/kquery/kquery', target file type 'TypeScript'.", @@ -33,8 +33,8 @@ "File '/node_modules/lquery.ts' does not exist.", "File '/node_modules/lquery.tsx' does not exist.", "File '/node_modules/lquery.d.ts' does not exist.", - "File '/node_modules/@types/lquery.d.ts' does not exist.", "Found 'package.json' at '/node_modules/@types/lquery/package.json'.", + "File '/node_modules/@types/lquery.d.ts' does not exist.", "'package.json' has 'typings' field 'lquery' that references '/node_modules/@types/lquery/lquery'.", "File '/node_modules/@types/lquery/lquery' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/@types/lquery/lquery', target file type 'TypeScript'.", @@ -47,8 +47,8 @@ "File '/node_modules/mquery.ts' does not exist.", "File '/node_modules/mquery.tsx' does not exist.", "File '/node_modules/mquery.d.ts' does not exist.", - "File '/node_modules/@types/mquery.d.ts' does not exist.", "Found 'package.json' at '/node_modules/@types/mquery/package.json'.", + "File '/node_modules/@types/mquery.d.ts' does not exist.", "'package.json' has 'typings' field 'mquery' that references '/node_modules/@types/mquery/mquery'.", "File '/node_modules/@types/mquery/mquery' does not exist.", "Loading module as file / folder, candidate module location '/node_modules/@types/mquery/mquery', target file type 'TypeScript'.", diff --git a/tests/baselines/reference/typingsLookupAmd.trace.json b/tests/baselines/reference/typingsLookupAmd.trace.json index ca64cf8fdf4..f18f63e7597 100644 --- a/tests/baselines/reference/typingsLookupAmd.trace.json +++ b/tests/baselines/reference/typingsLookupAmd.trace.json @@ -11,8 +11,8 @@ "File '/b.tsx' does not exist.", "File '/b.d.ts' does not exist.", "Directory '/x/y/node_modules' does not exist, skipping all lookups in it.", - "File '/x/node_modules/@types/b.d.ts' does not exist.", "File '/x/node_modules/@types/b/package.json' does not exist.", + "File '/x/node_modules/@types/b.d.ts' does not exist.", "File '/x/node_modules/@types/b/index.d.ts' exist - use it as a name resolution result.", "======== Module name 'b' was successfully resolved to '/x/node_modules/@types/b/index.d.ts'. ========", "======== Resolving module 'a' from '/x/node_modules/@types/b/index.d.ts'. ========", @@ -35,8 +35,8 @@ "Directory '/x/node_modules/@types/b/node_modules' does not exist, skipping all lookups in it.", "Directory '/x/node_modules/@types/node_modules' does not exist, skipping all lookups in it.", "File '/x/node_modules/@types/a.d.ts' does not exist.", - "File '/node_modules/@types/a.d.ts' does not exist.", "File '/node_modules/@types/a/package.json' does not exist.", + "File '/node_modules/@types/a.d.ts' does not exist.", "File '/node_modules/@types/a/index.d.ts' exist - use it as a name resolution result.", "======== Module name 'a' was successfully resolved to '/node_modules/@types/a/index.d.ts'. ========", "======== Resolving type reference directive 'a', containing file '/__inferred type names__.ts', root directory '/node_modules/@types'. ========", diff --git a/tests/cases/compiler/duplicatePackage_packageIdIncludesSubModule.ts b/tests/cases/compiler/duplicatePackage_packageIdIncludesSubModule.ts new file mode 100644 index 00000000000..19f56ed1325 --- /dev/null +++ b/tests/cases/compiler/duplicatePackage_packageIdIncludesSubModule.ts @@ -0,0 +1,17 @@ +// @noImplicitReferences: true + +// @Filename: /node_modules/foo/Foo.d.ts +export default class Foo { + protected source: boolean; +} + +// @Filename: /node_modules/foo/Bar.d.ts +// This is *not* the same! +export const x: number; + +// @Filename: /node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /index.ts +import Foo from "foo/Foo"; +import { x } from "foo/Bar"; diff --git a/tests/cases/compiler/duplicatePackage_referenceTypes.ts b/tests/cases/compiler/duplicatePackage_referenceTypes.ts new file mode 100644 index 00000000000..c6534fff70c --- /dev/null +++ b/tests/cases/compiler/duplicatePackage_referenceTypes.ts @@ -0,0 +1,24 @@ +// @noImplicitReferences: true + +// @Filename: /node_modules/a/index.d.ts +/// +import { Foo } from "foo"; +export const foo: Foo; + +// @Filename: /node_modules/a/node_modules/foo/index.d.ts +export class Foo { private x; } + +// @Filename: /node_modules/a/node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /node_modules/@types/foo/index.d.ts +export class Foo { private x; } + +// @Filename: /node_modules/@types/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /index.ts +import * as a from "a"; +import { Foo } from "foo"; + +let foo: Foo = a.foo; diff --git a/tests/cases/compiler/duplicatePackage_subModule.ts b/tests/cases/compiler/duplicatePackage_subModule.ts new file mode 100644 index 00000000000..4c704772eaf --- /dev/null +++ b/tests/cases/compiler/duplicatePackage_subModule.ts @@ -0,0 +1,27 @@ +// @noImplicitReferences: true + +// @Filename: /node_modules/a/index.d.ts +import Foo from "foo/Foo"; +export const o: Foo; + +// @Filename: /node_modules/a/node_modules/foo/Foo.d.ts +export default class Foo { + protected source: boolean; +} + +// @Filename: /node_modules/a/node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /node_modules/foo/Foo.d.ts +export default class Foo { + protected source: boolean; +} + +// @Filename: /node_modules/foo/package.json +{ "name": "foo", "version": "1.2.3" } + +// @Filename: /index.ts +import Foo from "foo/Foo"; +import * as a from "a"; + +const o: Foo = a.o; From 0e50da62c47368e7141301d0cf4e9cc105497ef2 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 30 Aug 2017 13:11:21 -0700 Subject: [PATCH 62/74] Handle the combination of a write and a void return When the return type is void, there's no `returnValueProperty`, but that doesn't mean we don't need a `return` at the call site. Fixes #18140. --- src/harness/unittests/extractMethods.ts | 7 +++++ src/services/refactors/extractMethod.ts | 4 +++ .../extractMethod/extractMethod21.ts | 26 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/baselines/reference/extractMethod/extractMethod21.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index c8b4b35ff1c..6fe57895725 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -613,6 +613,13 @@ namespace A { [#|let a1 = { x: 1 }; return a1.x + 10;|] } +}`); + // Write + void return + testExtractMethod("extractMethod21", + `function foo() { + let x = 10; + [#|x++; + return;|] }`); }); diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index 25a995dc231..c497b126759 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -748,6 +748,10 @@ namespace ts.refactor.extractMethod { } else { newNodes.push(createStatement(createBinary(assignments[0].name, SyntaxKind.EqualsToken, call))); + + if (range.facts & RangeFacts.HasReturn) { + newNodes.push(createReturn()); + } } } else { diff --git a/tests/baselines/reference/extractMethod/extractMethod21.ts b/tests/baselines/reference/extractMethod/extractMethod21.ts new file mode 100644 index 00000000000..4b73a6ed3c7 --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod21.ts @@ -0,0 +1,26 @@ +// ==ORIGINAL== +function foo() { + let x = 10; + x++; + return; +} +// ==SCOPE::function 'foo'== +function foo() { + let x = 10; + return newFunction(); + + function newFunction() { + x++; + return; + } +} +// ==SCOPE::global scope== +function foo() { + let x = 10; + x = newFunction(x); + return; +} +function newFunction(x: number) { + x++; + return x; +} From 27f9cdb1aec60c60ed2af52c2e4f470f6ee7dcbe Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 7 Sep 2017 15:54:24 -0700 Subject: [PATCH 63/74] Explicitly avoid canonicalizing paths during configuration handling (#18316) * Explicitly avoid canonicalizing paths during configuration handling * Extract usage of identity in commandLineParser into single function, use identity in checker --- src/compiler/checker.ts | 5 +---- src/compiler/commandLineParser.ts | 12 +++++++++--- src/compiler/core.ts | 3 +++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b05b69ef52..9c72a064b11 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -58,6 +58,7 @@ namespace ts { let symbolInstantiationDepth = 0; const emptySymbols = createSymbolTable(); + const identityMapper: (type: Type) => Type = identity; const compilerOptions = host.getCompilerOptions(); const languageVersion = getEmitScriptTarget(compilerOptions); @@ -8119,10 +8120,6 @@ namespace ts { mapper; } - function identityMapper(type: Type): Type { - return type; - } - function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper { return t => instantiateType(mapper1(t), mapper2); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index dc9c2ad35ed..54e5ee1d01d 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1385,6 +1385,12 @@ namespace ts { return x === undefined || x === null; } + function directoryOfCombinedPath(fileName: string, basePath: string) { + // Use the `identity` function to avoid canonicalizing the path, as it must remain noncanonical + // until consistient casing errors are reported + return getDirectoryPath(toPath(fileName, basePath, identity)); + } + /** * Parse the contents of a config file from json or json source file (tsconfig.json). * @param json The contents of the config file to parse @@ -1467,7 +1473,7 @@ namespace ts { includeSpecs = ["**/*"]; } - const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, configFileName ? getDirectoryPath(toPath(configFileName, basePath, createGetCanonicalFileName(host.useCaseSensitiveFileNames))) : basePath, options, host, errors, extraFileExtensions, sourceFile); + const result = matchFileNames(fileNames, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile); if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0) { errors.push( @@ -1577,7 +1583,7 @@ namespace ts { errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "extends", "string")); } else { - const newBase = configFileName ? getDirectoryPath(toPath(configFileName, basePath, getCanonicalFileName)) : basePath; + const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; extendedConfigPath = getExtendsConfigPath(json.extends, host, newBase, getCanonicalFileName, errors, createCompilerDiagnostic); } } @@ -1610,7 +1616,7 @@ namespace ts { onSetValidOptionKeyValueInRoot(key: string, _keyNode: PropertyName, value: CompilerOptionsValue, valueNode: Expression) { switch (key) { case "extends": - const newBase = configFileName ? getDirectoryPath(toPath(configFileName, basePath, getCanonicalFileName)) : basePath; + const newBase = configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath; extendedConfigPath = getExtendsConfigPath( value, host, diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 8ad12a14011..f5e2a4069e4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1228,6 +1228,9 @@ namespace ts { /** Does nothing. */ export function noop(): void {} + /** Returns its argument. */ + export function identity(x: T) { return x; } + /** Throws an error because a function is not implemented. */ export function notImplemented(): never { throw new Error("Not implemented"); From 9d11fbb9b9c4e7fbbc4a54d1b95d41e28e13ea42 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 30 Aug 2017 13:25:35 -0700 Subject: [PATCH 64/74] Correct permitted jumps check --- src/services/refactors/extractMethod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index c497b126759..e4fd0e85dc2 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -417,7 +417,7 @@ namespace ts.refactor.extractMethod { } } else { - if (!(permittedJumps & (SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { + if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? PermittedJumps.Break : PermittedJumps.Continue))) { // attempt to break or continue in a forbidden context (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.CannotExtractRangeContainingConditionalBreakOrContinueStatements)); } From a81fa7a801c7eff1865bcc2cd451bfc618ce832b Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 30 Aug 2017 13:55:18 -0700 Subject: [PATCH 65/74] Make permittedJumps a parameter to eliminate save-restore pattern --- src/services/refactors/extractMethod.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index e4fd0e85dc2..b73613350a8 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -293,14 +293,13 @@ namespace ts.refactor.extractMethod { } let errors: Diagnostic[]; - let permittedJumps = PermittedJumps.Return; let seenLabels: Array<__String>; - visit(nodeToCheck); + visit(nodeToCheck, PermittedJumps.Return); return errors; - function visit(node: Node) { + function visit(node: Node, permittedJumps: PermittedJumps) { if (errors) { // already found an error - can stop now return true; @@ -351,7 +350,6 @@ namespace ts.refactor.extractMethod { // do not dive into functions or classes return false; } - const savedPermittedJumps = permittedJumps; if (node.parent) { switch (node.parent.kind) { case SyntaxKind.IfStatement: @@ -402,7 +400,7 @@ namespace ts.refactor.extractMethod { { const label = (node).label; (seenLabels || (seenLabels = [])).push(label.escapedText); - forEachChild(node, visit); + forEachChild(node, child => visit(child, permittedJumps)); seenLabels.pop(); break; } @@ -439,11 +437,10 @@ namespace ts.refactor.extractMethod { } break; default: - forEachChild(node, visit); + forEachChild(node, child => visit(child, permittedJumps)); break; } - permittedJumps = savedPermittedJumps; } } } From e3808b65d4291c982cba374d336d65b1be87fae2 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 30 Aug 2017 14:23:11 -0700 Subject: [PATCH 66/74] Simplify and correct PermittedJumps computation 1. It was looking at the parent which wasn't guaranteed to be in the extracted range. 2. It was checking direct, rather than indirect containment - apparently to avoid applying the rules to certain expressions (which can't contain jumps anyway, unless they're in anonymous functions, in which case they're fine). Fixes #18144 --- src/harness/unittests/extractMethods.ts | 35 ++++++++++ src/services/refactors/extractMethod.ts | 64 ++++++++----------- .../extractMethod/extractMethod22.ts | 31 +++++++++ 3 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 tests/baselines/reference/extractMethod/extractMethod22.ts diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 6fe57895725..02ddbf4cae3 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -378,6 +378,32 @@ namespace A { "Cannot extract range containing conditional return statement." ]); + testExtractRangeFailed("extractRangeFailed7", + ` +function test(x: number) { + while (x) { + x--; + [#|break;|] + } +} + `, + [ + "Cannot extract range containing conditional break or continue statements." + ]); + + testExtractRangeFailed("extractRangeFailed8", + ` +function test(x: number) { + switch (x) { + case 1: + [#|break;|] + } +} + `, + [ + "Cannot extract range containing conditional break or continue statements." + ]); + testExtractMethod("extractMethod1", `namespace A { let x = 1; @@ -620,6 +646,15 @@ namespace A { let x = 10; [#|x++; return;|] +}`); + // Write + void return + testExtractMethod("extractMethod22", + `function test() { + try { + } + finally { + [#|return 1;|] + } }`); }); diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index b73613350a8..c0031f26cc8 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -350,45 +350,31 @@ namespace ts.refactor.extractMethod { // do not dive into functions or classes return false; } - if (node.parent) { - switch (node.parent.kind) { - case SyntaxKind.IfStatement: - if ((node.parent).thenStatement === node || (node.parent).elseStatement === node) { - // forbid all jumps inside thenStatement or elseStatement - permittedJumps = PermittedJumps.None; - } - break; - case SyntaxKind.TryStatement: - if ((node.parent).tryBlock === node) { - // forbid all jumps inside try blocks - permittedJumps = PermittedJumps.None; - } - else if ((node.parent).finallyBlock === node) { - // allow unconditional returns from finally blocks - permittedJumps = PermittedJumps.Return; - } - break; - case SyntaxKind.CatchClause: - if ((node.parent).block === node) { - // forbid all jumps inside the block of catch clause - permittedJumps = PermittedJumps.None; - } - break; - case SyntaxKind.CaseClause: - if ((node).expression !== node) { - // allow unlabeled break inside case clauses - permittedJumps |= PermittedJumps.Break; - } - break; - default: - if (isIterationStatement(node.parent, /*lookInLabeledStatements*/ false)) { - if ((node.parent).statement === node) { - // allow unlabeled break/continue inside loops - permittedJumps |= PermittedJumps.Break | PermittedJumps.Continue; - } - } - break; - } + + switch (node.kind) { + case SyntaxKind.IfStatement: + permittedJumps = PermittedJumps.None; + break; + case SyntaxKind.TryStatement: + // forbid all jumps inside try blocks + permittedJumps = PermittedJumps.None; + break; + case SyntaxKind.Block: + if (node.parent && node.parent.kind === SyntaxKind.TryStatement && (node).finallyBlock === node) { + // allow unconditional returns from finally blocks + permittedJumps = PermittedJumps.Return; + } + break; + case SyntaxKind.CaseClause: + // allow unlabeled break inside case clauses + permittedJumps |= PermittedJumps.Break; + break; + default: + if (isIterationStatement(node, /*lookInLabeledStatements*/ false)) { + // allow unlabeled break/continue inside loops + permittedJumps |= PermittedJumps.Break | PermittedJumps.Continue; + } + break; } switch (node.kind) { diff --git a/tests/baselines/reference/extractMethod/extractMethod22.ts b/tests/baselines/reference/extractMethod/extractMethod22.ts new file mode 100644 index 00000000000..7603c01681f --- /dev/null +++ b/tests/baselines/reference/extractMethod/extractMethod22.ts @@ -0,0 +1,31 @@ +// ==ORIGINAL== +function test() { + try { + } + finally { + return 1; + } +} +// ==SCOPE::function 'test'== +function test() { + try { + } + finally { + return newFunction(); + } + + function newFunction() { + return 1; + } +} +// ==SCOPE::global scope== +function test() { + try { + } + finally { + return newFunction(); + } +} +function newFunction() { + return 1; +} From 73bc0c9796ce2e294e8b0fa1a1dec46da1268187 Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Wed, 30 Aug 2017 14:36:20 -0700 Subject: [PATCH 67/74] Correct copied comment --- src/harness/unittests/extractMethods.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/unittests/extractMethods.ts b/src/harness/unittests/extractMethods.ts index 02ddbf4cae3..75404d12bf0 100644 --- a/src/harness/unittests/extractMethods.ts +++ b/src/harness/unittests/extractMethods.ts @@ -647,7 +647,7 @@ function test(x: number) { [#|x++; return;|] }`); - // Write + void return + // Return in finally block testExtractMethod("extractMethod22", `function test() { try { From baefdd2ccb21542b7aeab8b6f825e45c516566da Mon Sep 17 00:00:00 2001 From: Andrew Casey Date: Thu, 7 Sep 2017 15:36:32 -0700 Subject: [PATCH 68/74] Revert "Make permittedJumps a parameter to eliminate save-restore pattern" This reverts commit 57906fe90e8efd2fb285fcb67f018c0438ba06dd. --- src/services/refactors/extractMethod.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/services/refactors/extractMethod.ts b/src/services/refactors/extractMethod.ts index c0031f26cc8..83908def444 100644 --- a/src/services/refactors/extractMethod.ts +++ b/src/services/refactors/extractMethod.ts @@ -293,13 +293,14 @@ namespace ts.refactor.extractMethod { } let errors: Diagnostic[]; + let permittedJumps = PermittedJumps.Return; let seenLabels: Array<__String>; - visit(nodeToCheck, PermittedJumps.Return); + visit(nodeToCheck); return errors; - function visit(node: Node, permittedJumps: PermittedJumps) { + function visit(node: Node) { if (errors) { // already found an error - can stop now return true; @@ -350,6 +351,7 @@ namespace ts.refactor.extractMethod { // do not dive into functions or classes return false; } + const savedPermittedJumps = permittedJumps; switch (node.kind) { case SyntaxKind.IfStatement: @@ -386,7 +388,7 @@ namespace ts.refactor.extractMethod { { const label = (node).label; (seenLabels || (seenLabels = [])).push(label.escapedText); - forEachChild(node, child => visit(child, permittedJumps)); + forEachChild(node, visit); seenLabels.pop(); break; } @@ -423,10 +425,11 @@ namespace ts.refactor.extractMethod { } break; default: - forEachChild(node, child => visit(child, permittedJumps)); + forEachChild(node, visit); break; } + permittedJumps = savedPermittedJumps; } } } From 7aac67b9b4d42e4bdaa872c267465a268f0bd7a4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 16:22:16 -0700 Subject: [PATCH 69/74] Test: parsing of two-line @typedef jsdoc --- tests/baselines/reference/jsdocTwoLineTypedef.js | 10 ++++++++++ tests/baselines/reference/jsdocTwoLineTypedef.symbols | 9 +++++++++ tests/baselines/reference/jsdocTwoLineTypedef.types | 9 +++++++++ tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts | 6 ++++++ 4 files changed, 34 insertions(+) create mode 100644 tests/baselines/reference/jsdocTwoLineTypedef.js create mode 100644 tests/baselines/reference/jsdocTwoLineTypedef.symbols create mode 100644 tests/baselines/reference/jsdocTwoLineTypedef.types create mode 100644 tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts diff --git a/tests/baselines/reference/jsdocTwoLineTypedef.js b/tests/baselines/reference/jsdocTwoLineTypedef.js new file mode 100644 index 00000000000..b48d6a89a21 --- /dev/null +++ b/tests/baselines/reference/jsdocTwoLineTypedef.js @@ -0,0 +1,10 @@ +//// [jsdocTwoLineTypedef.ts] +// Regression from #18301 +/** + * @typedef LoadCallback + * @type {function} + */ +type LoadCallback = void; + + +//// [jsdocTwoLineTypedef.js] diff --git a/tests/baselines/reference/jsdocTwoLineTypedef.symbols b/tests/baselines/reference/jsdocTwoLineTypedef.symbols new file mode 100644 index 00000000000..80a69e5f52c --- /dev/null +++ b/tests/baselines/reference/jsdocTwoLineTypedef.symbols @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts === +// Regression from #18301 +/** + * @typedef LoadCallback + * @type {function} + */ +type LoadCallback = void; +>LoadCallback : Symbol(LoadCallback, Decl(jsdocTwoLineTypedef.ts, 0, 0)) + diff --git a/tests/baselines/reference/jsdocTwoLineTypedef.types b/tests/baselines/reference/jsdocTwoLineTypedef.types new file mode 100644 index 00000000000..5e0d05b3feb --- /dev/null +++ b/tests/baselines/reference/jsdocTwoLineTypedef.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts === +// Regression from #18301 +/** + * @typedef LoadCallback + * @type {function} + */ +type LoadCallback = void; +>LoadCallback : void + diff --git a/tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts b/tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts new file mode 100644 index 00000000000..2a7ad0d7dbf --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTwoLineTypedef.ts @@ -0,0 +1,6 @@ +// Regression from #18301 +/** + * @typedef LoadCallback + * @type {function} + */ +type LoadCallback = void; From fb5e8c611083c92f9744847957d2014d65025e6b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 16:37:13 -0700 Subject: [PATCH 70/74] Fix forEachChild's visit of JSDocTypedefTag Also remove JSDocTypeLiteral.jsdocTypeTag, which made no sense since it was only useful when storing information for its parent `@typedef` tag. --- src/compiler/parser.ts | 16 +++++++++------- src/compiler/types.ts | 1 - 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b0782b6707a..f81254572b7 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -438,8 +438,10 @@ namespace ts { visitNode(cbNode, (node).typeExpression); } case SyntaxKind.JSDocTypeLiteral: - for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) { - visitNode(cbNode, tag); + if ((node as JSDocTypeLiteral).jsDocPropertyTags) { + for (const tag of (node as JSDocTypeLiteral).jsDocPropertyTags) { + visitNode(cbNode, tag); + } } return; case SyntaxKind.PartiallyEmittedExpression: @@ -6672,19 +6674,18 @@ namespace ts { if (!typeExpression || isObjectOrObjectArrayTypeReference(typeExpression.type)) { let child: JSDocTypeTag | JSDocPropertyTag | false; let jsdocTypeLiteral: JSDocTypeLiteral; - let alreadyHasTypeTag = false; + let childTypeTag: JSDocTypeTag; const start = scanner.getStartPos(); while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.Property))) { if (!jsdocTypeLiteral) { jsdocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, start); } if (child.kind === SyntaxKind.JSDocTypeTag) { - if (alreadyHasTypeTag) { + if (childTypeTag) { break; } else { - jsdocTypeLiteral.jsDocTypeTag = child; - alreadyHasTypeTag = true; + childTypeTag = child; } } else { @@ -6698,7 +6699,8 @@ namespace ts { if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) { jsdocTypeLiteral.isArrayType = true; } - typedefTag.typeExpression = finishNode(jsdocTypeLiteral); + const useChildTypeTagAsType = childTypeTag && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type); + typedefTag.typeExpression = useChildTypeTagAsType ? childTypeTag.typeExpression : finishNode(jsdocTypeLiteral); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 55baf9763c2..3a3736a5ceb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2211,7 +2211,6 @@ namespace ts { export interface JSDocTypeLiteral extends JSDocType { kind: SyntaxKind.JSDocTypeLiteral; jsDocPropertyTags?: ReadonlyArray; - jsDocTypeTag?: JSDocTypeTag; /** If true, then this type literal represents an *array* of its type. */ isArrayType?: boolean; } From 7d5b5e957ece7c3062bfe7478ed760dd4ee6d389 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Thu, 7 Sep 2017 16:38:17 -0700 Subject: [PATCH 71/74] Update baselines --- ...sCorrectly.typedefTagWithChildrenTags.json | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json index f0e42ae6325..08d270286b9 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json @@ -34,38 +34,6 @@ "kind": "JSDocTypeLiteral", "pos": 26, "end": 98, - "jsDocTypeTag": { - "kind": "JSDocTypeTag", - "pos": 28, - "end": 42, - "atToken": { - "kind": "AtToken", - "pos": 28, - "end": 29 - }, - "tagName": { - "kind": "Identifier", - "pos": 29, - "end": 33, - "escapedText": "type" - }, - "typeExpression": { - "kind": "JSDocTypeExpression", - "pos": 34, - "end": 42, - "type": { - "kind": "TypeReference", - "pos": 35, - "end": 41, - "typeName": { - "kind": "Identifier", - "pos": 35, - "end": 41, - "escapedText": "Object" - } - } - } - }, "jsDocPropertyTags": [ { "kind": "JSDocPropertyTag", From 4ee7d3aeb20949dc30108236310aaf4cd7c91613 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 8 Sep 2017 07:18:37 -0700 Subject: [PATCH 72/74] Remove unnecessary check in emitNodeList (#18327) --- src/compiler/emitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5abeecd4107..8788e0c02f4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2415,7 +2415,7 @@ namespace ts { return; } - const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0; + const isEmpty = isUndefined || start >= children.length || count === 0; if (isEmpty && format & ListFormat.OptionalIfEmpty) { return; } From cab05ddd3fe70661a3c30bf2a912a444e9d4be55 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 8 Sep 2017 08:33:17 -0700 Subject: [PATCH 73/74] Inline variable to aid control flow --- src/compiler/parser.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f81254572b7..826f41d6bed 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6699,8 +6699,9 @@ namespace ts { if (typeExpression && typeExpression.type.kind === SyntaxKind.ArrayType) { jsdocTypeLiteral.isArrayType = true; } - const useChildTypeTagAsType = childTypeTag && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type); - typedefTag.typeExpression = useChildTypeTagAsType ? childTypeTag.typeExpression : finishNode(jsdocTypeLiteral); + typedefTag.typeExpression = childTypeTag && !isObjectOrObjectArrayTypeReference(childTypeTag.typeExpression.type) ? + childTypeTag.typeExpression : + finishNode(jsdocTypeLiteral); } } From 409d6597ebde2fce5673c9704907e339c8a5dc2d Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 8 Sep 2017 14:22:44 -0700 Subject: [PATCH 74/74] Add `never` helper function (#18287) * Add `never` helper function * Move to Debug.assertNever, keep old messages --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c72a064b11..aa5fbd6421c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1687,7 +1687,7 @@ namespace ts { undefined; } else { - Debug.fail("Unknown entity name kind."); + Debug.assertNever(name, "Unknown entity name kind."); } Debug.assert((getCheckFlags(symbol) & CheckFlags.Instantiated) === 0, "Should never get an instantiated symbol here."); return (symbol.flags & meaning) || dontResolveAlias ? symbol : resolveAlias(symbol); @@ -16357,7 +16357,7 @@ namespace ts { // This code-path is called by language service return resolveStatelessJsxOpeningLikeElement(node, checkExpression((node).tagName), candidatesOutArray); } - Debug.fail("Branch in 'resolveSignature' should be unreachable."); + Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable."); } /** @@ -24535,7 +24535,7 @@ namespace ts { currentKind = SetAccessor; } else { - Debug.fail("Unexpected syntax kind:" + (prop).kind); + Debug.assertNever(prop, "Unexpected syntax kind:" + (prop).kind); } const effectiveName = getPropertyNameForPropertyNameNode(name);