Skip to content

Commit 4db5d97

Browse files
committed
Parse comments as string when no @link occurs
1 parent 8de1fe9 commit 4db5d97

30 files changed

+113
-488
lines changed

src/compiler/emitter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3707,7 +3707,7 @@ namespace ts {
37073707
emit(tagName);
37083708
}
37093709

3710-
function emitJSDocComment(comment: NodeArray<JSDocText | JSDocLink> | undefined) {
3710+
function emitJSDocComment(comment: string | NodeArray<JSDocText | JSDocLink> | undefined) {
37113711
const text = getTextOfJSDocComment(comment);
37123712
if (text) {
37133713
writeSpace();

src/compiler/factory/nodeFactory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4243,7 +4243,7 @@ namespace ts {
42434243
function createBaseJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: Identifier, comment: string | NodeArray<JSDocText | JSDocLink> | undefined) {
42444244
const node = createBaseNode<T>(kind);
42454245
node.tagName = tagName;
4246-
node.comment = typeof comment === "string" ? createNodeArray([createJSDocText(comment)]) : comment;
4246+
node.comment = comment;
42474247
return node;
42484248
}
42494249

@@ -4507,7 +4507,7 @@ namespace ts {
45074507
// @api
45084508
function createJSDocComment(comment?: string | NodeArray<JSDocText | JSDocLink> | undefined, tags?: readonly JSDocTag[] | undefined) {
45094509
const node = createBaseNode<JSDoc>(SyntaxKind.JSDocComment);
4510-
node.comment = typeof comment === "string" ? createNodeArray([createJSDocText(comment)]) : comment;
4510+
node.comment = comment;
45114511
node.tags = asNodeArray(tags);
45124512
return node;
45134513
}

src/compiler/parser.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,12 @@ namespace ts {
481481
return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) ||
482482
visitNode(cbNode, (<JSDocFunctionType>node).type);
483483
case SyntaxKind.JSDocComment:
484-
return visitNodes(cbNode, cbNodes, (node as JSDoc).comment)
484+
return (typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined))
485485
|| visitNodes(cbNode, cbNodes, (node as JSDoc).tags);
486486
case SyntaxKind.JSDocSeeTag:
487487
return visitNode(cbNode, (node as JSDocSeeTag).tagName) ||
488488
visitNode(cbNode, (node as JSDocSeeTag).name) ||
489-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
489+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
490490
case SyntaxKind.JSDocNameReference:
491491
return visitNode(cbNode, (node as JSDocNameReference).name);
492492
case SyntaxKind.JSDocParameterTag:
@@ -495,47 +495,48 @@ namespace ts {
495495
((node as JSDocPropertyLikeTag).isNameFirst
496496
? visitNode(cbNode, (<JSDocPropertyLikeTag>node).name) ||
497497
visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) ||
498-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment)
498+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined))
499499
: visitNode(cbNode, (<JSDocPropertyLikeTag>node).typeExpression) ||
500500
visitNode(cbNode, (<JSDocPropertyLikeTag>node).name)) ||
501-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
501+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
502502
case SyntaxKind.JSDocAuthorTag:
503-
return visitNode(cbNode, (node as JSDocTag).tagName);
503+
return visitNode(cbNode, (node as JSDocTag).tagName) ||
504+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
504505
case SyntaxKind.JSDocImplementsTag:
505506
return visitNode(cbNode, (node as JSDocTag).tagName) ||
506507
visitNode(cbNode, (<JSDocImplementsTag>node).class) ||
507-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
508+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
508509
case SyntaxKind.JSDocAugmentsTag:
509510
return visitNode(cbNode, (node as JSDocTag).tagName) ||
510511
visitNode(cbNode, (<JSDocAugmentsTag>node).class) ||
511-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
512+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
512513
case SyntaxKind.JSDocTemplateTag:
513514
return visitNode(cbNode, (node as JSDocTag).tagName) ||
514515
visitNode(cbNode, (<JSDocTemplateTag>node).constraint) ||
515516
visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters) ||
516-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
517+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
517518
case SyntaxKind.JSDocTypedefTag:
518519
return visitNode(cbNode, (node as JSDocTag).tagName) ||
519520
((node as JSDocTypedefTag).typeExpression &&
520521
(node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression
521522
? visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
522523
visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
523-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment)
524+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined))
524525
: visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
525526
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression)) ||
526-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
527+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
527528
case SyntaxKind.JSDocCallbackTag:
528529
return visitNode(cbNode, (node as JSDocTag).tagName) ||
529530
visitNode(cbNode, (node as JSDocCallbackTag).fullName) ||
530531
visitNode(cbNode, (node as JSDocCallbackTag).typeExpression) ||
531-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
532+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
532533
case SyntaxKind.JSDocReturnTag:
533534
case SyntaxKind.JSDocTypeTag:
534535
case SyntaxKind.JSDocThisTag:
535536
case SyntaxKind.JSDocEnumTag:
536537
return visitNode(cbNode, (node as JSDocTag).tagName) ||
537538
visitNode(cbNode, (node as JSDocReturnTag | JSDocTypeTag | JSDocThisTag | JSDocEnumTag).typeExpression) ||
538-
visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
539+
(typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
539540
case SyntaxKind.JSDocSignature:
540541
return forEach((<JSDocSignature>node).typeParameters, cbNode) ||
541542
forEach((<JSDocSignature>node).parameters, cbNode) ||
@@ -551,7 +552,7 @@ namespace ts {
551552
case SyntaxKind.JSDocProtectedTag:
552553
case SyntaxKind.JSDocReadonlyTag:
553554
return visitNode(cbNode, (node as JSDocTag).tagName)
554-
|| visitNodes(cbNode, cbNodes, (node as JSDocTag).comment);
555+
|| (typeof (node as JSDoc).comment === "string" ? undefined : visitNodes(cbNode, cbNodes, (node as JSDoc).comment as NodeArray<JSDocText | JSDocLink> | undefined));
555556
case SyntaxKind.PartiallyEmittedExpression:
556557
return visitNode(cbNode, (<PartiallyEmittedExpression>node).expression);
557558
}
@@ -7412,6 +7413,7 @@ namespace ts {
74127413
state = JSDocState.SavingComments;
74137414
const commentEnd = scanner.getStartPos();
74147415
const linkStart = scanner.getTextPos() - 1;
7416+
// TODO: redo here
74157417
const link = parseJSDocLink(linkStart);
74167418
if (link) {
74177419
if (!linkEnd) {
@@ -7435,12 +7437,12 @@ namespace ts {
74357437
nextTokenJSDoc();
74367438
}
74377439
removeTrailingWhitespace(comments);
7438-
if (comments.length) {
7440+
if (parts.length && comments.length) {
74397441
parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? start, commentsPos));
74407442
}
74417443
if (parts.length && tags) Debug.assertIsDefined(commentsPos, "having parsed tags implies that the end of the comment span should be set");
74427444
const tagsArray = tags && createNodeArray(tags, tagsPos, tagsEnd);
7443-
return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : undefined, tagsArray), start, end);
7445+
return finishNode(factory.createJSDocComment(parts.length ? createNodeArray(parts, start, commentsPos) : comments.length ? comments.join("") : undefined, tagsArray), start, end);
74447446
});
74457447

