1
1
/** @import { TSESTree } from '@typescript-eslint/types' */
2
- /** @import { Visitors, Context } from '../types.js' */
2
+ /** @import { Visitors } from '../types.js' */
3
+ import { Context } from '../context.js' ;
3
4
4
5
/** @type {Record<TSESTree.Expression['type'] | 'Super' | 'RestElement', number> } */
5
6
export const EXPRESSIONS_PRECEDENCE = {
@@ -103,9 +104,40 @@ export default (options = {}) => {
103
104
104
105
let comment_index = 0 ;
105
106
107
+ /**
108
+ * Set `comment_index` to be the first comment after `start`.
109
+ * Most of the time this is already correct, but if nodes
110
+ * have been moved around we may need to search for it
111
+ * @param {TSESTree.Node } node
112
+ */
113
+ function reset_comment_index ( node ) {
114
+ if ( ! node . loc ) {
115
+ comment_index = comments . length ;
116
+ return ;
117
+ }
118
+
119
+ let previous = comments [ comment_index - 1 ] ;
120
+ let comment = comments [ comment_index ] ;
121
+
122
+ if (
123
+ comment &&
124
+ comment . loc &&
125
+ ! before ( comment . loc . start , node . loc . start ) &&
126
+ ( ! previous || ( previous . loc && before ( previous . loc . start , node . loc . start ) ) )
127
+ ) {
128
+ return ;
129
+ }
130
+
131
+ // TODO use a binary search here, account for synthetic nodes (without `loc`)
132
+ comment_index = comments . findIndex (
133
+ ( comment ) => comment . loc && node . loc && ! before ( comment . loc . start , node . loc . start )
134
+ ) ;
135
+ if ( comment_index === - 1 ) comment_index = comments . length ;
136
+ }
137
+
106
138
/**
107
139
* @param {Context } context
108
- * @param {{ line: number, column: number } } prev
140
+ * @param {{ line: number, column: number } | null } prev
109
141
* @param {{ line: number, column: number } | null } next
110
142
* @returns {boolean } true if final comment is a line comment
111
143
*/
@@ -115,6 +147,7 @@ export default (options = {}) => {
115
147
116
148
if (
117
149
comment &&
150
+ prev &&
118
151
comment . loc . start . line === prev . line &&
119
152
( next === null || before ( comment . loc . end , next ) )
120
153
) {
@@ -146,7 +179,7 @@ export default (options = {}) => {
146
179
while ( comment_index < comments . length ) {
147
180
const comment = comments [ comment_index ] ;
148
181
149
- if ( comment && before ( comment . loc . start , to ) ) {
182
+ if ( comment && comment . loc && to && before ( comment . loc . start , to ) ) {
150
183
if ( first && from !== null && comment . loc . start . line > from . line ) {
151
184
context . margin ( ) ;
152
185
context . newline ( ) ;
@@ -192,8 +225,8 @@ export default (options = {}) => {
192
225
child_context . write ( separator ) ;
193
226
}
194
227
195
- const next = i === nodes . length - 1 ? until : nodes [ i + 1 ] ?. loc . start || null ;
196
- if ( child && flush_trailing_comments ( child_context , child . loc . end , next ) ) {
228
+ const next = i === nodes . length - 1 ? until : nodes [ i + 1 ] ?. loc ? .start || null ;
229
+ if ( child && flush_trailing_comments ( child_context , child . loc ? .end || null , next ) ) {
197
230
multiline = true ;
198
231
}
199
232
@@ -237,7 +270,7 @@ export default (options = {}) => {
237
270
prev = child ;
238
271
}
239
272
240
- flush_comments_until ( context , nodes [ nodes . length - 1 ] ?. loc . end ?? null , until , false ) ;
273
+ flush_comments_until ( context , nodes [ nodes . length - 1 ] ?. loc ? .end ?? null , until , false ) ;
241
274
242
275
if ( multiline ) {
243
276
context . dedent ( ) ;
@@ -254,6 +287,8 @@ export default (options = {}) => {
254
287
* @param {TSESTree.Node & { body: TSESTree.Node[] } } node
255
288
*/
256
289
function body ( context , node ) {
290
+ reset_comment_index ( node ) ;
291
+
257
292
/** @type {string | null } */
258
293
let prev_type = null ;
259
294
let prev_multiline = false ;
@@ -282,7 +317,7 @@ export default (options = {}) => {
282
317
context . newline ( ) ;
283
318
flush_comments_until (
284
319
context ,
285
- node . body [ node . body . length - 1 ] ?. loc . end ?? null ,
320
+ node . body [ node . body . length - 1 ] ?. loc ? .end ?? null ,
286
321
node . loc . end ,
287
322
false
288
323
) ;
@@ -296,7 +331,12 @@ export default (options = {}) => {
296
331
*/
297
332
'ArrayExpression|ArrayPattern' : ( node , context ) => {
298
333
context . write ( '[' ) ;
299
- sequence ( context , /** @type {TSESTree.Node[] } */ ( node . elements ) , node . loc . end , false ) ;
334
+ sequence (
335
+ context ,
336
+ /** @type {TSESTree.Node[] } */ ( node . elements ) ,
337
+ node . loc ?. end ?? null ,
338
+ false
339
+ ) ;
300
340
context . write ( ']' ) ;
301
341
} ,
302
342
@@ -344,18 +384,13 @@ export default (options = {}) => {
344
384
context . write ( '{' ) ;
345
385
}
346
386
347
- const comment = comments [ comment_index ] ;
348
-
349
- let has_content = node . body . length > 0 ;
350
- let has_comment =
351
- comment &&
352
- before ( node . loc . start , comment . loc . start ) &&
353
- before ( comment . loc . end , node . loc . end ) ;
387
+ const child_context = context . new ( ) ;
388
+ body ( child_context , node ) ;
354
389
355
- if ( has_content || has_comment ) {
390
+ if ( ! child_context . empty ( ) ) {
356
391
context . indent ( ) ;
357
392
context . newline ( ) ;
358
- body ( context , node ) ;
393
+ context . append ( child_context ) ;
359
394
context . dedent ( ) ;
360
395
context . newline ( ) ;
361
396
}
@@ -421,7 +456,9 @@ export default (options = {}) => {
421
456
// we make the whole sequence multiline
422
457
if (
423
458
is_last &&
459
+ arg . loc &&
424
460
comments [ comment_index ] &&
461
+ comments [ comment_index ] . loc &&
425
462
comments [ comment_index ] . loc . start . line < arg . loc . start . line
426
463
) {
427
464
child_context . multiline = true ;
@@ -431,9 +468,11 @@ export default (options = {}) => {
431
468
432
469
if ( ! is_last ) context . write ( ',' ) ;
433
470
434
- const next = is_last ? node . loc . end : ( node . arguments [ i + 1 ] ?. loc . start ?? null ) ;
471
+ const next = is_last
472
+ ? ( node . loc ?. end ?? null )
473
+ : ( node . arguments [ i + 1 ] ?. loc ?. start ?? null ) ;
435
474
436
- if ( flush_trailing_comments ( context , arg . loc . end , next ) ) {
475
+ if ( flush_trailing_comments ( context , arg . loc ? .end ?? null , next ) ) {
437
476
child_context . multiline = true ;
438
477
}
439
478
@@ -475,7 +514,7 @@ export default (options = {}) => {
475
514
476
515
if ( node . implements ) {
477
516
context . write ( 'implements ' ) ;
478
- sequence ( context , node . implements , node . body . loc . start , false ) ;
517
+ sequence ( context , node . implements , node . body . loc ? .start ?? null , false ) ;
479
518
}
480
519
481
520
context . visit ( node . body ) ;
@@ -516,7 +555,7 @@ export default (options = {}) => {
516
555
}
517
556
518
557
context . write ( '(' ) ;
519
- sequence ( context , node . params , ( node . returnType ?? node . body ) . loc . start , false ) ;
558
+ sequence ( context , node . params , ( node . returnType ?? node . body ) . loc ? .start ?? null , false ) ;
520
559
context . write ( ')' ) ;
521
560
522
561
if ( node . returnType ) context . visit ( node . returnType ) ;
@@ -562,7 +601,7 @@ export default (options = {}) => {
562
601
if ( node . async ) context . write ( 'async ' ) ;
563
602
564
603
context . write ( '(' ) ;
565
- sequence ( context , node . params , node . body . loc . start , false ) ;
604
+ sequence ( context , node . params , node . body . loc ? .start ?? null , false ) ;
566
605
context . write ( ') => ' ) ;
567
606
568
607
if (
@@ -735,7 +774,7 @@ export default (options = {}) => {
735
774
}
736
775
737
776
context . write ( '{' ) ;
738
- sequence ( context , node . specifiers , node . source ?. loc . start ?? node . loc . end , true ) ;
777
+ sequence ( context , node . specifiers , node . source ?. loc ? .start ?? node . loc ? .end ?? null , true ) ;
739
778
context . write ( '}' ) ;
740
779
741
780
if ( node . source ) {
@@ -861,7 +900,7 @@ export default (options = {}) => {
861
900
862
901
if ( named_specifiers . length > 0 ) {
863
902
context . write ( '{' ) ;
864
- sequence ( context , named_specifiers , node . source . loc . start , true ) ;
903
+ sequence ( context , named_specifiers , node . source . loc ? .start ?? null , true ) ;
865
904
context . write ( '}' ) ;
866
905
}
867
906
@@ -987,7 +1026,7 @@ export default (options = {}) => {
987
1026
sequence (
988
1027
context ,
989
1028
node . value . params ,
990
- ( node . value . returnType ?? node . value . body ) ?. loc . start ?? node . loc . end ,
1029
+ ( node . value . returnType ?? node . value . body ) ?. loc ? .start ?? node . loc ? .end ?? null ,
991
1030
false
992
1031
) ;
993
1032
context . write ( ')' ) ;
@@ -1003,13 +1042,13 @@ export default (options = {}) => {
1003
1042
1004
1043
ObjectExpression ( node , context ) {
1005
1044
context . write ( '{' ) ;
1006
- sequence ( context , node . properties , node . loc . end , true ) ;
1045
+ sequence ( context , node . properties , node . loc ? .end ?? null , true ) ;
1007
1046
context . write ( '}' ) ;
1008
1047
} ,
1009
1048
1010
1049
ObjectPattern ( node , context ) {
1011
1050
context . write ( '{' ) ;
1012
- sequence ( context , node . properties , node . loc . end , true ) ;
1051
+ sequence ( context , node . properties , node . loc ? .end ?? null , true ) ;
1013
1052
context . write ( '}' ) ;
1014
1053
1015
1054
if ( node . typeAnnotation ) context . visit ( node . typeAnnotation ) ;
@@ -1056,7 +1095,7 @@ export default (options = {}) => {
1056
1095
sequence (
1057
1096
context ,
1058
1097
node . value . params ,
1059
- ( node . value . returnType ?? node . value . body ) . loc . start ,
1098
+ ( node . value . returnType ?? node . value . body ) . loc ? .start ?? null ,
1060
1099
false
1061
1100
) ;
1062
1101
context . write ( ')' ) ;
@@ -1116,6 +1155,8 @@ export default (options = {}) => {
1116
1155
if ( node . argument ) {
1117
1156
const contains_comment =
1118
1157
comments [ comment_index ] &&
1158
+ comments [ comment_index ] . loc &&
1159
+ node . argument . loc &&
1119
1160
before ( comments [ comment_index ] . loc . start , node . argument . loc . start ) ;
1120
1161
1121
1162
context . write ( contains_comment ? 'return (' : 'return ' ) ;
@@ -1128,7 +1169,7 @@ export default (options = {}) => {
1128
1169
1129
1170
SequenceExpression ( node , context ) {
1130
1171
context . write ( '(' ) ;
1131
- sequence ( context , node . expressions , node . loc . end , false ) ;
1172
+ sequence ( context , node . expressions , node . loc ? .end ?? null , false ) ;
1132
1173
context . write ( ')' ) ;
1133
1174
} ,
1134
1175
@@ -1363,7 +1404,7 @@ export default (options = {}) => {
1363
1404
1364
1405
TSTypeLiteral ( node , context ) {
1365
1406
context . write ( '{ ' ) ;
1366
- sequence ( context , node . members , node . loc . end , false , ';' ) ;
1407
+ sequence ( context , node . members , node . loc ? .end ?? null , false , ';' ) ;
1367
1408
context . write ( ' }' ) ;
1368
1409
} ,
1369
1410
@@ -1433,7 +1474,12 @@ export default (options = {}) => {
1433
1474
context . write ( '(' ) ;
1434
1475
1435
1476
// @ts -expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
1436
- sequence ( context , node . parameters , node . typeAnnotation . typeAnnotation . loc . start , false ) ;
1477
+ sequence (
1478
+ context ,
1479
+ node . parameters ,
1480
+ node . typeAnnotation . typeAnnotation . loc ?. start ?? null ,
1481
+ false
1482
+ ) ;
1437
1483
1438
1484
context . write ( ') => ' ) ;
1439
1485
@@ -1445,7 +1491,7 @@ export default (options = {}) => {
1445
1491
context . write ( '[' ) ;
1446
1492
1447
1493
// @ts -expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
1448
- sequence ( context , node . parameters , node . typeAnnotation ?. loc . start , false ) ;
1494
+ sequence ( context , node . parameters , node . typeAnnotation ?. loc ? .start ?? null , false ) ;
1449
1495
context . write ( ']' ) ;
1450
1496
1451
1497
// @ts -expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
@@ -1458,7 +1504,7 @@ export default (options = {}) => {
1458
1504
context . write ( '(' ) ;
1459
1505
1460
1506
// @ts -expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
1461
- sequence ( context , node . parameters , node . typeAnnotation . loc . start , false ) ;
1507
+ sequence ( context , node . parameters , node . typeAnnotation . loc ? .start ?? null , false ) ;
1462
1508
context . write ( ')' ) ;
1463
1509
1464
1510
// @ts -expect-error `acorn-typescript` and `@typescript-eslint/types` have slightly different type definitions
@@ -1467,7 +1513,7 @@ export default (options = {}) => {
1467
1513
1468
1514
TSTupleType ( node , context ) {
1469
1515
context . write ( '[' ) ;
1470
- sequence ( context , node . elementTypes , node . loc . end , false ) ;
1516
+ sequence ( context , node . elementTypes , node . loc ? .end ?? null , false ) ;
1471
1517
context . write ( ']' ) ;
1472
1518
} ,
1473
1519
@@ -1478,11 +1524,11 @@ export default (options = {}) => {
1478
1524
} ,
1479
1525
1480
1526
TSUnionType ( node , context ) {
1481
- sequence ( context , node . types , node . loc . end , false , ' |' ) ;
1527
+ sequence ( context , node . types , node . loc ? .end ?? null , false , ' |' ) ;
1482
1528
} ,
1483
1529
1484
1530
TSIntersectionType ( node , context ) {
1485
- sequence ( context , node . types , node . loc . end , false , ' &' ) ;
1531
+ sequence ( context , node . types , node . loc ? .end ?? null , false , ' &' ) ;
1486
1532
} ,
1487
1533
1488
1534
TSLiteralType ( node , context ) {
@@ -1540,7 +1586,7 @@ export default (options = {}) => {
1540
1586
context . write ( ' {' ) ;
1541
1587
context . indent ( ) ;
1542
1588
context . newline ( ) ;
1543
- sequence ( context , node . members , node . loc . end , false ) ;
1589
+ sequence ( context , node . members , node . loc ? .end ?? null , false ) ;
1544
1590
context . dedent ( ) ;
1545
1591
context . newline ( ) ;
1546
1592
context . write ( '}' ) ;
@@ -1572,7 +1618,7 @@ export default (options = {}) => {
1572
1618
} ,
1573
1619
1574
1620
TSInterfaceBody ( node , context ) {
1575
- sequence ( context , node . body , node . loc . end , true , ';' ) ;
1621
+ sequence ( context , node . body , node . loc ? .end ?? null , true , ';' ) ;
1576
1622
} ,
1577
1623
1578
1624
TSInterfaceDeclaration ( node , context ) {
@@ -1581,7 +1627,7 @@ export default (options = {}) => {
1581
1627
if ( node . typeParameters ) context . visit ( node . typeParameters ) ;
1582
1628
if ( node . extends ) {
1583
1629
context . write ( ' extends ' ) ;
1584
- sequence ( context , node . extends , node . body . loc . start , false ) ;
1630
+ sequence ( context , node . extends , node . body . loc ? .start ?? null , false ) ;
1585
1631
}
1586
1632
context . write ( ' {' ) ;
1587
1633
context . visit ( node . body ) ;
0 commit comments