Skip to content

Commit a45b405

Browse files
committed
Merge remote-tracking branch 'upstream/main' into $state-invalidate
2 parents 527042e + c365634 commit a45b405

File tree

118 files changed

+2129
-397
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+2129
-397
lines changed

.changeset/wild-bulldogs-move.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

benchmarking/compare/index.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,37 @@ for (let i = 0; i < results[0].length; i += 1) {
6767
for (const metric of ['time', 'gc_time']) {
6868
const times = results.map((result) => +result[i][metric]);
6969
let min = Infinity;
70+
let max = -Infinity;
7071
let min_index = -1;
7172

7273
for (let b = 0; b < times.length; b += 1) {
73-
if (times[b] < min) {
74-
min = times[b];
74+
const time = times[b];
75+
76+
if (time < min) {
77+
min = time;
7578
min_index = b;
7679
}
80+
81+
if (time > max) {
82+
max = time;
83+
}
7784
}
7885

7986
if (min !== 0) {
80-
console.group(`${metric}: fastest is ${branches[min_index]}`);
87+
console.group(`${metric}: fastest is ${char(min_index)} (${branches[min_index]})`);
8188
times.forEach((time, b) => {
82-
console.log(`${branches[b]}: ${time.toFixed(2)}ms (${((time / min) * 100).toFixed(2)}%)`);
89+
const SIZE = 20;
90+
const n = Math.round(SIZE * (time / max));
91+
92+
console.log(`${char(b)}: ${'◼'.repeat(n)}${' '.repeat(SIZE - n)} ${time.toFixed(2)}ms`);
8393
});
8494
console.groupEnd();
8595
}
8696
}
8797

8898
console.groupEnd();
8999
}
100+
101+
function char(i) {
102+
return String.fromCharCode(97 + i);
103+
}

documentation/docs/02-runes/02-$state.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Unlike other frameworks you may have encountered, there is no API for interactin
2020

2121
If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates.
2222

23-
> [!NOTE] Classes like `Set` and `Map` will not be proxied, but Svelte provides reactive implementations for various built-ins like these that can be imported from [`svelte/reactivity`](./svelte-reactivity).
23+
> [!NOTE] Class instances are not proxied. You can create [reactive state fields](#Classes) on classes that you define. Svelte provides reactive implementations of built-ins like `Set` and `Map` that can be imported from [`svelte/reactivity`](svelte-reactivity).
2424
2525
State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this...
2626

documentation/docs/02-runes/07-$inspect.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ This rune, added in 5.14, causes the surrounding function to be _traced_ in deve
5252
import { doSomeWork } from './elsewhere';
5353
5454
$effect(() => {
55+
+++// $inspect.trace must be the first statement of a function body+++
5556
+++$inspect.trace();+++
5657
doSomeWork();
5758
});

documentation/docs/03-template-syntax/01-basic-markup.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,14 @@ As with elements, `name={name}` can be replaced with the `{name}` shorthand.
8282
<Widget foo={bar} answer={42} text="hello" />
8383
```
8484

85+
## Spread attributes
86+
8587
_Spread attributes_ allow many attributes or properties to be passed to an element or component at once.
8688

87-
An element or component can have multiple spread attributes, interspersed with regular ones.
89+
An element or component can have multiple spread attributes, interspersed with regular ones. Order matters — if `things.a` exists it will take precedence over `a="b"`, while `c="d"` would take precedence over `things.c`:
8890

8991
```svelte
90-
<Widget {...things} />
92+
<Widget a="b" {...things} c="d" />
9193
```
9294

9395
## Events

documentation/docs/03-template-syntax/03-each.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ An each block can also specify an _index_, equivalent to the second argument in
4343
{#each expression as name, index (key)}...{/each}
4444
```
4545

46-
If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.
46+
If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to intelligently update the list when data changes by inserting, moving and deleting items, rather than adding or removing items at the end and updating the state in the middle.
47+
48+
The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change.
4749

4850
```svelte
4951
{#each items as item (item.id)}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: {@attach ...}
3+
---
4+
5+
Attachments are functions that run when an element is mounted to the DOM. Optionally, they can return a function that is called when the element is later removed from the DOM.
6+
7+
> [!NOTE]
8+
> Attachments are available in Svelte 5.29 and newer.
9+
10+
```svelte
11+
<!--- file: App.svelte --->
12+
<script>
13+
/** @type {import('svelte/attachments').Attachment} */
14+
function myAttachment(element) {
15+
console.log(element.nodeName); // 'DIV'
16+
17+
return () => {
18+
console.log('cleaning up');
19+
};
20+
}
21+
</script>
22+
23+
<div {@attach myAttachment}>...</div>
24+
```
25+
26+
An element can have any number of attachments.
27+
28+
## Attachment factories
29+
30+
A useful pattern is for a function, such as `tooltip` in this example, to _return_ an attachment ([demo](/playground/untitled#H4sIAAAAAAAAE3VT0XLaMBD8lavbDiaNCUlbHhTItG_5h5AH2T5ArdBppDOEMv73SkbGJGnH47F9t3un3TsfMyO3mInsh2SW1Sa7zlZKo8_E0zHjg42pGAjxBPxp7cTvUHOMldLjv-IVGUbDoUw295VTlh-WZslqa8kxsLL2ACtHWxh175NffnQfAAGikSGxYQGfPEvGfPSIWtOH0TiBVo2pWJEBJtKhQp4YYzjG9JIdcuMM5IZqHMPioY8vOSA997zQoevf4a7heO7cdp34olRiTGr07OhwH1IdoO2A7dLMbwahZq6MbRhKZWqxk7rBxTGVbuHmhCgb5qDgmIx_J6XtHHukHTrYYqx_YpzYng8aO4RYayql7hU-1ZJl0akqHBE_D9KLolwL-Dibzc7iSln9XjtqTF1UpMkJ2EmXR-BgQErsN4pxIJKr0RVO1qrxAqaTO4fbc9bKulZm3cfDY3aZDgvFGErWjmzhN7KmfX5rXyDeX8Pt1mU-hXjdBOrtuB97vK4GPUtmJ41XcRMEGDLD8do0nJ73zhUhSlyRw0t3vPqD8cjfLs-axiFgNBrkUd9Ulp50c-GLxlXAVlJX-ffpZyiSn7H0eLCUySZQcQdXlxj4El0Yv_FZvIKElqqGTruVLhzu7VRKCh22_5toOyxsWqLwwzK-cCbYNdg-hy-p9D7sbiZWUnts_wLUOF3CJgQAAA==)):
31+
32+
```svelte
33+
<!--- file: App.svelte --->
34+
<script>
35+
import tippy from 'tippy.js';
36+
37+
let content = $state('Hello!');
38+
39+
/**
40+
* @param {string} content
41+
* @returns {import('svelte/attachments').Attachment}
42+
*/
43+
function tooltip(content) {
44+
return (element) => {
45+
const tooltip = tippy(element, { content });
46+
return tooltip.destroy;
47+
};
48+
}
49+
</script>
50+
51+
<input bind:value={content} />
52+
53+
<button {@attach tooltip(content)}>
54+
Hover me
55+
</button>
56+
```
57+
58+
Since the `tooltip(content)` expression runs inside an [effect]($effect), the attachment will be destroyed and recreated whenever `content` changes.
59+
60+
## Inline attachments
61+
62+
Attachments can also be created inline ([demo](/playground/untitled#H4sIAAAAAAAAE71Wf3OaWBT9KoyTTnW3MS-I3dYmnWXVtnRAazRJzbozRSQEApiRhwKO333vuY8m225m_9yZGOT9OPfcc84D943UTfxGr_G7K6Xr3TVeNW7D2M8avT_3DVk-YAoDNF4vNB8e2tnWjyXGlm7mPzfurVPpp5JgGmeZtwkf5PtFupCxLzVvHa832rl2lElX-s2Xm2DZFNqp_hs-rZetd4v07ORpT3qmQHu7MF2td0BZp8k6z_xkvfXP902_pZ2_1_aYWEiqm0kN8I4r79qbdZ6umnq3q_2iNf22F4dE6qt2oimwdpim_uY6XMm7Fuo-IQT_iTD_CeGTHwZ38ieIJUFQRxirR1Xf39Dw0X5z0I72Af4tD61vvPNwWKQnqmfPTbduhsEd2J3vO_oBd3dc6fF2X7umNdWGf0vBRhSS6qoV7cCXfTXWfKmvWG61_si_vfU92Wz-E4RhsLhNIYinsox9QKGVd8-tuACCeKXRX12P-T_eKf7fhTq0Hvt-f3ailtSeoxJHRo1-58NoPe1UiBc1hkL8Yeh45y_vQ3mcuNl9T8s3cXPRWLnS7YWJG_gn2Tb4tUjid8jua-PVl08j_ab8I14mH8Llx0s5Tz5Err4ql52r_GYg0mVy1bEGZuD0ze64b5TWYFiM-16wSuJ4JT5vfVpDcztrcG_YkRU4s6HxufzDWF4XuVeJ1P10IbzBemt3Vp1V2e04ZXfrJd7Wicyd039brRIv_RIVu_nXi7X1cfL2sy66ztToUp1TO7qJ7NlwZ0f30pld5qNSVE5o6PbMojFHjgZB7oSicPpGteyLclQap7SvY0dXtM_LR1NT2JFHey3aaxa0VxCeYJ7RMHemoiCcgPZV9pR7o7kgcOjeGliYk9hjDZx8FAq6enwlTPSZj_vYPw9Il64dXdIY8ZmapzwfEd8-1ZyaxWhqkIZOibXUd-6Upqi1pD4uMicCV1GA_7zi73UN8BaF4sC8peJtMjfmjbHZBFwq5ov50qRaE0l96NZggnW4KqypYRAW-uhSz9ADvklwJF2J-5W0Z5fQPBhDX92R6I_0IFxRgDftge4l4dP-gH1hjD7uqU6fsOEZ9UNrCdPB-nys6uXgY6O3ZMd9sy5T9PghqrWHdjo4jB51CgLiKJaDYYA-7WgYONf1FbjkI-mE3EAfUY_rijfuJ_CVPaR50oe9JF7Q0pI8Dw3osxxYHdYPGbp2CnwHF8KvwJv2wEv0Z3ilQI6U9uwbZxbYJXvEmjjQjjCHkvNLvNg3yhzXQd1olamsT4IRrZmX0MUDpwL7R8zzHj7pSh9hPHFSHjLezKqAST51uC5zmtQ87skDUaneLokT5RbXkPWSYz53Abgjc8_o4KFGUZ-Hgv2Z1l5OTYM9D-HfUD0L-EwxH5wRnIG61gS-khfgY1bq7IAP_DA4l5xRuh9xlm8yGjutc8t-wHtkhWv3hc7aqGwiK5KzgvM5xRkZYn193uEln-su55j1GaIv7oM4iPrsVHiG0Dx7TR9-1lBfqFdwfvSd5LNL5xyZVp5NoHFZ57FkfiF6vKs4k5zvIfrX5xX6MXmt0gM5MTu8DjnhukrHHzTRd3jm0dma0_f_x5cxP9f4jBdqHvmbq2fUjzqcKh2Cp-yWj9ntcHanXmBXxhu7Q--eyjhfNFpaV7zgz4nWEUb7zUOhpevjjf_gu_KZ99pxFlZ-T3sttkmYqrco_26q35v0Ewzv5EZPbnL_8BfduWGMnyyN3q0bZ_7hb_7KG_L4CQAA)):
63+
64+
```svelte
65+
<!--- file: App.svelte --->
66+
<canvas
67+
width={32}
68+
height={32}
69+
{@attach (canvas) => {
70+
const context = canvas.getContext('2d');
71+
72+
$effect(() => {
73+
context.fillStyle = color;
74+
context.fillRect(0, 0, canvas.width, canvas.height);
75+
});
76+
}}
77+
></canvas>
78+
```
79+
80+
> [!NOTE]
81+
> The nested effect runs whenever `color` changes, while the outer effect (where `canvas.getContext(...)` is called) only runs once, since it doesn't read any reactive state.
82+
83+
## Passing attachments to components
84+
85+
When used on a component, `{@attach ...}` will create a prop whose key is a [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol). If the component then [spreads](/tutorial/svelte/spread-props) props onto an element, the element will receive those attachments.
86+
87+
This allows you to create _wrapper components_ that augment elements ([demo](/playground/untitled#H4sIAAAAAAAAE3VUS3ObMBD-KxvajnFqsJM2PhA7TXrKob31FjITAbKtRkiMtDhJPfz3LiAMdpxhGJvdb1_fPnaeYjn3Iu-WIbJ04028lZDcetHDzsO3olbVApI74F1RhHbLJdayhFl-Sp5qhVwhufEWNjWiwJtYxSjyQhsEFEXxBiujcxg1_8O_dnQ9APwsEbVyiHDafjrvDZCgkiO4MLCEzxYZcn90z6XUZ6OxA61KlaIgV6i1pFC-sxjDrlbHaDiWRoGvdMbHsLzp5DES0mJnRxGaRBvcBHb7yFUTCQeunEWYcYtGv12TqgFUDbCK1WLaM6IWQhUlQiJUFm2ZLPly51xXMG0Rjoyd69C7UqqG2nu95QZyXvtvLVpri2-SN4hoLXXCZFfhQ8aQBU1VgdEaH_vSgyBZR_BpPp_vi0tY-rw2ulRZkGqpTQRbZvwa2BPgFC8bgbw31CbjJjAsE6WNYBZeGp7vtQXLMqHWnZx-5kM1TR5ycpkZXQR2wzL94l8Ur1C_3-g168SfQf1MyfRi3LW9fs77emJEw5QV9SREoLTq06tcczq7d6xEUcJX2vAhO1b843XK34e5unZEMBr15ekuKEusluWAF8lXhE2ZTP2r2RcIHJ-163FPKerCgYJLOB9i4GvNwviI5-gAQiFFBk3tBTOU3HFXEk0R8o86WvUD64aINhv5K3oRmpJXkw8uxMG6Hh6JY9X7OwGSqfUy9tDG3sHNoEi0d_d_fv9qndxRU0VClFqo3KVo3U655Hnt1PXB3Qra2Y2QGdEwgTAMCxopsoxOe6SD0gD8movDhT0LAnhqlE8gVCpLWnRoV7OJCkFAwEXitrYL1W7p7pbiE_P7XH6E_rihODm5s52XtiH9Ekaw0VgI9exadWL1uoEYjPtg2672k5szsxbKyWB2fdT0w5Y_0hcT8oXOlRetmLS8-g-6TLXXQgYAAA==)):
88+
89+
```svelte
90+
<!--- file: Button.svelte --->
91+
<script>
92+
/** @type {import('svelte/elements').HTMLButtonAttributes} */
93+
let { children, ...props } = $props();
94+
</script>
95+
96+
<!-- `props` includes attachments -->
97+
<button {...props}>
98+
{@render children?.()}
99+
</button>
100+
```
101+
102+
```svelte
103+
<!--- file: App.svelte --->
104+
<script>
105+
import tippy from 'tippy.js';
106+
import Button from './Button.svelte';
107+
108+
let content = $state('Hello!');
109+
110+
/**
111+
* @param {string} content
112+
* @returns {import('svelte/attachments').Attachment}
113+
*/
114+
function tooltip(content) {
115+
return (element) => {
116+
const tooltip = tippy(element, { content });
117+
return tooltip.destroy;
118+
};
119+
}
120+
</script>
121+
122+
<input bind:value={content} />
123+
124+
<Button {@attach tooltip(content)}>
125+
Hover me
126+
</Button>
127+
```
128+
129+
## Creating attachments programmatically
130+
131+
To add attachments to an object that will be spread onto a component or element, use [`createAttachmentKey`](svelte-attachments#createAttachmentKey).

documentation/docs/03-template-syntax/11-bind.md renamed to documentation/docs/03-template-syntax/12-bind.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,29 @@ Since 5.6.0, if an `<input>` has a `defaultChecked` attribute and is part of a f
117117
</form>
118118
```
119119

120+
## `<input bind:indeterminate>`
121+
122+
Checkboxes can be in an [indeterminate](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/indeterminate) state, independently of whether they are checked or unchecked:
123+
124+
```svelte
125+
<script>
126+
let checked = $state(false);
127+
let indeterminate = $state(true);
128+
</script>
129+
130+
<form>
131+
<input type="checkbox" bind:checked bind:indeterminate>
132+
133+
{#if indeterminate}
134+
waiting...
135+
{:else if checked}
136+
checked
137+
{:else}
138+
unchecked
139+
{/if}
140+
</form>
141+
```
142+
120143
## `<input bind:group>`
121144

122145
Inputs that work together can use `bind:group`.
@@ -227,6 +250,7 @@ You can give the `<select>` a default value by adding a `selected` attribute to
227250
- [`seeking`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking_event)
228251
- [`ended`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended)
229252
- [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState)
253+
- [`played`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/played)
230254

231255
```svelte
232256
<audio src={clip} bind:duration bind:currentTime bind:paused></audio>
@@ -254,6 +278,10 @@ You can give the `<select>` a default value by adding a `selected` attribute to
254278
</details>
255279
```
256280

281+
## `window` and `document`
282+
283+
To bind to properties of `window` and `document`, see [`<svelte:window>`](svelte-window) and [`<svelte:document>`](svelte-document).
284+
257285
## Contenteditable bindings
258286

259287
Elements with the `contenteditable` attribute support the following bindings:
@@ -278,14 +306,18 @@ All visible elements have the following readonly bindings, measured with a `Resi
278306
- [`clientHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight)
279307
- [`offsetWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth)
280308
- [`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight)
309+
- [`contentRect`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentRect)
310+
- [`contentBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize)
311+
- [`borderBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize)
312+
- [`devicePixelContentBoxSize`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/devicePixelContentBoxSize)
281313

282314
```svelte
283315
<div bind:offsetWidth={width} bind:offsetHeight={height}>
284316
<Chart {width} {height} />
285317
</div>
286318
```
287319

288-
> [!NOTE] `display: inline` elements do not have a width or height (except for elements with 'intrinsic' dimensions, like `<img>` and `<canvas>`), and cannot be observed with a `ResizeObserver`. You will need to change the `display` style of these elements to something else, such as `inline-block`.
320+
> [!NOTE] `display: inline` elements do not have a width or height (except for elements with 'intrinsic' dimensions, like `<img>` and `<canvas>`), and cannot be observed with a `ResizeObserver`. You will need to change the `display` style of these elements to something else, such as `inline-block`. Note that CSS transformations do not trigger `ResizeObserver` callbacks.
289321
290322
## bind:this
291323

documentation/docs/03-template-syntax/12-use.md renamed to documentation/docs/03-template-syntax/13-use.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
title: use:
33
---
44

5+
> [!NOTE]
6+
> In Svelte 5.29 and newer, consider using [attachments](@attach) instead, as they are more flexible and composable.
7+
58
Actions are functions that are called when an element is mounted. They are added with the `use:` directive, and will typically use an `$effect` so that they can reset any state when the element is unmounted:
69

710
```svelte

documentation/docs/07-misc/02-testing.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ Testing helps you write and maintain your code and guard against regressions. Te
66

77
## Unit and integration testing using Vitest
88

9-
Unit tests allow you to test small isolated parts of your code. Integration tests allow you to test parts of your application to see if they work together. If you're using Vite (including via SvelteKit), we recommend using [Vitest](https://vitest.dev/).
9+
Unit tests allow you to test small isolated parts of your code. Integration tests allow you to test parts of your application to see if they work together. If you're using Vite (including via SvelteKit), we recommend using [Vitest](https://vitest.dev/). You can use the Svelte CLI to [setup Vitest](/docs/cli/vitest) either during project creation or later on.
1010

11-
To get started, install Vitest:
11+
To setup Vitest manually, first install it:
1212

1313
```bash
1414
npm install -D vitest
@@ -254,9 +254,9 @@ When writing component tests that involve two-way bindings, context or snippet p
254254

255255
E2E (short for 'end to end') tests allow you to test your full application through the eyes of the user. This section uses [Playwright](https://playwright.dev/) as an example, but you can also use other solutions like [Cypress](https://www.cypress.io/) or [NightwatchJS](https://nightwatchjs.org/).
256256

257-
To get started with Playwright, either install it via [the VS Code extension](https://playwright.dev/docs/getting-started-vscode), or install it from the command line using `npm init playwright`. It is also part of the setup CLI when you run `npx sv create`.
257+
You can use the Svelte CLI to [setup Playwright](/docs/cli/playwright) either during project creation or later on. You can also [set it up with `npm init playwright`](https://playwright.dev/docs/intro). Additionally, you may also want to install an IDE plugin such as [the VS Code extension](https://playwright.dev/docs/getting-started-vscode) to be able to execute tests from inside your IDE.
258258

259-
After you've done that, you should have a `tests` folder and a Playwright config. You may need to adjust that config to tell Playwright what to do before running the tests - mainly starting your application at a certain port:
259+
If you've run `npm init playwright` or are not using Vite, you may need to adjust the Playwright config to tell Playwright what to do before running the tests - mainly starting your application at a certain port. For example:
260260

261261
```js
262262
/// file: playwright.config.js

documentation/docs/07-misc/99-faq.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ _End-to-End Tests_: To ensure your users are able to interact with your applicat
8181

8282
Some resources for getting started with testing:
8383

84+
- [Svelte docs on testing](/docs/svelte/testing)
85+
- [Setup Vitest using the Svelte CLI](/docs/cli/vitest)
8486
- [Svelte Testing Library](https://testing-library.com/docs/svelte-testing-library/example/)
8587
- [Svelte Component Testing in Cypress](https://docs.cypress.io/guides/component-testing/svelte/overview)
86-
- [Example using vitest](https://github.com/vitest-dev/vitest/tree/main/examples/sveltekit)
8788
- [Example using uvu test runner with JSDOM](https://github.com/lukeed/uvu/tree/master/examples/svelte)
8889
- [Test Svelte components using Vitest & Playwright](https://davipon.hashnode.dev/test-svelte-component-using-vitest-playwright)
8990
- [Component testing with WebdriverIO](https://webdriver.io/docs/component-testing/svelte)

documentation/docs/98-reference/.generated/compile-warnings.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,14 @@ Attributes should not contain ':' characters to prevent ambiguity with Svelte di
586586
Quoted attributes on components and custom elements will be stringified in a future version of Svelte. If this isn't what you want, remove the quotes
587587
```
588588

589+
### bidirectional_control_characters
590+
591+
```
592+
A bidirectional control character was detected in your code. These characters can be used to alter the visual direction of your code and could have unintended consequences
593+
```
594+
595+
Bidirectional control characters can alter the direction in which text appears to be in. For example, via control characters, you can make `defabc` look like `abcdef`. As a result, if you were to unknowingly copy and paste some code that has these control characters, they may alter the behavior of your code in ways you did not intend. See [trojansource.codes](https://trojansource.codes/) for more information.
596+
589597
### bind_invalid_each_rest
590598

591599
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
title: svelte/attachments
3+
---
4+
5+
> MODULE: svelte/attachments

0 commit comments

Comments
 (0)