Skip to content

Commit 4643a40

Browse files
authored
Fix crash with <style lang=sass> (#26)
1 parent c3d487b commit 4643a40

File tree

11 files changed

+1519
-45
lines changed

11 files changed

+1519
-45
lines changed

src/context/index.ts

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import type { ScopeManager } from "eslint-scope"
55
import { TemplateScopeManager } from "./template-scope-manager"
66

77
type ContextSourceCode = {
8-
svelte: string
9-
script: {
8+
template: string
9+
scripts: {
1010
code: string
1111
attrs: Record<string, string | undefined>
1212
}
@@ -33,25 +33,30 @@ export class Context {
3333
this.parserOptions = parserOptions
3434
this.locs = new LinesAndColumns(code)
3535

36-
let svelteCode = ""
36+
let templateCode = ""
3737
let scriptCode = ""
3838
let scriptAttrs: Record<string, string | undefined> = {}
3939

4040
let start = 0
41-
for (const script of extractScriptBlocks(code)) {
42-
const before = code.slice(start, script.codeRange[0])
43-
svelteCode += before + script.code.replace(/[^\n\r ]/g, " ")
44-
scriptCode += before.replace(/[^\n\r ]/g, " ") + script.code
45-
scriptAttrs = Object.assign(scriptAttrs, script.attrs)
46-
start = script.codeRange[1]
41+
for (const block of extractBlocks(code)) {
42+
const before = code.slice(start, block.codeRange[0])
43+
const blankCode = block.code.replace(/[^\n\r ]/g, " ")
44+
templateCode += before + blankCode
45+
if (block.tag === "script") {
46+
scriptCode += before.replace(/[^\n\r ]/g, " ") + block.code
47+
scriptAttrs = Object.assign(scriptAttrs, block.attrs)
48+
} else {
49+
scriptCode += before.replace(/[^\n\r ]/g, " ") + blankCode
50+
}
51+
start = block.codeRange[1]
4752
}
4853
const before = code.slice(start)
49-
svelteCode += before
54+
templateCode += before
5055
scriptCode += before.replace(/[^\n\r ]/g, " ")
5156

5257
this.sourceCode = {
53-
svelte: svelteCode,
54-
script: {
58+
template: templateCode,
59+
scripts: {
5560
code: scriptCode,
5661
attrs: scriptAttrs,
5762
},
@@ -125,36 +130,43 @@ export class Context {
125130
}
126131

127132
/** Extract <script> blocks */
128-
function* extractScriptBlocks(code: string): IterableIterator<{
133+
function* extractBlocks(code: string): IterableIterator<{
129134
code: string
130135
codeRange: [number, number]
131-
tag: string
132-
tagRange: [number, number]
133136
attrs: Record<string, string | undefined>
137+
tag: "script" | "style"
134138
}> {
135-
const scriptRe = /<script(\s[\s\S]*?)?>([\s\S]*?)<\/script>/giu
136-
let res
137-
while ((res = scriptRe.exec(code))) {
138-
const [tag, attributes = "", context] = res
139-
const tagRange: [number, number] = [res.index, scriptRe.lastIndex]
140-
const codeRange: [number, number] = [
141-
tagRange[0] + 8 + attributes.length,
142-
tagRange[1] - 9,
143-
]
144-
145-
const attrRe =
146-
// eslint-disable-next-line regexp/no-unused-capturing-group -- maybe bug
147-
/(<key>[^\s=]+)(?:=(?:"(<val>[^"]*)"|'(<val>[^"]*)'|(<val>[^\s=]+)))?/giu
148-
const attrs: Record<string, string | undefined> = {}
149-
while ((res = attrRe.exec(attributes))) {
150-
attrs[res.groups!.key] = res.groups!.val
151-
}
152-
yield {
153-
code: context,
154-
codeRange,
155-
tag,
156-
tagRange,
157-
attrs,
139+
const startTagRe = /<(script|style)(\s[\s\S]*?)?>/giu
140+
const endScriptTagRe = /<\/script(?:\s[\s\S]*?)?>/giu
141+
const endStyleTagRe = /<\/style(?:\s[\s\S]*?)?>/giu
142+
let startTagRes
143+
while ((startTagRes = startTagRe.exec(code))) {
144+
const [startTag, tag, attributes = ""] = startTagRes
145+
const startTagStart = startTagRes.index
146+
const startTagEnd = startTagStart + startTag.length
147+
const endTagRe =
148+
tag.toLowerCase() === "script" ? endScriptTagRe : endStyleTagRe
149+
endTagRe.lastIndex = startTagRe.lastIndex
150+
const endTagRes = endTagRe.exec(code)
151+
if (endTagRes) {
152+
const endTagStart = endTagRes.index
153+
const codeRange: [number, number] = [startTagEnd, endTagStart]
154+
155+
const attrRe =
156+
// eslint-disable-next-line regexp/no-unused-capturing-group -- maybe bug
157+
/(<key>[^\s=]+)(?:=(?:"(<val>[^"]*)"|'(<val>[^"]*)'|(<val>[^\s=]+)))?/giu
158+
const attrs: Record<string, string | undefined> = {}
159+
let attrRes
160+
while ((attrRes = attrRe.exec(attributes))) {
161+
attrs[attrRes.groups!.key] = attrRes.groups!.val
162+
}
163+
yield {
164+
code: code.slice(...codeRange),
165+
codeRange,
166+
attrs,
167+
tag: tag as "script" | "style",
168+
}
169+
startTagRe.lastIndex = endTagRe.lastIndex
158170
}
159171
}
160172
}

src/parser/converts/root.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,15 @@ export function convertSvelteRoot(
131131

132132
const useRanges = sort([...ctx.tokens, ...ctx.comments]).map((t) => t.range)
133133
let range = useRanges.shift()
134-
for (let index = 0; index < ctx.sourceCode.svelte.length; index++) {
134+
for (let index = 0; index < ctx.sourceCode.template.length; index++) {
135135
while (range && range[1] <= index) {
136136
range = useRanges.shift()
137137
}
138138
if (range && range[0] <= index) {
139139
index = range[1] - 1
140140
continue
141141
}
142-
const c = ctx.sourceCode.svelte[index]
142+
const c = ctx.sourceCode.template[index]
143143
if (!c.trim()) {
144144
continue
145145
}
@@ -171,7 +171,7 @@ function extractAttributes(
171171
const script = element.type === "SvelteScriptElement"
172172
const code =
173173
" ".repeat(element.range[0]) +
174-
ctx.sourceCode.svelte
174+
ctx.sourceCode.template
175175
.slice(...element.range)
176176
.replace(
177177
script

src/parser/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ export function parseForESLint(
5858

5959
const ctx = new Context(code, parserOptions)
6060

61-
const resultScript = parseScript(ctx.sourceCode.script, parserOptions)
61+
const resultScript = parseScript(ctx.sourceCode.scripts, parserOptions)
6262
ctx.readyScopeManager(resultScript.scopeManager!)
6363
const resultTemplate = parseTemplate(
64-
ctx.sourceCode.svelte,
64+
ctx.sourceCode.template,
6565
ctx,
6666
parserOptions,
6767
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<style lang="sass">
2+
$font-stack: Helvetica, sans-serif
3+
$primary-color: #333
4+
5+
body
6+
font: 100% $font-stack
7+
color: $primary-color
8+
</style>

0 commit comments

Comments
 (0)