diff --git a/.changeset/clever-toys-decide.md b/.changeset/clever-toys-decide.md deleted file mode 100644 index 57eb2b0058..0000000000 --- a/.changeset/clever-toys-decide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'svelte': patch ---- - -fix: don't reexecute derived with no dependencies on teardown diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 046ad335f3..51408fc8cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,23 @@ jobs: env: CI: true SVELTE_NO_ASYNC: true + TSGo: + permissions: {} + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + - name: install + run: pnpm install --frozen-lockfile + - name: install tsgo + run: cd packages/svelte && pnpm i -D @typescript/native-preview + - name: type check + run: cd packages/svelte && pnpm check:tsgo Lint: permissions: {} runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2d3e45049..0653b08b76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,13 +101,13 @@ Test samples are kept in `/test/xxx/samples` folder. 1. To run test, run `pnpm test`. 1. To run a particular test suite, use `pnpm test `, for example: - ```bash + ```sh pnpm test validator ``` 1. To filter tests _within_ a test suite, use `pnpm test -t `, for example: - ```bash + ```sh pnpm test validator -t a11y-alt-text ``` diff --git a/documentation/docs/01-introduction/02-getting-started.md b/documentation/docs/01-introduction/02-getting-started.md index c7351729ff..e97a46ad34 100644 --- a/documentation/docs/01-introduction/02-getting-started.md +++ b/documentation/docs/01-introduction/02-getting-started.md @@ -4,7 +4,7 @@ title: Getting started We recommend using [SvelteKit](../kit), which lets you [build almost anything](../kit/project-types). It's the official application framework from the Svelte team and powered by [Vite](https://vite.dev/). Create a new project with: -```bash +```sh npx sv create myapp cd myapp npm install diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md index 59010c981f..87b4c3050f 100644 --- a/documentation/docs/02-runes/04-$effect.md +++ b/documentation/docs/02-runes/04-$effect.md @@ -135,7 +135,7 @@ An effect only reruns when the object it reads changes, not when a property insi An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. -For instance, if `condition` is `true` in the code snippet below, the code inside the `if` block will run and `color` will be evaluated. As such, changes to either `condition` or `color` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE21RQW6DMBD8ytaNBJHaJFLViwNIVZ8RcnBgXVk1xsILTYT4e20TQg89IOPZ2fHM7siMaJBx9tmaWpFqjQNlAKXEihx7YVJpdIyfRkY3G4gB8Pi97cPanRtQU8AuwuF_eNUaQuPlOMtc1SlLRWlKUo1tOwJflUikQHZtA0klzCDc64Imx0ANn8bInV1CDhtHgjClrsftcSXotluLybOUb3g4JJHhOZs5WZpuIS9gjNqkJKQP5e2ClrR4SMdZ13E4xZ8zTPOTJU2A2uE_PQ9COCI926_hTVarIU4hu_REPlBrKq2q73ycrf1N-vS4TMUsulaVg3EtR8H9rFgsg8uUsT1B2F9eshigZHBRpuaD0D3mY8Qm2BfB5N2YyRzdNEYVDy0Ja-WsFjcOUuP1HvFLWA6H3XuHTUSmmDV2--0TXonxsKbp7G9C6R__NONS-MFNvxj_d6mBAgAA). +For instance, if `condition` is `true` in the code snippet below, the code inside the `if` block will run and `color` will be evaluated. This means that changes to either `condition` or `color` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE21RQW6DMBD8ytaNBJHaJFLViwNIVZ8RcnBgXVk1xsILTYT4e20TQg89IOPZ2fHM7siMaJBx9tmaWpFqjQNlAKXEihx7YVJpdIyfRkY3G4gB8Pi97cPanRtQU8AuwuF_eNUaQuPlOMtc1SlLRWlKUo1tOwJflUikQHZtA0klzCDc64Imx0ANn8bInV1CDhtHgjClrsftcSXotluLybOUb3g4JJHhOZs5WZpuIS9gjNqkJKQP5e2ClrR4SMdZ13E4xZ8zTPOTJU2A2uE_PQ9COCI926_hTVarIU4hu_REPlBrKq2q73ycrf1N-vS4TMUsulaVg3EtR8H9rFgsg8uUsT1B2F9eshigZHBRpuaD0D3mY8Qm2BfB5N2YyRzdNEYVDy0Ja-WsFjcOUuP1HvFLWA6H3XuHTUSmmDV2--0TXonxsKbp7G9C6R__NONS-MFNvxj_d6mBAgAA). Conversely, if `condition` is `false`, `color` will not be evaluated, and the effect will _only_ re-run again when `condition` changes. diff --git a/documentation/docs/03-template-syntax/06-snippet.md b/documentation/docs/03-template-syntax/06-snippet.md index ab536c6e5c..02f58e0f6c 100644 --- a/documentation/docs/03-template-syntax/06-snippet.md +++ b/documentation/docs/03-template-syntax/06-snippet.md @@ -277,4 +277,4 @@ Snippets can be created programmatically with the [`createRawSnippet`](svelte#cr ## Snippets and slots -In Svelte 4, content can be passed to components using [slots](legacy-slots). Snippets are more powerful and flexible, and as such slots are deprecated in Svelte 5. +In Svelte 4, content can be passed to components using [slots](legacy-slots). Snippets are more powerful and flexible, and so slots have been deprecated in Svelte 5. diff --git a/documentation/docs/03-template-syntax/08-@html.md b/documentation/docs/03-template-syntax/08-@html.md index 30456fa666..6d8a8be0c6 100644 --- a/documentation/docs/03-template-syntax/08-@html.md +++ b/documentation/docs/03-template-syntax/08-@html.md @@ -22,7 +22,7 @@ It also will not compile Svelte code. ## Styling -Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](scoped-styles) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused: +Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](scoped-styles). In other words, this will not work, and the `a` and `img` styles will be regarded as unused: ```svelte diff --git a/documentation/docs/03-template-syntax/18-class.md b/documentation/docs/03-template-syntax/18-class.md index 1ea4a208df..db85db4b37 100644 --- a/documentation/docs/03-template-syntax/18-class.md +++ b/documentation/docs/03-template-syntax/18-class.md @@ -71,7 +71,7 @@ The user of this component has the same flexibility to use a mixture of objects, ``` -Svelte also exposes the `ClassValue` type, which is the type of value that the `class` attribute on elements accept. This is useful if you want to use a type-safe class name in component props: +Since Svelte 5.19, Svelte also exposes the `ClassValue` type, which is the type of value that the `class` attribute on elements accept. This is useful if you want to use a type-safe class name in component props: ```svelte ``` -> [!NOTE] This behaviour will only work when the function passed to `onMount` _synchronously_ returns a value. `async` functions always return a `Promise`, and as such cannot _synchronously_ return a function. +> [!NOTE] This behaviour will only work when the function passed to `onMount` is _synchronous_. `async` functions always return a `Promise`. ## `onDestroy` diff --git a/documentation/docs/07-misc/02-testing.md b/documentation/docs/07-misc/02-testing.md index db99b70770..bcec4db0a3 100644 --- a/documentation/docs/07-misc/02-testing.md +++ b/documentation/docs/07-misc/02-testing.md @@ -10,7 +10,7 @@ Unit tests allow you to test small isolated parts of your code. Integration test To setup Vitest manually, first install it: -```bash +```sh npm install -D vitest ``` @@ -166,7 +166,7 @@ It is possible to test your components in isolation using Vitest. To get started, install jsdom (a library that shims DOM APIs): -```bash +```sh npm install -D jsdom ``` diff --git a/documentation/docs/07-misc/07-v5-migration-guide.md b/documentation/docs/07-misc/07-v5-migration-guide.md index c24c1febee..37da3b7b23 100644 --- a/documentation/docs/07-misc/07-v5-migration-guide.md +++ b/documentation/docs/07-misc/07-v5-migration-guide.md @@ -245,7 +245,7 @@ In Svelte 4, you can add event modifiers to handlers: ``` -Modifiers are specific to `on:` and as such do not work with modern event handlers. Adding things like `event.preventDefault()` inside the handler itself is preferable, since all the logic lives in one place rather than being split between handler and modifiers. +Modifiers are specific to `on:` and so do not work with modern event handlers. Adding things like `event.preventDefault()` inside the handler itself is preferable, since all the logic lives in one place rather than being split between handler and modifiers. Since event handlers are just functions, you can create your own wrappers as necessary: @@ -340,7 +340,7 @@ When spreading props, local event handlers must go _after_ the spread, or they r ## Snippets instead of slots -In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets which are more powerful and flexible, and as such slots are deprecated in Svelte 5. +In Svelte 4, content can be passed to components using slots. Svelte 5 replaces them with snippets, which are more powerful and flexible, and so slots are deprecated in Svelte 5. They continue to work, however, and you can pass snippets to a component that uses slots: @@ -599,7 +599,7 @@ Note that `mount` and `hydrate` are _not_ synchronous, so things like `onMount` ### Server API changes -Similarly, components no longer have a `render` method when compiled for server side rendering. Instead, pass the function to `render` from `svelte/server`: +Similarly, components no longer have a `render` method when compiled for server-side rendering. Instead, pass the function to `render` from `svelte/server`: ```js +++import { render } from 'svelte/server';+++ @@ -803,7 +803,7 @@ Note that Svelte 5 will also warn if you have a single expression wrapped in quo ### HTML structure is stricter -In Svelte 4, you were allowed to write HTML code that would be repaired by the browser when server side rendering it. For example you could write this... +In Svelte 4, you were allowed to write HTML code that would be repaired by the browser when server-side rendering it. For example you could write this... ```svelte @@ -835,7 +835,7 @@ Assignments to destructured parts of a `@const` declaration are no longer allowe ### :is(...), :has(...), and :where(...) are scoped -Previously, Svelte did not analyse selectors inside `:is(...)`, `:has(...)`, and `:where(...)`, effectively treating them as global. Svelte 5 analyses them in the context of the current component. As such, some selectors may now be treated as unused if they were relying on this treatment. To fix this, use `:global(...)` inside the `:is(...)/:has(...)/:where(...)` selectors. +Previously, Svelte did not analyse selectors inside `:is(...)`, `:has(...)`, and `:where(...)`, effectively treating them as global. Svelte 5 analyses them in the context of the current component. Some selectors may now therefore be treated as unused if they were relying on this treatment. To fix this, use `:global(...)` inside the `:is(...)/:has(...)/:where(...)` selectors. When using Tailwind's `@apply` directive, add a `:global` selector to preserve rules that use Tailwind-generated `:is(...)` selectors: @@ -964,7 +964,7 @@ Since these mismatches are extremely rare, Svelte 5 assumes that the values are ### Hydration works differently -Svelte 5 makes use of comments during server side rendering which are used for more robust and efficient hydration on the client. As such, you shouldn't remove comments from your HTML output if you intend to hydrate it, and if you manually authored HTML to be hydrated by a Svelte component, you need to adjust that HTML to include said comments at the correct positions. +Svelte 5 makes use of comments during server-side rendering which are used for more robust and efficient hydration on the client. You therefore should not remove comments from your HTML output if you intend to hydrate it, and if you manually authored HTML to be hydrated by a Svelte component, you need to adjust that HTML to include said comments at the correct positions. ### `onevent` attributes are delegated diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md index 20f57770d1..b9c44163c9 100644 --- a/documentation/docs/98-reference/.generated/compile-errors.md +++ b/documentation/docs/98-reference/.generated/compile-errors.md @@ -196,6 +196,51 @@ Cyclical dependency detected: %cycle% `{@const}` must be the immediate child of `{#snippet}`, `{#if}`, `{:else if}`, `{:else}`, `{#each}`, `{:then}`, `{:catch}`, ``, `` ``` +### const_tag_invalid_reference + +``` +The `{@const %name% = ...}` declaration is not available in this snippet +``` + +The following is an error: + +```svelte + + {@const foo = 'bar'} + + {#snippet failed()} + {foo} + {/snippet} + +``` + +Here, `foo` is not available inside `failed`. The top level code inside `` becomes part of the implicit `children` snippet, in other words the above code is equivalent to this: + +```svelte + + {#snippet children()} + {@const foo = 'bar'} + {/snippet} + + {#snippet failed()} + {foo} + {/snippet} + +``` + +The same applies to components: + +```svelte + + {@const foo = 'bar'} + + {#snippet someProp()} + + {foo} + {/snippet} + +``` + ### constant_assignment ``` @@ -364,6 +409,12 @@ The $ name is reserved, and cannot be used for variables and imports The $ prefix is reserved, and cannot be used for variables and imports ``` +### duplicate_class_field + +``` +`%name%` has already been declared +``` + ### each_item_invalid_assignment ``` diff --git a/documentation/docs/98-reference/.generated/compile-warnings.md b/documentation/docs/98-reference/.generated/compile-warnings.md index 2af9021a6a..17841b863c 100644 --- a/documentation/docs/98-reference/.generated/compile-warnings.md +++ b/documentation/docs/98-reference/.generated/compile-warnings.md @@ -679,11 +679,11 @@ In HTML, there's [no such thing as a self-closing tag](https://jakearchibald.com ``` -Some templating languages (including Svelte) will 'fix' HTML by turning `` into ``. Others adhere to the spec. Both result in ambiguity and confusion when copy-pasting code between different contexts, and as such Svelte prompts you to resolve the ambiguity directly by having an explicit closing tag. +Some templating languages (including Svelte) will 'fix' HTML by turning `` into ``. Others adhere to the spec. Both result in ambiguity and confusion when copy-pasting code between different contexts, so Svelte prompts you to resolve the ambiguity directly by having an explicit closing tag. To automate this, run the dedicated migration: -```bash +```sh npx sv migrate self-closing-tags ``` diff --git a/documentation/docs/98-reference/21-svelte-action.md b/documentation/docs/98-reference/21-svelte-action.md index 53423ec409..ef3ebfbf70 100644 --- a/documentation/docs/98-reference/21-svelte-action.md +++ b/documentation/docs/98-reference/21-svelte-action.md @@ -2,4 +2,6 @@ title: svelte/action --- +This module provides types for [actions](use), which have been superseded by [attachments](@attach). + > MODULE: svelte/action diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 6f6b824174..de94eb1897 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,197 @@ # svelte +## 5.38.6 + +### Patch Changes + +- fix: don't fail on `flushSync` while flushing effects ([#16674](https://github.com/sveltejs/svelte/pull/16674)) + +## 5.38.5 + +### Patch Changes + +- fix: ensure async deriveds always get dependencies from thennable ([#16672](https://github.com/sveltejs/svelte/pull/16672)) + +## 5.38.4 + +### Patch Changes + +- fix: place instance-level snippets inside async body ([#16666](https://github.com/sveltejs/svelte/pull/16666)) + +- fix: Add check for builtin custom elements in `set_custom_element_data` ([#16592](https://github.com/sveltejs/svelte/pull/16592)) + +- fix: restore batch along with effect context ([#16668](https://github.com/sveltejs/svelte/pull/16668)) + +- fix: wait until changes propagate before updating input selection state ([#16649](https://github.com/sveltejs/svelte/pull/16649)) + +- fix: add "Accept-CH" as valid value for `http-equiv` ([#16671](https://github.com/sveltejs/svelte/pull/16671)) + +## 5.38.3 + +### Patch Changes + +- fix: ensure correct order of template effect values ([#16655](https://github.com/sveltejs/svelte/pull/16655)) + +- fix: allow async `{@const}` in more places ([#16643](https://github.com/sveltejs/svelte/pull/16643)) + +- fix: properly catch top level await errors ([#16619](https://github.com/sveltejs/svelte/pull/16619)) + +- perf: prune effects without dependencies ([#16625](https://github.com/sveltejs/svelte/pull/16625)) + +- fix: only emit `for_await_track_reactivity_loss` in async mode ([#16644](https://github.com/sveltejs/svelte/pull/16644)) + +## 5.38.2 + +### Patch Changes + +- perf: run blocks eagerly during flush instead of aborting ([#16631](https://github.com/sveltejs/svelte/pull/16631)) + +- fix: don't clone non-proxies in `$inspect` ([#16617](https://github.com/sveltejs/svelte/pull/16617)) + +- fix: avoid recursion error when tagging circular references ([#16622](https://github.com/sveltejs/svelte/pull/16622)) + +## 5.38.1 + +### Patch Changes + +- fix: wrap `abort` in `without_reactive_context` ([#16570](https://github.com/sveltejs/svelte/pull/16570)) + +- fix: add `hint` as a possible value for `popover` attribute ([#16581](https://github.com/sveltejs/svelte/pull/16581)) + +- fix: skip effects inside dynamic component that is about to be destroyed ([#16601](https://github.com/sveltejs/svelte/pull/16601)) + +## 5.38.0 + +### Minor Changes + +- feat: allow `await` inside `@const` declarations ([#16542](https://github.com/sveltejs/svelte/pull/16542)) + +### Patch Changes + +- fix: remount at any hydration error ([#16248](https://github.com/sveltejs/svelte/pull/16248)) + +- chore: emit `await_reactivity_loss` in `for await` loops ([#16521](https://github.com/sveltejs/svelte/pull/16521)) + +- fix: emit `snippet_invalid_export` instead of `undefined_export` for exported snippets ([#16539](https://github.com/sveltejs/svelte/pull/16539)) + +## 5.37.3 + +### Patch Changes + +- fix: reset attribute cache after setting corresponding property ([#16543](https://github.com/sveltejs/svelte/pull/16543)) + +## 5.37.2 + +### Patch Changes + +- fix: double event processing in firefox due to event object being garbage collected ([#16527](https://github.com/sveltejs/svelte/pull/16527)) + +- fix: add bindable dimension attributes types to SVG and MathML elements ([#16525](https://github.com/sveltejs/svelte/pull/16525)) + +- fix: correctly differentiate static fields before emitting `duplicate_class_field` ([#16526](https://github.com/sveltejs/svelte/pull/16526)) + +- fix: prevent last_propagated_event from being DCE'd ([#16538](https://github.com/sveltejs/svelte/pull/16538)) + +## 5.37.1 + +### Patch Changes + +- chore: remove some todos ([#16515](https://github.com/sveltejs/svelte/pull/16515)) + +- fix: allow await expressions inside `{#await ...}` argument ([#16514](https://github.com/sveltejs/svelte/pull/16514)) + +- fix: `append_styles` in an effect to make them available on mount ([#16509](https://github.com/sveltejs/svelte/pull/16509)) + +- chore: remove `parser.template_untrimmed` ([#16511](https://github.com/sveltejs/svelte/pull/16511)) + +- fix: always inject styles when compiling as a custom element ([#16509](https://github.com/sveltejs/svelte/pull/16509)) + +## 5.37.0 + +### Minor Changes + +- feat: ignore component options in `compileModule` ([#16362](https://github.com/sveltejs/svelte/pull/16362)) + +### Patch Changes + +- fix: always mark props as stateful ([#16504](https://github.com/sveltejs/svelte/pull/16504)) + +## 5.36.17 + +### Patch Changes + +- fix: throw on duplicate class field declarations ([#16502](https://github.com/sveltejs/svelte/pull/16502)) + +- fix: add types for `part` attribute to svg attributes ([#16499](https://github.com/sveltejs/svelte/pull/16499)) + +## 5.36.16 + +### Patch Changes + +- fix: don't update a focused input with values from its own past ([#16491](https://github.com/sveltejs/svelte/pull/16491)) + +- fix: don't destroy effect roots created inside of deriveds ([#16492](https://github.com/sveltejs/svelte/pull/16492)) + +## 5.36.15 + +### Patch Changes + +- fix: preserve dirty status of deferred effects ([#16487](https://github.com/sveltejs/svelte/pull/16487)) + +## 5.36.14 + +### Patch Changes + +- fix: keep input in sync when binding updated via effect ([#16482](https://github.com/sveltejs/svelte/pull/16482)) + +- fix: rename form accept-charset attribute ([#16478](https://github.com/sveltejs/svelte/pull/16478)) + +- fix: prevent infinite async loop ([#16482](https://github.com/sveltejs/svelte/pull/16482)) + +- fix: exclude derived writes from effect abort and rescheduling ([#16482](https://github.com/sveltejs/svelte/pull/16482)) + +## 5.36.13 + +### Patch Changes + +- fix: ensure subscriptions are picked up correctly by deriveds ([#16466](https://github.com/sveltejs/svelte/pull/16466)) + +## 5.36.12 + +### Patch Changes + +- chore: move `capture_signals` to legacy module ([#16456](https://github.com/sveltejs/svelte/pull/16456)) + +## 5.36.11 + +### Patch Changes + +- fix: always mark reactions of deriveds ([#16457](https://github.com/sveltejs/svelte/pull/16457)) + +- fix: add labels to `@const` tags and props ([#16454](https://github.com/sveltejs/svelte/pull/16454)) + +- fix: tag stores for `$inspect.trace()` ([#16452](https://github.com/sveltejs/svelte/pull/16452)) + +## 5.36.10 + +### Patch Changes + +- fix: prevent batches from getting intertwined ([#16446](https://github.com/sveltejs/svelte/pull/16446)) + +## 5.36.9 + +### Patch Changes + +- fix: don't reexecute derived with no dependencies on teardown ([#16438](https://github.com/sveltejs/svelte/pull/16438)) + +- fix: disallow `export { foo as default }` in ` + + + +{#snippet foo()} + {x} +{/snippet} diff --git a/packages/svelte/tests/compiler-errors/test.ts b/packages/svelte/tests/compiler-errors/test.ts index 13b9280dde..b3a2d4af31 100644 --- a/packages/svelte/tests/compiler-errors/test.ts +++ b/packages/svelte/tests/compiler-errors/test.ts @@ -5,6 +5,7 @@ import { suite, type BaseTest } from '../suite'; import { read_file } from '../helpers.js'; interface CompilerErrorTest extends BaseTest { + async?: boolean; error: { code: string; message: string; @@ -29,7 +30,8 @@ const { test, run } = suite((config, cwd) => { try { compile(read_file(`${cwd}/main.svelte`), { - generate: 'client' + generate: 'client', + experimental: { async: config.async ?? false } }); } catch (e) { const error = e as CompileError; diff --git a/packages/svelte/tests/helpers.js b/packages/svelte/tests/helpers.js index 410838829e..7a9640636c 100644 --- a/packages/svelte/tests/helpers.js +++ b/packages/svelte/tests/helpers.js @@ -43,6 +43,7 @@ export function create_deferred() { /** @param {any} [reason] */ let reject = (reason) => {}; + /** @type {Promise} */ const promise = new Promise((f, r) => { resolve = f; reject = r; diff --git a/packages/svelte/tests/hydration/samples/whitespace-at-block-start/Nested.svelte b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/Nested.svelte new file mode 100644 index 0000000000..70bf63ad9d --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/Nested.svelte @@ -0,0 +1 @@ +

nested

\ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_config.js b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_config.js new file mode 100644 index 0000000000..457eeb2201 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + errors: [ + 'Failed to hydrate: ', + new DOMException("Node can't be inserted in a #text parent.", 'HierarchyRequestError') + ] +}); diff --git a/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_expected.html b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_expected.html new file mode 100644 index 0000000000..46f8e8a7ac --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_expected.html @@ -0,0 +1 @@ +

