Skip to content

Commit bfa9d3a

Browse files
committed
Handle jsdoc backticks in the parser, not scanner
Previously, the jsdoc scanner had ad-hoc handling of backticks that was similar in structure to the normal scanner's handling, but much simpler. This was a smaller code change, but is handled backwards: the special case of backtick-quoted parameter names was handled in the scanner instead of in the jsdoc identifier parsing code. That made it overapply and block correct handling of asterisks across newlines, which was most obvious in code fences inside jsdoc, as in #23517. Fixes #23517
1 parent dfdffe3 commit bfa9d3a

File tree

5 files changed

+29
-24
lines changed

5 files changed

+29
-24
lines changed

src/compiler/parser.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6337,7 +6337,14 @@ namespace ts {
63376337
const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
63386338
result.type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
63396339
if (!mayOmitBraces || hasBrace) {
6340-
parseExpected(SyntaxKind.CloseBraceToken);
6340+
// parseExpected(SyntaxKind.CloseBraceToken); // TODO: need a parseExpectedJSDoc (and rename -> parseOptionalJSDoc)
6341+
if (token() === SyntaxKind.CloseBraceToken) {
6342+
nextJSDocToken();
6343+
}
6344+
else {
6345+
parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
6346+
}
6347+
63416348
}
63426349

63436350
fixupParentReferences(result);
@@ -6722,13 +6729,17 @@ namespace ts {
67226729
}
67236730

67246731
function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
6725-
if (token() === SyntaxKind.NoSubstitutionTemplateLiteral) {
6726-
// a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
6727-
return { name: createIdentifier(/*isIdentifier*/ true), isBracketed: false };
6728-
}
67296732
// Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
6730-
const isBracketed = parseOptional(SyntaxKind.OpenBracketToken);
6733+
const isBracketed = parseOptionalJsdoc(SyntaxKind.OpenBracketToken);
6734+
if (isBracketed) {
6735+
skipWhitespace();
6736+
}
6737+
// a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
6738+
const isBackquoted = parseOptionalJsdoc(SyntaxKind.NoSubstitutionTemplateLiteral);
67316739
const name = parseJSDocEntityName();
6740+
if (isBackquoted) {
6741+
parseExpectedToken(SyntaxKind.NoSubstitutionTemplateLiteral);
6742+
}
67326743
if (isBracketed) {
67336744
skipWhitespace();
67346745

@@ -7101,10 +7112,6 @@ namespace ts {
71017112
return result;
71027113
}
71037114

7104-
function nextJSDocToken(): JsDocSyntaxKind {
7105-
return currentToken = scanner.scanJSDocToken();
7106-
}
7107-
71087115
function parseOptionalJsdoc(t: JsDocSyntaxKind): boolean {
71097116
if (token() === t) {
71107117
nextJSDocToken();
@@ -7146,6 +7153,10 @@ namespace ts {
71467153
return result;
71477154
}
71487155
}
7156+
7157+
function nextJSDocToken(): JsDocSyntaxKind {
7158+
return currentToken = scanner.scanJSDocToken();
7159+
}
71497160
}
71507161
}
71517162

src/compiler/scanner.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,14 +2093,7 @@ namespace ts {
20932093
case CharacterCodes.dot:
20942094
return token = SyntaxKind.DotToken;
20952095
case CharacterCodes.backtick:
2096-
if (pos < end && text.charCodeAt(pos) !== CharacterCodes.backtick && text.charCodeAt(pos) !== CharacterCodes.carriageReturn && text.charCodeAt(pos) !== CharacterCodes.lineFeed) {
2097-
while (pos < end && text.charCodeAt(pos) !== CharacterCodes.backtick) {
2098-
pos++;
2099-
}
2100-
tokenValue = text.substring(tokenPos + 1, pos);
2101-
pos++;
2102-
return token = SyntaxKind.NoSubstitutionTemplateLiteral;
2103-
}
2096+
return token = SyntaxKind.NoSubstitutionTemplateLiteral;
21042097
}
21052098

21062099
if (isIdentifierStart(ch, ScriptTarget.Latest)) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ namespace ts {
181181
QuestionToken,
182182
ColonToken,
183183
AtToken,
184+
// BacktickToken, // TODO: Sure would be nice! But only JSDoc would use it, which would be super confusing
184185
// Assignments
185186
EqualsToken,
186187
PlusEqualsToken,

tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"0": {
99
"kind": "JSDocParameterTag",
1010
"pos": 8,
11-
"end": 29,
11+
"end": 32,
1212
"modifierFlagsCache": 0,
1313
"transformFlags": 0,
1414
"tagName": {
@@ -46,6 +46,6 @@
4646
},
4747
"length": 1,
4848
"pos": 8,
49-
"end": 29
49+
"end": 32
5050
}
5151
}

tests/baselines/reference/paramTagWrapping.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ tests/cases/conformance/jsdoc/bad.js(2,11): error TS1003: Identifier expected.
22
tests/cases/conformance/jsdoc/bad.js(2,11): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
33
tests/cases/conformance/jsdoc/bad.js(5,4): error TS1003: Identifier expected.
44
tests/cases/conformance/jsdoc/bad.js(5,4): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
5-
tests/cases/conformance/jsdoc/bad.js(6,19): error TS1003: Identifier expected.
6-
tests/cases/conformance/jsdoc/bad.js(6,19): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
5+
tests/cases/conformance/jsdoc/bad.js(6,20): error TS1003: Identifier expected.
6+
tests/cases/conformance/jsdoc/bad.js(6,20): error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
77
tests/cases/conformance/jsdoc/bad.js(9,14): error TS7006: Parameter 'x' implicitly has an 'any' type.
88
tests/cases/conformance/jsdoc/bad.js(9,17): error TS7006: Parameter 'y' implicitly has an 'any' type.
99
tests/cases/conformance/jsdoc/bad.js(9,20): error TS7006: Parameter 'z' implicitly has an 'any' type.
@@ -39,9 +39,9 @@ tests/cases/conformance/jsdoc/bad.js(9,20): error TS7006: Parameter 'z' implicit
3939

4040
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
4141
* @param {number} * z
42-
42+
4343
!!! error TS1003: Identifier expected.
44-
44+
4545
!!! error TS8024: JSDoc '@param' tag has name '', but there is no parameter with that name.
4646
* Arg z.
4747
*/

0 commit comments

Comments
 (0)