Skip to content

Commit 166f399

Browse files
committed
Merge pull request #8103 from zhengbli/typedefForJsdoc
[Salsa] Support @typedef for jsdoc
2 parents 4095602 + eb0f035 commit 166f399

19 files changed

+617
-82
lines changed

src/compiler/binder.ts

+31-3
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,18 @@ namespace ts {
263263
let functionType = <JSDocFunctionType>node.parent;
264264
let index = indexOf(functionType.parameters, node);
265265
return "p" + index;
266+
case SyntaxKind.JSDocTypedefTag:
267+
const parentNode = node.parent && node.parent.parent;
268+
let nameFromParentNode: string;
269+
if (parentNode && parentNode.kind === SyntaxKind.VariableStatement) {
270+
if ((<VariableStatement>parentNode).declarationList.declarations.length > 0) {
271+
const nameIdentifier = (<VariableStatement>parentNode).declarationList.declarations[0].name;
272+
if (nameIdentifier.kind === SyntaxKind.Identifier) {
273+
nameFromParentNode = (<Identifier>nameIdentifier).text;
274+
}
275+
}
276+
}
277+
return nameFromParentNode;
266278
}
267279
}
268280

@@ -402,6 +414,7 @@ namespace ts {
402414
// these saved values.
403415
const saveContainer = container;
404416
const savedBlockScopeContainer = blockScopeContainer;
417+
405418
// Depending on what kind of node this is, we may have to adjust the current container
406419
// and block-container. If the current node is a container, then it is automatically
407420
// considered the current block-container as well. Also, for containers that we know
@@ -491,8 +504,13 @@ namespace ts {
491504
}
492505

493506
function bindChildren(node: Node): void {
494-
if (node.flags & NodeFlags.JavaScriptFile && node.jsDocComment) {
495-
bind(node.jsDocComment);
507+
// Binding of JsDocComment should be done before the current block scope container changes.
508+
// because the scope of JsDocComment should not be affected by whether the current node is a
509+
// container or not.
510+
if (isInJavaScriptFile(node) && node.jsDocComments) {
511+
for (const jsDocComment of node.jsDocComments) {
512+
bind(jsDocComment);
513+
}
496514
}
497515
if (checkUnreachable(node)) {
498516
forEachChild(node, bind);
@@ -1090,6 +1108,7 @@ namespace ts {
10901108
case SyntaxKind.EnumDeclaration:
10911109
case SyntaxKind.ObjectLiteralExpression:
10921110
case SyntaxKind.TypeLiteral:
1111+
case SyntaxKind.JSDocTypeLiteral:
10931112
case SyntaxKind.JSDocRecordType:
10941113
return ContainerFlags.IsContainer;
10951114

@@ -1190,6 +1209,7 @@ namespace ts {
11901209
case SyntaxKind.ObjectLiteralExpression:
11911210
case SyntaxKind.InterfaceDeclaration:
11921211
case SyntaxKind.JSDocRecordType:
1212+
case SyntaxKind.JSDocTypeLiteral:
11931213
// Interface/Object-types always have their children added to the 'members' of
11941214
// their container. They are only accessible through an instance of their
11951215
// container, and are never in scope otherwise (even inside the body of the
@@ -1218,7 +1238,7 @@ namespace ts {
12181238
// their container in the tree. To accomplish this, we simply add their declared
12191239
// symbol to the 'locals' of the container. These symbols can then be found as
12201240
// the type checker walks up the containers, checking them for matching names.
1221-
return declareSymbol(container.locals, undefined, node, symbolFlags, symbolExcludes);
1241+
return declareSymbol(container.locals, /*parent*/ undefined, node, symbolFlags, symbolExcludes);
12221242
}
12231243
}
12241244

@@ -1679,6 +1699,8 @@ namespace ts {
16791699
case SyntaxKind.PropertySignature:
16801700
case SyntaxKind.JSDocRecordMember:
16811701
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
1702+
case SyntaxKind.JSDocPropertyTag:
1703+
return bindJSDocProperty(<JSDocPropertyTag>node);
16821704
case SyntaxKind.PropertyAssignment:
16831705
case SyntaxKind.ShorthandPropertyAssignment:
16841706
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
@@ -1714,6 +1736,7 @@ namespace ts {
17141736
case SyntaxKind.JSDocFunctionType:
17151737
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
17161738
case SyntaxKind.TypeLiteral:
1739+
case SyntaxKind.JSDocTypeLiteral:
17171740
case SyntaxKind.JSDocRecordType:
17181741
return bindAnonymousDeclaration(<TypeLiteralNode>node, SymbolFlags.TypeLiteral, "__type");
17191742
case SyntaxKind.ObjectLiteralExpression:
@@ -1736,6 +1759,7 @@ namespace ts {
17361759
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
17371760
case SyntaxKind.InterfaceDeclaration:
17381761
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
1762+
case SyntaxKind.JSDocTypedefTag:
17391763
case SyntaxKind.TypeAliasDeclaration:
17401764
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
17411765
case SyntaxKind.EnumDeclaration:
@@ -2077,6 +2101,10 @@ namespace ts {
20772101
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
20782102
}
20792103

2104+
function bindJSDocProperty(node: JSDocPropertyTag) {
2105+
return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
2106+
}
2107+
20802108
// reachability checks
20812109

20822110
function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean {

src/compiler/checker.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -3581,8 +3581,22 @@ namespace ts {
35813581
if (!pushTypeResolution(symbol, TypeSystemPropertyName.DeclaredType)) {
35823582
return unknownType;
35833583
}
3584-
const declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
3585-
let type = getTypeFromTypeNode(declaration.type);
3584+
3585+
let type: Type;
3586+
let declaration: JSDocTypedefTag | TypeAliasDeclaration = <JSDocTypedefTag>getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag);
3587+
if (declaration) {
3588+
if (declaration.jsDocTypeLiteral) {
3589+
type = getTypeFromTypeNode(declaration.jsDocTypeLiteral);
3590+
}
3591+
else {
3592+
type = getTypeFromTypeNode(declaration.typeExpression.type);
3593+
}
3594+
}
3595+
else {
3596+
declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
3597+
type = getTypeFromTypeNode(declaration.type);
3598+
}
3599+
35863600
if (popTypeResolution()) {
35873601
links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
35883602
if (links.typeParameters) {
@@ -5253,6 +5267,7 @@ namespace ts {
52535267
case SyntaxKind.FunctionType:
52545268
case SyntaxKind.ConstructorType:
52555269
case SyntaxKind.TypeLiteral:
5270+
case SyntaxKind.JSDocTypeLiteral:
52565271
case SyntaxKind.JSDocFunctionType:
52575272
case SyntaxKind.JSDocRecordType:
52585273
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
@@ -16728,7 +16743,7 @@ namespace ts {
1672816743
node = node.parent;
1672916744
}
1673016745

16731-
return node.parent && node.parent.kind === SyntaxKind.TypeReference;
16746+
return node.parent && (node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.JSDocTypeReference) ;
1673216747
}
1673316748

1673416749
function isHeritageClauseElementIdentifier(entityName: Node): boolean {
@@ -16864,7 +16879,7 @@ namespace ts {
1686416879
}
1686516880
}
1686616881
else if (isTypeReferenceIdentifier(<EntityName>entityName)) {
16867-
let meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
16882+
let meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace;
1686816883
// Include aliases in the meaning, this ensures that we do not follow aliases to where they point and instead
1686916884
// return the alias symbol.
1687016885
meaning |= SymbolFlags.Alias;

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,10 @@
819819
"category": "Error",
820820
"code": 1252
821821
},
822+
"'{0}' tag cannot be used independently as a top level JSDoc tag.": {
823+
"category": "Error",
824+
"code": 1253
825+
},
822826
"'with' statements are not allowed in an async function block.": {
823827
"category": "Error",
824828
"code": 1300

0 commit comments

Comments
 (0)