nested

\ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_override.html b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_override.html new file mode 100644 index 0000000000..90ca4ef4b8 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/_override.html @@ -0,0 +1,2 @@ + +

nested

\ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/whitespace-at-block-start/main.svelte b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/main.svelte new file mode 100644 index 0000000000..f1f962b958 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-at-block-start/main.svelte @@ -0,0 +1,7 @@ + + +
+ +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-browser/assert.js b/packages/svelte/tests/runtime-browser/assert.js index 48bde01410..9a294a48c7 100644 --- a/packages/svelte/tests/runtime-browser/assert.js +++ b/packages/svelte/tests/runtime-browser/assert.js @@ -87,15 +87,17 @@ function normalize_html(window, html) { /** @param {any} node */ function normalize_children(node) { // sort attributes - const attributes = Array.from(node.attributes).sort((a, b) => { - return a.name < b.name ? -1 : 1; - }); + const attributes = Array.from(node.attributes).sort( + (/** @type {any} */ a, /** @type {any} */ b) => { + return a.name < b.name ? -1 : 1; + } + ); - attributes.forEach((attr) => { + attributes.forEach((/** @type{any} */ attr) => { node.removeAttribute(attr.name); }); - attributes.forEach((attr) => { + attributes.forEach((/** @type{any} */ attr) => { node.setAttribute(attr.name, attr.value); }); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js new file mode 100644 index 0000000000..99a223492b --- /dev/null +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../assert'; +const tick = () => Promise.resolve(); + +export default test({ + async test({ assert, target }) { + target.innerHTML = ''; + /** @type {any} */ + const el = target.querySelector('custom-element'); + + /** @type {string} */ + let html = ''; + const handle_evt = (e) => (html = e.detail); + el.addEventListener('html', handle_evt); + + await tick(); + await tick(); + await tick(); + + assert.ok(html.includes(' + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/_config.js new file mode 100644 index 0000000000..f6a98b1797 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ target, assert }) { + const input = target.querySelector('input'); + const button = target.querySelector('button'); + + assert.equal(input?.step, 'any'); + + button?.click(); + flushSync(); + assert.equal(input?.step, '10'); + + button?.click(); + flushSync(); + assert.equal(input?.step, 'any'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/main.svelte new file mode 100644 index 0000000000..2921e4e241 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-after-property/main.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/Component.svelte b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/Component.svelte new file mode 100644 index 0000000000..7a54323cb9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/Component.svelte @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/_config.js b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/_config.js new file mode 100644 index 0000000000..2e4a27cf09 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + async test() {} +}); diff --git a/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/main.svelte b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/main.svelte new file mode 100644 index 0000000000..bd326edfb9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/1000-reading-derived-effects/main.svelte @@ -0,0 +1,8 @@ + + +{#each arr} + +{/each} diff --git a/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/_config.js b/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/_config.js new file mode 100644 index 0000000000..2dacf188d7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/_config.js @@ -0,0 +1,12 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ assert, target, errors }) { + const btn = target.querySelector('button'); + flushSync(() => { + btn?.click(); + }); + assert.deepEqual(errors, []); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/main.svelte b/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/main.svelte new file mode 100644 index 0000000000..ebefe38fb2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/abort-signal-derived-set-state/main.svelte @@ -0,0 +1,24 @@ + + +{der} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/async-await/_config.js b/packages/svelte/tests/runtime-runes/samples/async-await/_config.js new file mode 100644 index 0000000000..dda6a7a895 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-await/_config.js @@ -0,0 +1,43 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [reset, one, two, reject] = target.querySelectorAll('button'); + + await tick(); + assert.htmlEqual( + target.innerHTML, + ' waiting' + ); + + one.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ' one_res' + ); + + reset.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ' waiting' + ); + + two.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ' two_res' + ); + + reset.click(); + reject.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ' reject_catch' + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-await/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-await/main.svelte new file mode 100644 index 0000000000..8673e45414 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-await/main.svelte @@ -0,0 +1,22 @@ + + + + + + + + + {#await await deferred.promise + "_res"} + waiting + {:then res} + {res} + {:catch err} + {err}_catch + {/await} + + {#snippet pending()} +

pending

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/_config.js b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/_config.js new file mode 100644 index 0000000000..b0772ad3c0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/_config.js @@ -0,0 +1,37 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, instance }) { + instance.shift(); + await tick(); + + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = '1'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + await tick(); + + assert.htmlEqual(target.innerHTML, `

0

`); + assert.equal(input.value, '1'); + + input.focus(); + input.value = '2'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + await tick(); + + assert.htmlEqual(target.innerHTML, `

0

`); + assert.equal(input.value, '2'); + + instance.shift(); + await tick(); + assert.htmlEqual(target.innerHTML, `

1

`); + assert.equal(input.value, '2'); + + instance.shift(); + await tick(); + assert.htmlEqual(target.innerHTML, `

2

`); + assert.equal(input.value, '2'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte new file mode 100644 index 0000000000..2fc898e654 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused-2/main.svelte @@ -0,0 +1,25 @@ + + + + +

{await push(count)}

+ + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/_config.js b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/_config.js new file mode 100644 index 0000000000..782ae945f9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/_config.js @@ -0,0 +1,26 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = '3'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + await tick(); + + assert.equal(input.value, '3'); + assert.htmlEqual(target.innerHTML, `

3

`); + + input.focus(); + input.value = '1'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + await tick(); + + assert.equal(input.value, '2'); + assert.htmlEqual(target.innerHTML, `

2

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/main.svelte new file mode 100644 index 0000000000..763ce6ebf0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-binding-update-while-focused/main.svelte @@ -0,0 +1,27 @@ + + + +

{await value}

+ + + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-const/_config.js b/packages/svelte/tests/runtime-runes/samples/async-const/_config.js new file mode 100644 index 0000000000..8aeca875f3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-const/_config.js @@ -0,0 +1,12 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `

Loading...

`, + + async test({ assert, target }) { + await tick(); + + assert.htmlEqual(target.innerHTML, `

Hello, world!

5 01234`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-const/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-const/main.svelte new file mode 100644 index 0000000000..7410ff6a6f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-const/main.svelte @@ -0,0 +1,26 @@ + + + + {@const number = await Promise.resolve(5)} + + {#snippet pending()} +

Loading...

+ {/snippet} + + {#snippet greet()} + {@const greeting = await `Hello, ${name}!`} +

{greeting}

+ {number} + {#if number > 4} + {@const length = await number} + {#each { length }, index} + {@const i = await index} + {i} + {/each} + {/if} + {/snippet} + + {@render greet()} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte new file mode 100644 index 0000000000..39112b12a7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte @@ -0,0 +1,13 @@ + + + + +

{count} ** 2 = {squared}

+

{count} ** 3 = {cubed}

diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js new file mode 100644 index 0000000000..d444e8e1d9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js @@ -0,0 +1,31 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + + const [increment] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` + +

1 ** 2 = 1

+

1 ** 3 = 1

+ ` + ); + + increment.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + +

2 ** 2 = 4

+

2 ** 3 = 8

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte new file mode 100644 index 0000000000..c5d8a12a78 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte @@ -0,0 +1,11 @@ + + + + + + {#snippet pending()} +

pending

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js new file mode 100644 index 0000000000..bd0dd753c2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/_config.js @@ -0,0 +1,41 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [increment, pop] = target.querySelectorAll('button'); + + increment.click(); + await tick(); + + pop.click(); + await tick(); + + pop.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

1

+ ` + ); + + increment.click(); + await tick(); + + pop.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + + +

2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte new file mode 100644 index 0000000000..b9f6c26c2a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-reverse-order/main.svelte @@ -0,0 +1,35 @@ + + + + + + + +

{await push()}

+ + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/_config.js b/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/_config.js new file mode 100644 index 0000000000..bab06a203d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/_config.js @@ -0,0 +1,28 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + await tick(); + + const [increment] = target.querySelectorAll('button'); + + assert.deepEqual(logs, [false]); + assert.htmlEqual(target.innerHTML, '

0

'); + + increment.click(); + await tick(); + assert.deepEqual(logs, [false]); + assert.htmlEqual(target.innerHTML, '

1

'); + + increment.click(); + await tick(); + assert.deepEqual(logs, [false, true]); + assert.htmlEqual(target.innerHTML, '

2

'); + + increment.click(); + await tick(); + assert.deepEqual(logs, [false, true]); + assert.htmlEqual(target.innerHTML, '

3

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/main.svelte new file mode 100644 index 0000000000..5305067a5a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-conservative/main.svelte @@ -0,0 +1,17 @@ + + + + +

{await count}

+ + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/_config.js b/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/_config.js new file mode 100644 index 0000000000..c551cc6b8c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/_config.js @@ -0,0 +1,32 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + + const [increment] = target.querySelectorAll('button'); + + increment.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + +

1

+

1

+ ` + ); + + increment.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + +

2

+

2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/main.svelte new file mode 100644 index 0000000000..153fe03f0d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-triggers-await/main.svelte @@ -0,0 +1,24 @@ + + + + +

{JSON.stringify((await data), null, 2)}

+ {#if true} + +

{unrelated}

+ {/if} + + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Bar.svelte b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Bar.svelte new file mode 100644 index 0000000000..f1ac9ab760 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Bar.svelte @@ -0,0 +1,7 @@ + + +

bar: {bar}

diff --git a/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Foo.svelte b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Foo.svelte new file mode 100644 index 0000000000..e2029a3033 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/Foo.svelte @@ -0,0 +1,10 @@ + + +

foo: {foo}

+ + diff --git a/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/_config.js b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/_config.js new file mode 100644 index 0000000000..ca7965bf79 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/_config.js @@ -0,0 +1,42 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [show, resolve] = target.querySelectorAll('button'); + + show.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

pending...

+ ` + ); + + resolve.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

pending...

+ ` + ); + + resolve.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

foo: foo

+

bar: bar

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/main.svelte new file mode 100644 index 0000000000..bd0efaa4f8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-nested-top-level/main.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + {#if show} + + {/if} + + {#if $effect.pending()} +

pending...

+ {/if} + + {#snippet pending()} +

initializing...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/Child.svelte new file mode 100644 index 0000000000..d4d5cf7554 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/Child.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/_config.js b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/_config.js new file mode 100644 index 0000000000..167eee8488 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/_config.js @@ -0,0 +1,22 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + async test({ assert, target, warnings }) { + await tick(); + + const [button] = target.querySelectorAll('button'); + + button.click(); + await tick(); + + assert.htmlEqual(target.innerHTML, ''); + assert.deepEqual(warnings, [ + 'Mutating unbound props (`object`, at Child.svelte:7:23) is strongly discouraged. Consider using `bind:object={...}` in main.svelte (or using a callback) instead' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/main.svelte new file mode 100644 index 0000000000..ae6b43cbb1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-ownership-validation/main.svelte @@ -0,0 +1,13 @@ + + + + + + {#snippet pending()} +

loading...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/_config.js b/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/_config.js new file mode 100644 index 0000000000..bde65a499f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/_config.js @@ -0,0 +1,24 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + html: `

pending

`, + + async test({ assert, target, warnings }) { + await tick(); + assert.htmlEqual(target.innerHTML, '

3

'); + + assert.equal( + warnings[0], + 'Detected reactivity loss when reading `values[1]`. This happens when state is read in an async function after an earlier `await`' + ); + + assert.equal(warnings[1].name, 'TracedAtError'); + + assert.equal(warnings.length, 2); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/main.svelte new file mode 100644 index 0000000000..92a6ec18bc --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-reactivity-loss-for-await/main.svelte @@ -0,0 +1,24 @@ + + + + + + +

{await get_total()}

+ + {#snippet pending()} +

pending

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-redirect/_config.js b/packages/svelte/tests/runtime-runes/samples/async-redirect/_config.js index ebbe642860..fe92977c21 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-redirect/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/async-redirect/_config.js @@ -29,6 +29,7 @@ export default test({

c

+

b or c

` ); @@ -46,6 +47,7 @@ export default test({

b

+

b or c

` ); } diff --git a/packages/svelte/tests/runtime-runes/samples/async-redirect/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-redirect/main.svelte index bf5fdf9ed3..aead1b00e5 100644 --- a/packages/svelte/tests/runtime-runes/samples/async-redirect/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/async-redirect/main.svelte @@ -33,6 +33,10 @@

c

{/if} + {#if route === 'b' || route === 'c'} +

b or c

+ {/if} + {#snippet pending()}

pending...

{/snippet} diff --git a/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/_config.js b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/_config.js new file mode 100644 index 0000000000..c6903c3eed --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/_config.js @@ -0,0 +1,9 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + assert.htmlEqual(target.innerHTML, 'value'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/app.svelte b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/app.svelte new file mode 100644 index 0000000000..27b29cfe50 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/app.svelte @@ -0,0 +1,9 @@ + + +{#snippet valueSnippet()} + {value} +{/snippet} + +{@render valueSnippet()} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/main.svelte new file mode 100644 index 0000000000..c251a5645b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-reference-in-snippet/main.svelte @@ -0,0 +1,8 @@ + + + {#snippet pending()} + {/snippet} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/_config.js b/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/_config.js new file mode 100644 index 0000000000..709b88578f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/_config.js @@ -0,0 +1,9 @@ +import { tick } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + assert.htmlEqual(target.innerHTML, '

foo bar

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/main.svelte new file mode 100644 index 0000000000..2e0ae46f1f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-template-async-sync-mixed/main.svelte @@ -0,0 +1,17 @@ + + + +

{foo()} {await bar()}

+ + {#snippet pending()} +

pending

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/_config.js new file mode 100644 index 0000000000..06437d2e31 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/_config.js @@ -0,0 +1,56 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + + const [a, b, update] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

a

+ ` + ); + + b.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

b

+ ` + ); + + update.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

b

+ ` + ); + + a.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

a

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/main.svelte new file mode 100644 index 0000000000..5fca286a78 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-time-travelling-derived/main.svelte @@ -0,0 +1,26 @@ + + + + + + + + + {#if condition} +

a

+ {:else} +

b

+ {/if} + + {#snippet pending()}{/snippet} +
+ diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/Foo.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/Foo.svelte new file mode 100644 index 0000000000..e8a7c84137 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/Foo.svelte @@ -0,0 +1,8 @@ + + +

{foo} {bar}

diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/_config.js b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/_config.js new file mode 100644 index 0000000000..2c7ffd3952 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/_config.js @@ -0,0 +1,41 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [show, resolve] = target.querySelectorAll('button'); + + show.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

pending...

+ ` + ); + + resolve.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

pending...

+ ` + ); + + resolve.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + + +

foo bar

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/main.svelte new file mode 100644 index 0000000000..bd0efaa4f8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-deriveds/main.svelte @@ -0,0 +1,31 @@ + + + + + + + + + + {#if show} + + {/if} + + {#if $effect.pending()} +

pending...

+ {/if} + + {#snippet pending()} +

initializing...

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/Child.svelte new file mode 100644 index 0000000000..f7ba132ace --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/Child.svelte @@ -0,0 +1,9 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/_config.js b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/_config.js new file mode 100644 index 0000000000..298e33e9a2 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/_config.js @@ -0,0 +1,15 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `

pending

`, + + async test({ assert, target }) { + const [reject] = target.querySelectorAll('button'); + + await tick(); + reject.click(); + await tick(); + assert.htmlEqual(target.innerHTML, '

route: other

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/main.svelte new file mode 100644 index 0000000000..2f461e96c8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested-obsolete/main.svelte @@ -0,0 +1,18 @@ + + + + + + {#if route.current === 'home'} + + {:else} +

route: {route.current}

+ {/if} + + {#snippet pending()} +

pending

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/Child.svelte new file mode 100644 index 0000000000..11c9ebd653 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/Child.svelte @@ -0,0 +1,7 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/_config.js b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/_config.js new file mode 100644 index 0000000000..57005b4112 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/_config.js @@ -0,0 +1,14 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `

pending

`, + + async test({ assert, target }) { + const [reject] = target.querySelectorAll('button'); + + reject.click(); + await tick(); + assert.htmlEqual(target.innerHTML, '

failed

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/main.svelte new file mode 100644 index 0000000000..2fdf4c0d2f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-top-level-error-nested/main.svelte @@ -0,0 +1,18 @@ + + + + + + + + {#snippet pending()} +

pending

+ {/snippet} + + {#snippet failed()} +

failed

+ {/snippet} +
diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js new file mode 100644 index 0000000000..b6371ce11c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: `

a`, + + async test({ assert, target }) { + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = 'ab'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.htmlEqual(target.innerHTML, `

ab`); + assert.equal(input.value, 'ab'); + + input.focus(); + input.value = 'abc'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.htmlEqual(target.innerHTML, `

abc`); + assert.equal(input.value, 'abc'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte new file mode 100644 index 0000000000..7925195ee1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-in-each/main.svelte @@ -0,0 +1,8 @@ + + +{#each array as obj} + obj.value, (value) => array = [{ value }]} /> +

{obj.value}

+{/each} diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/_config.js b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/_config.js new file mode 100644 index 0000000000..7a56c79d71 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = '3'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.equal(input.value, '3'); + assert.htmlEqual(target.innerHTML, `

3

`); + + input.focus(); + input.value = '1'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + flushSync(); + + assert.equal(input.value, '2'); + assert.htmlEqual(target.innerHTML, `

2

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/main.svelte new file mode 100644 index 0000000000..b0597c223b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-2/main.svelte @@ -0,0 +1,21 @@ + + +

{value}

+ diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js new file mode 100644 index 0000000000..0909dee7a8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/_config.js @@ -0,0 +1,30 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + async test({ assert, target }) { + const [input] = target.querySelectorAll('input'); + + input.focus(); + input.value = 'Ab'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + + await tick(); + await tick(); + + assert.equal(input.value, 'AB'); + assert.htmlEqual(target.innerHTML, `

AB

`); + + input.focus(); + input.value = 'ABc'; + input.dispatchEvent(new InputEvent('input', { bubbles: true })); + + await tick(); + await tick(); + + assert.equal(input.value, 'ABC'); + assert.htmlEqual(target.innerHTML, `

ABC

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte new file mode 100644 index 0000000000..b61bfe4e67 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/binding-update-while-focused-3/main.svelte @@ -0,0 +1,6 @@ + + + text, (v) => text = v.toUpperCase()} /> +

{text}

diff --git a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/FlakyComponent.svelte b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/FlakyComponent.svelte similarity index 74% rename from packages/svelte/tests/runtime-runes/samples/const-tag-boundary/FlakyComponent.svelte rename to packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/FlakyComponent.svelte index 8bbec90de4..ea60542af9 100644 --- a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/FlakyComponent.svelte +++ b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/FlakyComponent.svelte @@ -1,3 +1,3 @@ \ No newline at end of file + diff --git a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/_config.js b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/_config.js new file mode 100644 index 0000000000..915bda91f3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + skip_async: true, + html: '

2

', + mode: ['client'], + test({ target, assert }) { + const btn = target.querySelector('button'); + const p = target.querySelector('p'); + + flushSync(() => { + btn?.click(); + }); + + assert.equal(p?.innerHTML, '4'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/main.svelte b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/main.svelte new file mode 100644 index 0000000000..25ea8a3ffc --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary-deprecated-usage/main.svelte @@ -0,0 +1,14 @@ + + + + + + {@const double = test * 2} + {#snippet failed()} +

{double}

+ {/snippet} + +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/_config.js b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/_config.js index 4338969a48..e4ffb4a850 100644 --- a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/_config.js @@ -2,7 +2,7 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ - html: '

2

', + html: '

2

', mode: ['client'], test({ target, assert }) { const btn = target.querySelector('button'); diff --git a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/main.svelte b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/main.svelte index 25ea8a3ffc..9605e12070 100644 --- a/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/const-tag-boundary/main.svelte @@ -1,14 +1,10 @@ - + - {@const double = test * 2} - {#snippet failed()} -

{double}

- {/snippet} - -
\ No newline at end of file + {@const double = count * 2} +

{double}

+
diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js index 7f406d8f0d..3d8917c147 100644 --- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/_config.js @@ -20,5 +20,8 @@ export default test({ const [value1, value2] = target.querySelectorAll('value-element'); assert.equal(value1.shadowRoot?.innerHTML, 'test'); assert.equal(value2.shadowRoot?.innerHTML, 'test'); + + const value_builtin = target.querySelector('div'); + assert.equal(value_builtin?.shadowRoot?.innerHTML, 'test'); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte index 82774f160d..badb8f96c7 100644 --- a/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-attributes/main.svelte @@ -15,6 +15,24 @@ } }); } + if(!customElements.get('value-builtin')) { + customElements.define('value-builtin', class extends HTMLDivElement { + + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + set value(v) { + if (this.__value !== v) { + this.__value = v; + this.shadowRoot.innerHTML = `${v}`; + } + } + }, { + extends: 'div' + }); + } @@ -22,3 +40,4 @@ +
diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/Thing.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/Thing.svelte new file mode 100644 index 0000000000..0a2b139274 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/Thing.svelte @@ -0,0 +1,9 @@ + + +

hello

+ + diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/_config.js b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/_config.js new file mode 100644 index 0000000000..74597504bd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/_config.js @@ -0,0 +1,15 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + async test({ assert, target }) { + const thing = /** @type HTMLElement & { object: { test: true }; } */ ( + target.querySelector('my-thing') + ); + + await tick(); + + assert.include(thing.shadowRoot?.innerHTML, 'red'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/main.svelte b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/main.svelte new file mode 100644 index 0000000000..ba5b788da9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/custom-element-injected-styles/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-loop-3/Child.svelte b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/Child.svelte new file mode 100644 index 0000000000..9bf4db52d6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/Child.svelte @@ -0,0 +1,13 @@ + + +{#if inited} + {@render children()} +{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/effect-loop-3/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/_config.js new file mode 100644 index 0000000000..046c190432 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/_config.js @@ -0,0 +1,12 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [button] = target.querySelectorAll('button'); + + assert.doesNotThrow(() => { + flushSync(() => button.click()); + }); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-loop-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/main.svelte new file mode 100644 index 0000000000..2b3a171798 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-loop-3/main.svelte @@ -0,0 +1,15 @@ + + + + +{#if show} + {#each { length: 1234 } as i} + {i} + {/each} +{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-6/A.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-6/A.svelte index 2e789a0460..22b8ed0f20 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-6/A.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-6/A.svelte @@ -1,11 +1,12 @@ - + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-6/B.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-6/B.svelte index 1fad19bc15..2233961177 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-6/B.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-6/B.svelte @@ -1,7 +1,5 @@ - - - -{#if object?.boolean} - - {@render children(object.boolean)} -{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-6/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-order-6/_config.js index 8f9077e954..91e1569e46 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-6/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-6/_config.js @@ -8,6 +8,6 @@ export default test({ flushSync(() => open.click()); flushSync(() => close.click()); - assert.deepEqual(logs, [true]); + assert.deepEqual(logs, [{ boolean: true, closed: false }]); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-6/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-6/main.svelte index eee487fa13..08f6fc48da 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-6/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-6/main.svelte @@ -1,6 +1,15 @@ @@ -15,9 +24,6 @@
- - {#snippet children(boolean)} - - {/snippet} - - +{#if object} + +{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-7/A.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-7/A.svelte index 54f4869d62..b55c8f4115 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-7/A.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-7/A.svelte @@ -1,9 +1,9 @@ -{boolean} +{boolean} {closed} - + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-7/B.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-7/B.svelte index 2a2e634db1..7b33c342f5 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-7/B.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-7/B.svelte @@ -1,7 +1,5 @@ - - - -{#if object?.nested} - - {@render children(object.nested)} -{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-7/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-order-7/_config.js index 29c33c7b18..f0a9c2e867 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-7/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-7/_config.js @@ -2,14 +2,18 @@ import { flushSync } from 'svelte'; import { test } from '../../test'; export default test({ - skip: true, + // For this to work in non-async mode, we would need to abort + // inside `#traverse_effect_tree`, which would be very + // complicated and annoying. Since this hasn't been + // a real issue (AFAICT), we ignore it + skip_no_async: true, - async test({ assert, target, logs }) { + async test({ target }) { const [open, close] = target.querySelectorAll('button'); flushSync(() => open.click()); - flushSync(() => close.click()); - assert.deepEqual(logs, [true]); + // if the effect queue isn't aborted after the state change, this will throw + flushSync(() => close.click()); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-order-7/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-order-7/main.svelte index c9c45c50cf..d9e9eb17ad 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-order-7/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-order-7/main.svelte @@ -1,6 +1,15 @@ @@ -15,8 +24,6 @@
- - {#snippet children(nested)} -
- {/snippet} - +{#if object} + +{/if} diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte new file mode 100644 index 0000000000..44447e4f36 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/Child.svelte @@ -0,0 +1,7 @@ + + +{text} diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js new file mode 100644 index 0000000000..ec8858b2c6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/_config.js @@ -0,0 +1,12 @@ +import { async_mode } from '../../../helpers'; +import { test } from '../../test'; + +export default test({ + // In legacy mode this succeeds and logs 'hello' + // In async mode this throws an error because flushSync is called inside an effect + async test({ assert, target, logs }) { + assert.htmlEqual(target.innerHTML, `
hello
`); + assert.deepEqual(logs, ['hello']); + }, + runtime_error: async_mode ? 'flush_sync_in_effect' : undefined +}); diff --git a/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte new file mode 100644 index 0000000000..bef820376b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/flush-sync-inside-attachment/main.svelte @@ -0,0 +1,13 @@ + + + + +
{ + mount(Child, { target, props: { text: 'hello' } }); + flushSync(); +}}>
diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/main.svelte index f7874d2192..23a1c237c3 100644 --- a/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/inspect-recursive-2/main.svelte @@ -1,21 +1,15 @@ \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/_config.js new file mode 100644 index 0000000000..4e16c0cf2a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/_config.js @@ -0,0 +1,30 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { normalise_trace_logs } from '../../../helpers.js'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, target, logs }) { + assert.deepEqual(normalise_trace_logs(logs), [ + { log: 'effect' }, + { log: 'store', highlighted: true }, + { log: '$count', highlighted: false }, + { log: 0 } + ]); + + logs.length = 0; + + const [button] = target.querySelectorAll('button'); + flushSync(() => button.click()); + + assert.deepEqual(normalise_trace_logs(logs), [ + { log: 'effect' }, + { log: 'store', highlighted: true }, + { log: '$count', highlighted: false }, + { log: 1 } + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/main.svelte new file mode 100644 index 0000000000..af57513365 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-trace-store/main.svelte @@ -0,0 +1,14 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js new file mode 100644 index 0000000000..6b281f04f0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/_config.js @@ -0,0 +1,15 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client'], + + test({ assert, target }) { + const btn = target.querySelector('button'); + + assert.htmlEqual(target.innerHTML, ` Inner: 0 Inner: 0`); + btn?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ` Inner: 1 Inner: 1`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte new file mode 100644 index 0000000000..6bde0a15a8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/inner.svelte @@ -0,0 +1,4 @@ + +Inner: {getter()} diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte new file mode 100644 index 0000000000..2cb2f67b82 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/main.svelte @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte new file mode 100644 index 0000000000..525494ddfb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte new file mode 100644 index 0000000000..9498f432d8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-default-value-function/wrapper2.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/store-inside-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/store-inside-derived/_config.js new file mode 100644 index 0000000000..de078b1e75 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-inside-derived/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test: ({ assert, target }) => { + const [loading, increment] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` +
$value: 0
+
valueFromStore.current: 0
+
valueDerivedCurrent: 0
+ + + ` + ); + + loading.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
$value: Loading...
+
valueFromStore.current: Loading...
+
valueDerivedCurrent: Loading...
+ + + ` + ); + + increment.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
$value: 1
+
valueFromStore.current: 1
+
valueDerivedCurrent: 1
+ + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/store-inside-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/store-inside-derived/main.svelte new file mode 100644 index 0000000000..06d0a0d4b4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/store-inside-derived/main.svelte @@ -0,0 +1,36 @@ + + +
+ $value: {isLoading ? 'Loading...' : $value} +
+ +
+ valueFromStore.current: {isLoading ? 'Loading...' : valueFromStore.current} +
+ +
+ valueDerivedCurrent: {isLoading ? 'Loading...' : valueDerivedCurrent} +
+ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte new file mode 100644 index 0000000000..fdafa27c3c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-1.svelte @@ -0,0 +1,7 @@ + + +{#each data.obj.arr as i} +

{i}

+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte new file mode 100644 index 0000000000..e345a7697c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/Comp-2.svelte @@ -0,0 +1 @@ +

Comp 2

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js new file mode 100644 index 0000000000..ff5ca12dbf --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/_config.js @@ -0,0 +1,11 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const [btn] = target.querySelectorAll('button'); + btn.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `

Comp 2

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte new file mode 100644 index 0000000000..abd785fff3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-component-props-update/main.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 32aed75b65..6bdaec9672 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -1428,4 +1428,55 @@ describe('signals', () => { ]); }; }); + + test('$effect.root inside deriveds stay alive independently', () => { + const log: any[] = []; + const c = state(0); + const cleanup: any[] = []; + const inner_states: any[] = []; + + const d = derived(() => { + const destroy = effect_root(() => { + const x = state(0); + inner_states.push(x); + + effect(() => { + log.push('inner ' + $.get(x)); + return () => { + log.push('inner destroyed'); + }; + }); + }); + + cleanup.push(destroy); + + return $.get(c); + }); + + return () => { + log.push($.get(d)); + flushSync(); + + assert.deepEqual(log, [0, 'inner 0']); + log.length = 0; + + set(inner_states[0], 1); + flushSync(); + + assert.deepEqual(log, ['inner destroyed', 'inner 1']); + log.length = 0; + + set(c, 1); + log.push($.get(d)); + flushSync(); + + assert.deepEqual(log, [1, 'inner 0']); + log.length = 0; + + cleanup.forEach((fn) => fn()); + flushSync(); + + assert.deepEqual(log, ['inner destroyed', 'inner destroyed']); + }; + }); }); diff --git a/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json b/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json index b7dd4c8ed4..94b5f191c2 100644 --- a/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json +++ b/packages/svelte/tests/validator/samples/class-state-constructor-9/errors.json @@ -1,14 +1,14 @@ [ { - "code": "state_field_invalid_assignment", - "message": "Cannot assign to a state field before its declaration", + "code": "duplicate_class_field", + "message": "`count` has already been declared", "start": { - "line": 2, - "column": 1 + "line": 5, + "column": 2 }, "end": { - "line": 2, - "column": 12 + "line": 5, + "column": 24 } } ] diff --git a/packages/svelte/tests/validator/samples/class-state-constructor-9/input.svelte.js b/packages/svelte/tests/validator/samples/class-state-constructor-9/input.svelte.js index a8469e13af..3806046f3f 100644 --- a/packages/svelte/tests/validator/samples/class-state-constructor-9/input.svelte.js +++ b/packages/svelte/tests/validator/samples/class-state-constructor-9/input.svelte.js @@ -1,6 +1,6 @@ export class Counter { count = -1; - + static count() {} constructor() { this.count = $state(0); } diff --git a/packages/svelte/tests/validator/samples/const-tag-placement-svelte-boundary/input.svelte b/packages/svelte/tests/validator/samples/const-tag-placement-svelte-boundary/input.svelte index 5708cc36ca..c965a379e5 100644 --- a/packages/svelte/tests/validator/samples/const-tag-placement-svelte-boundary/input.svelte +++ b/packages/svelte/tests/validator/samples/const-tag-placement-svelte-boundary/input.svelte @@ -4,8 +4,6 @@ {@const x = a} - {#snippet failed()} - {x} - {/snippet} + {x} - \ No newline at end of file + diff --git a/packages/svelte/tests/validator/samples/default-export-indirect/errors.json b/packages/svelte/tests/validator/samples/default-export-indirect/errors.json new file mode 100644 index 0000000000..6a8b2b3c13 --- /dev/null +++ b/packages/svelte/tests/validator/samples/default-export-indirect/errors.json @@ -0,0 +1,14 @@ +[ + { + "code": "module_illegal_default_export", + "message": "A component cannot have a default export", + "start": { + "line": 3, + "column": 4 + }, + "end": { + "line": 3, + "column": 32 + } + } +] diff --git a/packages/svelte/tests/validator/samples/default-export-indirect/input.svelte b/packages/svelte/tests/validator/samples/default-export-indirect/input.svelte new file mode 100644 index 0000000000..72150edab1 --- /dev/null +++ b/packages/svelte/tests/validator/samples/default-export-indirect/input.svelte @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index e1ac803198..6787ebf665 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1296,7 +1296,17 @@ declare module 'svelte/compiler' { name: string; /** The 'y' in `on:x={y}` */ expression: null | Expression; - modifiers: string[]; + modifiers: Array< + | 'capture' + | 'nonpassive' + | 'once' + | 'passive' + | 'preventDefault' + | 'self' + | 'stopImmediatePropagation' + | 'stopPropagation' + | 'trusted' + >; } /** A `style:` directive */ @@ -3303,7 +3313,7 @@ declare namespace $derived { * * If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted. * - * Does not run during server side rendering. + * Does not run during server-side rendering. * * https://svelte.dev/docs/svelte/$effect * @param fn The function to execute @@ -3350,7 +3360,7 @@ declare namespace $effect { * * If you return a function from the effect, it will be called right before the effect is run again, or when the component is unmounted. * - * Does not run during server side rendering. + * Does not run during server-side rendering. * * https://svelte.dev/docs/svelte/$effect#$effect.pre * @param fn The function to execute diff --git a/playgrounds/sandbox/package.json b/playgrounds/sandbox/package.json index 3ab65ac4b5..f11da983f6 100644 --- a/playgrounds/sandbox/package.json +++ b/playgrounds/sandbox/package.json @@ -11,7 +11,8 @@ "prod": "npm run build && node dist/server/ssr-prod", "preview": "vite preview", "download": "node scripts/download.js", - "hash": "node scripts/hash.js" + "hash": "node scripts/hash.js", + "create-test": "node scripts/create-test.js" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", diff --git a/playgrounds/sandbox/scripts/create-test.js b/playgrounds/sandbox/scripts/create-test.js new file mode 100644 index 0000000000..c733f19419 --- /dev/null +++ b/playgrounds/sandbox/scripts/create-test.js @@ -0,0 +1,155 @@ +// Creates a test from the existing playground. cwd needs to be playground/sandbox +import fs from 'fs'; +import path from 'path'; + +// Get target folder from command line arguments +let target_folder = process.argv[2]; +if (!target_folder) { + console.error( + 'Please provide a target folder as an argument. Example: node create-test.js runtime-runes/my-test' + ); + process.exit(1); +} +if (!target_folder.includes('/')) { + target_folder = 'runtime-runes/' + target_folder; +} +if (!target_folder.startsWith('runtime-')) { + console.error( + 'Target folder must start with "runtime-" (can only convert to these kinds of tests)' + ); + process.exit(1); +} +target_folder = path.join( + path.resolve('../../packages/svelte/tests', target_folder.split('/')[0]), + 'samples', + target_folder.split('/')[1] +); + +const exists = fs.existsSync(target_folder); + +// Check if target folder already exists and ask for confirmation +if (exists) { + console.log(`Target folder "${target_folder}" already exists.`); + process.stdout.write('Do you want to override the existing test? (Y/n): '); + + // Read user input synchronously + const stdin = process.stdin; + stdin.setRawMode(true); + stdin.resume(); + stdin.setEncoding('utf8'); + + const response = await new Promise((resolve) => { + stdin.on('data', (key) => { + stdin.setRawMode(false); + stdin.pause(); + process.stdout.write('\n'); + resolve(key); + }); + }); + + if (response.toLowerCase() === 'n') { + console.log('Operation cancelled.'); + process.exit(0); + } + + // Clear the existing target folder except for _config.js + const files = fs.readdirSync(target_folder); + for (const file of files) { + if (file !== '_config.js') { + const filePath = path.join(target_folder, file); + fs.rmSync(filePath, { recursive: true, force: true }); + } + } +} else { + fs.mkdirSync(target_folder, { recursive: true }); +} + +// Starting file +const app_svelte_path = path.resolve('./src/App.svelte'); +const collected_files = new Set(); +const processed_files = new Set(); + +function collect_imports(file_path) { + if (processed_files.has(file_path) || !fs.existsSync(file_path)) { + return; + } + + processed_files.add(file_path); + collected_files.add(file_path); + + const content = fs.readFileSync(file_path, 'utf8'); + + // Regex to match import statements + const import_regex = /import\s+(?:[^'"]*\s+from\s+)?['"]([^'"]+)['"]/g; + let match; + + while ((match = import_regex.exec(content)) !== null) { + const import_path = match[1]; + + // Skip node_modules imports + if (!import_path.startsWith('.')) { + continue; + } + + // Resolve relative import path + const resolved_path = path.resolve(path.dirname(file_path), import_path); + + // Try different extensions if file doesn't exist + const extensions = ['', '.svelte', '.js', '.ts']; + let actual_path = null; + + for (const ext of extensions) { + const test_path = resolved_path + ext; + if (fs.existsSync(test_path)) { + actual_path = test_path; + break; + } + } + + if (actual_path) { + collect_imports(actual_path); + } + } +} + +// Start collecting from App.svelte +collect_imports(app_svelte_path); + +// Copy collected files to target folder +for (const file_path of collected_files) { + const relative_path = path.relative(path.resolve('./src'), file_path); + let target_path = path.join(target_folder, relative_path); + + // Rename App.svelte to main.svelte + if (path.basename(file_path) === 'App.svelte') { + target_path = path.join(target_folder, path.dirname(relative_path), 'main.svelte'); + } + + // Ensure target directory exists + const target_dir = path.dirname(target_path); + if (!fs.existsSync(target_dir)) { + fs.mkdirSync(target_dir, { recursive: true }); + } + + // Copy file + fs.copyFileSync(file_path, target_path); + console.log(`Copied: ${file_path} -> ${target_path}`); +} + +// Create empty _config.js +if (!exists) { + const config_path = path.join(target_folder, '_config.js'); + fs.writeFileSync( + config_path, + `import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + } +}); +` + ); + console.log(`Created: ${config_path}`); +} + +console.log(`\nTest files created in: ${target_folder}`); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 315d699e25..cad5fefdf8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,9 +62,9 @@ importers: packages/svelte: dependencies: - '@ampproject/remapping': - specifier: ^2.3.0 - version: 2.3.0 + '@jridgewell/remapping': + specifier: ^2.3.4 + version: 2.3.4 '@jridgewell/sourcemap-codec': specifier: ^1.5.0 version: 1.5.0 @@ -457,6 +457,9 @@ packages: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.4': + resolution: {integrity: sha512-aG+WvAz17rhbzhKNkSeMLgbkPPK82ovXdONvmucbGhUqcroRFLLVhoGAk4xEI17gHpXgNX3sr0/B1ybRUsbEWw==} + '@jridgewell/resolve-uri@3.1.1': resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} @@ -2777,6 +2780,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/remapping@2.3.4': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/resolve-uri@3.1.1': {} '@jridgewell/set-array@1.2.1': {} diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000000..442cd7892c --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,8 @@ +// we need this so the VS Code extension doesn't yell at us +export default { + compilerOptions: { + experimental: { + async: true + } + } +};