74467448
function removeLeadingNewlines(comments: string[]) {
@@ -7588,7 +7590,7 @@ namespace ts {
75887590
return parseTagComments(margin, indentText.slice(margin));
75897591
}
75907592

7591-
function parseTagComments(indent: number, initialMargin?: string): NodeArray<JSDocText | JSDocLink> | undefined {
7593+
function parseTagComments(indent: number, initialMargin?: string): string | NodeArray<JSDocText | JSDocLink> | undefined {
75927594
const commentsPos = getNodePos();
75937595
let comments: string[] = [];
75947596
const parts: (JSDocLink | JSDocText)[] = [];
@@ -7689,12 +7691,15 @@ namespace ts {
76897691

76907692
removeLeadingNewlines(comments);
76917693
removeTrailingWhitespace(comments);
7692-
if (comments.length) {
7693-
parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos));
7694-
}
76957694
if (parts.length) {
7695+
if (comments.length) {
7696+
parts.push(finishNode(factory.createJSDocText(comments.join("")), linkEnd ?? commentsPos));
7697+
}
76967698
return createNodeArray(parts, commentsPos, scanner.getTextPos());
76977699
}
7700+
else if (comments.length) {
7701+
return comments.join("");
7702+
}
76987703
}
76997704

77007705
function parseJSDocLink(start: number) {
@@ -7858,8 +7863,10 @@ namespace ts {
78587863
if (!comments) {
78597864
commentEnd = scanner.getStartPos();
78607865
}
7861-
const allParts = concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as (JSDocText | JSDocLink)[]; // cast away readonly
7862-
return finishNode(factory.createJSDocAuthorTag(tagName, createNodeArray(allParts, commentStart)), start);
7866+
const allParts = typeof comments !== "string"
7867+
? createNodeArray(concatenate([finishNode(textOnly, commentStart, commentEnd)], comments) as (JSDocText | JSDocLink)[], commentStart) // cast away readonly
7868+
: textOnly.text + comments;
7869+
return finishNode(factory.createJSDocAuthorTag(tagName, allParts), start);
78637870
}
78647871

78657872
function parseAuthorNameAndEmail(): JSDocText {
@@ -7918,7 +7925,7 @@ namespace ts {
79187925
return node;
79197926
}
79207927

7921-
function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: NodeArray<JSDocText | JSDocLink>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag {
7928+
function parseSimpleTag(start: number, createTag: (tagName: Identifier | undefined, comment?: string | NodeArray<JSDocText | JSDocLink>) => JSDocTag, tagName: Identifier, margin: number, indentText: string): JSDocTag {
79227929
return finishNode(createTag(tagName, parseTrailingTagComments(start, getNodePos(), margin, indentText)), start);
79237930
}
79247931

src/compiler/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,13 +3135,13 @@ namespace ts {
31353135
readonly kind: SyntaxKind.JSDocComment;
31363136
readonly parent: HasJSDoc;
31373137
readonly tags?: NodeArray<JSDocTag>;
3138-
readonly comment?: NodeArray<JSDocText | JSDocLink>;
3138+
readonly comment?: string | NodeArray<JSDocText | JSDocLink>;
31393139
}
31403140

31413141
export interface JSDocTag extends Node {
31423142
readonly parent: JSDoc | JSDocTypeLiteral;
31433143
readonly tagName: Identifier;
3144-
readonly comment?: NodeArray<JSDocText | JSDocLink>;
3144+
readonly comment?: string | NodeArray<JSDocText | JSDocLink>;
31453145
}
31463146

31473147
export interface JSDocLink extends Node {

src/compiler/utilitiesPublic.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,10 @@ namespace ts {
897897
}
898898

899899
/** Gets the text of a jsdoc comment, flattening links to their text. */
900-
export function getTextOfJSDocComment(comment?: NodeArray<JSDocText | JSDocLink>) {
901-
return comment?.map(c => c.kind === SyntaxKind.JSDocText ? c.text : `{@link ${c.name ? entityNameToString(c.name) + " " : ""}${c.text}}`).join("");
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("");
902904
}
903905

904906
/**

src/services/classifier.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,27 +722,58 @@ namespace ts {
722722
pushClassification(tag.tagName.pos, tag.tagName.end - tag.tagName.pos, ClassificationType.docCommentTagName); // e.g. "param"
723723

724724
pos = tag.tagName.end;
725+
let commentStart = tag.tagName.end;
725726

726727
switch (tag.kind) {
727728
case SyntaxKind.JSDocParameterTag:
728-
processJSDocParameterTag(<JSDocParameterTag>tag);
729+
const param = tag as JSDocParameterTag;
730+
processJSDocParameterTag(param);
731+
commentStart = param.isNameFirst && param.typeExpression?.end || param.name.end;
732+
break;
733+
case SyntaxKind.JSDocPropertyTag:
734+
const prop = tag as JSDocPropertyTag;
735+
commentStart = prop.isNameFirst && prop.typeExpression?.end || prop.name.end;
729736
break;
730737
case SyntaxKind.JSDocTemplateTag:
731738
processJSDocTemplateTag(<JSDocTemplateTag>tag);
732739
pos = tag.end;
740+
commentStart = (tag as JSDocTemplateTag).typeParameters.end;
741+
break;
742+
case SyntaxKind.JSDocTypedefTag:
743+
const type = tag as JSDocTypedefTag;
744+
commentStart = type.typeExpression?.kind === SyntaxKind.JSDocTypeExpression && type.fullName?.end || type.typeExpression?.end || commentStart;
745+
break;
746+
case SyntaxKind.JSDocCallbackTag:
747+
commentStart = (tag as JSDocCallbackTag).typeExpression.end;
733748
break;
734749
case SyntaxKind.JSDocTypeTag:
735750
processElement((<JSDocTypeTag>tag).typeExpression);
736751
pos = tag.end;
752+
commentStart = (tag as JSDocTypeTag).typeExpression.end;
753+
break;
754+
case SyntaxKind.JSDocThisTag:
755+
case SyntaxKind.JSDocEnumTag:
756+
commentStart = (tag as JSDocThisTag | JSDocEnumTag).typeExpression.end;
737757
break;
738758
case SyntaxKind.JSDocReturnTag:
739759
processElement((<JSDocReturnTag>tag).typeExpression);
740760
pos = tag.end;
761+
commentStart = (tag as JSDocReturnTag).typeExpression?.end || commentStart;
762+
break;
763+
case SyntaxKind.JSDocSeeTag:
764+
commentStart = (tag as JSDocSeeTag).name?.end || commentStart;
765+
break;
766+
case SyntaxKind.JSDocAugmentsTag:
767+
case SyntaxKind.JSDocImplementsTag:
768+
commentStart = (tag as JSDocImplementsTag | JSDocAugmentsTag).class.end;
741769
break;
742770
}
743-
if (tag.comment) {
771+
if (typeof tag.comment === "object") {
744772
pushCommentRange(tag.comment.pos, tag.comment.end - tag.comment.pos);
745773
}
774+
else if (typeof tag.comment === "string") {
775+
pushCommentRange(commentStart, tag.end - commentStart);
776+
}
746777
}
747778
}
748779

src/services/codefixes/inferFromUsage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ namespace ts.codefix {
380380
}
381381

382382
export function addJSDocTags(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parent: HasJSDoc, newTags: readonly JSDocTag[]): void {
383-
const comments = flatMap(parent.jsDoc, j => j.comment) as (JSDocText | JSDocLink)[];
383+
const comments = flatMap(parent.jsDoc, j => typeof j.comment === 'string' ? factory.createJSDocText(j.comment) : j.comment) as (JSDocText | JSDocLink)[];
384384
const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags);
385385
const unmergedNewTags = newTags.filter(newTag => !oldTags || !oldTags.some((tag, i) => {
386386
const merged = tryMergeJsdocTags(tag, newTag);

0 commit comments

Comments
 (0)