Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created February 9, 2021 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mizchi/8d51d239bccec98408cffde5ef5b855d to your computer and use it in GitHub Desktop.
Save mizchi/8d51d239bccec98408cffde5ef5b855d to your computer and use it in GitHub Desktop.
import { ExtendedTemplateNode } from "../../types";
import * as compiler from "svelte/compiler";
// import ts from "typescript";
import prettier from "prettier/standalone";
// @ts-ignore
import * as sveltePlugin from "prettier-plugin-svelte";
import * as astring from "astring";
// @ts-ignore
const print = sveltePlugin.printers['svelte-ast'].print;
import {FastPath} from 'prettier';
const parse = sveltePlugin.parsers.svelte.parse;
// const parse = (text :string) => ({ ...compiler.parse(text), __isRoot: true });
// sveltePlugin[""]
// function renderSvelteTemplate(parsed: ParsedSvelteTemplate) {}
const code1 = `<div>a</div>
<div>{x}</div>
<Foo />
<Events {y} a={x} b="xxx" isX onClick={() => console.log('xxx')} on:message={handler} />
{#if true}
a
{:else if 5 > x}
x
{:else}
<div>y</div>
{/if}
<ul>
{#each cats as { id, name }, i}
<li><a target="_blank" href="https://www.youtube.com/watch?v={id}">
{i + 1}: {name}
</a></li>
{/each}
</ul>
`;
const code_events = `
<Events {y} a={x} b="xxx" isX onClick={() => console.log('xxx')} on:message={handler} on:foo|once={once} />
<Events2 on:message={handler} on:foo|once={once} on:bar|x|y={xy} />
`;
const code_await = `
{#await promise}
<p>...waiting</p>
{/await}
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{/await}
{#await promise}
<p>...waiting</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
`;
const code2 = `<div>a</div>
<div>{x}</div>
<Foo />
<Events {y} a={x} b="xxx" isX onClick={() => console.log('xxx')} on:message={handler} />
{#if true}
a
{:else if 5 > x}
x
{:else}
<div>y</div>
{/if}
<ul>
{#each cats as { id, name }, i (thing.id)}
<li>
<a target=_blank href=https://www.youtube.com/watch?v={id}">
{i + 1}: {name}
</a>
</li>
{/each}
</ul>
`;
const code3 =
'<a target=_blank href="{protocol}//www.youtube.com/watch?v={id}">xx</a>';
const code_bind = `
<label>
<input type=number bind:value={a} min=0 max=10>
<input type=range bind:value={a} min=0 max=10>
</label>`;
const code_each = `
{#each cats as cat}
<li>
{cat}
</li>
{/each}
{#each cats as cat, i}
<li>
{cat}
</li>
{/each}
{#each cats as { id, name }, i (thing.id)}
<li>
{i + 1}: {name}
</li>
{/each}
`;
it("test", () => {
const parsed = compiler.parse(code_await);
// console.log(parsed.html);
const out = renderSvelteNode(parsed.html as ExtendedTemplateNode);
console.log(out);
console.log(
prettier.format(out, {
parser: "svelte",
tabWidth: 2,
filepath: "/xxx.svelte",
plugins: [sveltePlugin],
})
);
});
function renderSvelteNode(node: ExtendedTemplateNode): string {
switch (node.type) {
case "Fragment": {
return node.children
.map((t) => {
return renderSvelteNode(t);
})
.join("");
}
case "IfBlock": {
return `{${node.elseif ? ":else if" : "#if"} ${astring.generate(
node.expression
)}}
${node.children.map(renderSvelteNode)}
${node.else?.children[0].type !== "IfBlock" ? "{:else}" : ""}
${node.else ? renderSvelteNode(node.else) : ""}
${!node.elseif ? "{/if}" : ""}
`;
}
case "ElseBlock": {
return `${node.children.map(renderSvelteNode).join("")}`;
}
case "EachBlock": {
console.log("each", node);
const expr = renderSvelteNode(node.expression);
const context = renderSvelteNode(node.context);
const key = node.key ? ` (${renderSvelteNode(node.key)})` : "";
const index = node.index ? `, ${node.index}` : "";
return `{#each ${expr} as ${context}${index}${key}}
${node.children.map(renderSvelteNode)}
{/each}`;
}
case "InlineComponent":
case "Element": {
const attrs =
node.attributes.length === 0
? ""
: " " + node.attributes.map(renderSvelteNode).join(" ");
if (node.children.length === 0) {
return `<${node.name}${attrs} />`;
}
return `<${node.name}${attrs}>${node.children
.map(renderSvelteNode)
.join("")}</${node.name}>`;
}
case "MustacheTag": {
return `{${renderSvelteNode(node.expression)}}`;
}
case "Identifier": {
return node.name;
}
case "Text": {
return node.data;
}
case "Attribute": {
if (node.value.length > 0) {
if (node.value[0].type === "AttributeShorthand") {
return `{${node.name}}`;
}
if (
node.value.every((t) => t.type === "Text" || t.type === "MustacheTag")
) {
return `${node.name}="${node.value.map(renderSvelteNode).join("")}"`;
}
return `${node.name}=${node.value.map(renderSvelteNode).join("")}`;
} else {
// isChecked
return `${node.name}`;
}
}
case "EventHandler": {
const modifiers =
node.modifiers.length > 0 ? `|${node.modifiers.join("|")}` : "";
// const modifiers = node.modifiers
return `on:${node.name}${modifiers}={${renderSvelteNode(
node.expression
)}}`;
}
case "Binding": {
return `bind:${node.name}={${renderSvelteNode(node.expression)}}`;
}
case "AttributeShorthand": {
return `{${node.name}}`;
}
case "AwaitBlock": {
// console.log("await", node);
return `{#await ${renderSvelteNode(node.expression)}}
${node.pending ? renderSvelteNode(node.pending) : ""}
{:then ${renderSvelteNode(node.value)}}
${renderSvelteNode(node.then)}
{:catch ${renderSvelteNode(node.error)}}
${renderSvelteNode(node.catch)}
{/await}
`;
}
case "PendingBlock": {
return `${node.children.map(renderSvelteNode).join("")}`;
}
case "CatchBlock": {
return `${node.children.map(renderSvelteNode).join("")}`;
}
case "ThenBlock": {
return `${node.children.map(renderSvelteNode).join("")}`;
}
default: {
try {
return astring.generate(node);
} catch (err) {
return `unknown:${node.type}`;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment