Skip to content

Commit ed16d11

Browse files
authored
Merge pull request #218 from microsoft/octogonz/param-tag-fixes
Improve parsing of JSDoc optional parameter declarations
2 parents 3752eda + 3c40349 commit ed16d11

File tree

5 files changed

+89
-33
lines changed

5 files changed

+89
-33
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@microsoft/tsdoc",
5+
"comment": "Fix an issue where JSDoc optional params were not parsed correctly",
6+
"type": "patch"
7+
}
8+
],
9+
"packageName": "@microsoft/tsdoc",
10+
"email": "4673363+octogonz@users.noreply.github.com"
11+
}

tsdoc/src/__tests__/__snapshots__/ParsingBasics.test.ts.snap

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,7 @@ Object {
16531653
"nodeExcerpt": " ",
16541654
},
16551655
Object {
1656-
"kind": "Excerpt: ErrorText",
1656+
"kind": "Excerpt: NonstandardText",
16571657
"nodeExcerpt": "{type} ",
16581658
},
16591659
Object {
@@ -1719,7 +1719,7 @@ Object {
17191719
"nodeExcerpt": " ",
17201720
},
17211721
Object {
1722-
"kind": "Excerpt: ErrorText",
1722+
"kind": "Excerpt: NonstandardText",
17231723
"nodeExcerpt": "{{}} ",
17241724
},
17251725
Object {
@@ -1785,7 +1785,7 @@ Object {
17851785
"nodeExcerpt": " ",
17861786
},
17871787
Object {
1788-
"kind": "Excerpt: ErrorText",
1788+
"kind": "Excerpt: NonstandardText",
17891789
"nodeExcerpt": "{[q]{[q]} ",
17901790
},
17911791
Object {
@@ -1851,7 +1851,7 @@ Object {
18511851
"nodeExcerpt": " ",
18521852
},
18531853
Object {
1854-
"kind": "Excerpt: ErrorText",
1854+
"kind": "Excerpt: NonstandardText",
18551855
"nodeExcerpt": "{[q][b][q][q]} ",
18561856
},
18571857
Object {
@@ -1925,7 +1925,7 @@ Object {
19251925
"nodeExcerpt": " ",
19261926
},
19271927
Object {
1928-
"kind": "Excerpt: ErrorText",
1928+
"kind": "Excerpt: NonstandardText",
19291929
"nodeExcerpt": "{type} ",
19301930
},
19311931
Object {
@@ -1991,7 +1991,7 @@ Object {
19911991
"nodeExcerpt": " ",
19921992
},
19931993
Object {
1994-
"kind": "Excerpt: ErrorText",
1994+
"kind": "Excerpt: NonstandardText",
19951995
"nodeExcerpt": "{{}} ",
19961996
},
19971997
Object {
@@ -2057,7 +2057,7 @@ Object {
20572057
"nodeExcerpt": " ",
20582058
},
20592059
Object {
2060-
"kind": "Excerpt: ErrorText",
2060+
"kind": "Excerpt: NonstandardText",
20612061
"nodeExcerpt": "{[q]{[q]} ",
20622062
},
20632063
Object {
@@ -2131,7 +2131,7 @@ Object {
21312131
"nodeExcerpt": " ",
21322132
},
21332133
Object {
2134-
"kind": "Excerpt: ErrorText",
2134+
"kind": "Excerpt: NonstandardText",
21352135
"nodeExcerpt": "{type} ",
21362136
},
21372137
Object {
@@ -2197,7 +2197,7 @@ Object {
21972197
"nodeExcerpt": " ",
21982198
},
21992199
Object {
2200-
"kind": "Excerpt: ErrorText",
2200+
"kind": "Excerpt: NonstandardText",
22012201
"nodeExcerpt": "{{}} ",
22022202
},
22032203
Object {
@@ -2263,7 +2263,7 @@ Object {
22632263
"nodeExcerpt": " ",
22642264
},
22652265
Object {
2266-
"kind": "Excerpt: ErrorText",
2266+
"kind": "Excerpt: NonstandardText",
22672267
"nodeExcerpt": "{[q]{[q]} ",
22682268
},
22692269
Object {
@@ -2313,13 +2313,29 @@ Object {
23132313
"nodeExcerpt": " ",
23142314
},
23152315
Object {
2316-
"kind": "Excerpt: ErrorText",
2316+
"kind": "Excerpt: NonstandardText",
23172317
"nodeExcerpt": "[",
23182318
},
23192319
Object {
23202320
"kind": "Excerpt: ParamBlock_ParameterName",
23212321
"nodeExcerpt": "k",
23222322
},
2323+
Object {
2324+
"kind": "Excerpt: NonstandardText",
2325+
"nodeExcerpt": "]",
2326+
},
2327+
Object {
2328+
"kind": "Excerpt: Spacing",
2329+
"nodeExcerpt": " ",
2330+
},
2331+
Object {
2332+
"kind": "Excerpt: ParamBlock_Hyphen",
2333+
"nodeExcerpt": "-",
2334+
},
2335+
Object {
2336+
"kind": "Excerpt: Spacing",
2337+
"nodeExcerpt": " ",
2338+
},
23232339
Object {
23242340
"kind": "Section",
23252341
"nodes": Array [
@@ -2331,7 +2347,7 @@ Object {
23312347
"nodes": Array [
23322348
Object {
23332349
"kind": "Excerpt: PlainText",
2334-
"nodeExcerpt": "] - description",
2350+
"nodeExcerpt": "description",
23352351
},
23362352
],
23372353
},
@@ -2367,15 +2383,15 @@ Object {
23672383
"nodeExcerpt": " ",
23682384
},
23692385
Object {
2370-
"kind": "Excerpt: ErrorText",
2386+
"kind": "Excerpt: NonstandardText",
23712387
"nodeExcerpt": "[",
23722388
},
23732389
Object {
23742390
"kind": "Excerpt: ParamBlock_ParameterName",
23752391
"nodeExcerpt": "l",
23762392
},
23772393
Object {
2378-
"kind": "Excerpt: ErrorText",
2394+
"kind": "Excerpt: NonstandardText",
23792395
"nodeExcerpt": "=]",
23802396
},
23812397
Object {
@@ -2437,15 +2453,15 @@ Object {
24372453
"nodeExcerpt": " ",
24382454
},
24392455
Object {
2440-
"kind": "Excerpt: ErrorText",
2456+
"kind": "Excerpt: NonstandardText",
24412457
"nodeExcerpt": "[",
24422458
},
24432459
Object {
24442460
"kind": "Excerpt: ParamBlock_ParameterName",
24452461
"nodeExcerpt": "m",
24462462
},
24472463
Object {
2448-
"kind": "Excerpt: ErrorText",
2464+
"kind": "Excerpt: NonstandardText",
24492465
"nodeExcerpt": "=[]]",
24502466
},
24512467
Object {
@@ -2507,15 +2523,15 @@ Object {
25072523
"nodeExcerpt": " ",
25082524
},
25092525
Object {
2510-
"kind": "Excerpt: ErrorText",
2526+
"kind": "Excerpt: NonstandardText",
25112527
"nodeExcerpt": "[",
25122528
},
25132529
Object {
25142530
"kind": "Excerpt: ParamBlock_ParameterName",
25152531
"nodeExcerpt": "n",
25162532
},
25172533
Object {
2518-
"kind": "Excerpt: ErrorText",
2534+
"kind": "Excerpt: NonstandardText",
25192535
"nodeExcerpt": "=[q][[q]]",
25202536
},
25212537
Object {
@@ -2577,15 +2593,15 @@ Object {
25772593
"nodeExcerpt": " ",
25782594
},
25792595
Object {
2580-
"kind": "Excerpt: ErrorText",
2596+
"kind": "Excerpt: NonstandardText",
25812597
"nodeExcerpt": "[",
25822598
},
25832599
Object {
25842600
"kind": "Excerpt: ParamBlock_ParameterName",
25852601
"nodeExcerpt": "o",
25862602
},
25872603
Object {
2588-
"kind": "Excerpt: ErrorText",
2604+
"kind": "Excerpt: NonstandardText",
25892605
"nodeExcerpt": "=[q][b][q][q]]",
25902606
},
25912607
Object {
@@ -2648,7 +2664,6 @@ Object {
26482664
"(10,15): The @param block should not include a JSDoc-style '{type}'",
26492665
"(11,15): The @param block should not include a JSDoc-style '{type}'",
26502666
"(12,11): The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets.",
2651-
"(12,4): The @param block should be followed by a parameter name and then a hyphen",
26522667
"(13,11): The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets.",
26532668
"(14,11): The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets.",
26542669
"(15,11): The @param should not include a JSDoc-style optional name; it must not be enclosed in '[ ]' brackets.",
@@ -2726,7 +2741,7 @@ Object {
27262741
"nodeExcerpt": " ",
27272742
},
27282743
Object {
2729-
"kind": "Excerpt: ErrorText",
2744+
"kind": "Excerpt: NonstandardText",
27302745
"nodeExcerpt": "[",
27312746
},
27322747
Object {

tsdoc/src/nodes/DocExcerpt.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,19 @@ export const enum ExcerptKind {
2020
DeclarationReference_ImportPath = 'DeclarationReference_ImportPath',
2121
DeclarationReference_ImportHash = 'DeclarationReference_ImportHash',
2222

23+
/**
24+
* Input characters that were reported as an error and do not appear to be part of a valid expression.
25+
* A syntax highlighter might display them with an error color (e.g. red).
26+
*/
2327
ErrorText = 'ErrorText',
2428

29+
/**
30+
* Input characters that do not conform to the TSDoc specification, but were recognized by the parser, for example
31+
* as a known JSDoc pattern. A syntax highlighter should not display them with an error color (e.g. red)
32+
* because the error reporting may be suppressed for "lax" parsing of legacy source code.
33+
*/
34+
NonstandardText = 'NonstandardText',
35+
2536
EscapedText = 'EscapedText',
2637

2738
FencedCode_OpeningFence = 'FencedCode_OpeningFence',

tsdoc/src/nodes/DocParamBlock.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ export class DocParamBlock extends DocBlock {
8080
if (parameters.unsupportedJsdocTypeBeforeParameterNameExcerpt) {
8181
this._unsupportedJsdocTypeBeforeParameterNameExcerpt = new DocExcerpt({
8282
configuration: this.configuration,
83-
excerptKind: ExcerptKind.ErrorText,
83+
excerptKind: ExcerptKind.NonstandardText,
8484
content: parameters.unsupportedJsdocTypeBeforeParameterNameExcerpt
8585
});
8686
}
8787

8888
if (parameters.unsupportedJsdocOptionalNameOpenBracketExcerpt) {
8989
this._unsupportedJsdocOptionalNameOpenBracketExcerpt = new DocExcerpt({
9090
configuration: this.configuration,
91-
excerptKind: ExcerptKind.ErrorText,
91+
excerptKind: ExcerptKind.NonstandardText,
9292
content: parameters.unsupportedJsdocOptionalNameOpenBracketExcerpt
9393
});
9494
}
@@ -102,7 +102,7 @@ export class DocParamBlock extends DocBlock {
102102
if (parameters.unsupportedJsdocOptionalNameRestExcerpt) {
103103
this._unsupportedJsdocOptionalNameRestExcerpt = new DocExcerpt({
104104
configuration: this.configuration,
105-
excerptKind: ExcerptKind.ErrorText,
105+
excerptKind: ExcerptKind.NonstandardText,
106106
content: parameters.unsupportedJsdocOptionalNameRestExcerpt
107107
});
108108
}
@@ -118,7 +118,7 @@ export class DocParamBlock extends DocBlock {
118118
if (parameters.unsupportedJsdocTypeAfterParameterNameExcerpt) {
119119
this._unsupportedJsdocTypeAfterParameterNameExcerpt = new DocExcerpt({
120120
configuration: this.configuration,
121-
excerptKind: ExcerptKind.ErrorText,
121+
excerptKind: ExcerptKind.NonstandardText,
122122
content: parameters.unsupportedJsdocTypeAfterParameterNameExcerpt
123123
});
124124
}
@@ -142,7 +142,7 @@ export class DocParamBlock extends DocBlock {
142142
if (parameters.unsupportedJsdocTypeAfterHyphenExcerpt) {
143143
this._unsupportedJsdocTypeAfterHyphenExcerpt = new DocExcerpt({
144144
configuration: this.configuration,
145-
excerptKind: ExcerptKind.ErrorText,
145+
excerptKind: ExcerptKind.NonstandardText,
146146
content: parameters.unsupportedJsdocTypeAfterHyphenExcerpt
147147
});
148148
}

tsdoc/src/parser/NodeParser.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,13 @@ export class NodeParser {
334334
}
335335
}
336336

337-
private _tryParseJSDocTypeOrValueRest(tokenReader: TokenReader, openKind: TokenKind, closeKind: TokenKind): TokenSequence | undefined {
338-
const startMarker: number = tokenReader.createMarker();
339-
tokenReader.readToken();
337+
/**
338+
* Used by `_parseParamBlock()`, this parses a JSDoc expression remainder like `string}` or `="]"]` from
339+
* an input like `@param {string} [x="]"] - the X value`. It detects nested balanced pairs of delimiters
340+
* and escaped string literals.
341+
*/
342+
private _tryParseJSDocTypeOrValueRest(tokenReader: TokenReader, openKind: TokenKind, closeKind: TokenKind,
343+
startMarker: number): TokenSequence | undefined {
340344

341345
let quoteKind: TokenKind | undefined;
342346
let openCount: number = 1;
@@ -382,6 +386,10 @@ export class NodeParser {
382386
return tokenReader.tryExtractAccumulatedSequence();
383387
}
384388

389+
/**
390+
* Used by `_parseParamBlock()`, this parses a JSDoc expression like `{string}` from
391+
* an input like `@param {string} x - the X value`.
392+
*/
385393
private _tryParseUnsupportedJSDocType(tokenReader: TokenReader, docBlockTag: DocBlockTag, tagName: string): TokenSequence | undefined {
386394
tokenReader.assertAccumulatedSequenceIsEmpty();
387395

@@ -391,7 +399,12 @@ export class NodeParser {
391399
return undefined;
392400
}
393401

394-
let jsdocTypeExcerpt: TokenSequence | undefined = this._tryParseJSDocTypeOrValueRest(tokenReader, TokenKind.LeftCurlyBracket, TokenKind.RightCurlyBracket);
402+
const startMarker: number = tokenReader.createMarker();
403+
tokenReader.readToken(); // read the "{"
404+
405+
let jsdocTypeExcerpt: TokenSequence | undefined = this._tryParseJSDocTypeOrValueRest(tokenReader,
406+
TokenKind.LeftCurlyBracket, TokenKind.RightCurlyBracket, startMarker);
407+
395408
if (jsdocTypeExcerpt) {
396409
this._parserContext.log.addMessageForTokenSequence(
397410
TSDocMessageId.ParamTagWithInvalidType,
@@ -411,10 +424,16 @@ export class NodeParser {
411424
return jsdocTypeExcerpt;
412425
}
413426

427+
/**
428+
* Used by `_parseParamBlock()`, this parses a JSDoc expression remainder like `=[]]` from
429+
* an input like `@param {string} [x=[]] - the X value`.
430+
*/
414431
private _tryParseJSDocOptionalNameRest(tokenReader: TokenReader): TokenSequence | undefined {
415432
tokenReader.assertAccumulatedSequenceIsEmpty();
416433
if (tokenReader.peekTokenKind() !== TokenKind.EndOfInput) {
417-
return this._tryParseJSDocTypeOrValueRest(tokenReader, TokenKind.LeftSquareBracket, TokenKind.RightSquareBracket);
434+
const startMarker: number = tokenReader.createMarker();
435+
return this._tryParseJSDocTypeOrValueRest(tokenReader,
436+
TokenKind.LeftSquareBracket, TokenKind.RightSquareBracket, startMarker);
418437
}
419438
return undefined;
420439
}
@@ -431,7 +450,7 @@ export class NodeParser {
431450
// Parse opening of invalid JSDoc optional parameter name (e.g., '[')
432451
let unsupportedJsdocOptionalNameOpenBracketExcerpt: TokenSequence | undefined;
433452
if (tokenReader.peekTokenKind() === TokenKind.LeftSquareBracket) {
434-
tokenReader.readToken();
453+
tokenReader.readToken(); // read the "["
435454
unsupportedJsdocOptionalNameOpenBracketExcerpt = tokenReader.extractAccumulatedSequence();
436455
}
437456

0 commit comments

Comments
 (0)