Skip to content

Commit 240f1f1

Browse files
authored
Merge pull request microsoft#17176 from Microsoft/parse-jsdoc-with-ts-type-parser
Parse jsdoc with normal TS type parser
2 parents e842182 + 3f60364 commit 240f1f1

93 files changed

Lines changed: 1439 additions & 1108 deletions

File tree

Some content is hidden

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

src/compiler/binder.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,14 +1395,12 @@ namespace ts {
13951395
case SyntaxKind.ObjectLiteralExpression:
13961396
case SyntaxKind.TypeLiteral:
13971397
case SyntaxKind.JSDocTypeLiteral:
1398-
case SyntaxKind.JSDocRecordType:
13991398
case SyntaxKind.JsxAttributes:
14001399
return ContainerFlags.IsContainer;
14011400

14021401
case SyntaxKind.InterfaceDeclaration:
14031402
return ContainerFlags.IsContainer | ContainerFlags.IsInterface;
14041403

1405-
case SyntaxKind.JSDocFunctionType:
14061404
case SyntaxKind.ModuleDeclaration:
14071405
case SyntaxKind.TypeAliasDeclaration:
14081406
case SyntaxKind.MappedType:
@@ -1422,9 +1420,10 @@ namespace ts {
14221420
case SyntaxKind.GetAccessor:
14231421
case SyntaxKind.SetAccessor:
14241422
case SyntaxKind.CallSignature:
1423+
case SyntaxKind.JSDocFunctionType:
1424+
case SyntaxKind.FunctionType:
14251425
case SyntaxKind.ConstructSignature:
14261426
case SyntaxKind.IndexSignature:
1427-
case SyntaxKind.FunctionType:
14281427
case SyntaxKind.ConstructorType:
14291428
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
14301429

@@ -1502,7 +1501,6 @@ namespace ts {
15021501
case SyntaxKind.TypeLiteral:
15031502
case SyntaxKind.ObjectLiteralExpression:
15041503
case SyntaxKind.InterfaceDeclaration:
1505-
case SyntaxKind.JSDocRecordType:
15061504
case SyntaxKind.JSDocTypeLiteral:
15071505
case SyntaxKind.JsxAttributes:
15081506
// Interface/Object-types always have their children added to the 'members' of
@@ -2095,6 +2093,7 @@ namespace ts {
20952093
case SyntaxKind.SetAccessor:
20962094
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
20972095
case SyntaxKind.FunctionType:
2096+
case SyntaxKind.JSDocFunctionType:
20982097
case SyntaxKind.ConstructorType:
20992098
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
21002099
case SyntaxKind.TypeLiteral:
@@ -2157,18 +2156,13 @@ namespace ts {
21572156
case SyntaxKind.ModuleBlock:
21582157
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
21592158

2160-
case SyntaxKind.JSDocRecordMember:
2161-
return bindPropertyWorker(node as JSDocRecordMember);
21622159
case SyntaxKind.JSDocPropertyTag:
21632160
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag,
21642161
(node as JSDocPropertyTag).isBracketed || ((node as JSDocPropertyTag).typeExpression && (node as JSDocPropertyTag).typeExpression.type.kind === SyntaxKind.JSDocOptionalType) ?
21652162
SymbolFlags.Property | SymbolFlags.Optional : SymbolFlags.Property,
21662163
SymbolFlags.PropertyExcludes);
2167-
case SyntaxKind.JSDocFunctionType:
2168-
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
21692164
case SyntaxKind.JSDocTypeLiteral:
2170-
case SyntaxKind.JSDocRecordType:
2171-
return bindAnonymousTypeWorker(node as JSDocTypeLiteral | JSDocRecordType);
2165+
return bindAnonymousTypeWorker(node as JSDocTypeLiteral);
21722166
case SyntaxKind.JSDocTypedefTag: {
21732167
const { fullName } = node as JSDocTypedefTag;
21742168
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
@@ -2183,7 +2177,7 @@ namespace ts {
21832177
return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
21842178
}
21852179

2186-
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral | JSDocRecordType) {
2180+
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral) {
21872181
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, InternalSymbolName.Type);
21882182
}
21892183

src/compiler/checker.ts

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6798,16 +6798,13 @@ namespace ts {
67986798
switch (node.kind) {
67996799
case SyntaxKind.TypeReference:
68006800
return (<TypeReferenceNode>node).typeName;
6801-
case SyntaxKind.JSDocTypeReference:
6802-
return (<JSDocTypeReference>node).name;
68036801
case SyntaxKind.ExpressionWithTypeArguments:
68046802
// We only support expressions that are simple qualified names. For other
68056803
// expressions this produces undefined.
68066804
const expr = (<ExpressionWithTypeArguments>node).expression;
68076805
if (isEntityNameExpression(expr)) {
68086806
return expr;
68096807
}
6810-
68116808
// fall through;
68126809
}
68136810

@@ -6833,8 +6830,8 @@ namespace ts {
68336830
return type;
68346831
}
68356832

6836-
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
6837-
// A JSDocTypeReference may have resolved to a value (as opposed to a type). If
6833+
if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) {
6834+
// A jsdoc TypeReference may have resolved to a value (as opposed to a type). If
68386835
// the symbol is a constructor function, return the inferred class type; otherwise,
68396836
// the type of this reference is just the type of the value we resolved to.
68406837
const valueType = getTypeOfSymbol(symbol);
@@ -6862,14 +6859,20 @@ namespace ts {
68626859
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
68636860
}
68646861

6865-
if (symbol.flags & SymbolFlags.Function && node.kind === SyntaxKind.JSDocTypeReference && (symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
6862+
if (symbol.flags & SymbolFlags.Function &&
6863+
isJSDocTypeReference(node) &&
6864+
(symbol.members || getJSDocClassTag(symbol.valueDeclaration))) {
68666865
return getInferredClassType(symbol);
68676866
}
68686867
}
68696868

6870-
function getPrimitiveTypeFromJSDocTypeReference(node: JSDocTypeReference): Type {
6871-
if (isIdentifier(node.name)) {
6872-
switch (node.name.text) {
6869+
function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode {
6870+
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
6871+
}
6872+
6873+
function getPrimitiveTypeFromJSDocTypeReference(node: TypeReferenceNode): Type {
6874+
if (isIdentifier(node.typeName)) {
6875+
switch (node.typeName.text) {
68736876
case "String":
68746877
return stringType;
68756878
case "Number":
@@ -6883,7 +6886,6 @@ namespace ts {
68836886
case "Null":
68846887
return nullType;
68856888
case "Object":
6886-
case "object":
68876889
return anyType;
68886890
case "Function":
68896891
case "function":
@@ -6909,7 +6911,7 @@ namespace ts {
69096911
let symbol: Symbol;
69106912
let type: Type;
69116913
let meaning = SymbolFlags.Type;
6912-
if (node.kind === SyntaxKind.JSDocTypeReference) {
6914+
if (isJSDocTypeReference(node)) {
69136915
type = getPrimitiveTypeFromJSDocTypeReference(node);
69146916
meaning |= SymbolFlags.Value;
69156917
}
@@ -7799,15 +7801,6 @@ namespace ts {
77997801
return links.resolvedType;
78007802
}
78017803

7802-
function getTypeFromJSDocTupleType(node: JSDocTupleType): Type {
7803-
const links = getNodeLinks(node);
7804-
if (!links.resolvedType) {
7805-
const types = map(node.types, getTypeFromTypeNode);
7806-
links.resolvedType = createTupleType(types);
7807-
}
7808-
return links.resolvedType;
7809-
}
7810-
78117804
function getThisType(node: Node): Type {
78127805
const container = getThisContainer(node, /*includeArrowFunctions*/ false);
78137806
const parent = container && container.parent;
@@ -7852,16 +7845,13 @@ namespace ts {
78527845
case SyntaxKind.NeverKeyword:
78537846
return neverType;
78547847
case SyntaxKind.ObjectKeyword:
7855-
return nonPrimitiveType;
7848+
return node.flags & NodeFlags.JavaScriptFile ? anyType : nonPrimitiveType;
78567849
case SyntaxKind.ThisType:
78577850
case SyntaxKind.ThisKeyword:
78587851
return getTypeFromThisTypeNode(node);
78597852
case SyntaxKind.LiteralType:
78607853
return getTypeFromLiteralTypeNode(<LiteralTypeNode>node);
7861-
case SyntaxKind.JSDocLiteralType:
7862-
return getTypeFromLiteralTypeNode((<JSDocLiteralType>node).literal);
78637854
case SyntaxKind.TypeReference:
7864-
case SyntaxKind.JSDocTypeReference:
78657855
return getTypeFromTypeReference(<TypeReferenceNode>node);
78667856
case SyntaxKind.TypePredicate:
78677857
return booleanType;
@@ -7870,25 +7860,19 @@ namespace ts {
78707860
case SyntaxKind.TypeQuery:
78717861
return getTypeFromTypeQueryNode(<TypeQueryNode>node);
78727862
case SyntaxKind.ArrayType:
7873-
case SyntaxKind.JSDocArrayType:
78747863
return getTypeFromArrayTypeNode(<ArrayTypeNode>node);
78757864
case SyntaxKind.TupleType:
78767865
return getTypeFromTupleTypeNode(<TupleTypeNode>node);
78777866
case SyntaxKind.UnionType:
7878-
case SyntaxKind.JSDocUnionType:
78797867
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
78807868
case SyntaxKind.IntersectionType:
78817869
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
78827870
case SyntaxKind.JSDocNullableType:
78837871
return getTypeFromJSDocNullableTypeNode(<JSDocNullableType>node);
78847872
case SyntaxKind.ParenthesizedType:
78857873
case SyntaxKind.JSDocNonNullableType:
7886-
case SyntaxKind.JSDocConstructorType:
7887-
case SyntaxKind.JSDocThisType:
78887874
case SyntaxKind.JSDocOptionalType:
78897875
return getTypeFromTypeNode((<ParenthesizedTypeNode | JSDocTypeReferencingNode>node).type);
7890-
case SyntaxKind.JSDocRecordType:
7891-
return getTypeFromTypeNode((node as JSDocRecordType).literal);
78927876
case SyntaxKind.FunctionType:
78937877
case SyntaxKind.ConstructorType:
78947878
case SyntaxKind.TypeLiteral:
@@ -7907,8 +7891,6 @@ namespace ts {
79077891
case SyntaxKind.QualifiedName:
79087892
const symbol = getSymbolAtLocation(node);
79097893
return symbol && getDeclaredTypeOfSymbol(symbol);
7910-
case SyntaxKind.JSDocTupleType:
7911-
return getTypeFromJSDocTupleType(<JSDocTupleType>node);
79127894
case SyntaxKind.JSDocVariadicType:
79137895
return getTypeFromJSDocVariadicType(<JSDocVariadicType>node);
79147896
default:
@@ -12381,7 +12363,9 @@ namespace ts {
1238112363
const jsdocType = getJSDocType(node);
1238212364
if (jsdocType && jsdocType.kind === SyntaxKind.JSDocFunctionType) {
1238312365
const jsDocFunctionType = <JSDocFunctionType>jsdocType;
12384-
if (jsDocFunctionType.parameters.length > 0 && jsDocFunctionType.parameters[0].type.kind === SyntaxKind.JSDocThisType) {
12366+
if (jsDocFunctionType.parameters.length > 0 &&
12367+
jsDocFunctionType.parameters[0].name &&
12368+
(jsDocFunctionType.parameters[0].name as Identifier).text === "this") {
1238512369
return getTypeFromTypeNode(jsDocFunctionType.parameters[0].type);
1238612370
}
1238712371
}
@@ -17883,9 +17867,9 @@ namespace ts {
1788317867
if (node.questionToken && isBindingPattern(node.name) && (func as FunctionLikeDeclaration).body) {
1788417868
error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature);
1788517869
}
17886-
if ((<Identifier>node.name).text === "this") {
17870+
if (node.name && ((node.name as Identifier).text === "this" || (node.name as Identifier).text === "new")) {
1788717871
if (indexOf(func.parameters, node) !== 0) {
17888-
error(node, Diagnostics.A_this_parameter_must_be_the_first_parameter);
17872+
error(node, Diagnostics.A_0_parameter_must_be_the_first_parameter, (node.name as Identifier).text as string);
1788917873
}
1789017874
if (func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.ConstructSignature || func.kind === SyntaxKind.ConstructorType) {
1789117875
error(node, Diagnostics.A_constructor_cannot_have_a_this_parameter);
@@ -18474,6 +18458,10 @@ namespace ts {
1847418458

1847518459
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
1847618460
checkGrammarTypeArguments(node, node.typeArguments);
18461+
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
18462+
grammarErrorAtPos(getSourceFileOfNode(node), node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
18463+
18464+
}
1847718465
const type = getTypeFromTypeReference(node);
1847818466
if (type !== unknownType) {
1847918467
if (node.typeArguments) {
@@ -19372,7 +19360,23 @@ namespace ts {
1937219360
}
1937319361
}
1937419362

19363+
function checkJSDoc(node: FunctionDeclaration | MethodDeclaration) {
19364+
if (!isInJavaScriptFile(node)) {
19365+
return;
19366+
}
19367+
forEach(node.jsDoc, checkSourceElement);
19368+
}
19369+
19370+
function checkJSDocComment(node: JSDoc) {
19371+
if ((node as JSDoc).tags) {
19372+
for (const tag of (node as JSDoc).tags) {
19373+
checkSourceElement(tag);
19374+
}
19375+
}
19376+
}
19377+
1937519378
function checkFunctionOrMethodDeclaration(node: FunctionDeclaration | MethodDeclaration): void {
19379+
checkJSDoc(node);
1937619380
checkDecorators(node);
1937719381
checkSignatureDeclaration(node);
1937819382
const functionFlags = getFunctionFlags(node);
@@ -19916,6 +19920,11 @@ namespace ts {
1991619920
function checkVariableLikeDeclaration(node: VariableLikeDeclaration) {
1991719921
checkDecorators(node);
1991819922
checkSourceElement(node.type);
19923+
19924+
// JSDoc `function(string, string): string` syntax results in parameters with no name
19925+
if (!node.name) {
19926+
return;
19927+
}
1991919928
// For a computed property, just check the initializer and exit
1992019929
// Do not use hasDynamicName here, because that returns false for well known symbols.
1992119930
// We want to perform checkComputedPropertyName for all computed properties, including
@@ -22030,6 +22039,24 @@ namespace ts {
2203022039
case SyntaxKind.ParenthesizedType:
2203122040
case SyntaxKind.TypeOperator:
2203222041
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
22042+
case SyntaxKind.JSDocComment:
22043+
return checkJSDocComment(node as JSDoc);
22044+
case SyntaxKind.JSDocParameterTag:
22045+
return checkSourceElement((node as JSDocParameterTag).typeExpression);
22046+
case SyntaxKind.JSDocFunctionType:
22047+
checkSignatureDeclaration(node as JSDocFunctionType);
22048+
// falls through
22049+
case SyntaxKind.JSDocVariadicType:
22050+
case SyntaxKind.JSDocNonNullableType:
22051+
case SyntaxKind.JSDocNullableType:
22052+
case SyntaxKind.JSDocAllType:
22053+
case SyntaxKind.JSDocUnknownType:
22054+
if (!isInJavaScriptFile(node) && !isInJSDoc(node)) {
22055+
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
22056+
}
22057+
return;
22058+
case SyntaxKind.JSDocTypeExpression:
22059+
return checkSourceElement((node as JSDocTypeExpression).type);
2203322060
case SyntaxKind.IndexedAccessType:
2203422061
return checkIndexedAccessType(<IndexedAccessTypeNode>node);
2203522062
case SyntaxKind.MappedType:
@@ -22386,7 +22413,7 @@ namespace ts {
2238622413
node = node.parent;
2238722414
}
2238822415

22389-
return node.parent && (node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.JSDocTypeReference) ;
22416+
return node.parent && node.parent.kind === SyntaxKind.TypeReference ;
2239022417
}
2239122418

2239222419
function isHeritageClauseElementIdentifier(entityName: Node): boolean {
@@ -22540,7 +22567,7 @@ namespace ts {
2254022567
}
2254122568
}
2254222569
else if (isTypeReferenceIdentifier(<EntityName>entityName)) {
22543-
const meaning = (entityName.parent.kind === SyntaxKind.TypeReference || entityName.parent.kind === SyntaxKind.JSDocTypeReference) ? SymbolFlags.Type : SymbolFlags.Namespace;
22570+
const meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
2254422571
return resolveEntityName(<EntityName>entityName, meaning, /*ignoreErrors*/ false, /*dontResolveAlias*/ true);
2254522572
}
2254622573
else if (entityName.parent.kind === SyntaxKind.JsxAttribute) {

src/compiler/diagnosticMessages.json

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,7 +2064,7 @@
20642064
"category": "Error",
20652065
"code": 2679
20662066
},
2067-
"A 'this' parameter must be the first parameter.": {
2067+
"A '{0}' parameter must be the first parameter.": {
20682068
"category": "Error",
20692069
"code": 2680
20702070
},
@@ -3463,6 +3463,22 @@
34633463
"category": "Error",
34643464
"code": 8016
34653465
},
3466+
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
3467+
"category": "Error",
3468+
"code": 8017
3469+
},
3470+
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
3471+
"category": "Error",
3472+
"code": 8018
3473+
},
3474+
"Report errors in .js files.": {
3475+
"category": "Message",
3476+
"code": 8019
3477+
},
3478+
"JSDoc types can only be used inside documentation comments.": {
3479+
"category": "Error",
3480+
"code": 8020
3481+
},
34663482
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
34673483
"category": "Error",
34683484
"code": 9002
@@ -3645,18 +3661,5 @@
36453661
"Convert function '{0}' to class": {
36463662
"category": "Message",
36473663
"code": 95002
3648-
},
3649-
3650-
"Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": {
3651-
"category": "Error",
3652-
"code": 8017
3653-
},
3654-
"Octal literals are not allowed in enums members initializer. Use the syntax '{0}'.": {
3655-
"category": "Error",
3656-
"code": 8018
3657-
},
3658-
"Report errors in .js files.": {
3659-
"category": "Message",
3660-
"code": 8019
36613664
}
36623665
}

0 commit comments

Comments
 (0)