Merge branch 'main' into opaque-rune

opaque-rune
Dominic Gannaway 9 months ago
commit af44d572b1

@ -1,5 +0,0 @@
---
'svelte': patch
---
fix: always run `if` block code the first time

@ -23,8 +23,6 @@ Iterating over values can be done with an each block. The values in question can
</ul>
```
You can use each blocks to iterate over any array or array-like value — that is, any object with a `length` property.
An each block can also specify an _index_, equivalent to the second argument in an `array.map(...)` callback:
```svelte

@ -12,10 +12,34 @@ The general syntax is `bind:property={expression}`, where `expression` is an _lv
<input bind:value />
```
Svelte creates an event listener that updates the bound value. If an element already has a listener for the same event, that listener will be fired before the bound value is updated.
Most bindings are _two-way_, meaning that changes to the value will affect the element and vice versa. A few bindings are _readonly_, meaning that changing their value will have no effect on the element.
## Function bindings
You can also use `bind:property={get, set}`, where `get` and `set` are functions, allowing you to perform validation and transformation:
```svelte
<input bind:value={
() => value,
(v) => value = v.toLowerCase()}
/>
```
In the case of readonly bindings like [dimension bindings](#Dimensions), the `get` value should be `null`:
```svelte
<div
bind:clientWidth={null, redraw}
bind:clientHeight={null, redraw}
>...</div>
```
> [!NOTE]
> Function bindings are available in Svelte 5.9.0 and newer.
## `<input bind:value>`
A `bind:value` directive on an `<input>` element binds the input's `value` property:

@ -66,6 +66,31 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
```
Certain attributes like `src` on an `<img>` element will not be repaired during hydration, i.e. the server value will be kept. That's because updating these attributes can cause the image to be refetched (or in the case of an `<iframe>`, for the frame to be reloaded), even if they resolve to the same resource.
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
```svelte
<script>
let { src } = $props();
if (typeof window !== 'undefined') {
// stash the value...
const initial = src;
// unset it...
src = undefined;
$effect(() => {
// ...and reset after we've mounted
src = initial;
});
}
</script>
<img {src} />
```
### hydration_html_changed
```
@ -76,6 +101,31 @@ The value of an `{@html ...}` block changed between server and client renders. T
The value of an `{@html ...}` block %location% changed between server and client renders. The client value will be ignored in favour of the server value
```
If the `{@html ...}` value changes between the server and the client, it will not be repaired during hydration, i.e. the server value will be kept. That's because change detection during hydration is expensive and usually unnecessary.
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
```svelte
<script>
let { markup } = $props();
if (typeof window !== 'undefined') {
// stash the value...
const initial = markup;
// unset it...
markup = undefined;
$effect(() => {
// ...and reset after we've mounted
markup = initial;
});
}
</script>
{@html markup}
```
### hydration_mismatch
```
@ -86,6 +136,10 @@ Hydration failed because the initial UI does not match what was rendered on the
Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location%
```
This warning is thrown when Svelte encounters an error while hydrating the HTML from the server. During hydration, Svelte walks the DOM, expecting a certain structure. If that structure is different (for example because the HTML was repaired by the DOM because of invalid HTML), then Svelte will run into issues, resulting in this warning.
During development, this error is often preceeded by a `console.error` detailing the offending HTML, which needs fixing.
### invalid_raw_snippet_render
```
@ -110,6 +164,10 @@ Tried to unmount a component that was not mounted
%parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent%
```
Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown.
To fix it, `bind:` to the value instead of just passing a property (i.e. in this example do `<Parent bind:value />`).
### ownership_invalid_mutation
```
@ -120,6 +178,32 @@ Mutating a value outside the component that created it is strongly discouraged.
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
```
Consider the following code:
```svelte
<!--- file: App.svelte --->
<script>
import Child from './Child.svelte';
let person = $state({ name: 'Florida', surname: 'Man' });
</script>
<Child {person} />
```
```svelte
<!--- file: Child.svelte --->
<script>
let { person } = $props();
</script>
<input bind:value={person.name}>
<input bind:value={person.surname}>
```
`Child` is mutating `person` which is owned by `App` without being explicitly "allowed" to do so. This is strongly discouraged since it can create code that is hard to reason about at scale ("who mutated this value?"), hence the warning.
To fix it, either create callback props to communicate changes, or mark `person` as [`$bindable`]($bindable).
### reactive_declaration_non_reactive_property
```

@ -78,10 +78,16 @@ Sequence expressions are not allowed as attribute/directive values in runes mode
Attribute values containing `{...}` must be enclosed in quote marks, unless the value only contains the expression
```
### bind_group_invalid_expression
```
`bind:group` can only bind to an Identifier or MemberExpression
```
### bind_invalid_expression
```
Can only bind to an Identifier or MemberExpression
Can only bind to an Identifier or MemberExpression or a `{get, set}` pair
```
### bind_invalid_name
@ -94,6 +100,12 @@ Can only bind to an Identifier or MemberExpression
`bind:%name%` is not a valid binding. %explanation%
```
### bind_invalid_parens
```
`bind:%name%={get, set}` must not have surrounding parentheses
```
### bind_invalid_target
```

