Skip to content

Commit dd66514

Browse files
committed
feat: add experimental support for Svelte 5
1 parent 9060efd commit dd66514

File tree

11 files changed

+78
-12
lines changed

11 files changed

+78
-12
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# prettier-plugin-svelte changelog
22

3+
## 3.1.0
4+
5+
- (feat) add experimental support for Svelte 5
6+
- (feat) support `#snippet` and `@render`
7+
38
## 3.0.3
49

510
- (fix) handle static `tag` attributes on `<svelte:element>`

package-lock.json

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "prettier-plugin-svelte",
3-
"version": "3.0.3",
3+
"version": "3.1.0",
44
"description": "Svelte plugin for prettier",
55
"main": "plugin.js",
66
"files": [
@@ -51,6 +51,6 @@
5151
},
5252
"peerDependencies": {
5353
"prettier": "^3.0.0",
54-
"svelte": "^3.2.0 || ^4.0.0-next.0"
54+
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
5555
}
5656
}

src/embed.ts

+24
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@ export function embed(path: FastPath, _options: Options) {
9191
printSvelteBlockJS('expression');
9292
printSvelteBlockJS('key');
9393
break;
94+
case 'SnippetBlock':
95+
// We merge the two parts into one expression, which future-proofs this for template TS support
96+
if (node === parent.expression) {
97+
parent.expression.end =
98+
options.originalText.indexOf(
99+
')',
100+
parent.context?.end ?? parent.expression.end,
101+
) + 1;
102+
parent.context = null;
103+
printSvelteBlockJS('expression');
104+
}
105+
break;
94106
case 'Element':
95107
printJS(parent, options.svelteStrictMode ?? false, false, false, 'tag');
96108
break;
@@ -106,6 +118,18 @@ export function embed(path: FastPath, _options: Options) {
106118
case 'ConstTag':
107119
printJS(parent, false, false, true, 'expression');
108120
break;
121+
case 'RenderTag':
122+
// We merge the two parts into one expression, which future-proofs this for template TS support
123+
if (node === parent.expression) {
124+
parent.expression.end =
125+
options.originalText.indexOf(
126+
')',
127+
parent.argument?.end ?? parent.expression.end,
128+
) + 1;
129+
parent.argument = null;
130+
printJS(parent, false, false, false, 'expression');
131+
}
132+
break;
109133
case 'EventHandler':
110134
case 'Binding':
111135
case 'Class':

src/print/index.ts

+11
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,12 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
607607
case 'PendingBlock':
608608
case 'CatchBlock':
609609
return printSvelteBlockChildren(path, print, options);
610+
// Svelte 5 only
611+
case 'SnippetBlock': {
612+
const snippet = ['{#snippet ', printJS(path, print, 'expression')];
613+
snippet.push('}', printSvelteBlockChildren(path, print, options), '{/snippet}');
614+
return snippet;
615+
}
610616
case 'EventHandler':
611617
return [
612618
'on:',
@@ -718,6 +724,11 @@ export function print(path: FastPath, options: ParserOptions, print: PrintFn): D
718724
return ['animate:', node.name, node.expression ? ['=', ...printJsExpression()] : ''];
719725
case 'RawMustacheTag':
720726
return ['{@html ', printJS(path, print, 'expression'), '}'];
727+
// Svelte 5 only
728+
case 'RenderTag': {
729+
const render = ['{@render ', printJS(path, print, 'expression'), '}'];
730+
return render;
731+
}
721732
case 'Spread':
722733
return ['{...', printJS(path, print, 'expression'), '}'];
723734
case 'ConstTag':

src/print/node-helpers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export function isSvelteBlock(
6060
| ThenBlockNode {
6161
return [
6262
'IfBlock',
63+
'SnippetBlock',
6364
'AwaitBlock',
6465
'CatchBlock',
6566
'EachBlock',

src/print/nodes.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,19 @@ export interface CommentInfo {
291291
emptyLineAfter: boolean;
292292
}
293293

294+
export interface SnippetBlock extends BaseNode {
295+
type: 'SnippetBlock';
296+
expression: IdentifierNode;
297+
context: null | any;
298+
children: Node[];
299+
}
300+
301+
export interface RenderTag extends BaseNode {
302+
type: 'RenderTag';
303+
expression: IdentifierNode;
304+
argument: null | any;
305+
}
306+
294307
export type Node =
295308
| FragmentNode
296309
| ElementNode
@@ -335,7 +348,9 @@ export type Node =
335348
| DocumentNode
336349
| OptionsNode
337350
| SlotTemplateNode
338-
| ConstTagNode;
351+
| ConstTagNode
352+
| RenderTag
353+
| SnippetBlock;
339354

340355
/**
341356
* The Svelte AST root node

test/formatting/samples/move-options-to-top/input.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p>hi</p>
44

5-
<svelte:options tag="my-custom-element" />
5+
<svelte:options immutable={true} />
66

77
<p>some stuff</p>
88

test/formatting/samples/move-options-to-top/output.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<svelte:options tag="my-custom-element" />
1+
<svelte:options immutable={true} />
22

33
<script></script>
44

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{#snippet foo()}
2+
<p>foo</p>
3+
{/snippet}
4+
5+
{#snippet bar({ a, b })}
6+
<p>bar</p>
7+
{/snippet}
8+
9+
{@render foo()}
10+
{@render bar(x)}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<svelte:options tag="my-custom-element" />
1+
<svelte:options immutable={true} />

0 commit comments

Comments
 (0)