hermes-transform 0.5.0

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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -0
  3. package/dist/detachedNode.js +128 -0
  4. package/dist/detachedNode.js.flow +113 -0
  5. package/dist/generated/TransformCloneSignatures.js.flow +19 -0
  6. package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
  7. package/dist/generated/node-types.js +2071 -0
  8. package/dist/generated/node-types.js.flow +3149 -0
  9. package/dist/generated/special-case-node-types.js +178 -0
  10. package/dist/generated/special-case-node-types.js.flow +248 -0
  11. package/dist/getVisitorKeys.js +35 -0
  12. package/dist/getVisitorKeys.js.flow +31 -0
  13. package/dist/index.js +41 -0
  14. package/dist/index.js.flow +15 -0
  15. package/dist/transform/Errors.js +151 -0
  16. package/dist/transform/Errors.js.flow +17 -0
  17. package/dist/transform/MutationContext.js +94 -0
  18. package/dist/transform/MutationContext.js.flow +80 -0
  19. package/dist/transform/TransformContext.js +136 -0
  20. package/dist/transform/TransformContext.js.flow +378 -0
  21. package/dist/transform/comments/comments.js +140 -0
  22. package/dist/transform/comments/comments.js.flow +145 -0
  23. package/dist/transform/comments/prettier/README.md +6 -0
  24. package/dist/transform/comments/prettier/common/util.js +365 -0
  25. package/dist/transform/comments/prettier/common/util.js.flow +349 -0
  26. package/dist/transform/comments/prettier/language-js/comments.js +777 -0
  27. package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
  28. package/dist/transform/comments/prettier/language-js/loc.js +41 -0
  29. package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
  30. package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
  31. package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
  32. package/dist/transform/comments/prettier/language-js/utils.js +131 -0
  33. package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
  34. package/dist/transform/comments/prettier/main/comments.js +513 -0
  35. package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
  36. package/dist/transform/comments/prettier/utils/get-last.js +15 -0
  37. package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
  38. package/dist/transform/getTransformedAST.js +159 -0
  39. package/dist/transform/getTransformedAST.js.flow +128 -0
  40. package/dist/transform/mutations/AddLeadingComments.js +47 -0
  41. package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
  42. package/dist/transform/mutations/AddTrailingComments.js +47 -0
  43. package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
  44. package/dist/transform/mutations/CloneCommentsTo.js +46 -0
  45. package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
  46. package/dist/transform/mutations/InsertStatement.js +92 -0
  47. package/dist/transform/mutations/InsertStatement.js.flow +113 -0
  48. package/dist/transform/mutations/RemoveComment.js +96 -0
  49. package/dist/transform/mutations/RemoveComment.js.flow +80 -0
  50. package/dist/transform/mutations/RemoveStatement.js +61 -0
  51. package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
  52. package/dist/transform/mutations/ReplaceNode.js +96 -0
  53. package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
  54. package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
  55. package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
  56. package/dist/transform/mutations/utils/arrayUtils.js +41 -0
  57. package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
  58. package/dist/transform/mutations/utils/getStatementParent.js +147 -0
  59. package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
  60. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
  61. package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
  62. package/dist/transform/transform.js +69 -0
  63. package/dist/transform/transform.js.flow +60 -0
  64. package/dist/traverse/NodeEventGenerator.js +427 -0
  65. package/dist/traverse/NodeEventGenerator.js.flow +406 -0
  66. package/dist/traverse/SafeEmitter.js +70 -0
  67. package/dist/traverse/SafeEmitter.js.flow +46 -0
  68. package/dist/traverse/SimpleTraverser.js +149 -0
  69. package/dist/traverse/SimpleTraverser.js.flow +109 -0
  70. package/dist/traverse/esquery.js +37 -0
  71. package/dist/traverse/esquery.js.flow +173 -0
  72. package/dist/traverse/traverse.js +139 -0
  73. package/dist/traverse/traverse.js.flow +149 -0
  74. package/package.json +22 -0
