@@ -8,25 +8,42 @@ function base64Decode(input: string): string {
88}
99
1010function refineSvelteAst ( preprocessedText : string , ast : AST ) {
11- if ( ! ast . instance ) {
12- return ast ;
13- }
14-
15- const scriptTag = preprocessedText . slice ( ast . instance . start , ast . instance . end ) ;
16- const matchResult = scriptTag . match ( / ✂ p r e t t i e r : c o n t e n t ✂ = " ( [ ^ " ] * ) " / ) ;
17-
18- if ( matchResult === null ) {
11+ const svelteAst = ast as AST & {
12+ module ?: unknown ;
13+ instance ?: unknown ;
14+ } ;
15+ const scriptInfos = [
16+ { key : 'module' as const , node : svelteAst . module } ,
17+ { key : 'instance' as const , node : svelteAst . instance } ,
18+ ]
19+ . filter (
20+ (
21+ info ,
22+ ) : info is {
23+ key : 'module' | 'instance' ;
24+ node : { start : number ; end : number ; content ?: { body ?: unknown [ ] } } ;
25+ } =>
26+ isTypeof (
27+ info . node ,
28+ z . object ( {
29+ start : z . number ( ) ,
30+ end : z . number ( ) ,
31+ } ) ,
32+ ) ,
33+ )
34+ . map ( ( { key, node } ) => ( {
35+ key,
36+ node,
37+ originalStart : node . start ,
38+ originalEnd : node . end ,
39+ } ) )
40+ . sort ( ( a , b ) => a . originalStart - b . originalStart ) ;
41+
42+ if ( scriptInfos . length === 0 ) {
1943 return ast ;
2044 }
2145
22- const [ temporaryAttributeWithLeadingSpace , encodedContent ] = matchResult ;
23- const plainContent = base64Decode ( encodedContent ) ;
24-
25- const restoreTextOffset =
26- plainContent . length - ( temporaryAttributeWithLeadingSpace . length + '{}' . length ) ;
27- const restoreLineOffset = plainContent . split ( EOL ) . length - 1 ;
28-
29- function recursion ( node : unknown ) : void {
46+ function shiftNode ( node : unknown , thresholdEnd : number , textOffset : number , lineOffset : number ) : void {
3047 if ( ! isTypeof ( node , z . object ( { type : z . string ( ) } ) ) ) {
3148 return ;
3249 }
@@ -38,12 +55,12 @@ function refineSvelteAst(preprocessedText: string, ast: AST) {
3855
3956 if ( Array . isArray ( value ) ) {
4057 value . forEach ( ( childNode : unknown ) => {
41- recursion ( childNode ) ;
58+ shiftNode ( childNode , thresholdEnd , textOffset , lineOffset ) ;
4259 } ) ;
4360 return ;
4461 }
4562
46- recursion ( value ) ;
63+ shiftNode ( value , thresholdEnd , textOffset , lineOffset ) ;
4764 } ) ;
4865
4966 if (
@@ -58,8 +75,8 @@ function refineSvelteAst(preprocessedText: string, ast: AST) {
5875 return ;
5976 }
6077
61- if ( ast . instance . end <= node . start ) {
62- node . start += restoreTextOffset ;
78+ if ( thresholdEnd <= node . start ) {
79+ node . start += textOffset ;
6380
6481 if (
6582 isTypeof (
@@ -75,12 +92,12 @@ function refineSvelteAst(preprocessedText: string, ast: AST) {
7592 ) {
7693 node . loc . start = {
7794 ...node . loc . start ,
78- line : node . loc . start . line + restoreLineOffset ,
95+ line : node . loc . start . line + lineOffset ,
7996 } ;
8097 }
8198 }
82- if ( ast . instance . end <= node . end ) {
83- node . end += restoreTextOffset ;
99+ if ( thresholdEnd <= node . end ) {
100+ node . end += textOffset ;
84101
85102 if (
86103 isTypeof (
@@ -96,36 +113,79 @@ function refineSvelteAst(preprocessedText: string, ast: AST) {
96113 ) {
97114 node . loc . end = {
98115 ...node . loc . end ,
99- line : node . loc . end . line + restoreLineOffset ,
116+ line : node . loc . end . line + lineOffset ,
100117 } ;
101118 }
102119 }
103120 }
104121
105- recursion ( ast . html ) ;
106- recursion ( ast . fragment ) ;
122+ let cumulativeTextOffset = 0 ;
123+ let cumulativeLineOffset = 0 ;
107124
108- ast . instance = {
109- type : 'RefinedScript' ,
110- start : ast . instance . start ,
111- end : ast . instance . end + restoreTextOffset ,
112- loc : {
113- start : {
114- line : preprocessedText . slice ( 0 , ast . instance . start ) . split ( EOL ) . length ,
115- } ,
116- } ,
117- content : {
118- type : 'RefinedScriptSource' ,
119- start : ast . instance . end + restoreTextOffset - ( '</script>' . length + plainContent . length ) ,
120- end : ast . instance . end + restoreTextOffset - '</script>' . length ,
125+ scriptInfos . forEach ( ( { key, node, originalStart, originalEnd } , scriptIndex ) => {
126+ const scriptTag = preprocessedText . slice ( originalStart , originalEnd ) ;
127+ const matchResult = scriptTag . match ( / ✂ p r e t t i e r : c o n t e n t ✂ = " ( [ ^ " ] * ) " / ) ;
128+
129+ if ( matchResult === null ) {
130+ return ;
131+ }
132+
133+ const [ temporaryAttributeWithLeadingSpace , encodedContent ] = matchResult ;
134+ const plainContent = base64Decode ( encodedContent ) ;
135+
136+ const restoreTextOffset =
137+ plainContent . length - ( temporaryAttributeWithLeadingSpace . length + '{}' . length ) ;
138+ const restoreLineOffset = plainContent . split ( EOL ) . length - 1 ;
139+ const currentStart = originalStart + cumulativeTextOffset ;
140+ const currentEnd = originalEnd + cumulativeTextOffset ;
141+ const currentStartLine =
142+ preprocessedText . slice ( 0 , originalStart ) . split ( EOL ) . length + cumulativeLineOffset ;
143+ const firstBodyNode = node . content ?. body ?. at ( 0 ) ;
144+ const contentStartLine = isTypeof (
145+ firstBodyNode ,
146+ z . object ( {
147+ loc : z . object ( {
148+ start : z . object ( {
149+ line : z . number ( ) ,
150+ } ) ,
151+ } ) ,
152+ } ) ,
153+ )
154+ ? firstBodyNode . loc . start . line + cumulativeLineOffset
155+ : currentStartLine + 1 ;
156+
157+ shiftNode ( svelteAst . html , currentEnd , restoreTextOffset , restoreLineOffset ) ;
158+ shiftNode ( svelteAst . fragment , currentEnd , restoreTextOffset , restoreLineOffset ) ;
159+
160+ scriptInfos . slice ( scriptIndex + 1 ) . forEach ( ( { key : nextKey } ) => {
161+ shiftNode ( svelteAst [ nextKey ] , currentEnd , restoreTextOffset , restoreLineOffset ) ;
162+ } ) ;
163+
164+ svelteAst [ key ] = {
165+ type : 'RefinedScript' ,
166+ start : currentStart ,
167+ end : currentEnd + restoreTextOffset ,
121168 loc : {
122169 start : {
123- line : ast . instance . content . body [ 0 ] . loc . start . line ,
170+ line : currentStartLine ,
124171 } ,
125172 } ,
126- value : plainContent ,
127- } ,
128- } ;
173+ content : {
174+ type : 'RefinedScriptSource' ,
175+ start : currentEnd + restoreTextOffset - ( '</script>' . length + plainContent . length ) ,
176+ end : currentEnd + restoreTextOffset - '</script>' . length ,
177+ loc : {
178+ start : {
179+ line : contentStartLine ,
180+ } ,
181+ } ,
182+ value : plainContent ,
183+ } ,
184+ } ;
185+
186+ cumulativeTextOffset += restoreTextOffset ;
187+ cumulativeLineOffset += restoreLineOffset ;
188+ } ) ;
129189
130190 return ast ;
131191}
0 commit comments