diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3bccf6b4a9b..49434e80aba 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -268,7 +268,7 @@ namespace ts { Debug.assert(node.parent.kind === SyntaxKind.JSDocFunctionType); let functionType = node.parent; let index = indexOf(functionType.parameters, node); - return "p" + index; + return "arg" + index; case SyntaxKind.JSDocTypedefTag: const parentNode = node.parent && node.parent.parent; let nameFromParentNode: string; @@ -540,9 +540,7 @@ namespace ts { // because the scope of JsDocComment should not be affected by whether the current node is a // container or not. if (isInJavaScriptFile(node) && node.jsDocComments) { - for (const jsDocComment of node.jsDocComments) { - bind(jsDocComment); - } + forEach(node.jsDocComments, bind); } if (checkUnreachable(node)) { forEachChild(node, bind); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8b1b70b0fa1..defee3a2bf6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5653,12 +5653,13 @@ namespace ts { case SyntaxKind.JSDocThisType: case SyntaxKind.JSDocOptionalType: return getTypeFromTypeNode((node).type); + case SyntaxKind.JSDocRecordType: + return getTypeFromTypeNode((node as JSDocRecordType).literal); case SyntaxKind.FunctionType: case SyntaxKind.ConstructorType: case SyntaxKind.TypeLiteral: case SyntaxKind.JSDocTypeLiteral: case SyntaxKind.JSDocFunctionType: - case SyntaxKind.JSDocRecordType: return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments); // This function assumes that an identifier or qualified name is a type expression // Callers should first ensure this by calling isTypeNode diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 6e6b372b1c1..1aec63bc588 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -379,7 +379,7 @@ namespace ts { case SyntaxKind.JSDocNullableType: return visitNode(cbNode, (node).type); case SyntaxKind.JSDocRecordType: - return visitNodes(cbNodes, (node).members); + return visitNode(cbNode, (node).literal); case SyntaxKind.JSDocTypeReference: return visitNode(cbNode, (node).name) || visitNodes(cbNodes, (node).typeArguments); @@ -398,7 +398,7 @@ namespace ts { return visitNode(cbNode, (node).name) || visitNode(cbNode, (node).type); case SyntaxKind.JSDocComment: - return visitNodes(cbNodes, (node).tags); + return visitNodes(cbNodes, (node).tags); case SyntaxKind.JSDocParameterTag: return visitNode(cbNode, (node).preParameterName) || visitNode(cbNode, (node).typeExpression) || @@ -453,10 +453,10 @@ namespace ts { /* @internal */ export function parseIsolatedJSDocComment(content: string, start?: number, length?: number) { const result = Parser.JSDocParser.parseIsolatedJSDocComment(content, start, length); - if (result && result.jsDocComment) { + if (result && result.jsDoc) { // because the jsDocComment was parsed out of the source file, it might // not be covered by the fixupParentReferences. - Parser.fixupParentReferences(result.jsDocComment); + Parser.fixupParentReferences(result.jsDoc); } return result; @@ -655,20 +655,18 @@ namespace ts { function addJSDocComment(node: T): T { - if (contextFlags & NodeFlags.JavaScriptFile) { - const comments = getLeadingCommentRangesOfNode(node, sourceFile); - if (comments) { - for (const comment of comments) { - const jsDocComment = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos); - if (!jsDocComment) { - continue; - } - - if (!node.jsDocComments) { - node.jsDocComments = []; - } - node.jsDocComments.push(jsDocComment); + const comments = getJsDocCommentsFromText(node, sourceFile.text); + if (comments) { + for (const comment of comments) { + const jsDoc = JSDocParser.parseJSDocComment(node, comment.pos, comment.end - comment.pos); + if (!jsDoc) { + continue; } + + if (!node.jsDocComments) { + node.jsDocComments = []; + } + node.jsDocComments.push(jsDoc); } } @@ -2204,7 +2202,7 @@ namespace ts { } fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); parseTypeMemberSemicolon(); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function isIndexSignature(): boolean { @@ -2294,7 +2292,7 @@ namespace ts { // [Yield] nor [Await] fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, method); parseTypeMemberSemicolon(); - return finishNode(method); + return addJSDocComment(finishNode(method)); } else { const property = createNode(SyntaxKind.PropertySignature, fullStart); @@ -2311,7 +2309,7 @@ namespace ts { } parseTypeMemberSemicolon(); - return finishNode(property); + return addJSDocComment(finishNode(property)); } } @@ -2898,7 +2896,7 @@ namespace ts { node.equalsGreaterThanToken = parseExpectedToken(SyntaxKind.EqualsGreaterThanToken, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, "=>"); node.body = parseArrowFunctionExpressionBody(/*isAsync*/ !!asyncModifier); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function tryParseParenthesizedArrowFunctionExpression(): Expression { @@ -2931,7 +2929,7 @@ namespace ts { ? parseArrowFunctionExpressionBody(isAsync) : parseIdentifier(); - return finishNode(arrowFunction); + return addJSDocComment(finishNode(arrowFunction)); } // True -> We definitely expect a parenthesized arrow function here. @@ -4114,7 +4112,7 @@ namespace ts { function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): AccessorDeclaration { if (parseContextualModifier(SyntaxKind.GetKeyword)) { - return addJSDocComment(parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers)); + return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers); } else if (parseContextualModifier(SyntaxKind.SetKeyword)) { return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, decorators, modifiers); @@ -4997,7 +4995,7 @@ namespace ts { : doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseNonParameterInitializer); parseSemicolon(); - return finishNode(property); + return addJSDocComment(finishNode(property)); } function parsePropertyOrMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ClassElement { @@ -5026,7 +5024,7 @@ namespace ts { node.name = parsePropertyName(); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function isClassMemberModifier(idToken: SyntaxKind) { @@ -5264,7 +5262,7 @@ namespace ts { node.members = createMissingList(); } - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseNameOfClassDeclarationOrExpression(): Identifier { @@ -5332,7 +5330,7 @@ namespace ts { node.typeParameters = parseTypeParameters(); node.heritageClauses = parseHeritageClauses(/*isClassHeritageClause*/ false); node.members = parseObjectTypeMembers(); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseTypeAliasDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): TypeAliasDeclaration { @@ -5356,7 +5354,7 @@ namespace ts { const node = createNode(SyntaxKind.EnumMember, scanner.getStartPos()); node.name = parsePropertyName(); node.initializer = allowInAnd(parseNonParameterInitializer); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseEnumDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): EnumDeclaration { @@ -5372,7 +5370,7 @@ namespace ts { else { node.members = createMissingList(); } - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseModuleBlock(): ModuleBlock { @@ -5399,7 +5397,7 @@ namespace ts { node.body = parseOptional(SyntaxKind.DotToken) ? parseModuleOrNamespaceDeclaration(getNodePos(), /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) : parseModuleBlock(); - return finishNode(node); + return addJSDocComment(finishNode(node)); } function parseAmbientExternalModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ModuleDeclaration { @@ -5488,7 +5486,7 @@ namespace ts { parseExpected(SyntaxKind.EqualsToken); importEqualsDeclaration.moduleReference = parseModuleReference(); parseSemicolon(); - return finishNode(importEqualsDeclaration); + return addJSDocComment(finishNode(importEqualsDeclaration)); } } @@ -5809,6 +5807,7 @@ namespace ts { export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number) { initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); + sourceFile = createSourceFile("file.js", ScriptTarget.Latest, ScriptKind.JS); scanner.setText(content, start, length); currentToken = scanner.scan(); const jsDocTypeExpression = parseJSDocTypeExpression(); @@ -6027,22 +6026,7 @@ namespace ts { function parseJSDocRecordType(): JSDocRecordType { const result = createNode(SyntaxKind.JSDocRecordType); - nextToken(); - result.members = parseDelimitedList(ParsingContext.JSDocRecordMembers, parseJSDocRecordMember); - checkForTrailingComma(result.members); - parseExpected(SyntaxKind.CloseBraceToken); - return finishNode(result); - } - - function parseJSDocRecordMember(): JSDocRecordMember { - const result = createNode(SyntaxKind.JSDocRecordMember); - result.name = parseSimplePropertyName(); - - if (token() === SyntaxKind.ColonToken) { - nextToken(); - result.type = parseJSDocType(); - } - + result.literal = parseTypeLiteral(); return finishNode(result); } @@ -6140,14 +6124,14 @@ namespace ts { export function parseIsolatedJSDocComment(content: string, start: number, length: number) { initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS); sourceFile = { languageVariant: LanguageVariant.Standard, text: content }; - const jsDocComment = parseJSDocCommentWorker(start, length); + const jsDoc = parseJSDocCommentWorker(start, length); const diagnostics = parseDiagnostics; clearState(); - return jsDocComment ? { jsDocComment, diagnostics } : undefined; + return jsDoc ? { jsDoc, diagnostics } : undefined; } - export function parseJSDocComment(parent: Node, start: number, length: number): JSDocComment { + export function parseJSDocComment(parent: Node, start: number, length: number): JSDoc { const saveToken = currentToken; const saveParseDiagnosticsLength = parseDiagnostics.length; const saveParseErrorBeforeNextFinishedNode = parseErrorBeforeNextFinishedNode; @@ -6164,7 +6148,13 @@ namespace ts { return comment; } - export function parseJSDocCommentWorker(start: number, length: number): JSDocComment { + const enum JSDocState { + BeginningOfLine, + SawAsterisk, + SavingComments, + } + + export function parseJSDocCommentWorker(start: number, length: number): JSDoc { const content = sourceText; start = start || 0; const end = length === undefined ? content.length : start + length; @@ -6175,76 +6165,134 @@ namespace ts { Debug.assert(end <= content.length); let tags: NodeArray; - let result: JSDocComment; + const comments: string[] = []; + let result: JSDoc; // Check for /** (JSDoc opening part) - if (content.charCodeAt(start) === CharacterCodes.slash && - content.charCodeAt(start + 1) === CharacterCodes.asterisk && - content.charCodeAt(start + 2) === CharacterCodes.asterisk && - content.charCodeAt(start + 3) !== CharacterCodes.asterisk) { + if (!isJsDocStart(content, start)) { + return result; + } + // + 3 for leading /**, - 5 in total for /** */ + scanner.scanRange(start + 3, length - 5, () => { + // Initially we can parse out a tag. We also have seen a starting asterisk. + // This is so that /** * @type */ doesn't parse. + let advanceToken = true; + let state = JSDocState.SawAsterisk; + let margin: number | undefined = undefined; + // + 4 for leading '/** ' + let indent = start - Math.max(content.lastIndexOf("\n", start), 0) + 4; + function pushComment(text: string) { + if (!margin) { + margin = indent; + } + comments.push(text); + indent += text.length; + } - // + 3 for leading /**, - 5 in total for /** */ - scanner.scanRange(start + 3, length - 5, () => { - // Initially we can parse out a tag. We also have seen a starting asterisk. - // This is so that /** * @type */ doesn't parse. - let canParseTag = true; - let seenAsterisk = true; - + nextJSDocToken(); + while (token() === SyntaxKind.WhitespaceTrivia) { nextJSDocToken(); - while (token() !== SyntaxKind.EndOfFileToken) { - switch (token()) { - case SyntaxKind.AtToken: - if (canParseTag) { - parseTag(); - } - // This will take us to the end of the line, so it's OK to parse a tag on the next pass through the loop - seenAsterisk = false; - break; - - case SyntaxKind.NewLineTrivia: - // After a line break, we can parse a tag, and we haven't seen an asterisk on the next line yet - canParseTag = true; - seenAsterisk = false; - break; - - case SyntaxKind.AsteriskToken: - if (seenAsterisk) { - // If we've already seen an asterisk, then we can no longer parse a tag on this line - canParseTag = false; - } + } + if (token() === SyntaxKind.NewLineTrivia) { + state = JSDocState.BeginningOfLine; + nextJSDocToken(); + } + while (token() !== SyntaxKind.EndOfFileToken) { + switch (token()) { + case SyntaxKind.AtToken: + if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) { + removeTrailingNewlines(comments); + parseTag(indent); + // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. + // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning + // for malformed examples like `/** @param {string} x @returns {number} the length */` + state = JSDocState.BeginningOfLine; + advanceToken = false; + margin = undefined; + indent++; + } + else { + pushComment(scanner.getTokenText()); + } + break; + case SyntaxKind.NewLineTrivia: + comments.push(scanner.getTokenText()); + state = JSDocState.BeginningOfLine; + indent = 0; + break; + case SyntaxKind.AsteriskToken: + const asterisk = scanner.getTokenText(); + if (state === JSDocState.SawAsterisk) { + // If we've already seen an asterisk, then we can no longer parse a tag on this line + state = JSDocState.SavingComments; + pushComment(asterisk); + } + else { // Ignore the first asterisk on a line - seenAsterisk = true; - break; - - case SyntaxKind.Identifier: - // Anything else is doc comment text. We can't do anything with it. Because it - // wasn't a tag, we can no longer parse a tag on this line until we hit the next - // line break. - canParseTag = false; - break; - - case SyntaxKind.EndOfFileToken: - break; - } - + state = JSDocState.SawAsterisk; + indent += asterisk.length; + } + break; + case SyntaxKind.Identifier: + // Anything else is doc comment text. We just save it. Because it + // wasn't a tag, we can no longer parse a tag on this line until we hit the next + // line break. + pushComment(scanner.getTokenText()); + state = JSDocState.SavingComments; + break; + case SyntaxKind.WhitespaceTrivia: + // only collect whitespace if we're already saving comments or have just crossed the comment indent margin + const whitespace = scanner.getTokenText(); + if (state === JSDocState.SavingComments || margin !== undefined && indent + whitespace.length > margin) { + comments.push(whitespace.slice(margin - indent - 1)); + } + indent += whitespace.length; + break; + case SyntaxKind.EndOfFileToken: + break; + default: + pushComment(scanner.getTokenText()); + break; + } + if (advanceToken) { nextJSDocToken(); } + else { + advanceToken = true; + } + } + removeLeadingNewlines(comments); + removeTrailingNewlines(comments); + result = createJSDocComment(); - result = createJSDocComment(); - - }); - } + }); return result; - function createJSDocComment(): JSDocComment { - if (!tags) { - return undefined; + function removeLeadingNewlines(comments: string[]) { + while (comments.length && (comments[0] === "\n" || comments[0] === "\r")) { + comments.shift(); } + } - const result = createNode(SyntaxKind.JSDocComment, start); + function removeTrailingNewlines(comments: string[]) { + while (comments.length && (comments[comments.length - 1] === "\n" || comments[comments.length - 1] === "\r")) { + comments.pop(); + } + } + + function isJsDocStart(content: string, start: number) { + return content.charCodeAt(start) === CharacterCodes.slash && + content.charCodeAt(start + 1) === CharacterCodes.asterisk && + content.charCodeAt(start + 2) === CharacterCodes.asterisk && + content.charCodeAt(start + 3) !== CharacterCodes.asterisk; + } + + function createJSDocComment(): JSDoc { + const result = createNode(SyntaxKind.JSDocComment, start); result.tags = tags; + result.comment = comments.length ? comments.join("") : undefined; return finishNode(result, end); } @@ -6254,78 +6302,154 @@ namespace ts { } } - function parseTag(): void { + function parseTag(indent: number) { Debug.assert(token() === SyntaxKind.AtToken); const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos()); atToken.end = scanner.getTextPos(); nextJSDocToken(); const tagName = parseJSDocIdentifierName(); + skipWhitespace(); if (!tagName) { return; } - const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName); - addTag(tag); - } - - function handleTag(atToken: Node, tagName: Identifier): JSDocTag { + let tag: JSDocTag; if (tagName) { switch (tagName.text) { case "param": - return handleParamTag(atToken, tagName); + tag = parseParamTag(atToken, tagName); + break; case "return": case "returns": - return handleReturnTag(atToken, tagName); + tag = parseReturnTag(atToken, tagName); + break; case "template": - return handleTemplateTag(atToken, tagName); + tag = parseTemplateTag(atToken, tagName); + break; case "type": - return handleTypeTag(atToken, tagName); + tag = parseTypeTag(atToken, tagName); + break; case "typedef": - return handleTypedefTag(atToken, tagName); + tag = parseTypedefTag(atToken, tagName); + break; + default: + tag = parseUnknownTag(atToken, tagName); + break; } } + else { + tag = parseUnknownTag(atToken, tagName); + } - return undefined; + if (!tag) { + // a badly malformed tag should not be added to the list of tags + return; + } + addTag(tag, parseTagComments(indent + tag.end - tag.pos)); } - function handleUnknownTag(atToken: Node, tagName: Identifier) { + function parseTagComments(indent: number) { + const comments: string[] = []; + let state = JSDocState.SawAsterisk; + let margin: number | undefined; + function pushComment(text: string) { + if (!margin) { + margin = indent; + } + comments.push(text); + indent += text.length; + } + while (token() !== SyntaxKind.AtToken && token() !== SyntaxKind.EndOfFileToken) { + switch (token()) { + case SyntaxKind.NewLineTrivia: + if (state >= JSDocState.SawAsterisk) { + state = JSDocState.BeginningOfLine; + comments.push(scanner.getTokenText()); + } + indent = 0; + break; + case SyntaxKind.AtToken: + // Done + break; + case SyntaxKind.WhitespaceTrivia: + if (state === JSDocState.SavingComments) { + pushComment(scanner.getTokenText()); + } + else { + const whitespace = scanner.getTokenText(); + // if the whitespace crosses the margin, take only the whitespace that passes the margin + if (margin !== undefined && indent + whitespace.length > margin) { + comments.push(whitespace.slice(margin - indent - 1)); + } + indent += whitespace.length; + } + break; + case SyntaxKind.AsteriskToken: + if (state === JSDocState.BeginningOfLine) { + // leading asterisks start recording on the *next* (non-whitespace) token + state = JSDocState.SawAsterisk; + indent += scanner.getTokenText().length; + break; + } + // FALLTHROUGH otherwise to record the * as a comment + default: + state = JSDocState.SavingComments; // leading identifiers start recording as well + pushComment(scanner.getTokenText()); + break; + } + if (token() === SyntaxKind.AtToken) { + // Done + break; + } + nextJSDocToken(); + } + + removeLeadingNewlines(comments); + removeTrailingNewlines(comments); + return comments; + } + + function parseUnknownTag(atToken: Node, tagName: Identifier) { const result = createNode(SyntaxKind.JSDocTag, atToken.pos); result.atToken = atToken; result.tagName = tagName; return finishNode(result); } - function addTag(tag: JSDocTag): void { - if (tag) { - if (!tags) { - tags = createNodeArray([tag], tag.pos); - } - else { - tags.push(tag); - } - tags.end = tag.end; + function addTag(tag: JSDocTag, comments: string[]): void { + tag.comment = comments.join(""); + + if (!tags) { + tags = createNodeArray([tag], tag.pos); } + else { + tags.push(tag); + } + tags.end = tag.end; } function tryParseTypeExpression(): JSDocTypeExpression { - if (token() !== SyntaxKind.OpenBraceToken) { - return undefined; - } + return tryParse(() => { + skipWhitespace(); + if (token() !== SyntaxKind.OpenBraceToken) { + return undefined; + } - const typeExpression = parseJSDocTypeExpression(); - return typeExpression; + return parseJSDocTypeExpression(); + }); } - function handleParamTag(atToken: Node, tagName: Identifier) { + function parseParamTag(atToken: Node, tagName: Identifier) { let typeExpression = tryParseTypeExpression(); - skipWhitespace(); + let name: Identifier; let isBracketed: boolean; // Looking for something like '[foo]' or 'foo' if (parseOptionalToken(SyntaxKind.OpenBracketToken)) { name = parseJSDocIdentifierName(); + skipWhitespace(); isBracketed = true; // May have an optional default, e.g. '[foo = 42]' @@ -6362,11 +6486,12 @@ namespace ts { result.preParameterName = preName; result.typeExpression = typeExpression; result.postParameterName = postName; + result.parameterName = postName || preName; result.isBracketed = isBracketed; return finishNode(result); } - function handleReturnTag(atToken: Node, tagName: Identifier): JSDocReturnTag { + function parseReturnTag(atToken: Node, tagName: Identifier): JSDocReturnTag { if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text); } @@ -6378,7 +6503,7 @@ namespace ts { return finishNode(result); } - function handleTypeTag(atToken: Node, tagName: Identifier): JSDocTypeTag { + function parseTypeTag(atToken: Node, tagName: Identifier): JSDocTypeTag { if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) { parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text); } @@ -6390,10 +6515,11 @@ namespace ts { return finishNode(result); } - function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { + function parsePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); const name = parseJSDocIdentifierName(); + skipWhitespace(); if (!name) { parseErrorAtPosition(scanner.getStartPos(), /*length*/ 0, Diagnostics.Identifier_expected); return undefined; @@ -6407,7 +6533,7 @@ namespace ts { return finishNode(result); } - function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { + function parseTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); @@ -6416,6 +6542,7 @@ namespace ts { typedefTag.tagName = tagName; typedefTag.name = parseJSDocIdentifierName(); typedefTag.typeExpression = typeExpression; + skipWhitespace(); if (typeExpression) { if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) { @@ -6485,6 +6612,7 @@ namespace ts { nextJSDocToken(); const tagName = parseJSDocIdentifierName(); + skipWhitespace(); if (!tagName) { return false; } @@ -6495,21 +6623,21 @@ namespace ts { // already has a @type tag, terminate the parent tag now. return false; } - parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName); + parentTag.jsDocTypeTag = parseTypeTag(atToken, tagName); return true; case "prop": case "property": if (!parentTag.jsDocPropertyTags) { parentTag.jsDocPropertyTags = >[]; } - const propertyTag = handlePropertyTag(atToken, tagName); + const propertyTag = parsePropertyTag(atToken, tagName); parentTag.jsDocPropertyTags.push(propertyTag); return true; } return false; } - function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag { + function parseTemplateTag(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); } @@ -6519,6 +6647,7 @@ namespace ts { while (true) { const name = parseJSDocIdentifierName(); + skipWhitespace(); if (!name) { parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); return undefined; @@ -6532,6 +6661,7 @@ namespace ts { if (token() === SyntaxKind.CommaToken) { nextJSDocToken(); + skipWhitespace(); } else { break; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index bfc9591baa7..e7b3872f2e3 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1759,40 +1759,46 @@ namespace ts { } startPos = pos; - - // Eat leading whitespace - let ch = text.charCodeAt(pos); - while (pos < end) { - ch = text.charCodeAt(pos); - if (isWhiteSpaceSingleLine(ch)) { - pos++; - } - else { - break; - } - } tokenPos = pos; + const ch = text.charCodeAt(pos); switch (ch) { + case CharacterCodes.tab: + case CharacterCodes.verticalTab: + case CharacterCodes.formFeed: + case CharacterCodes.space: + while (pos < end && isWhiteSpaceSingleLine(text.charCodeAt(pos))) { + pos++; + } + return token = SyntaxKind.WhitespaceTrivia; case CharacterCodes.at: - return pos += 1, token = SyntaxKind.AtToken; + pos++; + return token = SyntaxKind.AtToken; case CharacterCodes.lineFeed: case CharacterCodes.carriageReturn: - return pos += 1, token = SyntaxKind.NewLineTrivia; + pos++; + return token = SyntaxKind.NewLineTrivia; case CharacterCodes.asterisk: - return pos += 1, token = SyntaxKind.AsteriskToken; + pos++; + return token = SyntaxKind.AsteriskToken; case CharacterCodes.openBrace: - return pos += 1, token = SyntaxKind.OpenBraceToken; + pos++; + return token = SyntaxKind.OpenBraceToken; case CharacterCodes.closeBrace: - return pos += 1, token = SyntaxKind.CloseBraceToken; + pos++; + return token = SyntaxKind.CloseBraceToken; case CharacterCodes.openBracket: - return pos += 1, token = SyntaxKind.OpenBracketToken; + pos++; + return token = SyntaxKind.OpenBracketToken; case CharacterCodes.closeBracket: - return pos += 1, token = SyntaxKind.CloseBracketToken; + pos++; + return token = SyntaxKind.CloseBracketToken; case CharacterCodes.equals: - return pos += 1, token = SyntaxKind.EqualsToken; + pos++; + return token = SyntaxKind.EqualsToken; case CharacterCodes.comma: - return pos += 1, token = SyntaxKind.CommaToken; + pos++; + return token = SyntaxKind.CommaToken; } if (isIdentifierStart(ch, ScriptTarget.Latest)) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 82844980ca7..d901108e0f0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -487,7 +487,7 @@ namespace ts { parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). - /* @internal */ jsDocComments?: JSDocComment[]; // JSDoc for the node, if it has any. Only for .js files. + /* @internal */ jsDocComments?: JSDoc[]; // JSDoc for the node, if it has any. /* @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) @@ -1555,7 +1555,7 @@ namespace ts { // @kind(SyntaxKind.JSDocRecordType) export interface JSDocRecordType extends JSDocType, TypeLiteralNode { - members: NodeArray; + literal: TypeLiteralNode; } // @kind(SyntaxKind.JSDocTypeReference) @@ -1603,14 +1603,16 @@ namespace ts { } // @kind(SyntaxKind.JSDocComment) - export interface JSDocComment extends Node { + export interface JSDoc extends Node { tags: NodeArray; + comment: string | undefined; } // @kind(SyntaxKind.JSDocTag) export interface JSDocTag extends Node { atToken: Node; tagName: Identifier; + comment: string | undefined; } // @kind(SyntaxKind.JSDocTemplateTag) @@ -1649,9 +1651,13 @@ namespace ts { // @kind(SyntaxKind.JSDocParameterTag) export interface JSDocParameterTag extends JSDocTag { + /** the parameter name, if provided *before* the type (TypeScript-style) */ preParameterName?: Identifier; typeExpression?: JSDocTypeExpression; + /** the parameter name, if provided *after* the type (JSDoc-standard) */ postParameterName?: Identifier; + /** the parameter name, regardless of the location it was provided */ + parameterName: Identifier; isBracketed: boolean; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6c948a8e6d9..7a22c5634d8 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1426,39 +1426,75 @@ namespace ts { return undefined; } - const jsDocComments = getJSDocComments(node, checkParentVariableStatement); - if (!jsDocComments) { + const jsDocTags = getJSDocTags(node, checkParentVariableStatement); + if (!jsDocTags) { return undefined; } - for (const jsDocComment of jsDocComments) { - for (const tag of jsDocComment.tags) { - if (tag.kind === kind) { - return tag; - } + for (const tag of jsDocTags) { + if (tag.kind === kind) { + return tag; } } } - function getJSDocComments(node: Node, checkParentVariableStatement: boolean): JSDocComment[] { - if (node.jsDocComments) { - return node.jsDocComments; + function append(previous: T[] | undefined, additional: T[] | undefined): T[] | undefined { + if (additional) { + if (!previous) { + previous = []; + } + for (const x of additional) { + previous.push(x); + } } - // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. - // /** - // * @param {number} name - // * @returns {number} - // */ - // var x = function(name) { return name.length; } - if (checkParentVariableStatement) { - const isInitializerOfVariableDeclarationInStatement = - node.parent.kind === SyntaxKind.VariableDeclaration && - (node.parent).initializer === node && - node.parent.parent.parent.kind === SyntaxKind.VariableStatement; + return previous; + } - const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined; + export function getJSDocComments(node: Node, checkParentVariableStatement: boolean): string[] { + return getJSDocs(node, checkParentVariableStatement, docs => map(docs, doc => doc.comment), tags => map(tags, tag => tag.comment)); + } + + function getJSDocTags(node: Node, checkParentVariableStatement: boolean): JSDocTag[] { + return getJSDocs(node, checkParentVariableStatement, docs => { + const result: JSDocTag[] = []; + for (const doc of docs) { + if (doc.tags) { + result.push(...doc.tags); + } + } + return result; + }, tags => tags); + } + + function getJSDocs(node: Node, checkParentVariableStatement: boolean, getDocs: (docs: JSDoc[]) => T[], getTags: (tags: JSDocTag[]) => T[]): T[] { + // TODO: Get rid of getJsDocComments and friends (note the lowercase 's' in Js) + // TODO: A lot of this work should be cached, maybe. I guess it's only used in services right now... + let result: T[] = undefined; + // prepend documentation from parent sources + if (checkParentVariableStatement) { + // Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement. + // /** + // * @param {number} name + // * @returns {number} + // */ + // var x = function(name) { return name.length; } + const isInitializerOfVariableDeclarationInStatement = + isVariableLike(node.parent) && + (node.parent).initializer === node && + node.parent.parent.parent.kind === SyntaxKind.VariableStatement; + const isVariableOfVariableDeclarationStatement = isVariableLike(node) && + node.parent.parent.kind === SyntaxKind.VariableStatement; + + const variableStatementNode = + isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : + isVariableOfVariableDeclarationStatement ? node.parent.parent : + undefined; if (variableStatementNode) { - return variableStatementNode.jsDocComments; + result = append(result, getJSDocs(variableStatementNode, checkParentVariableStatement, getDocs, getTags)); + } + if (node.kind === SyntaxKind.ModuleDeclaration && + node.parent && node.parent.kind === SyntaxKind.ModuleDeclaration) { + result = append(result, getJSDocs(node.parent, checkParentVariableStatement, getDocs, getTags)); } // Also recognize when the node is the RHS of an assignment expression @@ -1469,16 +1505,62 @@ namespace ts { (parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken && parent.parent.kind === SyntaxKind.ExpressionStatement; if (isSourceOfAssignmentExpressionStatement) { - return parent.parent.jsDocComments; + result = append(result, getJSDocs(parent.parent, checkParentVariableStatement, getDocs, getTags)); } const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment; if (isPropertyAssignmentExpression) { - return parent.jsDocComments; + result = append(result, getJSDocs(parent, checkParentVariableStatement, getDocs, getTags)); + } + + // Pull parameter comments from declaring function as well + if (node.kind === SyntaxKind.Parameter) { + const paramTags = getJSDocParameterTag(node as ParameterDeclaration, checkParentVariableStatement); + if (paramTags) { + result = append(result, getTags(paramTags)); + } } } - return undefined; + if (isVariableLike(node) && node.initializer) { + result = append(result, getJSDocs(node.initializer, /*checkParentVariableStatement*/ false, getDocs, getTags)); + } + + if (node.jsDocComments) { + if (result) { + result = append(result, getDocs(node.jsDocComments)); + } + else { + return getDocs(node.jsDocComments); + } + } + + return result; + } + + function getJSDocParameterTag(param: ParameterDeclaration, checkParentVariableStatement: boolean): JSDocTag[] { + const func = param.parent as FunctionLikeDeclaration; + const tags = getJSDocTags(func, checkParentVariableStatement); + if (!param.name) { + // this is an anonymous jsdoc param from a `function(type1, type2): type3` specification + const i = func.parameters.indexOf(param); + const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag); + if (paramTags && 0 <= i && i < paramTags.length) { + return [paramTags[i]]; + } + } + else if (param.name.kind === SyntaxKind.Identifier) { + const name = (param.name as Identifier).text; + const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && (tag as JSDocParameterTag).parameterName.text === name); + if (paramTags) { + return paramTags; + } + } + else { + // TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines + // But multi-line object types aren't supported yet either + return undefined; + } } export function getJSDocTypeTag(node: Node): JSDocTypeTag { @@ -1499,17 +1581,15 @@ namespace ts { // annotation. const parameterName = (parameter.name).text; - 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; - } - } + const jsDocTags = getJSDocTags(parameter.parent, /*checkParentVariableStatement*/ true); + if (!jsDocTags) { + return undefined; + } + for (const tag of jsDocTags) { + if (tag.kind === SyntaxKind.JSDocParameterTag) { + const parameterTag = tag; + if (parameterTag.parameterName.text === parameterName) { + return parameterTag; } } } diff --git a/src/harness/unittests/jsDocParsing.ts b/src/harness/unittests/jsDocParsing.ts index 2de8cff7634..2c935439a9b 100644 --- a/src/harness/unittests/jsDocParsing.ts +++ b/src/harness/unittests/jsDocParsing.ts @@ -7,7 +7,7 @@ namespace ts { function parsesCorrectly(name: string, content: string) { it(name, () => { const typeAndDiagnostics = ts.parseJSDocTypeExpressionForTests(content); - assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0); + assert.isTrue(typeAndDiagnostics && typeAndDiagnostics.diagnostics.length === 0, "no errors issued"); Harness.Baseline.runBaseline("JSDocParsing/TypeExpressions.parsesCorrectly." + name + ".json", () => Utils.sourceFileToJSON(typeAndDiagnostics.jsDocTypeExpression.type)); @@ -36,6 +36,9 @@ namespace ts { parsesCorrectly("recordType6", "{{foo, bar: number}}"); parsesCorrectly("recordType7", "{{foo: number, bar: number}}"); parsesCorrectly("recordType8", "{{function}}"); + parsesCorrectly("trailingCommaInRecordType", "{{a,}}"); + parsesCorrectly("callSignatureInRecordType", "{{(): number}}"); + parsesCorrectly("methodInRecordType", "{{foo(): number}}"); parsesCorrectly("unionType", "{(number|string)}"); parsesCorrectly("topLevelNoParenUnionType", "{number|string}"); parsesCorrectly("functionType1", "{function()}"); @@ -63,7 +66,6 @@ namespace ts { describe("parsesIncorrectly", () => { parsesIncorrectly("emptyType", "{}"); - parsesIncorrectly("trailingCommaInRecordType", "{{a,}}"); parsesIncorrectly("unionTypeWithTrailingBar", "{(a|)}"); parsesIncorrectly("unionTypeWithoutTypes", "{()}"); parsesIncorrectly("nullableTypeWithoutType", "{!}"); @@ -80,8 +82,6 @@ namespace ts { parsesIncorrectly("tsConstructoType", "{new () => string}"); parsesIncorrectly("typeOfType", "{typeof M}"); parsesIncorrectly("namedParameter", "{function(a: number)}"); - parsesIncorrectly("callSignatureInRecordType", "{{(): number}}"); - parsesIncorrectly("methodInRecordType", "{{foo(): number}}"); parsesIncorrectly("tupleTypeWithComma", "{[,]}"); parsesIncorrectly("tupleTypeWithTrailingComma", "{[number,]}"); parsesIncorrectly("tupleTypeWithLeadingComma", "{[,number]}"); @@ -100,7 +100,7 @@ namespace ts { } Harness.Baseline.runBaseline("JSDocParsing/DocComments.parsesCorrectly." + name + ".json", - () => JSON.stringify(comment.jsDocComment, + () => JSON.stringify(comment.jsDoc, (k, v) => v && v.pos !== undefined ? JSON.parse(Utils.sourceFileToJSON(v)) : v, 4)); }); } @@ -115,7 +115,6 @@ namespace ts { describe("parsesIncorrectly", () => { parsesIncorrectly("emptyComment", "/***/"); parsesIncorrectly("threeAsterisks", "/*** */"); - parsesIncorrectly("asteriskAfterPreamble", "/** * @type {number} */"); parsesIncorrectly("multipleTypes", `/** * @type {number} @@ -167,6 +166,7 @@ namespace ts { * @type {number} */`); + parsesCorrectly("asteriskAfterPreamble", "/** * @type {number} */"); parsesCorrectly("typeTag", `/** diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 0c19fbc74f9..29a878224cd 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -698,9 +698,9 @@ namespace ts { // See if this is a doc comment. If so, we'll classify certain portions of it // specially. const docCommentAndDiagnostics = parseIsolatedJSDocComment(sourceFile.text, start, width); - if (docCommentAndDiagnostics && docCommentAndDiagnostics.jsDocComment) { - docCommentAndDiagnostics.jsDocComment.parent = token; - classifyJSDocComment(docCommentAndDiagnostics.jsDocComment); + if (docCommentAndDiagnostics && docCommentAndDiagnostics.jsDoc) { + docCommentAndDiagnostics.jsDoc.parent = token; + classifyJSDocComment(docCommentAndDiagnostics.jsDoc); return; } } @@ -713,37 +713,39 @@ namespace ts { pushClassification(start, width, ClassificationType.comment); } - function classifyJSDocComment(docComment: JSDocComment) { + function classifyJSDocComment(docComment: JSDoc) { let pos = docComment.pos; - for (const tag of docComment.tags) { - // As we walk through each tag, classify the portion of text from the end of - // the last tag (or the start of the entire doc comment) as 'comment'. - if (tag.pos !== pos) { - pushCommentRange(pos, tag.pos - pos); + if (docComment.tags) { + for (const tag of docComment.tags) { + // As we walk through each tag, classify the portion of text from the end of + // the last tag (or the start of the entire doc comment) as 'comment'. + if (tag.pos !== pos) { + pushCommentRange(pos, tag.pos - pos); + } + + pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); + pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); + + pos = tag.tagName.end; + + switch (tag.kind) { + case SyntaxKind.JSDocParameterTag: + processJSDocParameterTag(tag); + break; + case SyntaxKind.JSDocTemplateTag: + processJSDocTemplateTag(tag); + break; + case SyntaxKind.JSDocTypeTag: + processElement((tag).typeExpression); + break; + case SyntaxKind.JSDocReturnTag: + processElement((tag).typeExpression); + break; + } + + pos = tag.end; } - - pushClassification(tag.atToken.pos, tag.atToken.end - tag.atToken.pos, ClassificationType.punctuation); - pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); - - pos = tag.tagName.end; - - switch (tag.kind) { - case SyntaxKind.JSDocParameterTag: - processJSDocParameterTag(tag); - break; - case SyntaxKind.JSDocTemplateTag: - processJSDocTemplateTag(tag); - break; - case SyntaxKind.JSDocTypeTag: - processElement((tag).typeExpression); - break; - case SyntaxKind.JSDocReturnTag: - processElement((tag).typeExpression); - break; - } - - pos = tag.end; } if (pos !== docComment.end) { @@ -982,4 +984,4 @@ namespace ts { } } } -} \ No newline at end of file +} diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index f40a8013426..feca406359c 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -44,349 +44,47 @@ namespace ts.JsDoc { let jsDocCompletionEntries: CompletionEntry[]; export function getJsDocCommentsFromDeclarations(declarations: Declaration[], name: string, canUseParsedParamTagComments: boolean) { + // Only collect doc comments from duplicate declarations once: + // In case of a union property there might be same declaration multiple times + // which only varies in type parameter + // Eg. const a: Array | Array; a.length + // The property length will have two declarations of property length coming + // from Array - Array and Array const documentationComment = []; - const docComments = getJsDocCommentsSeparatedByNewLines(); - ts.forEach(docComments, docComment => { - if (documentationComment.length) { - documentationComment.push(lineBreakPart()); + forEachUnique(declarations, declaration => { + const comments = getJSDocComments(declaration, /*checkParentVariableStatement*/ true); + if (!comments) { + return; + } + for (const comment of comments) { + if (comment) { + if (documentationComment.length) { + documentationComment.push(lineBreakPart()); + } + documentationComment.push(textPart(comment)); + } } - documentationComment.push(docComment); }); - return documentationComment; + } - function getJsDocCommentsSeparatedByNewLines() { - const paramTag = "@param"; - const jsDocCommentParts: SymbolDisplayPart[] = []; - - ts.forEach(declarations, (declaration, indexOfDeclaration) => { - // Make sure we are collecting doc comment from declaration once, - // In case of union property there might be same declaration multiple times - // which only varies in type parameter - // Eg. const a: Array | Array; a.length - // The property length will have two declarations of property length coming - // from Array - Array and Array - if (indexOf(declarations, declaration) === indexOfDeclaration) { - const sourceFileOfDeclaration = getSourceFileOfNode(declaration); - // If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments - if (canUseParsedParamTagComments && declaration.kind === SyntaxKind.Parameter) { - if ((declaration.parent.kind === SyntaxKind.FunctionExpression || declaration.parent.kind === SyntaxKind.ArrowFunction) && - declaration.parent.parent.kind === SyntaxKind.VariableDeclaration) { - addCommentParts(declaration.parent.parent.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment); - } - addCommentParts(declaration.parent, sourceFileOfDeclaration, getCleanedParamJsDocComment); - } - - // If this is left side of dotted module declaration, there is no doc comments associated with this node - if (declaration.kind === SyntaxKind.ModuleDeclaration && (declaration).body && (declaration).body.kind === SyntaxKind.ModuleDeclaration) { - return; - } - - if ((declaration.kind === SyntaxKind.FunctionExpression || declaration.kind === SyntaxKind.ArrowFunction) && - declaration.parent.kind === SyntaxKind.VariableDeclaration) { - addCommentParts(declaration.parent.parent, sourceFileOfDeclaration, getCleanedJsDocComment); - } - - // If this is dotted module name, get the doc comments from the parent - while (declaration.kind === SyntaxKind.ModuleDeclaration && declaration.parent.kind === SyntaxKind.ModuleDeclaration) { - declaration = declaration.parent; - } - addCommentParts(declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, - sourceFileOfDeclaration, - getCleanedJsDocComment); - - if (declaration.kind === SyntaxKind.VariableDeclaration) { - const init = (declaration as VariableDeclaration).initializer; - if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) { - // Get the cleaned js doc comment text from the initializer - addCommentParts(init, sourceFileOfDeclaration, getCleanedJsDocComment); - } - } - } - }); - - return jsDocCommentParts; - - function addCommentParts(commented: Node, - sourceFileOfDeclaration: SourceFile, - getCommentPart: (pos: number, end: number, file: SourceFile) => SymbolDisplayPart[]): void { - const ranges = getJsDocCommentTextRange(commented, sourceFileOfDeclaration); - // Get the cleaned js doc comment text from the declaration - ts.forEach(ranges, jsDocCommentTextRange => { - const cleanedComment = getCommentPart(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); - if (cleanedComment) { - addRange(jsDocCommentParts, cleanedComment); - } - }); - } - - function getJsDocCommentTextRange(node: Node, sourceFile: SourceFile): TextRange[] { - return ts.map(getJsDocComments(node, sourceFile), - jsDocComment => { - return { - pos: jsDocComment.pos + "/*".length, // Consume /* from the comment - end: jsDocComment.end - "*/".length // Trim off comment end indicator - }; - }); - } - - function consumeWhiteSpacesOnTheLine(pos: number, end: number, sourceFile: SourceFile, maxSpacesToRemove?: number) { - if (maxSpacesToRemove !== undefined) { - end = Math.min(end, pos + maxSpacesToRemove); - } - - for (; pos < end; pos++) { - const ch = sourceFile.text.charCodeAt(pos); - if (!isWhiteSpaceSingleLine(ch)) { - return pos; - } - } - - return end; - } - - function consumeLineBreaks(pos: number, end: number, sourceFile: SourceFile) { - while (pos < end && isLineBreak(sourceFile.text.charCodeAt(pos))) { - pos++; - } - - return pos; - } - - function isName(pos: number, end: number, sourceFile: SourceFile, name: string) { - return pos + name.length < end && - sourceFile.text.substr(pos, name.length) === name && - isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length)); - } - - function isParamTag(pos: number, end: number, sourceFile: SourceFile) { - // If it is @param tag - return isName(pos, end, sourceFile, paramTag); - } - - function pushDocCommentLineText(docComments: SymbolDisplayPart[], text: string, blankLineCount: number) { - // Add the empty lines in between texts - while (blankLineCount) { - blankLineCount--; - docComments.push(textPart("")); - } - - docComments.push(textPart(text)); - } - - function getCleanedJsDocComment(pos: number, end: number, sourceFile: SourceFile) { - let spacesToRemoveAfterAsterisk: number; - const docComments: SymbolDisplayPart[] = []; - let blankLineCount = 0; - let isInParamTag = false; - - while (pos < end) { - let docCommentTextOfLine = ""; - // First consume leading white space - pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile); - - // If the comment starts with '*' consume the spaces on this line - if (pos < end && sourceFile.text.charCodeAt(pos) === CharacterCodes.asterisk) { - const lineStartPos = pos + 1; - pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, spacesToRemoveAfterAsterisk); - - // Set the spaces to remove after asterisk as margin if not already set - if (spacesToRemoveAfterAsterisk === undefined && pos < end && !isLineBreak(sourceFile.text.charCodeAt(pos))) { - spacesToRemoveAfterAsterisk = pos - lineStartPos; - } - } - else if (spacesToRemoveAfterAsterisk === undefined) { - spacesToRemoveAfterAsterisk = 0; - } - - // Analyze text on this line - while (pos < end && !isLineBreak(sourceFile.text.charCodeAt(pos))) { - const ch = sourceFile.text.charAt(pos); - if (ch === "@") { - // If it is @param tag - if (isParamTag(pos, end, sourceFile)) { - isInParamTag = true; - pos += paramTag.length; - continue; - } - else { - isInParamTag = false; - } - } - - // Add the ch to doc text if we arent in param tag - if (!isInParamTag) { - docCommentTextOfLine += ch; - } - - // Scan next character - pos++; - } - - // Continue with next line - pos = consumeLineBreaks(pos, end, sourceFile); - if (docCommentTextOfLine) { - pushDocCommentLineText(docComments, docCommentTextOfLine, blankLineCount); - blankLineCount = 0; - } - else if (!isInParamTag && docComments.length) { - // This is blank line when there is text already parsed - blankLineCount++; - } - } - - return docComments; - } - - function getCleanedParamJsDocComment(pos: number, end: number, sourceFile: SourceFile) { - let paramHelpStringMargin: number; - const paramDocComments: SymbolDisplayPart[] = []; - while (pos < end) { - if (isParamTag(pos, end, sourceFile)) { - let blankLineCount = 0; - let recordedParamTag = false; - // Consume leading spaces - pos = consumeWhiteSpaces(pos + paramTag.length); - if (pos >= end) { - break; - } - - // Ignore type expression - if (sourceFile.text.charCodeAt(pos) === CharacterCodes.openBrace) { - pos++; - for (let curlies = 1; pos < end; pos++) { - const charCode = sourceFile.text.charCodeAt(pos); - - // { character means we need to find another } to match the found one - if (charCode === CharacterCodes.openBrace) { - curlies++; - continue; - } - - // } char - if (charCode === CharacterCodes.closeBrace) { - curlies--; - if (curlies === 0) { - // We do not have any more } to match the type expression is ignored completely - pos++; - break; - } - else { - // there are more { to be matched with } - continue; - } - } - - // Found start of another tag - if (charCode === CharacterCodes.at) { - break; - } - } - - // Consume white spaces - pos = consumeWhiteSpaces(pos); - if (pos >= end) { - break; - } - } - - // Parameter name - if (isName(pos, end, sourceFile, name)) { - // Found the parameter we are looking for consume white spaces - pos = consumeWhiteSpaces(pos + name.length); - if (pos >= end) { - break; - } - - let paramHelpString = ""; - const firstLineParamHelpStringPos = pos; - while (pos < end) { - const ch = sourceFile.text.charCodeAt(pos); - - // at line break, set this comment line text and go to next line - if (isLineBreak(ch)) { - if (paramHelpString) { - pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); - paramHelpString = ""; - blankLineCount = 0; - recordedParamTag = true; - } - else if (recordedParamTag) { - blankLineCount++; - } - - // Get the pos after cleaning start of the line - setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos); - continue; - } - - // Done scanning param help string - next tag found - if (ch === CharacterCodes.at) { - break; - } - - paramHelpString += sourceFile.text.charAt(pos); - - // Go to next character - pos++; - } - - // If there is param help text, add it top the doc comments - if (paramHelpString) { - pushDocCommentLineText(paramDocComments, paramHelpString, blankLineCount); - } - paramHelpStringMargin = undefined; - } - - // If this is the start of another tag, continue with the loop in search of param tag with symbol name - if (sourceFile.text.charCodeAt(pos) === CharacterCodes.at) { - continue; - } - } - - // Next character - pos++; - } - - return paramDocComments; - - function consumeWhiteSpaces(pos: number) { - while (pos < end && isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(pos))) { - pos++; - } - - return pos; - } - - function setPosForParamHelpStringOnNextLine(firstLineParamHelpStringPos: number) { - // Get the pos after consuming line breaks - pos = consumeLineBreaks(pos, end, sourceFile); - if (pos >= end) { - return; - } - - if (paramHelpStringMargin === undefined) { - paramHelpStringMargin = sourceFile.getLineAndCharacterOfPosition(firstLineParamHelpStringPos).character; - } - - // Now consume white spaces max - const startOfLinePos = pos; - pos = consumeWhiteSpacesOnTheLine(pos, end, sourceFile, paramHelpStringMargin); - if (pos >= end) { - return; - } - - const consumedSpaces = pos - startOfLinePos; - if (consumedSpaces < paramHelpStringMargin) { - const ch = sourceFile.text.charCodeAt(pos); - if (ch === CharacterCodes.asterisk) { - // Consume more spaces after asterisk - pos = consumeWhiteSpacesOnTheLine(pos + 1, end, sourceFile, paramHelpStringMargin - consumedSpaces - 1); - } + /** + * Iterates through 'array' by index and performs the callback on each element of array until the callback + * returns a truthy value, then returns that value. + * If no such value is found, the callback is applied to each element of array and undefined is returned. + */ + function forEachUnique(array: T[], callback: (element: T, index: number) => U): U { + if (array) { + for (let i = 0, len = array.length; i < len; i++) { + if (indexOf(array, array[i]) === i) { + const result = callback(array[i], i); + if (result) { + return result; } } } } + return undefined; } export function getAllJsDocCompletionEntries(): CompletionEntry[] { diff --git a/src/services/services.ts b/src/services/services.ts index f3e95e94868..9b733179fe3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -42,7 +42,7 @@ namespace ts { public end: number; public flags: NodeFlags; public parent: Node; - public jsDocComments: JSDocComment[]; + public jsDocComments: JSDoc[]; public original: Node; public transformFlags: TransformFlags; public excludeTransformFlags: TransformFlags; @@ -215,7 +215,7 @@ namespace ts { public end: number; public flags: NodeFlags; public parent: Node; - public jsDocComments: JSDocComment[]; + public jsDocComments: JSDoc[]; public __tokenTag: any; constructor(pos: number, end: number) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index ba419e4fec0..d1f3a54563f 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -953,9 +953,11 @@ namespace ts { if (node) { if (node.jsDocComments) { for (const jsDocComment of node.jsDocComments) { - for (const tag of jsDocComment.tags) { - if (tag.pos <= position && position <= tag.end) { - return tag; + if (jsDocComment.tags) { + for (const tag of jsDocComment.tags) { + if (tag.pos <= position && position <= tag.end) { + return tag; + } } } } @@ -1353,4 +1355,4 @@ namespace ts { } return { configJsonObject, diagnostics }; } -} \ No newline at end of file +} diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.asteriskAfterPreamble.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.asteriskAfterPreamble.json new file mode 100644 index 00000000000..03baac016aa --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.asteriskAfterPreamble.json @@ -0,0 +1,6 @@ +{ + "kind": "JSDocComment", + "pos": 0, + "end": 23, + "comment": "* @type {number} " +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json index 3fe305d4106..4ce75d8c3f9 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json @@ -27,7 +27,8 @@ "pos": 15, "end": 21 } - } + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json index 3fe305d4106..4ce75d8c3f9 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json @@ -27,7 +27,8 @@ "pos": 15, "end": 21 } - } + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json index 7947de57a58..b37b887624a 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocReturnTag", "pos": 8, - "end": 15, + "end": 16, "atToken": { "kind": "AtToken", "pos": 8, @@ -17,10 +17,11 @@ "pos": 9, "end": 15, "text": "return" - } + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 15 + "end": 16 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json index 7a4b97b1336..53c73cdf7c1 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTypeTag", "pos": 8, - "end": 13, + "end": 14, "atToken": { "kind": "AtToken", "pos": 8, @@ -17,10 +17,11 @@ "pos": 9, "end": 13, "text": "type" - } + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 13 + "end": 14 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json index 746c4056f83..9d303955ab1 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json @@ -33,7 +33,14 @@ "pos": 24, "end": 29, "text": "name1" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json index ff4bba576d2..1b87d268b93 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json @@ -33,7 +33,14 @@ "pos": 24, "end": 29, "text": "name1" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + }, + "comment": "Description text follows" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json index 23264572fed..fe01df58851 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json @@ -34,7 +34,14 @@ "end": 30, "text": "name1" }, - "isBracketed": true + "parameterName": { + "kind": "Identifier", + "pos": 25, + "end": 30, + "text": "name1" + }, + "isBracketed": true, + "comment": "Description text follows" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json index ceb123b6b34..f50ce732606 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json @@ -34,7 +34,14 @@ "end": 31, "text": "name1" }, - "isBracketed": true + "parameterName": { + "kind": "Identifier", + "pos": 26, + "end": 31, + "text": "name1" + }, + "isBracketed": true, + "comment": "Description text follows" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json index 19bab08a77b..70f2641fd51 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json @@ -33,7 +33,14 @@ "pos": 22, "end": 28 } - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 15, + "end": 20, + "text": "name1" + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json index 5da9084897e..4b720567cc7 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json @@ -33,7 +33,14 @@ "pos": 22, "end": 28 } - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 15, + "end": 20, + "text": "name1" + }, + "comment": "Description" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json index 293d2a4c212..d77e80c7512 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json @@ -23,7 +23,14 @@ "pos": 15, "end": 18, "text": "foo" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 15, + "end": 18, + "text": "foo" + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json index a8425d833ae..59288030068 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json @@ -27,7 +27,8 @@ "pos": 17, "end": 23 } - } + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json index af4fd91964d..48c72efad36 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json @@ -27,7 +27,8 @@ "pos": 17, "end": 23 } - } + }, + "comment": "Description text follows" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json index ceca9584a2d..12111466f9e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json @@ -27,7 +27,8 @@ "pos": 18, "end": 24 } - } + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json index 2804a704ba7..8dd2963713e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 19, + "end": 20, "atToken": { "kind": "AtToken", "pos": 8, @@ -22,7 +22,7 @@ "0": { "kind": "TypeParameter", "pos": 18, - "end": 19, + "end": 20, "name": { "kind": "Identifier", "pos": 18, @@ -31,12 +31,13 @@ } }, "length": 1, - "pos": 17, - "end": 19 - } + "pos": 18, + "end": 20 + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 19 + "end": 20 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json index a55761a52b7..2f66159c249 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 21, + "end": 22, "atToken": { "kind": "AtToken", "pos": 8, @@ -33,7 +33,7 @@ "1": { "kind": "TypeParameter", "pos": 20, - "end": 21, + "end": 22, "name": { "kind": "Identifier", "pos": 20, @@ -42,12 +42,13 @@ } }, "length": 2, - "pos": 17, - "end": 21 - } + "pos": 18, + "end": 22 + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 21 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json index 64e6e206e11..e5814c387bb 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 22, + "end": 23, "atToken": { "kind": "AtToken", "pos": 8, @@ -22,7 +22,7 @@ "0": { "kind": "TypeParameter", "pos": 18, - "end": 19, + "end": 20, "name": { "kind": "Identifier", "pos": 18, @@ -33,7 +33,7 @@ "1": { "kind": "TypeParameter", "pos": 21, - "end": 22, + "end": 23, "name": { "kind": "Identifier", "pos": 21, @@ -42,12 +42,13 @@ } }, "length": 2, - "pos": 17, - "end": 22 - } + "pos": 18, + "end": 23 + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 22 + "end": 23 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json index 64e6e206e11..f29fed31e4c 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 22, + "end": 23, "atToken": { "kind": "AtToken", "pos": 8, @@ -33,7 +33,7 @@ "1": { "kind": "TypeParameter", "pos": 21, - "end": 22, + "end": 23, "name": { "kind": "Identifier", "pos": 21, @@ -42,12 +42,13 @@ } }, "length": 2, - "pos": 17, - "end": 22 - } + "pos": 18, + "end": 23 + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 22 + "end": 23 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json index 9b5a4a6c790..d3ee964df7a 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 23, + "end": 24, "atToken": { "kind": "AtToken", "pos": 8, @@ -22,7 +22,7 @@ "0": { "kind": "TypeParameter", "pos": 18, - "end": 19, + "end": 20, "name": { "kind": "Identifier", "pos": 18, @@ -33,7 +33,7 @@ "1": { "kind": "TypeParameter", "pos": 22, - "end": 23, + "end": 24, "name": { "kind": "Identifier", "pos": 22, @@ -42,12 +42,13 @@ } }, "length": 2, - "pos": 17, - "end": 23 - } + "pos": 18, + "end": 24 + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 23 + "end": 24 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json index d5c1c997b02..98f0de70848 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTemplateTag", "pos": 8, - "end": 23, + "end": 24, "atToken": { "kind": "AtToken", "pos": 8, @@ -22,7 +22,7 @@ "0": { "kind": "TypeParameter", "pos": 18, - "end": 19, + "end": 20, "name": { "kind": "Identifier", "pos": 18, @@ -33,7 +33,7 @@ "1": { "kind": "TypeParameter", "pos": 22, - "end": 23, + "end": 24, "name": { "kind": "Identifier", "pos": 22, @@ -42,12 +42,13 @@ } }, "length": 2, - "pos": 17, - "end": 23 - } + "pos": 18, + "end": 24 + }, + "comment": "Description of type parameters." }, "length": 1, "pos": 8, - "end": 23 + "end": 24 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json index da465077066..16968061afc 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json @@ -33,7 +33,14 @@ "pos": 24, "end": 29, "text": "name1" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + }, + "comment": "" }, "1": { "kind": "JSDocParameterTag", @@ -65,7 +72,14 @@ "pos": 50, "end": 55, "text": "name2" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 50, + "end": 55, + "text": "name2" + }, + "comment": "" }, "length": 2, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json index c995aa8bf22..8818c3a909e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json @@ -33,10 +33,56 @@ "pos": 24, "end": 29, "text": "name1" - } + }, + "parameterName": { + "kind": "Identifier", + "pos": 24, + "end": 29, + "text": "name1" + }, + "comment": "" }, - "length": 1, + "1": { + "kind": "JSDocParameterTag", + "pos": 30, + "end": 51, + "atToken": { + "kind": "AtToken", + "pos": 30, + "end": 31 + }, + "tagName": { + "kind": "Identifier", + "pos": 31, + "end": 36, + "text": "param" + }, + "typeExpression": { + "kind": "JSDocTypeExpression", + "pos": 37, + "end": 45, + "type": { + "kind": "NumberKeyword", + "pos": 38, + "end": 44 + } + }, + "postParameterName": { + "kind": "Identifier", + "pos": 46, + "end": 51, + "text": "name2" + }, + "parameterName": { + "kind": "Identifier", + "pos": 46, + "end": 51, + "text": "name2" + }, + "comment": "" + }, + "length": 2, "pos": 8, - "end": 29 + "end": 51 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json index 3fe305d4106..4ce75d8c3f9 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json @@ -27,7 +27,8 @@ "pos": 15, "end": 21 } - } + }, + "comment": "" }, "length": 1, "pos": 8, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json index 2d6d58d36b2..30ca205587e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json @@ -6,7 +6,7 @@ "0": { "kind": "JSDocTypedefTag", "pos": 8, - "end": 97, + "end": 98, "atToken": { "kind": "AtToken", "pos": 8, @@ -26,15 +26,15 @@ }, "jsDocTypeLiteral": { "kind": "JSDocTypeLiteral", - "pos": 23, - "end": 97, + "pos": 26, + "end": 98, "jsDocTypeTag": { "kind": "JSDocTypeTag", - "pos": 27, + "pos": 28, "end": 42, "atToken": { "kind": "AtToken", - "pos": 27, + "pos": 28, "end": 29 }, "tagName": { @@ -63,11 +63,11 @@ "jsDocPropertyTags": [ { "kind": "JSDocPropertyTag", - "pos": 46, - "end": 69, + "pos": 47, + "end": 72, "atToken": { "kind": "AtToken", - "pos": 46, + "pos": 47, "end": 48 }, "tagName": { @@ -95,11 +95,11 @@ }, { "kind": "JSDocPropertyTag", - "pos": 73, - "end": 97, + "pos": 74, + "end": 98, "atToken": { "kind": "AtToken", - "pos": 73, + "pos": 74, "end": 75 }, "tagName": { @@ -126,10 +126,11 @@ } } ] - } + }, + "comment": "" }, "length": 1, "pos": 8, - "end": 97 + "end": 98 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json new file mode 100644 index 00000000000..244c568ae05 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.callSignatureInRecordType.json @@ -0,0 +1,30 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 13, + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 13, + "members": { + "0": { + "kind": "CallSignature", + "pos": 2, + "end": 12, + "parameters": { + "length": 0, + "pos": 3, + "end": 3 + }, + "type": { + "kind": "NumberKeyword", + "pos": 5, + "end": 12 + } + }, + "length": 1, + "pos": 2, + "end": 12 + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json new file mode 100644 index 00000000000..fab9a581bd9 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.methodInRecordType.json @@ -0,0 +1,36 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 16, + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 16, + "members": { + "0": { + "kind": "MethodSignature", + "pos": 2, + "end": 15, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "parameters": { + "length": 0, + "pos": 6, + "end": 6 + }, + "type": { + "kind": "NumberKeyword", + "pos": 8, + "end": 15 + } + }, + "length": 1, + "pos": 2, + "end": 15 + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json index ab9bb050a89..12be4806629 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json @@ -2,9 +2,14 @@ "kind": "JSDocRecordType", "pos": 1, "end": 3, - "members": { - "length": 0, - "pos": 2, - "end": 2 + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 3, + "members": { + "length": 0, + "pos": 2, + "end": 2 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json index 73ff5dbfa60..4bed6d0b918 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json @@ -2,20 +2,25 @@ "kind": "JSDocRecordType", "pos": 1, "end": 6, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 6, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, "end": 5, - "text": "foo" - } - }, - "length": 1, - "pos": 2, - "end": 5 + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } + }, + "length": 1, + "pos": 2, + "end": 5 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json index 0ffac6cba8f..565738a6ba9 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json @@ -2,25 +2,30 @@ "kind": "JSDocRecordType", "pos": 1, "end": 14, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 14, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, - "end": 5, - "text": "foo" + "end": 13, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "length": 1, - "pos": 2, - "end": 13 + "length": 1, + "pos": 2, + "end": 13 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json index f49c2fd22ae..74bb20ab30b 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json @@ -2,31 +2,36 @@ "kind": "JSDocRecordType", "pos": 1, "end": 11, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 11, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, - "end": 5, - "text": "foo" - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 6, - "end": 10, - "name": { - "kind": "Identifier", + "end": 6, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } + }, + "1": { + "kind": "PropertySignature", "pos": 6, "end": 10, - "text": "bar" - } - }, - "length": 2, - "pos": 2, - "end": 10 + "name": { + "kind": "Identifier", + "pos": 6, + "end": 10, + "text": "bar" + } + }, + "length": 2, + "pos": 2, + "end": 10 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json index 4474dba8e21..b57de3aea3c 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json @@ -2,36 +2,41 @@ "kind": "JSDocRecordType", "pos": 1, "end": 19, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 19, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, - "end": 5, - "text": "foo" + "end": 14, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 14, - "end": 18, - "name": { - "kind": "Identifier", + "1": { + "kind": "PropertySignature", "pos": 14, "end": 18, - "text": "bar" - } - }, - "length": 2, - "pos": 2, - "end": 18 + "name": { + "kind": "Identifier", + "pos": 14, + "end": 18, + "text": "bar" + } + }, + "length": 2, + "pos": 2, + "end": 18 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json index a88005b0cec..6c980da4085 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json @@ -2,36 +2,41 @@ "kind": "JSDocRecordType", "pos": 1, "end": 19, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 5, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 19, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, - "end": 5, - "text": "foo" - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 6, - "end": 18, - "name": { - "kind": "Identifier", - "pos": 6, - "end": 10, - "text": "bar" + "end": 6, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + } }, - "type": { - "kind": "NumberKeyword", - "pos": 11, - "end": 18 - } - }, - "length": 2, - "pos": 2, - "end": 18 + "1": { + "kind": "PropertySignature", + "pos": 6, + "end": 18, + "name": { + "kind": "Identifier", + "pos": 6, + "end": 10, + "text": "bar" + }, + "type": { + "kind": "NumberKeyword", + "pos": 11, + "end": 18 + } + }, + "length": 2, + "pos": 2, + "end": 18 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json index e69f9a74682..fb9f8c055cb 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json @@ -2,41 +2,46 @@ "kind": "JSDocRecordType", "pos": 1, "end": 27, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 13, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 27, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, - "end": 5, - "text": "foo" + "end": 14, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 5, + "text": "foo" + }, + "type": { + "kind": "NumberKeyword", + "pos": 6, + "end": 13 + } }, - "type": { - "kind": "NumberKeyword", - "pos": 6, - "end": 13 - } - }, - "1": { - "kind": "JSDocRecordMember", - "pos": 14, - "end": 26, - "name": { - "kind": "Identifier", + "1": { + "kind": "PropertySignature", "pos": 14, - "end": 18, - "text": "bar" + "end": 26, + "name": { + "kind": "Identifier", + "pos": 14, + "end": 18, + "text": "bar" + }, + "type": { + "kind": "NumberKeyword", + "pos": 19, + "end": 26 + } }, - "type": { - "kind": "NumberKeyword", - "pos": 19, - "end": 26 - } - }, - "length": 2, - "pos": 2, - "end": 26 + "length": 2, + "pos": 2, + "end": 26 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json index 35701931097..748b593d235 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json @@ -2,21 +2,26 @@ "kind": "JSDocRecordType", "pos": 1, "end": 11, - "members": { - "0": { - "kind": "JSDocRecordMember", - "pos": 2, - "end": 10, - "name": { - "kind": "Identifier", + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 11, + "members": { + "0": { + "kind": "PropertySignature", "pos": 2, "end": 10, - "originalKeywordKind": "FunctionKeyword", - "text": "function" - } - }, - "length": 1, - "pos": 2, - "end": 10 + "name": { + "kind": "Identifier", + "pos": 2, + "end": 10, + "originalKeywordKind": "FunctionKeyword", + "text": "function" + } + }, + "length": 1, + "pos": 2, + "end": 10 + } } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json new file mode 100644 index 00000000000..1694cf9aa73 --- /dev/null +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.trailingCommaInRecordType.json @@ -0,0 +1,26 @@ +{ + "kind": "JSDocRecordType", + "pos": 1, + "end": 5, + "literal": { + "kind": "TypeLiteral", + "pos": 1, + "end": 5, + "members": { + "0": { + "kind": "PropertySignature", + "pos": 2, + "end": 4, + "name": { + "kind": "Identifier", + "pos": 2, + "end": 3, + "text": "a" + } + }, + "length": 1, + "pos": 2, + "end": 4 + } + } +} \ No newline at end of file diff --git a/tests/baselines/reference/returns.js b/tests/baselines/reference/returns.js new file mode 100644 index 00000000000..67390dea72a --- /dev/null +++ b/tests/baselines/reference/returns.js @@ -0,0 +1,16 @@ +//// [returns.js] +/** + * @returns {string} This comment is not currently exposed + */ +function f() { + return ""; +} + + +//// [dummy.js] +/** + * @returns {string} This comment is not currently exposed + */ +function f() { + return ""; +} diff --git a/tests/baselines/reference/returns.symbols b/tests/baselines/reference/returns.symbols new file mode 100644 index 00000000000..e0f0d4dac96 --- /dev/null +++ b/tests/baselines/reference/returns.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/jsdoc/returns.js === +/** + * @returns {string} This comment is not currently exposed + */ +function f() { +>f : Symbol(f, Decl(returns.js, 0, 0)) + + return ""; +} + diff --git a/tests/baselines/reference/returns.types b/tests/baselines/reference/returns.types new file mode 100644 index 00000000000..c85bc7272f8 --- /dev/null +++ b/tests/baselines/reference/returns.types @@ -0,0 +1,11 @@ +=== tests/cases/conformance/jsdoc/returns.js === +/** + * @returns {string} This comment is not currently exposed + */ +function f() { +>f : () => string + + return ""; +>"" : "" +} + diff --git a/tests/cases/conformance/jsdoc/returns.ts b/tests/cases/conformance/jsdoc/returns.ts new file mode 100644 index 00000000000..72cb4a6cb67 --- /dev/null +++ b/tests/cases/conformance/jsdoc/returns.ts @@ -0,0 +1,9 @@ +// @allowJs: true +// @filename: returns.js +// @out: dummy.js +/** + * @returns {string} This comment is not currently exposed + */ +function f() { + return ""; +} diff --git a/tests/cases/fourslash/commentsClassMembers.ts b/tests/cases/fourslash/commentsClassMembers.ts index 90ca3ff5671..6edb684caa6 100644 --- a/tests/cases/fourslash/commentsClassMembers.ts +++ b/tests/cases/fourslash/commentsClassMembers.ts @@ -8,11 +8,11 @@ //// public p/*3*/2(/** number to add*/b: number) { //// return this./*4*/p1 + /*5*/b; //// } -//// /** getter property*/ +//// /** getter property 1*/ //// public get p/*6*/3() { //// return this./*7*/p/*8q*/2(/*8*/this./*9*/p1); //// } -//// /** setter property*/ +//// /** setter property 1*/ //// public set p/*10*/3(/** this is value*/value: number) { //// this./*11*/p1 = this./*12*/p/*13q*/2(/*13*/value); //// } @@ -22,11 +22,11 @@ //// private p/*15*/p2(/** number to add*/b: number) { //// return this./*16*/p1 + /*17*/b; //// } -//// /** getter property*/ +//// /** getter property 2*/ //// private get p/*18*/p3() { //// return this./*19*/p/*20q*/p2(/*20*/this./*21*/pp1); //// } -//// /** setter property*/ +//// /** setter property 2*/ //// private set p/*22*/p3( /** this is value*/value: number) { //// this./*23*/pp1 = this./*24*/p/*25q*/p2(/*25*/value); //// } @@ -43,7 +43,7 @@ //// static get s/*32*/3() { //// return /*33*/c1./*34*/s/*35q*/2(/*35*/c1./*36*/s1); //// } -//// /** setter property*/ +//// /** setter property 3*/ //// static set s/*37*/3( /** this is value*/value: number) { //// /*38*/c1./*39*/s1 = /*40*/c1./*41*/s/*42q*/2(/*42*/value); //// } @@ -141,10 +141,10 @@ verify.quickInfos({ goTo.marker('4'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -155,15 +155,15 @@ verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); goTo.marker('5'); verify.completionListContains("b", "(parameter) b: number", "number to add"); -verify.quickInfoAt("6", "(property) c1.p3: number", "getter property\nsetter property"); +verify.quickInfoAt("6", "(property) c1.p3: number", "getter property 1\nsetter property 1"); goTo.marker('7'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -179,10 +179,10 @@ verify.quickInfoAt("8q", "(method) c1.p2(b: number): number", "sum with property goTo.marker('9'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -190,15 +190,15 @@ verify.memberListContains("nc_pp1", "(property) c1.nc_pp1: number", ""); verify.memberListContains("nc_pp2", "(method) c1.nc_pp2(b: number): number", ""); verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); -verify.quickInfoAt("10", "(property) c1.p3: number", "getter property\nsetter property"); +verify.quickInfoAt("10", "(property) c1.p3: number", "getter property 1\nsetter property 1"); goTo.marker('11'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -209,10 +209,10 @@ verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); goTo.marker('12'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -234,10 +234,10 @@ verify.quickInfos({ goTo.marker('16'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -248,15 +248,15 @@ verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); goTo.marker('17'); verify.completionListContains("b", "(parameter) b: number", "number to add"); -verify.quickInfoAt("18", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.quickInfoAt("18", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); goTo.marker('19'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -272,10 +272,10 @@ verify.quickInfoAt("20q", "(method) c1.pp2(b: number): number", "sum with proper goTo.marker('21'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -283,15 +283,15 @@ verify.memberListContains("nc_pp1", "(property) c1.nc_pp1: number", ""); verify.memberListContains("nc_pp2", "(method) c1.nc_pp2(b: number): number", ""); verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); -verify.quickInfoAt("22", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.quickInfoAt("22", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); goTo.marker('23'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -302,10 +302,10 @@ verify.memberListContains("nc_pp3", "(property) c1.nc_pp3: number", ""); goTo.marker('24'); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("pp1", "(property) c1.pp1: number", "pp1 is property of c1"); verify.memberListContains("pp2", "(method) c1.pp2(b: number): number", "sum with property"); -verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property\nsetter property"); +verify.memberListContains("pp3", "(property) c1.pp3: number", "getter property 2\nsetter property 2"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -331,7 +331,7 @@ verify.completionListContains("c1", "class c1", "This is comment for c1"); goTo.marker('30'); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); @@ -339,7 +339,7 @@ verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); goTo.marker('31'); verify.completionListContains("b", "(parameter) b: number", "number to add"); -verify.quickInfoAt("32", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.quickInfoAt("32", "(property) c1.s3: number", "static getter property\nsetter property 3"); goTo.marker('33'); verify.completionListContains("c1", "class c1", "This is comment for c1"); @@ -347,7 +347,7 @@ verify.completionListContains("c1", "class c1", "This is comment for c1"); goTo.marker('34'); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); @@ -361,12 +361,12 @@ verify.quickInfoAt("35q", "(method) c1.s2(b: number): number", "static sum with goTo.marker('36'); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); -verify.quickInfoAt("37", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.quickInfoAt("37", "(property) c1.s3: number", "static getter property\nsetter property 3"); goTo.marker('38'); verify.completionListContains("c1", "class c1", "This is comment for c1"); @@ -374,7 +374,7 @@ verify.completionListContains("c1", "class c1", "This is comment for c1"); goTo.marker('39'); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); @@ -385,7 +385,7 @@ verify.completionListContains("c1", "class c1", "This is comment for c1"); goTo.marker('41'); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); @@ -479,7 +479,7 @@ goTo.marker("67"); verify.quickInfoIs("(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p1", "(property) c1.p1: number", "p1 is property of c1"); verify.memberListContains("p2", "(method) c1.p2(b: number): number", "sum with property"); -verify.memberListContains("p3", "(property) c1.p3: number", "getter property\nsetter property"); +verify.memberListContains("p3", "(property) c1.p3: number", "getter property 1\nsetter property 1"); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", ""); verify.memberListContains("nc_p2", "(method) c1.nc_p2(b: number): number", ""); verify.memberListContains("nc_p3", "(property) c1.nc_p3: number", ""); @@ -497,8 +497,8 @@ verify.currentParameterHelpArgumentDocCommentIs("number to add"); verify.quickInfos({ "71q": ["(method) c1.p2(b: number): number", "sum with property"], 72: "var i1_prop: number", - 73: ["(property) c1.p3: number", "getter property\nsetter property"], - 74: ["(property) c1.p3: number", "getter property\nsetter property"], + 73: ["(property) c1.p3: number", "getter property 1\nsetter property 1"], + 74: ["(property) c1.p3: number", "getter property 1\nsetter property 1"], 75: "var i1_prop: number", 76: "var i1_nc_p: number", 77: "(property) c1.nc_p1: number", @@ -528,7 +528,7 @@ goTo.marker('88'); verify.quickInfoIs("(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s1", "(property) c1.s1: number", "s1 is static property of c1"); verify.memberListContains("s2", "(method) c1.s2(b: number): number", "static sum with property"); -verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property"); +verify.memberListContains("s3", "(property) c1.s3: number", "static getter property\nsetter property 3"); verify.memberListContains("nc_s1", "(property) c1.nc_s1: number", ""); verify.memberListContains("nc_s2", "(method) c1.nc_s2(b: number): number", ""); verify.memberListContains("nc_s3", "(property) c1.nc_s3: number", ""); @@ -546,8 +546,8 @@ verify.currentParameterHelpArgumentDocCommentIs("number to add"); verify.quickInfos({ "92q": ["(method) c1.s2(b: number): number", "static sum with property"], 93: "var i1_s_prop: number", - 94: ["(property) c1.s3: number", "static getter property\nsetter property"], - 95: ["(property) c1.s3: number", "static getter property\nsetter property"], + 94: ["(property) c1.s3: number", "static getter property\nsetter property 3"], + 95: ["(property) c1.s3: number", "static getter property\nsetter property 3"], 96: "var i1_s_prop: number", 97: "var i1_s_nc_p: number", 98: "(property) c1.nc_s1: number", @@ -605,8 +605,8 @@ verify.quickInfos({ }); goTo.marker('114'); -verify.memberListContains("a", "(property) cWithConstructorProperty.a: number", "more info about a"); -verify.quickInfoIs("(property) cWithConstructorProperty.a: number", "more info about a"); +verify.memberListContains("a", "(property) cWithConstructorProperty.a: number", "this is first parameter a\nmore info about a"); +verify.quickInfoIs("(property) cWithConstructorProperty.a: number", "this is first parameter a\nmore info about a"); goTo.marker('115'); verify.completionListContains("a", "(parameter) a: number", "this is first parameter a\nmore info about a"); diff --git a/tests/cases/fourslash/commentsCommentParsing.ts b/tests/cases/fourslash/commentsCommentParsing.ts index b2ed4e8a379..ce80fd519dd 100644 --- a/tests/cases/fourslash/commentsCommentParsing.ts +++ b/tests/cases/fourslash/commentsCommentParsing.ts @@ -48,7 +48,7 @@ ////} ////jsDocMi/*7q*/xedComments2(/*7*/); //// -/////** jsdoc comment */ /*** another jsDocComment*/ +/////** jsdoc comment */ /*** malformed jsDocComment*/ /////// Triple slash comment ////function jsDocMixedComments3() { ////} @@ -231,8 +231,8 @@ verify.currentSignatureHelpDocCommentIs("jsdoc comment \nanother jsDocComment"); verify.quickInfoAt("7q", "function jsDocMixedComments2(): void", "jsdoc comment \nanother jsDocComment"); goTo.marker('8'); -verify.currentSignatureHelpDocCommentIs("jsdoc comment \n* another jsDocComment"); -verify.quickInfoAt("8q", "function jsDocMixedComments3(): void", "jsdoc comment \n* another jsDocComment"); +verify.currentSignatureHelpDocCommentIs("jsdoc comment "); +verify.quickInfoAt("8q", "function jsDocMixedComments3(): void", "jsdoc comment "); goTo.marker('9'); verify.currentSignatureHelpDocCommentIs("jsdoc comment \nanother jsDocComment"); @@ -280,33 +280,33 @@ verify.completionListContains("a", "(parameter) a: number", "first number"); verify.completionListContains("b", "(parameter) b: number", "second number"); goTo.marker('19'); -verify.currentSignatureHelpDocCommentIs("This is multiplication function\n@anotherTag\n@anotherTag"); +verify.currentSignatureHelpDocCommentIs("This is multiplication function"); verify.currentParameterHelpArgumentDocCommentIs("first number"); verify.quickInfos({ "19q": [ "function multiply(a: number, b: number, c?: number, d?: any, e?: any): void", - "This is multiplication function\n@anotherTag\n@anotherTag" + "This is multiplication function" ], "19aq": ["(parameter) a: number", "first number"] }); goTo.marker('20'); -verify.currentSignatureHelpDocCommentIs("This is multiplication function\n@anotherTag\n@anotherTag"); +verify.currentSignatureHelpDocCommentIs("This is multiplication function"); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfoAt("20aq", "(parameter) b: number"); goTo.marker('21'); -verify.currentSignatureHelpDocCommentIs("This is multiplication function\n@anotherTag\n@anotherTag"); -verify.currentParameterHelpArgumentDocCommentIs("{"); -verify.quickInfoAt("21aq", "(parameter) c: number", "{"); +verify.currentSignatureHelpDocCommentIs("This is multiplication function"); +verify.currentParameterHelpArgumentDocCommentIs(""); +verify.quickInfoAt("21aq", "(parameter) c: number"); goTo.marker('22'); -verify.currentSignatureHelpDocCommentIs("This is multiplication function\n@anotherTag\n@anotherTag"); +verify.currentSignatureHelpDocCommentIs("This is multiplication function"); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfoAt("22aq", "(parameter) d: any"); goTo.marker('23'); -verify.currentSignatureHelpDocCommentIs("This is multiplication function\n@anotherTag\n@anotherTag"); +verify.currentSignatureHelpDocCommentIs("This is multiplication function"); verify.currentParameterHelpArgumentDocCommentIs("LastParam "); verify.quickInfoAt("23aq", "(parameter) e: any", "LastParam "); @@ -331,52 +331,52 @@ verify.quickInfos({ }); goTo.marker('27'); -verify.completionListContains("multiply", "function multiply(a: number, b: number, c?: number, d?: any, e?: any): void", "This is multiplication function\n@anotherTag\n@anotherTag"); +verify.completionListContains("multiply", "function multiply(a: number, b: number, c?: number, d?: any, e?: any): void", "This is multiplication function"); verify.completionListContains("f1", "function f1(a: number): any (+1 overload)", "fn f1 with number"); goTo.marker('28'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfos({ "28q": [ "function subtract(a: number, b: number, c?: () => string, d?: () => string, e?: () => string, f?: () => string): void", - "This is subtract function" + "This is subtract function{ () => string; } } f this is optional param f" ], "28aq": "(parameter) a: number" }); goTo.marker('29'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); verify.currentParameterHelpArgumentDocCommentIs("this is about b"); verify.quickInfoAt("29aq", "(parameter) b: number", "this is about b"); goTo.marker('30'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); verify.currentParameterHelpArgumentDocCommentIs("this is optional param c"); verify.quickInfoAt("30aq", "(parameter) c: () => string", "this is optional param c"); goTo.marker('31'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); -verify.currentParameterHelpArgumentDocCommentIs(""); -verify.quickInfoAt("31aq", "(parameter) d: () => string"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentParameterHelpArgumentDocCommentIs("this is optional param d"); +verify.quickInfoAt("31aq", "(parameter) d: () => string", "this is optional param d"); goTo.marker('32'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); verify.currentParameterHelpArgumentDocCommentIs("this is optional param e"); verify.quickInfoAt("32aq", "(parameter) e: () => string", "this is optional param e"); goTo.marker('33'); -verify.currentSignatureHelpDocCommentIs("This is subtract function"); +verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfoAt("33aq", "(parameter) f: () => string"); goTo.marker('34'); -verify.currentSignatureHelpDocCommentIs("this is square function\n@paramTag { number } a this is input number of paramTag\n@returnType { number } it is return type"); +verify.currentSignatureHelpDocCommentIs("this is square function"); verify.currentParameterHelpArgumentDocCommentIs("this is input number"); verify.quickInfos({ "34q": [ "function square(a: number): number", - "this is square function\n@paramTag { number } a this is input number of paramTag\n@returnType { number } it is return type" + "this is square function" ], "34aq": [ "(parameter) a: number", @@ -385,12 +385,12 @@ verify.quickInfos({ }); goTo.marker('35'); -verify.currentSignatureHelpDocCommentIs("this is divide function\n@paramTag { number } g this is optional param g"); +verify.currentSignatureHelpDocCommentIs("this is divide function"); verify.currentParameterHelpArgumentDocCommentIs("this is a"); verify.quickInfos({ "35q": [ "function divide(a: number, b: number): void", - "this is divide function\n@paramTag { number } g this is optional param g" + "this is divide function" ], "35aq": [ "(parameter) a: number", @@ -399,7 +399,7 @@ verify.quickInfos({ }); goTo.marker('36'); -verify.currentSignatureHelpDocCommentIs("this is divide function\n@paramTag { number } g this is optional param g"); +verify.currentSignatureHelpDocCommentIs("this is divide function"); verify.currentParameterHelpArgumentDocCommentIs("this is b"); verify.quickInfoAt("36aq", "(parameter) b: number", "this is b"); diff --git a/tests/cases/fourslash/commentsFunctionExpression.ts b/tests/cases/fourslash/commentsFunctionExpression.ts index 87da4c56168..65a061d1f91 100644 --- a/tests/cases/fourslash/commentsFunctionExpression.ts +++ b/tests/cases/fourslash/commentsFunctionExpression.ts @@ -60,23 +60,23 @@ verify.currentParameterHelpArgumentDocCommentIs("param b"); verify.quickInfos({ 7: "function anotherFunc(a: number): string", 8: ["(local var) lambdaVar: (b: string) => string", "documentation\ninner docs "], - 9: ["(parameter) b: string", "{string} inner parameter "], + 9: ["(parameter) b: string", "inner parameter "], 10: "(local var) localVar: string", 11: "(local var) localVar: string", - 12: ["(parameter) b: string", "{string} inner parameter "], + 12: ["(parameter) b: string", "inner parameter "], 13: ["(local var) lambdaVar: (b: string) => string", "documentation\ninner docs "], 14: [ "var assigned: (s: string) => number", - "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression" + "On variable\nSummary on expression" ] }); goTo.marker('15'); verify.completionListContains('s', '(parameter) s: string', "the first parameter!\nparam on expression\nOn parameter "); -verify.quickInfoAt("16", "var assigned: (s: string) => number", "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression"); +verify.quickInfoAt("16", "var assigned: (s: string) => number", "On variable\nSummary on expression"); goTo.marker('17'); -verify.completionListContains("assigned", "var assigned: (s: string) => number", "On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression"); +verify.completionListContains("assigned", "var assigned: (s: string) => number", "On variable\nSummary on expression"); goTo.marker('18'); -verify.currentSignatureHelpDocCommentIs("On variable\n@returns the parameter's length\nSummary on expression\n@returns return on expression"); +verify.currentSignatureHelpDocCommentIs("On variable\nSummary on expression"); verify.currentParameterHelpArgumentDocCommentIs("the first parameter!\nparam on expression\nOn parameter "); diff --git a/tests/cases/fourslash/commentsLinePreservation.ts b/tests/cases/fourslash/commentsLinePreservation.ts index 9ccfd5c26a9..6d085f71f80 100644 --- a/tests/cases/fourslash/commentsLinePreservation.ts +++ b/tests/cases/fourslash/commentsLinePreservation.ts @@ -111,19 +111,19 @@ verify.quickInfos({ b: ["var b: string", "This is firstLine\nThis is second Line\n\nThis is fourth Line"], c: ["var c: string", "This is firstLine\nThis is second Line\n\nThis is fourth Line"], - d: ["function d(param: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"], + d: ["function d(param: string): void", "This is firstLine\nThis is second Line"], 1: "(parameter) param: string", e: ["function e(param: string): void", "This is firstLine\nThis is second Line"], 2: "(parameter) param: string", - f: ["function f(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"], + f: ["function f(param1: string): void", "This is firstLine\nThis is second Line"], 3: ["(parameter) param1: string", "first line of param\n\nparam information third line"], - g: ["function g(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"], + g: ["function g(param1: string): void", "This is firstLine\nThis is second Line"], 4: ["(parameter) param1: string", "param information first line"], - h: ["function h(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"], + h: ["function h(param1: string): void", "This is firstLine\nThis is second Line"], 5: ["(parameter) param1: string", "param information first line\n\nparam information third line"], i: ["function i(param1: string): void", "This is firstLine\nThis is second Line"], @@ -132,7 +132,7 @@ verify.quickInfos({ j: ["function j(param1: string): void", "This is firstLine\nThis is second Line"], 7: ["(parameter) param1: string", "param information first line\n\nparam information third line"], - k: ["function k(param1: string): void", "This is firstLine\nThis is second Line\n@randomtag \n\n random information first line\n\n random information third line"], + k: ["function k(param1: string): void", "This is firstLine\nThis is second Line"], 8: ["(parameter) param1: string", "hello "], l: ["function l(param1: string): void", "This is firstLine\nThis is second Line"], diff --git a/tests/cases/fourslash/commentsModules.ts b/tests/cases/fourslash/commentsModules.ts index f56b009081a..5f9457d81f4 100644 --- a/tests/cases/fourslash/commentsModules.ts +++ b/tests/cases/fourslash/commentsModules.ts @@ -126,8 +126,8 @@ verify.memberListContains("c", "constructor m1.m2.c(): m1.m2.c", ""); verify.memberListContains("i", "var m1.m2.i: m1.m2.c", "i"); goTo.marker('9'); -verify.completionListContains("m2", "namespace m2", ""); -verify.quickInfoIs("namespace m2"); +verify.completionListContains("m2", "namespace m2", "namespace comment of m2.m3"); +verify.quickInfoIs("namespace m2", "namespace comment of m2.m3"); goTo.marker('10'); verify.memberListContains("m3", "namespace m2.m3"); @@ -138,12 +138,12 @@ verify.quickInfoIs("constructor m2.m3.c(): m2.m3.c"); verify.memberListContains("c", "constructor m2.m3.c(): m2.m3.c", ""); goTo.marker('12'); -verify.completionListContains("m3", "namespace m3", ""); -verify.quickInfoIs("namespace m3"); +verify.completionListContains("m3", "namespace m3", "namespace comment of m3.m4.m5"); +verify.quickInfoIs("namespace m3", "namespace comment of m3.m4.m5"); goTo.marker('13'); -verify.memberListContains("m4", "namespace m3.m4", ""); -verify.quickInfoIs("namespace m3.m4"); +verify.memberListContains("m4", "namespace m3.m4", "namespace comment of m3.m4.m5"); +verify.quickInfoIs("namespace m3.m4", "namespace comment of m3.m4.m5"); goTo.marker('14'); verify.memberListContains("m5", "namespace m3.m4.m5"); @@ -154,12 +154,12 @@ verify.quickInfoIs("constructor m3.m4.m5.c(): m3.m4.m5.c"); verify.memberListContains("c", "constructor m3.m4.m5.c(): m3.m4.m5.c", ""); goTo.marker('16'); -verify.completionListContains("m4", "namespace m4", ""); -verify.quickInfoIs("namespace m4"); +verify.completionListContains("m4", "namespace m4", "namespace comment of m4.m5.m6"); +verify.quickInfoIs("namespace m4", "namespace comment of m4.m5.m6"); goTo.marker('17'); -verify.memberListContains("m5", "namespace m4.m5", ""); -verify.quickInfoIs("namespace m4.m5"); +verify.memberListContains("m5", "namespace m4.m5", "namespace comment of m4.m5.m6"); +verify.quickInfoIs("namespace m4.m5", "namespace comment of m4.m5.m6"); goTo.marker('18'); verify.memberListContains("m6", "namespace m4.m5.m6"); @@ -175,11 +175,11 @@ verify.quickInfoIs("constructor m4.m5.m6.m7.c(): m4.m5.m6.m7.c"); goTo.marker('21'); verify.completionListContains("m5", "namespace m5"); -verify.quickInfoIs("namespace m5"); +verify.quickInfoIs("namespace m5", "namespace comment of m5.m6.m7"); goTo.marker('22'); verify.memberListContains("m6", "namespace m5.m6"); -verify.quickInfoIs("namespace m5.m6"); +verify.quickInfoIs("namespace m5.m6", "namespace comment of m5.m6.m7"); goTo.marker('23'); verify.memberListContains("m7", "namespace m5.m6.m7"); diff --git a/tests/cases/fourslash/getJavaScriptQuickInfo1.ts b/tests/cases/fourslash/getJavaScriptQuickInfo1.ts index b983ef0e4f0..95769764660 100644 --- a/tests/cases/fourslash/getJavaScriptQuickInfo1.ts +++ b/tests/cases/fourslash/getJavaScriptQuickInfo1.ts @@ -5,4 +5,4 @@ /////** @type {function(new:string,number)} */ ////var /**/v; -verify.quickInfoAt("", "var v: new (p1: number) => string", "@type {function(new:string,number)} "); +verify.quickInfoAt("", "var v: new (arg1: number) => string", undefined); diff --git a/tests/cases/fourslash/getJavaScriptQuickInfo7.ts b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts index 144e0ac11d4..cdf2027e3a6 100644 --- a/tests/cases/fourslash/getJavaScriptQuickInfo7.ts +++ b/tests/cases/fourslash/getJavaScriptQuickInfo7.ts @@ -17,4 +17,4 @@ //// x - /**/a1() verify.quickInfoAt("", "function a1(p: any): number", - "This is a very cool function that is very nice.\n@returns something"); + "This is a very cool function that is very nice."); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures10.ts b/tests/cases/fourslash/jsDocFunctionSignatures10.ts new file mode 100644 index 00000000000..60810c46e70 --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures10.ts @@ -0,0 +1,15 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * Do some foo things +//// * @template T A Foolish template +//// * @param {T} x a parameter +//// */ +////function foo(x) { +////} +//// +////fo/**/o() + +goTo.marker(); +verify.quickInfoIs("function foo(x: T): void", "Do some foo things"); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures11.ts b/tests/cases/fourslash/jsDocFunctionSignatures11.ts new file mode 100644 index 00000000000..26b2cda6d2a --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures11.ts @@ -0,0 +1,9 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * @type {{ [name: string]: string; }} variables +//// */ +////const vari/**/ables = {}; +goTo.marker(); +verify.quickInfoIs("const variables: {\n [name: string]: string;\n}"); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures12.ts b/tests/cases/fourslash/jsDocFunctionSignatures12.ts new file mode 100644 index 00000000000..29a8ac4caeb --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures12.ts @@ -0,0 +1,13 @@ + +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * @param {{ stringProp: string, +//// * numProp: number }} o +//// */ +////function f1(o) { +//// o/**/; +////} +goTo.marker(); +verify.quickInfoIs("(parameter) o: any"); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures2.ts b/tests/cases/fourslash/jsDocFunctionSignatures2.ts index 174ea7d6560..e6430cba5bd 100644 --- a/tests/cases/fourslash/jsDocFunctionSignatures2.ts +++ b/tests/cases/fourslash/jsDocFunctionSignatures2.ts @@ -9,4 +9,4 @@ //// f6('', /**/false) goTo.marker(); -verify.currentSignatureHelpIs('f6(p0: string, p1?: boolean): number') +verify.currentSignatureHelpIs('f6(arg0: string, arg1?: boolean): number') diff --git a/tests/cases/fourslash/jsDocFunctionSignatures5.ts b/tests/cases/fourslash/jsDocFunctionSignatures5.ts new file mode 100644 index 00000000000..08d0da990bc --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures5.ts @@ -0,0 +1,18 @@ +/// +// @allowJs: true +// @Filename: Foo.js + +/////** +//// * Filters a path based on a regexp or glob pattern. +//// * @param {String} basePath The base path where the search will be performed. +//// * @param {String} pattern A string defining a regexp of a glob pattern. +//// * @param {String} type The search pattern type, can be a regexp or a glob. +//// * @param {Object} options A object containing options to the search. +//// * @return {Array} A list containing the filtered paths. +//// */ +////function pathFilter(basePath, pattern, type, options){ +//////... +////} +////pathFilter(/**/'foo', 'bar', 'baz', {}); +goTo.marker(); +verify.currentSignatureHelpDocCommentIs("Filters a path based on a regexp or glob pattern."); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures6.ts b/tests/cases/fourslash/jsDocFunctionSignatures6.ts new file mode 100644 index 00000000000..10b290d6d02 --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures6.ts @@ -0,0 +1,19 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * @param {string} p1 - A string param +//// * @param {string?} p2 - An optional param +//// * @param {string} [p3] - Another optional param +//// * @param {string} [p4="test"] - An optional param with a default value +//// */ +////function f1(p1, p2, p3, p4){} +////f1(/*1*/'foo', /*2*/'bar', /*3*/'baz', /*4*/'qux'); +goTo.marker('1'); +verify.currentParameterHelpArgumentDocCommentIs("- A string param"); +goTo.marker('2'); +verify.currentParameterHelpArgumentDocCommentIs("- An optional param "); +goTo.marker('3'); +verify.currentParameterHelpArgumentDocCommentIs("- Another optional param"); +goTo.marker('4'); +verify.currentParameterHelpArgumentDocCommentIs("- An optional param with a default value"); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures7.ts b/tests/cases/fourslash/jsDocFunctionSignatures7.ts new file mode 100644 index 00000000000..6bbb8a34dcc --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures7.ts @@ -0,0 +1,16 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * @param {string} p0 +//// * @param {string} [p1] +//// */ +////function Test(p0, p1) { +//// this.P0 = p0; +//// this.P1 = p1; +////} +//// +//// +////var /**/test = new Test(""); +goTo.marker(); +verify.quickInfoIs('var test: {\n P0: string;\n P1: string;\n}'); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures8.ts b/tests/cases/fourslash/jsDocFunctionSignatures8.ts new file mode 100644 index 00000000000..3dbe38e34df --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures8.ts @@ -0,0 +1,16 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** +//// * Represents a person +//// * @constructor +//// * @param {string} name The name of the person +//// * @param {number} age The age of the person +//// */ +////function Person(name, age) { +//// this.name = name; +//// this.age = age; +////} +////var p = new Pers/**/on(); +goTo.marker(); +verify.quickInfoIs("function Person(name: string, age: number): void", "Represents a person"); diff --git a/tests/cases/fourslash/jsDocFunctionSignatures9.ts b/tests/cases/fourslash/jsDocFunctionSignatures9.ts new file mode 100644 index 00000000000..26361bfe106 --- /dev/null +++ b/tests/cases/fourslash/jsDocFunctionSignatures9.ts @@ -0,0 +1,22 @@ +/// +// @allowJs: true +// @Filename: Foo.js +/////** first line of the comment +//// +////third line */ +////function foo() {} +////foo/**/(); +goTo.marker(); +verify.verifyQuickInfoDisplayParts('function', + '', + { start: 63, length: 3 }, + [{"text": "function", "kind": "keyword"}, + {"text": " ", "kind": "space"}, + {"text": "foo", "kind": "functionName"}, + {"text": "(", "kind": "punctuation"}, + {"text": ")", "kind": "punctuation"}, + {"text": ":", "kind": "punctuation"}, + {"text": " ", "kind": "space"}, + {"text": "void", "kind": "keyword"} + ], + [{"text": "first line of the comment\n\nthird line ", "kind": "text"}]); diff --git a/tests/cases/fourslash/jsdocReturnsTag.ts b/tests/cases/fourslash/jsdocReturnsTag.ts new file mode 100644 index 00000000000..9203bd9e036 --- /dev/null +++ b/tests/cases/fourslash/jsdocReturnsTag.ts @@ -0,0 +1,17 @@ +/// +// @allowJs: true +// @Filename: dummy.js +/////** +//// * Find an item +//// * @template T +//// * @param {T[]} l +//// * @param {T} x +//// * @returns {?T} The names of the found item(s). +//// */ +////function find(l, x) { +////} +////find(''/**/); + +goTo.marker(); +verify.currentSignatureHelpIs("find(l: T[], x: T): T") +// There currently isn't a way to display the return tag comment