Skip to content

Commit 278ef12

Browse files
committed
feat: change it to use modern AST, if svelte v5 is installed
1 parent 5f2b111 commit 278ef12

File tree

12 files changed

+849
-247
lines changed

12 files changed

+849
-247
lines changed

src/context/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
} from "../ast";
1313
import type ESTree from "estree";
1414
import type * as SvAST from "../parser/svelte-ast-types";
15+
import type * as Compiler from "svelte/compiler";
1516
import { ScriptLetContext } from "./script-let";
1617
import { LetDirectiveCollections } from "./let-directive-collection";
1718
import type { AttributeToken } from "../parser/html";
@@ -164,6 +165,19 @@ export class Context {
164165
| SvAST.SlotTemplate
165166
| SvAST.Slot
166167
| SvAST.Title
168+
| Compiler.RegularElement
169+
| Compiler.Component
170+
| Compiler.SvelteComponent
171+
| Compiler.SvelteElement
172+
| Compiler.SvelteWindow
173+
| Compiler.SvelteBody
174+
| Compiler.SvelteHead
175+
| Compiler.SvelteDocument
176+
| Compiler.SvelteFragment
177+
| Compiler.SvelteSelf
178+
| Compiler.SvelteOptionsRaw
179+
| Compiler.SlotElement
180+
| Compiler.TitleElement
167181
>();
168182

169183
public readonly snippets: SvelteSnippetBlock[] = [];

src/parser/compat.ts

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/** Compatibility for Svelte v4 <-> v5 */
2+
import type ESTree from "estree";
3+
import type * as SvAST from "./svelte-ast-types";
4+
import type * as Compiler from "svelte/compiler";
5+
6+
export type Child =
7+
| Compiler.Text
8+
| Compiler.Tag
9+
| Compiler.ElementLike
10+
| Compiler.Block
11+
| Compiler.Comment;
12+
type HasChildren = { children?: SvAST.TemplateNode[] };
13+
// Root
14+
export function getFragmentFromRoot(
15+
svelteAst: SvAST.Ast | SvAST.AstLegacy,
16+
): SvAST.Fragment | Compiler.Fragment | undefined {
17+
return (
18+
(svelteAst as SvAST.Ast).fragment ?? (svelteAst as SvAST.AstLegacy).html
19+
);
20+
}
21+
export function getInstanceFromRoot(
22+
svelteAst: SvAST.Ast | SvAST.AstLegacy,
23+
): SvAST.Script | Compiler.Script | undefined {
24+
return (svelteAst as SvAST.AstLegacy).instance;
25+
}
26+
export function getModuleFromRoot(
27+
svelteAst: SvAST.Ast | SvAST.AstLegacy,
28+
): SvAST.Script | Compiler.Script | undefined {
29+
return (svelteAst as SvAST.AstLegacy).module;
30+
}
31+
export function getOptionsFromRoot(
32+
svelteAst: SvAST.Ast | SvAST.AstLegacy,
33+
): Compiler.SvelteOptionsRaw | null {
34+
return (svelteAst as any).options?.__raw__ ?? null;
35+
}
36+
37+
export function getChildren(
38+
fragment: Required<HasChildren> | { nodes: (Child | SvAST.TemplateNode)[] },
39+
): (SvAST.TemplateNode | Child)[];
40+
export function getChildren(
41+
fragment: HasChildren | { nodes: (Child | SvAST.TemplateNode)[] },
42+
): (SvAST.TemplateNode | Child)[] | undefined;
43+
export function getChildren(
44+
fragment: HasChildren | { nodes: (Child | SvAST.TemplateNode)[] },
45+
): (SvAST.TemplateNode | Child)[] | undefined {
46+
return (
47+
(fragment as { nodes: (Child | SvAST.TemplateNode)[] }).nodes ??
48+
(fragment as HasChildren).children
49+
);
50+
}
51+
export function trimChildren(
52+
children: (SvAST.TemplateNode | Child)[],
53+
): (SvAST.TemplateNode | Child)[] {
54+
if (
55+
!startsWithWhitespace(children[0]) &&
56+
!endsWithWhitespace(children[children.length - 1])
57+
) {
58+
return children;
59+
}
60+
61+
const nodes = [...children];
62+
while (isWhitespace(nodes[0])) {
63+
nodes.shift();
64+
}
65+
const first = nodes[0];
66+
if (startsWithWhitespace(first)) {
67+
nodes[0] = { ...first, data: first.data.trimStart() };
68+
}
69+
while (isWhitespace(nodes[nodes.length - 1])) {
70+
nodes.pop();
71+
}
72+
const last = nodes[nodes.length - 1];
73+
if (endsWithWhitespace(last)) {
74+
nodes[nodes.length - 1] = { ...last, data: last.data.trimEnd() };
75+
}
76+
return nodes;
77+
78+
function startsWithWhitespace(
79+
child: SvAST.TemplateNode | Child | undefined,
80+
): child is SvAST.Text | Compiler.Text {
81+
if (!child) {
82+
return false;
83+
}
84+
return child.type === "Text" && child.data.trimStart() !== child.data;
85+
}
86+
87+
function endsWithWhitespace(
88+
child: SvAST.TemplateNode | Child | undefined,
89+
): child is SvAST.Text | Compiler.Text {
90+
if (!child) {
91+
return false;
92+
}
93+
return child.type === "Text" && child.data.trimEnd() !== child.data;
94+
}
95+
96+
function isWhitespace(child: SvAST.TemplateNode | Child | undefined) {
97+
if (!child) {
98+
return false;
99+
}
100+
return child.type === "Text" && child.data.trim() === "";
101+
}
102+
}
103+
export function getFragment(
104+
element:
105+
| {
106+
fragment: Compiler.Fragment;
107+
}
108+
| Required<HasChildren>,
109+
): Compiler.Fragment | Required<HasChildren>;
110+
export function getFragment(
111+
element:
112+
| {
113+
fragment: Compiler.Fragment;
114+
}
115+
| HasChildren,
116+
): Compiler.Fragment | HasChildren;
117+
export function getFragment(
118+
element:
119+
| {
120+
fragment: Compiler.Fragment;
121+
}
122+
| HasChildren,
123+
): Compiler.Fragment | HasChildren {
124+
if (
125+
(
126+
element as {
127+
fragment: Compiler.Fragment;
128+
}
129+
).fragment
130+
) {
131+
return (
132+
element as {
133+
fragment: Compiler.Fragment;
134+
}
135+
).fragment;
136+
}
137+
return element as HasChildren;
138+
}
139+
export function getModifiers(
140+
node: SvAST.Directive | SvAST.StyleDirective | Compiler.Directive,
141+
): string[] {
142+
return (node as { modifiers?: string[] }).modifiers ?? [];
143+
}
144+
// IfBlock
145+
export function getTestFromIfBlock(
146+
block: SvAST.IfBlock | Compiler.IfBlock,
147+
): ESTree.Expression {
148+
return (
149+
(block as SvAST.IfBlock).expression ?? (block as Compiler.IfBlock).test
150+
);
151+
}
152+
export function getConsequentFromIfBlock(
153+
block: SvAST.IfBlock | Compiler.IfBlock,
154+
): Compiler.Fragment | SvAST.IfBlock {
155+
return (block as Compiler.IfBlock).consequent ?? (block as SvAST.IfBlock);
156+
}
157+
export function getAlternateFromIfBlock(
158+
block: SvAST.IfBlock | Compiler.IfBlock,
159+
): Compiler.Fragment | SvAST.ElseBlock | null {
160+
if ((block as Compiler.IfBlock).alternate) {
161+
return (block as Compiler.IfBlock).alternate;
162+
}
163+
return (block as SvAST.IfBlock).else ?? null;
164+
}
165+
// EachBlock
166+
export function getBodyFromEachBlock(
167+
block: SvAST.EachBlock | Compiler.EachBlock,
168+
): Compiler.Fragment | SvAST.EachBlock {
169+
if ((block as Compiler.EachBlock).body) {
170+
return (block as Compiler.EachBlock).body;
171+
}
172+
return block as SvAST.EachBlock;
173+
}
174+
export function getFallbackFromEachBlock(
175+
block: SvAST.EachBlock | Compiler.EachBlock,
176+
): Compiler.Fragment | SvAST.ElseBlock | null {
177+
if ((block as Compiler.EachBlock).fallback) {
178+
return (block as Compiler.EachBlock).fallback!;
179+
}
180+
return (block as SvAST.EachBlock).else ?? null;
181+
}
182+
// SnippetBlock
183+
export function getBodyFromSnippetBlock(
184+
block: SvAST.SnippetBlock | Compiler.SnippetBlock,
185+
): Compiler.Fragment | SvAST.SnippetBlock {
186+
if ((block as Compiler.SnippetBlock).body) {
187+
return (block as Compiler.SnippetBlock).body;
188+
}
189+
return block as SvAST.SnippetBlock;
190+
}
191+
// AwaitBlock
192+
export function getPendingFromAwaitBlock(
193+
block: SvAST.AwaitBlock | Compiler.AwaitBlock,
194+
): Compiler.Fragment | SvAST.PendingBlock | null {
195+
const pending = block.pending;
196+
if (!pending) {
197+
return null;
198+
}
199+
if (pending.type === "Fragment") {
200+
return pending;
201+
}
202+
return pending.skip ? null : pending;
203+
}
204+
export function getThenFromAwaitBlock(
205+
block: SvAST.AwaitBlock | Compiler.AwaitBlock,
206+
): Compiler.Fragment | SvAST.ThenBlock | null {
207+
const then = block.then;
208+
if (!then) {
209+
return null;
210+
}
211+
if (then.type === "Fragment") {
212+
return then;
213+
}
214+
return then.skip ? null : then;
215+
}
216+
217+
export function getCatchFromAwaitBlock(
218+
block: SvAST.AwaitBlock | Compiler.AwaitBlock,
219+
): Compiler.Fragment | SvAST.CatchBlock | null {
220+
const catchFragment = block.catch;
221+
if (!catchFragment) {
222+
return null;
223+
}
224+
if (catchFragment.type === "Fragment") {
225+
return catchFragment;
226+
}
227+
return catchFragment.skip ? null : catchFragment;
228+
}

0 commit comments

Comments
 (0)