@@ -401,6 +401,9 @@ namespace ts {
401
401
case CharacterCodes . greaterThan :
402
402
// Starts of conflict marker trivia
403
403
return true ;
404
+ case CharacterCodes . hash :
405
+ // Only if its the beginning can we have #! trivia
406
+ return pos === 0 ;
404
407
default :
405
408
return ch > CharacterCodes . maxAsciiCharacter ;
406
409
}
@@ -461,6 +464,13 @@ namespace ts {
461
464
}
462
465
break ;
463
466
467
+ case CharacterCodes . hash :
468
+ if ( isShebangTrivia ( text , pos ) ) {
469
+ pos = scanShebangTrivia ( text , pos ) ;
470
+ continue ;
471
+ }
472
+ break ;
473
+
464
474
default :
465
475
if ( ch > CharacterCodes . maxAsciiCharacter && ( isWhiteSpace ( ch ) || isLineBreak ( ch ) ) ) {
466
476
pos ++ ;
@@ -528,6 +538,20 @@ namespace ts {
528
538
return pos ;
529
539
}
530
540
541
+ const shebangTriviaRegex = / ^ # ! .* / ;
542
+
543
+ function isShebangTrivia ( text : string , pos : number ) {
544
+ // Shebangs check must only be done at the start of the file
545
+ Debug . assert ( pos === 0 ) ;
546
+ return shebangTriviaRegex . test ( text ) ;
547
+ }
548
+
549
+ function scanShebangTrivia ( text : string , pos : number ) {
550
+ let shebang = shebangTriviaRegex . exec ( text ) [ 0 ] ;
551
+ pos = pos + shebang . length ;
552
+ return pos ;
553
+ }
554
+
531
555
// Extract comments from the given source text starting at the given position. If trailing is
532
556
// false, whitespace is skipped until the first line break and comments between that location
533
557
// and the next token are returned.If trailing is true, comments occurring between the given
@@ -617,6 +641,13 @@ namespace ts {
617
641
export function getTrailingCommentRanges ( text : string , pos : number ) : CommentRange [ ] {
618
642
return getCommentRanges ( text , pos , /*trailing*/ true ) ;
619
643
}
644
+
645
+ /** Optionally, get the shebang */
646
+ export function getShebang ( text : string ) : string {
647
+ return shebangTriviaRegex . test ( text )
648
+ ? shebangTriviaRegex . exec ( text ) [ 0 ]
649
+ : undefined ;
650
+ }
620
651
621
652
export function isIdentifierStart ( ch : number , languageVersion : ScriptTarget ) : boolean {
622
653
return ch >= CharacterCodes . A && ch <= CharacterCodes . Z || ch >= CharacterCodes . a && ch <= CharacterCodes . z ||
@@ -1087,6 +1118,18 @@ namespace ts {
1087
1118
return token = SyntaxKind . EndOfFileToken ;
1088
1119
}
1089
1120
let ch = text . charCodeAt ( pos ) ;
1121
+
1122
+ // Special handling for shebang
1123
+ if ( ch === CharacterCodes . hash && pos === 0 && isShebangTrivia ( text , pos ) ) {
1124
+ pos = scanShebangTrivia ( text , pos ) ;
1125
+ if ( skipTrivia ) {
1126
+ continue ;
1127
+ }
1128
+ else {
1129
+ return token = SyntaxKind . ShebangTrivia ;
1130
+ }
1131
+ }
1132
+
1090
1133
switch ( ch ) {
1091
1134
case CharacterCodes . lineFeed :
1092
1135
case CharacterCodes . carriageReturn :
0 commit comments