mirror of https://github.com/sveltejs/svelte
commit
b10f1de17f
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: prevent untracked derived reads from retaining disconnected dependencies
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: restore hydration state when custom element attribute updates throw
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: flush anything pending before invoking flushSync callback function
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: preserve location information for `await` wrappers
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: keep a reactive assignment with no dependencies when `migrate` cannot turn it into a declaration
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: don't hang `migrate` on a declaration that shares a line with its script tag
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: don't warn about a redundant `link` role on `<area>` elements without an `href`
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: read batch-local array on each-block commit
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: error at compile time when a declaration in a snippet redeclares one of its parameters
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: error when using `let:` directives on a component with a `children` snippet
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: ignore stale boundary reset callbacks
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
'svelte': patch
|
||||
---
|
||||
|
||||
fix: handle deferred transitions aborted before initialization
|
||||
@ -0,0 +1,10 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'let_directive_snippet_conflict',
|
||||
message:
|
||||
'Cannot use `let:` directives on a component that has a `children` snippet. Use snippet parameters instead (e.g. `{#snippet children({ item: x })}`)',
|
||||
position: [62, 74]
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
import Child from './irrelevant';
|
||||
</script>
|
||||
|
||||
<Child let:item={x}>
|
||||
{#snippet children()}{x}{/snippet}
|
||||
</Child>
|
||||
@ -0,0 +1,10 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
error: {
|
||||
code: 'let_directive_snippet_conflict',
|
||||
message:
|
||||
'Cannot use `let:` directives on a component that has a `children` snippet. Use snippet parameters instead (e.g. `{#snippet children({ value })}`)',
|
||||
position: [359, 368]
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import Child from './irrelevant';
|
||||
import Parent from './irrelevant';
|
||||
</script>
|
||||
|
||||
<!-- ok -->
|
||||
<Child let:value>
|
||||
{value}
|
||||
{#snippet foo()}x{/snippet}
|
||||
</Child>
|
||||
<Child>
|
||||
{#snippet children({ value })}{value}{/snippet}
|
||||
</Child>
|
||||
<Parent>
|
||||
<Child slot="foo" let:value>
|
||||
{#snippet children()}{value}{/snippet}
|
||||
</Child>
|
||||
</Parent>
|
||||
|
||||
<!-- invalid -->
|
||||
<Child let:value>
|
||||
{#snippet children()}Value is: {value}{/snippet}
|
||||
</Child>
|
||||
@ -0,0 +1,8 @@
|
||||
<script>
|
||||
$: count = 7;
|
||||
$: other = 8;
|
||||
let obj = {};
|
||||
$: obj.x = 1;
|
||||
</script>
|
||||
|
||||
<p>{count} {other} {obj.x}</p>
|
||||
@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
let count = $state(7);
|
||||
|
||||
let other = $state(8);
|
||||
|
||||
let obj = $state({});
|
||||
run(() => {
|
||||
obj.x = 1;
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>{count} {other} {obj.x}</p>
|
||||
@ -0,0 +1,2 @@
|
||||
<script>export let answer</script>
|
||||
<p>{answer}</p>
|
||||
@ -0,0 +1,3 @@
|
||||
<script>
|
||||
let { answer } = $props();</script>
|
||||
<p>{answer}</p>
|
||||
@ -0,0 +1,13 @@
|
||||
import { flushSync } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
async test({ assert, target }) {
|
||||
const [button] = target.querySelectorAll('button');
|
||||
|
||||
button.click();
|
||||
flushSync();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, '<button>Reproduce</button><p>Deferred outro</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
<script>
|
||||
import { crossfade } from 'svelte/transition';
|
||||
|
||||
let visible = $state(true);
|
||||
let restore = $state(false);
|
||||
const [send] = crossfade({});
|
||||
|
||||
$effect(() => {
|
||||
if (restore) visible = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<button
|
||||
onclick={() => {
|
||||
visible = false;
|
||||
restore = true;
|
||||
}}
|
||||
>
|
||||
Reproduce
|
||||
</button>
|
||||
|
||||
{#if visible}
|
||||
<p out:send={{ key: 'item' }}>Deferred outro</p>
|
||||
{/if}
|
||||
@ -0,0 +1,50 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
/** @type {Array<() => void>} */
|
||||
const resolvers = [];
|
||||
|
||||
export default test({
|
||||
transformError: (error) => new Promise((resolve) => resolvers.push(() => resolve(error))),
|
||||
|
||||
async test({ assert, target, logs }) {
|
||||
const [error, toggle, reset, destroy] = target.querySelectorAll('button');
|
||||
const paragraph = /** @type {HTMLParagraphElement} */ (target.querySelector('p'));
|
||||
|
||||
error.click();
|
||||
await tick();
|
||||
resolvers.shift()?.();
|
||||
await tick();
|
||||
assert.htmlEqual(paragraph.innerHTML, 'boom');
|
||||
|
||||
// A retained reset is inert after its boundary has been destroyed
|
||||
toggle.click();
|
||||
await tick();
|
||||
reset.click();
|
||||
await tick();
|
||||
assert.htmlEqual(paragraph.innerHTML, 'boom');
|
||||
|
||||
// Resolving an error transform cannot resume a destroyed boundary
|
||||
toggle.click();
|
||||
await tick();
|
||||
error.click();
|
||||
await tick();
|
||||
toggle.click();
|
||||
await tick();
|
||||
resolvers.shift()?.();
|
||||
await tick();
|
||||
assert.htmlEqual(paragraph.innerHTML, 'boom');
|
||||
|
||||
// A failed snippet's reset is also inert while the boundary is being destroyed
|
||||
toggle.click();
|
||||
await tick();
|
||||
error.click();
|
||||
await tick();
|
||||
resolvers.shift()?.();
|
||||
await tick();
|
||||
destroy.click();
|
||||
await tick();
|
||||
assert.htmlEqual(paragraph.innerHTML, 'boom,boom');
|
||||
assert.deepEqual(logs, ['render', 'render', 'render']);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,47 @@
|
||||
<script>
|
||||
let show = $state(true);
|
||||
let must_throw = $state(false);
|
||||
let reset;
|
||||
let element;
|
||||
let errors = $state([]);
|
||||
let reset_during_cleanup = false;
|
||||
|
||||
function throw_error() {
|
||||
throw new Error('boom');
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
must_throw = false;
|
||||
show = !show;
|
||||
}
|
||||
|
||||
function reset_on_cleanup(_, reset_boundary) {
|
||||
return {
|
||||
destroy() {
|
||||
if (reset_during_cleanup) reset_boundary();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function track_render() {
|
||||
console.log('render');
|
||||
}
|
||||
</script>
|
||||
|
||||
<button onclick={() => (must_throw = true)}>error</button>
|
||||
<button onclick={toggle}>toggle</button>
|
||||
<button onclick={() => reset()}>reset</button>
|
||||
<button onclick={() => { reset_during_cleanup = true; toggle(); }}>destroy</button>
|
||||
<p>{errors.join(',')}</p>
|
||||
|
||||
{#if show}
|
||||
<svelte:boundary onerror={(error, fn) => { errors.push(error.message); reset = fn; }}>
|
||||
{track_render()}
|
||||
<input bind:this={element} />
|
||||
{must_throw ? throw_error() : ''}
|
||||
|
||||
{#snippet failed(_, failed_reset)}
|
||||
<input bind:this={element} use:reset_on_cleanup={failed_reset} />
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
{/if}
|
||||
@ -0,0 +1,11 @@
|
||||
import { tick } from 'svelte';
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({
|
||||
mode: ['hydrate'],
|
||||
|
||||
async test({ assert, target }) {
|
||||
await tick();
|
||||
assert.htmlEqual(target.innerHTML, '<p>failed: setter error</p><p>after</p>');
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,22 @@
|
||||
<script module>
|
||||
if (!customElements.get('throwing-element')) {
|
||||
customElements.define(
|
||||
'throwing-element',
|
||||
class extends HTMLElement {
|
||||
set value(_) {
|
||||
throw new Error('setter error');
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<throwing-element {...{ value: 'boom' }}></throwing-element>
|
||||
|
||||
{#snippet failed(error)}
|
||||
<p>failed: {error.message}</p>
|
||||
{/snippet}
|
||||
</svelte:boundary>
|
||||
|
||||
<p>after</p>
|
||||
@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"code": "declaration_duplicate",
|
||||
"message": "`item` has already been declared",
|
||||
"start": {
|
||||
"line": 13,
|
||||
"column": 8
|
||||
},
|
||||
"end": {
|
||||
"line": 13,
|
||||
"column": 12
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,17 @@
|
||||
<!-- this is ok -->
|
||||
{#snippet row1(item)}
|
||||
{#if item}
|
||||
{const item = 1}
|
||||
<p>{item}</p>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
{@render row1(5)}
|
||||
|
||||
<!-- this is not -->
|
||||
{#snippet row2(item)}
|
||||
{const item = 1}
|
||||
<p>{item}</p>
|
||||
{/snippet}
|
||||
|
||||
{@render row2(5)}
|
||||
Loading…
Reference in new issue