@ -610,6 +610,20 @@ Empty block
Unused CSS selector "%name%"
```
Svelte traverses both the template and the `<style>` tag to find out which of the CSS selectors are not used within the template, so it can remove them.
In some situations a selector may target an element that is not 'visible' to the compiler, for example because it is part of an `{@html ...}` tag or you're overriding styles in a child component. In these cases, use [`:global`](/docs/svelte/global-styles) to preserve the selector as-is:
```svelte
<div class="post">{@html content}</div>
<style>
.post :global {
p {...}
}
</style>
```
### element_invalid_self_closing_tag
```
@ -622,6 +636,8 @@ Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...>
Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead
```
See [the migration guide](v5-migration-guide#Event-changes) for more info.
### export_let_unused
```
@ -640,6 +656,8 @@ Component has unused export property '%name%'. If it is for external reference o
Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead.
```
See the [migration guide](v5-migration-guide#Components-are-no-longer-classes) for more info.
### node_invalid_placement_ssr
```
@ -660,6 +678,30 @@ This code will work when the component is rendered on the client (which is why t
`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
```
This warning is thrown when the compiler detects the following:
- a variable was declared without `$state` or `$state.raw`
- the variable is reassigned
- the variable is read in a reactive context
In this case, changing the value will not correctly trigger updates. Example:
```svelte
<script>
let reactive = $state('reactive');
let stale = 'stale';
</script>
<p>This value updates: {reactive}</p>
<p>This value does not update: {stale}</p>
<button onclick={() => {
stale = 'updated';
reactive = 'updated';
}}>update</button>
```
To fix this, wrap your variable declaration with `$state`.
### options_deprecated_accessors
```
@ -732,6 +774,12 @@ Reassignments of module-level declarations will not cause reactive statements to
`context="module"` is deprecated, use the `module` attribute instead
```
```svelte
<script ---context="module"--- +++context+++>
let foo = 'bar';
</script>
```
### script_unknown_attribute
```
@ -744,12 +792,79 @@ Unrecognized attribute — should be one of `generics`, `lang` or `module`. If t
Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead
```
See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info.
### state_referenced_locally
```
State referenced in its own scope will never update. Did you mean to reference it inside a closure?
```
This warning is thrown when the compiler detects the following:
- A reactive variable is declared
- the variable is reassigned
- the variable is referenced inside the same scope it is declared and it is a non-reactive context
In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates:
```svelte
<!--- file: Parent.svelte --->
<script>
import { setContext } from 'svelte';
let count = $state(0);
// warning: state_referenced_locally
setContext('count', count);
</script>
<button onclick={() => count++}>
increment
</button>
```
```svelte
<!--- file: Child.svelte --->
<script>
import { getContext } from 'svelte';
const count = getContext('count');
</script>
<!-- This will never update -->
<p>The count is {count}</p>
```
To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping `count` in a function:
```svelte
<!--- file: Parent.svelte --->
<script>
import { setContext } from 'svelte';
let count = $state(0);
setContext('count', +++() => count+++);
</script>
<button onclick={() => count++}>
increment
</button>
```
```svelte
<!--- file: Child.svelte --->
<script>
import { getContext } from 'svelte';
const count = getContext('count');
</script>
<!-- This will update -->
<p>The count is {+++count()+++}</p>
```
For more info, see [Passing state into functions]($state#Passing-state-into-functions).
### store_rune_conflict
```
@ -805,6 +920,8 @@ A derived value may be used in other contexts:
`<svelte:self>` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead
```
See [the note in the docs](legacy-svelte-self) for more info.
### unknown_code
```

@ -5,3 +5,5 @@
```
`%name%(...)` is not available on the server
```
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.

@ -6,12 +6,54 @@
Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead
```
This error would be thrown in a setup like this:
```svelte
<!--- file: Parent.svelte --->
<List {items} let:entry>
<span>{entry}</span>
</List>
```
```svelte
<!--- file: List.svelte --->
<script>
let { items, children } = $props();
</script>
<ul>
{#each items as item}
<li>{@render children(item)}</li>
{/each}
</ul>
```
Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error.
### lifecycle_outside_component
```
`%name%(...)` can only be used during component initialisation
```
Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component.
```svelte
<script>
import { onMount } from 'svelte';
function handleClick() {
// This is wrong
onMount(() => {})
}
// This is correct
onMount(() => {})
</script>
<button onclick={handleClick}>click me</button>
```
### store_invalid_shape
```

@ -6,6 +6,8 @@
`<svelte:element this="%tag%">` is a void element — it cannot have content
```
Elements such as `<input>` cannot have content, any children passed to these elements will be ignored.
### state_snapshot_uncloneable
```
@ -17,3 +19,10 @@ The following properties cannot be cloned with `$state.snapshot` — the return
%properties%
```
`$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable:
```js
const object = $state({ property: 'this is cloneable', window })
const snapshot = $state.snapshot(object);
```

@ -1,5 +1,33 @@
# svelte
## 5.10.0
### Minor Changes
- feat: provide links to documentation for errors/warnings ([#14629](https://github.com/sveltejs/svelte/pull/14629))
### Patch Changes
- fix: allow exports with source from script module even if no bind is present ([#14620](https://github.com/sveltejs/svelte/pull/14620))
- fix: deconflict `get_name` for literal class properties ([#14607](https://github.com/sveltejs/svelte/pull/14607))
## 5.9.1
### Patch Changes
- fix: mark subtree dynamic for bind with sequence expressions ([#14626](https://github.com/sveltejs/svelte/pull/14626))
## 5.9.0
### Minor Changes
- feat: add support for bind getters/setters ([#14307](https://github.com/sveltejs/svelte/pull/14307))
### Patch Changes
- fix: always run `if` block code the first time ([#14597](https://github.com/sveltejs/svelte/pull/14597))
## 5.8.1
### Patch Changes

@ -52,18 +52,72 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
> The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
Certain attributes like `src` on an `<img>` element will not be repaired during hydration, i.e. the server value will be kept. That's because updating these attributes can cause the image to be refetched (or in the case of an `<iframe>`, for the frame to be reloaded), even if they resolve to the same resource.
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
```svelte
<script>
let { src } = $props();
if (typeof window !== 'undefined') {
// stash the value...
const initial = src;
// unset it...
src = undefined;
$effect(() => {
// ...and reset after we've mounted
src = initial;
});
}
</script>
<img {src} />
```
## hydration_html_changed
> The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value
> The value of an `{@html ...}` block %location% changed between server and client renders. The client value will be ignored in favour of the server value
If the `{@html ...}` value changes between the server and the client, it will not be repaired during hydration, i.e. the server value will be kept. That's because change detection during hydration is expensive and usually unnecessary.
To fix this, either silence the warning with a [`svelte-ignore`](basic-markup#Comments) comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
```svelte
<script>
let { markup } = $props();
if (typeof window !== 'undefined') {
// stash the value...
const initial = markup;
// unset it...
markup = undefined;
$effect(() => {
// ...and reset after we've mounted
markup = initial;
});
}
</script>
{@html markup}
```
## hydration_mismatch
> Hydration failed because the initial UI does not match what was rendered on the server
> Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location%
This warning is thrown when Svelte encounters an error while hydrating the HTML from the server. During hydration, Svelte walks the DOM, expecting a certain structure. If that structure is different (for example because the HTML was repaired by the DOM because of invalid HTML), then Svelte will run into issues, resulting in this warning.
During development, this error is often preceeded by a `console.error` detailing the offending HTML, which needs fixing.
## invalid_raw_snippet_render
> The `render` function passed to `createRawSnippet` should return HTML for a single element
@ -80,12 +134,42 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
> %parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent%
Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown.
To fix it, `bind:` to the value instead of just passing a property (i.e. in this example do `<Parent bind:value />`).
## ownership_invalid_mutation
> Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
> %component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
Consider the following code:
```svelte
<!--- file: App.svelte --->
<script>
import Child from './Child.svelte';
let person = $state({ name: 'Florida', surname: 'Man' });
</script>
<Child {person} />
```
```svelte
<!--- file: Child.svelte --->
<script>
let { person } = $props();
</script>
<input bind:value={person.name}>
<input bind:value={person.surname}>
```
`Child` is mutating `person` which is owned by `App` without being explicitly "allowed" to do so. This is strongly discouraged since it can create code that is hard to reason about at scale ("who mutated this value?"), hence the warning.
To fix it, either create callback props to communicate changes, or mark `person` as [`$bindable`]($bindable).
## reactive_declaration_non_reactive_property
> A `$:` statement (%location%) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode

@ -50,9 +50,13 @@
> Attribute values containing `{...}` must be enclosed in quote marks, unless the value only contains the expression
## bind_group_invalid_expression
> `bind:group` can only bind to an Identifier or MemberExpression
## bind_invalid_expression
> Can only bind to an Identifier or MemberExpression
> Can only bind to an Identifier or MemberExpression or a `{get, set}` pair
## bind_invalid_name
@ -60,6 +64,10 @@
> `bind:%name%` is not a valid binding. %explanation%
## bind_invalid_parens
> `bind:%name%={get, set}` must not have surrounding parentheses
## bind_invalid_target
> `bind:%name%` can only be used with %elements%

@ -6,10 +6,36 @@
> Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead.
See the [migration guide](v5-migration-guide#Components-are-no-longer-classes) for more info.
## non_reactive_update
> `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
This warning is thrown when the compiler detects the following:
- a variable was declared without `$state` or `$state.raw`
- the variable is reassigned
- the variable is read in a reactive context
In this case, changing the value will not correctly trigger updates. Example:
```svelte
<script>
let reactive = $state('reactive');
let stale = 'stale';
</script>
<p>This value updates: {reactive}</p>
<p>This value does not update: {stale}</p>
<button onclick={() => {
stale = 'updated';
reactive = 'updated';
}}>update</button>
```
To fix this, wrap your variable declaration with `$state`.
## perf_avoid_inline_class
> Avoid 'new class' — instead, declare the class at the top level scope
@ -30,6 +56,71 @@
> State referenced in its own scope will never update. Did you mean to reference it inside a closure?
This warning is thrown when the compiler detects the following:
- A reactive variable is declared
- the variable is reassigned
- the variable is referenced inside the same scope it is declared and it is a non-reactive context
In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates:
```svelte
<!--- file: Parent.svelte --->
<script>
import { setContext } from 'svelte';
let count = $state(0);
// warning: state_referenced_locally
setContext('count', count);
</script>
<button onclick={() => count++}>
increment
</button>
```
```svelte
<!--- file: Child.svelte --->
<script>
import { getContext } from 'svelte';
const count = getContext('count');
</script>
<!-- This will never update -->
<p>The count is {count}</p>
```
To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping `count` in a function:
```svelte
<!--- file: Parent.svelte --->
<script>
import { setContext } from 'svelte';
let count = $state(0);
setContext('count', +++() => count+++);
</script>
<button onclick={() => count++}>
increment
</button>
```
```svelte
<!--- file: Child.svelte --->
<script>
import { getContext } from 'svelte';
const count = getContext('count');
</script>
<!-- This will update -->
<p>The count is {+++count()+++}</p>
```
For more info, see [Passing state into functions]($state#Passing-state-into-functions).
## store_rune_conflict
> It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity

@ -1,3 +1,17 @@
## css_unused_selector
> Unused CSS selector "%name%"
Svelte traverses both the template and the `<style>` tag to find out which of the CSS selectors are not used within the template, so it can remove them.
In some situations a selector may target an element that is not 'visible' to the compiler, for example because it is part of an `{@html ...}` tag or you're overriding styles in a child component. In these cases, use [`:global`](/docs/svelte/global-styles) to preserve the selector as-is:
```svelte
<div class="post">{@html content}</div>
<style>
.post :global {
p {...}
}
</style>
```

@ -38,6 +38,8 @@
> Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead
See [the migration guide](v5-migration-guide#Event-changes) for more info.
## node_invalid_placement_ssr
> %message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning
@ -54,6 +56,12 @@ This code will work when the component is rendered on the client (which is why t
> `context="module"` is deprecated, use the `module` attribute instead
```svelte
<script ---context="module"--- +++context+++>
let foo = 'bar';
</script>
```
## script_unknown_attribute
> Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it
@ -62,6 +70,8 @@ This code will work when the component is rendered on the client (which is why t
> Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead
See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info.
## svelte_component_deprecated
> `<svelte:component>` is deprecated in runes mode — components are dynamic by default
@ -104,3 +114,5 @@ A derived value may be used in other contexts:
## svelte_self_deprecated
> `<svelte:self>` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead
See [the note in the docs](legacy-svelte-self) for more info.

@ -1,3 +1,5 @@
## lifecycle_function_unavailable
> `%name%(...)` is not available on the server
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.

@ -2,10 +2,52 @@
> Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead
This error would be thrown in a setup like this:
```svelte
<!--- file: Parent.svelte --->
<List {items} let:entry>
<span>{entry}</span>
</List>
```
```svelte
<!--- file: List.svelte --->
<script>
let { items, children } = $props();
</script>
<ul>
{#each items as item}
<li>{@render children(item)}</li>
{/each}
</ul>
```
Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error.
## lifecycle_outside_component
> `%name%(...)` can only be used during component initialisation
Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component.
```svelte
<script>
import { onMount } from 'svelte';
function handleClick() {
// This is wrong
onMount(() => {})
}
// This is correct
onMount(() => {})
</script>
<button onclick={handleClick}>click me</button>
```
## store_invalid_shape
> `%name%` is not a store with a `subscribe` method

@ -2,6 +2,8 @@
> `<svelte:element this="%tag%">` is a void element — it cannot have content
Elements such as `<input>` cannot have content, any children passed to these elements will be ignored.
## state_snapshot_uncloneable
> Value cannot be cloned with `$state.snapshot` — the original value was returned
@ -9,3 +11,10 @@
> The following properties cannot be cloned with `$state.snapshot` — the return value contains the originals:
>
> %properties%
`$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable:
```js
const object = $state({ property: 'this is cloneable', window })
const snapshot = $state.snapshot(object);
```

@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
"version": "5.8.1",
"version": "5.10.0",
"type": "module",
"types": "./types/index.d.ts",
"engines": {

@ -339,7 +339,7 @@ function transform(name, dest) {
};
for (let i = 0; i < node.expressions.length; i += 1) {
const q = node.quasis[i + 1];
const q = structuredClone(node.quasis[i + 1]);
const e = node.expressions[i];
if (e.type === 'Literal' && e.value === 'CODE') {
@ -355,10 +355,12 @@ function transform(name, dest) {
}
if (message.type === 'TemplateLiteral') {
quasi.value.raw += message.quasis[0].value.raw + q.value.raw;
out.quasis.push(...message.quasis.slice(1));
out.expressions.push(...message.expressions);
quasi = message.quasis[message.quasis.length - 1];
const m = structuredClone(message);
quasi.value.raw += m.quasis[0].value.raw;
out.quasis.push(...m.quasis.slice(1));
out.expressions.push(...m.expressions);
quasi = m.quasis[m.quasis.length - 1];
quasi.value.raw += q.value.raw;
continue;
}
}

@ -7,11 +7,10 @@ import { DEV } from 'esm-env';
*/
export function CODE(PARAMETER) {
if (DEV) {
const error = new Error(`${'CODE'}\n${MESSAGE}`);
const error = new Error(`${'CODE'}\n${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error('CODE');
throw new Error(`https://svelte.dev/e/${'CODE'}`);
}
}

@ -9,9 +9,12 @@ var normal = 'font-weight: normal';
*/
export function CODE(PARAMETER) {
if (DEV) {
console.warn(`%c[svelte] ${'CODE'}\n%c${MESSAGE}`, bold, normal);
console.warn(
`%c[svelte] ${'CODE'}\n%c${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`,
bold,
normal
);
} else {
// TODO print a link to the documentation
console.warn('CODE');
console.warn(`https://svelte.dev/e/${'CODE'}`);
}
}

@ -56,5 +56,5 @@ function e(node, code, message) {
* @returns {never}
*/
export function CODE(node, PARAMETER) {
e(node, 'CODE', MESSAGE);
e(node, 'CODE', `${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`);
}

@ -47,5 +47,5 @@ export const codes = CODES;
* @param {string} PARAMETER
*/
export function CODE(node, PARAMETER) {
w(node, 'CODE', MESSAGE);
w(node, 'CODE', `${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`);
}

@ -4,7 +4,7 @@
* @returns {never}
*/
export function CODE(PARAMETER) {
const error = new Error(`${'CODE'}\n${MESSAGE}`);
const error = new Error(`${'CODE'}\n${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`);
error.name = 'Svelte error';
throw error;
}

@ -7,11 +7,11 @@ import { DEV } from 'esm-env';
*/
export function CODE(PARAMETER) {
if (DEV) {
const error = new Error(`${'CODE'}\n${MESSAGE}`);
const error = new Error(`${'CODE'}\n${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error('CODE');
throw new Error(`https://svelte.dev/e/${'CODE'}`);
}
}

@ -9,9 +9,13 @@ var normal = 'font-weight: normal';
*/
export function CODE(PARAMETER) {
if (DEV) {
console.warn(`%c[svelte] ${'CODE'}\n%c${MESSAGE}`, bold, normal);
console.warn(
`%c[svelte] ${'CODE'}\n%c${MESSAGE}\nhttps://svelte.dev/e/${'CODE'}`,
bold,
normal
);
} else {
// TODO print a link to the documentation
console.warn('CODE');
console.warn(`https://svelte.dev/e/${'CODE'}`);
}
}

File diff suppressed because it is too large Load Diff

@ -698,7 +698,7 @@ export function analyze_component(root, source, options) {
}
for (const node of analysis.module.ast.body) {
if (node.type === 'ExportNamedDeclaration' && node.specifiers !== null) {
if (node.type === 'ExportNamedDeclaration' && node.specifiers !== null && node.source == null) {
for (const specifier of node.specifiers) {
if (specifier.local.type !== 'Identifier') continue;

@ -11,108 +11,13 @@ import * as w from '../../../warnings.js';
import { binding_properties } from '../../bindings.js';
import fuzzymatch from '../../1-parse/utils/fuzzymatch.js';
import { is_content_editable_binding, is_svg } from '../../../../utils.js';
import { mark_subtree_dynamic } from './shared/fragment.js';
/**
* @param {AST.BindDirective} node
* @param {Context} context
*/
export function BindDirective(node, context) {
validate_no_const_assignment(node, node.expression, context.state.scope, true);
const assignee = node.expression;
const left = object(assignee);
if (left === null) {
e.bind_invalid_expression(node);
}
const binding = context.state.scope.get(left.name);
if (assignee.type === 'Identifier') {
// reassignment
if (
node.name !== 'this' && // bind:this also works for regular variables
(!binding ||
(binding.kind !== 'state' &&
binding.kind !== 'raw_state' &&
binding.kind !== 'prop' &&
binding.kind !== 'bindable_prop' &&
binding.kind !== 'each' &&
binding.kind !== 'store_sub' &&
!binding.updated)) // TODO wut?
) {
e.bind_invalid_value(node.expression);
}
if (context.state.analysis.runes && binding?.kind === 'each') {
e.each_item_invalid_assignment(node);
}
if (binding?.kind === 'snippet') {
e.snippet_parameter_assignment(node);
}
}
if (node.name === 'group') {
if (!binding) {
throw new Error('Cannot find declaration for bind:group');
}
// Traverse the path upwards and find all EachBlocks who are (indirectly) contributing to bind:group,
// i.e. one of their declarations is referenced in the binding. This allows group bindings to work
// correctly when referencing a variable declared in an EachBlock by using the index of the each block
// entries as keys.
const each_blocks = [];
const [keypath, expression_ids] = extract_all_identifiers_from_expression(node.expression);
let ids = expression_ids;
let i = context.path.length;
while (i--) {
const parent = context.path[i];
if (parent.type === 'EachBlock') {
const references = ids.filter((id) => parent.metadata.declarations.has(id.name));
if (references.length > 0) {
parent.metadata.contains_group_binding = true;
each_blocks.push(parent);
ids = ids.filter((id) => !references.includes(id));
ids.push(...extract_all_identifiers_from_expression(parent.expression)[1]);
}
}
}
// The identifiers that make up the binding expression form they key for the binding group.
// If the same identifiers in the same order are used in another bind:group, they will be in the same group.
// (there's an edge case where `bind:group={a[i]}` will be in a different group than `bind:group={a[j]}` even when i == j,
// but this is a limitation of the current static analysis we do; it also never worked in Svelte 4)
const bindings = expression_ids.map((id) => context.state.scope.get(id.name));
let group_name;
outer: for (const [[key, b], group] of context.state.analysis.binding_groups) {
if (b.length !== bindings.length || key !== keypath) continue;
for (let i = 0; i < bindings.length; i++) {
if (bindings[i] !== b[i]) continue outer;
}
group_name = group;
}
if (!group_name) {
group_name = context.state.scope.root.unique('binding_group');
context.state.analysis.binding_groups.set([keypath, bindings], group_name);
}
node.metadata = {
binding_group_name: group_name,
parent_each_blocks: each_blocks
};
}
if (binding?.kind === 'each' && binding.metadata?.inside_rest) {
w.bind_invalid_each_rest(binding.node, binding.node.name);
}
const parent = context.path.at(-1);
if (
@ -218,5 +123,125 @@ export function BindDirective(node, context) {
}
}
// When dealing with bind getters/setters skip the specific binding validation
// Group bindings aren't supported for getter/setters so we don't need to handle
// the metadata
if (node.expression.type === 'SequenceExpression') {
if (node.name === 'group') {
e.bind_group_invalid_expression(node);
}
let i = /** @type {number} */ (node.expression.start);
while (context.state.analysis.source[--i] !== '{') {
if (context.state.analysis.source[i] === '(') {
e.bind_invalid_parens(node, node.name);
}
}
if (node.expression.expressions.length !== 2) {
e.bind_invalid_expression(node);
}
mark_subtree_dynamic(context.path);
return;
}
validate_no_const_assignment(node, node.expression, context.state.scope, true);
const assignee = node.expression;
const left = object(assignee);
if (left === null) {
e.bind_invalid_expression(node);
}
const binding = context.state.scope.get(left.name);
if (assignee.type === 'Identifier') {
// reassignment
if (
node.name !== 'this' && // bind:this also works for regular variables
(!binding ||
(binding.kind !== 'state' &&
binding.kind !== 'raw_state' &&
binding.kind !== 'prop' &&
binding.kind !== 'bindable_prop' &&
binding.kind !== 'each' &&
binding.kind !== 'store_sub' &&
!binding.updated)) // TODO wut?
) {
e.bind_invalid_value(node.expression);
}
if (context.state.analysis.runes && binding?.kind === 'each') {
e.each_item_invalid_assignment(node);
}
if (binding?.kind === 'snippet') {
e.snippet_parameter_assignment(node);
}
}
if (node.name === 'group') {
if (!binding) {
throw new Error('Cannot find declaration for bind:group');
}
// Traverse the path upwards and find all EachBlocks who are (indirectly) contributing to bind:group,
// i.e. one of their declarations is referenced in the binding. This allows group bindings to work
// correctly when referencing a variable declared in an EachBlock by using the index of the each block
// entries as keys.
const each_blocks = [];
const [keypath, expression_ids] = extract_all_identifiers_from_expression(node.expression);
let ids = expression_ids;
let i = context.path.length;
while (i--) {
const parent = context.path[i];
if (parent.type === 'EachBlock') {
const references = ids.filter((id) => parent.metadata.declarations.has(id.name));
if (references.length > 0) {
parent.metadata.contains_group_binding = true;
each_blocks.push(parent);
ids = ids.filter((id) => !references.includes(id));
ids.push(...extract_all_identifiers_from_expression(parent.expression)[1]);
}
}
}
// The identifiers that make up the binding expression form they key for the binding group.
// If the same identifiers in the same order are used in another bind:group, they will be in the same group.
// (there's an edge case where `bind:group={a[i]}` will be in a different group than `bind:group={a[j]}` even when i == j,
// but this is a limitation of the current static analysis we do; it also never worked in Svelte 4)
const bindings = expression_ids.map((id) => context.state.scope.get(id.name));
let group_name;
outer: for (const [[key, b], group] of context.state.analysis.binding_groups) {
if (b.length !== bindings.length || key !== keypath) continue;
for (let i = 0; i < bindings.length; i++) {
if (bindings[i] !== b[i]) continue outer;
}
group_name = group;
}
if (!group_name) {
group_name = context.state.scope.root.unique('binding_group');
context.state.analysis.binding_groups.set([keypath, bindings], group_name);
}
node.metadata = {
binding_group_name: group_name,
parent_each_blocks: each_blocks
};
}
if (binding?.kind === 'each' && binding.metadata?.inside_rest) {
w.bind_invalid_each_rest(binding.node, binding.node.name);
}
context.next();
}

@ -1,4 +1,4 @@
/** @import { CallExpression, Expression, MemberExpression } from 'estree' */
/** @import { CallExpression, Expression, MemberExpression, Pattern } from 'estree' */
/** @import { AST, SvelteNode } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import { dev, is_ignored } from '../../../../state.js';
@ -13,41 +13,50 @@ import { build_bind_this, validate_binding } from './shared/utils.js';
* @param {ComponentContext} context
*/
export function BindDirective(node, context) {
const expression = node.expression;
const expression = /** @type {Expression} */ (context.visit(node.expression));
const property = binding_properties[node.name];
const parent = /** @type {SvelteNode} */ (context.path.at(-1));
if (
dev &&
context.state.analysis.runes &&
expression.type === 'MemberExpression' &&
(node.name !== 'this' ||
context.path.some(
({ type }) =>
type === 'IfBlock' || type === 'EachBlock' || type === 'AwaitBlock' || type === 'KeyBlock'
)) &&
!is_ignored(node, 'binding_property_non_reactive')
) {
validate_binding(
context.state,
node,
/**@type {MemberExpression} */ (context.visit(expression))
);
}
let get, set;
const get = b.thunk(/** @type {Expression} */ (context.visit(expression)));
if (expression.type === 'SequenceExpression') {
[get, set] = expression.expressions;
} else {
if (
dev &&
context.state.analysis.runes &&
expression.type === 'MemberExpression' &&
(node.name !== 'this' ||
context.path.some(
({ type }) =>
type === 'IfBlock' ||
type === 'EachBlock' ||
type === 'AwaitBlock' ||
type === 'KeyBlock'
)) &&
!is_ignored(node, 'binding_property_non_reactive')
) {
validate_binding(context.state, node, expression);
}
/** @type {Expression | undefined} */
let set = b.unthunk(
b.arrow(
[b.id('$$value')],
/** @type {Expression} */ (context.visit(b.assignment('=', expression, b.id('$$value'))))
)
);
get = b.thunk(expression);
if (get === set) {
set = undefined;
/** @type {Expression | undefined} */
set = b.unthunk(
b.arrow(
[b.id('$$value')],
/** @type {Expression} */ (
context.visit(
b.assignment('=', /** @type {Pattern} */ (node.expression), b.id('$$value'))
)
)
)
);
if (get === set) {
set = undefined;
}
}
/** @type {CallExpression} */
@ -162,7 +171,7 @@ export function BindDirective(node, context) {
break;
case 'this':
call = build_bind_this(expression, context.state.node, context);
call = build_bind_this(node.expression, context.state.node, context);
break;
case 'textContent':
@ -213,10 +222,7 @@ export function BindDirective(node, context) {
if (value !== undefined) {
group_getter = b.thunk(
b.block([
b.stmt(build_attribute_value(value, context).value),
b.return(/** @type {Expression} */ (context.visit(expression)))
])
b.block([b.stmt(build_attribute_value(value, context).value), b.return(expression)])
);
}
}

@ -23,6 +23,9 @@ export function ClassBody(node, context) {
/** @type {Map<string, StateField>} */
const private_state = new Map();
/** @type {Map<(MethodDefinition|PropertyDefinition)["key"], string>} */
const definition_names = new Map();
/** @type {string[]} */
const private_ids = [];
@ -34,9 +37,12 @@ export function ClassBody(node, context) {
definition.key.type === 'Literal')
) {
const type = definition.key.type;
const name = get_name(definition.key);
const name = get_name(definition.key, public_state);
if (!name) continue;
// we store the deconflicted name in the map so that we can access it later
definition_names.set(definition.key, name);
const is_private = type === 'PrivateIdentifier';
if (is_private) private_ids.push(name);
@ -96,7 +102,7 @@ export function ClassBody(node, context) {
definition.key.type === 'PrivateIdentifier' ||
definition.key.type === 'Literal')
) {
const name = get_name(definition.key);
const name = definition_names.get(definition.key);
if (!name) continue;
const is_private = definition.key.type === 'PrivateIdentifier';
@ -210,10 +216,20 @@ export function ClassBody(node, context) {
/**
* @param {Identifier | PrivateIdentifier | Literal} node
* @param {Map<string, StateField>} public_state
*/
function get_name(node) {
function get_name(node, public_state) {
if (node.type === 'Literal') {
return node.value?.toString().replace(regex_invalid_identifier_chars, '_');
let name = node.value?.toString().replace(regex_invalid_identifier_chars, '_');
// the above could generate conflicts because it has to generate a valid identifier
// so stuff like `0` and `1` or `state%` and `state^` will result in the same string
// so we have to de-conflict. We can only check `public_state` because private state
// can't have literal keys
while (name && public_state.has(name)) {
name = '_' + name;
}
return name;
} else {
return node.name;
}

@ -450,6 +450,11 @@ function setup_select_synchronization(value_binding, context) {
if (context.state.analysis.runes) return;
let bound = value_binding.expression;
if (bound.type === 'SequenceExpression') {
return;
}
while (bound.type === 'MemberExpression') {
bound = /** @type {Identifier | MemberExpression} */ (bound.object);
}
@ -484,10 +489,7 @@ function setup_select_synchronization(value_binding, context) {
b.call(
'$.template_effect',
b.thunk(
b.block([
b.stmt(/** @type {Expression} */ (context.visit(value_binding.expression))),
b.stmt(invalidator)
])
b.block([b.stmt(/** @type {Expression} */ (context.visit(bound))), b.stmt(invalidator)])
)
)
)

@ -1,4 +1,4 @@
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Property, Statement } from 'estree' */
/** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
/** @import { AST, TemplateNode } from '#compiler' */
/** @import { ComponentContext } from '../../types.js' */
import { dev, is_ignored } from '../../../../../state.js';
@ -44,7 +44,7 @@ export function build_component(node, component_name, context, anchor = context.
/** @type {Property[]} */
const custom_css_props = [];
/** @type {Identifier | MemberExpression | null} */
/** @type {Identifier | MemberExpression | SequenceExpression | null} */
let bind_this = null;
/** @type {ExpressionStatement[]} */
@ -174,60 +174,83 @@ export function build_component(node, component_name, context, anchor = context.
} else if (attribute.type === 'BindDirective') {
const expression = /** @type {Expression} */ (context.visit(attribute.expression));
if (
dev &&
expression.type === 'MemberExpression' &&
context.state.analysis.runes &&
!is_ignored(node, 'binding_property_non_reactive')
) {
validate_binding(context.state, attribute, expression);
if (dev && attribute.name !== 'this' && attribute.expression.type !== 'SequenceExpression') {
const left = object(attribute.expression);
let binding;
if (left?.type === 'Identifier') {
binding = context.state.scope.get(left.name);
}
// Only run ownership addition on $state fields.
// Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`,
// but that feels so much of an edge case that it doesn't warrant a perf hit for the common case.
if (binding?.kind !== 'derived' && binding?.kind !== 'raw_state') {
binding_initializers.push(
b.stmt(
b.call(
b.id('$.add_owner_effect'),
b.thunk(expression),
b.id(component_name),
is_ignored(node, 'ownership_invalid_binding') && b.true
)
)
);
}
}
if (attribute.name === 'this') {
bind_this = attribute.expression;
if (expression.type === 'SequenceExpression') {
if (attribute.name === 'this') {
bind_this = attribute.expression;
} else {
const [get, set] = expression.expressions;
const get_id = b.id(context.state.scope.generate('bind_get'));
const set_id = b.id(context.state.scope.generate('bind_set'));
context.state.init.push(b.var(get_id, get));
context.state.init.push(b.var(set_id, set));
push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
}
} else {
if (dev) {
const left = object(attribute.expression);
let binding;
if (left?.type === 'Identifier') {
binding = context.state.scope.get(left.name);
}
// Only run ownership addition on $state fields.
// Theoretically someone could create a `$state` while creating `$state.raw` or inside a `$derived.by`,
// but that feels so much of an edge case that it doesn't warrant a perf hit for the common case.
if (binding?.kind !== 'derived' && binding?.kind !== 'raw_state') {
binding_initializers.push(
b.stmt(
b.call(
b.id('$.add_owner_effect'),
b.thunk(expression),
b.id(component_name),
is_ignored(node, 'ownership_invalid_binding') && b.true
)
)
if (
dev &&
expression.type === 'MemberExpression' &&
context.state.analysis.runes &&
!is_ignored(node, 'binding_property_non_reactive')
) {
validate_binding(context.state, attribute, expression);
}
if (attribute.name === 'this') {
bind_this = attribute.expression;
} else {
const is_store_sub =
attribute.expression.type === 'Identifier' &&
context.state.scope.get(attribute.expression.name)?.kind === 'store_sub';
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
if (is_store_sub) {
push_prop(
b.get(attribute.name, [b.stmt(b.call('$.mark_store_binding')), b.return(expression)]),
true
);
} else {
push_prop(b.get(attribute.name, [b.return(expression)]), true);
}
}
const is_store_sub =
attribute.expression.type === 'Identifier' &&
context.state.scope.get(attribute.expression.name)?.kind === 'store_sub';
const assignment = b.assignment(
'=',
/** @type {Pattern} */ (attribute.expression),
b.id('$$value')
);
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
if (is_store_sub) {
push_prop(
b.get(attribute.name, [b.stmt(b.call('$.mark_store_binding')), b.return(expression)]),
b.set(attribute.name, [b.stmt(/** @type {Expression} */ (context.visit(assignment)))]),
true
);
} else {
push_prop(b.get(attribute.name, [b.return(expression)]), true);
}
const assignment = b.assignment('=', attribute.expression, b.id('$$value'));
push_prop(
b.set(attribute.name, [b.stmt(/** @type {Expression} */ (context.visit(assignment)))]),
true
);
}
}
}

@ -1,4 +1,4 @@
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, Statement, Super } from 'estree' */
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, SequenceExpression, Statement, Super } from 'estree' */
/** @import { AST, SvelteNode } from '#compiler' */
/** @import { ComponentClientTransformState } from '../../types' */
import { walk } from 'zimmerframe';
@ -143,11 +143,16 @@ export function build_update_assignment(state, id, init, value, update) {
/**
* Serializes `bind:this` for components and elements.
* @param {Identifier | MemberExpression} expression
* @param {Identifier | MemberExpression | SequenceExpression} expression
* @param {Expression} value
* @param {import('zimmerframe').Context<SvelteNode, ComponentClientTransformState>} context
*/
export function build_bind_this(expression, value, { state, visit }) {
if (expression.type === 'SequenceExpression') {
const [get, set] = /** @type {SequenceExpression} */ (visit(expression)).expressions;
return b.call('$.bind_this', value, set, get);
}
/** @type {Identifier[]} */
const ids = [];
@ -224,6 +229,9 @@ export function build_bind_this(expression, value, { state, visit }) {
* @param {MemberExpression} expression
*/
export function validate_binding(state, binding, expression) {
if (binding.expression.type === 'SequenceExpression') {
return;
}
// If we are referencing a $store.foo then we don't need to add validation
const left = object(binding.expression);
const left_binding = left && state.scope.get(left.name);

@ -1,4 +1,4 @@
/** @import { BlockStatement, Expression, Pattern, Property, Statement } from 'estree' */
/** @import { BlockStatement, Expression, Pattern, Property, SequenceExpression, Statement } from 'estree' */
/** @import { AST, TemplateNode } from '#compiler' */
/** @import { ComponentContext } from '../../types.js' */
import { empty_comment, build_attribute_value } from './utils.js';
@ -92,24 +92,38 @@ export function build_inline_component(node, expression, context) {
const value = build_attribute_value(attribute.value, context, false, true);
push_prop(b.prop('init', b.key(attribute.name), value));
} else if (attribute.type === 'BindDirective' && attribute.name !== 'this') {
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
push_prop(
b.get(attribute.name, [
b.return(/** @type {Expression} */ (context.visit(attribute.expression)))
]),
true
);
push_prop(
b.set(attribute.name, [
b.stmt(
/** @type {Expression} */ (
context.visit(b.assignment('=', attribute.expression, b.id('$$value')))
)
),
b.stmt(b.assignment('=', b.id('$$settled'), b.false))
]),
true
);
if (attribute.expression.type === 'SequenceExpression') {
const [get, set] = /** @type {SequenceExpression} */ (context.visit(attribute.expression))
.expressions;
const get_id = b.id(context.state.scope.generate('bind_get'));
const set_id = b.id(context.state.scope.generate('bind_set'));
context.state.init.push(b.var(get_id, get));
context.state.init.push(b.var(set_id, set));
push_prop(b.get(attribute.name, [b.return(b.call(get_id))]));
push_prop(b.set(attribute.name, [b.stmt(b.call(set_id, b.id('$$value')))]));
} else {
// Delay prop pushes so bindings come at the end, to avoid spreads overwriting them
push_prop(
b.get(attribute.name, [
b.return(/** @type {Expression} */ (context.visit(attribute.expression)))
]),
true
);
push_prop(
b.set(attribute.name, [
b.stmt(
/** @type {Expression} */ (
context.visit(b.assignment('=', attribute.expression, b.id('$$value')))
)
),
b.stmt(b.assignment('=', b.id('$$settled'), b.false))
]),
true
);
}
}
}

@ -110,14 +110,17 @@ export function build_element_attributes(node, context) {
const binding = binding_properties[attribute.name];
if (binding?.omit_in_ssr) continue;
let expression = /** @type {Expression} */ (context.visit(attribute.expression));
if (expression.type === 'SequenceExpression') {
expression = b.call(expression.expressions[0]);
}
if (is_content_editable_binding(attribute.name)) {
content = /** @type {Expression} */ (context.visit(attribute.expression));
content = expression;
} else if (attribute.name === 'value' && node.name === 'textarea') {
content = b.call(
'$.escape',
/** @type {Expression} */ (context.visit(attribute.expression))
);
} else if (attribute.name === 'group') {
content = b.call('$.escape', expression);
} else if (attribute.name === 'group' && attribute.expression.type !== 'SequenceExpression') {
const value_attribute = /** @type {AST.Attribute | undefined} */ (
node.attributes.find((attr) => attr.type === 'Attribute' && attr.name === 'value')
);
@ -130,6 +133,7 @@ export function build_element_attributes(node, context) {
is_text_attribute(attr) &&
attr.value[0].data === 'checkbox'
);
attributes.push(
create_attribute('checked', -1, -1, [
{
@ -159,7 +163,7 @@ export function build_element_attributes(node, context) {
type: 'ExpressionTag',
start: -1,
end: -1,
expression: attribute.expression,
expression,
metadata: {
expression: create_expression_metadata()
}

@ -6,7 +6,8 @@ import type {
Identifier,
MemberExpression,
ObjectExpression,
Pattern
Pattern,
SequenceExpression
} from 'estree';
interface BaseNode {
@ -49,7 +50,7 @@ export interface LegacyBinding extends BaseNode {
/** The 'x' in `bind:x` */
name: string;
/** The y in `bind:x={y}` */
expression: Identifier | MemberExpression;
expression: Identifier | MemberExpression | SequenceExpression;
}
export interface LegacyBody extends BaseElement {

@ -14,7 +14,8 @@ import type {
Pattern,
Program,
ChainExpression,
SimpleCallExpression
SimpleCallExpression,
SequenceExpression
} from 'estree';
import type { Scope } from '../phases/scope';
@ -187,7 +188,7 @@ export namespace AST {
/** The 'x' in `bind:x` */
name: string;
/** The y in `bind:x={y}` */
expression: Identifier | MemberExpression;
expression: Identifier | MemberExpression | SequenceExpression;
/** @internal */
metadata: {
binding_group_name: Identifier;

@ -129,7 +129,7 @@ export const codes = [
* @param {null | NodeLike} node
*/
export function a11y_accesskey(node) {
w(node, "a11y_accesskey", "Avoid using accesskey");
w(node, "a11y_accesskey", `Avoid using accesskey\nhttps://svelte.dev/e/a11y_accesskey`);
}
/**
@ -137,7 +137,7 @@ export function a11y_accesskey(node) {
* @param {null | NodeLike} node
*/
export function a11y_aria_activedescendant_has_tabindex(node) {
w(node, "a11y_aria_activedescendant_has_tabindex", "An element with an aria-activedescendant attribute should have a tabindex value");
w(node, "a11y_aria_activedescendant_has_tabindex", `An element with an aria-activedescendant attribute should have a tabindex value\nhttps://svelte.dev/e/a11y_aria_activedescendant_has_tabindex`);
}
/**
@ -146,7 +146,7 @@ export function a11y_aria_activedescendant_has_tabindex(node) {
* @param {string} name
*/
export function a11y_aria_attributes(node, name) {
w(node, "a11y_aria_attributes", `\`<${name}>\` should not have aria-* attributes`);
w(node, "a11y_aria_attributes", `\`<${name}>\` should not have aria-* attributes\nhttps://svelte.dev/e/a11y_aria_attributes`);
}
/**
@ -156,7 +156,7 @@ export function a11y_aria_attributes(node, name) {
* @param {string} type
*/
export function a11y_autocomplete_valid(node, value, type) {
w(node, "a11y_autocomplete_valid", `'${value}' is an invalid value for 'autocomplete' on \`<input type="${type}">\``);
w(node, "a11y_autocomplete_valid", `'${value}' is an invalid value for 'autocomplete' on \`<input type="${type}">\`\nhttps://svelte.dev/e/a11y_autocomplete_valid`);
}
/**
@ -164,7 +164,7 @@ export function a11y_autocomplete_valid(node, value, type) {
* @param {null | NodeLike} node
*/
export function a11y_autofocus(node) {
w(node, "a11y_autofocus", "Avoid using autofocus");
w(node, "a11y_autofocus", `Avoid using autofocus\nhttps://svelte.dev/e/a11y_autofocus`);
}
/**
@ -172,7 +172,7 @@ export function a11y_autofocus(node) {
* @param {null | NodeLike} node
*/
export function a11y_click_events_have_key_events(node) {
w(node, "a11y_click_events_have_key_events", "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as `<button type=\"button\">` or `<a>` might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details");
w(node, "a11y_click_events_have_key_events", `Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as \`<button type="button">\` or \`<a>\` might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details\nhttps://svelte.dev/e/a11y_click_events_have_key_events`);
}
/**
@ -180,7 +180,7 @@ export function a11y_click_events_have_key_events(node) {
* @param {null | NodeLike} node
*/
export function a11y_consider_explicit_label(node) {
w(node, "a11y_consider_explicit_label", "Buttons and links should either contain text or have an `aria-label` or `aria-labelledby` attribute");
w(node, "a11y_consider_explicit_label", `Buttons and links should either contain text or have an \`aria-label\` or \`aria-labelledby\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`);
}
/**
@ -189,7 +189,7 @@ export function a11y_consider_explicit_label(node) {
* @param {string} name
*/
export function a11y_distracting_elements(node, name) {
w(node, "a11y_distracting_elements", `Avoid \`<${name}>\` elements`);
w(node, "a11y_distracting_elements", `Avoid \`<${name}>\` elements\nhttps://svelte.dev/e/a11y_distracting_elements`);
}
/**
@ -197,7 +197,7 @@ export function a11y_distracting_elements(node, name) {
* @param {null | NodeLike} node
*/
export function a11y_figcaption_index(node) {
w(node, "a11y_figcaption_index", "`<figcaption>` must be first or last child of `<figure>`");
w(node, "a11y_figcaption_index", `\`<figcaption>\` must be first or last child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_index`);
}
/**
@ -205,7 +205,7 @@ export function a11y_figcaption_index(node) {
* @param {null | NodeLike} node
*/
export function a11y_figcaption_parent(node) {
w(node, "a11y_figcaption_parent", "`<figcaption>` must be an immediate child of `<figure>`");
w(node, "a11y_figcaption_parent", `\`<figcaption>\` must be an immediate child of \`<figure>\`\nhttps://svelte.dev/e/a11y_figcaption_parent`);
}
/**
@ -214,7 +214,7 @@ export function a11y_figcaption_parent(node) {
* @param {string} name
*/
export function a11y_hidden(node, name) {
w(node, "a11y_hidden", `\`<${name}>\` element should not be hidden`);
w(node, "a11y_hidden", `\`<${name}>\` element should not be hidden\nhttps://svelte.dev/e/a11y_hidden`);
}
/**
@ -222,7 +222,7 @@ export function a11y_hidden(node, name) {
* @param {null | NodeLike} node
*/
export function a11y_img_redundant_alt(node) {
w(node, "a11y_img_redundant_alt", "Screenreaders already announce `<img>` elements as an image");
w(node, "a11y_img_redundant_alt", `Screenreaders already announce \`<img>\` elements as an image\nhttps://svelte.dev/e/a11y_img_redundant_alt`);
}
/**
@ -232,7 +232,7 @@ export function a11y_img_redundant_alt(node) {
* @param {string} type
*/
export function a11y_incorrect_aria_attribute_type(node, attribute, type) {
w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be a ${type}`);
w(node, "a11y_incorrect_aria_attribute_type", `The value of '${attribute}' must be a ${type}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type`);
}
/**
@ -241,7 +241,7 @@ export function a11y_incorrect_aria_attribute_type(node, attribute, type) {
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'. It cannot be empty`);
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'. It cannot be empty\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_boolean`);
}
/**
@ -250,7 +250,7 @@ export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_id(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID`);
w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_id`);
}
/**
@ -259,7 +259,7 @@ export function a11y_incorrect_aria_attribute_type_id(node, attribute) {
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`);
w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_idlist`);
}
/**
@ -268,7 +268,7 @@ export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) {
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_integer(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer`);
w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_integer`);
}
/**
@ -278,7 +278,7 @@ export function a11y_incorrect_aria_attribute_type_integer(node, attribute) {
* @param {string} values
*/
export function a11y_incorrect_aria_attribute_type_token(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}`);
w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_token`);
}
/**
@ -288,7 +288,7 @@ export function a11y_incorrect_aria_attribute_type_token(node, attribute, values
* @param {string} values
*/
export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}`);
w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tokenlist`);
}
/**
@ -297,7 +297,7 @@ export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, va
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed`);
w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed\nhttps://svelte.dev/e/a11y_incorrect_aria_attribute_type_tristate`);
}
/**
@ -306,7 +306,7 @@ export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) {
* @param {string} role
*/
export function a11y_interactive_supports_focus(node, role) {
w(node, "a11y_interactive_supports_focus", `Elements with the '${role}' interactive role must have a tabindex value`);
w(node, "a11y_interactive_supports_focus", `Elements with the '${role}' interactive role must have a tabindex value\nhttps://svelte.dev/e/a11y_interactive_supports_focus`);
}
/**
@ -316,7 +316,7 @@ export function a11y_interactive_supports_focus(node, role) {
* @param {string} href_attribute
*/
export function a11y_invalid_attribute(node, href_value, href_attribute) {
w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute`);
w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute\nhttps://svelte.dev/e/a11y_invalid_attribute`);
}
/**
@ -324,7 +324,7 @@ export function a11y_invalid_attribute(node, href_value, href_attribute) {
* @param {null | NodeLike} node
*/
export function a11y_label_has_associated_control(node) {
w(node, "a11y_label_has_associated_control", "A form label must be associated with a control");
w(node, "a11y_label_has_associated_control", `A form label must be associated with a control\nhttps://svelte.dev/e/a11y_label_has_associated_control`);
}
/**
@ -332,7 +332,7 @@ export function a11y_label_has_associated_control(node) {
* @param {null | NodeLike} node
*/
export function a11y_media_has_caption(node) {
w(node, "a11y_media_has_caption", "`<video>` elements must have a `<track kind=\"captions\">`");
w(node, "a11y_media_has_caption", `\`<video>\` elements must have a \`<track kind="captions">\`\nhttps://svelte.dev/e/a11y_media_has_caption`);
}
/**
@ -341,7 +341,7 @@ export function a11y_media_has_caption(node) {
* @param {string} name
*/
export function a11y_misplaced_role(node, name) {
w(node, "a11y_misplaced_role", `\`<${name}>\` should not have role attribute`);
w(node, "a11y_misplaced_role", `\`<${name}>\` should not have role attribute\nhttps://svelte.dev/e/a11y_misplaced_role`);
}
/**
@ -349,7 +349,7 @@ export function a11y_misplaced_role(node, name) {
* @param {null | NodeLike} node
*/
export function a11y_misplaced_scope(node) {
w(node, "a11y_misplaced_scope", "The scope attribute should only be used with `<th>` elements");
w(node, "a11y_misplaced_scope", `The scope attribute should only be used with \`<th>\` elements\nhttps://svelte.dev/e/a11y_misplaced_scope`);
}
/**
@ -360,7 +360,7 @@ export function a11y_misplaced_scope(node) {
* @param {string} sequence
*/
export function a11y_missing_attribute(node, name, article, sequence) {
w(node, "a11y_missing_attribute", `\`<${name}>\` element should have ${article} ${sequence} attribute`);
w(node, "a11y_missing_attribute", `\`<${name}>\` element should have ${article} ${sequence} attribute\nhttps://svelte.dev/e/a11y_missing_attribute`);
}
/**
@ -369,7 +369,7 @@ export function a11y_missing_attribute(node, name, article, sequence) {
* @param {string} name
*/
export function a11y_missing_content(node, name) {
w(node, "a11y_missing_content", `\`<${name}>\` element should contain text`);
w(node, "a11y_missing_content", `\`<${name}>\` element should contain text\nhttps://svelte.dev/e/a11y_missing_content`);
}
/**
@ -379,7 +379,7 @@ export function a11y_missing_content(node, name) {
* @param {string} accompanied_by
*/
export function a11y_mouse_events_have_key_events(node, event, accompanied_by) {
w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event`);
w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event\nhttps://svelte.dev/e/a11y_mouse_events_have_key_events`);
}
/**
@ -388,7 +388,7 @@ export function a11y_mouse_events_have_key_events(node, event, accompanied_by) {
* @param {string} role
*/
export function a11y_no_abstract_role(node, role) {
w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden`);
w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden\nhttps://svelte.dev/e/a11y_no_abstract_role`);
}
/**
@ -398,7 +398,7 @@ export function a11y_no_abstract_role(node, role) {
* @param {string} role
*/
export function a11y_no_interactive_element_to_noninteractive_role(node, element, role) {
w(node, "a11y_no_interactive_element_to_noninteractive_role", `\`<${element}>\` cannot have role '${role}'`);
w(node, "a11y_no_interactive_element_to_noninteractive_role", `\`<${element}>\` cannot have role '${role}'\nhttps://svelte.dev/e/a11y_no_interactive_element_to_noninteractive_role`);
}
/**
@ -407,7 +407,7 @@ export function a11y_no_interactive_element_to_noninteractive_role(node, element
* @param {string} element
*/
export function a11y_no_noninteractive_element_interactions(node, element) {
w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element \`<${element}>\` should not be assigned mouse or keyboard event listeners`);
w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element \`<${element}>\` should not be assigned mouse or keyboard event listeners\nhttps://svelte.dev/e/a11y_no_noninteractive_element_interactions`);
}
/**
@ -417,7 +417,7 @@ export function a11y_no_noninteractive_element_interactions(node, element) {
* @param {string} role
*/
export function a11y_no_noninteractive_element_to_interactive_role(node, element, role) {
w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element \`<${element}>\` cannot have interactive role '${role}'`);
w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element \`<${element}>\` cannot have interactive role '${role}'\nhttps://svelte.dev/e/a11y_no_noninteractive_element_to_interactive_role`);
}
/**
@ -425,7 +425,7 @@ export function a11y_no_noninteractive_element_to_interactive_role(node, element
* @param {null | NodeLike} node
*/
export function a11y_no_noninteractive_tabindex(node) {
w(node, "a11y_no_noninteractive_tabindex", "noninteractive element cannot have nonnegative tabIndex value");
w(node, "a11y_no_noninteractive_tabindex", `noninteractive element cannot have nonnegative tabIndex value\nhttps://svelte.dev/e/a11y_no_noninteractive_tabindex`);
}
/**
@ -434,7 +434,7 @@ export function a11y_no_noninteractive_tabindex(node) {
* @param {string} role
*/
export function a11y_no_redundant_roles(node, role) {
w(node, "a11y_no_redundant_roles", `Redundant role '${role}'`);
w(node, "a11y_no_redundant_roles", `Redundant role '${role}'\nhttps://svelte.dev/e/a11y_no_redundant_roles`);
}
/**
@ -444,7 +444,7 @@ export function a11y_no_redundant_roles(node, role) {
* @param {string} handler
*/
export function a11y_no_static_element_interactions(node, element, handler) {
w(node, "a11y_no_static_element_interactions", `\`<${element}>\` with a ${handler} handler must have an ARIA role`);
w(node, "a11y_no_static_element_interactions", `\`<${element}>\` with a ${handler} handler must have an ARIA role\nhttps://svelte.dev/e/a11y_no_static_element_interactions`);
}
/**
@ -452,7 +452,7 @@ export function a11y_no_static_element_interactions(node, element, handler) {
* @param {null | NodeLike} node
*/
export function a11y_positive_tabindex(node) {
w(node, "a11y_positive_tabindex", "Avoid tabindex values above zero");
w(node, "a11y_positive_tabindex", `Avoid tabindex values above zero\nhttps://svelte.dev/e/a11y_positive_tabindex`);
}
/**
@ -462,7 +462,7 @@ export function a11y_positive_tabindex(node) {
* @param {string} props
*/
export function a11y_role_has_required_aria_props(node, role, props) {
w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}`);
w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}\nhttps://svelte.dev/e/a11y_role_has_required_aria_props`);
}
/**
@ -472,7 +472,7 @@ export function a11y_role_has_required_aria_props(node, role, props) {
* @param {string} role
*/
export function a11y_role_supports_aria_props(node, attribute, role) {
w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'`);
w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'\nhttps://svelte.dev/e/a11y_role_supports_aria_props`);
}
/**
@ -483,7 +483,7 @@ export function a11y_role_supports_aria_props(node, attribute, role) {
* @param {string} name
*/
export function a11y_role_supports_aria_props_implicit(node, attribute, role, name) {
w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element \`<${name}>\``);
w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element \`<${name}>\`\nhttps://svelte.dev/e/a11y_role_supports_aria_props_implicit`);
}
/**
@ -493,7 +493,7 @@ export function a11y_role_supports_aria_props_implicit(node, attribute, role, na
* @param {string | undefined | null} [suggestion]
*/
export function a11y_unknown_aria_attribute(node, attribute, suggestion) {
w(node, "a11y_unknown_aria_attribute", suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`);
w(node, "a11y_unknown_aria_attribute", `${suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`}\nhttps://svelte.dev/e/a11y_unknown_aria_attribute`);
}
/**
@ -503,7 +503,7 @@ export function a11y_unknown_aria_attribute(node, attribute, suggestion) {
* @param {string | undefined | null} [suggestion]
*/
export function a11y_unknown_role(node, role, suggestion) {
w(node, "a11y_unknown_role", suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`);
w(node, "a11y_unknown_role", `${suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`}\nhttps://svelte.dev/e/a11y_unknown_role`);
}
/**
@ -513,7 +513,7 @@ export function a11y_unknown_role(node, role, suggestion) {
* @param {string} suggestion
*/
export function legacy_code(node, code, suggestion) {
w(node, "legacy_code", `\`${code}\` is no longer valid — please use \`${suggestion}\` instead`);
w(node, "legacy_code", `\`${code}\` is no longer valid — please use \`${suggestion}\` instead\nhttps://svelte.dev/e/legacy_code`);
}
/**
@ -523,7 +523,7 @@ export function legacy_code(node, code, suggestion) {
* @param {string | undefined | null} [suggestion]
*/
export function unknown_code(node, code, suggestion) {
w(node, "unknown_code", suggestion ? `\`${code}\` is not a recognised code (did you mean \`${suggestion}\`?)` : `\`${code}\` is not a recognised code`);
w(node, "unknown_code", `${suggestion ? `\`${code}\` is not a recognised code (did you mean \`${suggestion}\`?)` : `\`${code}\` is not a recognised code`}\nhttps://svelte.dev/e/unknown_code`);
}
/**
@ -531,7 +531,7 @@ export function unknown_code(node, code, suggestion) {
* @param {null | NodeLike} node
*/
export function options_deprecated_accessors(node) {
w(node, "options_deprecated_accessors", "The `accessors` option has been deprecated. It will have no effect in runes mode");
w(node, "options_deprecated_accessors", `The \`accessors\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_accessors`);
}
/**
@ -539,7 +539,7 @@ export function options_deprecated_accessors(node) {
* @param {null | NodeLike} node
*/
export function options_deprecated_immutable(node) {
w(node, "options_deprecated_immutable", "The `immutable` option has been deprecated. It will have no effect in runes mode");
w(node, "options_deprecated_immutable", `The \`immutable\` option has been deprecated. It will have no effect in runes mode\nhttps://svelte.dev/e/options_deprecated_immutable`);
}
/**
@ -547,7 +547,7 @@ export function options_deprecated_immutable(node) {
* @param {null | NodeLike} node
*/
export function options_missing_custom_element(node) {
w(node, "options_missing_custom_element", "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?");
w(node, "options_missing_custom_element", `The \`customElement\` option is used when generating a custom element. Did you forget the \`customElement: true\` compile option?\nhttps://svelte.dev/e/options_missing_custom_element`);
}
/**
@ -555,7 +555,7 @@ export function options_missing_custom_element(node) {
* @param {null | NodeLike} node
*/
export function options_removed_enable_sourcemap(node) {
w(node, "options_removed_enable_sourcemap", "The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them");
w(node, "options_removed_enable_sourcemap", `The \`enableSourcemap\` option has been removed. Source maps are always generated now, and tooling can choose to ignore them\nhttps://svelte.dev/e/options_removed_enable_sourcemap`);
}
/**
@ -563,7 +563,7 @@ export function options_removed_enable_sourcemap(node) {
* @param {null | NodeLike} node
*/
export function options_removed_hydratable(node) {
w(node, "options_removed_hydratable", "The `hydratable` option has been removed. Svelte components are always hydratable now");
w(node, "options_removed_hydratable", `The \`hydratable\` option has been removed. Svelte components are always hydratable now\nhttps://svelte.dev/e/options_removed_hydratable`);
}
/**
@ -571,7 +571,7 @@ export function options_removed_hydratable(node) {
* @param {null | NodeLike} node
*/
export function options_removed_loop_guard_timeout(node) {
w(node, "options_removed_loop_guard_timeout", "The `loopGuardTimeout` option has been removed");
w(node, "options_removed_loop_guard_timeout", `The \`loopGuardTimeout\` option has been removed\nhttps://svelte.dev/e/options_removed_loop_guard_timeout`);
}
/**
@ -579,7 +579,7 @@ export function options_removed_loop_guard_timeout(node) {
* @param {null | NodeLike} node
*/
export function options_renamed_ssr_dom(node) {
w(node, "options_renamed_ssr_dom", "`generate: \"dom\"` and `generate: \"ssr\"` options have been renamed to \"client\" and \"server\" respectively");
w(node, "options_renamed_ssr_dom", `\`generate: "dom"\` and \`generate: "ssr"\` options have been renamed to "client" and "server" respectively\nhttps://svelte.dev/e/options_renamed_ssr_dom`);
}
/**
@ -588,7 +588,7 @@ export function options_renamed_ssr_dom(node) {
* @param {string} name
*/
export function export_let_unused(node, name) {
w(node, "export_let_unused", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``);
w(node, "export_let_unused", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\`\nhttps://svelte.dev/e/export_let_unused`);
}
/**
@ -596,7 +596,7 @@ export function export_let_unused(node, name) {
* @param {null | NodeLike} node
*/
export function legacy_component_creation(node) {
w(node, "legacy_component_creation", "Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead.");
w(node, "legacy_component_creation", `Svelte 5 components are no longer classes. Instantiate them using \`mount\` or \`hydrate\` (imported from 'svelte') instead.\nhttps://svelte.dev/e/legacy_component_creation`);
}
/**
@ -605,7 +605,7 @@ export function legacy_component_creation(node) {
* @param {string} name
*/
export function non_reactive_update(node, name) {
w(node, "non_reactive_update", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates`);
w(node, "non_reactive_update", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates\nhttps://svelte.dev/e/non_reactive_update`);
}
/**
@ -613,7 +613,7 @@ export function non_reactive_update(node, name) {
* @param {null | NodeLike} node
*/
export function perf_avoid_inline_class(node) {
w(node, "perf_avoid_inline_class", "Avoid 'new class' — instead, declare the class at the top level scope");
w(node, "perf_avoid_inline_class", `Avoid 'new class' — instead, declare the class at the top level scope\nhttps://svelte.dev/e/perf_avoid_inline_class`);
}
/**
@ -621,7 +621,7 @@ export function perf_avoid_inline_class(node) {
* @param {null | NodeLike} node
*/
export function perf_avoid_nested_class(node) {
w(node, "perf_avoid_nested_class", "Avoid declaring classes below the top level scope");
w(node, "perf_avoid_nested_class", `Avoid declaring classes below the top level scope\nhttps://svelte.dev/e/perf_avoid_nested_class`);
}
/**
@ -629,7 +629,7 @@ export function perf_avoid_nested_class(node) {
* @param {null | NodeLike} node
*/
export function reactive_declaration_invalid_placement(node) {
w(node, "reactive_declaration_invalid_placement", "Reactive declarations only exist at the top level of the instance script");
w(node, "reactive_declaration_invalid_placement", `Reactive declarations only exist at the top level of the instance script\nhttps://svelte.dev/e/reactive_declaration_invalid_placement`);
}
/**
@ -637,7 +637,7 @@ export function reactive_declaration_invalid_placement(node) {
* @param {null | NodeLike} node
*/
export function reactive_declaration_module_script_dependency(node) {
w(node, "reactive_declaration_module_script_dependency", "Reassignments of module-level declarations will not cause reactive statements to update");
w(node, "reactive_declaration_module_script_dependency", `Reassignments of module-level declarations will not cause reactive statements to update\nhttps://svelte.dev/e/reactive_declaration_module_script_dependency`);
}
/**
@ -645,7 +645,7 @@ export function reactive_declaration_module_script_dependency(node) {
* @param {null | NodeLike} node
*/
export function state_referenced_locally(node) {
w(node, "state_referenced_locally", "State referenced in its own scope will never update. Did you mean to reference it inside a closure?");
w(node, "state_referenced_locally", `State referenced in its own scope will never update. Did you mean to reference it inside a closure?\nhttps://svelte.dev/e/state_referenced_locally`);
}
/**
@ -654,7 +654,7 @@ export function state_referenced_locally(node) {
* @param {string} name
*/
export function store_rune_conflict(node, name) {
w(node, "store_rune_conflict", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity`);
w(node, "store_rune_conflict", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity\nhttps://svelte.dev/e/store_rune_conflict`);
}
/**
@ -663,7 +663,7 @@ export function store_rune_conflict(node, name) {
* @param {string} name
*/
export function css_unused_selector(node, name) {
w(node, "css_unused_selector", `Unused CSS selector "${name}"`);
w(node, "css_unused_selector", `Unused CSS selector "${name}"\nhttps://svelte.dev/e/css_unused_selector`);
}
/**
@ -671,7 +671,7 @@ export function css_unused_selector(node, name) {
* @param {null | NodeLike} node
*/
export function attribute_avoid_is(node) {
w(node, "attribute_avoid_is", "The \"is\" attribute is not supported cross-browser and should be avoided");
w(node, "attribute_avoid_is", `The "is" attribute is not supported cross-browser and should be avoided\nhttps://svelte.dev/e/attribute_avoid_is`);
}
/**
@ -680,7 +680,7 @@ export function attribute_avoid_is(node) {
* @param {string} name
*/
export function attribute_global_event_reference(node, name) {
w(node, "attribute_global_event_reference", `You are referencing \`globalThis.${name}\`. Did you forget to declare a variable with that name?`);
w(node, "attribute_global_event_reference", `You are referencing \`globalThis.${name}\`. Did you forget to declare a variable with that name?\nhttps://svelte.dev/e/attribute_global_event_reference`);
}
/**
@ -688,7 +688,7 @@ export function attribute_global_event_reference(node, name) {
* @param {null | NodeLike} node
*/
export function attribute_illegal_colon(node) {
w(node, "attribute_illegal_colon", "Attributes should not contain ':' characters to prevent ambiguity with Svelte directives");
w(node, "attribute_illegal_colon", `Attributes should not contain ':' characters to prevent ambiguity with Svelte directives\nhttps://svelte.dev/e/attribute_illegal_colon`);
}
/**
@ -698,7 +698,7 @@ export function attribute_illegal_colon(node) {
* @param {string} right
*/
export function attribute_invalid_property_name(node, wrong, right) {
w(node, "attribute_invalid_property_name", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?`);
w(node, "attribute_invalid_property_name", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?\nhttps://svelte.dev/e/attribute_invalid_property_name`);
}
/**
@ -706,7 +706,7 @@ export function attribute_invalid_property_name(node, wrong, right) {
* @param {null | NodeLike} node
*/
export function attribute_quoted(node) {
w(node, "attribute_quoted", "Quoted attributes on components and custom elements will be stringified in a future version of Svelte. If this isn't what you want, remove the quotes");
w(node, "attribute_quoted", `Quoted attributes on components and custom elements will be stringified in a future version of Svelte. If this isn't what you want, remove the quotes\nhttps://svelte.dev/e/attribute_quoted`);
}
/**
@ -715,7 +715,7 @@ export function attribute_quoted(node) {
* @param {string} name
*/
export function bind_invalid_each_rest(node, name) {
w(node, "bind_invalid_each_rest", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work`);
w(node, "bind_invalid_each_rest", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work\nhttps://svelte.dev/e/bind_invalid_each_rest`);
}
/**
@ -723,7 +723,7 @@ export function bind_invalid_each_rest(node, name) {
* @param {null | NodeLike} node
*/
export function block_empty(node) {
w(node, "block_empty", "Empty block");
w(node, "block_empty", `Empty block\nhttps://svelte.dev/e/block_empty`);
}
/**
@ -732,7 +732,7 @@ export function block_empty(node) {
* @param {string} name
*/
export function component_name_lowercase(node, name) {
w(node, "component_name_lowercase", `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter`);
w(node, "component_name_lowercase", `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter\nhttps://svelte.dev/e/component_name_lowercase`);
}
/**
@ -741,7 +741,7 @@ export function component_name_lowercase(node, name) {
* @param {string} name
*/
export function element_invalid_self_closing_tag(node, name) {
w(node, "element_invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use \`<${name} ...></${name}>\` rather than \`<${name} ... />\``);
w(node, "element_invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use \`<${name} ...></${name}>\` rather than \`<${name} ... />\`\nhttps://svelte.dev/e/element_invalid_self_closing_tag`);
}
/**
@ -750,7 +750,7 @@ export function element_invalid_self_closing_tag(node, name) {
* @param {string} name
*/
export function event_directive_deprecated(node, name) {
w(node, "event_directive_deprecated", `Using \`on:${name}\` to listen to the ${name} event is deprecated. Use the event attribute \`on${name}\` instead`);
w(node, "event_directive_deprecated", `Using \`on:${name}\` to listen to the ${name} event is deprecated. Use the event attribute \`on${name}\` instead\nhttps://svelte.dev/e/event_directive_deprecated`);
}
/**
@ -759,7 +759,7 @@ export function event_directive_deprecated(node, name) {
* @param {string} message
*/
export function node_invalid_placement_ssr(node, message) {
w(node, "node_invalid_placement_ssr", `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning`);
w(node, "node_invalid_placement_ssr", `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a \`hydration_mismatch\` warning\nhttps://svelte.dev/e/node_invalid_placement_ssr`);
}
/**
@ -767,7 +767,7 @@ export function node_invalid_placement_ssr(node, message) {
* @param {null | NodeLike} node
*/
export function script_context_deprecated(node) {
w(node, "script_context_deprecated", "`context=\"module\"` is deprecated, use the `module` attribute instead");
w(node, "script_context_deprecated", `\`context="module"\` is deprecated, use the \`module\` attribute instead\nhttps://svelte.dev/e/script_context_deprecated`);
}
/**
@ -775,7 +775,7 @@ export function script_context_deprecated(node) {
* @param {null | NodeLike} node
*/
export function script_unknown_attribute(node) {
w(node, "script_unknown_attribute", "Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it");
w(node, "script_unknown_attribute", `Unrecognized attribute — should be one of \`generics\`, \`lang\` or \`module\`. If this exists for a preprocessor, ensure that the preprocessor removes it\nhttps://svelte.dev/e/script_unknown_attribute`);
}
/**
@ -783,7 +783,7 @@ export function script_unknown_attribute(node) {
* @param {null | NodeLike} node
*/
export function slot_element_deprecated(node) {
w(node, "slot_element_deprecated", "Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead");
w(node, "slot_element_deprecated", `Using \`<slot>\` to render parent content is deprecated. Use \`{@render ...}\` tags instead\nhttps://svelte.dev/e/slot_element_deprecated`);
}
/**
@ -791,7 +791,7 @@ export function slot_element_deprecated(node) {
* @param {null | NodeLike} node
*/
export function svelte_component_deprecated(node) {
w(node, "svelte_component_deprecated", "`<svelte:component>` is deprecated in runes mode — components are dynamic by default");
w(node, "svelte_component_deprecated", `\`<svelte:component>\` is deprecated in runes mode — components are dynamic by default\nhttps://svelte.dev/e/svelte_component_deprecated`);
}
/**
@ -799,7 +799,7 @@ export function svelte_component_deprecated(node) {
* @param {null | NodeLike} node
*/
export function svelte_element_invalid_this(node) {
w(node, "svelte_element_invalid_this", "`this` should be an `{expression}`. Using a string attribute value will cause an error in future versions of Svelte");
w(node, "svelte_element_invalid_this", `\`this\` should be an \`{expression}\`. Using a string attribute value will cause an error in future versions of Svelte\nhttps://svelte.dev/e/svelte_element_invalid_this`);
}
/**
@ -809,5 +809,5 @@ export function svelte_element_invalid_this(node) {
* @param {string} basename
*/
export function svelte_self_deprecated(node, name, basename) {
w(node, "svelte_self_deprecated", `\`<svelte:self>\` is deprecated — use self-imports (e.g. \`import ${name} from './${basename}'\`) instead`);
w(node, "svelte_self_deprecated", `\`<svelte:self>\` is deprecated — use self-imports (e.g. \`import ${name} from './${basename}'\`) instead\nhttps://svelte.dev/e/svelte_self_deprecated`);
}

@ -8,13 +8,12 @@ import { DEV } from 'esm-env';
*/
export function bind_invalid_checkbox_value() {
if (DEV) {
const error = new Error(`bind_invalid_checkbox_value\nUsing \`bind:value\` together with a checkbox input is not allowed. Use \`bind:checked\` instead`);
const error = new Error(`bind_invalid_checkbox_value\nUsing \`bind:value\` together with a checkbox input is not allowed. Use \`bind:checked\` instead\nhttps://svelte.dev/e/bind_invalid_checkbox_value`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_invalid_checkbox_value");
throw new Error(`https://svelte.dev/e/bind_invalid_checkbox_value`);
}
}
@ -27,13 +26,12 @@ export function bind_invalid_checkbox_value() {
*/
export function bind_invalid_export(component, key, name) {
if (DEV) {
const error = new Error(`bind_invalid_export\nComponent ${component} has an export named \`${key}\` that a consumer component is trying to access using \`bind:${key}\`, which is disallowed. Instead, use \`bind:this\` (e.g. \`<${name} bind:this={component} />\`) and then access the property on the bound component instance (e.g. \`component.${key}\`)`);
const error = new Error(`bind_invalid_export\nComponent ${component} has an export named \`${key}\` that a consumer component is trying to access using \`bind:${key}\`, which is disallowed. Instead, use \`bind:this\` (e.g. \`<${name} bind:this={component} />\`) and then access the property on the bound component instance (e.g. \`component.${key}\`)\nhttps://svelte.dev/e/bind_invalid_export`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_invalid_export");
throw new Error(`https://svelte.dev/e/bind_invalid_export`);
}
}
@ -46,13 +44,12 @@ export function bind_invalid_export(component, key, name) {
*/
export function bind_not_bindable(key, component, name) {
if (DEV) {
const error = new Error(`bind_not_bindable\nA component is attempting to bind to a non-bindable property \`${key}\` belonging to ${component} (i.e. \`<${name} bind:${key}={...}>\`). To mark a property as bindable: \`let { ${key} = $bindable() } = $props()\``);
const error = new Error(`bind_not_bindable\nA component is attempting to bind to a non-bindable property \`${key}\` belonging to ${component} (i.e. \`<${name} bind:${key}={...}>\`). To mark a property as bindable: \`let { ${key} = $bindable() } = $props()\`\nhttps://svelte.dev/e/bind_not_bindable`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_not_bindable");
throw new Error(`https://svelte.dev/e/bind_not_bindable`);
}
}
@ -65,13 +62,12 @@ export function bind_not_bindable(key, component, name) {
*/
export function component_api_changed(parent, method, component) {
if (DEV) {
const error = new Error(`component_api_changed\n${parent} called \`${method}\` on an instance of ${component}, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information`);
const error = new Error(`component_api_changed\n${parent} called \`${method}\` on an instance of ${component}, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information\nhttps://svelte.dev/e/component_api_changed`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("component_api_changed");
throw new Error(`https://svelte.dev/e/component_api_changed`);
}
}
@ -83,13 +79,12 @@ export function component_api_changed(parent, method, component) {
*/
export function component_api_invalid_new(component, name) {
if (DEV) {
const error = new Error(`component_api_invalid_new\nAttempted to instantiate ${component} with \`new ${name}\`, which is no longer valid in Svelte 5. If this component is not under your control, set the \`compatibility.componentApi\` compiler option to \`4\` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information`);
const error = new Error(`component_api_invalid_new\nAttempted to instantiate ${component} with \`new ${name}\`, which is no longer valid in Svelte 5. If this component is not under your control, set the \`compatibility.componentApi\` compiler option to \`4\` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information\nhttps://svelte.dev/e/component_api_invalid_new`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("component_api_invalid_new");
throw new Error(`https://svelte.dev/e/component_api_invalid_new`);
}
}
@ -99,13 +94,12 @@ export function component_api_invalid_new(component, name) {
*/
export function derived_references_self() {
if (DEV) {
const error = new Error(`derived_references_self\nA derived value cannot reference itself recursively`);
const error = new Error(`derived_references_self\nA derived value cannot reference itself recursively\nhttps://svelte.dev/e/derived_references_self`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("derived_references_self");
throw new Error(`https://svelte.dev/e/derived_references_self`);
}
}
@ -118,13 +112,12 @@ export function derived_references_self() {
*/
export function each_key_duplicate(a, b, value) {
if (DEV) {
const error = new Error(`each_key_duplicate\n${value ? `Keyed each block has duplicate key \`${value}\` at indexes ${a} and ${b}` : `Keyed each block has duplicate key at indexes ${a} and ${b}`}`);
const error = new Error(`each_key_duplicate\n${value ? `Keyed each block has duplicate key \`${value}\` at indexes ${a} and ${b}` : `Keyed each block has duplicate key at indexes ${a} and ${b}`}\nhttps://svelte.dev/e/each_key_duplicate`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("each_key_duplicate");
throw new Error(`https://svelte.dev/e/each_key_duplicate`);
}
}
@ -135,13 +128,12 @@ export function each_key_duplicate(a, b, value) {
*/
export function effect_in_teardown(rune) {
if (DEV) {
const error = new Error(`effect_in_teardown\n\`${rune}\` cannot be used inside an effect cleanup function`);
const error = new Error(`effect_in_teardown\n\`${rune}\` cannot be used inside an effect cleanup function\nhttps://svelte.dev/e/effect_in_teardown`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_in_teardown");
throw new Error(`https://svelte.dev/e/effect_in_teardown`);
}
}
@ -151,13 +143,12 @@ export function effect_in_teardown(rune) {
*/
export function effect_in_unowned_derived() {
if (DEV) {
const error = new Error(`effect_in_unowned_derived\nEffect cannot be created inside a \`$derived\` value that was not itself created inside an effect`);
const error = new Error(`effect_in_unowned_derived\nEffect cannot be created inside a \`$derived\` value that was not itself created inside an effect\nhttps://svelte.dev/e/effect_in_unowned_derived`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_in_unowned_derived");
throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`);
}
}
@ -168,13 +159,12 @@ export function effect_in_unowned_derived() {
*/
export function effect_orphan(rune) {
if (DEV) {
const error = new Error(`effect_orphan\n\`${rune}\` can only be used inside an effect (e.g. during component initialisation)`);
const error = new Error(`effect_orphan\n\`${rune}\` can only be used inside an effect (e.g. during component initialisation)\nhttps://svelte.dev/e/effect_orphan`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_orphan");
throw new Error(`https://svelte.dev/e/effect_orphan`);
}
}
@ -184,13 +174,12 @@ export function effect_orphan(rune) {
*/
export function effect_update_depth_exceeded() {
if (DEV) {
const error = new Error(`effect_update_depth_exceeded\nMaximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops`);
const error = new Error(`effect_update_depth_exceeded\nMaximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops\nhttps://svelte.dev/e/effect_update_depth_exceeded`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_update_depth_exceeded");
throw new Error(`https://svelte.dev/e/effect_update_depth_exceeded`);
}
}
@ -200,13 +189,12 @@ export function effect_update_depth_exceeded() {
*/
export function hydration_failed() {
if (DEV) {
const error = new Error(`hydration_failed\nFailed to hydrate the application`);
const error = new Error(`hydration_failed\nFailed to hydrate the application\nhttps://svelte.dev/e/hydration_failed`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("hydration_failed");
throw new Error(`https://svelte.dev/e/hydration_failed`);
}
}
@ -216,13 +204,12 @@ export function hydration_failed() {
*/
export function invalid_snippet() {
if (DEV) {
const error = new Error(`invalid_snippet\nCould not \`{@render}\` snippet due to the expression being \`null\` or \`undefined\`. Consider using optional chaining \`{@render snippet?.()}\``);
const error = new Error(`invalid_snippet\nCould not \`{@render}\` snippet due to the expression being \`null\` or \`undefined\`. Consider using optional chaining \`{@render snippet?.()}\`\nhttps://svelte.dev/e/invalid_snippet`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("invalid_snippet");
throw new Error(`https://svelte.dev/e/invalid_snippet`);
}
}
@ -233,13 +220,12 @@ export function invalid_snippet() {
*/
export function lifecycle_legacy_only(name) {
if (DEV) {
const error = new Error(`lifecycle_legacy_only\n\`${name}(...)\` cannot be used in runes mode`);
const error = new Error(`lifecycle_legacy_only\n\`${name}(...)\` cannot be used in runes mode\nhttps://svelte.dev/e/lifecycle_legacy_only`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("lifecycle_legacy_only");
throw new Error(`https://svelte.dev/e/lifecycle_legacy_only`);
}
}
@ -250,13 +236,12 @@ export function lifecycle_legacy_only(name) {
*/
export function props_invalid_value(key) {
if (DEV) {
const error = new Error(`props_invalid_value\nCannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value`);
const error = new Error(`props_invalid_value\nCannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value\nhttps://svelte.dev/e/props_invalid_value`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("props_invalid_value");
throw new Error(`https://svelte.dev/e/props_invalid_value`);
}
}
@ -267,13 +252,12 @@ export function props_invalid_value(key) {
*/
export function props_rest_readonly(property) {
if (DEV) {
const error = new Error(`props_rest_readonly\nRest element properties of \`$props()\` such as \`${property}\` are readonly`);
const error = new Error(`props_rest_readonly\nRest element properties of \`$props()\` such as \`${property}\` are readonly\nhttps://svelte.dev/e/props_rest_readonly`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("props_rest_readonly");
throw new Error(`https://svelte.dev/e/props_rest_readonly`);
}
}
@ -284,13 +268,12 @@ export function props_rest_readonly(property) {
*/
export function rune_outside_svelte(rune) {
if (DEV) {
const error = new Error(`rune_outside_svelte\nThe \`${rune}\` rune is only available inside \`.svelte\` and \`.svelte.js/ts\` files`);
const error = new Error(`rune_outside_svelte\nThe \`${rune}\` rune is only available inside \`.svelte\` and \`.svelte.js/ts\` files\nhttps://svelte.dev/e/rune_outside_svelte`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("rune_outside_svelte");
throw new Error(`https://svelte.dev/e/rune_outside_svelte`);
}
}
@ -300,13 +283,12 @@ export function rune_outside_svelte(rune) {
*/
export function state_descriptors_fixed() {
if (DEV) {
const error = new Error(`state_descriptors_fixed\nProperty descriptors defined on \`$state\` objects must contain \`value\` and always be \`enumerable\`, \`configurable\` and \`writable\`.`);
const error = new Error(`state_descriptors_fixed\nProperty descriptors defined on \`$state\` objects must contain \`value\` and always be \`enumerable\`, \`configurable\` and \`writable\`.\nhttps://svelte.dev/e/state_descriptors_fixed`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_descriptors_fixed");
throw new Error(`https://svelte.dev/e/state_descriptors_fixed`);
}
}
@ -316,13 +298,12 @@ export function state_descriptors_fixed() {
*/
export function state_prototype_fixed() {
if (DEV) {
const error = new Error(`state_prototype_fixed\nCannot set prototype of \`$state\` object`);
const error = new Error(`state_prototype_fixed\nCannot set prototype of \`$state\` object\nhttps://svelte.dev/e/state_prototype_fixed`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_prototype_fixed");
throw new Error(`https://svelte.dev/e/state_prototype_fixed`);
}
}
@ -332,13 +313,12 @@ export function state_prototype_fixed() {
*/
export function state_unsafe_local_read() {
if (DEV) {
const error = new Error(`state_unsafe_local_read\nReading state that was created inside the same derived is forbidden. Consider using \`untrack\` to read locally created state`);
const error = new Error(`state_unsafe_local_read\nReading state that was created inside the same derived is forbidden. Consider using \`untrack\` to read locally created state\nhttps://svelte.dev/e/state_unsafe_local_read`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_unsafe_local_read");
throw new Error(`https://svelte.dev/e/state_unsafe_local_read`);
}
}
@ -348,12 +328,11 @@ export function state_unsafe_local_read() {
*/
export function state_unsafe_mutation() {
if (DEV) {
const error = new Error(`state_unsafe_mutation\nUpdating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without \`$state\``);
const error = new Error(`state_unsafe_mutation\nUpdating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without \`$state\`\nhttps://svelte.dev/e/state_unsafe_mutation`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_unsafe_mutation");
throw new Error(`https://svelte.dev/e/state_unsafe_mutation`);
}
}

@ -12,10 +12,9 @@ var normal = 'font-weight: normal';
*/
export function assignment_value_stale(property, location) {
if (DEV) {
console.warn(`%c[svelte] assignment_value_stale\n%cAssignment to \`${property}\` property (${location}) will evaluate to the right-hand side, not the value of \`${property}\` following the assignment. This may result in unexpected behaviour.`, bold, normal);
console.warn(`%c[svelte] assignment_value_stale\n%cAssignment to \`${property}\` property (${location}) will evaluate to the right-hand side, not the value of \`${property}\` following the assignment. This may result in unexpected behaviour.\nhttps://svelte.dev/e/assignment_value_stale`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("assignment_value_stale");
console.warn(`https://svelte.dev/e/assignment_value_stale`);
}
}
@ -26,10 +25,9 @@ export function assignment_value_stale(property, location) {
*/
export function binding_property_non_reactive(binding, location) {
if (DEV) {
console.warn(`%c[svelte] binding_property_non_reactive\n%c${location ? `\`${binding}\` (${location}) is binding to a non-reactive property` : `\`${binding}\` is binding to a non-reactive property`}`, bold, normal);
console.warn(`%c[svelte] binding_property_non_reactive\n%c${location ? `\`${binding}\` (${location}) is binding to a non-reactive property` : `\`${binding}\` is binding to a non-reactive property`}\nhttps://svelte.dev/e/binding_property_non_reactive`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("binding_property_non_reactive");
console.warn(`https://svelte.dev/e/binding_property_non_reactive`);
}
}
@ -39,10 +37,9 @@ export function binding_property_non_reactive(binding, location) {
*/
export function console_log_state(method) {
if (DEV) {
console.warn(`%c[svelte] console_log_state\n%cYour \`console.${method}\` contained \`$state\` proxies. Consider using \`$inspect(...)\` or \`$state.snapshot(...)\` instead`, bold, normal);
console.warn(`%c[svelte] console_log_state\n%cYour \`console.${method}\` contained \`$state\` proxies. Consider using \`$inspect(...)\` or \`$state.snapshot(...)\` instead\nhttps://svelte.dev/e/console_log_state`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("console_log_state");
console.warn(`https://svelte.dev/e/console_log_state`);
}
}
@ -53,10 +50,9 @@ export function console_log_state(method) {
*/
export function event_handler_invalid(handler, suggestion) {
if (DEV) {
console.warn(`%c[svelte] event_handler_invalid\n%c${handler} should be a function. Did you mean to ${suggestion}?`, bold, normal);
console.warn(`%c[svelte] event_handler_invalid\n%c${handler} should be a function. Did you mean to ${suggestion}?\nhttps://svelte.dev/e/event_handler_invalid`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("event_handler_invalid");
console.warn(`https://svelte.dev/e/event_handler_invalid`);
}
}
@ -68,10 +64,9 @@ export function event_handler_invalid(handler, suggestion) {
*/
export function hydration_attribute_changed(attribute, html, value) {
if (DEV) {
console.warn(`%c[svelte] hydration_attribute_changed\n%cThe \`${attribute}\` attribute on \`${html}\` changed its value between server and client renders. The client value, \`${value}\`, will be ignored in favour of the server value`, bold, normal);
console.warn(`%c[svelte] hydration_attribute_changed\n%cThe \`${attribute}\` attribute on \`${html}\` changed its value between server and client renders. The client value, \`${value}\`, will be ignored in favour of the server value\nhttps://svelte.dev/e/hydration_attribute_changed`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("hydration_attribute_changed");
console.warn(`https://svelte.dev/e/hydration_attribute_changed`);
}
}
@ -81,10 +76,9 @@ export function hydration_attribute_changed(attribute, html, value) {
*/
export function hydration_html_changed(location) {
if (DEV) {
console.warn(`%c[svelte] hydration_html_changed\n%c${location ? `The value of an \`{@html ...}\` block ${location} changed between server and client renders. The client value will be ignored in favour of the server value` : "The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value"}`, bold, normal);
console.warn(`%c[svelte] hydration_html_changed\n%c${location ? `The value of an \`{@html ...}\` block ${location} changed between server and client renders. The client value will be ignored in favour of the server value` : "The value of an `{@html ...}` block changed between server and client renders. The client value will be ignored in favour of the server value"}\nhttps://svelte.dev/e/hydration_html_changed`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("hydration_html_changed");
console.warn(`https://svelte.dev/e/hydration_html_changed`);
}
}
@ -94,10 +88,9 @@ export function hydration_html_changed(location) {
*/
export function hydration_mismatch(location) {
if (DEV) {
console.warn(`%c[svelte] hydration_mismatch\n%c${location ? `Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near ${location}` : "Hydration failed because the initial UI does not match what was rendered on the server"}`, bold, normal);
console.warn(`%c[svelte] hydration_mismatch\n%c${location ? `Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near ${location}` : "Hydration failed because the initial UI does not match what was rendered on the server"}\nhttps://svelte.dev/e/hydration_mismatch`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("hydration_mismatch");
console.warn(`https://svelte.dev/e/hydration_mismatch`);
}
}
@ -106,10 +99,9 @@ export function hydration_mismatch(location) {
*/
export function invalid_raw_snippet_render() {
if (DEV) {
console.warn(`%c[svelte] invalid_raw_snippet_render\n%cThe \`render\` function passed to \`createRawSnippet\` should return HTML for a single element`, bold, normal);
console.warn(`%c[svelte] invalid_raw_snippet_render\n%cThe \`render\` function passed to \`createRawSnippet\` should return HTML for a single element\nhttps://svelte.dev/e/invalid_raw_snippet_render`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("invalid_raw_snippet_render");
console.warn(`https://svelte.dev/e/invalid_raw_snippet_render`);
}
}
@ -119,10 +111,9 @@ export function invalid_raw_snippet_render() {
*/
export function legacy_recursive_reactive_block(filename) {
if (DEV) {
console.warn(`%c[svelte] legacy_recursive_reactive_block\n%cDetected a migrated \`$:\` reactive block in \`${filename}\` that both accesses and updates the same reactive value. This may cause recursive updates when converted to an \`$effect\`.`, bold, normal);
console.warn(`%c[svelte] legacy_recursive_reactive_block\n%cDetected a migrated \`$:\` reactive block in \`${filename}\` that both accesses and updates the same reactive value. This may cause recursive updates when converted to an \`$effect\`.\nhttps://svelte.dev/e/legacy_recursive_reactive_block`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("legacy_recursive_reactive_block");
console.warn(`https://svelte.dev/e/legacy_recursive_reactive_block`);
}
}
@ -131,10 +122,9 @@ export function legacy_recursive_reactive_block(filename) {
*/
export function lifecycle_double_unmount() {
if (DEV) {
console.warn(`%c[svelte] lifecycle_double_unmount\n%cTried to unmount a component that was not mounted`, bold, normal);
console.warn(`%c[svelte] lifecycle_double_unmount\n%cTried to unmount a component that was not mounted\nhttps://svelte.dev/e/lifecycle_double_unmount`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("lifecycle_double_unmount");
console.warn(`https://svelte.dev/e/lifecycle_double_unmount`);
}
}
@ -146,10 +136,9 @@ export function lifecycle_double_unmount() {
*/
export function ownership_invalid_binding(parent, child, owner) {
if (DEV) {
console.warn(`%c[svelte] ownership_invalid_binding\n%c${parent} passed a value to ${child} with \`bind:\`, but the value is owned by ${owner}. Consider creating a binding between ${owner} and ${parent}`, bold, normal);
console.warn(`%c[svelte] ownership_invalid_binding\n%c${parent} passed a value to ${child} with \`bind:\`, but the value is owned by ${owner}. Consider creating a binding between ${owner} and ${parent}\nhttps://svelte.dev/e/ownership_invalid_binding`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("ownership_invalid_binding");
console.warn(`https://svelte.dev/e/ownership_invalid_binding`);
}
}
@ -160,10 +149,9 @@ export function ownership_invalid_binding(parent, child, owner) {
*/
export function ownership_invalid_mutation(component, owner) {
if (DEV) {
console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : "Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead"}`, bold, normal);
console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : "Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead"}\nhttps://svelte.dev/e/ownership_invalid_mutation`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("ownership_invalid_mutation");
console.warn(`https://svelte.dev/e/ownership_invalid_mutation`);
}
}
@ -173,10 +161,9 @@ export function ownership_invalid_mutation(component, owner) {
*/
export function reactive_declaration_non_reactive_property(location) {
if (DEV) {
console.warn(`%c[svelte] reactive_declaration_non_reactive_property\n%cA \`$:\` statement (${location}) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode`, bold, normal);
console.warn(`%c[svelte] reactive_declaration_non_reactive_property\n%cA \`$:\` statement (${location}) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode\nhttps://svelte.dev/e/reactive_declaration_non_reactive_property`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("reactive_declaration_non_reactive_property");
console.warn(`https://svelte.dev/e/reactive_declaration_non_reactive_property`);
}
}
@ -186,9 +173,8 @@ export function reactive_declaration_non_reactive_property(location) {
*/
export function state_proxy_equality_mismatch(operator) {
if (DEV) {
console.warn(`%c[svelte] state_proxy_equality_mismatch\n%cReactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results`, bold, normal);
console.warn(`%c[svelte] state_proxy_equality_mismatch\n%cReactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results\nhttps://svelte.dev/e/state_proxy_equality_mismatch`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("state_proxy_equality_mismatch");
console.warn(`https://svelte.dev/e/state_proxy_equality_mismatch`);
}
}

@ -6,7 +6,7 @@
* @returns {never}
*/
export function lifecycle_function_unavailable(name) {
const error = new Error(`lifecycle_function_unavailable\n\`${name}(...)\` is not available on the server`);
const error = new Error(`lifecycle_function_unavailable\n\`${name}(...)\` is not available on the server\nhttps://svelte.dev/e/lifecycle_function_unavailable`);
error.name = 'Svelte error';
throw error;

@ -126,7 +126,7 @@ test('uncloneable value', () => {
assert.equal(fn, copy);
assert.deepEqual(warnings(), [
'%c[svelte] state_snapshot_uncloneable\n%cValue cannot be cloned with `$state.snapshot` — the original value was returned'
'%c[svelte] state_snapshot_uncloneable\n%cValue cannot be cloned with `$state.snapshot` — the original value was returned\nhttps://svelte.dev/e/state_snapshot_uncloneable'
]);
});
@ -160,7 +160,8 @@ test('uncloneable properties', () => {
- <value>.c[4]
- <value>.c[5]
- <value>.c[6]
- <value>.c[7]`
- <value>.c[7]
https://svelte.dev/e/state_snapshot_uncloneable`
]);
});
@ -181,6 +182,7 @@ test('many uncloneable properties', () => {
- <value>[4]
- <value>[5]
- <value>[6]
- ...and 93 more`
- ...and 93 more
https://svelte.dev/e/state_snapshot_uncloneable`
]);
});

@ -8,13 +8,13 @@ import { DEV } from 'esm-env';
*/
export function invalid_default_snippet() {
if (DEV) {
const error = new Error(`invalid_default_snippet\nCannot use \`{@render children(...)}\` if the parent component uses \`let:\` directives. Consider using a named snippet instead`);
const error = new Error(`invalid_default_snippet\nCannot use \`{@render children(...)}\` if the parent component uses \`let:\` directives. Consider using a named snippet instead\nhttps://svelte.dev/e/invalid_default_snippet`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("invalid_default_snippet");
throw new Error(`https://svelte.dev/e/invalid_default_snippet`);
}
}
@ -25,13 +25,13 @@ export function invalid_default_snippet() {
*/
export function lifecycle_outside_component(name) {
if (DEV) {
const error = new Error(`lifecycle_outside_component\n\`${name}(...)\` can only be used during component initialisation`);
const error = new Error(`lifecycle_outside_component\n\`${name}(...)\` can only be used during component initialisation\nhttps://svelte.dev/e/lifecycle_outside_component`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("lifecycle_outside_component");
throw new Error(`https://svelte.dev/e/lifecycle_outside_component`);
}
}
@ -42,13 +42,13 @@ export function lifecycle_outside_component(name) {
*/
export function store_invalid_shape(name) {
if (DEV) {
const error = new Error(`store_invalid_shape\n\`${name}\` is not a store with a \`subscribe\` method`);
const error = new Error(`store_invalid_shape\n\`${name}\` is not a store with a \`subscribe\` method\nhttps://svelte.dev/e/store_invalid_shape`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("store_invalid_shape");
throw new Error(`https://svelte.dev/e/store_invalid_shape`);
}
}
@ -58,12 +58,12 @@ export function store_invalid_shape(name) {
*/
export function svelte_element_invalid_this_value() {
if (DEV) {
const error = new Error(`svelte_element_invalid_this_value\nThe \`this\` prop on \`<svelte:element>\` must be a string, if defined`);
const error = new Error(`svelte_element_invalid_this_value\nThe \`this\` prop on \`<svelte:element>\` must be a string, if defined\nhttps://svelte.dev/e/svelte_element_invalid_this_value`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("svelte_element_invalid_this_value");
throw new Error(`https://svelte.dev/e/svelte_element_invalid_this_value`);
}
}

@ -11,10 +11,10 @@ var normal = 'font-weight: normal';
*/
export function dynamic_void_element_content(tag) {
if (DEV) {
console.warn(`%c[svelte] dynamic_void_element_content\n%c\`<svelte:element this="${tag}">\` is a void element — it cannot have content`, bold, normal);
console.warn(`%c[svelte] dynamic_void_element_content\n%c\`<svelte:element this="${tag}">\` is a void element — it cannot have content\nhttps://svelte.dev/e/dynamic_void_element_content`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("dynamic_void_element_content");
console.warn(`https://svelte.dev/e/dynamic_void_element_content`);
}
}
@ -30,9 +30,9 @@ export function state_snapshot_uncloneable(properties) {
? `The following properties cannot be cloned with \`$state.snapshot\` — the return value contains the originals:
${properties}`
: "Value cannot be cloned with `$state.snapshot` — the original value was returned"}`, bold, normal);
: "Value cannot be cloned with `$state.snapshot` — the original value was returned"}\nhttps://svelte.dev/e/state_snapshot_uncloneable`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("state_snapshot_uncloneable");
console.warn(`https://svelte.dev/e/state_snapshot_uncloneable`);
}
}

@ -6,5 +6,5 @@
* https://svelte.dev/docs/svelte-compiler#svelte-version
* @type {string}
*/
export const VERSION = '5.8.1';
export const VERSION = '5.10.0';
export const PUBLIC_VERSION = '5';

@ -12,6 +12,13 @@ interface CompilerErrorTest extends BaseTest {
};
}
/**
* Remove the "https://svelte.dev/e/..." link
*/
function strip_link(message: string) {
return message.slice(0, message.lastIndexOf('\n'));
}
const { test, run } = suite<CompilerErrorTest>((config, cwd) => {
if (!fs.existsSync(`${cwd}/main.svelte`) && !fs.existsSync(`${cwd}/main.svelte.js`)) {
throw new Error('Expected main.svelte or main.svelte.js');
@ -30,7 +37,7 @@ const { test, run } = suite<CompilerErrorTest>((config, cwd) => {
caught_error = true;
expect(error.code).toBe(config.error.code);
expect(error.message).toBe(config.error.message);
expect(strip_link(error.message)).toBe(config.error.message);
if (config.error.position) {
expect(error.position).toEqual(config.error.position);
@ -55,7 +62,7 @@ const { test, run } = suite<CompilerErrorTest>((config, cwd) => {
caught_error = true;
expect(error.code).toEqual(config.error.code);
expect(error.message).toEqual(config.error.message);
expect(strip_link(error.message)).toEqual(config.error.message);
if (config.error.position) {
expect(error.position).toEqual(config.error.position);

@ -12,6 +12,14 @@ function normalize_warning(warning: Warning) {
delete warning.filename;
delete warning.position;
delete warning.frame;
// Remove the "https://svelte.dev/e/..." link at the end
const lines = warning.message.split('\n');
if (lines.at(-1)?.startsWith('https://svelte.dev/e/')) {
lines.pop();
}
warning.message = lines.join('\n');
return warning;
}
@ -28,6 +36,13 @@ interface CssTest extends BaseTest {
props?: Record<string, any>;
}
/**
* Remove the "https://svelte.dev/e/..." link
*/
function strip_link(message: string) {
return message.slice(0, message.lastIndexOf('\n'));
}
const { test, run } = suite<CssTest>(async (config, cwd) => {
await compile_directory(cwd, 'client', { cssHash: () => 'svelte-xyz', ...config.compileOptions });
await compile_directory(cwd, 'server', { cssHash: () => 'svelte-xyz', ...config.compileOptions });

@ -77,7 +77,14 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
// TODO convert this to structured data, for more robust comparison?
const text = args[0];
const code = text.slice(11, text.indexOf('\n%c', 11));
const message = text.slice(text.indexOf('%c', 2) + 2);
let message = text.slice(text.indexOf('%c', 2) + 2);
// Remove the "https://svelte.dev/e/..." link at the end
const lines = message.split('\n');
if (lines.at(-1)?.startsWith('https://svelte.dev/e/')) {
lines.pop();
}
message = lines.join('\n');
if (typeof message === 'string' && code === 'hydration_mismatch') {
got_hydration_error = true;

@ -18,7 +18,7 @@ export default test({
2:
3: unterminated template
^`,
message: 'Unexpected end of input',
message: 'Unexpected end of input\nhttps://svelte.dev/e/unexpected_eof',
position: [30, 30],
start: {
character: 30,

@ -1,4 +1,5 @@
<!-- @migration-task Error while migrating Svelte code: Unexpected end of input -->
<!-- @migration-task Error while migrating Svelte code: Unexpected end of input
https://svelte.dev/e/unexpected_eof -->
<script
unterminated template

@ -5,7 +5,8 @@ export default test({
warnings: [
{
code: 'attribute_avoid_is',
message: 'The "is" attribute is not supported cross-browser and should be avoided',
message:
'The "is" attribute is not supported cross-browser and should be avoided\nhttps://svelte.dev/e/attribute_avoid_is',
start: {
character: 109,
column: 8,

@ -216,8 +216,18 @@ async function run_test_variant(
console.warn = (...args) => {
if (args[0].startsWith('%c[svelte]')) {
// TODO convert this to structured data, for more robust comparison?
const message = args[0];
warnings.push(message.slice(message.indexOf('%c', 2) + 2));
let message = args[0];
message = message.slice(message.indexOf('%c', 2) + 2);
// Remove the "https://svelte.dev/e/..." link at the end
const lines = message.split('\n');
if (lines.at(-1)?.startsWith('https://svelte.dev/e/')) {
lines.pop();
}
message = lines.join('\n');
warnings.push(message);
} else {
warnings.push(...args);
}

@ -0,0 +1,11 @@
<script>
let div = $state();
$effect(() => {
console.log(div?.textContent);
})
export const someData = '123';
</script>
<div bind:this={() => div, v => div = v}>123</div>

@ -0,0 +1,9 @@
import { test } from '../../test';
export default test({
async test({ assert, target, logs }) {
assert.htmlEqual(target.innerHTML, `<div>123</div>`);
assert.deepEqual(logs, ['123', '123']);
}
});

@ -0,0 +1,11 @@
<script>
import Child from './Child.svelte';
let child = $state();
$effect(() => {
console.log(child.someData);
});
</script>
<Child bind:this={() => child, v => child = v} />

@ -0,0 +1,12 @@
<script>
let { a = $bindable() } = $props();
</script>
<input
type="value"
bind:value={() => a,
(v) => {
console.log('b', v);
a = v;
}}
/>

@ -0,0 +1,26 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { assert_ok } from '../../../suite';
export default test({
async test({ assert, target, logs }) {
const [input, checkbox] = target.querySelectorAll('input');
input.value = '2';
input.dispatchEvent(new window.Event('input'));
flushSync();
assert.htmlEqual(
target.innerHTML,
`<button>a: 2</button><input type="value"><div><input type="checkbox" ></div>`
);
assert.deepEqual(logs, ['b', '2', 'a', '2']);
flushSync(() => {
checkbox.click();
});
assert.deepEqual(logs, ['b', '2', 'a', '2', 'check', false]);
}
});

@ -0,0 +1,25 @@
<script>
import Child from './Child.svelte';
let a = $state(0);
let check = $state(true);
</script>
<button onclick={() => a++}>a: {a}</button>
<Child
bind:a={() => a,
(v) => {
console.log('a', v);
a = v;
}}
/>
<div>
<input type="checkbox"
bind:checked={()=>check,
(v)=>{
console.log('check', v);
check = v;
}} />
</div>

@ -0,0 +1,3 @@
import { test } from '../../test';
export default test({});

@ -0,0 +1,6 @@
<script>
class Test {
0 = $state();
1 = $state();
}
</script>

@ -0,0 +1,14 @@
[
{
"code": "bind_group_invalid_expression",
"message": "`bind:group` can only bind to an Identifier or MemberExpression",
"start": {
"line": 8,
"column": 38
},
"end": {
"line": 8,
"column": 84
}
}
]

@ -0,0 +1,12 @@
<script>
let values = $state([{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]);
let selected = $state(values[1]);
</script>
{#each values as value}
<label>
<input type="radio" value="{value}" bind:group={() => selected, v => selected = v} /> {value.name}
</label>
{/each}
<p>{selected.name}</p>

@ -0,0 +1,3 @@
<script module>
export { something } from "./something.js";
</script>

@ -13,6 +13,13 @@ interface ValidatorTest extends BaseTest {
};
}
/**
* Remove the "https://svelte.dev/e/..." link
*/
function strip_link(message: string) {
return message.slice(0, message.lastIndexOf('\n'));
}
const { test, run } = suite<ValidatorTest>(async (config, cwd) => {
const expected_warnings = try_load_json(`${cwd}/warnings.json`) || [];
const expected_errors = try_load_json(`${cwd}/errors.json`);
@ -40,7 +47,7 @@ const { test, run } = suite<ValidatorTest>(async (config, cwd) => {
assert.deepEqual(
warnings.map((w) => ({
code: w.code,
message: w.message,
message: strip_link(w.message),
start: { line: w.start?.line, column: w.start?.column },
end: { line: w.end?.line, column: w.end?.column }
})),
@ -56,7 +63,7 @@ const { test, run } = suite<ValidatorTest>(async (config, cwd) => {
assert.deepEqual(
{
code: error.code,
message: error.message,
message: strip_link(error.message),
start: { line: error.start?.line, column: error.start?.column },
end: { line: error.end?.line, column: error.end?.column }
},

@ -606,7 +606,7 @@ declare module 'svelte/animate' {
}
declare module 'svelte/compiler' {
import type { Expression, Identifier, ArrayExpression, ArrowFunctionExpression, VariableDeclaration, VariableDeclarator, MemberExpression, ObjectExpression, Pattern, Program, ChainExpression, SimpleCallExpression } from 'estree';
import type { Expression, Identifier, ArrayExpression, ArrowFunctionExpression, VariableDeclaration, VariableDeclarator, MemberExpression, ObjectExpression, Pattern, Program, ChainExpression, SimpleCallExpression, SequenceExpression } from 'estree';
import type { SourceMap } from 'magic-string';
import type { Location } from 'locate-character';
/**
@ -1047,7 +1047,7 @@ declare module 'svelte/compiler' {
/** The 'x' in `bind:x` */
name: string;
/** The y in `bind:x={y}` */
expression: Identifier | MemberExpression;
expression: Identifier | MemberExpression | SequenceExpression;
}
/** A `class:` directive */

Loading…
Cancel
Save