Skip to content

Commit d4eca2a

Browse files
authored
Svelte Lexer Improvements (#478)
1 parent 3626d89 commit d4eca2a

File tree

4 files changed

+438
-29
lines changed

4 files changed

+438
-29
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ O | Objective-C, OCaml, Octave, OpenSCAD, Org Mode
5353
P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerShell, Prolog, PromQL, Protocol Buffer, Puppet, Python, Python 3
5454
Q | QBasic
5555
R | R, Racket, Ragel, Raku, react, ReasonML, reg, reStructuredText, Rexx, Ruby, Rust
56-
S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Swift, SYSTEMD, systemverilog
56+
S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Smalltalk, Smarty, Snobol, Solidity, SPARQL, SQL, SquidConf, Standard ML, Stylus, Svelte, Swift, SYSTEMD, systemverilog
5757
T | TableGen, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData
5858
V | VB.net, verilog, VHDL, VimL, vue
5959
W | WDTE

Diff for: lexers/s/svelte.go

+40-6
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,52 @@ var Svelte = internal.Register(DelegatingLexer(h.HTML, MustNewLazyLexer(
2222
func svelteRules() Rules {
2323
return Rules{
2424
"root": {
25-
{`(<\s*script\s*lang\s*=\s*['"](?:ts|typescript)['"]\s*>)(.+?)(<\s*/\s*script\s*>)`, ByGroups(Other, Using(t.TypeScript), Other), nil},
26-
{`\{`, Punctuation, Push("templates")},
27-
{`[^{]`, Other, nil},
25+
// Let HTML handle the comments, including comments containing script and style tags
26+
{`<!--`, Other, Push("comment")},
27+
{
28+
// Highlight script and style tags based on lang attribute
29+
// and allow attributes besides lang
30+
`(<\s*(?:script|style).*?lang\s*=\s*['"])` +
31+
`(.+?)(['"].*?>)` +
32+
`(.+?)` +
33+
`(<\s*/\s*(?:script|style)\s*>)`,
34+
UsingByGroup(internal.Get, 2, 4, Other, Other, Other, Other, Other),
35+
nil,
36+
},
37+
{
38+
// Make sure `{` is not inside script or style tags
39+
`(?<!<\s*(?:script|style)(?:(?!(?:script|style)\s*>).)*?)` +
40+
`{` +
41+
`(?!(?:(?!<\s*(?:script|style)).)*?(?:script|style)\s*>)`,
42+
Punctuation,
43+
Push("templates"),
44+
},
45+
// on:submit|preventDefault
46+
{`(?<=\s+on:\w+(?:\|\w+)*)\|(?=\w+)`, Operator, nil},
47+
{`.+?`, Other, nil},
48+
},
49+
"comment": {
50+
{`-->`, Other, Pop(1)},
51+
{`.+?`, Other, nil},
2852
},
2953
"templates": {
3054
{`}`, Punctuation, Pop(1)},
55+
// Let TypeScript handle strings and the curly braces inside them
56+
{`(?<!(?<!\\)\\)(['"` + "`])" + `.*?(?<!(?<!\\)\\)\1`, Using(t.TypeScript), nil},
57+
// If there is another opening curly brace push to templates again
58+
{"{", Punctuation, Push("templates")},
3159
{`@(debug|html)\b`, Keyword, nil},
32-
{`(#|/)(await|each|if)\b`, Keyword, nil},
60+
{
61+
`(#await)(\s+)(\w+)(\s+)(then|catch)(\s+)(\w+)`,
62+
ByGroups(Keyword, Text, Using(t.TypeScript), Text,
63+
Keyword, Text, Using(t.TypeScript),
64+
),
65+
nil,
66+
},
67+
{`(#|/)(await|each|if|key)\b`, Keyword, nil},
3368
{`(:else)(\s+)(if)?\b`, ByGroups(Keyword, Text, Keyword), nil},
3469
{`:(catch|then)\b`, Keyword, nil},
35-
{`then\b`, Keyword, nil},
36-
{`[^}]+`, Using(t.TypeScript), nil},
70+
{`[^{}]+`, Using(t.TypeScript), nil},
3771
},
3872
}
3973
}

Diff for: lexers/testdata/svelte.actual

+55-2
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,67 @@
2020
}
2121
</style>
2222

23+
<style lang="sass">
24+
$color: red
25+
h1
26+
color: $color
27+
font-family: Arial, Helvetica, sans-serif
28+
font-size: 2em
29+
</style>
30+
2331
<h1>Hello {name}!</h1>
2432
<img {src} alt="Example image">
2533

2634
<!-- import external component -->
2735
<Nested/>
2836

2937
<ul>
30-
{#each names as { id, name }}
31-
<li>{name} ({id})</li>
38+
{#each names as { id, name }, i}
39+
<li>{name} ({id})</li>
3240
{/each}
3341
</ul>
42+
43+
<template>
44+
<form on:submit|preventDefault="{submitSearch}">
45+
<input type="search" bind:value="{name}" required />
46+
<button type="submit">Search</button>
47+
</form>
48+
49+
{#if porridge.temperature > 100}
50+
<p>too hot!</p>
51+
{:else if 80 > porridge.temperature}
52+
<p>too cold!</p>
53+
{:else}
54+
<p>just right!</p>
55+
{/if}
56+
57+
{#await promise}
58+
<!-- promise is pending -->
59+
<p>waiting for the promise to resolve...</p>
60+
{:then value}
61+
<!-- promise was fulfilled -->
62+
<p>The value is {value}</p>
63+
{:catch error}
64+
<!-- promise was rejected -->
65+
<p>Something went wrong: {error.message}</p>
66+
{/await}
67+
68+
{#await promise then value}
69+
<p>The value is {value}</p>
70+
{/await}
71+
72+
{#await promise catch error}
73+
<p>The error is {error}</p>
74+
{/await}
75+
76+
{#key value}
77+
<div transition:fade>{value}</div>
78+
{/key}
79+
80+
<div class="blog-post">
81+
<h1>{post.title}</h1>
82+
{@html post.content}
83+
</div>
84+
85+
{@debug user}
86+
</template>

0 commit comments

Comments
 (0)