Skip to content

Commit a983fbd

Browse files
committed
more
1 parent a20b693 commit a983fbd

File tree

16 files changed

+243
-68
lines changed

16 files changed

+243
-68
lines changed

packages/svelte/messages/client-errors/errors.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## bind_invalid_checkbox_value
2+
3+
> Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead
4+
15
## bind_invalid_export
26

37
> Component %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%`)
@@ -12,6 +16,14 @@
1216
1317
> Keyed each block has duplicate key `%value%` at indexes %a% and %b%
1418
19+
## effect_in_teardown
20+
21+
> `%rune%` cannot be used inside an effect cleanup function
22+
23+
## effect_orphan
24+
25+
> `%rune%` can only be used inside an effect (e.g. during component initialisation)
26+
1527
## effect_update_depth_exceeded
1628

1729
> Maximum 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
@@ -28,9 +40,13 @@
2840

2941
> `%name%(...)` cannot be used in runes mode
3042
31-
## lifecycle_outside_component
43+
## props_invalid_value
44+
45+
> Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value
46+
47+
## props_rest_readonly
3248

33-
> `%name%(...)` can only be used during component initialisation
49+
> Rest element properties of `$props()` such as `%property%` are readonly
3450
3551
## rune_outside_svelte
3652

@@ -40,6 +56,12 @@
4056

4157
> Cannot set prototype of `$state` object
4258
59+
## state_unsafe_mutation
60+
61+
> Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.
62+
>
63+
> If the object is not meant to be reactive, declare it without `$state`
64+
4365
## svelte_component_invalid_this_value
4466

4567
> The `this={...}` property of a `<svelte:component>` must be a Svelte component, if defined
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
## lifecycle_outside_component
2+
3+
> `%name%(...)` can only be used during component initialisation
4+
5+
## render_tag_invalid_argument
6+
7+
> The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`
8+
9+
## snippet_used_as_component
10+
11+
> A snippet must be rendered with `{@render ...}`
12+
113
## store_invalid_shape
214

315
> `%name%` is not a store with a `subscribe` method
16+
17+
## svelte_element_invalid_this_value
18+
19+
> The `this` prop on `<svelte:element>` must be a string, if defined

packages/svelte/src/index-client.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { current_component_context, flush_sync, untrack } from './internal/clien
22
import { is_array } from './internal/client/utils.js';
33
import { user_effect } from './internal/client/index.js';
44
import * as e from './internal/client/errors.js';
5+
import { lifecycle_outside_component } from './internal/shared/errors.js';
56

