@@ -549,11 +549,10 @@ export function parseScriptElement(
549
549
parserOptions : ParserOptions ,
550
550
) : ESLintExtendedProgram {
551
551
const text = node . children [ 0 ]
552
- const offset =
552
+ const { code , offset } =
553
553
text != null && text . type === "VText"
554
- ? text . range [ 0 ]
555
- : node . startTag . range [ 1 ]
556
- const code = text != null && text . type === "VText" ? text . value : ""
554
+ ? { code : text . value , offset : text . range [ 0 ] }
555
+ : { code : "" , offset : node . startTag . range [ 1 ] }
557
556
const locationCalculator =
558
557
globalLocationCalculator . getSubCalculatorAfter ( offset )
559
558
const result = parseScriptFragment ( code , locationCalculator , parserOptions )
@@ -564,14 +563,12 @@ export function parseScriptElement(
564
563
const startTag = node . startTag
565
564
const endTag = node . endTag
566
565
567
- if ( startTag != null ) {
568
- result . ast . tokens . unshift ( {
569
- type : "Punctuator" ,
570
- range : startTag . range ,
571
- loc : startTag . loc ,
572
- value : "<script>" ,
573
- } )
574
- }
566
+ result . ast . tokens . unshift ( {
567
+ type : "Punctuator" ,
568
+ range : startTag . range ,
569
+ loc : startTag . loc ,
570
+ value : "<script>" ,
571
+ } )
575
572
if ( endTag != null ) {
576
573
result . ast . tokens . push ( {
577
574
type : "Punctuator" ,
@@ -585,6 +582,125 @@ export function parseScriptElement(
585
582
return result
586
583
}
587
584
585
+ /**
586
+ * Parse the source code of the given `<script>` elements.
587
+ * @param nodes The `<script>` elements to parse.
588
+ * @param code The source code of SFC.
589
+ * @param globalLocationCalculatorWithoutGapOffsets The location calculator for fixLocations.
590
+ * @param parserOptions The parser options.
591
+ * @returns The result of parsing.
592
+ */
593
+ export function parseScriptElements (
594
+ nodes : VElement [ ] ,
595
+ code : string ,
596
+ globalLocationCalculatorWithoutGapOffsets : LocationCalculator ,
597
+ parserOptions : ParserOptions ,
598
+ ) : ESLintExtendedProgram {
599
+ let scriptCode = ""
600
+ let startOffset = 0
601
+ const tagTokens : Token [ ] = [ ]
602
+
603
+ let firstScriptTextNode : Token | null = null
604
+ for ( const node of nodes ) {
605
+ const scriptTextNode = node . children [ 0 ]
606
+ if ( scriptTextNode . type === "VText" ) {
607
+ const scriptText = code . slice ( ...scriptTextNode . range )
608
+ if ( ! scriptCode ) {
609
+ firstScriptTextNode = scriptTextNode
610
+ scriptCode += scriptText
611
+ } else {
612
+ const spaces = code
613
+ . slice ( startOffset , scriptTextNode . range [ 0 ] )
614
+ // eslint-disable-next-line require-unicode-regexp -- ignore u flag
615
+ . replace ( / [ ^ \n \r \u2028 \u2029 ] / g, " " )
616
+ scriptCode += spaces + scriptText
617
+ }
618
+ startOffset = scriptTextNode . range [ 1 ]
619
+
620
+ const startTag = node . startTag
621
+ const endTag = node . endTag
622
+ tagTokens . push ( {
623
+ type : "Punctuator" ,
624
+ range : startTag . range ,
625
+ loc : startTag . loc ,
626
+ value : "<script>" ,
627
+ } )
628
+ if ( endTag != null ) {
629
+ tagTokens . push ( {
630
+ type : "Punctuator" ,
631
+ range : endTag . range ,
632
+ loc : endTag . loc ,
633
+ value : "</script>" ,
634
+ } )
635
+ }
636
+ }
637
+ }
638
+ const offset =
639
+ firstScriptTextNode != null
640
+ ? firstScriptTextNode . range [ 0 ]
641
+ : nodes [ 0 ] . startTag . range [ 1 ]
642
+
643
+ const locationCalculator =
644
+ globalLocationCalculatorWithoutGapOffsets . getSubCalculatorAfter ( offset )
645
+ const result = parseScriptFragment (
646
+ scriptCode ,
647
+ locationCalculator ,
648
+ parserOptions ,
649
+ )
650
+
651
+ if ( result . ast . comments != null ) {
652
+ for ( const comment of result . ast . comments ) {
653
+ for ( const tagToken of tagTokens ) {
654
+ checkIntersect ( tagToken , comment )
655
+ }
656
+ }
657
+ }
658
+ if ( result . ast . tokens != null ) {
659
+ const newTokens : Token [ ] = [ ]
660
+ let tagToken = tagTokens . shift ( )
661
+ for ( const token of result . ast . tokens ) {
662
+ while ( tagToken && tagToken . range [ 0 ] < token . range [ 0 ] ) {
663
+ newTokens . push ( tagToken )
664
+ tagToken = tagTokens . shift ( )
665
+ }
666
+ checkIntersect ( tagToken , token )
667
+ newTokens . push ( token )
668
+ }
669
+ if ( tagToken ) {
670
+ newTokens . push ( tagToken , ...tagTokens )
671
+ }
672
+ result . ast . tokens = newTokens
673
+ }
674
+
675
+ return result
676
+
677
+ /**
678
+ * Check if the tokens intersect.
679
+ */
680
+ function checkIntersect ( tagToken : Token | undefined , token : Token ) {
681
+ if ( tagToken ) {
682
+ if (
683
+ token . range [ 0 ] < tagToken . range [ 0 ] &&
684
+ tagToken . range [ 0 ] < token . range [ 1 ]
685
+ ) {
686
+ throw new ParseError (
687
+ token . type === "Template"
688
+ ? "Unterminated template literal"
689
+ : token . type === "Block"
690
+ ? "Unterminated comment"
691
+ : token . type === "String"
692
+ ? "Unterminated string constant"
693
+ : `Unterminated '${ token . type } '` ,
694
+ undefined ,
695
+ tagToken . range [ 0 ] ,
696
+ tagToken . loc . start . line ,
697
+ tagToken . loc . start . column ,
698
+ )
699
+ }
700
+ }
701
+ }
702
+ }
703
+
588
704
/**
589
705
* Parse the source code of inline scripts.
590
706
* @param code The source code of inline scripts.
0 commit comments