Created
February 9, 2021 10:42
-
-
Save mizchi/8d51d239bccec98408cffde5ef5b855d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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