Skip to content

Commit ee5f51b

Browse files
Kingwlamcaseytypescript-botwyzecherryblossom000
authored
Add see tag support (#39760)
* Add see tag parser * add baseline * fix symbol resolve * add more case * fix unittests * improve tests and parser * accept baseline * Adopt package-lock.json and npm ci * Add a workflow to update package-lock.json daily * Git ignore package-lock.json and forcibly update in workflow * Update bot email address * Delete extra npm update * Update package-lock.json * Add compactDisplay and signDisplay to NumberFormatOptions (#40039) * Fix typo in (Readonly)Set.keys comment (fixes #40164) (#40176) * fix(26325): use a unique name for reserved words in 'constructor like' function name (#39684) * fix(25770): add diagnostic message for the possible mapped type used as an index (#39973) * fix(31046): add new diagnostic message for incompatible constructor signature (#40073) * Update package-lock.json * Update package-lock.json * Add rename support * Accpet baseline * wip * fix anders * Revert "fix anders" This reverts commit b3178d4. * Fix call hierarchy item serialization and server tests (#40348) * Avoid error * accept baseline * Add more tests * Add signature name resolve Co-authored-by: Andrew Casey <[email protected]> Co-authored-by: TypeScript Bot <[email protected]> Co-authored-by: Neil Kistner <[email protected]> Co-authored-by: cherryblossom000 <[email protected]> Co-authored-by: Alexander T <[email protected]> Co-authored-by: Erich Gamma <[email protected]> Co-authored-by: Andrew Branch <[email protected]>
1 parent 4584d6d commit ee5f51b

25 files changed

+634
-109
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36425,6 +36425,17 @@ namespace ts {
3642536425
return node.parent.kind === SyntaxKind.ExpressionWithTypeArguments;
3642636426
}
3642736427

36428+
function isJSDocEntryNameReference(node: Identifier | PrivateIdentifier | PropertyAccessExpression | QualifiedName): boolean {
36429+
while (node.parent.kind === SyntaxKind.QualifiedName) {
36430+
node = node.parent as QualifiedName;
36431+
}
36432+
while (node.parent.kind === SyntaxKind.PropertyAccessExpression) {
36433+
node = node.parent as PropertyAccessExpression;
36434+
}
36435+
36436+
return node.parent.kind === SyntaxKind.JSDocNameReference;
36437+
}
36438+
3642836439
function forEachEnclosingClass<T>(node: Node, callback: (node: Node) => T | undefined): T | undefined {
3642936440
let result: T | undefined;
3643036441

@@ -36609,6 +36620,10 @@ namespace ts {
3660936620
const meaning = name.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
3661036621
return resolveEntityName(<EntityName>name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true);
3661136622
}
36623+
else if (isJSDocEntryNameReference(name)) {
36624+
const meaning = SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Value;
36625+
return resolveEntityName(<EntityName>name, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true, getHostSignatureFromJSDoc(name));
36626+
}
3661236627

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

src/compiler/emitter.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,10 @@ namespace ts {
15481548
case SyntaxKind.JSDocClassTag:
15491549
case SyntaxKind.JSDocTag:
15501550
return emitJSDocSimpleTag(node as JSDocTag);
1551+
case SyntaxKind.JSDocSeeTag:
1552+
return emitJSDocSeeTag(node as JSDocSeeTag);
1553+
case SyntaxKind.JSDocNameReference:
1554+
return emitJSDocNameReference(node as JSDocNameReference);
15511555

15521556
case SyntaxKind.JSDocComment:
15531557
return emitJSDoc(node as JSDoc);
@@ -3503,6 +3507,19 @@ namespace ts {
35033507
emitJSDocComment(tag.comment);
35043508
}
35053509

3510+
function emitJSDocSeeTag(tag: JSDocSeeTag) {
3511+
emitJSDocTagName(tag.tagName);
3512+
emit(tag.name);
3513+
emitJSDocComment(tag.comment);
3514+
}
3515+
3516+
function emitJSDocNameReference(node: JSDocNameReference) {
3517+
writeSpace();
3518+
writePunctuation("{");
3519+
emit(node.name);
3520+
writePunctuation("}");
3521+
}
3522+
35063523
function emitJSDocHeritageTag(tag: JSDocImplementsTag | JSDocAugmentsTag) {
35073524
emitJSDocTagName(tag.tagName);
35083525
writeSpace();

src/compiler/factory/nodeFactory.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,10 @@ namespace ts {
337337
updateJSDocAugmentsTag,
338338
createJSDocImplementsTag,
339339
updateJSDocImplementsTag,
340+
createJSDocSeeTag,
341+
updateJSDocSeeTag,
342+
createJSDocNameReference,
343+
updateJSDocNameReference,
340344
// lazily load factory members for JSDoc tags with similar structure
341345
get createJSDocTypeTag() { return getJSDocTypeLikeTagCreateFunction<JSDocTypeTag>(SyntaxKind.JSDocTypeTag); },
342346
get updateJSDocTypeTag() { return getJSDocTypeLikeTagUpdateFunction<JSDocTypeTag>(SyntaxKind.JSDocTypeTag); },
@@ -4259,6 +4263,36 @@ namespace ts {
42594263
return node;
42604264
}
42614265

4266+
// @api
4267+
function createJSDocSeeTag(tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string): JSDocSeeTag {
4268+
const node = createBaseJSDocTag<JSDocSeeTag>(SyntaxKind.JSDocSeeTag, tagName ?? createIdentifier("see"), comment);
4269+
node.name = name;
4270+
return node;
4271+
}
4272+
4273+
// @api
4274+
function updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, name: JSDocNameReference | undefined, comment?: string): JSDocSeeTag {
4275+
return node.tagName !== tagName
4276+
|| node.name !== name
4277+
|| node.comment !== comment
4278+
? update(createJSDocSeeTag(tagName, name, comment), node)
4279+
: node;
4280+
}
4281+
4282+
// @api
4283+
function createJSDocNameReference(name: EntityName): JSDocNameReference {
4284+
const node = createBaseNode<JSDocNameReference>(SyntaxKind.JSDocNameReference);
4285+
node.name = name;
4286+
return node;
4287+
}
4288+
4289+
// @api
4290+
function updateJSDocNameReference(node: JSDocNameReference, name: EntityName): JSDocNameReference {
4291+
return node.name !== name
4292+
? update(createJSDocNameReference(name), node)
4293+
: node;
4294+
}
4295+
42624296
// @api
42634297
function updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier = getDefaultTagName(node), className: JSDocImplementsTag["class"], comment: string | undefined): JSDocImplementsTag {
42644298
return node.tagName !== tagName

src/compiler/factory/nodeTests.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,10 @@ namespace ts {
695695
return node.kind === SyntaxKind.JSDocTypeExpression;
696696
}
697697

698+
export function isJSDocNameReference(node: Node): node is JSDocNameReference {
699+
return node.kind === SyntaxKind.JSDocNameReference;
700+
}
701+
698702
export function isJSDocAllType(node: Node): node is JSDocAllType {
699703
return node.kind === SyntaxKind.JSDocAllType;
700704
}

src/compiler/parser.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,11 @@ namespace ts {
477477
visitNode(cbNode, (<JSDocFunctionType>node).type);
478478
case SyntaxKind.JSDocComment:
479479
return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
480+
case SyntaxKind.JSDocSeeTag:
481+
return visitNode(cbNode, (node as JSDocSeeTag).tagName) ||
482+
visitNode(cbNode, (node as JSDocSeeTag).name);
483+
case SyntaxKind.JSDocNameReference:
484+
return visitNode(cbNode, (node as JSDocNameReference).name);
480485
case SyntaxKind.JSDocParameterTag:
481486
case SyntaxKind.JSDocPropertyTag:
482487
return visitNode(cbNode, (node as JSDocTag).tagName) ||
@@ -7150,6 +7155,19 @@ namespace ts {
71507155
return finishNode(result, pos);
71517156
}
71527157

7158+
export function parseJSDocNameReference(): JSDocNameReference {
7159+
const pos = getNodePos();
7160+
const hasBrace = parseOptional(SyntaxKind.OpenBraceToken);
7161+
const entityName = parseEntityName(/* allowReservedWords*/ false);
7162+
if (hasBrace) {
7163+
parseExpectedJSDoc(SyntaxKind.CloseBraceToken);
7164+
}
7165+
7166+
const result = factory.createJSDocNameReference(entityName);
7167+
fixupParentReferences(result);
7168+
return finishNode(result, pos);
7169+
}
7170+
71537171
export function parseIsolatedJSDocComment(content: string, start: number | undefined, length: number | undefined): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
71547172
initializeState("", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
71557173
const jsDoc = doInsideOfContext(NodeFlags.JSDoc, () => parseJSDocCommentWorker(start, length));
@@ -7431,6 +7449,9 @@ namespace ts {
74317449
case "callback":
74327450
tag = parseCallbackTag(start, tagName, margin, indentText);
74337451
break;
7452+
case "see":
7453+
tag = parseSeeTag(start, tagName, margin, indentText);
7454+
break;
74347455
default:
74357456
tag = parseUnknownTag(start, tagName, margin, indentText);
74367457
break;
@@ -7661,6 +7682,13 @@ namespace ts {
76617682
return finishNode(factory.createJSDocTypeTag(tagName, typeExpression, comments), start, end);
76627683
}
76637684

7685+
function parseSeeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocSeeTag {
7686+
const nameExpression = parseJSDocNameReference();
7687+
const end = getNodePos();
7688+
const comments = indent !== undefined && indentText !== undefined ? parseTrailingTagComments(start, end, indent, indentText) : undefined;
7689+
return finishNode(factory.createJSDocSeeTag(tagName, nameExpression, comments), start, end);
7690+
}
7691+
76647692
function parseAuthorTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocAuthorTag {
76657693
const authorInfoWithEmail = tryParse(() => tryParseAuthorNameAndEmail());
76667694
if (!authorInfoWithEmail) {

src/compiler/types.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ namespace ts {
357357

358358
// JSDoc nodes
359359
JSDocTypeExpression,
360+
JSDocNameReference,
360361
// The * type
361362
JSDocAllType,
362363
// The ? type
@@ -389,6 +390,7 @@ namespace ts {
389390
JSDocTypeTag,
390391
JSDocTemplateTag,
391392
JSDocTypedefTag,
393+
JSDocSeeTag,
392394
JSDocPropertyTag,
393395

394396
// Synthesized list
@@ -3055,6 +3057,11 @@ namespace ts {
30553057
readonly type: TypeNode;
30563058
}
30573059

3060+
export interface JSDocNameReference extends Node {
3061+
readonly kind: SyntaxKind.JSDocNameReference;
3062+
readonly name: EntityName;
3063+
}
3064+
30583065
export interface JSDocType extends TypeNode {
30593066
_jsDocTypeBrand: any;
30603067
}
@@ -3179,6 +3186,11 @@ namespace ts {
31793186
readonly typeParameters: NodeArray<TypeParameterDeclaration>;
31803187
}
31813188

3189+
export interface JSDocSeeTag extends JSDocTag {
3190+
readonly kind: SyntaxKind.JSDocSeeTag;
3191+
readonly name?: JSDocNameReference;
3192+
}
3193+
31823194
export interface JSDocReturnTag extends JSDocTag {
31833195
readonly kind: SyntaxKind.JSDocReturnTag;
31843196
readonly typeExpression?: JSDocTypeExpression;
@@ -6965,6 +6977,8 @@ namespace ts {
69656977
updateJSDocNamepathType(node: JSDocNamepathType, type: TypeNode): JSDocNamepathType;
69666978
createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression;
69676979
updateJSDocTypeExpression(node: JSDocTypeExpression, type: TypeNode): JSDocTypeExpression;
6980+
createJSDocNameReference(name: EntityName): JSDocNameReference;
6981+
updateJSDocNameReference(node: JSDocNameReference, name: EntityName): JSDocNameReference;
69686982
createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral;
69696983
updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral;
69706984
createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature;
@@ -6979,6 +6993,8 @@ namespace ts {
69796993
updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | undefined): JSDocPropertyTag;
69806994
createJSDocTypeTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string): JSDocTypeTag;
69816995
updateJSDocTypeTag(node: JSDocTypeTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | undefined): JSDocTypeTag;
6996+
createJSDocSeeTag(tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string): JSDocSeeTag;
6997+
updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string): JSDocSeeTag;
69826998
createJSDocReturnTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag;
69836999
updateJSDocReturnTag(node: JSDocReturnTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | undefined): JSDocReturnTag;
69847000
createJSDocThisTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string): JSDocThisTag;

src/services/utilities.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ namespace ts {
105105
else if (isDeclarationName(node)) {
106106
return getMeaningFromDeclaration(node.parent);
107107
}
108+
else if (isEntityName(node) && isJSDocNameReference(node.parent)) {
109+
return SemanticMeaning.All;
110+
}
108111
else if (isTypeReference(node)) {
109112
return SemanticMeaning.Type;
110113
}

src/testRunner/unittests/jsDocParsing.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,6 @@ namespace ts {
314314
`/**
315315
* {@link first link}
316316
* Inside {@link link text} thing
317-
* @see {@link second link text} and {@link Foo|a foo} as well.
318317
*/`);
319318
parsesCorrectly("authorTag",
320319
`/**
Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,9 @@
11
{
22
"kind": "JSDocComment",
33
"pos": 0,
4-
"end": 127,
4+
"end": 63,
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"comment": "{@link first link}\nInside {@link link text} thing",
9-
"tags": {
10-
"0": {
11-
"kind": "JSDocTag",
12-
"pos": 63,
13-
"end": 68,
14-
"modifierFlagsCache": 0,
15-
"transformFlags": 0,
16-
"tagName": {
17-
"kind": "Identifier",
18-
"pos": 64,
19-
"end": 67,
20-
"modifierFlagsCache": 0,
21-
"transformFlags": 0,
22-
"escapedText": "see"
23-
},
24-
"comment": "{@link second link text} and {@link Foo|a foo} as well."
25-
},
26-
"length": 1,
27-
"pos": 63,
28-
"end": 68,
29-
"hasTrailingComma": false,
30-
"transformFlags": 0
31-
}
8+
"comment": "{@link first link}\nInside {@link link text} thing"
329
}

0 commit comments

Comments
 (0)