Skip to content

Commit 855af3b

Browse files
authored
feat: support {@Attach ...} (#714)
1 parent 10fc353 commit 855af3b

33 files changed

+49078
-2
lines changed

.changeset/public-sheep-speak.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
feat: support `{@attach ...}`

docs/AST.md

+13
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ interface SvelteStartTag extends Node {
169169
| SvelteAttribute
170170
| SvelteShorthandAttribute
171171
| SvelteSpreadAttribute
172+
| SvelteAttachTag
172173
| SvelteDirective
173174
| SvelteStyleDirective
174175
| SvelteSpecialDirective
@@ -451,6 +452,18 @@ interface SvelteRenderTag extends Node {
451452
}
452453
```
453454

455+
### SvelteAttachTag
456+
457+
This is `{@attach}` tag node.
458+
459+
```ts
460+
export interface SvelteAttachTag extends BaseNode {
461+
type: "SvelteAttachTag";
462+
expression: ESTree.Expression;
463+
parent: SvelteStartTag;
464+
}
465+
```
466+
454467
### SvelteIfBlock
455468

456469
This is the `{#if}` tag node. `{:else if}` is also included in this node.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
"prettier-plugin-svelte": "^3.3.3",
106106
"rimraf": "^6.0.1",
107107
"semver": "^7.7.1",
108-
"svelte": "^5.25.3",
108+
"svelte": "^5.30.1",
109109
"svelte2tsx": "^0.7.35",
110110
"tsx": "^4.19.3",
111111
"typescript": "~5.8.2",

src/ast/html.ts

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type SvelteHTMLNode =
3131
| SvelteAttribute
3232
| SvelteShorthandAttribute
3333
| SvelteSpreadAttribute
34+
| SvelteAttachTag
3435
| SvelteDirective
3536
| SvelteStyleDirective
3637
| SvelteSpecialDirective
@@ -142,6 +143,7 @@ export interface SvelteStartTag extends BaseNode {
142143
| SvelteAttribute
143144
| SvelteShorthandAttribute
144145
| SvelteSpreadAttribute
146+
| SvelteAttachTag
145147
| SvelteDirective
146148
| SvelteStyleDirective
147149
| SvelteSpecialDirective
@@ -541,6 +543,12 @@ export interface SvelteSpreadAttribute extends BaseNode {
541543
parent: SvelteStartTag;
542544
}
543545

546+
export interface SvelteAttachTag extends BaseNode {
547+
type: "SvelteAttachTag";
548+
expression: ESTree.Expression;
549+
parent: SvelteStartTag;
550+
}
551+
544552
/** Node of directive. e.g. `<input bind:value />` */
545553
export type SvelteDirective =
546554
| SvelteActionDirective

src/parser/converts/attr.ts

+32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
SvelteAnimationDirective,
44
SvelteAttribute,
55
SvelteShorthandAttribute,
6+
SvelteAttachTag,
67
SvelteBindingDirective,
78
SvelteClassDirective,
89
SvelteDirective,
@@ -48,6 +49,7 @@ export function* convertAttributes(
4849
| SvAST.AttributeOrDirective
4950
| Compiler.Attribute
5051
| Compiler.SpreadAttribute
52+
| Compiler.AttachTag
5153
| Compiler.Directive
5254
)[],
5355
parent: SvelteStartTag,
@@ -56,6 +58,7 @@ export function* convertAttributes(
5658
| SvelteAttribute
5759
| SvelteShorthandAttribute
5860
| SvelteSpreadAttribute
61+
| SvelteAttachTag
5962
| SvelteDirective
6063
| SvelteStyleDirective
6164
> {
@@ -68,6 +71,10 @@ export function* convertAttributes(
6871
yield convertSpreadAttribute(attr, parent, ctx);
6972
continue;
7073
}
74+
if (attr.type === "AttachTag") {
75+
yield convertAttachTag(attr, parent, ctx);
76+
continue;
77+
}
7178
if (attr.type === "BindDirective" || attr.type === "Binding") {
7279
yield convertBindingDirective(attr, parent, ctx);
7380
continue;
@@ -344,6 +351,31 @@ function convertSpreadAttribute(
344351
return attribute;
345352
}
346353

354+
function convertAttachTag(
355+
node: Compiler.AttachTag,
356+
parent: SvelteAttachTag["parent"],
357+
ctx: Context,
358+
): SvelteAttachTag {
359+
const attachTag: SvelteAttachTag = {
360+
type: "SvelteAttachTag",
361+
expression: node.expression,
362+
parent,
363+
...ctx.getConvertLocation(node),
364+
};
365+
366+
ctx.scriptLet.addExpression(node.expression, attachTag, null, (es) => {
367+
attachTag.expression = es;
368+
});
369+
370+
const atAttachStart = ctx.code.indexOf("@attach", attachTag.range[0]);
371+
ctx.addToken("MustacheKeyword", {
372+
start: atAttachStart,
373+
end: atAttachStart + 7,
374+
});
375+
376+
return attachTag;
377+
}
378+
347379
/** Convert for Binding Directive */
348380
function convertBindingDirective(
349381
node: SvAST.DirectiveForExpression | Compiler.BindDirective,

src/parser/converts/element.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,19 @@ export function* convertChildren(
223223
function extractLetDirectives(fragment: {
224224
attributes:
225225
| SvAST.AttributeOrDirective[]
226-
| (Compiler.Attribute | Compiler.SpreadAttribute | Compiler.Directive)[];
226+
| (
227+
| Compiler.Attribute
228+
| Compiler.SpreadAttribute
229+
| Compiler.AttachTag
230+
| Compiler.Directive
231+
)[];
227232
}): {
228233
letDirectives: (SvAST.LetDirective | Compiler.LetDirective)[];
229234
attributes: Exclude<
230235
| SvAST.AttributeOrDirective
231236
| Compiler.Attribute
232237
| Compiler.SpreadAttribute
238+
| Compiler.AttachTag
233239
| Compiler.Directive,
234240
SvAST.LetDirective | Compiler.LetDirective
235241
>[];
@@ -239,6 +245,7 @@ function extractLetDirectives(fragment: {
239245
| SvAST.AttributeOrDirective
240246
| Compiler.Attribute
241247
| Compiler.SpreadAttribute
248+
| Compiler.AttachTag
242249
| Compiler.Directive,
243250
SvAST.LetDirective | Compiler.LetDirective
244251
>[] = [];

src/parser/svelte-ast-types-for-v5.ts

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export type SnippetBlock = AST.SnippetBlock;
3737
export type Comment = AST.Comment;
3838
export type Attribute = AST.Attribute;
3939
export type SpreadAttribute = AST.SpreadAttribute;
40+
export type AttachTag = AST.AttachTag;
4041
export type AnimateDirective = AST.AnimateDirective;
4142
export type BindDirective = AST.BindDirective;
4243
export type ClassDirective = AST.ClassDirective;

src/visitor-keys.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const svelteKeys: SvelteKeysType = {
4242
SvelteAttribute: ["key", "value"],
4343
SvelteShorthandAttribute: ["key", "value"],
4444
SvelteSpreadAttribute: ["argument"],
45+
SvelteAttachTag: ["expression"],
4546
SvelteDirective: ["key", "expression"],
4647
SvelteStyleDirective: ["key", "value"],
4748
SvelteSpecialDirective: ["key", "expression"],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
import type { Attachment } from 'svelte/attachments';
3+
4+
5+
const myAttachment: Attachment = (element) => {
6+
console.log(element.nodeName); // 'DIV'
7+
8+
return () => {
9+
console.log('cleaning up');
10+
};
11+
};
12+
</script>
13+
14+
<div {@attach myAttachment}>...</div>

0 commit comments

Comments
 (0)