Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Print AwaitBlock #63

Merged
merged 3 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 130 additions & 18 deletions src/node/block/await.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,140 @@
/**
* Related to Svelte AST node {@link AwaitBlock}.
* @see {@link https://svelte.dev/docs/logic-blocks#await}
* @module
*/

import { print } from "esrap";

import { print_fragment } from "#node/fragment";
import { define_printer } from "#printer";
import type { AwaitBlock } from "#types";
import { insert } from "#util";

/**
* Print Svelte AST node {@link AwaitBlock} as string.
* @see {@link https://svelte.dev/docs/logic-blocks#await}
*
* @example standard
* ```svelte
* {#await expression}...{:then name}...{:catch name}...{/await}
* ```
*
* @example without catch
* ```svelte
* {#if expression}...{:else if expression}...{/if}
* ```
*
* @example without pending body
* ```svelte
* {#await expression then name}...{/await}
* ```
*
* @example with catch body only
* ```svelte
* https://svelte.dev/docs/logic-blocks#await
* ```
*/
export const print_await_block = define_printer((node: AwaitBlock, options) => {
const { catch: catch_, error, expression, pending, then, value } = node;
return [
`{#await ${print(expression).code}}`,
pending ? print_fragment(pending, options) : "",
[
// then block
"{:then",
value ? ` ${print(value).code}` : "",
"}",
then ? print_fragment(then, options) : "",
].join(""),
[
// catch block
"{:catch",
error ? ` ${print(error).code}` : "",
"}",
catch_ ? print_fragment(catch_, options) : "",
].join(""),

return insert(
"{#await ",
print(expression).code,
insert(
then && !pending && insert(" then", value && insert(" ", print(value).code)),
catch_ && !pending && insert(" catch", error && insert(" ", print(error).code)),
),
"}",
pending && print_fragment(pending, options),
then &&
insert(
pending && insert("{:then", value && insert(" ", print(value).code), "}"),
print_fragment(then, options),
),
catch_ &&
insert(
pending && insert("{:catch", error && insert(" ", print(error).code), "}"),
print_fragment(catch_, options),
),
"{/await}",
].join("");
);
});

if (import.meta.vitest) {
const { describe, it } = import.meta.vitest;
const [{ parse_and_extract_svelte_node }, { DEFAULT_OPTIONS }] = await Promise.all([
import("#test/mod"),
import("#options"),
]);

describe("AwaitBlock", () => {
it("correctly prints standard example", ({ expect }) => {
const code = `
{#await promise}
<p>waiting for the promise to resolve...</p>
{:then value}
<p>The value is {value}</p>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
`;
const node = parse_and_extract_svelte_node<AwaitBlock>(code, "AwaitBlock");
expect(print_await_block(node, DEFAULT_OPTIONS)).toMatchInlineSnapshot(`
"{#await promise}
<p>waiting for the promise to resolve...</p>
{:then value}
<p>The value is {value}</p>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}"
`);
});

it("correctly prints with omitted catch", ({ expect }) => {
const code = `
{#await promise}
<p>waiting for the promise to resolve...</p>
{:then value}
<p>The value is {value}</p>
{/await}
`;
const node = parse_and_extract_svelte_node<AwaitBlock>(code, "AwaitBlock");
expect(print_await_block(node, DEFAULT_OPTIONS)).toMatchInlineSnapshot(`
"{#await promise}
<p>waiting for the promise to resolve...</p>
{:then value}
<p>The value is {value}</p>
{/await}"
`);
});

it("correctly prints omitted initial block", ({ expect }) => {
const code = `
{#await promise then value}
<p>The value is {value}</p>
{/await}
`;
const node = parse_and_extract_svelte_node<AwaitBlock>(code, "AwaitBlock");
expect(print_await_block(node, DEFAULT_OPTIONS)).toMatchInlineSnapshot(`
"{#await promise then value}
<p>The value is {value}</p>
{/await}"
`);
});

it("correctly prints omitted then block", ({ expect }) => {
const code = `
{#await promise catch error}
<p>The error is {error}</p>
{/await}
`;
const node = parse_and_extract_svelte_node<AwaitBlock>(code, "AwaitBlock");
expect(print_await_block(node, DEFAULT_OPTIONS)).toMatchInlineSnapshot(`
"{#await promise catch error}
<p>The error is {error}</p>
{/await}"
`);
});
});
}
25 changes: 7 additions & 18 deletions src/node/block/if.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { print } from "esrap";
import { print_fragment } from "#node/fragment";
import { define_printer } from "#printer";
import type { Fragment, IfBlock } from "#types";
import { insert } from "#util";

const has_alternate_else_if = (node: Fragment): boolean => node.nodes.some((n) => n.type === "IfBlock");

Expand Down Expand Up @@ -45,37 +46,25 @@ export const print_if_block = define_printer((node: IfBlock, options) => {
const { alternate, consequent, elseif, test } = node;

if (elseif) {
return [
return insert(
"{:else if",
" ",
print(test).code,
"}",
print_fragment(consequent, options),
alternate
? [
//
!has_alternate_else_if(alternate) ? "{:else}" : "",
print_fragment(alternate, options),
].join("")
: "",
].join("");
alternate && insert(!has_alternate_else_if(alternate) && "{:else}", print_fragment(alternate, options)),
);
}

return [
return insert(
"{#if",
" ",
print(test).code,
"}",
print_fragment(consequent, options),
alternate
? [
//
!has_alternate_else_if(alternate) ? "{:else}" : "",
print_fragment(alternate, options),
].join("")
: "",
alternate && insert(!has_alternate_else_if(alternate) && "{:else}", print_fragment(alternate, options)),
"{/if}",
].join("");
);
});

if (import.meta.vitest) {
Expand Down
8 changes: 2 additions & 6 deletions src/node/tag/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { print } from "esrap";

import { define_printer } from "#printer";
import type { ExpressionTag } from "#types";
import { insert } from "#util";

/**
* Print Svelte AST node {@link ExpressionTag} as string.
Expand All @@ -18,12 +19,7 @@ import type { ExpressionTag } from "#types";
*/
export const print_expression_tag = define_printer((node: ExpressionTag, _options) => {
const { expression } = node;
return [
//
"{",
print(expression).code,
"}",
].join("");
return insert("{", print(expression).code, "}");
});

if (import.meta.vitest) {
Expand Down
15 changes: 15 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
export const NEW_LINE = "\n";

/**
* Filter out the falsy values and join the truthy (string) values together.
*/
export function insert(...values: (string | null | false)[]) {
let results = "";

for (const value of values) {
if (typeof value === "string") {
results += value;
}
}

return results;
}
Loading