@cjser/es-joy__jsdoccomment 0.96.0-cjser.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,705 @@
1
+ /* eslint-disable jsdoc/reject-any-type -- Todo */
2
+ /**
3
+ * Obtained originally from {@link https://github.com/eslint/eslint/blob/master/lib/util/source-code.js#L313}.
4
+ *
5
+ * @license MIT
6
+ */
7
+
8
+ /**
9
+ * @typedef {import('eslint').AST.Token | import('estree').Comment | {
10
+ * type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
11
+ * range: [number, number],
12
+ * value: string
13
+ * }} Token
14
+ */
15
+
16
+ /**
17
+ * @typedef {import('eslint').Rule.Node|
18
+ * import('@typescript-eslint/types').TSESTree.Node} ESLintOrTSNode
19
+ */
20
+
21
+ /**
22
+ * @typedef {number} int
23
+ */
24
+
25
+ /**
26
+ * Checks if the given token is a comment token or not.
27
+ *
28
+ * @param {Token} token - The token to check.
29
+ * @returns {boolean} `true` if the token is a comment token.
30
+ */
31
+ const isCommentToken = (token) => {
32
+ return ['Line', 'Block', 'Shebang'].includes(token.type);
33
+ };
34
+
35
+ /**
36
+ * @typedef {(
37
+ * ESLintOrTSNode|
38
+ * import('estree').Comment|
39
+ * import('eslint').Rule.Node & {declaration?: any, decorators?: any[]}
40
+ * )} DecoratedNode
41
+ */
42
+ /**
43
+ * @param {DecoratedNode} node
44
+ * @returns {import('@typescript-eslint/types').TSESTree.Decorator|undefined}
45
+ */
46
+ const getDecorator = (node) => {
47
+ // @ts-expect-error -- Loose checking for decorator presence across node kinds
48
+ return node?.declaration?.decorators?.[0] ||
49
+ // @ts-expect-error -- Loose checking
50
+ node?.decorators?.[0] ||
51
+ // @ts-expect-error -- Loose checking
52
+ node?.parent?.decorators?.[0];
53
+ };
54
+
55
+ /**
56
+ * Check to see if it is a ES6 export declaration.
57
+ *
58
+ * @param {ESLintOrTSNode} astNode An AST node.
59
+ * @returns {boolean} whether the given node represents an export declaration.
60
+ * @private
61
+ */
62
+ const looksLikeExport = function (astNode) {
63
+ return [
64
+ 'ExportDefaultDeclaration',
65
+ 'ExportNamedDeclaration',
66
+ 'ExportAllDeclaration',
67
+ 'ExportSpecifier'
68
+ ].includes(astNode.type);
69
+ };
70
+
71
+ /**
72
+ * @param {ESLintOrTSNode} astNode
73
+ * @returns {ESLintOrTSNode}
74
+ */
75
+ const getTSFunctionComment = function (astNode) {
76
+ const {parent} = astNode;
77
+ /* v8 ignore next 3 */
78
+ if (!parent) {
79
+ return astNode;
80
+ }
81
+ const grandparent = parent.parent;
82
+ /* v8 ignore next 3 */
83
+ if (!grandparent) {
84
+ return astNode;
85
+ }
86
+
87
+ if (/** @type {ESLintOrTSNode} */ (parent).type !== 'TSTypeAnnotation') {
88
+ if (
89
+ parent.type === 'TSTypeAliasDeclaration' &&
90
+ grandparent.type === 'ExportNamedDeclaration'
91
+ ) {
92
+ return grandparent;
93
+ /* v8 ignore start */
94
+ }
95
+ return astNode;
96
+ /* v8 ignore stop */
97
+ }
98
+
99
+ const greatGrandparent = grandparent.parent;
100
+ const greatGreatGrandparent = greatGrandparent && greatGrandparent.parent;
101
+
102
+ switch (/** @type {ESLintOrTSNode} */ (grandparent).type) {
103
+ // @ts-expect-error -- For `ClassProperty`.
104
+ case 'PropertyDefinition': case 'ClassProperty':
105
+ case 'TSDeclareFunction':
106
+ case 'TSMethodSignature':
107
+ case 'TSPropertySignature':
108
+ return grandparent;
109
+ case 'ArrowFunctionExpression':
110
+ /* v8 ignore next 3 */
111
+ if (!greatGrandparent) {
112
+ return astNode;
113
+ }
114
+
115
+ if (
116
+ greatGrandparent.type === 'VariableDeclarator'
117
+
118
+ // && greatGreatGrandparent.parent.type === 'VariableDeclaration'
119
+ ) {
120
+ /* v8 ignore next 3 */
121
+ if (!greatGreatGrandparent || !greatGreatGrandparent.parent) {
122
+ return astNode;
123
+ }
124
+ return greatGreatGrandparent.parent;
125
+ /* v8 ignore start */
126
+ }
127
+ return astNode;
128
+ /* v8 ignore stop */
129
+ case 'FunctionExpression':
130
+ /* v8 ignore next 3 */
131
+ if (!greatGreatGrandparent) {
132
+ return astNode;
133
+ }
134
+ if (greatGrandparent.type === 'MethodDefinition') {
135
+ return greatGrandparent;
136
+ }
137
+
138
+ // Fallthrough
139
+ default:
140
+ /* v8 ignore next 3 */
141
+ if (grandparent.type !== 'Identifier') {
142
+ return astNode;
143
+ }
144
+ }
145
+
146
+ /* v8 ignore next 3 */
147
+ if (!greatGreatGrandparent) {
148
+ return astNode;
149
+ }
150
+
151
+ switch (greatGrandparent.type) {
152
+ case 'ArrowFunctionExpression':
153
+ if (
154
+ greatGreatGrandparent.type === 'VariableDeclarator' &&
155
+ greatGreatGrandparent.parent.type === 'VariableDeclaration'
156
+ ) {
157
+ return greatGreatGrandparent.parent;
158
+ }
159
+
160
+ return astNode;
161
+ case 'FunctionDeclaration':
162
+ return greatGrandparent;
163
+ case 'VariableDeclarator':
164
+ /* v8 ignore next */
165
+ if (greatGreatGrandparent.type === 'VariableDeclaration') {
166
+ return greatGreatGrandparent;
167
+ }
168
+ /* v8 ignore next 2 */
169
+ // Fallthrough
170
+ default:
171
+ /* v8 ignore next 3 */
172
+ return astNode;
173
+ }
174
+ };
175
+
176
+ const invokedExpression = new Set(
177
+ ['CallExpression', 'OptionalCallExpression', 'NewExpression']
178
+ );
179
+ const allowableCommentNode = new Set([
180
+ 'AssignmentPattern',
181
+ 'VariableDeclaration',
182
+ 'ExpressionStatement',
183
+ 'MethodDefinition',
184
+ 'Property',
185
+ 'ObjectProperty',
186
+ 'ClassProperty',
187
+ 'PropertyDefinition',
188
+ 'ExportDefaultDeclaration',
189
+ 'ReturnStatement'
190
+ ]);
191
+
192
+ /**
193
+ * @typedef {{
194
+ * maxLines: int,
195
+ * minLines: int,
196
+ * skipInvokedExpressionsForCommentFinding?: boolean,
197
+ * [name: string]: any
198
+ * }} Settings
199
+ */
200
+
201
+ /**
202
+ * Reduces the provided node to the appropriate node for evaluating
203
+ * JSDoc comment status.
204
+ *
205
+ * @param {ESLintOrTSNode} node An AST node.
206
+ * @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode.
207
+ * @param {Settings} [settings]
208
+ * @returns {ESLintOrTSNode} The AST node that
209
+ * can be evaluated for appropriate JSDoc comments.
210
+ */
211
+ const getReducedASTNode = function (node, sourceCode, settings) {
212
+ let {parent} = node;
213
+ switch (/** @type {ESLintOrTSNode} */ (node).type) {
214
+ case 'TSFunctionType':
215
+ return getTSFunctionComment(node);
216
+ case 'TSInterfaceDeclaration':
217
+ case 'TSTypeAliasDeclaration':
218
+ case 'TSEnumDeclaration':
219
+ case 'ClassDeclaration':
220
+ case 'FunctionDeclaration':
221
+ /* v8 ignore next 3 */
222
+ if (!parent) {
223
+ return node;
224
+ }
225
+ return looksLikeExport(parent) ? parent : node;
226
+
227
+ case 'TSDeclareFunction':
228
+ case 'ClassExpression':
229
+ case 'ObjectExpression':
230
+ case 'ArrowFunctionExpression':
231
+ case 'TSEmptyBodyFunctionExpression':
232
+ case 'FunctionExpression':
233
+ /* v8 ignore next 3 */
234
+ if (!parent) {
235
+ return node;
236
+ }
237
+ if (
238
+ !invokedExpression.has(parent.type) ||
239
+ settings?.skipInvokedExpressionsForCommentFinding
240
+ ) {
241
+ /**
242
+ * @type {ESLintOrTSNode|Token|null}
243
+ */
244
+ let token = node;
245
+ do {
246
+ token = sourceCode.getTokenBefore(
247
+ /** @type {import('eslint').Rule.Node|import('eslint').AST.Token} */ (
248
+ token
249
+ ),
250
+ {includeComments: true}
251
+ );
252
+ } while (token && token.type === 'Punctuator' && token.value === '(');
253
+ if (token && token.type === 'Block') {
254
+ return node;
255
+ }
256
+
257
+ if (sourceCode.getCommentsBefore(
258
+ /** @type {import('eslint').Rule.Node} */
259
+ (node)
260
+ ).length) {
261
+ return node;
262
+ }
263
+
264
+ while (
265
+ !sourceCode.getCommentsBefore(
266
+ /** @type {import('eslint').Rule.Node} */
267
+ (parent)
268
+ ).length &&
269
+ !(/Function/v).test(parent.type) &&
270
+ !allowableCommentNode.has(parent.type)
271
+ ) {
272
+ ({parent} = parent);
273
+
274
+ if (!parent) {
275
+ break;
276
+ }
277
+ }
278
+ if (parent && parent.type !== 'FunctionDeclaration' &&
279
+ parent.type !== 'Program'
280
+ ) {
281
+ if (parent.parent && parent.parent.type === 'ExportNamedDeclaration') {
282
+ return parent.parent;
283
+ }
284
+
285
+ return parent;
286
+ }
287
+ }
288
+
289
+ return node;
290
+
291
+ default:
292
+ return node;
293
+ }
294
+ };
295
+
296
+ /**
297
+ * Checks for the presence of a JSDoc comment for the given node and returns it.
298
+ *
299
+ * @param {ESLintOrTSNode} astNode The AST node to get
300
+ * the comment for.
301
+ * @param {import('eslint').SourceCode} sourceCode
302
+ * @param {{maxLines: int, minLines: int, [name: string]: any}} settings
303
+ * @param {{nonJSDoc?: boolean}} [opts]
304
+ * @returns {Token|null} The Block comment token containing the JSDoc comment
305
+ * for the given node or null if not found.
306
+ */
307
+ const findJSDocComment = (astNode, sourceCode, settings, opts = {}) => {
308
+ const {nonJSDoc} = opts;
309
+ const {minLines, maxLines} = settings;
310
+
311
+ /** @type {ESLintOrTSNode|import('estree').Comment} */
312
+ let currentNode = astNode;
313
+ let tokenBefore = null;
314
+ let parenthesisToken = null;
315
+
316
+ while (currentNode) {
317
+ const decorator = getDecorator(currentNode);
318
+ if (decorator) {
319
+ const dec = /** @type {unknown} */ (decorator);
320
+ currentNode = /** @type {import('eslint').Rule.Node} */ (dec);
321
+ }
322
+ tokenBefore = sourceCode.getTokenBefore(
323
+ /** @type {import('eslint').Rule.Node} */
324
+ (currentNode),
325
+ {includeComments: true}
326
+ );
327
+ if (
328
+ tokenBefore && tokenBefore.type === 'Punctuator' &&
329
+ tokenBefore.value === '('
330
+ ) {
331
+ parenthesisToken = tokenBefore;
332
+ [tokenBefore] = sourceCode.getTokensBefore(
333
+ /** @type {import('eslint').Rule.Node} */
334
+ (currentNode),
335
+ {
336
+ count: 2,
337
+ includeComments: true
338
+ }
339
+ );
340
+ }
341
+ if (!tokenBefore || !isCommentToken(tokenBefore)) {
342
+ return null;
343
+ }
344
+ if (!nonJSDoc && tokenBefore.type === 'Line') {
345
+ currentNode = tokenBefore;
346
+ continue;
347
+ }
348
+ break;
349
+ }
350
+
351
+ /* v8 ignore next 3 */
352
+ if (!tokenBefore || !currentNode.loc || !tokenBefore.loc) {
353
+ return null;
354
+ }
355
+
356
+ if (
357
+ (
358
+ (nonJSDoc && (tokenBefore.type !== 'Block' ||
359
+ !(/^\*\s/v).test(tokenBefore.value))) ||
360
+ (!nonJSDoc && tokenBefore.type === 'Block' &&
361
+ (/^\*\s/v).test(tokenBefore.value))
362
+ ) &&
363
+ currentNode.loc.start.line - (
364
+ /** @type {import('eslint').AST.Token} */
365
+ (parenthesisToken ?? tokenBefore)
366
+ ).loc.end.line >= minLines &&
367
+ currentNode.loc.start.line - (
368
+ /** @type {import('eslint').AST.Token} */
369
+ (parenthesisToken ?? tokenBefore)
370
+ ).loc.end.line <= maxLines
371
+ ) {
372
+ return tokenBefore;
373
+ }
374
+
375
+ return null;
376
+ };
377
+
378
+ const overloadMethodNode = new Set([
379
+ 'MethodDefinition',
380
+ 'TSAbstractMethodDefinition'
381
+ ]);
382
+
383
+ /**
384
+ * @param {ESLintOrTSNode|null|undefined} node
385
+ * @returns {ESLintOrTSNode[]|undefined}
386
+ */
387
+ const getOverloadStatementSiblings = (node) => {
388
+ if (
389
+ node &&
390
+ // eslint-disable-next-line @stylistic/max-len -- Long
391
+ // eslint-disable-next-line unicorn/prefer-includes-over-repeated-comparisons -- TS
392
+ (node.type === 'BlockStatement' ||
393
+ node.type === 'Program' ||
394
+ node.type === 'StaticBlock' ||
395
+ node.type === 'TSModuleBlock')
396
+ ) {
397
+ return /** @type {ESLintOrTSNode[]} */ (node.body);
398
+ }
399
+
400
+ return undefined;
401
+ };
402
+
403
+ /**
404
+ * @param {ESLintOrTSNode} node
405
+ * @returns {{
406
+ * bodyless: boolean,
407
+ * kind: string,
408
+ * name: string,
409
+ * static: boolean
410
+ * }|null}
411
+ */
412
+ const getMethodOverloadInfo = (node) => {
413
+ /* v8 ignore next 3 -- Defensive */
414
+ if (!overloadMethodNode.has(node.type)) {
415
+ return null;
416
+ }
417
+
418
+ /**
419
+ * @type {{
420
+ * computed?: boolean,
421
+ * key?: {name?: string},
422
+ * kind?: string,
423
+ * static?: boolean,
424
+ * value?: {type?: string}
425
+ * }}
426
+ */
427
+ // @ts-expect-error -- Loose method-shape check after node.type guard.
428
+ const method = node;
429
+ if (method.computed ||
430
+ !method.kind ||
431
+ !['method', 'constructor'].includes(/** @type {string} */ (method.kind)) ||
432
+ !method.key?.name
433
+ ) {
434
+ return null;
435
+ }
436
+
437
+ return {
438
+ bodyless: node.type === 'TSAbstractMethodDefinition' ||
439
+ method.value?.type === 'TSEmptyBodyFunctionExpression',
440
+ kind: method.kind,
441
+ name: method.key.name,
442
+ static: Boolean(method.static)
443
+ };
444
+ };
445
+
446
+ /**
447
+ * @param {ESLintOrTSNode} node
448
+ * @param {ESLintOrTSNode} prevSibling
449
+ * @returns {boolean}
450
+ */
451
+ const isMatchingMethodOverloadSibling = (node, prevSibling) => {
452
+ const current = getMethodOverloadInfo(node);
453
+ const previous = getMethodOverloadInfo(prevSibling);
454
+
455
+ return Boolean(
456
+ current &&
457
+ previous?.bodyless &&
458
+ previous.name === current.name &&
459
+ previous.kind === current.kind &&
460
+ previous.static === current.static
461
+ );
462
+ };
463
+
464
+ /**
465
+ * @param {ESLintOrTSNode} node
466
+ * @returns {string|undefined}
467
+ */
468
+ const getCurrentOverloadName = (node) => {
469
+ if (node.type === 'TSDeclareFunction' ||
470
+ node.type === 'FunctionDeclaration') {
471
+ return /** @type {{id?: {name?: string}}} */ (node).id?.name;
472
+ }
473
+
474
+ if (node.type === 'ExportNamedDeclaration') {
475
+ const {declaration} =
476
+ /** @type {{declaration?: {type?: string, id?: {name?: string}}}} */ (
477
+ node
478
+ );
479
+ if (declaration?.type === 'FunctionDeclaration' ||
480
+ declaration?.type === 'TSDeclareFunction') {
481
+ return declaration.id?.name;
482
+ }
483
+ }
484
+
485
+ if (overloadMethodNode.has(node.type)) {
486
+ const method =
487
+ /** @type {{computed?: boolean, key?: {name?: string}}} */ (node);
488
+ if (!method.computed) {
489
+ return method.key?.name;
490
+ }
491
+ }
492
+
493
+ return undefined;
494
+ };
495
+
496
+ /**
497
+ * @param {ESLintOrTSNode} node
498
+ * @returns {string|undefined}
499
+ */
500
+ const getPreviousOverloadName = (node) => {
501
+ if (node.type === 'TSDeclareFunction') {
502
+ return /** @type {{id?: {name?: string}}} */ (node).id?.name;
503
+ }
504
+
505
+ if (node.type === 'ExportNamedDeclaration') {
506
+ const {declaration} =
507
+ /** @type {{declaration?: {type?: string, id?: {name?: string}}}} */ (
508
+ node
509
+ );
510
+ if (declaration?.type === 'TSDeclareFunction') {
511
+ return declaration.id?.name;
512
+ }
513
+ }
514
+
515
+ if (overloadMethodNode.has(node.type)) {
516
+ const method =
517
+ /** @type {{computed?: boolean, key?: {name?: string}}} */ (node);
518
+ if (!method.computed) {
519
+ return method.key?.name;
520
+ }
521
+ }
522
+
523
+ return undefined;
524
+ };
525
+
526
+ /**
527
+ * @param {ESLintOrTSNode} node
528
+ * @returns {ESLintOrTSNode|null}
529
+ */
530
+ const getPreviousOverloadSibling = (node) => {
531
+ const {parent} = node;
532
+ let childNode = node;
533
+ /** @type {ESLintOrTSNode[]|undefined} */
534
+ let siblings;
535
+
536
+ if (
537
+ overloadMethodNode.has(node.type) &&
538
+ parent?.type === 'ClassBody'
539
+ ) {
540
+ siblings = /** @type {ESLintOrTSNode[]} */ (parent.body);
541
+ } else if (parent?.type === 'ExportNamedDeclaration') {
542
+ childNode = parent;
543
+ siblings = getOverloadStatementSiblings(parent.parent);
544
+ } else {
545
+ siblings = getOverloadStatementSiblings(parent);
546
+ }
547
+
548
+ if (!siblings) {
549
+ return null;
550
+ }
551
+
552
+ const idx = siblings.indexOf(childNode);
553
+ return idx > 0 ? siblings[idx - 1] : null;
554
+ };
555
+
556
+ /**
557
+ * Retrieves the JSDoc comment for a given node.
558
+ *
559
+ * @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
560
+ * @param {ESLintOrTSNode} node The AST node to get
561
+ * the comment for.
562
+ * @param {Settings} settings The settings in context
563
+ * @param {{checkOverloads?: boolean}} [opts]
564
+ * @returns {Token|null} The Block comment
565
+ * token containing the JSDoc comment for the given node or
566
+ * null if not found.
567
+ * @public
568
+ */
569
+ const getJSDocComment = function (sourceCode, node, settings, opts = {}) {
570
+ const reducedNode = getReducedASTNode(node, sourceCode, settings);
571
+ const comment = findJSDocComment(reducedNode, sourceCode, settings);
572
+
573
+ if (!comment && opts.checkOverloads) {
574
+ const functionName = getCurrentOverloadName(reducedNode);
575
+ const prevSibling = getPreviousOverloadSibling(reducedNode);
576
+ if (
577
+ prevSibling &&
578
+ functionName &&
579
+ getPreviousOverloadName(prevSibling) === functionName &&
580
+ (
581
+ !overloadMethodNode.has(reducedNode.type) ||
582
+ isMatchingMethodOverloadSibling(reducedNode, prevSibling)
583
+ )
584
+ ) {
585
+ return getJSDocComment(sourceCode, prevSibling, settings, opts);
586
+ }
587
+ }
588
+ return comment;
589
+ };
590
+
591
+ /**
592
+ * Retrieves the comment preceding a given node.
593
+ *
594
+ * @param {import('eslint').SourceCode} sourceCode The ESLint SourceCode
595
+ * @param {ESLintOrTSNode} node The AST node to get
596
+ * the comment for.
597
+ * @param {{maxLines: int, minLines: int, [name: string]: any}} settings The
598
+ * settings in context
599
+ * @returns {Token|null} The Block comment
600
+ * token containing the JSDoc comment for the given node or
601
+ * null if not found.
602
+ * @public
603
+ */
604
+ const getNonJsdocComment = function (sourceCode, node, settings) {
605
+ const reducedNode = getReducedASTNode(node, sourceCode, settings);
606
+
607
+ return findJSDocComment(reducedNode, sourceCode, settings, {
608
+ nonJSDoc: true
609
+ });
610
+ };
611
+
612
+ /**
613
+ * @param {ESLintOrTSNode|import('eslint').AST.Token|
614
+ * import('estree').Comment
615
+ * } nodeA The AST node or token to compare
616
+ * @param {ESLintOrTSNode|import('eslint').AST.Token|
617
+ * import('estree').Comment} nodeB The
618
+ * AST node or token to compare
619
+ */
620
+ const compareLocEndToStart = (nodeA, nodeB) => {
621
+ /* v8 ignore next */
622
+ return (nodeA.loc?.end.line ?? 0) === (nodeB.loc?.start.line ?? 0);
623
+ };
624
+
625
+ /**
626
+ * Checks for the presence of a comment following the given node and
627
+ * returns it.
628
+ *
629
+ * This method is experimental.
630
+ *
631
+ * @param {import('eslint').SourceCode} sourceCode
632
+ * @param {ESLintOrTSNode} astNode The AST node to get
633
+ * the comment for.
634
+ * @returns {Token|null} The comment token containing the comment
635
+ * for the given node or null if not found.
636
+ */
637
+ const getFollowingComment = function (sourceCode, astNode) {
638
+ /**
639
+ * @param {ESLintOrTSNode} node The
640
+ * AST node to get the comment for.
641
+ */
642
+ const getTokensAfterIgnoringSemis = (node) => {
643
+ let tokenAfter = sourceCode.getTokenAfter(
644
+ /** @type {import('eslint').Rule.Node} */
645
+ (node),
646
+ {includeComments: true}
647
+ );
648
+
649
+ while (
650
+ tokenAfter && tokenAfter.type === 'Punctuator' &&
651
+ // tokenAfter.value === ')' // Don't apparently need to ignore
652
+ tokenAfter.value === ';'
653
+ ) {
654
+ [tokenAfter] = sourceCode.getTokensAfter(tokenAfter, {
655
+ includeComments: true
656
+ });
657
+ }
658
+ return tokenAfter;
659
+ };
660
+
661
+ /**
662
+ * @param {ESLintOrTSNode} node The
663
+ * AST node to get the comment for.
664
+ */
665
+ const tokenAfterIgnoringSemis = (node) => {
666
+ const tokenAfter = getTokensAfterIgnoringSemis(node);
667
+ return (
668
+ tokenAfter &&
669
+ isCommentToken(tokenAfter) &&
670
+ compareLocEndToStart(node, tokenAfter)
671
+ )
672
+ ? tokenAfter
673
+ : null;
674
+ };
675
+
676
+ let tokenAfter = tokenAfterIgnoringSemis(astNode);
677
+
678
+ if (!tokenAfter) {
679
+ switch (astNode.type) {
680
+ case 'FunctionDeclaration':
681
+ tokenAfter = tokenAfterIgnoringSemis(
682
+ /** @type {ESLintOrTSNode} */
683
+ (astNode.body)
684
+ );
685
+ break;
686
+ case 'ExpressionStatement':
687
+ tokenAfter = tokenAfterIgnoringSemis(
688
+ /** @type {ESLintOrTSNode} */
689
+ (astNode.expression)
690
+ );
691
+ break;
692
+
693
+ /* v8 ignore next 3 */
694
+ default:
695
+ break;
696
+ }
697
+ }
698
+
699
+ return tokenAfter;
700
+ };
701
+
702
+ export {
703
+ getReducedASTNode, getJSDocComment, getNonJsdocComment,
704
+ getDecorator, findJSDocComment, getFollowingComment
705
+ };