67
/**
78
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
@@ -19,7 +20,7 @@ import * as e from './internal/client/errors.js';
1920
*/
2021
export function onMount(fn) {
2122
if (current_component_context === null) {
22-
e.lifecycle_outside_component('onMount');
23+
lifecycle_outside_component('onMount');
2324
}
2425

2526
if (current_component_context.l !== null) {
@@ -44,7 +45,7 @@ export function onMount(fn) {
4445
*/
4546
export function onDestroy(fn) {
4647
if (current_component_context === null) {
47-
e.lifecycle_outside_component('onDestroy');
48+
lifecycle_outside_component('onDestroy');
4849
}
4950

5051
onMount(() => () => untrack(fn));
@@ -88,7 +89,7 @@ function create_custom_event(type, detail, { bubbles = false, cancelable = false
8889
export function createEventDispatcher() {
8990
const component_context = current_component_context;
9091
if (component_context === null) {
91-
e.lifecycle_outside_component('createEventDispatcher');
92+
lifecycle_outside_component('createEventDispatcher');
9293
}
9394

9495
return (type, detail, options) => {
@@ -127,7 +128,7 @@ export function createEventDispatcher() {
127128
*/
128129
export function beforeUpdate(fn) {
129130
if (current_component_context === null) {
130-
e.lifecycle_outside_component('beforeUpdate');
131+
lifecycle_outside_component('beforeUpdate');
131132
}
132133

133134
if (current_component_context.l === null) {
@@ -151,7 +152,7 @@ export function beforeUpdate(fn) {
151152
*/
152153
export function afterUpdate(fn) {
153154
if (current_component_context === null) {
154-
e.lifecycle_outside_component('afterUpdate');
155+
lifecycle_outside_component('afterUpdate');
155156
}
156157

157158
if (current_component_context.l === null) {

packages/svelte/src/internal/client/dom/elements/bindings/input.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DEV } from 'esm-env';
22
import { render_effect, effect } from '../../../reactivity/effects.js';
33
import { stringify } from '../../../render.js';
44
import { listen_to_event_and_reset_event } from './shared.js';
5+
import * as e from '../../../errors.js';
56

67
/**
78
* @param {HTMLInputElement} input
@@ -12,19 +13,17 @@ import { listen_to_event_and_reset_event } from './shared.js';
1213
export function bind_value(input, get_value, update) {
1314
listen_to_event_and_reset_event(input, 'input', () => {
1415
if (DEV && input.type === 'checkbox') {
15-
throw new Error(
16-
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
17-
);
16+
// TODO should this happen in prod too?
17+
e.bind_invalid_checkbox_value();
1818
}
1919

2020
update(is_numberlike_input(input) ? to_number(input.value) : input.value);
2121
});
2222

2323
render_effect(() => {
2424
if (DEV && input.type === 'checkbox') {
25-
throw new Error(
26-
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
27-
);
25+
// TODO should this happen in prod too?
26+
e.bind_invalid_checkbox_value();
2827
}
2928

3029
var value = get_value();

packages/svelte/src/internal/client/errors.js

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
import { DEV } from 'esm-env';
44

5+
/**
6+
* Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead
7+
* @returns {never}
8+
*/
9+
export function bind_invalid_checkbox_value() {
10+
if (DEV) {
11+
const error = new Error(`${"bind_invalid_checkbox_value"}\n${"Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead"}`);
12+
13+
error.name = 'Svelte error';
14+
throw error;
15+
} else {
16+
// TODO print a link to the documentation
17+
throw new Error("bind_invalid_checkbox_value");
18+
}
19+
}
20+
521
/**
622
* Component %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%`)
723
* @param {string} component
@@ -59,6 +75,40 @@ export function each_key_duplicate(a, b, value) {
5975
}
6076
}
6177

78+
/**
79+
* `%rune%` cannot be used inside an effect cleanup function
80+
* @param {string} rune
81+
* @returns {never}
82+
*/
83+
export function effect_in_teardown(rune) {
84+
if (DEV) {
85+
const error = new Error(`${"effect_in_teardown"}\n${`\`${rune}\` cannot be used inside an effect cleanup function`}`);
86+
87+
error.name = 'Svelte error';
88+
throw error;
89+
} else {
90+
// TODO print a link to the documentation
91+
throw new Error("effect_in_teardown");
92+
}
93+
}
94+
95+
/**
96+
* `%rune%` can only be used inside an effect (e.g. during component initialisation)
97+
* @param {string} rune
98+
* @returns {never}
99+
*/
100+
export function effect_orphan(rune) {
101+
if (DEV) {
102+
const error = new Error(`${"effect_orphan"}\n${`\`${rune}\` can only be used inside an effect (e.g. during component initialisation)`}`);
103+
104+
error.name = 'Svelte error';
105+
throw error;
106+
} else {
107+
// TODO print a link to the documentation
108+
throw new Error("effect_orphan");
109+
}
110+
}
111+
62112
/**
63113
* Maximum 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
64114
* @returns {never}
@@ -125,19 +175,36 @@ export function lifecycle_legacy_only(name) {
125175
}
126176

127177
/**
128-
* `%name%(...)` can only be used during component initialisation
129-
* @param {string} name
178+
* Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value
179+
* @param {string} key
180+
* @returns {never}
181+
*/
182+
export function props_invalid_value(key) {
183+
if (DEV) {
184+
const error = new Error(`${"props_invalid_value"}\n${`Cannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value`}`);
185+
186+
error.name = 'Svelte error';
187+
throw error;
188+
} else {
189+
// TODO print a link to the documentation
190+
throw new Error("props_invalid_value");
191+
}
192+
}
193+
194+
/**
195+
* Rest element properties of `$props()` such as `%property%` are readonly
196+
* @param {string} property
130197
* @returns {never}
131198
*/
132-
export function lifecycle_outside_component(name) {
199+
export function props_rest_readonly(property) {
133200
if (DEV) {
134-
const error = new Error(`${"lifecycle_outside_component"}\n${`\`${name}(...)\` can only be used during component initialisation`}`);
201+
const error = new Error(`${"props_rest_readonly"}\n${`Rest element properties of \`$props()\` such as \`${property}\` are readonly`}`);
135202

136203
error.name = 'Svelte error';
137204
throw error;
138205
} else {
139206
// TODO print a link to the documentation
140-
throw new Error("lifecycle_outside_component");
207+
throw new Error("props_rest_readonly");
141208
}
142209
}
143210

@@ -174,6 +241,24 @@ export function state_prototype_fixed() {
174241
}
175242
}
176243

244+
/**
245+
* Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.
246+
* >
247+
* If the object is not meant to be reactive, declare it without `$state`
248+
* @returns {never}
249+
*/
250+
export function state_unsafe_mutation() {
251+
if (DEV) {
252+
const error = new Error(`${"state_unsafe_mutation"}\n${"Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.\n>\nIf the object is not meant to be reactive, declare it without `$state`"}`);
253+
254+
error.name = 'Svelte error';
255+
throw error;
256+
} else {
257+
// TODO print a link to the documentation
258+
throw new Error("state_unsafe_mutation");
259+
}
260+
}
261+
177262
/**
178263
* The `this={...}` property of a `<svelte:component>` must be a Svelte component, if defined
179264
* @returns {never}

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { DEV } from 'esm-env';
21
import {
32
check_dirtiness,
43
current_component_context,
@@ -30,6 +29,7 @@ import {
3029
} from '../constants.js';
3130
import { set } from './sources.js';
3231
import { remove } from '../dom/reconciler.js';
32+
import * as e from '../errors.js';
3333

3434
/**
3535
* @param {import('#client').Effect | null} effect
@@ -38,19 +38,11 @@ import { remove } from '../dom/reconciler.js';
3838
*/
3939
export function validate_effect(effect, rune) {
4040
if (effect === null) {
41-
throw new Error(
42-
'ERR_SVELTE_ORPHAN_EFFECT' +
43-
(DEV
44-
? `: ${rune} can only be used inside an effect (e.g. during component initialisation)`
45-
: '')
46-
);
41+
e.effect_orphan(rune);
4742
}
4843

4944
if (is_destroying_effect) {
50-
throw new Error(
51-
'ERR_SVELTE_EFFECT_IN_TEARDOWN' +
52-
(DEV ? `: ${rune} cannot be used inside an effect cleanup function.` : '')
53-
);
45+
e.effect_in_teardown(rune);
5446
}
5547
}
5648

packages/svelte/src/internal/client/reactivity/props.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { derived } from './deriveds.js';
1111
import { get, is_signals_recorded, untrack } from '../runtime.js';
1212
import { safe_equals } from './equality.js';
1313
import { inspect_fn } from '../dev/inspect.js';
14+
import * as e from '../errors.js';
1415

1516
/**
1617
* @param {((value?: number) => number)} fn
@@ -46,9 +47,8 @@ const rest_props_handler = {
4647
},
4748
set(target, key) {
4849
if (DEV) {
49-
throw new Error(
50-
`Rest element properties of $props() such as ${target.name}.${String(key)} are readonly`
51-
);
50+
// TODO should this happen in prod too?
51+
e.props_rest_readonly(`${target.name}.${String(key)}`);
5252
}
5353

5454
return false;
@@ -169,13 +169,7 @@ export function prop(props, key, flags, fallback) {
169169

170170
if (prop_value === undefined && fallback !== undefined) {
171171
if (setter && runes) {
172-
// TODO consolidate all these random runtime errors
173-
throw new Error(
174-
'ERR_SVELTE_BINDING_FALLBACK' +
175-
(DEV
176-
? `: Cannot pass undefined to bind:${key} because the property contains a fallback value. Pass a different value than undefined to ${key}.`
177-
: '')
178-
);
172+
e.props_invalid_value(key);
179173
}
180174

181175
prop_value = get_fallback();

packages/svelte/src/internal/client/reactivity/sources.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
import { equals, safe_equals } from './equality.js';
2020
import { CLEAN, DERIVED, DIRTY, BRANCH_EFFECT } from '../constants.js';
2121
import { UNINITIALIZED } from '../../../constants.js';
22+
import * as e from '../errors.js';
2223

2324
/**
2425
* @template V
@@ -91,14 +92,7 @@ export function set(signal, value) {
9192
is_runes() &&
9293
(current_reaction.f & DERIVED) !== 0
9394
) {
94-
throw new Error(
95-
'ERR_SVELTE_UNSAFE_MUTATION' +
96-
(DEV
97-
? ": Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. " +
98-
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
99-
'to be reactive do not use the "$state" rune for that declaration.'
100-
: '')
101-
);
95+
e.state_unsafe_mutation();
10296
}
10397

10498
if (!signal.equals(value)) {

packages/svelte/src/internal/client/runtime.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { mutate, set, source } from './reactivity/sources.js';
2323
import { update_derived } from './reactivity/deriveds.js';
2424
import { inspect_captured_signals, inspect_fn, set_inspect_fn } from './dev/inspect.js';
2525
import * as e from './errors.js';
26+
import { lifecycle_outside_component } from '../shared/errors.js';
2627

2728
const FLUSH_MICROTASK = 0;
2829
const FLUSH_SYNC = 1;
@@ -952,7 +953,7 @@ export function getAllContexts() {
952953
*/
953954
function get_or_init_context_map(name) {
954955
if (current_component_context === null) {
955-
e.lifecycle_outside_component(name);
956+
lifecycle_outside_component(name);
956957
}
957958

958959
return (current_component_context.c ??= new Map(

0 commit comments

Comments
 (0)