Skip to content

Commit ab8233c

Browse files
authored
Two JSdoc parsing fixes (microsoft#22705)
* Correctly parse JSDoc type *= * Allow `markdown` quoted param names in JSDoc * Add tests and update baselines * Get correct span for the type '*' * Fix whitespace lint * Add unbracketed type test
1 parent d3b55f4 commit ab8233c

11 files changed

+128
-6
lines changed

src/compiler/parser.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -2203,9 +2203,14 @@ namespace ts {
22032203
return finishNode(node);
22042204
}
22052205

2206-
function parseJSDocAllType(): JSDocAllType {
2206+
function parseJSDocAllType(postFixEquals: boolean): JSDocAllType | JSDocOptionalType {
22072207
const result = createNode(SyntaxKind.JSDocAllType) as JSDocAllType;
2208-
nextToken();
2208+
if (postFixEquals) {
2209+
return createJSDocPostfixType(SyntaxKind.JSDocOptionalType, result) as JSDocOptionalType;
2210+
}
2211+
else {
2212+
nextToken();
2213+
}
22092214
return finishNode(result);
22102215
}
22112216

@@ -2740,7 +2745,9 @@ namespace ts {
27402745
// If these are followed by a dot, then parse these out as a dotted type reference instead.
27412746
return tryParse(parseKeywordAndNoDot) || parseTypeReference();
27422747
case SyntaxKind.AsteriskToken:
2743-
return parseJSDocAllType();
2748+
return parseJSDocAllType(/*postfixEquals*/ false);
2749+
case SyntaxKind.AsteriskEqualsToken:
2750+
return parseJSDocAllType(/*postfixEquals*/ true);
27442751
case SyntaxKind.QuestionToken:
27452752
return parseJSDocUnknownOrNullableType();
27462753
case SyntaxKind.FunctionKeyword:
@@ -6496,6 +6503,10 @@ namespace ts {
64966503
}
64976504

64986505
function parseBracketNameInPropertyAndParamTag(): { name: EntityName, isBracketed: boolean } {
6506+
if (token() === SyntaxKind.NoSubstitutionTemplateLiteral) {
6507+
// a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
6508+
return { name: createIdentifier(/*isIdentifier*/ true), isBracketed: false };
6509+
}
64996510
// Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
65006511
const isBracketed = parseOptional(SyntaxKind.OpenBracketToken);
65016512
const name = parseJSDocEntityName();

src/compiler/scanner.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1974,6 +1974,13 @@ namespace ts {
19741974
return token = SyntaxKind.CommaToken;
19751975
case CharacterCodes.dot:
19761976
return token = SyntaxKind.DotToken;
1977+
case CharacterCodes.backtick:
1978+
while (pos < end && text.charCodeAt(pos) !== CharacterCodes.backtick) {
1979+
pos++;
1980+
}
1981+
tokenValue = text.substring(tokenPos + 1, pos);
1982+
pos++;
1983+
return token = SyntaxKind.NoSubstitutionTemplateLiteral;
19771984
}
19781985

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

src/compiler/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ namespace ts {
7373
| SyntaxKind.CommaToken
7474
| SyntaxKind.DotToken
7575
| SyntaxKind.Identifier
76+
| SyntaxKind.NoSubstitutionTemplateLiteral
7677
| SyntaxKind.Unknown;
7778

7879
export type JsxTokenSyntaxKind =
@@ -84,7 +85,7 @@ namespace ts {
8485
| SyntaxKind.OpenBraceToken
8586
| SyntaxKind.LessThanToken;
8687

87-
// token > SyntaxKind.Identifer => token is a keyword
88+
// token > SyntaxKind.Identifier => token is a keyword
8889
// Also, If you add a new SyntaxKind be sure to keep the `Markers` section at the bottom in sync
8990
export const enum SyntaxKind {
9091
Unknown,

tests/baselines/reference/api/tsserverlibrary.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ declare namespace ts {
5959
pos: number;
6060
end: number;
6161
}
62-
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.Unknown;
62+
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown;
6363
type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken;
6464
enum SyntaxKind {
6565
Unknown = 0,

tests/baselines/reference/api/typescript.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ declare namespace ts {
5959
pos: number;
6060
end: number;
6161
}
62-
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.Unknown;
62+
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown;
6363
type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken;
6464
enum SyntaxKind {
6565
Unknown = 0,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/**
3+
* @param {string=} `args`
4+
* @param `bwarg` {?number?}
5+
*/
6+
function f(args, bwarg) {
7+
>f : Symbol(f, Decl(a.js, 0, 0))
8+
>args : Symbol(args, Decl(a.js, 4, 11))
9+
>bwarg : Symbol(bwarg, Decl(a.js, 4, 16))
10+
}
11+
12+
=== tests/cases/conformance/jsdoc/ts.ts ===
13+
/**
14+
* @param `arg` - this is fine
15+
*/
16+
function g(arg: string) {
17+
>g : Symbol(g, Decl(ts.ts, 0, 0))
18+
>arg : Symbol(arg, Decl(ts.ts, 3, 11))
19+
}
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/**
3+
* @param {string=} `args`
4+
* @param `bwarg` {?number?}
5+
*/
6+
function f(args, bwarg) {
7+
>f : (args?: string | undefined, bwarg: number | null) => void
8+
>args : string | undefined
9+
>bwarg : number | null
10+
}
11+
12+
=== tests/cases/conformance/jsdoc/ts.ts ===
13+
/**
14+
* @param `arg` - this is fine
15+
*/
16+
function g(arg: string) {
17+
>g : (arg: string) => void
18+
>arg : string
19+
}
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/** @param {...*=} args
3+
@return {*=} */
4+
function f(...args) {
5+
>f : Symbol(f, Decl(a.js, 0, 0))
6+
>args : Symbol(args, Decl(a.js, 2, 11))
7+
8+
return null
9+
}
10+
11+
/** @type *= */
12+
var x;
13+
>x : Symbol(x, Decl(a.js, 7, 3))
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/jsdoc/a.js ===
2+
/** @param {...*=} args
3+
@return {*=} */
4+
function f(...args) {
5+
>f : (...args: any[]) => any
6+
>args : any[]
7+
8+
return null
9+
>null : null
10+
}
11+
12+
/** @type *= */
13+
var x;
14+
>x : any
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @strict: true
5+
// @Filename: a.js
6+
7+
/**
8+
* @param {string=} `args`
9+
* @param `bwarg` {?number?}
10+
*/
11+
function f(args, bwarg) {
12+
}
13+
14+
// @Filename: ts.ts
15+
16+
/**
17+
* @param `arg` - this is fine
18+
*/
19+
function g(arg: string) {
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @strict: true
5+
// @Filename: a.js
6+
7+
/** @param {...*=} args
8+
@return {*=} */
9+
function f(...args) {
10+
return null
11+
}
12+
13+
/** @type *= */
14+
var x;

0 commit comments

Comments
 (0)