Skip to content

Commit 95fd3a1

Browse files
committed
Change how typedef tag is parsed
1 parent 5f9fa69 commit 95fd3a1

File tree

2 files changed

+96
-126
lines changed

2 files changed

+96
-126
lines changed

src/compiler/parser.ts

+93-116
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ namespace ts {
406406
visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
407407
visitNode(cbNode, (<JSDocTypedefTag>node).type);
408408
case SyntaxKind.JSDocTypeLiteral:
409-
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).members);
409+
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
410410
case SyntaxKind.JSDocPropertyTag:
411411
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
412412
visitNode(cbNode, (<JSDocPropertyTag>node).name);
@@ -4113,9 +4113,9 @@ namespace ts {
41134113
const isAsync = !!(node.flags & NodeFlags.Async);
41144114
node.name =
41154115
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
4116-
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
4117-
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
4118-
parseOptionalIdentifier();
4116+
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
4117+
isAsync ? doInAwaitContext(parseOptionalIdentifier) :
4118+
parseOptionalIdentifier();
41194119

41204120
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node);
41214121
node.body = parseFunctionBlock(/*allowYield*/ isGenerator, /*allowAwait*/ isAsync, /*ignoreMissingOpenBrace*/ false);
@@ -6066,9 +6066,6 @@ namespace ts {
60666066
Debug.assert(end <= content.length);
60676067

60686068
let tags: NodeArray<JSDocTag>;
6069-
let currentParentJSDocTag: JSDocParentTag;
6070-
let currentParentJSDocTagEnd: number;
6071-
60726069
let result: JSDocComment;
60736070

60746071
// Check for /** (JSDoc opening part)
@@ -6125,10 +6122,6 @@ namespace ts {
61256122
nextJSDocToken();
61266123
}
61276124

6128-
if (currentParentJSDocTag) {
6129-
finishCurrentParentTag();
6130-
}
6131-
61326125
result = createJSDocComment();
61336126

61346127
});
@@ -6152,40 +6145,6 @@ namespace ts {
61526145
}
61536146
}
61546147

6155-
function finishCurrentParentTag(): void {
6156-
if (!currentParentJSDocTag) {
6157-
return;
6158-
}
6159-
6160-
if (currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) {
6161-
const typedefTag = <JSDocTypedefTag>currentParentJSDocTag;
6162-
if (typedefTag.jsDocTypeTag) {
6163-
if (typedefTag.jsDocTypeTag.typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
6164-
const typeTagtype = <JSDocTypeReference>typedefTag.jsDocTypeTag.typeExpression.type;
6165-
if ((typeTagtype.name.kind !== SyntaxKind.Identifier) ||
6166-
(<Identifier>typeTagtype.name).text !== "Object") {
6167-
typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type;
6168-
}
6169-
}
6170-
else {
6171-
typedefTag.type = typedefTag.jsDocTypeTag.typeExpression.type;
6172-
}
6173-
}
6174-
if (!typedefTag.type && typedefTag.jsDocPropertyTags && typedefTag.jsDocPropertyTags.length > 0) {
6175-
const pos = typedefTag.jsDocPropertyTags[0].pos;
6176-
const end = typedefTag.jsDocPropertyTags[typedefTag.jsDocPropertyTags.length - 1].end;
6177-
const jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, pos);
6178-
jsdocTypeLiteral.members = <NodeArray<JSDocPropertyTag>>[];
6179-
addRange(jsdocTypeLiteral.members, typedefTag.jsDocPropertyTags);
6180-
typedefTag.type = finishNode(jsdocTypeLiteral, end);
6181-
}
6182-
}
6183-
6184-
addTag(finishNode(currentParentJSDocTag, currentParentJSDocTagEnd));
6185-
currentParentJSDocTag = undefined;
6186-
currentParentJSDocTagEnd = undefined;
6187-
}
6188-
61896148
function parseTag(): void {
61906149
Debug.assert(token === SyntaxKind.AtToken);
61916150
const atToken = createNode(SyntaxKind.AtToken, scanner.getTokenPos());
@@ -6198,30 +6157,22 @@ namespace ts {
61986157
}
61996158

62006159
const tag = handleTag(atToken, tagName) || handleUnknownTag(atToken, tagName);
6201-
if (!currentParentJSDocTag) {
6202-
addTag(tag);
6203-
}
6160+
addTag(tag);
62046161
}
62056162

