From df91ef0b382464c7c05419ffb2d35b50252a3a3a Mon Sep 17 00:00:00 2001 From: zhengbli Date: Mon, 28 Mar 2016 12:37:37 -0700 Subject: [PATCH 01/13] Simple case and scoping --- src/compiler/binder.ts | 14 +++-- src/compiler/checker.ts | 24 +++++--- src/compiler/diagnosticMessages.json | 4 ++ src/compiler/parser.ts | 86 +++++++++++++++++++++++----- src/compiler/types.ts | 29 +++++++++- 5 files changed, 130 insertions(+), 27 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 6957be484f35a..881ad81cb2e6b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -404,6 +404,13 @@ namespace ts { // This node will now be set as the parent of all of its children as we recurse into them. parent = node; + // 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 (isInJavaScriptFile(node) && node.jsDocComment) { + bind(node.jsDocComment); + } + // Depending on what kind of node this is, we may have to adjust the current container // and block-container. If the current node is a container, then it is automatically // considered the current block-container as well. Also, for containers that we know @@ -468,10 +475,6 @@ namespace ts { labelStack = labelIndexMap = implicitLabels = undefined; } - if (isInJavaScriptFile(node) && node.jsDocComment) { - bind(node.jsDocComment); - } - bindReachableStatement(node); if (currentReachabilityState === Reachability.Reachable && isFunctionLikeKind(kind) && nodeIsPresent((node).body)) { @@ -857,7 +860,7 @@ namespace ts { // their container in the tree. To accomplish this, we simply add their declared // symbol to the 'locals' of the container. These symbols can then be found as // the type checker walks up the containers, checking them for matching names. - return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes); + return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes); } } @@ -1343,6 +1346,7 @@ namespace ts { return bindClassLikeDeclaration(node); case SyntaxKind.InterfaceDeclaration: return bindBlockScopedDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); + case SyntaxKind.JSDocTypedefTag: case SyntaxKind.TypeAliasDeclaration: return bindBlockScopedDeclaration(node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); case SyntaxKind.EnumDeclaration: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9509c286236ea..ff416ec2cc5f1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3403,7 +3403,7 @@ namespace ts { return links.declaredType; } - function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type { + function getDeclaredTypeOfTypeAlias(symbol: Symbol, node?: Node): Type { const links = getSymbolLinks(symbol); if (!links.declaredType) { // Note that we use the links object as the target here because the symbol object is used as the unique @@ -3411,8 +3411,18 @@ namespace ts { if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) { return unknownType; } - const declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); - let type = getTypeFromTypeNode(declaration.type); + + let typeNode: TypeNode; + let name: Identifier; + if (node && (node.flags & NodeFlags.JavaScriptFile)) { + const declaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); + typeNode = declaration.typeExpression.type; + } + if (!typeNode) { + const declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + typeNode = declaration.type; + } + let type = getTypeFromTypeNode(typeNode); if (popTypeResolution()) { links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (links.typeParameters) { @@ -3424,7 +3434,7 @@ namespace ts { } else { type = unknownType; - error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error(name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); } links.declaredType = type; } @@ -3462,13 +3472,13 @@ namespace ts { return links.declaredType; } - function getDeclaredTypeOfSymbol(symbol: Symbol): Type { + function getDeclaredTypeOfSymbol(symbol: Symbol, node?: Node): Type { Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0); if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { return getDeclaredTypeOfClassOrInterface(symbol); } if (symbol.flags & SymbolFlags.TypeAlias) { - return getDeclaredTypeOfTypeAlias(symbol); + return getDeclaredTypeOfTypeAlias(symbol, node); } if (symbol.flags & SymbolFlags.Enum) { return getDeclaredTypeOfEnum(symbol); @@ -4564,7 +4574,7 @@ namespace ts { // references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the // declared type. Instantiations are cached using the type identities of the type arguments as the key. function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type { - const type = getDeclaredTypeOfSymbol(symbol); + const type = getDeclaredTypeOfSymbol(symbol, node); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; if (typeParameters) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d7c2fac27102f..c887a9c7112a2 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -811,6 +811,10 @@ "category": "Error", "code": 1249 }, + "'{0}' tag cannot be used independently as a top level JSDoc tag.": { + "category": "Error", + "code": 1250 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", "code": 1300 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b7c011631ee18..91f225931d265 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -401,6 +401,8 @@ namespace ts { return visitNode(cbNode, (node).typeExpression); case SyntaxKind.JSDocTemplateTag: return visitNodes(cbNodes, (node).typeParameters); + case SyntaxKind.JSDocTypedefTag: + return visitNode(cbNode, (node).typeExpression); } } @@ -886,7 +888,7 @@ namespace ts { /** Invokes the provided callback then unconditionally restores the parser to the state it * was in immediately prior to invoking the callback. The result of invoking the callback - * is returned from this function. + * is returned from this function. */ function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ true); @@ -2068,11 +2070,11 @@ namespace ts { } function fillSignature( - returnToken: SyntaxKind, - yieldContext: boolean, - awaitContext: boolean, - requireCompleteParameterList: boolean, - signature: SignatureDeclaration): void { + returnToken: SyntaxKind, + yieldContext: boolean, + awaitContext: boolean, + requireCompleteParameterList: boolean, + signature: SignatureDeclaration): void { const returnTokenRequired = returnToken === SyntaxKind.EqualsGreaterThanToken; signature.typeParameters = parseTypeParameters(); @@ -3341,8 +3343,8 @@ namespace ts { if (sourceFile.languageVariant !== LanguageVariant.JSX) { return false; } - // We are in JSX context and the token is part of JSXElement. - // Fall through + // We are in JSX context and the token is part of JSXElement. + // Fall through default: return true; } @@ -4044,9 +4046,9 @@ namespace ts { const isAsync = !!(node.flags & NodeFlags.Async); node.name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : - isGenerator ? doInYieldContext(parseOptionalIdentifier) : - isAsync ? doInAwaitContext(parseOptionalIdentifier) : - parseOptionalIdentifier(); + isGenerator ? doInYieldContext(parseOptionalIdentifier) : + isAsync ? doInAwaitContext(parseOptionalIdentifier) : + parseOptionalIdentifier(); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false); @@ -4984,7 +4986,7 @@ namespace ts { if (token === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { // We need to ensure that any subsequent modifiers appear on the same line - // so that when 'const' is a standalone declaration, we don't issue an error. + // so that when 'const' is a standalone declaration, we don't issue an error. if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { break; } @@ -5247,7 +5249,7 @@ namespace ts { node.decorators = decorators; setModifiers(node, modifiers); if (token === SyntaxKind.GlobalKeyword) { - // parse 'global' as name of global scope augmentation + // parse 'global' as name of global scope augmentation node.name = parseIdentifier(); node.flags |= NodeFlags.GlobalAugmentation; } @@ -5829,7 +5831,7 @@ namespace ts { } function checkForEmptyTypeArgumentList(typeArguments: NodeArray) { - if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) { + if (parseDiagnostics.length === 0 && typeArguments && typeArguments.length === 0) { const start = typeArguments.pos - "<".length; const end = skipTrivia(sourceText, typeArguments.end) + ">".length; return parseErrorAtPosition(start, end - start, Diagnostics.Type_argument_list_cannot_be_empty); @@ -5990,6 +5992,7 @@ namespace ts { Debug.assert(end <= content.length); let tags: NodeArray; + let currentParentJSDocDeclaration: Declaration; let result: JSDocComment; @@ -6097,6 +6100,11 @@ namespace ts { return handleTemplateTag(atToken, tagName); case "type": return handleTypeTag(atToken, tagName); + case "typedef": + return handleTypedefTag(atToken, tagName); + case "property": + case "prop": + return handlePropertyTag(atToken, tagName); } } @@ -6204,6 +6212,56 @@ namespace ts { return finishNode(result); } + function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { + if (!currentParentJSDocDeclaration) { + parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_cannot_be_used_independently_as_a_top_level_JSDoc_tag, tagName.text); + return undefined; + } + + const typeExpression = tryParseTypeExpression(); + skipWhitespace(); + const name = parseJSDocIdentifier(); + if (!name) { + parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected); + return undefined; + } + + const result = createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.name = name; + result.typeExpression = typeExpression; + return finishNode(result); + } + + function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { + const typeExpression = tryParseTypeExpression(); + skipWhitespace(); + const name = parseJSDocIdentifier(); + if (!name) { + parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); + return undefined; + } + + const result = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); + result.atToken = atToken; + result.tagName = tagName; + result.name = name; + result.typeExpression = typeExpression; + + // if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { + // const jsDocTypeReference = typeExpression.type; + // if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { + // const name = jsDocTypeReference.name; + // if (name.text === "Object") { + // currentParentJSDocDeclaration = declaration; + // } + // } + // } + + return result; + } + function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag { if (forEach(tags, t => t.kind === SyntaxKind.JSDocTemplateTag)) { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 546d1631945cc..a0cc8d054e1bd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -342,6 +342,10 @@ namespace ts { JSDocReturnTag, JSDocTypeTag, JSDocTemplateTag, + JSDocTypedefTag, + JSDocPropertyTag, + JSDocTypedefDeclaration, + JSDocTypeLiteral, // Synthesized list SyntaxList, @@ -1510,6 +1514,29 @@ namespace ts { typeExpression: JSDocTypeExpression; } + // @kind(SyntaxKind.JSDocTypedefTag) + export interface JSDocTypedefTag extends JSDocTag, Declaration { + name: Identifier; + typeExpression: JSDocTypeExpression; + } + + // @kind(SyntaxKind.JSDocPropertyTag) + export interface JSDocPropertyTag extends JSDocTag, TypeElement { + name: Identifier; + typeExpression: JSDocTypeExpression; + } + + // @kind(SyntaxKind.JSDocTypedefDeclaration) + export interface JSDocTypedefDeclaration extends Declaration { + name: Identifier; + type: TypeNode; + } + + // @kind(SyntaxKind.JSDocTypeLiteral) + export interface JSDocTypeLiteral extends TypeNode { + members: NodeArray; + } + // @kind(SyntaxKind.JSDocParameterTag) export interface JSDocParameterTag extends JSDocTag { preParameterName?: Identifier; @@ -2094,7 +2121,7 @@ namespace ts { jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt. - superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing + superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing } export const enum TypeFlags { From 23bca4eda6b220a88771a6c922842f8da1c3b366 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Mon, 4 Apr 2016 00:44:51 -0700 Subject: [PATCH 02/13] Support the case with @property and @type --- src/compiler/binder.ts | 4 + src/compiler/checker.ts | 16 +- src/compiler/parser.ts | 142 +++++++++++++++--- src/compiler/types.ts | 19 +-- .../fourslash/server/jsdocCompletions.ts | 15 ++ 5 files changed, 160 insertions(+), 36 deletions(-) create mode 100644 tests/cases/fourslash/server/jsdocCompletions.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 881ad81cb2e6b..b3f163bbef1c1 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -744,6 +744,7 @@ namespace ts { case SyntaxKind.EnumDeclaration: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.TypeLiteral: + case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocRecordType: return ContainerFlags.IsContainer; @@ -832,6 +833,7 @@ namespace ts { case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.JSDocRecordType: + case SyntaxKind.JSDocTypeLiteral: // Interface/Object-types always have their children added to the 'members' of // their container. They are only accessible through an instance of their // container, and are never in scope otherwise (even inside the body of the @@ -1294,6 +1296,7 @@ namespace ts { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.JSDocRecordMember: + case SyntaxKind.JSDocPropertyTag: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: @@ -1326,6 +1329,7 @@ namespace ts { case SyntaxKind.JSDocFunctionType: return bindFunctionOrConstructorType(node); case SyntaxKind.TypeLiteral: + case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocRecordType: return bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type"); case SyntaxKind.ObjectLiteralExpression: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ff416ec2cc5f1..e66e5e6a9d805 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3412,17 +3412,14 @@ namespace ts { return unknownType; } - let typeNode: TypeNode; - let name: Identifier; + let declaration: JSDocTypedefTag | TypeAliasDeclaration; if (node && (node.flags & NodeFlags.JavaScriptFile)) { - const declaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); - typeNode = declaration.typeExpression.type; + declaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); } - if (!typeNode) { - const declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); - typeNode = declaration.type; + if (!declaration) { + declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); } - let type = getTypeFromTypeNode(typeNode); + let type = getTypeFromTypeNode(declaration.type); if (popTypeResolution()) { links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (links.typeParameters) { @@ -3434,7 +3431,7 @@ namespace ts { } else { type = unknownType; - error(name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); + error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol)); } links.declaredType = type; } @@ -5067,6 +5064,7 @@ namespace ts { case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: case SyntaxKind.TypeLiteral: + case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocFunctionType: case SyntaxKind.JSDocRecordType: return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 91f225931d265..5de1369ee092d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -402,7 +402,15 @@ namespace ts { case SyntaxKind.JSDocTemplateTag: return visitNodes(cbNodes, (node).typeParameters); case SyntaxKind.JSDocTypedefTag: - return visitNode(cbNode, (node).typeExpression); + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).type); + case SyntaxKind.JSDocTypeLiteral: + return visitNodes(cbNodes, (node).members); + case SyntaxKind.JSDocPropertyTag: + return visitNode(cbNode, (node).name) || + visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).type); } } @@ -5992,7 +6000,8 @@ namespace ts { Debug.assert(end <= content.length); let tags: NodeArray; - let currentParentJSDocDeclaration: Declaration; + let currentParentJSDocTag: JSDocParentTag; + let currentParentJSDocTagEnd: number; let result: JSDocComment; @@ -6050,6 +6059,10 @@ namespace ts { nextJSDocToken(); } + if (currentParentJSDocTag) { + finishCurrentParentTag(); + } + result = createJSDocComment(); }); @@ -6073,6 +6086,40 @@ namespace ts { } } + function finishCurrentParentTag(): void { + if (!currentParentJSDocTag) { + return; + } + + if (currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) { + const typedefTag = currentParentJSDocTag; + if (typedefTag.jsDocTypeTag) { + if (typedefTag.jsDocTypeTag.typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { + const typeTagtype = typedefTag.jsDocTypeTag.typeExpression.type; + if ((typeTagtype.name.kind !== SyntaxKind.Identifier) || + (typeTagtype.name).text !== "Object") { + typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; + } + } + else { + typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; + } + } + if (!typedefTag.type) { + const tagType = createNode(SyntaxKind.JSDocTypeLiteral, currentParentJSDocTag.pos); + if (typedefTag.jsDocPropertyTags){ + tagType.members = >[]; + addRange(tagType.members, typedefTag.jsDocPropertyTags); + } + typedefTag.type = finishNode(tagType, currentParentJSDocTagEnd); + } + } + + addTag(finishNode(currentParentJSDocTag, currentParentJSDocTagEnd)); + currentParentJSDocTag = undefined; + currentParentJSDocTagEnd = undefined; + } + function parseTag(): void { Debug.assert(token === SyntaxKind.AtToken); const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos()); @@ -6085,22 +6132,30 @@ namespace ts { } const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName); - addTag(tag); + if (!currentParentJSDocTag) { + addTag(tag); + } } function handleTag(atToken: Node, tagName: Identifier): JSDocTag { if (tagName) { switch (tagName.text) { case "param": + finishCurrentParentTag(); return handleParamTag(atToken, tagName); case "return": case "returns": + finishCurrentParentTag(); return handleReturnTag(atToken, tagName); case "template": + finishCurrentParentTag(); return handleTemplateTag(atToken, tagName); case "type": + // @typedef tag is allowed to have one @type tag, therefore seeing + // a @type tag may not indicate the end of the current parent tag. return handleTypeTag(atToken, tagName); case "typedef": + finishCurrentParentTag(); return handleTypedefTag(atToken, tagName); case "property": case "prop": @@ -6130,6 +6185,25 @@ namespace ts { } } + function addToCurrentParentTag(tag: JSDocTag): void { + if (!currentParentJSDocTag) { + return; + } + switch (tag.kind) { + case SyntaxKind.JSDocPropertyTag: + if (!currentParentJSDocTag.jsDocPropertyTags) { + currentParentJSDocTag.jsDocPropertyTags = >[]; + } + currentParentJSDocTag.jsDocPropertyTags.push(tag); + break; + case SyntaxKind.JSDocTypeTag: + if (!currentParentJSDocTag.jsDocTypeTag) { + currentParentJSDocTag.jsDocTypeTag = tag; + } + break; + } + } + function tryParseTypeExpression(): JSDocTypeExpression { if (token !== SyntaxKind.OpenBraceToken) { return undefined; @@ -6205,15 +6279,33 @@ namespace ts { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text); } - const result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); + let result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; result.typeExpression = tryParseTypeExpression(); - return finishNode(result); + result = finishNode(result); + + let typeTagPartOfParentTag = false; + if (currentParentJSDocTag && currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) { + const parentTag = currentParentJSDocTag; + if (!parentTag.typeExpression && !parentTag.jsDocTypeTag) { + typeTagPartOfParentTag = true; + parentTag.jsDocTypeTag = result; + currentParentJSDocTagEnd = scanner.getStartPos(); + } + } + if (!typeTagPartOfParentTag) { + // If this @type tag is not part of the current parent tag, then + // it denotes the end of the current parent tag. + finishCurrentParentTag(); + return result; + } + + return undefined; } function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { - if (!currentParentJSDocDeclaration) { + if (!currentParentJSDocTag) { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_cannot_be_used_independently_as_a_top_level_JSDoc_tag, tagName.text); return undefined; } @@ -6226,12 +6318,17 @@ namespace ts { return undefined; } - const result = createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); + let result = createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; result.name = name; result.typeExpression = typeExpression; - return finishNode(result); + result.type = typeExpression.type; + result = finishNode(result); + + addToCurrentParentTag(result); + currentParentJSDocTagEnd = scanner.getStartPos(); + return undefined; } function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { @@ -6249,17 +6346,26 @@ namespace ts { result.name = name; result.typeExpression = typeExpression; - // if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { - // const jsDocTypeReference = typeExpression.type; - // if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { - // const name = jsDocTypeReference.name; - // if (name.text === "Object") { - // currentParentJSDocDeclaration = declaration; - // } - // } - // } + if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { + const jsDocTypeReference = typeExpression.type; + if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { + const name = jsDocTypeReference.name; + if (name.text === "Object") { + currentParentJSDocTag = result; + } + } + } + else if (!typeExpression) { + currentParentJSDocTag = result; + } + + if (!currentParentJSDocTag) { + result.type = result.typeExpression.type; + return finishNode(result); + } - return result; + currentParentJSDocTagEnd = scanner.getStartPos(); + return undefined; } function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a0cc8d054e1bd..31c2c8eb068ee 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -344,7 +344,6 @@ namespace ts { JSDocTemplateTag, JSDocTypedefTag, JSDocPropertyTag, - JSDocTypedefDeclaration, JSDocTypeLiteral, // Synthesized list @@ -616,6 +615,7 @@ namespace ts { // SyntaxKind.PropertyAssignment // SyntaxKind.ShorthandPropertyAssignment // SyntaxKind.EnumMember + // SyntaxKind.JSDocPropertyTag export interface VariableLikeDeclaration extends Declaration { propertyName?: PropertyName; dotDotDotToken?: Node; @@ -1515,25 +1515,26 @@ namespace ts { } // @kind(SyntaxKind.JSDocTypedefTag) - export interface JSDocTypedefTag extends JSDocTag, Declaration { + export interface JSDocTypedefTag extends JSDocTag, Declaration, JSDocParentTag { name: Identifier; - typeExpression: JSDocTypeExpression; + typeExpression?: JSDocTypeExpression; + type: JSDocType; + } + + export interface JSDocParentTag extends JSDocTag { + jsDocPropertyTags?: NodeArray; + jsDocTypeTag?: JSDocTypeTag; } // @kind(SyntaxKind.JSDocPropertyTag) export interface JSDocPropertyTag extends JSDocTag, TypeElement { name: Identifier; typeExpression: JSDocTypeExpression; - } - - // @kind(SyntaxKind.JSDocTypedefDeclaration) - export interface JSDocTypedefDeclaration extends Declaration { - name: Identifier; type: TypeNode; } // @kind(SyntaxKind.JSDocTypeLiteral) - export interface JSDocTypeLiteral extends TypeNode { + export interface JSDocTypeLiteral extends JSDocType { members: NodeArray; } diff --git a/tests/cases/fourslash/server/jsdocCompletions.ts b/tests/cases/fourslash/server/jsdocCompletions.ts new file mode 100644 index 0000000000000..c8dc1bbe48113 --- /dev/null +++ b/tests/cases/fourslash/server/jsdocCompletions.ts @@ -0,0 +1,15 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsdocCompletion_typedef.js +//// /** +//// * @typedef {Object} Person +//// * @property {string} personName +//// * @type {Person} +//// */ +//// var x1; +//// x1/**/ + +goTo.marker(); +edit.insert('.'); +verify.memberListContains('personName'); \ No newline at end of file From 9a8f6395e44ed494876f7a671b2d2750b336b929 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 6 Apr 2016 20:22:23 -0700 Subject: [PATCH 03/13] Support the case with variable name as @typedef type name --- src/compiler/checker.ts | 13 +++++-------- src/compiler/parser.ts | 22 +++++++++++++++++----- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e66e5e6a9d805..35ae6777fe2d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3403,7 +3403,7 @@ namespace ts { return links.declaredType; } - function getDeclaredTypeOfTypeAlias(symbol: Symbol, node?: Node): Type { + function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.declaredType) { // Note that we use the links object as the target here because the symbol object is used as the unique @@ -3412,10 +3412,7 @@ namespace ts { return unknownType; } - let declaration: JSDocTypedefTag | TypeAliasDeclaration; - if (node && (node.flags & NodeFlags.JavaScriptFile)) { - declaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); - } + let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); if (!declaration) { declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); } @@ -3469,13 +3466,13 @@ namespace ts { return links.declaredType; } - function getDeclaredTypeOfSymbol(symbol: Symbol, node?: Node): Type { + function getDeclaredTypeOfSymbol(symbol: Symbol): Type { Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0); if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { return getDeclaredTypeOfClassOrInterface(symbol); } if (symbol.flags & SymbolFlags.TypeAlias) { - return getDeclaredTypeOfTypeAlias(symbol, node); + return getDeclaredTypeOfTypeAlias(symbol); } if (symbol.flags & SymbolFlags.Enum) { return getDeclaredTypeOfEnum(symbol); @@ -4571,7 +4568,7 @@ namespace ts { // references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the // declared type. Instantiations are cached using the type identities of the type arguments as the key. function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type { - const type = getDeclaredTypeOfSymbol(symbol, node); + const type = getDeclaredTypeOfSymbol(symbol); const links = getSymbolLinks(symbol); const typeParameters = links.typeParameters; if (typeParameters) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5de1369ee092d..0b4a98bd98691 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5977,7 +5977,7 @@ namespace ts { const saveParseDiagnosticsLength = parseDiagnostics.length; const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; - const comment = parseJSDocCommentWorker(start, length); + const comment = parseJSDocCommentWorker(start, length, parent); if (comment) { comment.parent = parent; } @@ -5989,7 +5989,7 @@ namespace ts { return comment; } - export function parseJSDocCommentWorker(start: number, length: number): JSDocComment { + export function parseJSDocCommentWorker(start: number, length: number, parentNode?: Node): JSDocComment { const content = sourceText; start = start || 0; const end = length === undefined ? content.length : start + length; @@ -6334,10 +6334,22 @@ namespace ts { function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - const name = parseJSDocIdentifier(); + let name = parseJSDocIdentifier(); if (!name) { - parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); - return undefined; + let foundNameFromParentNode = false; + if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { + if ((parentNode).declarationList.declarations.length > 0) { + const nameFromParentNode = (parentNode).declarationList.declarations[0].name; + if (nameFromParentNode.kind === SyntaxKind.Identifier) { + foundNameFromParentNode = true; + name = nameFromParentNode; + } + } + } + if (!foundNameFromParentNode) { + parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); + return undefined; + } } const result = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); From 2945f64e3b88f8658ed7863d4d3146ad9d5c6b52 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 8 Apr 2016 20:19:39 -0700 Subject: [PATCH 04/13] Add tests for renaming and incremental parsing. Changed how the AST was hydrated with jsdocComment nodes. --- src/compiler/binder.ts | 6 +- src/compiler/checker.ts | 4 +- src/compiler/parser.ts | 44 +-- src/compiler/scanner.ts | 5 +- src/compiler/types.ts | 9 +- src/compiler/utilities.ts | 89 ++++-- src/harness/harness.ts | 22 +- src/services/services.ts | 53 +++- src/services/utilities.ts | 61 ++-- tests/cases/fourslash/commentsVariables.ts | 80 ++--- tests/cases/fourslash/doesnotwork.ts | 45 +++ .../fourslash/server/jsdocCompletions.ts | 15 - .../cases/fourslash/server/jsdocTypedefTag.ts | 64 ++++ .../server/jsdocTypedefTagGoToDefinition.ts | 29 ++ .../server/jsdocTypedefTagRename01.ts | 20 ++ .../server/jsdocTypedefTagRename02.ts | 15 + .../server/jsdocTypedefTagRename03.ts | 20 ++ .../server/jsdocTypedefTagRename04.ts | 24 ++ tests/cases/unittests/jsDocParsing.ts | 3 +- tests/webTestServer.js | 288 ++++++++++++++++++ tests/webTestServer.js.map | 1 + 21 files changed, 757 insertions(+), 140 deletions(-) create mode 100644 tests/cases/fourslash/doesnotwork.ts delete mode 100644 tests/cases/fourslash/server/jsdocCompletions.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTag.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagGoToDefinition.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagRename01.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagRename02.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagRename03.ts create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagRename04.ts create mode 100644 tests/webTestServer.js create mode 100644 tests/webTestServer.js.map diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b3f163bbef1c1..45629da8adfad 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -407,8 +407,10 @@ 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 (isInJavaScriptFile(node) && node.jsDocComment) { - bind(node.jsDocComment); + if (isInJavaScriptFile(node) && node.jsDocComments) { + for (const jsDocComment of node.jsDocComments) { + bind(jsDocComment); + } } // Depending on what kind of node this is, we may have to adjust the current container diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 35ae6777fe2d7..c903696f88fb2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16117,7 +16117,7 @@ namespace ts { node = node.parent; } - return node.parent && node.parent.kind === SyntaxKind.TypeReference; + return node.parent && (node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.JSDocTypeReference) ; } function isHeritageClauseElementIdentifier(entityName: Node): boolean { @@ -16251,7 +16251,7 @@ namespace ts { } } else if (isTypeReferenceIdentifier(entityName)) { - let meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace; + let meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace; // Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead // return the alias symbol. meaning |= SymbolFlags.Alias; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0b4a98bd98691..009a3e13fa208 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -402,15 +402,15 @@ namespace ts { case SyntaxKind.JSDocTemplateTag: return visitNodes(cbNodes, (node).typeParameters); case SyntaxKind.JSDocTypedefTag: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).typeExpression) || + return visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).name) || visitNode(cbNode, (node).type); case SyntaxKind.JSDocTypeLiteral: return visitNodes(cbNodes, (node).members); case SyntaxKind.JSDocPropertyTag: - return visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).type); + return visitNode(cbNode, (node).typeExpression) || + visitNode(cbNode, (node).type) || + visitNode(cbNode, (node).name); } } @@ -638,9 +638,14 @@ namespace ts { if (comments) { for (const comment of comments) { const jsDocComment = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos); - if (jsDocComment) { - node.jsDocComment = jsDocComment; + if (!jsDocComment) { + continue; } + + if (!node.jsDocComments) { + node.jsDocComments = []; + } + node.jsDocComments.push(jsDocComment); } } } @@ -6105,13 +6110,15 @@ namespace ts { typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; } } - if (!typedefTag.type) { - const tagType = createNode(SyntaxKind.JSDocTypeLiteral, currentParentJSDocTag.pos); - if (typedefTag.jsDocPropertyTags){ - tagType.members = >[]; - addRange(tagType.members, typedefTag.jsDocPropertyTags); - } - typedefTag.type = finishNode(tagType, currentParentJSDocTagEnd); + if (!typedefTag.type && typedefTag.jsDocPropertyTags) { + const childrenTagPoses = ts.map(typedefTag.jsDocPropertyTags, tag => tag.pos); + const childrenTagEnds = ts.map(typedefTag.jsDocPropertyTags, tag => tag.end); + const pos = Math.min(...childrenTagPoses); + const end = Math.max(...childrenTagEnds); + const tagType = createNode(SyntaxKind.JSDocTypeLiteral, pos); + tagType.members = >[]; + addRange(tagType.members, typedefTag.jsDocPropertyTags); + typedefTag.type = finishNode(tagType, end); } } @@ -6545,10 +6552,6 @@ namespace ts { node._children = undefined; } - if (node.jsDocComment) { - node.jsDocComment = undefined; - } - node.pos += delta; node.end += delta; @@ -6557,6 +6560,11 @@ namespace ts { } forEachChild(node, visitNode, visitArray); + if (node.jsDocComments) { + for (const jsDocComment of node.jsDocComments) { + forEachChild(jsDocComment, visitNode, visitArray); + } + } checkNodePositions(node, aggressiveChecks); } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 8979814a7a2a6..d4206749faed2 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -433,7 +433,7 @@ namespace ts { } /* @internal */ - export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number { + export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean, stopAtComments = false): number { // Using ! with a greater than test is a fast way of testing the following conditions: // pos === undefined || pos === null || isNaN(pos) || pos < 0; if (!(pos >= 0)) { @@ -461,6 +461,9 @@ namespace ts { pos++; continue; case CharacterCodes.slash: + if (stopAtComments) { + break; + } if (text.charCodeAt(pos + 1) === CharacterCodes.slash) { pos += 2; while (pos < text.length) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 31c2c8eb068ee..838b5d951f255 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -374,6 +374,8 @@ namespace ts { FirstBinaryOperator = LessThanToken, LastBinaryOperator = CaretEqualsToken, FirstNode = QualifiedName, + FirstJSDocNode = JSDocTypeExpression, + LastJSDocNode = JSDocTypeLiteral } export const enum NodeFlags { @@ -447,7 +449,7 @@ namespace ts { modifiers?: ModifiersArray; // Array of modifiers /* @internal */ id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding - /* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files. + /* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files. /* @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) @@ -2827,4 +2829,9 @@ namespace ts { /* @internal */ reattachFileDiagnostics(newFile: SourceFile): void; } + + // SyntaxKind.SyntaxList + export interface SyntaxList extends Node { + _children: Node[]; + } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4356486d3b5aa..fab5e9f8f8ba0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -203,16 +203,54 @@ namespace ts { return !nodeIsMissing(node); } - export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { + export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, includeJsDocComment?: boolean): number { // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't* // want to skip trivia because this will launch us forward to the next token. if (nodeIsMissing(node)) { return node.pos; } + if (isJSDocNode(node)) { + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); + } + + if (node.jsDocComments && node.jsDocComments.length > 0 && includeJsDocComment) { + return getTokenPosOfNode(node.jsDocComments[0]); + } + + if (node.kind === SyntaxKind.SyntaxList) { + const childrenPoses = ts.map((node)._children, child => getTokenPosOfNode(child, sourceFile, includeJsDocComment)); + return Math.min(...childrenPoses); + } + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); } + export function isJSDocNode(node: Node) { + return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; + } + export function isJSDocType(node: Node) { + switch (node.kind) { + case SyntaxKind.JSDocAllType: + case SyntaxKind.JSDocUnknownType: + case SyntaxKind.JSDocArrayType: + case SyntaxKind.JSDocUnionType: + case SyntaxKind.JSDocTupleType: + case SyntaxKind.JSDocNullableType: + case SyntaxKind.JSDocNonNullableType: + case SyntaxKind.JSDocRecordType: + case SyntaxKind.JSDocRecordMember: + case SyntaxKind.JSDocTypeReference: + case SyntaxKind.JSDocOptionalType: + case SyntaxKind.JSDocFunctionType: + case SyntaxKind.JSDocVariadicType: + case SyntaxKind.JSDocConstructorType: + case SyntaxKind.JSDocThisType: + return true; + } + return false; + } + export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { if (nodeIsMissing(node) || !node.decorators) { return getTokenPosOfNode(node, sourceFile); @@ -1199,26 +1237,28 @@ namespace ts { return undefined; } - const jsDocComment = getJSDocComment(node, checkParentVariableStatement); - if (!jsDocComment) { + const jsDocComments = getJSDocComments(node, checkParentVariableStatement); + if (!jsDocComments) { return undefined; } - for (const tag of jsDocComment.tags) { - if (tag.kind === kind) { - return tag; + for (const jsDocComment of jsDocComments) { + for (const tag of jsDocComment.tags) { + if (tag.kind === kind) { + return tag; + } } } } - function getJSDocComment(node: Node, checkParentVariableStatement: boolean): JSDocComment { - if (node.jsDocComment) { - return node.jsDocComment; + function getJSDocComments(node: Node, checkParentVariableStatement: boolean): JSDocComment[] { + if (node.jsDocComments) { + return node.jsDocComments; } - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. - // /** + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. + // /** // * @param {number} name - // * @returns {number} + // * @returns {number} // */ // var x = function(name) { return name.length; } if (checkParentVariableStatement) { @@ -1229,7 +1269,7 @@ namespace ts { const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined; if (variableStatementNode) { - return variableStatementNode.jsDocComment; + return variableStatementNode.jsDocComments; } // Also recognize when the node is the RHS of an assignment expression @@ -1240,12 +1280,12 @@ namespace ts { (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - return parent.parent.jsDocComment; + return parent.parent.jsDocComments; } const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; if (isPropertyAssignmentExpression) { - return parent.jsDocComment; + return parent.jsDocComments; } } @@ -1270,14 +1310,16 @@ namespace ts { // annotation. const parameterName = (parameter.name).text; - const jsDocComment = getJSDocComment(parameter.parent, /*checkParentVariableStatement*/ true); - if (jsDocComment) { - for (const tag of jsDocComment.tags) { - if (tag.kind === SyntaxKind.JSDocParameterTag) { - const parameterTag = tag; - const name = parameterTag.preParameterName || parameterTag.postParameterName; - if (name.text === parameterName) { - return parameterTag; + const jsDocComments = getJSDocComments(parameter.parent, /*checkParentVariableStatement*/ true); + if (jsDocComments) { + for (const jsDocComment of jsDocComments) { + for (const tag of jsDocComment.tags) { + if (tag.kind === SyntaxKind.JSDocParameterTag) { + const parameterTag = tag; + const name = parameterTag.preParameterName || parameterTag.postParameterName; + if (name.text === parameterName) { + return parameterTag; + } } } } @@ -1374,6 +1416,7 @@ namespace ts { case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.TypeParameter: case SyntaxKind.VariableDeclaration: + case SyntaxKind.JSDocTypedefTag: return true; } return false; diff --git a/src/harness/harness.ts b/src/harness/harness.ts index ddaca6420944f..330f57cf5c9f6 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1,7 +1,7 @@ // // Copyright (c) Microsoft Corporation. All rights reserved. -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -217,6 +217,14 @@ namespace Utils { return k; } + if (k === (ts).SyntaxKind.FirstJSDocCommentNode || k === (ts).SyntaxKind.LastJSDocCommentNode) { + for (const kindName in (ts).SyntaxKind) { + if ((ts).SyntaxKind[kindName] === k) { + return kindName; + } + } + } + return (ts).SyntaxKind[k]; } @@ -346,7 +354,7 @@ namespace Utils { assert.equal(node1.end, node2.end, "node1.end !== node2.end"); assert.equal(node1.kind, node2.kind, "node1.kind !== node2.kind"); - // call this on both nodes to ensure all propagated flags have been set (and thus can be + // call this on both nodes to ensure all propagated flags have been set (and thus can be // compared). assert.equal(ts.containsParseError(node1), ts.containsParseError(node2)); assert.equal(node1.flags, node2.flags, "node1.flags !== node2.flags"); @@ -753,7 +761,7 @@ namespace Harness { (emittedFile: string, emittedLine: number, emittedColumn: number, sourceFile: string, sourceLine: number, sourceColumn: number, sourceName: string): void; } - // Settings + // Settings export let userSpecifiedRoot = ""; export let lightMode = false; @@ -792,7 +800,7 @@ namespace Harness { fileName: string, sourceText: string, languageVersion: ts.ScriptTarget) { - // We'll only assert invariants outside of light mode. + // We'll only assert invariants outside of light mode. const shouldAssertInvariants = !Harness.lightMode; // Only set the parent nodes if we're asserting invariants. We don't need them otherwise. @@ -887,7 +895,7 @@ namespace Harness { libFiles?: string; } - // Additional options not already in ts.optionDeclarations + // Additional options not already in ts.optionDeclarations const harnessOptionDeclarations: ts.CommandLineOption[] = [ { name: "allowNonTsExtensions", type: "boolean" }, { name: "useCaseSensitiveFileNames", type: "boolean" }, @@ -1135,7 +1143,7 @@ namespace Harness { errLines.forEach(e => outputLines.push(e)); // do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics - // if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers) + // if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers) // then they will be added twice thus triggering 'total errors' assertion with condition // 'totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length @@ -1445,7 +1453,7 @@ namespace Harness { }; testUnitData.push(newTestFile2); - // unit tests always list files explicitly + // unit tests always list files explicitly const parseConfigHost: ts.ParseConfigHost = { readDirectory: (name) => [] }; diff --git a/src/services/services.ts b/src/services/services.ts index a634b2baf1a49..d85d478fcbe94 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -20,7 +20,7 @@ namespace ts { getChildCount(sourceFile?: SourceFile): number; getChildAt(index: number, sourceFile?: SourceFile): Node; getChildren(sourceFile?: SourceFile): Node[]; - getStart(sourceFile?: SourceFile): number; + getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; getFullStart(): number; getEnd(): number; getWidth(sourceFile?: SourceFile): number; @@ -170,6 +170,8 @@ namespace ts { "static", "throws", "type", + "typedef", + "property", "version" ]; let jsDocCompletionEntries: CompletionEntry[]; @@ -187,6 +189,7 @@ namespace ts { public end: number; public flags: NodeFlags; public parent: Node; + public jsDocComments: JSDocComment[]; private _children: Node[]; constructor(kind: SyntaxKind, pos: number, end: number) { @@ -201,8 +204,8 @@ namespace ts { return getSourceFileOfNode(this); } - public getStart(sourceFile?: SourceFile): number { - return getTokenPosOfNode(this, sourceFile); + public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number { + return getTokenPosOfNode(this, sourceFile, includeJsDocComment); } public getFullStart(): number { @@ -233,12 +236,14 @@ namespace ts { return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); } - private addSyntheticNodes(nodes: Node[], pos: number, end: number): number { + private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number { scanner.setTextPos(pos); while (pos < end) { - const token = scanner.scan(); + const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan(); const textPos = scanner.getTextPos(); - nodes.push(createNode(token, pos, textPos, 0, this)); + if (textPos <= end) { + nodes.push(createNode(token, pos, textPos, 0, this)); + } pos = textPos; } return pos; @@ -268,20 +273,36 @@ namespace ts { scanner.setText((sourceFile || this.getSourceFile()).text); children = []; let pos = this.pos; + const isJSDocTag = + this.kind === SyntaxKind.JSDocComment || + this.kind === SyntaxKind.JSDocParameterTag || + this.kind === SyntaxKind.JSDocTag || + this.kind === SyntaxKind.JSDocParameterTag || + this.kind === SyntaxKind.JSDocReturnTag || + this.kind === SyntaxKind.JSDocTypeTag || + this.kind === SyntaxKind.JSDocTemplateTag || + this.kind === SyntaxKind.JSDocTypedefTag || + this.kind === SyntaxKind.JSDocPropertyTag; const processNode = (node: Node) => { if (pos < node.pos) { - pos = this.addSyntheticNodes(children, pos, node.pos); + pos = this.addSyntheticNodes(children, pos, node.pos, /*useJSDocScanner*/ isJSDocTag); } children.push(node); pos = node.end; }; const processNodes = (nodes: NodeArray) => { if (pos < nodes.pos) { - pos = this.addSyntheticNodes(children, pos, nodes.pos); + pos = this.addSyntheticNodes(children, pos, nodes.pos, /*useJSDocScanner*/ isJSDocTag); } children.push(this.createSyntaxList(>nodes)); pos = nodes.end; }; + // jsDocComments need to be the first children + if (this.jsDocComments) { + for (const jsDocComment of this.jsDocComments) { + processNode(jsDocComment); + } + } forEachChild(this, processNode, processNodes); if (pos < this.end) { this.addSyntheticNodes(children, pos, this.end); @@ -1883,7 +1904,7 @@ namespace ts { options.isolatedModules = true; - // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. + // transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths. options.suppressOutputPathCheck = true; // Filename can be non-ts file. @@ -5499,7 +5520,7 @@ namespace ts { const sourceFile = getValidSourceFile(fileName); - const node = getTouchingPropertyName(sourceFile, position); + const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); if (!node) { return undefined; } @@ -5808,7 +5829,8 @@ namespace ts { const sourceFile = container.getSourceFile(); const tripleSlashDirectivePrefixRegex = /^\/\/\/\s* 0) { + for (const jsDocComment of node.jsDocComments) { + forEachChild(jsDocComment, walk); + } + } } } } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 8006fea2c079a..5ea011f2226c9 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -260,29 +260,29 @@ namespace ts { /* Gets the token whose text has range [start, end) and * position >= start and (position < end or (position === end && token is keyword or identifier)) */ - export function getTouchingWord(sourceFile: SourceFile, position: number): Node { - return getTouchingToken(sourceFile, position, n => isWord(n.kind)); + export function getTouchingWord(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node { + return getTouchingToken(sourceFile, position, n => isWord(n.kind), includeJsDocComment); } /* Gets the token whose text has range [start, end) and position >= start * and (position < end or (position === end && token is keyword or identifier or numeric/string literal)) */ - export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node { - return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind)); + export function getTouchingPropertyName(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node { + return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind), includeJsDocComment); } /** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */ - export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition); + export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean, includeJsDocComment = false): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition, includeJsDocComment); } /** Returns a token if position is in [start-of-leading-trivia, end) */ - export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined); + export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment = false): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined, includeJsDocComment); } /** Get the token whose text contains the position */ - function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean): Node { + function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean, includeJsDocComment = false): Node { let current: Node = sourceFile; outer: while (true) { if (isToken(current)) { @@ -290,10 +290,34 @@ namespace ts { return current; } + if (includeJsDocComment) { + const jsDocChildren = ts.filter(current.getChildren(), isJSDocNode); + for (const jsDocChild of jsDocChildren) { + let start = allowPositionInLeadingTrivia ? jsDocChild.getFullStart() : jsDocChild.getStart(sourceFile, includeJsDocComment); + if (start <= position) { + let end = jsDocChild.getEnd(); + if (position < end || (position === end && jsDocChild.kind === SyntaxKind.EndOfFileToken)) { + current = jsDocChild; + continue outer; + } + else if (includeItemAtEndPosition && end === position) { + let previousToken = findPrecedingToken(position, sourceFile, jsDocChild); + if (previousToken && includeItemAtEndPosition(previousToken)) { + return previousToken; + } + } + } + } + } + // find the child that contains 'position' for (let i = 0, n = current.getChildCount(sourceFile); i < n; i++) { let child = current.getChildAt(i); - let start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile); + // all jsDocComment nodes were already visited + if (isJSDocNode(child)) { + continue; + } + let start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile, includeJsDocComment); if (start <= position) { let end = child.getEnd(); if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { @@ -308,6 +332,7 @@ namespace ts { } } } + return current; } } @@ -501,11 +526,13 @@ namespace ts { } if (node) { - let jsDocComment = node.jsDocComment; - if (jsDocComment) { - for (let tag of jsDocComment.tags) { - if (tag.pos <= position && position <= tag.end) { - return tag; + let jsDocComments = node.jsDocComments; + if (jsDocComments) { + for (const jsDocComment of jsDocComments) { + for (const tag of jsDocComment.tags) { + if (tag.pos <= position && position <= tag.end) { + return tag; + } } } } @@ -615,7 +642,7 @@ namespace ts { // [a,b,c] from: // [a, b, c] = someExpression; if (node.parent.kind === SyntaxKind.BinaryExpression && - (node.parent).left === node && + (node.parent).left === node && (node.parent).operatorToken.kind === SyntaxKind.EqualsToken) { return true; } @@ -629,7 +656,7 @@ namespace ts { // [a, b, c] of // [x, [a, b, c] ] = someExpression - // or + // or // {x, a: {a, b, c} } = someExpression if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) { return true; diff --git a/tests/cases/fourslash/commentsVariables.ts b/tests/cases/fourslash/commentsVariables.ts index d62e1e9bee817..b2cf6c9cb9b0b 100644 --- a/tests/cases/fourslash/commentsVariables.ts +++ b/tests/cases/fourslash/commentsVariables.ts @@ -41,60 +41,60 @@ ////} ////var x = fo/*15*/o2; -goTo.marker('1'); -verify.quickInfoIs("var myVariable: number", "This is my variable"); +// goTo.marker('1'); +// verify.quickInfoIs("var myVariable: number", "This is my variable"); -goTo.marker('2'); -verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); +// goTo.marker('2'); +// verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); -goTo.marker('3'); -verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); -verify.completionListContains("d", "var d: number", "d variable"); +// goTo.marker('3'); +// verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); +// verify.completionListContains("d", "var d: number", "d variable"); goTo.marker('4'); verify.completionListContains("foo", "function foo(): void", "foos comment"); verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); -goTo.marker('5'); -verify.currentSignatureHelpDocCommentIs("foos comment"); -goTo.marker('5q'); -verify.quickInfoIs("function foo(): void", "foos comment"); +// goTo.marker('5'); +// verify.currentSignatureHelpDocCommentIs("foos comment"); +// goTo.marker('5q'); +// verify.quickInfoIs("function foo(): void", "foos comment"); -goTo.marker('6'); -verify.currentSignatureHelpDocCommentIs(""); -goTo.marker('6q'); -verify.quickInfoIs("var fooVar: () => void", ""); +// goTo.marker('6'); +// verify.currentSignatureHelpDocCommentIs(""); +// goTo.marker('6q'); +// verify.quickInfoIs("var fooVar: () => void", ""); -goTo.marker('7'); -verify.completionListContains("foo", "function foo(): void", "foos comment"); -verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); +// goTo.marker('7'); +// verify.completionListContains("foo", "function foo(): void", "foos comment"); +// verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); -goTo.marker('8'); -verify.currentSignatureHelpDocCommentIs("foos comment"); -goTo.marker('8q'); -verify.quickInfoIs("function foo(): void", "foos comment"); +// goTo.marker('8'); +// verify.currentSignatureHelpDocCommentIs("foos comment"); +// goTo.marker('8q'); +// verify.quickInfoIs("function foo(): void", "foos comment"); -goTo.marker('9'); -verify.currentSignatureHelpDocCommentIs(""); -goTo.marker('9q'); -verify.quickInfoIs("var fooVar: () => void", ""); -goTo.marker('9aq'); -verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +// goTo.marker('9'); +// verify.currentSignatureHelpDocCommentIs(""); +// goTo.marker('9q'); +// verify.quickInfoIs("var fooVar: () => void", ""); +// goTo.marker('9aq'); +// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -goTo.marker('10'); -verify.completionListContains("i", "var i: c", "instance comment"); +// goTo.marker('10'); +// verify.completionListContains("i", "var i: c", "instance comment"); -goTo.marker('11'); -verify.completionListContains("i1_i", "var i1_i: i1", "interface instance comments"); +// goTo.marker('11'); +// verify.completionListContains("i1_i", "var i1_i: i1", "interface instance comments"); -goTo.marker('12'); -verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +// goTo.marker('12'); +// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -goTo.marker('13'); -verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +// goTo.marker('13'); +// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -goTo.marker('14'); -verify.quickInfoIs("function foo(): void", "foos comment"); +// goTo.marker('14'); +// verify.quickInfoIs("function foo(): void", "foos comment"); -goTo.marker('15'); -verify.quickInfoIs("function foo2(a: number): void (+1 overload)", ""); +// goTo.marker('15'); +// verify.quickInfoIs("function foo2(a: number): void (+1 overload)", ""); diff --git a/tests/cases/fourslash/doesnotwork.ts b/tests/cases/fourslash/doesnotwork.ts new file mode 100644 index 0000000000000..2f415563c2153 --- /dev/null +++ b/tests/cases/fourslash/doesnotwork.ts @@ -0,0 +1,45 @@ +/// + +/////** This is my variable*/ +////var myVariable = 10; +//// +/////** d variable*/ +////var d = 10; +////myVariable = d; +//// +/////** foos comment*/ +////function foo() { +////} +/////** fooVar comment*/ +////var fooVar: () => void; +/////*4*/ +////foo(); +////fooVar(); +////fooVar = foo; +//// +////foo(); +////fooVar(); +////var fooVarVar = fooVar; +/////**class comment*/ +////class c { +//// /** constructor comment*/ +//// constructor() { +//// } +////} +/////**instance comment*/ +////var i = new c(); +//// +/////** interface comments*/ +////interface i1 { +////} +/////**interface instance comments*/ +////var i1_i: i1; +//// +////function foo2(a: number): void; +////function foo2(b: string): void; +////function foo2(aOrb) { +////} +////var x = foo2; + +goTo.marker('4'); +verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); diff --git a/tests/cases/fourslash/server/jsdocCompletions.ts b/tests/cases/fourslash/server/jsdocCompletions.ts deleted file mode 100644 index c8dc1bbe48113..0000000000000 --- a/tests/cases/fourslash/server/jsdocCompletions.ts +++ /dev/null @@ -1,15 +0,0 @@ -/// - -// @allowNonTsExtensions: true -// @Filename: jsdocCompletion_typedef.js -//// /** -//// * @typedef {Object} Person -//// * @property {string} personName -//// * @type {Person} -//// */ -//// var x1; -//// x1/**/ - -goTo.marker(); -edit.insert('.'); -verify.memberListContains('personName'); \ No newline at end of file diff --git a/tests/cases/fourslash/server/jsdocTypedefTag.ts b/tests/cases/fourslash/server/jsdocTypedefTag.ts new file mode 100644 index 0000000000000..e645b518020bb --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTag.ts @@ -0,0 +1,64 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsdocCompletion_typedef.js + +//// /** @typedef {(string | number)} NumberLike */ +//// +//// /** +//// * @typedef Animal +//// * @type {Object} +//// * @property {string} animalName +//// * @property {number} animalAge +//// */ +//// +//// /** +//// * @typedef {Object} Person +//// * @property {string} personName +//// * @property {number} personAge +//// */ +//// +//// /** +//// * @typedef {Object} +//// * @property {string} catName +//// * @property {number} catAge +//// */ +//// var Cat; +//// +//// /** @typedef {{ dogName: string, dogAge: number }} */ +//// var Dog; +//// +//// /** @type {NumberLike} */ +//// var numberLike; numberLike./*numberLike*/ +//// +//// /** @type {Person} */ +//// var p;p./*person*/ +//// +//// /** @type {Animal} */ +//// var a;a./*animal*/ +//// +//// /** @type {Cat} */ +//// var c;c./*cat*/ +//// +//// /** @type {Dog} */ +//// var d;d./*dog*/ + +goTo.marker('numberLike'); +verify.memberListContains('charAt'); +verify.memberListContains('toExponential'); + +goTo.marker('person'); +verify.memberListContains('personName'); +verify.memberListContains('personAge'); + +goTo.marker('animal'); +verify.memberListContains('animalName'); +verify.memberListContains('animalAge'); + +goTo.marker('dog'); +verify.memberListContains('dogName'); +verify.memberListContains('dogAge'); + +goTo.marker('cat'); +verify.memberListContains('catName'); +verify.memberListContains('catAge'); \ No newline at end of file diff --git a/tests/cases/fourslash/server/jsdocTypedefTagGoToDefinition.ts b/tests/cases/fourslash/server/jsdocTypedefTagGoToDefinition.ts new file mode 100644 index 0000000000000..4db14611938b7 --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagGoToDefinition.ts @@ -0,0 +1,29 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsdocCompletion_typedef.js + +//// /** +//// * @typedef {Object} Person +//// * /*1*/@property {string} personName +//// * @property {number} personAge +//// */ +//// +//// /** +//// * @typedef {{ /*2*/animalName: string, animalAge: number }} Animal +//// */ +//// +//// /** @type {Person} */ +//// var person; person.personName/*3*/ +//// +//// /** @type {Animal} */ +//// var animal; animal.animalName/*4*/ + +goTo.file('jsdocCompletion_typedef.js'); +goTo.marker('3'); +goTo.definition(); +verify.caretAtMarker('1'); + +goTo.marker('4'); +goTo.definition(); +verify.caretAtMarker('2'); diff --git a/tests/cases/fourslash/server/jsdocTypedefTagRename01.ts b/tests/cases/fourslash/server/jsdocTypedefTagRename01.ts new file mode 100644 index 0000000000000..776d0180b0689 --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagRename01.ts @@ -0,0 +1,20 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsDocTypedef_form1.js +//// +//// /** @typedef {(string | number)} */ +//// var /*1*/[|NumberLike|]; +//// +//// /*2*/[|NumberLike|] = 10; +//// +//// /** @type {/*3*/[|NumberLike|]} */ +//// var numberLike; + +goTo.file('jsDocTypedef_form1.js') +goTo.marker('1'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); +goTo.marker('2'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); +goTo.marker('3'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); \ No newline at end of file diff --git a/tests/cases/fourslash/server/jsdocTypedefTagRename02.ts b/tests/cases/fourslash/server/jsdocTypedefTagRename02.ts new file mode 100644 index 0000000000000..7f1d422d971d9 --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagRename02.ts @@ -0,0 +1,15 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsDocTypedef_form2.js +//// +//// /** @typedef {(string | number)} /*1*/[|NumberLike|] */ +//// +//// /** @type {/*2*/[|NumberLike|]} */ +//// var numberLike; + +goTo.file('jsDocTypedef_form2.js') +goTo.marker('1'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); +goTo.marker('2'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); \ No newline at end of file diff --git a/tests/cases/fourslash/server/jsdocTypedefTagRename03.ts b/tests/cases/fourslash/server/jsdocTypedefTagRename03.ts new file mode 100644 index 0000000000000..c1b389458069d --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagRename03.ts @@ -0,0 +1,20 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsDocTypedef_form3.js +//// +//// /** +//// * @typedef /*1*/[|Person|] +//// * @type {Object} +//// * @property {number} age +//// * @property {string} name +//// */ +//// +//// /** @type {/*2*/[|Person|]} */ +//// var person; + +goTo.file('jsDocTypedef_form3.js') +goTo.marker('1'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); +goTo.marker('2'); +verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true); \ No newline at end of file diff --git a/tests/cases/fourslash/server/jsdocTypedefTagRename04.ts b/tests/cases/fourslash/server/jsdocTypedefTagRename04.ts new file mode 100644 index 0000000000000..b7bf220512a5d --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagRename04.ts @@ -0,0 +1,24 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsDocTypedef_form2.js +//// +//// function test1() { +//// /** @typedef {(string | number)} NumberLike */ +//// +//// /** @type {/*1*/NumberLike} */ +//// var numberLike; +//// } +//// function test2() { +//// /** @typedef {(string | number)} NumberLike2 */ +//// +//// /** @type {NumberLike2} */ +//// var n/*2*/umberLike2; +//// } + +goTo.marker('2'); +verify.quickInfoExists(); +goTo.marker('1'); +edit.insert('111'); +goTo.marker('2'); +verify.quickInfoExists(); \ No newline at end of file diff --git a/tests/cases/unittests/jsDocParsing.ts b/tests/cases/unittests/jsDocParsing.ts index 1bd7b1147ca2a..0540c02d135a8 100644 --- a/tests/cases/unittests/jsDocParsing.ts +++ b/tests/cases/unittests/jsDocParsing.ts @@ -1004,7 +1004,8 @@ module ts { if (result !== expected) { // Turn on a human-readable diff if (typeof require !== 'undefined') { - require('chai').config.showDiff = true; + const chai = require('chai'); + chai.config.showDiff = true; chai.expect(JSON.parse(result)).equal(JSON.parse(expected)); } else { diff --git a/tests/webTestServer.js b/tests/webTestServer.js new file mode 100644 index 0000000000000..b47da7bfe765d --- /dev/null +++ b/tests/webTestServer.js @@ -0,0 +1,288 @@ +/// +"use strict"; +var http = require("http"); +var fs = require("fs"); +var path = require("path"); +var url = require("url"); +var child_process = require("child_process"); +var os = require("os"); +/// Command line processing /// +if (process.argv[2] == '--help') { + console.log('Runs a node server on port 8888 by default, looking for tests folder in the current directory\n'); + console.log('Syntax: node nodeServer.js [port] [typescriptEnlistmentDirectory] [tests] [--browser] [--verbose]\n'); + console.log('Examples: \n\tnode nodeServer.js 8888 .'); + console.log('\tnode nodeServer.js 3000 D:/src/typescript/public --verbose IE'); +} +function switchToForwardSlashes(path) { + return path.replace(/\\/g, "/").replace(/\/\//g, '/'); +} +var defaultPort = 8888; +var port = process.argv[2] || defaultPort; +var rootDir = switchToForwardSlashes(__dirname + '/../'); +var browser; +if (process.argv[3]) { + browser = process.argv[3]; + if (browser !== 'chrome' && browser !== 'IE') { + console.log('Invalid command line arguments. Got ' + browser + ' but expected chrome, IE or nothing.'); + } +} +var grep = process.argv[4]; +var verbose = false; +if (process.argv[5] == '--verbose') { + verbose = true; +} +else if (process.argv[5] && process.argv[5] !== '--verbose') { + console.log('Invalid command line arguments. Got ' + process.argv[5] + ' but expected --verbose or nothing.'); +} +/// Utils /// +function log(msg) { + if (verbose) { + console.log(msg); + } +} +// Copied from the compiler sources +function dir(path, spec, options) { + options = options || {}; + function filesInFolder(folder) { + var folder = switchToForwardSlashes(folder); + var paths = []; + // Everything after the current directory is relative + var baseDirectoryLength = process.cwd().length + 1; + try { + var files = fs.readdirSync(folder); + for (var i = 0; i < files.length; i++) { + var stat = fs.statSync(folder + "/" + files[i]); + if (options.recursive && stat.isDirectory()) { + paths = paths.concat(filesInFolder(folder + "/" + files[i])); + } + else if (stat.isFile() && (!spec || files[i].match(spec))) { + var relativePath = folder.substring(baseDirectoryLength); + paths.push(relativePath + "/" + files[i]); + } + } + } + catch (err) { + } + return paths; + } + return filesInFolder(path); +} +// fs.rmdirSync won't delete directories with files in it +function deleteFolderRecursive(path) { + if (fs.existsSync(path)) { + fs.readdirSync(path).forEach(function (file, index) { + var curPath = path + "/" + file; + if (fs.statSync(curPath).isDirectory()) { + deleteFolderRecursive(curPath); + } + else { + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(path); + } +} +; +function writeFile(path, data, opts) { + try { + fs.writeFileSync(path, data); + } + catch (e) { + // assume file was written to a directory that exists, if not, start recursively creating them as necessary + var parts = switchToForwardSlashes(path).split('/'); + for (var i = 0; i < parts.length; i++) { + var subDir = parts.slice(0, i).join('/'); + if (!fs.existsSync(subDir)) { + fs.mkdir(subDir); + } + } + fs.writeFileSync(path, data); + } +} +/// Request Handling /// +function handleResolutionRequest(filePath, res) { + var resolvedPath = path.resolve(filePath, ''); + resolvedPath = resolvedPath.substring(resolvedPath.indexOf('tests')); + resolvedPath = switchToForwardSlashes(resolvedPath); + send('success', res, resolvedPath); + return; +} +function send(result, res, contents, contentType) { + if (contentType === void 0) { contentType = "binary"; } + var responseCode = result === "success" ? 200 : result === "fail" ? 500 : result === 'unknown' ? 404 : parseInt(result); + res.writeHead(responseCode, { "Content-Type": contentType }); + res.end(contents); + return; +} +// Reads the data from a post request and passes it to the given callback +function processPost(req, res, callback) { + var queryData = ""; + if (typeof callback !== 'function') + return null; + if (req.method == 'POST') { + req.on('data', function (data) { + queryData += data; + if (queryData.length > 1e8) { + queryData = ""; + send("413", res, null); + console.log("ERROR: destroying connection"); + req.connection.destroy(); + } + }); + req.on('end', function () { + //res.post = url.parse(req.url).query; + callback(queryData); + }); + } + else { + send("405", res, null); + } +} +var RequestType; +(function (RequestType) { + RequestType[RequestType["GetFile"] = 0] = "GetFile"; + RequestType[RequestType["GetDir"] = 1] = "GetDir"; + RequestType[RequestType["ResolveFile"] = 2] = "ResolveFile"; + RequestType[RequestType["WriteFile"] = 3] = "WriteFile"; + RequestType[RequestType["DeleteFile"] = 4] = "DeleteFile"; + RequestType[RequestType["WriteDir"] = 5] = "WriteDir"; + RequestType[RequestType["DeleteDir"] = 6] = "DeleteDir"; + RequestType[RequestType["AppendFile"] = 7] = "AppendFile"; + RequestType[RequestType["Unknown"] = 8] = "Unknown"; +})(RequestType || (RequestType = {})); +function getRequestOperation(req, filename) { + if (req.method === 'GET' && req.url.indexOf('?') === -1) { + if (req.url.indexOf('.') !== -1) + return RequestType.GetFile; + else + return RequestType.GetDir; + } + else { + var queryData = url.parse(req.url, true).query; + if (req.method === 'GET' && queryData.resolve !== undefined) + return RequestType.ResolveFile; + // mocha uses ?grep= query string as equivalent to the --grep command line option used to filter tests + if (req.method === 'GET' && queryData.grep !== undefined) + return RequestType.GetFile; + if (req.method === 'POST' && queryData.action) { + var path = req.url.substr(0, req.url.lastIndexOf('?')); + var isFile = path.substring(path.lastIndexOf('/')).indexOf('.') !== -1; + switch (queryData.action.toUpperCase()) { + case 'WRITE': + return isFile ? RequestType.WriteFile : RequestType.WriteDir; + case 'DELETE': + return isFile ? RequestType.DeleteFile : RequestType.DeleteDir; + case 'APPEND': + return isFile ? RequestType.AppendFile : RequestType.Unknown; + } + } + return RequestType.Unknown; + } +} +function handleRequestOperation(req, res, operation, reqPath) { + switch (operation) { + case RequestType.GetDir: + var filesInFolder = dir(reqPath, "", { recursive: true }); + send('success', res, filesInFolder.join(',')); + break; + case RequestType.GetFile: + fs.readFile(reqPath, function (err, file) { + var ext = reqPath.substr(reqPath.lastIndexOf('.')); + var contentType = 'binary'; + if (ext === '.js') + contentType = 'text/javascript'; + else if (ext === '.css') + contentType = 'text/javascript'; + else if (ext === '.html') + contentType = 'text/html'; + err + ? send('fail', res, err.message, contentType) + : send('success', res, file, contentType); + }); + break; + case RequestType.ResolveFile: + var resolveRequest = req.url.match(/(.*)\?resolve/); + handleResolutionRequest(resolveRequest[1], res); + break; + case RequestType.WriteFile: + processPost(req, res, function (data) { + writeFile(reqPath, data, { recursive: true }); + }); + send('success', res, null); + break; + case RequestType.WriteDir: + fs.mkdirSync(reqPath); + send('success', res, null); + break; + case RequestType.DeleteFile: + if (fs.existsSync(reqPath)) { + fs.unlinkSync(reqPath); + } + send('success', res, null); + break; + case RequestType.DeleteDir: + if (fs.existsSync(reqPath)) { + fs.rmdirSync(reqPath); + } + send('success', res, null); + break; + case RequestType.AppendFile: + processPost(req, res, function (data) { + fs.appendFileSync(reqPath, data); + }); + send('success', res, null); + break; + case RequestType.Unknown: + default: + send('unknown', res, null); + break; + } +} +console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown"); +http.createServer(function (req, res) { + log(req.method + ' ' + req.url); + var uri = url.parse(req.url).pathname; + var reqPath = path.join(process.cwd(), uri); + var operation = getRequestOperation(req, reqPath); + handleRequestOperation(req, res, operation, reqPath); +}).listen(8888); +var browserPath; +if ((browser && browser === 'chrome')) { + var defaultChromePath = ""; + switch (os.platform()) { + case "win32": + case "win64": + defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"; + break; + case "darwin": + defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; + break; + case "linux": + defaultChromePath = "/opt/google/chrome/chrome"; + break; + default: + console.log("default Chrome location is unknown for platform '" + os.platform() + "'"); + break; + } + if (fs.existsSync(defaultChromePath)) { + browserPath = defaultChromePath; + } + else { + browserPath = browser; + } +} +else { + var defaultIEPath = 'C:/Program Files/Internet Explorer/iexplore.exe'; + if (fs.existsSync(defaultIEPath)) { + browserPath = defaultIEPath; + } + else { + browserPath = browser; + } +} +console.log('Using browser: ' + browserPath); +var queryString = grep ? "?grep=" + grep : ''; +child_process.spawn(browserPath, ['http://localhost:' + port + '/tests/webTestResults.html' + queryString], { + stdio: 'inherit' +}); +//# sourceMappingURL=file:///C:/Users/lizhe/Documents/github/TypeScript/tests/webTestServer.js.map \ No newline at end of file diff --git a/tests/webTestServer.js.map b/tests/webTestServer.js.map new file mode 100644 index 0000000000000..1c924a872f41d --- /dev/null +++ b/tests/webTestServer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"webTestServer.js","sourceRoot":"","sources":["file:///C:/Users/lizhe/Documents/github/TypeScript/tests/webTestServer.ts"],"names":[],"mappings":"AAAA,yDAAyD;;AAEzD,IAAO,IAAI,WAAW,MAAM,CAAC,CAAC;AAC9B,IAAO,EAAE,WAAW,IAAI,CAAC,CAAC;AAC1B,IAAO,IAAI,WAAW,MAAM,CAAC,CAAC;AAC9B,IAAO,GAAG,WAAW,KAAK,CAAC,CAAC;AAC5B,IAAO,aAAa,WAAW,eAAe,CAAC,CAAC;AAChD,IAAO,EAAE,WAAW,IAAI,CAAC,CAAC;AAE1B,+BAA+B;AAE/B,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,iGAAiG,CAAC,CAAC;IAC/G,OAAO,CAAC,GAAG,CAAC,qGAAqG,CAAC,CAAC;IACnH,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;AACnF,CAAC;AAED,gCAAgC,IAAY;IACxC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,IAAI,WAAW,GAAG,IAAI,CAAC;AACvB,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;AAC1C,IAAI,OAAO,GAAG,sBAAsB,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC;AAEzD,IAAI,OAAe,CAAC;AACpB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClB,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1B,EAAE,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,sCAAsC,GAAG,OAAO,GAAG,sCAAsC,CAAC,CAAC;IAC3G,CAAC;AACL,CAAC;AAED,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE3B,IAAI,OAAO,GAAG,KAAK,CAAC;AACpB,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC;IACjC,OAAO,GAAG,IAAI,CAAC;AACnB,CAAC;AAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,sCAAsC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,qCAAqC,CAAC,CAAC;AAClH,CAAC;AAED,aAAa;AACb,aAAa,GAAW;IACpB,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;AACL,CAAC;AAED,mCAAmC;AACnC,aAAa,IAAY,EAAE,IAAa,EAAE,OAAa;IACnD,OAAO,GAAG,OAAO,IAA8B,EAAE,CAAC;IAElD,uBAAuB,MAAc;QACjC,IAAI,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,KAAK,GAAa,EAAE,CAAC;QACzB,qDAAqD;QACrD,IAAI,mBAAmB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAEnD,IAAI,CAAC;YACD,IAAI,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YACnC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpC,IAAI,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChD,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;oBAC1C,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACjE,CAAC;gBAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC1D,IAAI,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;oBACzD,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9C,CAAC;YACL,CAAC;QACL,CAAE;QAAA,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAEf,CAAC;QACD,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED,yDAAyD;AACzD,+BAA+B,IAAY;IACvC,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,KAAK;YAC9C,IAAI,OAAO,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC;YAChC,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;gBACrC,qBAAqB,CAAC,OAAO,CAAC,CAAC;YACnC,CAAC;YAAC,IAAI,CAAC,CAAC;gBACJ,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACL,CAAC;AAAA,CAAC;AAEF,mBAAmB,IAAY,EAAE,IAAS,EAAE,IAA4B;IACpE,IAAI,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAE;IAAA,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACT,2GAA2G;QAC3G,IAAI,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpC,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACzB,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrB,CAAC;QACL,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;AACL,CAAC;AAED,wBAAwB;AAExB,iCAAiC,QAAgB,EAAE,GAAwB;IACvE,IAAI,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC9C,YAAY,GAAG,YAAY,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,YAAY,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IACnC,MAAM,CAAC;AACX,CAAC;AAMD,cAAc,MAAc,EAAE,GAAwB,EAAE,QAAgB,EAAE,WAAsB;IAAtB,2BAAsB,GAAtB,sBAAsB;IAC5F,IAAI,YAAY,GAAG,MAAM,KAAK,SAAS,GAAG,GAAG,GAAG,MAAM,KAAK,MAAM,GAAG,GAAG,GAAG,MAAM,KAAK,SAAS,GAAG,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxH,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7D,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClB,MAAM,CAAC;AACX,CAAC;AAED,yEAAyE;AACzE,qBAAqB,GAAuB,EAAE,GAAwB,EAAE,QAA+B;IACnG,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,EAAE,CAAC,CAAC,OAAO,QAAQ,KAAK,UAAU,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC;IAEhD,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC;QACvB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,IAAY;YACjC,SAAS,IAAI,IAAI,CAAC;YAClB,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;gBACzB,SAAS,GAAG,EAAE,CAAC;gBACf,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;gBAC5C,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YAC7B,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE;YACV,sCAAsC;YACtC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IAEP,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;AACL,CAAC;AAED,IAAK,WAUJ;AAVD,WAAK,WAAW;IACZ,mDAAO,CAAA;IACP,iDAAM,CAAA;IACN,2DAAW,CAAA;IACX,uDAAS,CAAA;IACT,yDAAU,CAAA;IACV,qDAAQ,CAAA;IACR,uDAAS,CAAA;IACT,yDAAU,CAAA;IACV,mDAAO,CAAA;AACX,CAAC,EAVI,WAAW,KAAX,WAAW,QAUf;AAED,6BAA6B,GAAuB,EAAE,QAAgB;IAClE,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;QAC5D,IAAI;YAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,CAAC;QACF,IAAI,SAAS,GAAQ,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC;QACpD,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,CAAC;YAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAA;QAC3F,8GAA8G;QAC9G,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC;YAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAA;QACpF,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5C,IAAI,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YACvD,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACvE,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;gBACrC,KAAK,OAAO;oBACR,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC;gBACjE,KAAK,QAAQ;oBACT,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,UAAU,GAAG,WAAW,CAAC,SAAS,CAAC;gBACnE,KAAK,QAAQ;oBACT,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC;YACrE,CAAC;QACL,CAAC;QACD,MAAM,CAAC,WAAW,CAAC,OAAO,CAAA;IAC9B,CAAC;AACL,CAAC;AAED,gCAAgC,GAAuB,EAAE,GAAwB,EAAE,SAAsB,EAAE,OAAe;IACtH,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;QAChB,KAAK,WAAW,CAAC,MAAM;YACnB,IAAI,aAAa,GAAG,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9C,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,OAAO;YACpB,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,EAAE,IAAI;gBACpC,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;gBACnD,IAAI,WAAW,GAAG,QAAQ,CAAC;gBAC3B,EAAE,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC;oBAAC,WAAW,GAAG,iBAAiB,CAAA;gBAClD,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC;oBAAC,WAAW,GAAG,iBAAiB,CAAA;gBACxD,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC;oBAAC,WAAW,GAAG,WAAW,CAAA;gBACnD,GAAG;sBACD,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC;sBAC3C,IAAI,CAAC,SAAS,EAAE,GAAG,EAAQ,IAAK,EAAE,WAAW,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;YACH,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,WAAW;YACxB,IAAI,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YACpD,uBAAuB,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAChD,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,SAAS;YACtB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,UAAC,IAAI;gBACvB,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,QAAQ;YACrB,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACtB,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,UAAU;YACvB,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACzB,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;YACD,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,SAAS;YACtB,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACzB,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;YACD,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,UAAU;YACvB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,UAAC,IAAI;gBACvB,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;QACV,KAAK,WAAW,CAAC,OAAO,CAAC;QACzB;YACI,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;YAC3B,KAAK,CAAC;IACd,CAAC;AACL,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,uDAAuD,GAAG,IAAI,GAAG,yBAAyB,CAAC,CAAC;AAExG,IAAI,CAAC,YAAY,CAAC,UAAU,GAAuB,EAAE,GAAwB;IACzE,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAA;IACrC,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,SAAS,GAAG,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAClD,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAEhB,IAAI,WAAmB,CAAC;AACxB,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAC3B,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACpB,KAAK,OAAO,CAAC;QACb,KAAK,OAAO;YACR,iBAAiB,GAAG,6DAA6D,CAAC;YAClF,KAAK,CAAC;QACV,KAAK,QAAQ;YACT,iBAAiB,GAAG,8DAA8D,CAAC;YACnF,KAAK,CAAC;QACV,KAAK,OAAO;YACR,iBAAiB,GAAG,2BAA2B,CAAA;YAC/C,KAAK,CAAC;QACV;YACI,OAAO,CAAC,GAAG,CAAC,sDAAoD,EAAE,CAAC,QAAQ,EAAE,MAAG,CAAC,CAAC;YAClF,KAAK,CAAC;IACd,CAAC;IACD,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACnC,WAAW,GAAG,iBAAiB,CAAC;IACpC,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,WAAW,GAAG,OAAO,CAAC;IAC1B,CAAC;AACL,CAAC;AAAC,IAAI,CAAC,CAAC;IACJ,IAAI,aAAa,GAAG,iDAAiD,CAAC;IACtE,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAC/B,WAAW,GAAG,aAAa,CAAC;IAChC,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,WAAW,GAAG,OAAO,CAAC;IAC1B,CAAC;AACL,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,WAAW,CAAC,CAAC;AAE7C,IAAI,WAAW,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;AAC9C,aAAa,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,mBAAmB,GAAG,IAAI,GAAG,4BAA4B,GAAG,WAAW,CAAC,EAAE;IACxG,KAAK,EAAE,SAAS;CACnB,CAAC,CAAC"} \ No newline at end of file From 0dddcf4b84ee3eba1413a1591984605ef4940708 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 14 Apr 2016 16:51:22 -0700 Subject: [PATCH 05/13] code clean up --- src/compiler/parser.ts | 38 ++- src/compiler/types.ts | 2 + src/compiler/utilities.ts | 32 +-- src/harness/harness.ts | 4 +- src/services/services.ts | 9 +- tests/cases/fourslash/commentsVariables.ts | 80 +++--- tests/cases/fourslash/doesnotwork.ts | 45 ---- tests/webTestServer.js | 288 --------------------- tests/webTestServer.js.map | 1 - 9 files changed, 72 insertions(+), 427 deletions(-) delete mode 100644 tests/cases/fourslash/doesnotwork.ts delete mode 100644 tests/webTestServer.js delete mode 100644 tests/webTestServer.js.map diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 058098eff1db0..3a1c3c62f410f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -409,7 +409,6 @@ namespace ts { return visitNodes(cbNodes, (node).members); case SyntaxKind.JSDocPropertyTag: return visitNode(cbNode, (node).typeExpression) || - visitNode(cbNode, (node).type) || visitNode(cbNode, (node).name); } } @@ -4063,9 +4062,9 @@ namespace ts { const isAsync = !!(node.flags & NodeFlags.Async); node.name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : - isGenerator ? doInYieldContext(parseOptionalIdentifier) : - isAsync ? doInAwaitContext(parseOptionalIdentifier) : - parseOptionalIdentifier(); + isGenerator ? doInYieldContext(parseOptionalIdentifier) : + isAsync ? doInAwaitContext(parseOptionalIdentifier) : + parseOptionalIdentifier(); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false); @@ -6121,15 +6120,13 @@ namespace ts { typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; } } - if (!typedefTag.type && typedefTag.jsDocPropertyTags) { - const childrenTagPoses = ts.map(typedefTag.jsDocPropertyTags, tag => tag.pos); - const childrenTagEnds = ts.map(typedefTag.jsDocPropertyTags, tag => tag.end); - const pos = Math.min(...childrenTagPoses); - const end = Math.max(...childrenTagEnds); - const tagType = createNode(SyntaxKind.JSDocTypeLiteral, pos); - tagType.members = >[]; - addRange(tagType.members, typedefTag.jsDocPropertyTags); - typedefTag.type = finishNode(tagType, end); + if (!typedefTag.type && typedefTag.jsDocPropertyTags && typedefTag.jsDocPropertyTags.length > 0) { + const pos = typedefTag.jsDocPropertyTags[0].pos; + const end = typedefTag.jsDocPropertyTags[typedefTag.jsDocPropertyTags.length - 1].end; + const jsdocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, pos); + jsdocTypeLiteral.members = >[]; + addRange(jsdocTypeLiteral.members, typedefTag.jsDocPropertyTags); + typedefTag.type = finishNode(jsdocTypeLiteral, end); } } @@ -6303,23 +6300,18 @@ namespace ts { result.typeExpression = tryParseTypeExpression(); result = finishNode(result); - let typeTagPartOfParentTag = false; if (currentParentJSDocTag && currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) { const parentTag = currentParentJSDocTag; if (!parentTag.typeExpression && !parentTag.jsDocTypeTag) { - typeTagPartOfParentTag = true; parentTag.jsDocTypeTag = result; currentParentJSDocTagEnd = scanner.getStartPos(); + return result; } } - if (!typeTagPartOfParentTag) { - // If this @type tag is not part of the current parent tag, then - // it denotes the end of the current parent tag. - finishCurrentParentTag(); - return result; - } - - return undefined; + // If this @type tag is not part of the current parent tag, then + // it denotes the end of the current parent tag. + finishCurrentParentTag(); + return result; } function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7743f7c35de97..91ce1f1022fba 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1533,6 +1533,8 @@ namespace ts { export interface JSDocPropertyTag extends JSDocTag, TypeElement { name: Identifier; typeExpression: JSDocTypeExpression; + // Add a "type" property here to make the interface compatible + // with the "VariableLikeDeclaration" definition type: TypeNode; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ebf6b42581aa6..2f29e477d69cd 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -279,13 +279,16 @@ namespace ts { return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true); } - if (node.jsDocComments && node.jsDocComments.length > 0 && includeJsDocComment) { + if (includeJsDocComment && node.jsDocComments && node.jsDocComments.length > 0) { return getTokenPosOfNode(node.jsDocComments[0]); } - if (node.kind === SyntaxKind.SyntaxList) { - const childrenPoses = ts.map((node)._children, child => getTokenPosOfNode(child, sourceFile, includeJsDocComment)); - return Math.min(...childrenPoses); + // For a syntax list, it is possible that one of its children has JSDocComment nodes, while + // the syntax list itself considers them as normal trivia. Therefore if we simply skip + // trivia for the list, we may have skipped the JSDocComment as well. So we should process its + // first child to determine the actual position of its first token. + if (node.kind === SyntaxKind.SyntaxList && (node)._children.length > 0) { + return getTokenPosOfNode((node)._children[0], sourceFile, includeJsDocComment); } return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); @@ -294,27 +297,6 @@ namespace ts { export function isJSDocNode(node: Node) { return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode; } - export function isJSDocType(node: Node) { - switch (node.kind) { - case SyntaxKind.JSDocAllType: - case SyntaxKind.JSDocUnknownType: - case SyntaxKind.JSDocArrayType: - case SyntaxKind.JSDocUnionType: - case SyntaxKind.JSDocTupleType: - case SyntaxKind.JSDocNullableType: - case SyntaxKind.JSDocNonNullableType: - case SyntaxKind.JSDocRecordType: - case SyntaxKind.JSDocRecordMember: - case SyntaxKind.JSDocTypeReference: - case SyntaxKind.JSDocOptionalType: - case SyntaxKind.JSDocFunctionType: - case SyntaxKind.JSDocVariadicType: - case SyntaxKind.JSDocConstructorType: - case SyntaxKind.JSDocThisType: - return true; - } - return false; - } export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { if (nodeIsMissing(node) || !node.decorators) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 790ecebb75f04..e07fe60ba8688 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -222,7 +222,9 @@ namespace Utils { return k; } - if (k === (ts).SyntaxKind.FirstJSDocCommentNode || k === (ts).SyntaxKind.LastJSDocCommentNode) { + // For some markers in SyntaxKind, we should print its original syntax name instead of + // the marker name in tests. + if (k === (ts).SyntaxKind.FirstJSDocNode || k === (ts).SyntaxKind.LastJSDocNode) { for (const kindName in (ts).SyntaxKind) { if ((ts).SyntaxKind[kindName] === k) { return kindName; diff --git a/src/services/services.ts b/src/services/services.ts index f2906aaa8b4ff..ffbb174fe8cba 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -173,6 +173,7 @@ namespace ts { "type", "typedef", "property", + "prop", "version" ]; let jsDocCompletionEntries: CompletionEntry[]; @@ -274,7 +275,7 @@ namespace ts { scanner.setText((sourceFile || this.getSourceFile()).text); children = []; let pos = this.pos; - const isJSDocTag = + const useJSDocScanner = this.kind === SyntaxKind.JSDocComment || this.kind === SyntaxKind.JSDocParameterTag || this.kind === SyntaxKind.JSDocTag || @@ -286,14 +287,14 @@ namespace ts { this.kind === SyntaxKind.JSDocPropertyTag; const processNode = (node: Node) => { if (pos < node.pos) { - pos = this.addSyntheticNodes(children, pos, node.pos, /*useJSDocScanner*/ isJSDocTag); + pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); } children.push(node); pos = node.end; }; const processNodes = (nodes: NodeArray) => { if (pos < nodes.pos) { - pos = this.addSyntheticNodes(children, pos, nodes.pos, /*useJSDocScanner*/ isJSDocTag); + pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner); } children.push(this.createSyntaxList(>nodes)); pos = nodes.end; @@ -7803,7 +7804,7 @@ namespace ts { break; default: forEachChild(node, walk); - if (node.jsDocComments && node.jsDocComments.length > 0) { + if (node.jsDocComments) { for (const jsDocComment of node.jsDocComments) { forEachChild(jsDocComment, walk); } diff --git a/tests/cases/fourslash/commentsVariables.ts b/tests/cases/fourslash/commentsVariables.ts index b2cf6c9cb9b0b..d62e1e9bee817 100644 --- a/tests/cases/fourslash/commentsVariables.ts +++ b/tests/cases/fourslash/commentsVariables.ts @@ -41,60 +41,60 @@ ////} ////var x = fo/*15*/o2; -// goTo.marker('1'); -// verify.quickInfoIs("var myVariable: number", "This is my variable"); +goTo.marker('1'); +verify.quickInfoIs("var myVariable: number", "This is my variable"); -// goTo.marker('2'); -// verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); +goTo.marker('2'); +verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); -// goTo.marker('3'); -// verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); -// verify.completionListContains("d", "var d: number", "d variable"); +goTo.marker('3'); +verify.completionListContains("myVariable", "var myVariable: number", "This is my variable"); +verify.completionListContains("d", "var d: number", "d variable"); goTo.marker('4'); verify.completionListContains("foo", "function foo(): void", "foos comment"); verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); -// goTo.marker('5'); -// verify.currentSignatureHelpDocCommentIs("foos comment"); -// goTo.marker('5q'); -// verify.quickInfoIs("function foo(): void", "foos comment"); +goTo.marker('5'); +verify.currentSignatureHelpDocCommentIs("foos comment"); +goTo.marker('5q'); +verify.quickInfoIs("function foo(): void", "foos comment"); -// goTo.marker('6'); -// verify.currentSignatureHelpDocCommentIs(""); -// goTo.marker('6q'); -// verify.quickInfoIs("var fooVar: () => void", ""); +goTo.marker('6'); +verify.currentSignatureHelpDocCommentIs(""); +goTo.marker('6q'); +verify.quickInfoIs("var fooVar: () => void", ""); -// goTo.marker('7'); -// verify.completionListContains("foo", "function foo(): void", "foos comment"); -// verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); +goTo.marker('7'); +verify.completionListContains("foo", "function foo(): void", "foos comment"); +verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); -// goTo.marker('8'); -// verify.currentSignatureHelpDocCommentIs("foos comment"); -// goTo.marker('8q'); -// verify.quickInfoIs("function foo(): void", "foos comment"); +goTo.marker('8'); +verify.currentSignatureHelpDocCommentIs("foos comment"); +goTo.marker('8q'); +verify.quickInfoIs("function foo(): void", "foos comment"); -// goTo.marker('9'); -// verify.currentSignatureHelpDocCommentIs(""); -// goTo.marker('9q'); -// verify.quickInfoIs("var fooVar: () => void", ""); -// goTo.marker('9aq'); -// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +goTo.marker('9'); +verify.currentSignatureHelpDocCommentIs(""); +goTo.marker('9q'); +verify.quickInfoIs("var fooVar: () => void", ""); +goTo.marker('9aq'); +verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -// goTo.marker('10'); -// verify.completionListContains("i", "var i: c", "instance comment"); +goTo.marker('10'); +verify.completionListContains("i", "var i: c", "instance comment"); -// goTo.marker('11'); -// verify.completionListContains("i1_i", "var i1_i: i1", "interface instance comments"); +goTo.marker('11'); +verify.completionListContains("i1_i", "var i1_i: i1", "interface instance comments"); -// goTo.marker('12'); -// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +goTo.marker('12'); +verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -// goTo.marker('13'); -// verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); +goTo.marker('13'); +verify.quickInfoIs("var fooVar: () => void", "fooVar comment"); -// goTo.marker('14'); -// verify.quickInfoIs("function foo(): void", "foos comment"); +goTo.marker('14'); +verify.quickInfoIs("function foo(): void", "foos comment"); -// goTo.marker('15'); -// verify.quickInfoIs("function foo2(a: number): void (+1 overload)", ""); +goTo.marker('15'); +verify.quickInfoIs("function foo2(a: number): void (+1 overload)", ""); diff --git a/tests/cases/fourslash/doesnotwork.ts b/tests/cases/fourslash/doesnotwork.ts deleted file mode 100644 index 2f415563c2153..0000000000000 --- a/tests/cases/fourslash/doesnotwork.ts +++ /dev/null @@ -1,45 +0,0 @@ -/// - -/////** This is my variable*/ -////var myVariable = 10; -//// -/////** d variable*/ -////var d = 10; -////myVariable = d; -//// -/////** foos comment*/ -////function foo() { -////} -/////** fooVar comment*/ -////var fooVar: () => void; -/////*4*/ -////foo(); -////fooVar(); -////fooVar = foo; -//// -////foo(); -////fooVar(); -////var fooVarVar = fooVar; -/////**class comment*/ -////class c { -//// /** constructor comment*/ -//// constructor() { -//// } -////} -/////**instance comment*/ -////var i = new c(); -//// -/////** interface comments*/ -////interface i1 { -////} -/////**interface instance comments*/ -////var i1_i: i1; -//// -////function foo2(a: number): void; -////function foo2(b: string): void; -////function foo2(aOrb) { -////} -////var x = foo2; - -goTo.marker('4'); -verify.completionListContains("fooVar", "var fooVar: () => void", "fooVar comment"); diff --git a/tests/webTestServer.js b/tests/webTestServer.js deleted file mode 100644 index b47da7bfe765d..0000000000000 --- a/tests/webTestServer.js +++ /dev/null @@ -1,288 +0,0 @@ -/// -"use strict"; -var http = require("http"); -var fs = require("fs"); -var path = require("path"); -var url = require("url"); -var child_process = require("child_process"); -var os = require("os"); -/// Command line processing /// -if (process.argv[2] == '--help') { - console.log('Runs a node server on port 8888 by default, looking for tests folder in the current directory\n'); - console.log('Syntax: node nodeServer.js [port] [typescriptEnlistmentDirectory] [tests] [--browser] [--verbose]\n'); - console.log('Examples: \n\tnode nodeServer.js 8888 .'); - console.log('\tnode nodeServer.js 3000 D:/src/typescript/public --verbose IE'); -} -function switchToForwardSlashes(path) { - return path.replace(/\\/g, "/").replace(/\/\//g, '/'); -} -var defaultPort = 8888; -var port = process.argv[2] || defaultPort; -var rootDir = switchToForwardSlashes(__dirname + '/../'); -var browser; -if (process.argv[3]) { - browser = process.argv[3]; - if (browser !== 'chrome' && browser !== 'IE') { - console.log('Invalid command line arguments. Got ' + browser + ' but expected chrome, IE or nothing.'); - } -} -var grep = process.argv[4]; -var verbose = false; -if (process.argv[5] == '--verbose') { - verbose = true; -} -else if (process.argv[5] && process.argv[5] !== '--verbose') { - console.log('Invalid command line arguments. Got ' + process.argv[5] + ' but expected --verbose or nothing.'); -} -/// Utils /// -function log(msg) { - if (verbose) { - console.log(msg); - } -} -// Copied from the compiler sources -function dir(path, spec, options) { - options = options || {}; - function filesInFolder(folder) { - var folder = switchToForwardSlashes(folder); - var paths = []; - // Everything after the current directory is relative - var baseDirectoryLength = process.cwd().length + 1; - try { - var files = fs.readdirSync(folder); - for (var i = 0; i < files.length; i++) { - var stat = fs.statSync(folder + "/" + files[i]); - if (options.recursive && stat.isDirectory()) { - paths = paths.concat(filesInFolder(folder + "/" + files[i])); - } - else if (stat.isFile() && (!spec || files[i].match(spec))) { - var relativePath = folder.substring(baseDirectoryLength); - paths.push(relativePath + "/" + files[i]); - } - } - } - catch (err) { - } - return paths; - } - return filesInFolder(path); -} -// fs.rmdirSync won't delete directories with files in it -function deleteFolderRecursive(path) { - if (fs.existsSync(path)) { - fs.readdirSync(path).forEach(function (file, index) { - var curPath = path + "/" + file; - if (fs.statSync(curPath).isDirectory()) { - deleteFolderRecursive(curPath); - } - else { - fs.unlinkSync(curPath); - } - }); - fs.rmdirSync(path); - } -} -; -function writeFile(path, data, opts) { - try { - fs.writeFileSync(path, data); - } - catch (e) { - // assume file was written to a directory that exists, if not, start recursively creating them as necessary - var parts = switchToForwardSlashes(path).split('/'); - for (var i = 0; i < parts.length; i++) { - var subDir = parts.slice(0, i).join('/'); - if (!fs.existsSync(subDir)) { - fs.mkdir(subDir); - } - } - fs.writeFileSync(path, data); - } -} -/// Request Handling /// -function handleResolutionRequest(filePath, res) { - var resolvedPath = path.resolve(filePath, ''); - resolvedPath = resolvedPath.substring(resolvedPath.indexOf('tests')); - resolvedPath = switchToForwardSlashes(resolvedPath); - send('success', res, resolvedPath); - return; -} -function send(result, res, contents, contentType) { - if (contentType === void 0) { contentType = "binary"; } - var responseCode = result === "success" ? 200 : result === "fail" ? 500 : result === 'unknown' ? 404 : parseInt(result); - res.writeHead(responseCode, { "Content-Type": contentType }); - res.end(contents); - return; -} -// Reads the data from a post request and passes it to the given callback -function processPost(req, res, callback) { - var queryData = ""; - if (typeof callback !== 'function') - return null; - if (req.method == 'POST') { - req.on('data', function (data) { - queryData += data; - if (queryData.length > 1e8) { - queryData = ""; - send("413", res, null); - console.log("ERROR: destroying connection"); - req.connection.destroy(); - } - }); - req.on('end', function () { - //res.post = url.parse(req.url).query; - callback(queryData); - }); - } - else { - send("405", res, null); - } -} -var RequestType; -(function (RequestType) { - RequestType[RequestType["GetFile"] = 0] = "GetFile"; - RequestType[RequestType["GetDir"] = 1] = "GetDir"; - RequestType[RequestType["ResolveFile"] = 2] = "ResolveFile"; - RequestType[RequestType["WriteFile"] = 3] = "WriteFile"; - RequestType[RequestType["DeleteFile"] = 4] = "DeleteFile"; - RequestType[RequestType["WriteDir"] = 5] = "WriteDir"; - RequestType[RequestType["DeleteDir"] = 6] = "DeleteDir"; - RequestType[RequestType["AppendFile"] = 7] = "AppendFile"; - RequestType[RequestType["Unknown"] = 8] = "Unknown"; -})(RequestType || (RequestType = {})); -function getRequestOperation(req, filename) { - if (req.method === 'GET' && req.url.indexOf('?') === -1) { - if (req.url.indexOf('.') !== -1) - return RequestType.GetFile; - else - return RequestType.GetDir; - } - else { - var queryData = url.parse(req.url, true).query; - if (req.method === 'GET' && queryData.resolve !== undefined) - return RequestType.ResolveFile; - // mocha uses ?grep= query string as equivalent to the --grep command line option used to filter tests - if (req.method === 'GET' && queryData.grep !== undefined) - return RequestType.GetFile; - if (req.method === 'POST' && queryData.action) { - var path = req.url.substr(0, req.url.lastIndexOf('?')); - var isFile = path.substring(path.lastIndexOf('/')).indexOf('.') !== -1; - switch (queryData.action.toUpperCase()) { - case 'WRITE': - return isFile ? RequestType.WriteFile : RequestType.WriteDir; - case 'DELETE': - return isFile ? RequestType.DeleteFile : RequestType.DeleteDir; - case 'APPEND': - return isFile ? RequestType.AppendFile : RequestType.Unknown; - } - } - return RequestType.Unknown; - } -} -function handleRequestOperation(req, res, operation, reqPath) { - switch (operation) { - case RequestType.GetDir: - var filesInFolder = dir(reqPath, "", { recursive: true }); - send('success', res, filesInFolder.join(',')); - break; - case RequestType.GetFile: - fs.readFile(reqPath, function (err, file) { - var ext = reqPath.substr(reqPath.lastIndexOf('.')); - var contentType = 'binary'; - if (ext === '.js') - contentType = 'text/javascript'; - else if (ext === '.css') - contentType = 'text/javascript'; - else if (ext === '.html') - contentType = 'text/html'; - err - ? send('fail', res, err.message, contentType) - : send('success', res, file, contentType); - }); - break; - case RequestType.ResolveFile: - var resolveRequest = req.url.match(/(.*)\?resolve/); - handleResolutionRequest(resolveRequest[1], res); - break; - case RequestType.WriteFile: - processPost(req, res, function (data) { - writeFile(reqPath, data, { recursive: true }); - }); - send('success', res, null); - break; - case RequestType.WriteDir: - fs.mkdirSync(reqPath); - send('success', res, null); - break; - case RequestType.DeleteFile: - if (fs.existsSync(reqPath)) { - fs.unlinkSync(reqPath); - } - send('success', res, null); - break; - case RequestType.DeleteDir: - if (fs.existsSync(reqPath)) { - fs.rmdirSync(reqPath); - } - send('success', res, null); - break; - case RequestType.AppendFile: - processPost(req, res, function (data) { - fs.appendFileSync(reqPath, data); - }); - send('success', res, null); - break; - case RequestType.Unknown: - default: - send('unknown', res, null); - break; - } -} -console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown"); -http.createServer(function (req, res) { - log(req.method + ' ' + req.url); - var uri = url.parse(req.url).pathname; - var reqPath = path.join(process.cwd(), uri); - var operation = getRequestOperation(req, reqPath); - handleRequestOperation(req, res, operation, reqPath); -}).listen(8888); -var browserPath; -if ((browser && browser === 'chrome')) { - var defaultChromePath = ""; - switch (os.platform()) { - case "win32": - case "win64": - defaultChromePath = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"; - break; - case "darwin": - defaultChromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"; - break; - case "linux": - defaultChromePath = "/opt/google/chrome/chrome"; - break; - default: - console.log("default Chrome location is unknown for platform '" + os.platform() + "'"); - break; - } - if (fs.existsSync(defaultChromePath)) { - browserPath = defaultChromePath; - } - else { - browserPath = browser; - } -} -else { - var defaultIEPath = 'C:/Program Files/Internet Explorer/iexplore.exe'; - if (fs.existsSync(defaultIEPath)) { - browserPath = defaultIEPath; - } - else { - browserPath = browser; - } -} -console.log('Using browser: ' + browserPath); -var queryString = grep ? "?grep=" + grep : ''; -child_process.spawn(browserPath, ['http://localhost:' + port + '/tests/webTestResults.html' + queryString], { - stdio: 'inherit' -}); -//# sourceMappingURL=file:///C:/Users/lizhe/Documents/github/TypeScript/tests/webTestServer.js.map \ No newline at end of file diff --git a/tests/webTestServer.js.map b/tests/webTestServer.js.map deleted file mode 100644 index 1c924a872f41d..0000000000000 --- a/tests/webTestServer.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"webTestServer.js","sourceRoot":"","sources":["file:///C:/Users/lizhe/Documents/github/TypeScript/tests/webTestServer.ts"],"names":[],"mappings":"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"} \ No newline at end of file From 15cbb0216202eec3e9fa5f04c124607d4bf8c020 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 22 Apr 2016 14:26:30 -0700 Subject: [PATCH 06/13] refactor --- src/compiler/types.ts | 2 +- src/services/utilities.ts | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 91ce1f1022fba..f40237ba47efe 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -450,7 +450,7 @@ namespace ts { modifiers?: ModifiersArray; // Array of modifiers /* @internal */ id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding - /* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files. + /* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files. /* @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) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 73ac43911b552..0230195b0ccb5 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -267,7 +267,7 @@ namespace ts { if (includeJsDocComment) { const jsDocChildren = ts.filter(current.getChildren(), isJSDocNode); for (const jsDocChild of jsDocChildren) { - let start = allowPositionInLeadingTrivia ? jsDocChild.getFullStart() : jsDocChild.getStart(sourceFile, includeJsDocComment); + const start = allowPositionInLeadingTrivia ? jsDocChild.getFullStart() : jsDocChild.getStart(sourceFile, includeJsDocComment); if (start <= position) { let end = jsDocChild.getEnd(); if (position < end || (position === end && jsDocChild.kind === SyntaxKind.EndOfFileToken)) { @@ -500,9 +500,8 @@ namespace ts { } if (node) { - let jsDocComments = node.jsDocComments; - if (jsDocComments) { - for (const jsDocComment of jsDocComments) { + if (node.jsDocComments) { + for (const jsDocComment of node.jsDocComments) { for (const tag of jsDocComment.tags) { if (tag.pos <= position && position <= tag.end) { return tag; From d568d79b495d256e93907b28c3aeec912b41594f Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 22 Apr 2016 15:19:57 -0700 Subject: [PATCH 07/13] resolve build error --- src/compiler/parser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b9662126e654c..612602f56583c 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6322,7 +6322,7 @@ namespace ts { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - const name = parseJSDocIdentifier(); + const name = parseJSDocIdentifierName(); if (!name) { parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected); return undefined; @@ -6344,7 +6344,7 @@ namespace ts { function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - let name = parseJSDocIdentifier(); + let name = parseJSDocIdentifierName(); if (!name) { let foundNameFromParentNode = false; if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { From 79bb4ba5b42d58c2f8ff8955f26f58a9ef24cddb Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Mon, 25 Apr 2016 11:56:16 -0700 Subject: [PATCH 08/13] Fix broken test --- src/services/utilities.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index bf90a023c14e1..12baca1af54f7 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -445,6 +445,10 @@ namespace ts { return false; } + if (token.kind === SyntaxKind.JsxText) { + return true; + } + //
Hello |
if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxText) { return true; @@ -455,7 +459,7 @@ namespace ts { return true; } - //
{ + //
{ // | // } < /div> if (token && token.kind === SyntaxKind.CloseBraceToken && token.parent.kind === SyntaxKind.JsxExpression) { From 81ce532cde1f4ffd88e8c507b19432712723401f Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 25 May 2016 23:05:20 -0700 Subject: [PATCH 09/13] Change how typedef tag is parsed --- src/compiler/binder.ts | 7 +- src/compiler/parser.ts | 215 ++++++++++++++++++----------------------- src/compiler/types.ts | 13 +-- 3 files changed, 103 insertions(+), 132 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 9b421ed34cb9a..377c5d3f46575 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1702,8 +1702,9 @@ namespace ts { case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: case SyntaxKind.JSDocRecordMember: - case SyntaxKind.JSDocPropertyTag: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); + case SyntaxKind.JSDocPropertyTag: + return bindJSDocProperty(node); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); @@ -2085,6 +2086,10 @@ namespace ts { : declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes); } + function bindJSDocProperty(node: JSDocPropertyTag) { + return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); + } + // reachability checks function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9c26fdeb1798d..07509d0afccbb 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -406,7 +406,7 @@ namespace ts { visitNode(cbNode, (node).name) || visitNode(cbNode, (node).type); case SyntaxKind.JSDocTypeLiteral: - return visitNodes(cbNodes, (node).members); + return visitNodes(cbNodes, (node).jsDocPropertyTags); case SyntaxKind.JSDocPropertyTag: return visitNode(cbNode, (node).typeExpression) || visitNode(cbNode, (node).name); @@ -4113,9 +4113,9 @@ namespace ts { const isAsync = !!(node.flags & NodeFlags.Async); node.name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : - isGenerator ? doInYieldContext(parseOptionalIdentifier) : - isAsync ? doInAwaitContext(parseOptionalIdentifier) : - parseOptionalIdentifier(); + isGenerator ? doInYieldContext(parseOptionalIdentifier) : + isAsync ? doInAwaitContext(parseOptionalIdentifier) : + parseOptionalIdentifier(); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false); @@ -6066,9 +6066,6 @@ namespace ts { Debug.assert(end <= content.length); let tags: NodeArray; - let currentParentJSDocTag: JSDocParentTag; - let currentParentJSDocTagEnd: number; - let result: JSDocComment; // Check for /** (JSDoc opening part) @@ -6125,10 +6122,6 @@ namespace ts { nextJSDocToken(); } - if (currentParentJSDocTag) { - finishCurrentParentTag(); - } - result = createJSDocComment(); }); @@ -6152,40 +6145,6 @@ namespace ts { } } - function finishCurrentParentTag(): void { - if (!currentParentJSDocTag) { - return; - } - - if (currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) { - const typedefTag = currentParentJSDocTag; - if (typedefTag.jsDocTypeTag) { - if (typedefTag.jsDocTypeTag.typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { - const typeTagtype = typedefTag.jsDocTypeTag.typeExpression.type; - if ((typeTagtype.name.kind !== SyntaxKind.Identifier) || - (typeTagtype.name).text !== "Object") { - typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; - } - } - else { - typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type; - } - } - if (!typedefTag.type && typedefTag.jsDocPropertyTags && typedefTag.jsDocPropertyTags.length > 0) { - const pos = typedefTag.jsDocPropertyTags[0].pos; - const end = typedefTag.jsDocPropertyTags[typedefTag.jsDocPropertyTags.length - 1].end; - const jsdocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, pos); - jsdocTypeLiteral.members = >[]; - addRange(jsdocTypeLiteral.members, typedefTag.jsDocPropertyTags); - typedefTag.type = finishNode(jsdocTypeLiteral, end); - } - } - - addTag(finishNode(currentParentJSDocTag, currentParentJSDocTagEnd)); - currentParentJSDocTag = undefined; - currentParentJSDocTagEnd = undefined; - } - function parseTag(): void { Debug.assert(token === SyntaxKind.AtToken); const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos()); @@ -6198,34 +6157,23 @@ namespace ts { } const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName); - if (!currentParentJSDocTag) { - addTag(tag); - } + addTag(tag); } function handleTag(atToken: Node, tagName: Identifier): JSDocTag { if (tagName) { switch (tagName.text) { case "param": - finishCurrentParentTag(); return handleParamTag(atToken, tagName); case "return": case "returns": - finishCurrentParentTag(); return handleReturnTag(atToken, tagName); case "template": - finishCurrentParentTag(); return handleTemplateTag(atToken, tagName); case "type": - // @typedef tag is allowed to have one @type tag, therefore seeing - // a @type tag may not indicate the end of the current parent tag. return handleTypeTag(atToken, tagName); case "typedef": - finishCurrentParentTag(); return handleTypedefTag(atToken, tagName); - case "property": - case "prop": - return handlePropertyTag(atToken, tagName); } } @@ -6251,25 +6199,6 @@ namespace ts { } } - function addToCurrentParentTag(tag: JSDocTag): void { - if (!currentParentJSDocTag) { - return; - } - switch (tag.kind) { - case SyntaxKind.JSDocPropertyTag: - if (!currentParentJSDocTag.jsDocPropertyTags) { - currentParentJSDocTag.jsDocPropertyTags = >[]; - } - currentParentJSDocTag.jsDocPropertyTags.push(tag); - break; - case SyntaxKind.JSDocTypeTag: - if (!currentParentJSDocTag.jsDocTypeTag) { - currentParentJSDocTag.jsDocTypeTag = tag; - } - break; - } - } - function tryParseTypeExpression(): JSDocTypeExpression { if (token !== SyntaxKind.OpenBraceToken) { return undefined; @@ -6345,32 +6274,14 @@ namespace ts { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text); } - let result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); + const result = createNode(SyntaxKind.JSDocTypeTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; result.typeExpression = tryParseTypeExpression(); - result = finishNode(result); - - if (currentParentJSDocTag && currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) { - const parentTag = currentParentJSDocTag; - if (!parentTag.typeExpression && !parentTag.jsDocTypeTag) { - parentTag.jsDocTypeTag = result; - currentParentJSDocTagEnd = scanner.getStartPos(); - return result; - } - } - // If this @type tag is not part of the current parent tag, then - // it denotes the end of the current parent tag. - finishCurrentParentTag(); - return result; + return finishNode(result); } function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { - if (!currentParentJSDocTag) { - parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_cannot_be_used_independently_as_a_top_level_JSDoc_tag, tagName.text); - return undefined; - } - const typeExpression = tryParseTypeExpression(); skipWhitespace(); const name = parseJSDocIdentifierName(); @@ -6379,17 +6290,12 @@ namespace ts { return undefined; } - let result = createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); + const result = createNode(SyntaxKind.JSDocPropertyTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; result.name = name; result.typeExpression = typeExpression; - result.type = typeExpression.type; - result = finishNode(result); - - addToCurrentParentTag(result); - currentParentJSDocTagEnd = scanner.getStartPos(); - return undefined; + return finishNode(result); } function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { @@ -6413,32 +6319,99 @@ namespace ts { } } - const result = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); - result.atToken = atToken; - result.tagName = tagName; - result.name = name; - result.typeExpression = typeExpression; + const typedefTag = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); + typedefTag.atToken = atToken; + typedefTag.tagName = tagName; + typedefTag.name = name; + typedefTag.typeExpression = typeExpression; - if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { - const jsDocTypeReference = typeExpression.type; - if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { - const name = jsDocTypeReference.name; - if (name.text === "Object") { - currentParentJSDocTag = result; + if (typeExpression) { + if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { + const jsDocTypeReference = typeExpression.type; + if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { + const name = jsDocTypeReference.name; + if (name.text === "Object") { + typedefTag.type = scanChildTags(); + } } } + if (!typedefTag.type) { + typedefTag.type = typeExpression.type; + } + } + else { + typedefTag.type = scanChildTags(); } - else if (!typeExpression) { - currentParentJSDocTag = result; + + return finishNode(typedefTag); + + function scanChildTags(): JSDocTypeLiteral { + const jsDocTypeLiteral = createNode(SyntaxKind.JSDocTypeLiteral, scanner.getStartPos()); + let resumePos = scanner.getStartPos(); + let canParseTag = true; + let seenAsterisk = false; + let parentTagTerminated = false; + + while (token !== SyntaxKind.EndOfFileToken && !parentTagTerminated) { + nextJSDocToken(); + switch (token) { + case SyntaxKind.AtToken: + if (canParseTag) { + parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral); + } + seenAsterisk = false; + break; + case SyntaxKind.NewLineTrivia: + resumePos = scanner.getStartPos() - 1; + canParseTag = true; + seenAsterisk = false; + break; + case SyntaxKind.AsteriskToken: + if (seenAsterisk) { + canParseTag = false; + } + seenAsterisk = true; + break; + case SyntaxKind.Identifier: + canParseTag = false; + case SyntaxKind.EndOfFileToken: + break; + } + } + scanner.setTextPos(resumePos); + return finishNode(jsDocTypeLiteral); } + } + + function tryParseChildTag(parentTag: JSDocTypeLiteral): boolean { + Debug.assert(token === SyntaxKind.AtToken); + const atToken = createNode(SyntaxKind.AtToken, scanner.getStartPos()); + atToken.end = scanner.getTextPos(); + nextJSDocToken(); - if (!currentParentJSDocTag) { - result.type = result.typeExpression.type; - return finishNode(result); + const tagName = parseJSDocIdentifierName(); + if (!tagName) { + return false; } - currentParentJSDocTagEnd = scanner.getStartPos(); - return undefined; + switch (tagName.text) { + case "type": + if (parentTag.jsDocTypeTag) { + // already has a @type tag, terminate the parent tag now. + return false; + } + parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName); + return true; + case "prop": + case "property": + if (!parentTag.jsDocPropertyTags) { + parentTag.jsDocPropertyTags = >[]; + } + const propertyTag = handlePropertyTag(atToken, tagName); + parentTag.jsDocPropertyTags.push(propertyTag); + return true; + } + return false; } function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b472aa92e6229..1b9af02a8d50a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1517,29 +1517,22 @@ namespace ts { } // @kind(SyntaxKind.JSDocTypedefTag) - export interface JSDocTypedefTag extends JSDocTag, Declaration, JSDocParentTag { + export interface JSDocTypedefTag extends JSDocTag, Declaration { name: Identifier; typeExpression?: JSDocTypeExpression; type: JSDocType; } - export interface JSDocParentTag extends JSDocTag { - jsDocPropertyTags?: NodeArray; - jsDocTypeTag?: JSDocTypeTag; - } - // @kind(SyntaxKind.JSDocPropertyTag) export interface JSDocPropertyTag extends JSDocTag, TypeElement { name: Identifier; typeExpression: JSDocTypeExpression; - // Add a "type" property here to make the interface compatible - // with the "VariableLikeDeclaration" definition - type: TypeNode; } // @kind(SyntaxKind.JSDocTypeLiteral) export interface JSDocTypeLiteral extends JSDocType { - members: NodeArray; + jsDocPropertyTags?: NodeArray; + jsDocTypeTag?: JSDocTypeTag; } // @kind(SyntaxKind.JSDocParameterTag) From 18ee4b0a1ee1e326b5bbcdc0104466ac9c3d13d2 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Mon, 30 May 2016 22:11:43 -0700 Subject: [PATCH 10/13] cr feedback --- src/compiler/binder.ts | 12 ++++++++++++ src/compiler/checker.ts | 14 ++++++++++++-- src/compiler/parser.ts | 29 ++++++----------------------- src/compiler/types.ts | 8 +++++--- src/services/navigationBar.ts | 6 ++++++ src/services/services.ts | 11 +---------- 6 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 756be48ed9462..3d3a86f20fd60 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -267,6 +267,18 @@ namespace ts { let functionType = node.parent; let index = indexOf(functionType.parameters, node); return "p" + index; + 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 (nameIdentifier.kind === SyntaxKind.Identifier) { + nameFromParentNode = (nameIdentifier).text; + } + } + } + return nameFromParentNode; } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 42af34c065992..e8b23822593f6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3586,11 +3586,21 @@ namespace ts { return unknownType; } + let type: Type; let declaration: JSDocTypedefTag | TypeAliasDeclaration = getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag); - if (!declaration) { + if (declaration) { + if (declaration.jsDocTypeLiteral) { + type = getTypeFromTypeNode(declaration.jsDocTypeLiteral); + } + else { + type = getTypeFromTypeNode(declaration.typeExpression.type); + } + } + else { declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration); + type = getTypeFromTypeNode(declaration.type); } - let type = getTypeFromTypeNode(declaration.type); + if (popTypeResolution()) { links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); if (links.typeParameters) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 07509d0afccbb..c61b4b836ea40 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -404,7 +404,7 @@ namespace ts { case SyntaxKind.JSDocTypedefTag: return visitNode(cbNode, (node).typeExpression) || visitNode(cbNode, (node).name) || - visitNode(cbNode, (node).type); + visitNode(cbNode, (node).jsDocTypeLiteral); case SyntaxKind.JSDocTypeLiteral: return visitNodes(cbNodes, (node).jsDocPropertyTags); case SyntaxKind.JSDocPropertyTag: @@ -6301,28 +6301,11 @@ namespace ts { function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); - let name = parseJSDocIdentifierName(); - if (!name) { - let foundNameFromParentNode = false; - if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { - if ((parentNode).declarationList.declarations.length > 0) { - const nameFromParentNode = (parentNode).declarationList.declarations[0].name; - if (nameFromParentNode.kind === SyntaxKind.Identifier) { - foundNameFromParentNode = true; - name = nameFromParentNode; - } - } - } - if (!foundNameFromParentNode) { - parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); - return undefined; - } - } const typedefTag = createNode(SyntaxKind.JSDocTypedefTag, atToken.pos); typedefTag.atToken = atToken; typedefTag.tagName = tagName; - typedefTag.name = name; + typedefTag.name = parseJSDocIdentifierName(); typedefTag.typeExpression = typeExpression; if (typeExpression) { @@ -6331,16 +6314,16 @@ namespace ts { if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) { const name = jsDocTypeReference.name; if (name.text === "Object") { - typedefTag.type = scanChildTags(); + typedefTag.jsDocTypeLiteral = scanChildTags(); } } } - if (!typedefTag.type) { - typedefTag.type = typeExpression.type; + if (!typedefTag.jsDocTypeLiteral) { + typedefTag.jsDocTypeLiteral = typeExpression.type; } } else { - typedefTag.type = scanChildTags(); + typedefTag.jsDocTypeLiteral = scanChildTags(); } return finishNode(typedefTag); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1b9af02a8d50a..f23b52b35d7a0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -376,7 +376,9 @@ namespace ts { LastBinaryOperator = CaretEqualsToken, FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, - LastJSDocNode = JSDocTypeLiteral + LastJSDocNode = JSDocTypeLiteral, + FirstJSDocTagNode = JSDocComment, + LastJSDocTagNode = JSDocTypeLiteral } export const enum NodeFlags { @@ -1518,9 +1520,9 @@ namespace ts { // @kind(SyntaxKind.JSDocTypedefTag) export interface JSDocTypedefTag extends JSDocTag, Declaration { - name: Identifier; + name?: Identifier; typeExpression?: JSDocTypeExpression; - type: JSDocType; + jsDocTypeLiteral?: JSDocTypeLiteral; } // @kind(SyntaxKind.JSDocPropertyTag) diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 0cb431de668ab..5515356a259d2 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -653,6 +653,12 @@ namespace ts.NavigationBar { topItem.childItems.push(newItem); } + if (node.jsDocComments && node.jsDocComments.length > 0) { + for (const jsDocComment of node.jsDocComments) { + visitNode(jsDocComment); + } + } + // Add a level if traversing into a container if (newItem && (isFunctionLike(node) || isClassLike(node))) { const lastTop = topItem; diff --git a/src/services/services.ts b/src/services/services.ts index 8fef753f2e86c..90740b257c6b5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -276,16 +276,7 @@ namespace ts { scanner.setText((sourceFile || this.getSourceFile()).text); children = []; let pos = this.pos; - const useJSDocScanner = - this.kind === SyntaxKind.JSDocComment || - this.kind === SyntaxKind.JSDocParameterTag || - this.kind === SyntaxKind.JSDocTag || - this.kind === SyntaxKind.JSDocParameterTag || - this.kind === SyntaxKind.JSDocReturnTag || - this.kind === SyntaxKind.JSDocTypeTag || - this.kind === SyntaxKind.JSDocTemplateTag || - this.kind === SyntaxKind.JSDocTypedefTag || - this.kind === SyntaxKind.JSDocPropertyTag; + const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode; const processNode = (node: Node) => { if (pos < node.pos) { pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); From 59b188d4cae7c9d0c4d39a6ec839506c1170a519 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Tue, 31 May 2016 02:05:26 -0700 Subject: [PATCH 11/13] Add navigationTo test for jsdoc typedef --- src/compiler/parser.ts | 7 ++++++ src/harness/harness.ts | 5 +++- src/services/navigationBar.ts | 23 ++++++++++++++++++- .../server/jsdocTypedefTagNavigateTo.ts | 16 +++++++++++++ tests/cases/unittests/jsDocParsing.ts | 3 ++- 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c61b4b836ea40..20f3d927e7171 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -672,6 +672,13 @@ namespace ts { const saveParent = parent; parent = n; forEachChild(n, visitNode); + if (n.jsDocComments) { + for (const jsDocComment of n.jsDocComments) { + jsDocComment.parent = n; + parent = jsDocComment; + forEachChild(jsDocComment, visitNode); + } + } parent = saveParent; } } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index e1c90cee80cdd..5fe5b84ac9148 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -223,7 +223,10 @@ namespace Utils { // For some markers in SyntaxKind, we should print its original syntax name instead of // the marker name in tests. - if (k === (ts).SyntaxKind.FirstJSDocNode || k === (ts).SyntaxKind.LastJSDocNode) { + if (k === (ts).SyntaxKind.FirstJSDocNode || + k === (ts).SyntaxKind.LastJSDocNode || + k === (ts).SyntaxKind.FirstJSDocTagNode || + k === (ts).SyntaxKind.LastJSDocTagNode) { for (const kindName in (ts).SyntaxKind) { if ((ts).SyntaxKind[kindName] === k) { return kindName; diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 5515356a259d2..3adc5563d7138 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -738,6 +738,27 @@ namespace ts.NavigationBar { } const declName = declarationNameToString(decl.name); return getNavBarItem(declName, ScriptElementKind.constElement, [getNodeSpan(node)]); + case SyntaxKind.JSDocTypedefTag: + if ((node).name) { + return getNavBarItem( + (node).name.text, + ScriptElementKind.typeElement, + [getNodeSpan(node)]); + } + else { + const parentNode = node.parent && node.parent.parent; + if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) { + if ((parentNode).declarationList.declarations.length > 0) { + const nameIdentifier = (parentNode).declarationList.declarations[0].name; + if (nameIdentifier.kind === SyntaxKind.Identifier) { + return getNavBarItem( + (nameIdentifier).text, + ScriptElementKind.typeElement, + [getNodeSpan(node)]); + } + } + } + } default: return undefined; } @@ -808,7 +829,7 @@ namespace ts.NavigationBar { } function getNodeSpan(node: Node) { - return node.kind === SyntaxKind.SourceFile + return node.kind === SyntaxKind.SourceFile ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) : createTextSpanFromBounds(node.getStart(), node.getEnd()); } diff --git a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts new file mode 100644 index 0000000000000..1d1c1ac27caa8 --- /dev/null +++ b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts @@ -0,0 +1,16 @@ +/// + +// @allowNonTsExtensions: true +// @Filename: jsDocTypedef_form2.js +//// +//// /** @typedef {(string | number)} NumberLike */ +//// /** @typedef {(string | number | string[])} */ +//// var NumberLike2; +//// +//// /** @type {/*1*/NumberLike} */ +//// var numberLike; + +verify.navigationBarContains("NumberLike", "type"); +verify.navigationBarContains("NumberLike2", "type"); +verify.navigationBarContains("NumberLike2", "var"); +verify.navigationBarContains("numberLike", "var"); \ No newline at end of file diff --git a/tests/cases/unittests/jsDocParsing.ts b/tests/cases/unittests/jsDocParsing.ts index 8afad08909c0f..fb75b4d494071 100644 --- a/tests/cases/unittests/jsDocParsing.ts +++ b/tests/cases/unittests/jsDocParsing.ts @@ -1004,7 +1004,8 @@ namespace ts { if (result !== expected) { // Turn on a human-readable diff if (typeof require !== "undefined") { - require("chai").config.showDiff = true; + const chai = require("chai"); + chai.config.showDiff = true; chai.expect(JSON.parse(result)).equal(JSON.parse(expected)); } else { From e93f9df95506a8cf3daa99b18a05331960c9f726 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 31 May 2016 10:48:25 -0700 Subject: [PATCH 12/13] Fix broken test --- .../server/jsdocTypedefTagNavigateTo.ts | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts index 1d1c1ac27caa8..77cd75aa44c77 100644 --- a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts +++ b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts @@ -10,7 +10,21 @@ //// /** @type {/*1*/NumberLike} */ //// var numberLike; -verify.navigationBarContains("NumberLike", "type"); -verify.navigationBarContains("NumberLike2", "type"); -verify.navigationBarContains("NumberLike2", "var"); -verify.navigationBarContains("numberLike", "var"); \ No newline at end of file +verify.navigationBar([ + { + "text": "NumberLike", + "kind": "type" + }, + { + "text": "NumberLike2", + "kind": "type" + }, + { + "text": "NumberLike2", + "kind": "var" + }, + { + "text": "numberLike", + "kind": "var" + } +]); \ No newline at end of file From eb0f035c78219ed920052094351326c5b35e1fe3 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Tue, 31 May 2016 16:08:12 -0700 Subject: [PATCH 13/13] Remove unused parameter --- src/compiler/parser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 20f3d927e7171..6f042627c6ba4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2725,7 +2725,7 @@ namespace ts { // 1) async[no LineTerminator here]AsyncArrowBindingIdentifier[?Yield][no LineTerminator here]=>AsyncConciseBody[?In] // 2) CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await][no LineTerminator here]=>AsyncConciseBody[?In] // Production (1) of AsyncArrowFunctionExpression is parsed in "tryParseAsyncSimpleArrowFunctionExpression". - // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". + // And production (2) is parsed in "tryParseParenthesizedArrowFunctionExpression". // // If we do successfully parse arrow-function, we must *not* recurse for productions 1, 2 or 3. An ArrowFunction is // not a LeftHandSideExpression, nor does it start a ConditionalExpression. So we are done @@ -6050,7 +6050,7 @@ namespace ts { const saveParseDiagnosticsLength = parseDiagnostics.length; const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; - const comment = parseJSDocCommentWorker(start, length, parent); + const comment = parseJSDocCommentWorker(start, length); if (comment) { comment.parent = parent; } @@ -6062,7 +6062,7 @@ namespace ts { return comment; } - export function parseJSDocCommentWorker(start: number, length: number, parentNode?: Node): JSDocComment { + export function parseJSDocCommentWorker(start: number, length: number): JSDocComment { const content = sourceText; start = start || 0; const end = length === undefined ? content.length : start + length;