mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Support the case with @property and @type
This commit is contained in:
@@ -744,6 +744,7 @@ namespace ts {
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return ContainerFlags.IsContainer;
|
||||
|
||||
@@ -832,6 +833,7 @@ namespace ts {
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
// Interface/Object-types always have their children added to the 'members' of
|
||||
// their container. They are only accessible through an instance of their
|
||||
// container, and are never in scope otherwise (even inside the body of the
|
||||
@@ -1294,6 +1296,7 @@ namespace ts {
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.JSDocRecordMember:
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
@@ -1326,6 +1329,7 @@ namespace ts {
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return bindAnonymousDeclaration(<TypeLiteralNode>node, SymbolFlags.TypeLiteral, "__type");
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
|
||||
@@ -3412,17 +3412,14 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
let typeNode: TypeNode;
|
||||
let name: Identifier;
|
||||
let declaration: JSDocTypedefTag | TypeAliasDeclaration;
|
||||
if (node && (node.flags & NodeFlags.JavaScriptFile)) {
|
||||
const declaration = <JSDocTypedefTag>getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag);
|
||||
typeNode = declaration.typeExpression.type;
|
||||
declaration = <JSDocTypedefTag>getDeclarationOfKind(symbol, SyntaxKind.JSDocTypedefTag);
|
||||
}
|
||||
if (!typeNode) {
|
||||
const declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
|
||||
typeNode = declaration.type;
|
||||
if (!declaration) {
|
||||
declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
|
||||
}
|
||||
let type = getTypeFromTypeNode(typeNode);
|
||||
let type = getTypeFromTypeNode(declaration.type);
|
||||
if (popTypeResolution()) {
|
||||
links.typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
if (links.typeParameters) {
|
||||
@@ -3434,7 +3431,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
type = unknownType;
|
||||
error(name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
|
||||
error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
|
||||
}
|
||||
links.declaredType = type;
|
||||
}
|
||||
@@ -5067,6 +5064,7 @@ namespace ts {
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
case SyntaxKind.JSDocRecordType:
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
|
||||
+124
-18
@@ -402,7 +402,15 @@ namespace ts {
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return visitNodes(cbNodes, (<JSDocTemplateTag>node).typeParameters);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression);
|
||||
return visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocTypedefTag>node).type);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).members);
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return visitNode(cbNode, (<JSDocPropertyTag>node).name) ||
|
||||
visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
|
||||
visitNode(cbNode, (<JSDocPropertyTag>node).type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5992,7 +6000,8 @@ namespace ts {
|
||||
Debug.assert(end <= content.length);
|
||||
|
||||
let tags: NodeArray<JSDocTag>;
|
||||
let currentParentJSDocDeclaration: Declaration;
|
||||
let currentParentJSDocTag: JSDocParentTag;
|
||||
let currentParentJSDocTagEnd: number;
|
||||
|
||||
let result: JSDocComment;
|
||||
|
||||
@@ -6050,6 +6059,10 @@ namespace ts {
|
||||
nextJSDocToken();
|
||||
}
|
||||
|
||||
if (currentParentJSDocTag) {
|
||||
finishCurrentParentTag();
|
||||
}
|
||||
|
||||
result = createJSDocComment();
|
||||
|
||||
});
|
||||
@@ -6073,6 +6086,40 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function finishCurrentParentTag(): void {
|
||||
if (!currentParentJSDocTag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
const typedefTag = <JSDocTypedefTag>currentParentJSDocTag;
|
||||
if (typedefTag.jsDocTypeTag) {
|
||||
if (typedefTag.jsDocTypeTag.typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
|
||||
const typeTagtype = <JSDocTypeReference>typedefTag.jsDocTypeTag.typeExpression.type;
|
||||
if ((typeTagtype.name.kind !== SyntaxKind.Identifier) ||
|
||||
(<Identifier>typeTagtype.name).text !== "Object") {
|
||||
typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type;
|
||||
}
|
||||
}
|
||||
if (!typedefTag.type) {
|
||||
const tagType = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, currentParentJSDocTag.pos);
|
||||
if (typedefTag.jsDocPropertyTags){
|
||||
tagType.members = <NodeArray<JSDocPropertyTag>>[];
|
||||
addRange(tagType.members, typedefTag.jsDocPropertyTags);
|
||||
}
|
||||
typedefTag.type = finishNode(tagType, currentParentJSDocTagEnd);
|
||||
}
|
||||
}
|
||||
|
||||
addTag(finishNode(currentParentJSDocTag, currentParentJSDocTagEnd));
|
||||
currentParentJSDocTag = undefined;
|
||||
currentParentJSDocTagEnd = undefined;
|
||||
}
|
||||
|
||||
function parseTag(): void {
|
||||
Debug.assert(token === SyntaxKind.AtToken);
|
||||
const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos());
|
||||
@@ -6085,22 +6132,30 @@ namespace ts {
|
||||
}
|
||||
|
||||
const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName);
|
||||
addTag(tag);
|
||||
if (!currentParentJSDocTag) {
|
||||
addTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
function handleTag(atToken: Node, tagName: Identifier): JSDocTag {
|
||||
if (tagName) {
|
||||
switch (tagName.text) {
|
||||
case "param":
|
||||
finishCurrentParentTag();
|
||||
return handleParamTag(atToken, tagName);
|
||||
case "return":
|
||||
case "returns":
|
||||
finishCurrentParentTag();
|
||||
return handleReturnTag(atToken, tagName);
|
||||
case "template":
|
||||
finishCurrentParentTag();
|
||||
return handleTemplateTag(atToken, tagName);
|
||||
case "type":
|
||||
// @typedef tag is allowed to have one @type tag, therefore seeing
|
||||
// a @type tag may not indicate the end of the current parent tag.
|
||||
return handleTypeTag(atToken, tagName);
|
||||
case "typedef":
|
||||
finishCurrentParentTag();
|
||||
return handleTypedefTag(atToken, tagName);
|
||||
case "property":
|
||||
case "prop":
|
||||
@@ -6130,6 +6185,25 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function addToCurrentParentTag(tag: JSDocTag): void {
|
||||
if (!currentParentJSDocTag) {
|
||||
return;
|
||||
}
|
||||
switch (tag.kind) {
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
if (!currentParentJSDocTag.jsDocPropertyTags) {
|
||||
currentParentJSDocTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
|
||||
}
|
||||
currentParentJSDocTag.jsDocPropertyTags.push(<JSDocPropertyTag>tag);
|
||||
break;
|
||||
case SyntaxKind.JSDocTypeTag:
|
||||
if (!currentParentJSDocTag.jsDocTypeTag) {
|
||||
currentParentJSDocTag.jsDocTypeTag = <JSDocTypeTag>tag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseTypeExpression(): JSDocTypeExpression {
|
||||
if (token !== SyntaxKind.OpenBraceToken) {
|
||||
return undefined;
|
||||
@@ -6205,15 +6279,33 @@ namespace ts {
|
||||
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_already_specified, tagName.text);
|
||||
}
|
||||
|
||||
const result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
|
||||
let result = <JSDocTypeTag>createNode(SyntaxKind.JSDocTypeTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.typeExpression = tryParseTypeExpression();
|
||||
return finishNode(result);
|
||||
result = finishNode(result);
|
||||
|
||||
let typeTagPartOfParentTag = false;
|
||||
if (currentParentJSDocTag && currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) {
|
||||
const parentTag = <JSDocTypedefTag>currentParentJSDocTag;
|
||||
if (!parentTag.typeExpression && !parentTag.jsDocTypeTag) {
|
||||
typeTagPartOfParentTag = true;
|
||||
parentTag.jsDocTypeTag = result;
|
||||
currentParentJSDocTagEnd = scanner.getStartPos();
|
||||
}
|
||||
}
|
||||
if (!typeTagPartOfParentTag) {
|
||||
// If this @type tag is not part of the current parent tag, then
|
||||
// it denotes the end of the current parent tag.
|
||||
finishCurrentParentTag();
|
||||
return result;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
|
||||
if (!currentParentJSDocDeclaration) {
|
||||
if (!currentParentJSDocTag) {
|
||||
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_cannot_be_used_independently_as_a_top_level_JSDoc_tag, tagName.text);
|
||||
return undefined;
|
||||
}
|
||||
@@ -6226,12 +6318,17 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
let result = <JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos);
|
||||
result.atToken = atToken;
|
||||
result.tagName = tagName;
|
||||
result.name = name;
|
||||
result.typeExpression = typeExpression;
|
||||
return finishNode(result);
|
||||
result.type = typeExpression.type;
|
||||
result = finishNode(result);
|
||||
|
||||
addToCurrentParentTag(result);
|
||||
currentParentJSDocTagEnd = scanner.getStartPos();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
|
||||
@@ -6249,17 +6346,26 @@ namespace ts {
|
||||
result.name = name;
|
||||
result.typeExpression = typeExpression;
|
||||
|
||||
// if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
|
||||
// const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
|
||||
// if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
|
||||
// const name = <Identifier>jsDocTypeReference.name;
|
||||
// if (name.text === "Object") {
|
||||
// currentParentJSDocDeclaration = declaration;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
|
||||
const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
|
||||
if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
|
||||
const name = <Identifier>jsDocTypeReference.name;
|
||||
if (name.text === "Object") {
|
||||
currentParentJSDocTag = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!typeExpression) {
|
||||
currentParentJSDocTag = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
if (!currentParentJSDocTag) {
|
||||
result.type = result.typeExpression.type;
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
currentParentJSDocTagEnd = scanner.getStartPos();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {
|
||||
|
||||
+10
-9
@@ -344,7 +344,6 @@ namespace ts {
|
||||
JSDocTemplateTag,
|
||||
JSDocTypedefTag,
|
||||
JSDocPropertyTag,
|
||||
JSDocTypedefDeclaration,
|
||||
JSDocTypeLiteral,
|
||||
|
||||
// Synthesized list
|
||||
@@ -616,6 +615,7 @@ namespace ts {
|
||||
// SyntaxKind.PropertyAssignment
|
||||
// SyntaxKind.ShorthandPropertyAssignment
|
||||
// SyntaxKind.EnumMember
|
||||
// SyntaxKind.JSDocPropertyTag
|
||||
export interface VariableLikeDeclaration extends Declaration {
|
||||
propertyName?: PropertyName;
|
||||
dotDotDotToken?: Node;
|
||||
@@ -1515,25 +1515,26 @@ namespace ts {
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypedefTag)
|
||||
export interface JSDocTypedefTag extends JSDocTag, Declaration {
|
||||
export interface JSDocTypedefTag extends JSDocTag, Declaration, JSDocParentTag {
|
||||
name: Identifier;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
typeExpression?: JSDocTypeExpression;
|
||||
type: JSDocType;
|
||||
}
|
||||
|
||||
export interface JSDocParentTag extends JSDocTag {
|
||||
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
|
||||
jsDocTypeTag?: JSDocTypeTag;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocPropertyTag)
|
||||
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
|
||||
name: Identifier;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypedefDeclaration)
|
||||
export interface JSDocTypedefDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
// @kind(SyntaxKind.JSDocTypeLiteral)
|
||||
export interface JSDocTypeLiteral extends TypeNode {
|
||||
export interface JSDocTypeLiteral extends JSDocType {
|
||||
members: NodeArray<TypeElement>;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/// <reference path="../fourslash.ts"/>
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: jsdocCompletion_typedef.js
|
||||
//// /**
|
||||
//// * @typedef {Object} Person
|
||||
//// * @property {string} personName
|
||||
//// * @type {Person}
|
||||
//// */
|
||||
//// var x1;
|
||||
//// x1/**/
|
||||
|
||||
goTo.marker();
|
||||
edit.insert('.');
|
||||
verify.memberListContains('personName');
|
||||
Reference in New Issue
Block a user