@@ -0,0 +1,950 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const {
13
+ getLast,
14
+ hasNewline,
15
+ addLeadingComment,
16
+ getNextNonSpaceNonCommentCharacterIndexWithStartIndex,
17
+ getNextNonSpaceNonCommentCharacterIndex,
18
+ hasNewlineInRange,
19
+ addTrailingComment,
20
+ addDanglingComment,
21
+ getNextNonSpaceNonCommentCharacter,
22
+ isNonEmptyArray,
23
+ } = require('../common/util.js');
24
+ const {
25
+ isBlockComment,
26
+ getFunctionParameters,
27
+ isPrettierIgnoreComment,
28
+ isCallLikeExpression,
29
+ getCallArguments,
30
+ isCallExpression,
31
+ isMemberExpression,
32
+ isObjectProperty,
33
+ } = require('./utils.js');
34
+ const {locStart, locEnd} = require('./loc.js');
35
+
36
+ /**
37
+ * @typedef {import("./types/estree").Node} Node
38
+ * @typedef {import("./types/estree").Comment} Comment
39
+ * @typedef {import("../common/ast-path")} AstPath
40
+ *
41
+ * @typedef {Object} CommentContext
42
+ * @property {Comment} comment
43
+ * @property {Node} precedingNode
44
+ * @property {Node} enclosingNode
45
+ * @property {Node} followingNode
46
+ * @property {string} text
47
+ * @property {any} options
48
+ * @property {Node} ast
49
+ * @property {boolean} isLastComment
50
+ */
51
+
52
+ /**
53
+ * @param {CommentContext} context
54
+ * @returns {boolean}
55
+ */
56
+ function handleOwnLineComment(context) {
57
+ return [
58
+ handleIgnoreComments,
59
+ handleLastFunctionArgComments,
60
+ handleMemberExpressionComments,
61
+ handleIfStatementComments,
62
+ handleWhileComments,
63
+ handleTryStatementComments,
64
+ handleClassComments,
65
+ handleImportSpecifierComments,
66
+ handleForComments,
67
+ handleUnionTypeComments,
68
+ handleOnlyComments,
69
+ handleImportDeclarationComments,
70
+ handleAssignmentPatternComments,
71
+ handleMethodNameComments,
72
+ handleLabeledStatementComments,
73
+ ].some(fn => fn(context));
74
+ }
75
+
76
+ /**
77
+ * @param {CommentContext} context
78
+ * @returns {boolean}
79
+ */
80
+ function handleEndOfLineComment(context) {
81
+ return [
82
+ handleClosureTypeCastComments,
83
+ handleLastFunctionArgComments,
84
+ handleConditionalExpressionComments,
85
+ handleImportSpecifierComments,
86
+ handleIfStatementComments,
87
+ handleWhileComments,
88
+ handleTryStatementComments,
89
+ handleClassComments,
90
+ handleLabeledStatementComments,
91
+ handleCallExpressionComments,
92
+ handlePropertyComments,
93
+ handleOnlyComments,
94
+ handleTypeAliasComments,
95
+ handleVariableDeclaratorComments,
96
+ ].some(fn => fn(context));
97
+ }
98
+
99
+ /**
100
+ * @param {CommentContext} context
101
+ * @returns {boolean}
102
+ */
103
+ function handleRemainingComment(context) {
104
+ return [
105
+ handleIgnoreComments,
106
+ handleIfStatementComments,
107
+ handleWhileComments,
108
+ handleObjectPropertyAssignment,
109
+ handleCommentInEmptyParens,
110
+ handleMethodNameComments,
111
+ handleOnlyComments,
112
+ handleCommentAfterArrowParams,
113
+ handleFunctionNameComments,
114
+ handleTSMappedTypeComments,
115
+ handleBreakAndContinueStatementComments,
116
+ handleTSFunctionTrailingComments,
117
+ ].some(fn => fn(context));
118
+ }
119
+
120
+ /**
121
+ * @param {Node} node
122
+ * @returns {void}
123
+ */
124
+ function addBlockStatementFirstComment(node, comment) {
125
+ // @ts-expect-error
126
+ const firstNonEmptyNode = (node.body || node.properties).find(
127
+ ({type}) => type !== 'EmptyStatement',
128
+ );
129
+ if (firstNonEmptyNode) {
130
+ addLeadingComment(firstNonEmptyNode, comment);
131
+ } else {
132
+ addDanglingComment(node, comment);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @param {Node} node
138
+ * @returns {void}
139
+ */
140
+ function addBlockOrNotComment(node, comment) {
141
+ if (node.type === 'BlockStatement') {
142
+ addBlockStatementFirstComment(node, comment);
143
+ } else {
144
+ addLeadingComment(node, comment);
145
+ }
146
+ }
147
+
148
+ function handleClosureTypeCastComments({comment, followingNode}) {
149
+ if (followingNode && isTypeCastComment(comment)) {
150
+ addLeadingComment(followingNode, comment);
151
+ return true;
152
+ }
153
+ return false;
154
+ }
155
+
156
+ // There are often comments before the else clause of if statements like
157
+ //
158
+ // if (1) { ... }
159
+ // // comment
160
+ // else { ... }
161
+ //
162
+ // They are being attached as leading comments of the BlockExpression which
163
+ // is not well printed. What we want is to instead move the comment inside
164
+ // of the block and make it leadingComment of the first element of the block
165
+ // or dangling comment of the block if there is nothing inside
166
+ //
167
+ // if (1) { ... }
168
+ // else {
169
+ // // comment
170
+ // ...
171
+ // }
172
+ function handleIfStatementComments({
173
+ comment,
174
+ precedingNode,
175
+ enclosingNode,
176
+ followingNode,
177
+ text,
178
+ }) {
179
+ if (
180
+ !enclosingNode ||
181
+ enclosingNode.type !== 'IfStatement' ||
182
+ !followingNode
183
+ ) {
184
+ return false;
185
+ }
186
+
187
+ // We unfortunately have no way using the AST or location of nodes to know
188
+ // if the comment is positioned before the condition parenthesis:
189
+ // if (a /* comment */) {}
190
+ // The only workaround I found is to look at the next character to see if
191
+ // it is a ).
192
+ const nextCharacter = getNextNonSpaceNonCommentCharacter(
193
+ text,
194
+ comment,
195
+ locEnd,
196
+ );
197
+ if (nextCharacter === ')') {
198
+ addTrailingComment(precedingNode, comment);
199
+ return true;
200
+ }
201
+
202
+ // Comments before `else`:
203
+ // - treat as trailing comments of the consequent, if it's a BlockStatement
204
+ // - treat as a dangling comment otherwise
205
+ if (
206
+ precedingNode === enclosingNode.consequent &&
207
+ followingNode === enclosingNode.alternate
208
+ ) {
209
+ if (precedingNode.type === 'BlockStatement') {
210
+ addTrailingComment(precedingNode, comment);
211
+ } else {
212
+ addDanglingComment(enclosingNode, comment);
213
+ }
214
+ return true;
215
+ }
216
+
217
+ if (followingNode.type === 'BlockStatement') {
218
+ addBlockStatementFirstComment(followingNode, comment);
219
+ return true;
220
+ }
221
+
222
+ if (followingNode.type === 'IfStatement') {
223
+ addBlockOrNotComment(followingNode.consequent, comment);
224
+ return true;
225
+ }
226
+
227
+ // For comments positioned after the condition parenthesis in an if statement
228
+ // before the consequent without brackets on, such as
229
+ // if (a) /* comment */ true,
230
+ // we look at the next character to see if the following node
231
+ // is the consequent for the if statement
232
+ if (enclosingNode.consequent === followingNode) {
233
+ addLeadingComment(followingNode, comment);
234
+ return true;
235
+ }
236
+
237
+ return false;
238
+ }
239
+
240
+ function handleWhileComments({
241
+ comment,
242
+ precedingNode,
243
+ enclosingNode,
244
+ followingNode,
245
+ text,
246
+ }) {
247
+ if (
248
+ !enclosingNode ||
249
+ enclosingNode.type !== 'WhileStatement' ||
250
+ !followingNode
251
+ ) {
252
+ return false;
253
+ }
254
+
255
+ // We unfortunately have no way using the AST or location of nodes to know
256
+ // if the comment is positioned before the condition parenthesis:
257
+ // while (a /* comment */) {}
258
+ // The only workaround I found is to look at the next character to see if
259
+ // it is a ).
260
+ const nextCharacter = getNextNonSpaceNonCommentCharacter(
261
+ text,
262
+ comment,
263
+ locEnd,
264
+ );
265
+ if (nextCharacter === ')') {
266
+ addTrailingComment(precedingNode, comment);
267
+ return true;
268
+ }
269
+
270
+ if (followingNode.type === 'BlockStatement') {
271
+ addBlockStatementFirstComment(followingNode, comment);
272
+ return true;
273
+ }
274
+
275
+ if (enclosingNode.body === followingNode) {
276
+ addLeadingComment(followingNode, comment);
277
+ return true;
278
+ }
279
+
280
+ return false;
281
+ }
282
+
283
+ // Same as IfStatement but for TryStatement
284
+ function handleTryStatementComments({
285
+ comment,
286
+ precedingNode,
287
+ enclosingNode,
288
+ followingNode,
289
+ }) {
290
+ if (
291
+ !enclosingNode ||
292
+ (enclosingNode.type !== 'TryStatement' &&
293
+ enclosingNode.type !== 'CatchClause') ||
294
+ !followingNode
295
+ ) {
296
+ return false;
297
+ }
298
+
299
+ if (enclosingNode.type === 'CatchClause' && precedingNode) {
300
+ addTrailingComment(precedingNode, comment);
301
+ return true;
302
+ }
303
+
304
+ if (followingNode.type === 'BlockStatement') {
305
+ addBlockStatementFirstComment(followingNode, comment);
306
+ return true;
307
+ }
308
+
309
+ if (followingNode.type === 'TryStatement') {
310
+ addBlockOrNotComment(followingNode.finalizer, comment);
311
+ return true;
312
+ }
313
+
314
+ if (followingNode.type === 'CatchClause') {
315
+ addBlockOrNotComment(followingNode.body, comment);
316
+ return true;
317
+ }
318
+
319
+ return false;
320
+ }
321
+
322
+ function handleMemberExpressionComments({
323
+ comment,
324
+ enclosingNode,
325
+ followingNode,
326
+ }) {
327
+ if (
328
+ isMemberExpression(enclosingNode) &&
329
+ followingNode &&
330
+ followingNode.type === 'Identifier'
331
+ ) {
332
+ addLeadingComment(enclosingNode, comment);
333
+ return true;
334
+ }
335
+
336
+ return false;
337
+ }
338
+
339
+ function handleConditionalExpressionComments({
340
+ comment,
341
+ precedingNode,
342
+ enclosingNode,
343
+ followingNode,
344
+ text,
345
+ }) {
346
+ const isSameLineAsPrecedingNode =
347
+ precedingNode &&
348
+ !hasNewlineInRange(text, locEnd(precedingNode), locStart(comment));
349
+
350
+ if (
351
+ (!precedingNode || !isSameLineAsPrecedingNode) &&
352
+ enclosingNode &&
353
+ (enclosingNode.type === 'ConditionalExpression' ||
354
+ enclosingNode.type === 'TSConditionalType') &&
355
+ followingNode
356
+ ) {
357
+ addLeadingComment(followingNode, comment);
358
+ return true;
359
+ }
360
+ return false;
361
+ }
362
+
363
+ function handleObjectPropertyAssignment({
364
+ comment,
365
+ precedingNode,
366
+ enclosingNode,
367
+ }) {
368
+ if (
369
+ isObjectProperty(enclosingNode) &&
370
+ enclosingNode.shorthand &&
371
+ enclosingNode.key === precedingNode &&
372
+ enclosingNode.value.type === 'AssignmentPattern'
373
+ ) {
374
+ addTrailingComment(enclosingNode.value.left, comment);
375
+ return true;
376
+ }
377
+ return false;
378
+ }
379
+
380
+ function handleClassComments({
381
+ comment,
382
+ precedingNode,
383
+ enclosingNode,
384
+ followingNode,
385
+ }) {
386
+ if (
387
+ enclosingNode &&
388
+ (enclosingNode.type === 'ClassDeclaration' ||
389
+ enclosingNode.type === 'ClassExpression' ||
390
+ enclosingNode.type === 'DeclareClass' ||
391
+ enclosingNode.type === 'DeclareInterface' ||
392
+ enclosingNode.type === 'InterfaceDeclaration' ||
393
+ enclosingNode.type === 'TSInterfaceDeclaration')
394
+ ) {
395
+ if (
396
+ isNonEmptyArray(enclosingNode.decorators) &&
397
+ !(followingNode && followingNode.type === 'Decorator')
398
+ ) {
399
+ addTrailingComment(getLast(enclosingNode.decorators), comment);
400
+ return true;
401
+ }
402
+
403
+ if (enclosingNode.body && followingNode === enclosingNode.body) {
404
+ addBlockStatementFirstComment(enclosingNode.body, comment);
405
+ return true;
406
+ }
407
+
408
+ // Don't add leading comments to `implements`, `extends`, `mixins` to
409
+ // avoid printing the comment after the keyword.
410
+ if (followingNode) {
411
+ for (const prop of ['implements', 'extends', 'mixins']) {
412
+ if (enclosingNode[prop] && followingNode === enclosingNode[prop][0]) {
413
+ if (
414
+ precedingNode &&
415
+ (precedingNode === enclosingNode.id ||
416
+ precedingNode === enclosingNode.typeParameters ||
417
+ precedingNode === enclosingNode.superClass)
418
+ ) {
419
+ addTrailingComment(precedingNode, comment);
420
+ } else {
421
+ addDanglingComment(enclosingNode, comment, prop);
422
+ }
423
+ return true;
424
+ }
425
+ }
426
+ }
427
+ }
428
+ return false;
429
+ }
430
+
431
+ function handleMethodNameComments({
432
+ comment,
433
+ precedingNode,
434
+ enclosingNode,
435
+ text,
436
+ }) {
437
+ // This is only needed for estree parsers (flow, typescript) to attach
438
+ // after a method name:
439
+ // obj = { fn /*comment*/() {} };
440
+ if (
441
+ enclosingNode &&
442
+ precedingNode &&
443
+ // "MethodDefinition" is handled in getCommentChildNodes
444
+ (enclosingNode.type === 'Property' ||
445
+ enclosingNode.type === 'TSDeclareMethod' ||
446
+ enclosingNode.type === 'TSAbstractMethodDefinition') &&
447
+ precedingNode.type === 'Identifier' &&
448
+ enclosingNode.key === precedingNode &&
449
+ // special Property case: { key: /*comment*/(value) };
450
+ // comment should be attached to value instead of key
451
+ getNextNonSpaceNonCommentCharacter(text, precedingNode, locEnd) !== ':'
452
+ ) {
453
+ addTrailingComment(precedingNode, comment);
454
+ return true;
455
+ }
456
+
457
+ // Print comments between decorators and class methods as a trailing comment
458
+ // on the decorator node instead of the method node
459
+ if (
460
+ precedingNode &&
461
+ enclosingNode &&
462
+ precedingNode.type === 'Decorator' &&
463
+ (enclosingNode.type === 'ClassMethod' ||
464
+ enclosingNode.type === 'ClassProperty' ||
465
+ enclosingNode.type === 'PropertyDefinition' ||
466
+ enclosingNode.type === 'TSAbstractPropertyDefinition' ||
467
+ enclosingNode.type === 'TSAbstractMethodDefinition' ||
468
+ enclosingNode.type === 'TSDeclareMethod' ||
469
+ enclosingNode.type === 'MethodDefinition')
470
+ ) {
471
+ addTrailingComment(precedingNode, comment);
472
+ return true;
473
+ }
474
+
475
+ return false;
476
+ }
477
+
478
+ function handleFunctionNameComments({
479
+ comment,
480
+ precedingNode,
481
+ enclosingNode,
482
+ text,
483
+ }) {
484
+ if (getNextNonSpaceNonCommentCharacter(text, comment, locEnd) !== '(') {
485
+ return false;
486
+ }
487
+ if (
488
+ precedingNode &&
489
+ enclosingNode &&
490
+ (enclosingNode.type === 'FunctionDeclaration' ||
491
+ enclosingNode.type === 'FunctionExpression' ||
492
+ enclosingNode.type === 'ClassMethod' ||
493
+ enclosingNode.type === 'MethodDefinition' ||
494
+ enclosingNode.type === 'ObjectMethod')
495
+ ) {
496
+ addTrailingComment(precedingNode, comment);
497
+ return true;
498
+ }
499
+ return false;
500
+ }
501
+
502
+ function handleCommentAfterArrowParams({comment, enclosingNode, text}) {
503
+ if (!(enclosingNode && enclosingNode.type === 'ArrowFunctionExpression')) {
504
+ return false;
505
+ }
506
+
507
+ const index = getNextNonSpaceNonCommentCharacterIndex(text, comment, locEnd);
508
+ if (index !== false && text.slice(index, index + 2) === '=>') {
509
+ addDanglingComment(enclosingNode, comment);
510
+ return true;
511
+ }
512
+
513
+ return false;
514
+ }
515
+
516
+ function handleCommentInEmptyParens({comment, enclosingNode, text}) {
517
+ if (getNextNonSpaceNonCommentCharacter(text, comment, locEnd) !== ')') {
518
+ return false;
519
+ }
520
+
521
+ // Only add dangling comments to fix the case when no params are present,
522
+ // i.e. a function without any argument.
523
+ if (
524
+ enclosingNode &&
525
+ ((isRealFunctionLikeNode(enclosingNode) &&
526
+ getFunctionParameters(enclosingNode).length === 0) ||
527
+ (isCallLikeExpression(enclosingNode) &&
528
+ getCallArguments(enclosingNode).length === 0))
529
+ ) {
530
+ addDanglingComment(enclosingNode, comment);
531
+ return true;
532
+ }
533
+ if (
534
+ enclosingNode &&
535
+ (enclosingNode.type === 'MethodDefinition' ||
536
+ enclosingNode.type === 'TSAbstractMethodDefinition') &&
537
+ getFunctionParameters(enclosingNode.value).length === 0
538
+ ) {
539
+ addDanglingComment(enclosingNode.value, comment);
540
+ return true;
541
+ }
542
+ return false;
543
+ }
544
+
545
+ function handleLastFunctionArgComments({
546
+ comment,
547
+ precedingNode,
548
+ enclosingNode,
549
+ followingNode,
550
+ text,
551
+ }) {
552
+ // Flow function type definitions
553
+ if (
554
+ precedingNode &&
555
+ precedingNode.type === 'FunctionTypeParam' &&
556
+ enclosingNode &&
557
+ enclosingNode.type === 'FunctionTypeAnnotation' &&
558
+ followingNode &&
559
+ followingNode.type !== 'FunctionTypeParam'
560
+ ) {
561
+ addTrailingComment(precedingNode, comment);
562
+ return true;
563
+ }
564
+
565
+ // Real functions and TypeScript function type definitions
566
+ if (
567
+ precedingNode &&
568
+ (precedingNode.type === 'Identifier' ||
569
+ precedingNode.type === 'AssignmentPattern') &&
570
+ enclosingNode &&
571
+ isRealFunctionLikeNode(enclosingNode) &&
572
+ getNextNonSpaceNonCommentCharacter(text, comment, locEnd) === ')'
573
+ ) {
574
+ addTrailingComment(precedingNode, comment);
575
+ return true;
576
+ }
577
+
578
+ if (
579
+ enclosingNode &&
580
+ enclosingNode.type === 'FunctionDeclaration' &&
581
+ followingNode &&
582
+ followingNode.type === 'BlockStatement'
583
+ ) {
584
+ const functionParamRightParenIndex = (() => {
585
+ const parameters = getFunctionParameters(enclosingNode);
586
+ if (parameters.length > 0) {
587
+ return getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
588
+ text,
589
+ locEnd(getLast(parameters)),
590
+ );
591
+ }
592
+ const functionParamLeftParenIndex =
593
+ getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
594
+ text,
595
+ locEnd(enclosingNode.id),
596
+ );
597
+ return (
598
+ functionParamLeftParenIndex !== false &&
599
+ getNextNonSpaceNonCommentCharacterIndexWithStartIndex(
600
+ text,
601
+ functionParamLeftParenIndex + 1,
602
+ )
603
+ );
604
+ })();
605
+ if (locStart(comment) > functionParamRightParenIndex) {
606
+ addBlockStatementFirstComment(followingNode, comment);
607
+ return true;
608
+ }
609
+ }
610
+
611
+ return false;
612
+ }
613
+
614
+ function handleImportSpecifierComments({comment, enclosingNode}) {
615
+ if (enclosingNode && enclosingNode.type === 'ImportSpecifier') {
616
+ addLeadingComment(enclosingNode, comment);
617
+ return true;
618
+ }
619
+ return false;
620
+ }
621
+
622
+ function handleLabeledStatementComments({comment, enclosingNode}) {
623
+ if (enclosingNode && enclosingNode.type === 'LabeledStatement') {
624
+ addLeadingComment(enclosingNode, comment);
625
+ return true;
626
+ }
627
+ return false;
628
+ }
629
+
630
+ function handleBreakAndContinueStatementComments({comment, enclosingNode}) {
631
+ if (
632
+ enclosingNode &&
633
+ (enclosingNode.type === 'ContinueStatement' ||
634
+ enclosingNode.type === 'BreakStatement') &&
635
+ !enclosingNode.label
636
+ ) {
637
+ addTrailingComment(enclosingNode, comment);
638
+ return true;
639
+ }
640
+ return false;
641
+ }
642
+
643
+ function handleCallExpressionComments({comment, precedingNode, enclosingNode}) {
644
+ if (
645
+ isCallExpression(enclosingNode) &&
646
+ precedingNode &&
647
+ enclosingNode.callee === precedingNode &&
648
+ enclosingNode.arguments.length > 0
649
+ ) {
650
+ addLeadingComment(enclosingNode.arguments[0], comment);
651
+ return true;
652
+ }
653
+ return false;
654
+ }
655
+
656
+ function handleUnionTypeComments({
657
+ comment,
658
+ precedingNode,
659
+ enclosingNode,
660
+ followingNode,
661
+ }) {
662
+ if (
663
+ enclosingNode &&
664
+ (enclosingNode.type === 'UnionTypeAnnotation' ||
665
+ enclosingNode.type === 'TSUnionType')
666
+ ) {
667
+ if (isPrettierIgnoreComment(comment)) {
668
+ followingNode.prettierIgnore = true;
669
+ comment.unignore = true;
670
+ }
671
+ if (precedingNode) {
672
+ addTrailingComment(precedingNode, comment);
673
+ return true;
674
+ }
675
+ return false;
676
+ }
677
+
678
+ if (
679
+ followingNode &&
680
+ (followingNode.type === 'UnionTypeAnnotation' ||
681
+ followingNode.type === 'TSUnionType') &&
682
+ isPrettierIgnoreComment(comment)
683
+ ) {
684
+ followingNode.types[0].prettierIgnore = true;
685
+ comment.unignore = true;
686
+ }
687
+
688
+ return false;
689
+ }
690
+
691
+ function handlePropertyComments({comment, enclosingNode}) {
692
+ if (isObjectProperty(enclosingNode)) {
693
+ addLeadingComment(enclosingNode, comment);
694
+ return true;
695
+ }
696
+ return false;
697
+ }
698
+
699
+ function handleOnlyComments({
700
+ comment,
701
+ enclosingNode,
702
+ followingNode,
703
+ ast,
704
+ isLastComment,
705
+ }) {
706
+ // With Flow the enclosingNode is undefined so use the AST instead.
707
+ if (ast && ast.body && ast.body.length === 0) {
708
+ if (isLastComment) {
709
+ addDanglingComment(ast, comment);
710
+ } else {
711
+ addLeadingComment(ast, comment);
712
+ }
713
+ return true;
714
+ }
715
+
716
+ if (
717
+ enclosingNode &&
718
+ enclosingNode.type === 'Program' &&
719
+ enclosingNode.body.length === 0 &&
720
+ !isNonEmptyArray(enclosingNode.directives)
721
+ ) {
722
+ if (isLastComment) {
723
+ addDanglingComment(enclosingNode, comment);
724
+ } else {
725
+ addLeadingComment(enclosingNode, comment);
726
+ }
727
+ return true;
728
+ }
729
+
730
+ if (
731
+ followingNode &&
732
+ followingNode.type === 'Program' &&
733
+ followingNode.body.length === 0 &&
734
+ enclosingNode &&
735
+ enclosingNode.type === 'ModuleExpression'
736
+ ) {
737
+ addDanglingComment(followingNode, comment);
738
+ return true;
739
+ }
740
+
741
+ return false;
742
+ }
743
+
744
+ function handleForComments({comment, enclosingNode}) {
745
+ if (
746
+ enclosingNode &&
747
+ (enclosingNode.type === 'ForInStatement' ||
748
+ enclosingNode.type === 'ForOfStatement')
749
+ ) {
750
+ addLeadingComment(enclosingNode, comment);
751
+ return true;
752
+ }
753
+ return false;
754
+ }
755
+
756
+ function handleImportDeclarationComments({
757
+ comment,
758
+ precedingNode,
759
+ enclosingNode,
760
+ text,
761
+ }) {
762
+ if (
763
+ precedingNode &&
764
+ precedingNode.type === 'ImportSpecifier' &&
765
+ enclosingNode &&
766
+ enclosingNode.type === 'ImportDeclaration' &&
767
+ hasNewline(text, locEnd(comment))
768
+ ) {
769
+ addTrailingComment(precedingNode, comment);
770
+ return true;
771
+ }
772
+ return false;
773
+ }
774
+
775
+ function handleAssignmentPatternComments({comment, enclosingNode}) {
776
+ if (enclosingNode && enclosingNode.type === 'AssignmentPattern') {
777
+ addLeadingComment(enclosingNode, comment);
778
+ return true;
779
+ }
780
+ return false;
781
+ }
782
+
783
+ function handleTypeAliasComments({comment, enclosingNode}) {
784
+ if (enclosingNode && enclosingNode.type === 'TypeAlias') {
785
+ addLeadingComment(enclosingNode, comment);
786
+ return true;
787
+ }
788
+ return false;
789
+ }
790
+
791
+ function handleVariableDeclaratorComments({
792
+ comment,
793
+ enclosingNode,
794
+ followingNode,
795
+ }) {
796
+ if (
797
+ enclosingNode &&
798
+ (enclosingNode.type === 'VariableDeclarator' ||
799
+ enclosingNode.type === 'AssignmentExpression') &&
800
+ followingNode &&
801
+ (followingNode.type === 'ObjectExpression' ||
802
+ followingNode.type === 'ArrayExpression' ||
803
+ followingNode.type === 'TemplateLiteral' ||
804
+ followingNode.type === 'TaggedTemplateExpression' ||
805
+ isBlockComment(comment))
806
+ ) {
807
+ addLeadingComment(followingNode, comment);
808
+ return true;
809
+ }
810
+ return false;
811
+ }
812
+
813
+ function handleTSFunctionTrailingComments({
814
+ comment,
815
+ enclosingNode,
816
+ followingNode,
817
+ text,
818
+ }) {
819
+ if (
820
+ !followingNode &&
821
+ enclosingNode &&
822
+ (enclosingNode.type === 'TSMethodSignature' ||
823
+ enclosingNode.type === 'TSDeclareFunction' ||
824
+ enclosingNode.type === 'TSAbstractMethodDefinition') &&
825
+ getNextNonSpaceNonCommentCharacter(text, comment, locEnd) === ';'
826
+ ) {
827
+ addTrailingComment(enclosingNode, comment);
828
+ return true;
829
+ }
830
+ return false;
831
+ }
832
+
833
+ function handleIgnoreComments({comment, enclosingNode, followingNode}) {
834
+ if (
835
+ isPrettierIgnoreComment(comment) &&
836
+ enclosingNode &&
837
+ enclosingNode.type === 'TSMappedType' &&
838
+ followingNode &&
839
+ followingNode.type === 'TSTypeParameter' &&
840
+ followingNode.constraint
841
+ ) {
842
+ enclosingNode.prettierIgnore = true;
843
+ comment.unignore = true;
844
+ return true;
845
+ }
846
+ }
847
+
848
+ function handleTSMappedTypeComments({
849
+ comment,
850
+ precedingNode,
851
+ enclosingNode,
852
+ followingNode,
853
+ }) {
854
+ if (!enclosingNode || enclosingNode.type !== 'TSMappedType') {
855
+ return false;
856
+ }
857
+
858
+ if (
859
+ followingNode &&
860
+ followingNode.type === 'TSTypeParameter' &&
861
+ followingNode.name
862
+ ) {
863
+ addLeadingComment(followingNode.name, comment);
864
+ return true;
865
+ }
866
+
867
+ if (
868
+ precedingNode &&
869
+ precedingNode.type === 'TSTypeParameter' &&
870
+ precedingNode.constraint
871
+ ) {
872
+ addTrailingComment(precedingNode.constraint, comment);
873
+ return true;
874
+ }
875
+
876
+ return false;
877
+ }
878
+
879
+ /**
880
+ * @param {Node} node
881
+ * @returns {boolean}
882
+ */
883
+ function isRealFunctionLikeNode(node) {
884
+ return (
885
+ node.type === 'ArrowFunctionExpression' ||
886
+ node.type === 'FunctionExpression' ||
887
+ node.type === 'FunctionDeclaration' ||
888
+ node.type === 'ObjectMethod' ||
889
+ node.type === 'ClassMethod' ||
890
+ node.type === 'TSDeclareFunction' ||
891
+ node.type === 'TSCallSignatureDeclaration' ||
892
+ node.type === 'TSConstructSignatureDeclaration' ||
893
+ node.type === 'TSMethodSignature' ||
894
+ node.type === 'TSConstructorType' ||
895
+ node.type === 'TSFunctionType' ||
896
+ node.type === 'TSDeclareMethod'
897
+ );
898
+ }
899
+
900
+ /**
901
+ * @param {any} node
902
+ * @returns {Node[] | void}
903
+ */
904
+ function getCommentChildNodes(node, options) {
905
+ // Prevent attaching comments to FunctionExpression in this case:
906
+ // class Foo {
907
+ // bar() // comment
908
+ // {
909
+ // baz();
910
+ // }
911
+ // }
912
+ if (
913
+ (options.parser === 'typescript' ||
914
+ options.parser === 'flow' ||
915
+ options.parser === 'espree' ||
916
+ options.parser === 'meriyah' ||
917
+ options.parser === '__babel_estree') &&
918
+ node.type === 'MethodDefinition' &&
919
+ node.value &&
920
+ node.value.type === 'FunctionExpression' &&
921
+ getFunctionParameters(node.value).length === 0 &&
922
+ !node.value.returnType &&
923
+ !isNonEmptyArray(node.value.typeParameters) &&
924
+ node.value.body
925
+ ) {
926
+ return [...(node.decorators || []), node.key, node.value.body];
927
+ }
928
+ }
929
+
930
+ /**
931
+ * @param {Comment} comment
932
+ * @returns {boolean}
933
+ */
934
+ function isTypeCastComment(comment) {
935
+ return (
936
+ isBlockComment(comment) &&
937
+ comment.value[0] === '*' &&
938
+ // TypeScript expects the type to be enclosed in curly brackets, however
939
+ // Closure Compiler accepts types in parens and even without any delimiters at all.
940
+ // That's why we just search for "@type".
941
+ /@type\b/.test(comment.value)
942
+ );
943
+ }
944
+
945
+ module.exports = {
946
+ handleOwnLineComment,
947
+ handleEndOfLineComment,
948
+ handleRemainingComment,
949
+ getCommentChildNodes,
950
+ };