62066163
function handleTag(atToken: Node, tagName: Identifier): JSDocTag {
62076164
if (tagName) {
62086165
switch (tagName.text) {
62096166
case "param":
6210-
finishCurrentParentTag();
62116167
return handleParamTag(atToken, tagName);
62126168
case "return":
62136169
case "returns":
6214-
finishCurrentParentTag();
62156170
return handleReturnTag(atToken, tagName);
62166171
case "template":
6217-
finishCurrentParentTag();
62186172
return handleTemplateTag(atToken, tagName);
62196173
case "type":
6220-
// @typedef tag is allowed to have one @type tag, therefore seeing
6221-
// a @type tag may not indicate the end of the current parent tag.
62226174
return handleTypeTag(atToken, tagName);
62236175
case "typedef":
6224-
finishCurrentParentTag();
62256176
return handleTypedefTag(atToken, tagName);
62266177
case "property":
62276178
case "prop":
@@ -6251,25 +6202,6 @@ namespace ts {
62516202
}
62526203
}
62536204

6254-
function addToCurrentParentTag(tag: JSDocTag): void {
6255-
if (!currentParentJSDocTag) {
6256-
return;
6257-
}
6258-
switch (tag.kind) {
6259-
case SyntaxKind.JSDocPropertyTag:
6260-
if (!currentParentJSDocTag.jsDocPropertyTags) {
6261-
currentParentJSDocTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
6262-
}
6263-
currentParentJSDocTag.jsDocPropertyTags.push(<JSDocPropertyTag>tag);
6264-
break;
6265-
case SyntaxKind.JSDocTypeTag:
6266-
if (!currentParentJSDocTag.jsDocTypeTag) {
6267-
currentParentJSDocTag.jsDocTypeTag = <JSDocTypeTag>tag;
6268-
}
6269-
break;
6270-
}
6271-
}
6272-
62736205
function tryParseTypeExpression(): JSDocTypeExpression {
62746206
if (token !== SyntaxKind.OpenBraceToken) {
62756207
return undefined;
@@ -6349,28 +6281,10 @@ namespace ts {
63496281
result.atToken = atToken;
63506282
result.tagName = tagName;
63516283
result.typeExpression = tryParseTypeExpression();
6352-
result = finishNode(result);
6353-
6354-
if (currentParentJSDocTag && currentParentJSDocTag.kind === SyntaxKind.JSDocTypedefTag) {
6355-
const parentTag = <JSDocTypedefTag>currentParentJSDocTag;
6356-
if (!parentTag.typeExpression && !parentTag.jsDocTypeTag) {
6357-
parentTag.jsDocTypeTag = result;
6358-
currentParentJSDocTagEnd = scanner.getStartPos();
6359-
return result;
6360-
}
6361-
}
6362-
// If this @type tag is not part of the current parent tag, then
6363-
// it denotes the end of the current parent tag.
6364-
finishCurrentParentTag();
6365-
return result;
6284+
return finishNode(result);
63666285
}
63676286

63686287
function handlePropertyTag(atToken: Node, tagName: Identifier): JSDocPropertyTag {
6369-
if (!currentParentJSDocTag) {
6370-
parseErrorAtPosition(tagName.pos, scanner.getTokenPos() - tagName.pos, Diagnostics._0_tag_cannot_be_used_independently_as_a_top_level_JSDoc_tag, tagName.text);
6371-
return undefined;
6372-
}
6373-
63746288
const typeExpression = tryParseTypeExpression();
63756289
skipWhitespace();
63766290
const name = parseJSDocIdentifierName();
@@ -6384,12 +6298,7 @@ namespace ts {
63846298
result.tagName = tagName;
63856299
result.name = name;
63866300
result.typeExpression = typeExpression;
6387-
result.type = typeExpression.type;
6388-
result = finishNode(result);
6389-
6390-
addToCurrentParentTag(result);
6391-
currentParentJSDocTagEnd = scanner.getStartPos();
6392-
return undefined;
6301+
return finishNode(result);
63936302
}
63946303

63956304
function handleTypedefTag(atToken: Node, tagName: Identifier): JSDocTypedefTag {
@@ -6413,32 +6322,100 @@ namespace ts {
64136322
}
64146323
}
64156324

6416-
const result = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
6417-
result.atToken = atToken;
6418-
result.tagName = tagName;
6419-
result.name = name;
6420-
result.typeExpression = typeExpression;
6325+
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
6326+
typedefTag.atToken = atToken;
6327+
typedefTag.tagName = tagName;
6328+
typedefTag.name = name;
6329+
typedefTag.typeExpression = typeExpression;
64216330

6422-
if (typeExpression && typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
6423-
const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
6424-
if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
6425-
const name = <Identifier>jsDocTypeReference.name;
6426-
if (name.text === "Object") {
6427-
currentParentJSDocTag = result;
6331+
if (typeExpression) {
6332+
if (typeExpression.type.kind === SyntaxKind.JSDocTypeReference) {
6333+
const jsDocTypeReference = <JSDocTypeReference>typeExpression.type;
6334+
if (jsDocTypeReference.name.kind === SyntaxKind.Identifier) {
6335+
const name = <Identifier>jsDocTypeReference.name;
6336+
if (name.text === "Object") {
6337+
typedefTag.type = scanChildTags();
6338+
}
64286339
}
64296340
}
6341+
if (!typedefTag.type) {
6342+
typedefTag.type = typeExpression.type;
6343+
}
64306344
}
6431-
else if (!typeExpression) {
6432-
currentParentJSDocTag = result;
6345+
else {
6346+
typedefTag.type = scanChildTags();
64336347
}
64346348

6435-
if (!currentParentJSDocTag) {
6436-
result.type = result.typeExpression.type;
6437-
return finishNode(result);
6349+
return finishNode(typedefTag);
6350+
6351+
function scanChildTags(): JSDocTypeLiteral {
6352+
const jsDocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, scanner.getStartPos());
6353+
let resumePos = scanner.getStartPos();
6354+
let canParseTag = true;
6355+
let seenAsterisk = false;
6356+
let parentTagTerminated = false;
6357+
6358+
nextJSDocToken();
6359+
while (token !== SyntaxKind.EndOfFileToken && !parentTagTerminated) {
6360+
nextJSDocToken();
6361+
switch (token) {
6362+
case SyntaxKind.AtToken:
6363+
if (canParseTag) {
6364+
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
6365+
}
6366+
seenAsterisk = false;
6367+
break;
6368+
case SyntaxKind.NewLineTrivia:
6369+
resumePos = scanner.getStartPos() - 1;
6370+
canParseTag = true;
6371+
seenAsterisk = false;
6372+
break;
6373+
case SyntaxKind.AsteriskToken:
6374+
if (seenAsterisk) {
6375+
canParseTag = false;
6376+
}
6377+
seenAsterisk = true;
6378+
break;
6379+
case SyntaxKind.Identifier:
6380+
canParseTag = false;
6381+
case SyntaxKind.EndOfFileToken:
6382+
break;
6383+
}
6384+
}
6385+
scanner.setTextPos(resumePos);
6386+
return finishNode(jsDocTypeLiteral);
64386387
}
6388+
}
64396389

6440-
currentParentJSDocTagEnd = scanner.getStartPos();
6441-
return undefined;
6390+
function tryParseChildTag(parentTag: JSDocTypeLiteral): boolean {
6391+
Debug.assert(token === SyntaxKind.AtToken);
6392+
const atToken = createNode(SyntaxKind.AtToken, scanner.getStartPos());
6393+
atToken.end = scanner.getTextPos();
6394+
nextJSDocToken();
6395+
6396+
const tagName = parseJSDocIdentifierName();
6397+
if (!tagName) {
6398+
return false;
6399+
}
6400+
6401+
switch (tagName.text) {
6402+
case "type":
6403+
if (parentTag.jsDocTypeTag) {
6404+
// already has a @type tag, terminate the parent tag now.
6405+
return false;
6406+
}
6407+
parentTag.jsDocTypeTag = handleTypeTag(atToken, tagName);
6408+
return true;
6409+
case "prop":
6410+
case "property":
6411+
if (!parentTag.jsDocPropertyTags) {
6412+
parentTag.jsDocPropertyTags = <NodeArray<JSDocPropertyTag>>[];
6413+
}
6414+
const propertyTag = handlePropertyTag(atToken, tagName);
6415+
parentTag.jsDocPropertyTags.push(propertyTag);
6416+
return true;
6417+
}
6418+
return false;
64426419
}
64436420

64446421
function handleTemplateTag(atToken: Node, tagName: Identifier): JSDocTemplateTag {

src/compiler/types.ts

+3-10
Original file line numberDiff line numberDiff line change
@@ -1517,29 +1517,22 @@ namespace ts {
15171517
}
15181518

15191519
// @kind(SyntaxKind.JSDocTypedefTag)
1520-
export interface JSDocTypedefTag extends JSDocTag, Declaration, JSDocParentTag {
1520+
export interface JSDocTypedefTag extends JSDocTag, Declaration {
15211521
name: Identifier;
15221522
typeExpression?: JSDocTypeExpression;
15231523
type: JSDocType;
15241524
}
15251525

1526-
export interface JSDocParentTag extends JSDocTag {
1527-
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
1528-
jsDocTypeTag?: JSDocTypeTag;
1529-
}
1530-
15311526
// @kind(SyntaxKind.JSDocPropertyTag)
15321527
export interface JSDocPropertyTag extends JSDocTag, TypeElement {
15331528
name: Identifier;
15341529
typeExpression: JSDocTypeExpression;
1535-
// Add a "type" property here to make the interface compatible
1536-
// with the "VariableLikeDeclaration" definition
1537-
type: TypeNode;
15381530
}
15391531

15401532
// @kind(SyntaxKind.JSDocTypeLiteral)
15411533
export interface JSDocTypeLiteral extends JSDocType {
1542-
members: NodeArray<TypeElement>;
1534+
jsDocPropertyTags?: NodeArray<JSDocPropertyTag>;
1535+
jsDocTypeTag?: JSDocTypeTag;
15431536
}
15441537

15451538
// @kind(SyntaxKind.JSDocParameterTag)

0 commit comments

Comments
 (0)