Skip to content

Commit 81e8840

Browse files
authored
Merge pull request microsoft#9565 from zhengbli/fixTypedefParsingIssue
Fix typedef parsing issue
2 parents f0d5ff6 + ebc75a2 commit 81e8840

File tree

2 files changed

+174
-9
lines changed

2 files changed

+174
-9
lines changed

src/compiler/parser.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6374,6 +6374,9 @@ namespace ts {
63746374
case SyntaxKind.AtToken:
63756375
if (canParseTag) {
63766376
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
6377+
if (!parentTagTerminated) {
6378+
resumePos = scanner.getStartPos();
6379+
}
63776380
}
63786381
seenAsterisk = false;
63796382
break;

tests/cases/unittests/jsDocParsing.ts

+171-9
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ namespace ts {
986986
});
987987

988988
describe("DocComments", () => {
989-
function parsesCorrectly(content: string, expected: string) {
989+
function parsesCorrectly(content: string, expected: string | {}) {
990990
const comment = parseIsolatedJSDocComment(content);
991991
if (!comment) {
992992
Debug.fail("Comment failed to parse entirely");
@@ -995,30 +995,46 @@ namespace ts {
995995
Debug.fail("Comment has at least one diagnostic: " + comment.diagnostics[0].messageText);
996996
}
997997

998-
const result = JSON.stringify(comment.jsDocComment, (k, v) => {
999-
return v && v.pos !== undefined
1000-
? JSON.parse(Utils.sourceFileToJSON(v))
1001-
: v;
1002-
}, 4);
998+
const result = toJsonString(comment.jsDocComment);
1003999

1004-
if (result !== expected) {
1000+
const expectedString = typeof expected === "string"
1001+
? expected
1002+
: toJsonString(expected);
1003+
if (result !== expectedString) {
10051004
// Turn on a human-readable diff
10061005
if (typeof require !== "undefined") {
10071006
const chai = require("chai");
10081007
chai.config.showDiff = true;
1009-
chai.expect(JSON.parse(result)).equal(JSON.parse(expected));
1008+
// Use deep equal to compare key value data instead of the two objects
1009+
chai.expect(JSON.parse(result)).deep.equal(JSON.parse(expectedString));
10101010
}
10111011
else {
1012-
assert.equal(result, expected);
1012+
assert.equal(result, expectedString);
10131013
}
10141014
}
10151015
}
10161016

1017+
function toJsonString(obj: {}) {
1018+
return JSON.stringify(obj, (k, v) => {
1019+
return v && v.pos !== undefined
1020+
? JSON.parse(Utils.sourceFileToJSON(v))
1021+
: v;
1022+
}, 4);
1023+
}
1024+
10171025
function parsesIncorrectly(content: string) {
10181026
const type = parseIsolatedJSDocComment(content);
10191027
assert.isTrue(!type || type.diagnostics.length > 0);
10201028
}
10211029

1030+
function reIndentJSDocComment(jsdocComment: string) {
1031+
const result = jsdocComment
1032+
.replace(/[\t ]*\/\*\*/, "/**")
1033+
.replace(/[\t ]*\*\s?@/g, " * @")
1034+
.replace(/[\t ]*\*\s?\//, " */");
1035+
return result;
1036+
}
1037+
10221038
describe("parsesIncorrectly", () => {
10231039
it("emptyComment", () => {
10241040
parsesIncorrectly("/***/");
@@ -2216,6 +2232,152 @@ namespace ts {
22162232
}
22172233
}`);
22182234
});
2235+
2236+
it("typedefTagWithChildrenTags", () => {
2237+
const content =
2238+
`/**
2239+
* @typedef People
2240+
* @type {Object}
2241+
* @property {number} age
2242+
* @property {string} name
2243+
*/`;
2244+
const expected = {
2245+
"end": 102,
2246+
"kind": "JSDocComment",
2247+
"pos": 0,
2248+
"tags": {
2249+
"0": {
2250+
"atToken": {
2251+
"end": 9,
2252+
"kind": "AtToken",
2253+
"pos": 8
2254+
},
2255+
"end": 97,
2256+
"jsDocTypeLiteral": {
2257+
"end": 97,
2258+
"jsDocPropertyTags": [
2259+
{
2260+
"atToken": {
2261+
"end": 48,
2262+
"kind": "AtToken",
2263+
"pos": 46
2264+
},
2265+
"end": 69,
2266+
"kind": "JSDocPropertyTag",
2267+
"name": {
2268+
"end": 69,
2269+
"kind": "Identifier",
2270+
"pos": 66,
2271+
"text": "age"
2272+
},
2273+
"pos": 46,
2274+
"tagName": {
2275+
"end": 56,
2276+
"kind": "Identifier",
2277+
"pos": 48,
2278+
"text": "property"
2279+
},
2280+
"typeExpression": {
2281+
"end": 65,
2282+
"kind": "JSDocTypeExpression",
2283+
"pos": 57,
2284+
"type": {
2285+
"end": 64,
2286+
"kind": "NumberKeyword",
2287+
"pos": 58
2288+
}
2289+
}
2290+
},
2291+
{
2292+
"atToken": {
2293+
"end": 75,
2294+
"kind": "AtToken",
2295+
"pos": 73
2296+
},
2297+
"end": 97,
2298+
"kind": "JSDocPropertyTag",
2299+
"name": {
2300+
"end": 97,
2301+
"kind": "Identifier",
2302+
"pos": 93,
2303+
"text": "name"
2304+
},
2305+
"pos": 73,
2306+
"tagName": {
2307+
"end": 83,
2308+
"kind": "Identifier",
2309+
"pos": 75,
2310+
"text": "property"
2311+
},
2312+
"typeExpression": {
2313+
"end": 92,
2314+
"kind": "JSDocTypeExpression",
2315+
"pos": 84,
2316+
"type": {
2317+
"end": 91,
2318+
"kind": "StringKeyword",
2319+
"pos": 85
2320+
}
2321+
}
2322+
}
2323+
],
2324+
"jsDocTypeTag": {
2325+
"atToken": {
2326+
"end": 29,
2327+
"kind": "AtToken",
2328+
"pos": 27
2329+
},
2330+
"end": 42,
2331+
"kind": "JSDocTypeTag",
2332+
"pos": 27,
2333+
"tagName": {
2334+
"end": 33,
2335+
"kind": "Identifier",
2336+
"pos": 29,
2337+
"text": "type"
2338+
},
2339+
"typeExpression": {
2340+
"end": 42,
2341+
"kind": "JSDocTypeExpression",
2342+
"pos": 34,
2343+
"type": {
2344+
"end": 41,
2345+
"kind": "JSDocTypeReference",
2346+
"name": {
2347+
"end": 41,
2348+
"kind": "Identifier",
2349+
"pos": 35,
2350+
"text": "Object"
2351+
},
2352+
"pos": 35
2353+
}
2354+
}
2355+
},
2356+
"kind": "JSDocTypeLiteral",
2357+
"pos": 23
2358+
},
2359+
"kind": "JSDocTypedefTag",
2360+
"name": {
2361+
"end": 23,
2362+
"kind": "Identifier",
2363+
"pos": 17,
2364+
"text": "People"
2365+
},
2366+
"pos": 8,
2367+
"tagName": {
2368+
"end": 16,
2369+
"kind": "Identifier",
2370+
"pos": 9,
2371+
"text": "typedef"
2372+
}
2373+
},
2374+
"end": 97,
2375+
"length": 1,
2376+
"pos": 8
2377+
}
2378+
};
2379+
parsesCorrectly(reIndentJSDocComment(content), expected);
2380+
});
22192381
});
22202382
});
22212383
});

0 commit comments

Comments
 (0)