Skip to content

Commit dcc27eb

Browse files
authored
@link support, second try (#43312)
* Revert "Revert "Editor support for link tag (#41877)" (#43302)" This reverts commit 451d435. * Fix parsing @link at end of comment * Parse comments as string when no @link occurs * fix lint
1 parent 4622718 commit dcc27eb

File tree

145 files changed

+20102
-1575
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+20102
-1575
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5190,7 +5190,7 @@ namespace ts {
51905190
function preserveCommentsOn<T extends Node>(node: T) {
51915191
if (some(propertySymbol.declarations, d => d.kind === SyntaxKind.JSDocPropertyTag)) {
51925192
const d = propertySymbol.declarations?.find(d => d.kind === SyntaxKind.JSDocPropertyTag)! as JSDocPropertyTag;
5193-
const commentText = d.comment;
5193+
const commentText = getTextOfJSDocComment(d.comment);
51945194
if (commentText) {
51955195
setSyntheticLeadingComments(node, [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]);
51965196
}
@@ -6705,7 +6705,7 @@ namespace ts {
67056705
const typeParams = getSymbolLinks(symbol).typeParameters;
67066706
const typeParamDecls = map(typeParams, p => typeParameterToDeclaration(p, context));
67076707
const jsdocAliasDecl = symbol.declarations?.find(isJSDocTypeAlias);
6708-
const commentText = jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined;
6708+
const commentText = getTextOfJSDocComment(jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined);
67096709
const oldFlags = context.flags;
67106710
context.flags |= NodeBuilderFlags.InTypeAlias;
67116711
const oldEnclosingDecl = context.enclosingDeclaration;
@@ -38673,6 +38673,10 @@ namespace ts {
3867338673
const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value;
3867438674
return resolveEntityName(<EntityName>name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name));
3867538675
}
38676+
else if (isJSDocLink(name.parent)) {
38677+
const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value;
38678+
return resolveEntityName(<EntityName>name, meaning, /*ignoreErrors*/ true);
38679+
}
3867638680

3867738681
if (name.parent.kind === SyntaxKind.TypePredicate) {
3867838682
return resolveEntityName(<Identifier>name, /*meaning*/ SymbolFlags.FunctionScopedVariable);

src/compiler/emitter.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3565,13 +3565,16 @@ namespace ts {
35653565
function emitJSDoc(node: JSDoc) {
35663566
write("/**");
35673567
if (node.comment) {
3568-
const lines = node.comment.split(/\r\n?|\n/g);
3569-
for (const line of lines) {
3570-
writeLine();
3571-
writeSpace();
3572-
writePunctuation("*");
3573-
writeSpace();
3574-
write(line);
3568+
const text = getTextOfJSDocComment(node.comment);
3569+
if (text) {
3570+
const lines = text.split(/\r\n?|\n/g);
3571+
for (const line of lines) {
3572+
writeLine();
3573+
writeSpace();
3574+
writePunctuation("*");
3575+
writeSpace();
3576+
write(line);
3577+
}
35753578
}
35763579
}
35773580
if (node.tags) {
@@ -3704,10 +3707,11 @@ namespace ts {
37043707
emit(tagName);
37053708
}
37063709

3707-
function emitJSDocComment(comment: string | undefined) {
3708-
if (comment) {
3710+
function emitJSDocComment(comment: string | NodeArray<JSDocText | JSDocLink> | undefined) {
3711+
const text = getTextOfJSDocComment(comment);
3712+
if (text) {
37093713
writeSpace();
3710-
write(comment);
3714+
write(text);
37113715
}
37123716
}
37133717

src/compiler/factory/nodeFactory.ts

Lines changed: 62 additions & 29 deletions
Large diffs are not rendered by default.

src/compiler/factory/nodeTests.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,10 @@ namespace ts {
770770
return node.kind === SyntaxKind.JSDocNameReference;
771771
}
772772

773+
export function isJSDocLink(node: Node): node is JSDocLink {
774+
return node.kind === SyntaxKind.JSDocLink;
775+
}
776+
773777
export function isJSDocAllType(node: Node): node is JSDocAllType {
774778
return node.kind === SyntaxKind.JSDocAllType;
775779
}

src/compiler/parser.ts

Lines changed: 138 additions & 63 deletions
Large diffs are not rendered by default.

src/compiler/types.ts

Lines changed: 61 additions & 44 deletions
Large diffs are not rendered by default.

src/compiler/utilitiesPublic.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,13 @@ namespace ts {
896896
return getJSDocTags(node).filter(doc => doc.kind === kind);
897897
}
898898

899+
/** Gets the text of a jsdoc comment, flattening links to their text. */
900+
export function getTextOfJSDocComment(comment?: string | NodeArray<JSDocText | JSDocLink>) {
901+
return typeof comment === "string" ? comment
902+
: comment?.map(c =>
903+
c.kind === SyntaxKind.JSDocText ? c.text : `{@link ${c.name ? entityNameToString(c.name) + " " : ""}${c.text}}`).join("");
904+
}
905+
899906
/**
900907
* Gets the effective type parameters. If the node was parsed in a
901908
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
@@ -1860,7 +1867,13 @@ namespace ts {
18601867

18611868
/** True if node is of a kind that may contain comment text. */
18621869
export function isJSDocCommentContainingNode(node: Node): boolean {
1863-
return node.kind === SyntaxKind.JSDocComment || node.kind === SyntaxKind.JSDocNamepathType || isJSDocTag(node) || isJSDocTypeLiteral(node) || isJSDocSignature(node);
1870+
return node.kind === SyntaxKind.JSDocComment
1871+
|| node.kind === SyntaxKind.JSDocNamepathType
1872+
|| node.kind === SyntaxKind.JSDocText
1873+
|| node.kind === SyntaxKind.JSDocLink
1874+
|| isJSDocTag(node)
1875+
|| isJSDocTypeLiteral(node)
1876+
|| isJSDocSignature(node);
18641877
}
18651878

18661879
// TODO: determine what this does before making it public.

src/deprecatedCompat/deprecations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ namespace ts {
12291229

12301230
/** @deprecated Use `factory.createJSDocParameterTag` or the factory supplied by your transformation context instead. */
12311231
export const createJSDocParamTag = Debug.deprecate(function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
1232-
return factory.createJSDocParameterTag(/*tagName*/ undefined, name, isBracketed, typeExpression, /*isNameFirst*/ false, comment);
1232+
return factory.createJSDocParameterTag(/*tagName*/ undefined, name, isBracketed, typeExpression, /*isNameFirst*/ false, comment ? factory.createNodeArray([factory.createJSDocText(comment)]) : undefined);
12331233
}, factoryDeprecation);
12341234

12351235
/** @deprecated Use `factory.createComma` or the factory supplied by your transformation context instead. */
@@ -1374,4 +1374,4 @@ namespace ts {
13741374
});
13751375

13761376
// #endregion Renamed node Tests
1377-
}
1377+
}

src/harness/client.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ namespace ts.server {
175175
kindModifiers: body.kindModifiers,
176176
textSpan: this.decodeSpan(body, fileName),
177177
displayParts: [{ kind: "text", text: body.displayString }],
178-
documentation: [{ kind: "text", text: body.documentation }],
179-
tags: body.tags
178+
documentation: typeof body.documentation === "string" ? [{ kind: "text", text: body.documentation }] : body.documentation,
179+
tags: this.decodeLinkDisplayParts(body.tags)
180180
};
181181
}
182182

@@ -536,6 +536,13 @@ namespace ts.server {
536536
this.lineOffsetToPosition(fileName, span.end, lineMap));
537537
}
538538

539+
private decodeLinkDisplayParts(tags: (protocol.JSDocTagInfo | JSDocTagInfo)[]): JSDocTagInfo[] {
540+
return tags.map(tag => typeof tag.text === "string" ? {
541+
...tag,
542+
text: [textPart(tag.text)]
543+
} : (tag as JSDocTagInfo));
544+
}
545+
539546
getNameOrDottedNameSpan(_fileName: string, _startPos: number, _endPos: number): TextSpan {
540547
return notImplemented();
541548
}
@@ -554,9 +561,10 @@ namespace ts.server {
554561
return undefined;
555562
}
556563

557-
const { items, applicableSpan: encodedApplicableSpan, selectedItemIndex, argumentIndex, argumentCount } = response.body;
564+
const { items: encodedItems, applicableSpan: encodedApplicableSpan, selectedItemIndex, argumentIndex, argumentCount } = response.body;
558565

559-
const applicableSpan = this.decodeSpan(encodedApplicableSpan, fileName);
566+
const applicableSpan = encodedApplicableSpan as unknown as TextSpan;
567+
const items = (encodedItems as (SignatureHelpItem | protocol.SignatureHelpItem)[]).map(item => ({ ...item, tags: this.decodeLinkDisplayParts(item.tags) }));
560568

561569
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
562570
}

src/harness/fourslashImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,7 @@ namespace FourSlash {
15831583
assert.equal(actualTags.length, (options.tags || ts.emptyArray).length, this.assertionMessageAtLastKnownMarker("signature help tags"));
15841584
ts.zipWith((options.tags || ts.emptyArray), actualTags, (expectedTag, actualTag) => {
15851585
assert.equal(actualTag.name, expectedTag.name);
1586-
assert.equal(actualTag.text, expectedTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name));
1586+
assert.deepEqual(actualTag.text, expectedTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name));
15871587
});
15881588

15891589
const allKeys: readonly (keyof FourSlashInterface.VerifySignatureHelpOptions)[] = [

0 commit comments

Comments
 (0)