Skip to content

Commit 4d693d1

Browse files
committed
tweaks
1 parent 08d5799 commit 4d693d1

File tree

3 files changed

+53
-27
lines changed

3 files changed

+53
-27
lines changed

packages/svelte/elements.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,6 +2028,7 @@ export interface SvelteHTMLElements {
20282028
'svelte:head': { [name: string]: any };
20292029
'svelte:boundary': {
20302030
onerror?: (error: Error, reset: () => void) => void;
2031+
failed?: import('svelte').Snippet;
20312032
};
20322033

20332034
[name: string]: { [name: string]: any };

packages/svelte/src/compiler/phases/3-transform/client/visitors/SvelteBoundary.js

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { BlockStatement, Statement, Pattern, Expression } from 'estree' */
1+
/** @import { BlockStatement, Statement, Property, Expression } from 'estree' */
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
44

@@ -11,27 +11,45 @@ export function SvelteBoundary(node, context) {
1111
const nodes = [];
1212
/** @type {Statement[]} */
1313
const snippet_statements = [];
14-
/** @type {Expression} */
15-
let failed_param = b.literal(null);
16-
/** @type {Expression | null} */
17-
let onerror = null;
14+
/** @type {Array<Property[] | Expression>} */
15+
const props_and_spreads = [];
16+
17+
let has_spread = false;
18+
19+
const push_prop = (/** @type {Property} */ prop) => {
20+
let current = props_and_spreads.at(-1);
21+
if (Array.isArray(current)) {
22+
current.push(prop);
23+
}
24+
const arr = [prop];
25+
props_and_spreads.push(arr);
26+
};
1827

1928
for (const attribute of node.attributes) {
29+
if (attribute.type === 'SpreadAttribute') {
30+
has_spread = true;
31+
props_and_spreads.push(attribute.expression);
32+
continue;
33+
}
2034
if (
2135
attribute.type !== 'Attribute' ||
2236
attribute.value === true ||
2337
Array.isArray(attribute.value)
2438
) {
2539
continue;
2640
}
27-
if (attribute.name === 'onerror') {
28-
onerror = /** @type {Expression} */ (
29-
context.visit(attribute.value.expression, context.state)
30-
);
31-
} else if (attribute.name === 'failed') {
32-
failed_param = /** @type {Expression} */ (
41+
if (attribute.name === 'onerror' || attribute.name === 'failed') {
42+
const value = /** @type {Expression} */ (
3343
context.visit(attribute.value.expression, context.state)
3444
);
45+
46+
if (attribute.metadata.expression.has_state) {
47+
push_prop(
48+
b.prop('get', b.id(attribute.name), b.function(null, [], b.block([b.return(value)])))
49+
);
50+
} else {
51+
push_prop(b.prop('init', b.id(attribute.name), value));
52+
}
3553
}
3654
}
3755

@@ -41,7 +59,8 @@ export function SvelteBoundary(node, context) {
4159
const init = [];
4260
const block_state = { ...context.state, init };
4361
context.visit(child, block_state);
44-
failed_param = b.id('failed');
62+
const current = props_and_spreads.at(-1) ?? props_and_spreads.push([]);
63+
push_prop(b.prop('init', b.id('failed'), b.id('failed')));
4564
snippet_statements.push(...init);
4665
} else {
4766
nodes.push(child);
@@ -58,14 +77,16 @@ export function SvelteBoundary(node, context) {
5877
)
5978
);
6079

80+
const props_expression =
81+
!has_spread && Array.isArray(props_and_spreads[0])
82+
? b.object(props_and_spreads[0])
83+
: b.call(
84+
'$.spread_props',
85+
...props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))
86+
);
87+
6188
const boundary = b.stmt(
62-
b.call(
63-
'$.boundary',
64-
context.state.node,
65-
b.arrow([b.id('$$anchor')], block),
66-
failed_param,
67-
!onerror ? b.literal(null) : onerror
68-
)
89+
b.call('$.boundary', context.state.node, b.arrow([b.id('$$anchor')], block), props_expression)
6990
);
7091

7192
context.state.template.push('<!>');

packages/svelte/src/internal/client/dom/blocks/boundary.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ function with_boundary(boundary, fn) {
4343
/**
4444
* @param {TemplateNode} node
4545
* @param {((anchor: Node) => void)} boundary_fn
46-
* @param {(anchor: Node, error: () => Error, reset: () => () => void) => void | null} failed
47-
* @param {(error: Error, reset: () => void) => void | null} onerror
46+
* @param {{
47+
* onerror?: (error: Error, reset: () => void) => void,
48+
* failed?: (anchor: Node, error: () => Error, reset: () => () => void) => void
49+
* }} props
4850
* @returns {void}
4951
*/
50-
export function boundary(node, boundary_fn, failed, onerror) {
52+
export function boundary(node, boundary_fn, props) {
5153
var anchor = node;
5254

5355
/** @type {Effect | null} */
@@ -67,7 +69,7 @@ export function boundary(node, boundary_fn, failed, onerror) {
6769

6870
// If we have nothing to capture the error then rethrow the error
6971
// for another boundary to handle
70-
if (!onerror && !failed) {
72+
if (!props.onerror && !props.failed) {
7173
throw error;
7274
}
7375

@@ -82,17 +84,19 @@ export function boundary(node, boundary_fn, failed, onerror) {
8284
});
8385
};
8486

85-
if (onerror) {
86-
onerror(error, reset);
87+
if (props.onerror) {
88+
props.onerror(error, reset);
8789
}
8890

89-
if (failed) {
91+
let failed_snippet = props.failed;
92+
93+
if (failed_snippet) {
9094
// Ensure we create the boundary branch after the catch event cycle finishes
9195
queue_micro_task(() => {
9296
with_boundary(boundary, () => {
9397
boundary_effect = null;
9498
boundary_effect = branch(() =>
95-
failed(
99+
failed_snippet(
96100
anchor,
97101
() => error,
98102
() => reset

0 commit comments

Comments
 (0)