Skip to content

Commit 1e0b874

Browse files
authored
feat: add support {#each} without as (svelte v5.4.0) (#617)
1 parent 1cede6c commit 1e0b874

17 files changed

+4071
-19
lines changed

.changeset/witty-hairs-judge.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
feat: add support `{#each}` without `as` (svelte v5.4.0)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
"prettier-plugin-svelte": "^3.3.2",
106106
"rimraf": "^6.0.1",
107107
"semver": "^7.6.3",
108-
"svelte": "^5.3.1",
108+
"svelte": "^5.9.0",
109109
"svelte2tsx": "^0.7.28",
110110
"tsx": "^4.19.2",
111111
"typescript": "~5.7.2",

src/ast/html.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ export interface SvelteElseBlockElseIf extends BaseSvelteElseBlock {
347347
export interface SvelteEachBlock extends BaseNode {
348348
type: "SvelteEachBlock";
349349
expression: ESTree.Expression;
350-
context: ESTree.Pattern;
350+
context: ESTree.Pattern | null;
351351
index: ESTree.Identifier | null;
352352
key: ESTree.Expression | null;
353353
children: Child[];

src/context/script-let.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -433,22 +433,26 @@ export class ScriptLetContext {
433433

434434
public nestEachBlock(
435435
expression: ESTree.Expression,
436-
context: ESTree.Pattern,
436+
context: ESTree.Pattern | null,
437437
indexRange: { start: number; end: number } | null,
438438
eachBlock: SvelteEachBlock,
439439
callback: (
440440
expr: ESTree.Expression,
441-
ctx: ESTree.Pattern,
441+
ctx: ESTree.Pattern | null,
442442
index: ESTree.Identifier | null,
443443
) => void,
444444
): void {
445445
const exprRange = getNodeRange(expression);
446-
const ctxRange = getNodeRange(context);
446+
const ctxRange = context && getNodeRange(context);
447447
let source = "Array.from(";
448448
const exprOffset = source.length;
449449
source += `${this.ctx.code.slice(...exprRange)}).forEach((`;
450450
const ctxOffset = source.length;
451-
source += this.ctx.code.slice(...ctxRange);
451+
if (ctxRange) {
452+
source += this.ctx.code.slice(...ctxRange);
453+
} else {
454+
source += "__$ctx__";
455+
}
452456
let idxOffset: number | null = null;
453457
if (indexRange) {
454458
source += ",";
@@ -473,7 +477,7 @@ export class ScriptLetContext {
473477
const scope = result.getScope(fn.body);
474478

475479
// Process for nodes
476-
callback(expr, ctx, idx);
480+
callback(expr, context ? ctx : null, idx);
477481

478482
// Process for scope
479483
result.registerNodeToScope(eachBlock, scope);
@@ -484,6 +488,10 @@ export class ScriptLetContext {
484488
}
485489
}
486490
}
491+
if (!context) {
492+
// remove `__$ctx__` variable
493+
removeIdentifierVariable(ctx, scope);
494+
}
487495
// remove Array reference
488496
const arrayId = (callArrayFrom.callee as ESTree.MemberExpression)
489497
.object;
@@ -512,18 +520,24 @@ export class ScriptLetContext {
512520
tokens.pop(); // )
513521
tokens.pop(); // ;
514522

515-
const map = [
523+
const map: {
524+
offset: number;
525+
range: [number, number];
526+
newNode: ESTree.Expression | ESTree.Pattern;
527+
}[] = [
516528
{
517529
offset: exprOffset,
518530
range: exprRange,
519531
newNode: expr,
520532
},
521-
{
533+
];
534+
if (ctxRange) {
535+
map.push({
522536
offset: ctxOffset,
523537
range: ctxRange,
524538
newNode: ctx,
525-
},
526-
];
539+
});
540+
}
527541
if (indexRange) {
528542
map.push({
529543
offset: idxOffset!,

src/parser/converts/block.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export function convertEachBlock(
269269
const eachBlock: SvelteEachBlock = {
270270
type: "SvelteEachBlock",
271271
expression: null as any,
272-
context: null as any,
272+
context: null,
273273
index: null,
274274
key: null,
275275
children: [],
@@ -281,7 +281,10 @@ export function convertEachBlock(
281281
let indexRange: null | { start: number; end: number } = null;
282282

283283
if (node.index) {
284-
const start = ctx.code.indexOf(node.index, getWithLoc(node.context).end);
284+
const start = ctx.code.indexOf(
285+
node.index,
286+
getWithLoc(node.context ?? node.expression).end,
287+
);
285288
indexRange = {
286289
start,
287290
end: start + node.index.length,
@@ -300,11 +303,13 @@ export function convertEachBlock(
300303
},
301304
);
302305

303-
const asStart = ctx.code.indexOf("as", getWithLoc(node.expression).end);
304-
ctx.addToken("Keyword", {
305-
start: asStart,
306-
end: asStart + 2,
307-
});
306+
if (node.context) {
307+
const asStart = ctx.code.indexOf("as", getWithLoc(node.expression).end);
308+
ctx.addToken("Keyword", {
309+
start: asStart,
310+
end: asStart + 2,
311+
});
312+
}
308313

309314
if (node.key) {
310315
ctx.scriptLet.addExpression(node.key, eachBlock, null, (key) => {
@@ -335,7 +340,7 @@ export function convertEachBlock(
335340
const elseStart = startBlockIndexForElse(
336341
fallbackFragment,
337342
body,
338-
node.key || indexRange || node.context,
343+
node.key || indexRange || node.context || node.expression,
339344
ctx,
340345
);
341346

Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{#each expression}...{/each}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{
3+
"ruleId": "no-undef",
4+
"code": "expression",
5+
"line": 1,
6+
"column": 8
7+
}
8+
]
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
{
2+
"type": "Program",
3+
"body": [
4+
{
5+
"type": "SvelteEachBlock",
6+
"expression": {
7+
"type": "Identifier",
8+
"name": "expression",
9+
"range": [
10+
7,
11+
17
12+
],
13+
"loc": {
14+
"start": {
15+
"line": 1,
16+
"column": 7
17+
},
18+
"end": {
19+
"line": 1,
20+
"column": 17
21+
}
22+
}
23+
},
24+
"context": null,
25+
"index": null,
26+
"key": null,
27+
"children": [
28+
{
29+
"type": "SvelteText",
30+
"value": "...",
31+
"range": [
32+
18,
33+
21
34+
],
35+
"loc": {
36+
"start": {
37+
"line": 1,
38+
"column": 18
39+
},
40+
"end": {
41+
"line": 1,
42+
"column": 21
43+
}
44+
}
45+
}
46+
],
47+
"else": null,
48+
"range": [
49+
0,
50+
28
51+
],
52+
"loc": {
53+
"start": {
54+
"line": 1,
55+
"column": 0
56+
},
57+
"end": {
58+
"line": 1,
59+
"column": 28
60+
}
61+
}
62+
}
63+
],
64+
"sourceType": "module",
65+
"comments": [],
66+
"tokens": [
67+
{
68+
"type": "Punctuator",
69+
"value": "{",
70+
"range": [
71+
0,
72+
1
73+
],
74+
"loc": {
75+
"start": {
76+
"line": 1,
77+
"column": 0
78+
},
79+
"end": {
80+
"line": 1,
81+
"column": 1
82+
}
83+
}
84+
},
85+
{
86+
"type": "MustacheKeyword",
87+
"value": "#each",
88+
"range": [
89+
1,
90+
6
91+
],
92+
"loc": {
93+
"start": {
94+
"line": 1,
95+
"column": 1
96+
},
97+
"end": {
98+
"line": 1,
99+
"column": 6
100+
}
101+
}
102+
},
103+
{
104+
"type": "Identifier",
105+
"value": "expression",
106+
"range": [
107+
7,
108+
17
109+
],
110+
"loc": {
111+
"start": {
112+
"line": 1,
113+
"column": 7
114+
},
115+
"end": {
116+
"line": 1,
117+
"column": 17
118+
}
119+
}
120+
},
121+
{
122+
"type": "Punctuator",
123+
"value": "}",
124+
"range": [
125+
17,
126+
18
127+
],
128+
"loc": {
129+
"start": {
130+
"line": 1,
131+
"column": 17
132+
},
133+
"end": {
134+
"line": 1,
135+
"column": 18
136+
}
137+
}
138+
},
139+
{
140+
"type": "HTMLText",
141+
"value": "...",
142+
"range": [
143+
18,
144+
21
145+
],
146+
"loc": {
147+
"start": {
148+
"line": 1,
149+
"column": 18
150+
},
151+
"end": {
152+
"line": 1,
153+
"column": 21
154+
}
155+
}
156+
},
157+
{
158+
"type": "Punctuator",
159+
"value": "{",
160+
"range": [
161+
21,
162+
22
163+
],
164+
"loc": {
165+
"start": {
166+
"line": 1,
167+
"column": 21
168+
},
169+
"end": {
170+
"line": 1,
171+
"column": 22
172+
}
173+
}
174+
},
175+
{
176+
"type": "MustacheKeyword",
177+
"value": "/each",
178+
"range": [
179+
22,
180+
27
181+
],
182+
"loc": {
183+
"start": {
184+
"line": 1,
185+
"column": 22
186+
},
187+
"end": {
188+
"line": 1,
189+
"column": 27
190+
}
191+
}
192+
},
193+
{
194+
"type": "Punctuator",
195+
"value": "}",
196+
"range": [
197+
27,
198+
28
199+
],
200+
"loc": {
201+
"start": {
202+
"line": 1,
203+
"column": 27
204+
},
205+
"end": {
206+
"line": 1,
207+
"column": 28
208+
}
209+
}
210+
}
211+
],
212+
"range": [
213+
0,
214+
29
215+
],
216+
"loc": {
217+
"start": {
218+
"line": 1,
219+
"column": 0
220+
},
221+
"end": {
222+
"line": 2,
223+
"column": 0
224+
}
225+
}
226+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy