11import fs from "fs"
22import path from "path"
3- import type { Comment , Locations , Position , Token } from "../ast"
3+ import type {
4+ Comment ,
5+ Locations ,
6+ Position ,
7+ SvelteScriptElement ,
8+ SvelteStyleElement ,
9+ Token ,
10+ } from "../ast"
411import type ESTree from "estree"
512import { ScriptLetContext } from "./script-let"
613import { LetDirectiveCollections } from "./let-directive-collection"
714import { getParserName } from "../parser/resolve-parser"
15+ import type { AttributeToken } from "../parser/html"
16+ import { parseAttributes } from "../parser/html"
817
918export class ScriptsSourceCode {
1019 private raw : string
@@ -87,6 +96,8 @@ export class Context {
8796
8897 private state : { isTypeScript ?: boolean } = { }
8998
99+ private readonly blocks : Block [ ] = [ ]
100+
90101 public constructor ( code : string , parserOptions : any ) {
91102 this . code = code
92103 this . parserOptions = parserOptions
@@ -96,21 +107,25 @@ export class Context {
96107
97108 let templateCode = ""
98109 let scriptCode = ""
99- let scriptAttrs : Record < string , string | undefined > = { }
110+ const scriptAttrs : Record < string , string | undefined > = { }
100111
101112 let start = 0
102113 for ( const block of extractBlocks ( code ) ) {
114+ this . blocks . push ( block )
103115 templateCode +=
104- code . slice ( start , block . codeRange [ 0 ] ) +
105- spaces . slice ( block . codeRange [ 0 ] , block . codeRange [ 1 ] )
116+ code . slice ( start , block . contentRange [ 0 ] ) +
117+ spaces . slice ( block . contentRange [ 0 ] , block . contentRange [ 1 ] )
106118 if ( block . tag === "script" ) {
107119 scriptCode +=
108- spaces . slice ( start , block . codeRange [ 0 ] ) + block . code
109- scriptAttrs = Object . assign ( scriptAttrs , block . attrs )
120+ spaces . slice ( start , block . contentRange [ 0 ] ) +
121+ code . slice ( ...block . contentRange )
122+ for ( const attr of block . attrs ) {
123+ scriptAttrs [ attr . key . name ] = attr . value ?. value
124+ }
110125 } else {
111- scriptCode += spaces . slice ( start , block . codeRange [ 1 ] )
126+ scriptCode += spaces . slice ( start , block . contentRange [ 1 ] )
112127 }
113- start = block . codeRange [ 1 ]
128+ start = block . contentRange [ 1 ]
114129 }
115130 templateCode += code . slice ( start )
116131 scriptCode += spaces . slice ( start )
@@ -223,49 +238,63 @@ export class Context {
223238 public stripScriptCode ( start : number , end : number ) : void {
224239 this . sourceCode . scripts . stripCode ( start , end )
225240 }
241+
242+ public findBlock (
243+ element : SvelteScriptElement | SvelteStyleElement ,
244+ ) : Block | undefined {
245+ const tag = element . type === "SvelteScriptElement" ? "script" : "style"
246+ return this . blocks . find (
247+ ( block ) =>
248+ block . tag === tag &&
249+ element . range [ 0 ] <= block . contentRange [ 0 ] &&
250+ block . contentRange [ 1 ] <= element . range [ 1 ] ,
251+ )
252+ }
226253}
227254
228- /** Extract <script> blocks */
229- function * extractBlocks ( code : string ) : IterableIterator < {
230- code : string
231- codeRange : [ number , number ]
232- attrs : Record < string , string | undefined >
255+ type Block = {
233256 tag : "script" | "style"
234- } > {
235- const startTagRe = / < ( s c r i p t | s t y l e ) ( \s [ \s \S ] * ?) ? > / giu
236- const endScriptTagRe = / < \/ s c r i p t (?: \s [ \s \S ] * ?) ? > / giu
237- const endStyleTagRe = / < \/ s t y l e (?: \s [ \s \S ] * ?) ? > / giu
238- let startTagRes
239- while ( ( startTagRes = startTagRe . exec ( code ) ) ) {
240- const [ startTag , tag , attributes = "" ] = startTagRes
241- const startTagStart = startTagRes . index
242- const startTagEnd = startTagStart + startTag . length
257+ attrs : AttributeToken [ ]
258+ contentRange : [ number , number ]
259+ }
260+
261+ /** Extract <script> blocks */
262+ function * extractBlocks ( code : string ) : IterableIterator < Block > {
263+ const startTagOpenRe = / < ( s c r i p t | s t y l e ) ( [ \s > ] ) / giu
264+ const endScriptTagRe = / < \/ s c r i p t > / giu
265+ const endStyleTagRe = / < \/ s t y l e > / giu
266+ let startTagOpenMatch
267+ while ( ( startTagOpenMatch = startTagOpenRe . exec ( code ) ) ) {
268+ const [ , tag , nextChar ] = startTagOpenMatch
269+ let startTagEnd = startTagOpenRe . lastIndex
270+
271+ let attrs : AttributeToken [ ] = [ ]
272+ if ( ! nextChar . trim ( ) ) {
273+ const attrsData = parseAttributes ( code , startTagOpenRe . lastIndex )
274+ attrs = attrsData . attributes
275+ startTagEnd = attrsData . index
276+ if ( code [ startTagEnd ] === "/" ) {
277+ startTagEnd ++
278+ }
279+ if ( code [ startTagEnd ] === ">" ) {
280+ startTagEnd ++
281+ } else {
282+ continue
283+ }
284+ }
243285 const endTagRe =
244286 tag . toLowerCase ( ) === "script" ? endScriptTagRe : endStyleTagRe
245- endTagRe . lastIndex = startTagRe . lastIndex
246- const endTagRes = endTagRe . exec ( code )
247- if ( endTagRes ) {
248- const endTagStart = endTagRes . index
249- const codeRange : [ number , number ] = [ startTagEnd , endTagStart ]
250-
251- const attrRe =
252- / (?< key > [ ^ \s = ] + ) (?: = (?: " (?< val1 > [ ^ " ] * ) " | ' (?< val2 > [ ^ " ] * ) ' | (?< val3 > [ ^ \s = ] + ) ) ) ? / gu
253- const attrs : Record < string , string | undefined > = { }
254- let attrRes
255- while ( ( attrRes = attrRe . exec ( attributes ) ) ) {
256- attrs [ attrRes . groups ! . key ] =
257- ( attrRes . groups ! . val1 ||
258- attrRes . groups ! . val2 ||
259- attrRes . groups ! . val3 ) ??
260- null
261- }
287+ endTagRe . lastIndex = startTagEnd
288+ const endTagMatch = endTagRe . exec ( code )
289+ if ( endTagMatch ) {
290+ const endTagStart = endTagMatch . index
291+ const contentRange : [ number , number ] = [ startTagEnd , endTagStart ]
262292 yield {
263- code : code . slice ( ...codeRange ) ,
264- codeRange,
293+ contentRange,
265294 attrs,
266295 tag : tag as "script" | "style" ,
267296 }
268- startTagRe . lastIndex = endTagRe . lastIndex
297+ startTagOpenRe . lastIndex = endTagRe . lastIndex
269298 }
270299 }
271300}
0 commit comments