svelte 5.55.1 → 5.55.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/elements.d.ts CHANGED
@@ -952,9 +952,9 @@ export interface HTMLDetailsAttributes extends HTMLAttributes<HTMLDetailsElement
952
952
 
953
953
  'bind:open'?: boolean | undefined | null;
954
954
 
955
- 'on:toggle'?: EventHandler<Event, HTMLDetailsElement> | undefined | null;
956
- ontoggle?: EventHandler<Event, HTMLDetailsElement> | undefined | null;
957
- ontogglecapture?: EventHandler<Event, HTMLDetailsElement> | undefined | null;
955
+ 'on:toggle'?: ToggleEventHandler<HTMLDetailsElement> | undefined | null;
956
+ ontoggle?: ToggleEventHandler<HTMLDetailsElement> | undefined | null;
957
+ ontogglecapture?: ToggleEventHandler<HTMLDetailsElement> | undefined | null;
958
958
  }
959
959
 
960
960
  export interface HTMLDelAttributes extends HTMLAttributes<HTMLModElement> {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "svelte",
3
3
  "description": "Cybernetically enhanced web apps",
4
4
  "license": "MIT",
5
- "version": "5.55.1",
5
+ "version": "5.55.2",
6
6
  "type": "module",
7
7
  "types": "./types/index.d.ts",
8
8
  "engines": {
@@ -1,10 +1,13 @@
1
1
  /** @import { Comment, Program } from 'estree' */
2
2
  /** @import { AST } from '#compiler' */
3
+ /** @import { Parser } from './index.js' */
3
4
  import * as acorn from 'acorn';
4
5
  import { walk } from 'zimmerframe';
5
6
  import { tsPlugin } from '@sveltejs/acorn-typescript';
7
+ import * as e from '../../errors.js';
6
8
 
7
- const ParserWithTS = acorn.Parser.extend(tsPlugin());
9
+ const JSParser = acorn.Parser;
10
+ const TSParser = JSParser.extend(tsPlugin());
8
11
 
9
12
  /**
10
13
  * @typedef {Comment & {
@@ -20,15 +23,15 @@ const ParserWithTS = acorn.Parser.extend(tsPlugin());
20
23
  * @param {boolean} [is_script]
21
24
  */
22
25
  export function parse(source, comments, typescript, is_script) {
23
- const parser = typescript ? ParserWithTS : acorn.Parser;
26
+ const acorn = typescript ? TSParser : JSParser;
24
27
 
25
28
  const { onComment, add_comments } = get_comment_handlers(
26
29
  source,
27
30
  /** @type {CommentWithLocation[]} */ (comments)
28
31
  );
29
32
 
30
- // @ts-ignore
31
- const parse_statement = parser.prototype.parseStatement;
33
+ // @ts-expect-error
34
+ const parse_statement = acorn.prototype.parseStatement;
32
35
 
33
36
  // If we're dealing with a <script> then it might contain an export
34
37
  // for something that doesn't exist directly inside but is inside the
@@ -36,7 +39,7 @@ export function parse(source, comments, typescript, is_script) {
36
39
  // an error in these cases
37
40
  if (is_script) {
38
41
  // @ts-ignore
39
- parser.prototype.parseStatement = function (...args) {
42
+ acorn.prototype.parseStatement = function (...args) {
40
43
  const v = parse_statement.call(this, ...args);
41
44
  // @ts-ignore
42
45
  this.undefinedExports = {};
@@ -44,53 +47,77 @@ export function parse(source, comments, typescript, is_script) {
44
47
  };
45
48
  }
46
49
 
47
- let ast;
48
-
49
50
  try {
50
- ast = parser.parse(source, {
51
+ const ast = acorn.parse(source, {
51
52
  onComment,
52
53
  sourceType: 'module',
53
54
  ecmaVersion: 16,
54
55
  locations: true
55
56
  });
57
+
58
+ add_comments(ast);
59
+
60
+ return /** @type {Program} */ (ast);
61
+ } catch (err) {
62
+ // TODO the `return` in necessary for TS<7 due to a bug; otherwise
63
+ // the `finally` block is regarded as unreachable
64
+ return handle_parse_error(err);
56
65
  } finally {
57
66
  if (is_script) {
58
- // @ts-ignore
59
- parser.prototype.parseStatement = parse_statement;
67
+ // @ts-expect-error
68
+ acorn.prototype.parseStatement = parse_statement;
60
69
  }
61
70
  }
62
-
63
- add_comments(ast);
64
-
65
- return /** @type {Program} */ (ast);
66
71
  }
67
72
 
68
73
  /**
74
+ * @param {Parser} parser
69
75
  * @param {string} source
70
- * @param {Comment[]} comments
71
- * @param {boolean} typescript
72
76
  * @param {number} index
73
77
  * @returns {acorn.Expression & { leadingComments?: CommentWithLocation[]; trailingComments?: CommentWithLocation[]; }}
74
78
  */
75
- export function parse_expression_at(source, comments, typescript, index) {
76
- const parser = typescript ? ParserWithTS : acorn.Parser;
79
+ export function parse_expression_at(parser, source, index) {
80
+ const acorn = parser.ts ? TSParser : JSParser;
77
81
 
78
- const { onComment, add_comments } = get_comment_handlers(
79
- source,
80
- /** @type {CommentWithLocation[]} */ (comments),
81
- index
82
- );
82
+ const { onComment, add_comments } = get_comment_handlers(source, parser.root.comments, index);
83
83
 
84
- const ast = parser.parseExpressionAt(source, index, {
85
- onComment,
86
- sourceType: 'module',
87
- ecmaVersion: 16,
88
- locations: true
89
- });
84
+ try {
85
+ const ast = acorn.parseExpressionAt(source, index, {
86
+ onComment,
87
+ sourceType: 'module',
88
+ ecmaVersion: 16,
89
+ locations: true,
90
+ preserveParens: true
91
+ });
92
+
93
+ add_comments(ast);
94
+
95
+ return ast;
96
+ } catch (e) {
97
+ handle_parse_error(e);
98
+ }
99
+ }
100
+
101
+ const regex_position_indicator = / \(\d+:\d+\)$/;
90
102
 
91
- add_comments(ast);
103
+ /**
104
+ * @param {any} err
105
+ * @returns {never}
106
+ */
107
+ function handle_parse_error(err) {
108
+ e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, ''));
109
+ }
92
110
 
93
- return ast;
111
+ /**
112
+ * @param {acorn.Expression} node
113
+ * @returns {acorn.Expression}
114
+ */
115
+ export function remove_parens(node) {
116
+ return walk(node, null, {
117
+ ParenthesizedExpression(node, context) {
118
+ return context.visit(node.expression);
119
+ }
120
+ });
94
121
  }
95
122
 
96
123
  /**
@@ -11,8 +11,6 @@ import { is_reserved } from '../../../utils.js';
11
11
  import { disallow_children } from '../2-analyze/visitors/shared/special-element.js';
12
12
  import * as state from '../../state.js';
13
13
 
14
- const regex_position_indicator = / \(\d+:\d+\)$/;
15
-
16
14
  /** @param {number} cc */
17
15
  function is_whitespace(cc) {
18
16
  // fast path for common whitespace
@@ -175,14 +173,6 @@ export class Parser {
175
173
  return this.stack[this.stack.length - 1];
176
174
  }
177
175
 
178
- /**
179
- * @param {any} err
180
- * @returns {never}
181
- */
182
- acorn_error(err) {
183
- e.js_parse_error(err.pos, err.message.replace(regex_position_indicator, ''));
184
- }
185
-
186
176
  /**
187
177
  * @param {string} str
188
178
  * @param {boolean} required
@@ -1,7 +1,7 @@
1
1
  /** @import { Pattern } from 'estree' */
2
2
  /** @import { Parser } from '../index.js' */
3
3
  import { match_bracket } from '../utils/bracket.js';
4
- import { parse_expression_at } from '../acorn.js';
4
+ import { parse_expression_at, remove_parens } from '../acorn.js';
5
5
  import { regex_not_newline_characters } from '../../patterns.js';
6
6
  import * as e from '../../../errors.js';
7
7
 
@@ -35,38 +35,32 @@ export default function read_pattern(parser) {
35
35
 
36
36
  const pattern_string = parser.template.slice(start, i);
37
37
 
38
- try {
39
- // the length of the `space_with_newline` has to be start - 1
40
- // because we added a `(` in front of the pattern_string,
41
- // which shifted the entire string to right by 1
42
- // so we offset it by removing 1 character in the `space_with_newline`
43
- // to achieve that, we remove the 1st space encountered,
44
- // so it will not affect the `column` of the node
45
- let space_with_newline = parser.template
46
- .slice(0, start)
47
- .replace(regex_not_newline_characters, ' ');
48
- const first_space = space_with_newline.indexOf(' ');
49
- space_with_newline =
50
- space_with_newline.slice(0, first_space) + space_with_newline.slice(first_space + 1);
51
-
52
- const expression = /** @type {any} */ (
53
- parse_expression_at(
54
- `${space_with_newline}(${pattern_string} = 1)`,
55
- parser.root.comments,
56
- parser.ts,
57
- start - 1
58
- )
59
- ).left;
60
-
61
- expression.typeAnnotation = read_type_annotation(parser);
62
- if (expression.typeAnnotation) {
63
- expression.end = expression.typeAnnotation.end;
64
- }
65
-
66
- return expression;
67
- } catch (error) {
68
- parser.acorn_error(error);
38
+ // the length of the `space_with_newline` has to be start - 1
39
+ // because we added a `(` in front of the pattern_string,
40
+ // which shifted the entire string to right by 1
41
+ // so we offset it by removing 1 character in the `space_with_newline`
42
+ // to achieve that, we remove the 1st space encountered,
43
+ // so it will not affect the `column` of the node
44
+ let space_with_newline = parser.template
45
+ .slice(0, start)
46
+ .replace(regex_not_newline_characters, ' ');
47
+ const first_space = space_with_newline.indexOf(' ');
48
+ space_with_newline =
49
+ space_with_newline.slice(0, first_space) + space_with_newline.slice(first_space + 1);
50
+
51
+ /** @type {any} */
52
+ let expression = remove_parens(
53
+ parse_expression_at(parser, `${space_with_newline}(${pattern_string} = 1)`, start - 1)
54
+ );
55
+
56
+ expression = expression.left;
57
+
58
+ expression.typeAnnotation = read_type_annotation(parser);
59
+ if (expression.typeAnnotation) {
60
+ expression.end = expression.typeAnnotation.end;
69
61
  }
62
+
63
+ return expression;
70
64
  }
71
65
 
72
66
  /**
@@ -92,13 +86,13 @@ function read_type_annotation(parser) {
92
86
  // parameters as part of a sequence expression instead, and will then error on optional
93
87
  // parameters (`?:`). Therefore replace that sequence with something that will not error.
94
88
  parser.template.slice(parser.index).replace(/\?\s*:/g, ':');
95
- let expression = parse_expression_at(template, parser.root.comments, parser.ts, a);
89
+ let expression = remove_parens(parse_expression_at(parser, template, a));
96
90
 
97
91
  // `foo: bar = baz` gets mangled — fix it
98
92
  if (expression.type === 'AssignmentExpression') {
99
93
  let b = expression.right.start;
100
94
  while (template[b] !== '=') b -= 1;
101
- expression = parse_expression_at(template.slice(0, b), parser.root.comments, parser.ts, a);
95
+ expression = remove_parens(parse_expression_at(parser, template.slice(0, b), a));
102
96
  }
103
97
 
104
98
  // `array as item: string, index` becomes `string, index`, which is mistaken as a sequence expression - fix that
@@ -1,6 +1,6 @@
1
1
  /** @import { Expression } from 'estree' */
2
2
  /** @import { Parser } from '../index.js' */
3
- import { parse_expression_at } from '../acorn.js';
3
+ import { parse_expression_at, remove_parens } from '../acorn.js';
4
4
  import { regex_whitespace } from '../../patterns.js';
5
5
  import * as e from '../../../errors.js';
6
6
  import { find_matching_bracket } from '../utils/bracket.js';
@@ -34,50 +34,16 @@ export function get_loose_identifier(parser, opening_token) {
34
34
  */
35
35
  export default function read_expression(parser, opening_token, disallow_loose) {
36
36
  try {
37
- let comment_index = parser.root.comments.length;
38
-
39
- const node = parse_expression_at(
40
- parser.template,
41
- parser.root.comments,
42
- parser.ts,
43
- parser.index
44
- );
45
-
46
- let num_parens = 0;
47
-
48
- let i = parser.root.comments.length;
49
- while (i-- > comment_index) {
50
- const comment = parser.root.comments[i];
51
- if (comment.end < node.start) {
52
- parser.index = comment.end;
53
- break;
54
- }
55
- }
56
-
57
- for (let i = parser.index; i < /** @type {number} */ (node.start); i += 1) {
58
- if (parser.template[i] === '(') num_parens += 1;
59
- }
37
+ const node = parse_expression_at(parser, parser.template, parser.index);
60
38
 
61
39
  let index = /** @type {number} */ (node.end);
62
40
 
63
41
  const last_comment = parser.root.comments.at(-1);
64
42
  if (last_comment && last_comment.end > index) index = last_comment.end;
65
43
 
66
- while (num_parens > 0) {
67
- const char = parser.template[index];
68
-
69
- if (char === ')') {
70
- num_parens -= 1;
71
- } else if (!regex_whitespace.test(char)) {
72
- e.expected_token(index, ')');
73
- }
74
-
75
- index += 1;
76
- }
77
-
78
44
  parser.index = index;
79
45
 
80
- return /** @type {Expression} */ (node);
46
+ return /** @type {Expression} */ (remove_parens(node));
81
47
  } catch (err) {
82
48
  // If we are in an each loop we need the error to be thrown in cases like
83
49
  // `as { y = z }` so we still throw and handle the error there
@@ -88,6 +54,6 @@ export default function read_expression(parser, opening_token, disallow_loose) {
88
54
  }
89
55
  }
90
56
 
91
- parser.acorn_error(err);
57
+ throw err;
92
58
  }
93
59
  }
@@ -31,14 +31,7 @@ export function read_script(parser, start, attributes) {
31
31
  parser.template.slice(0, script_start).replace(regex_not_newline_characters, ' ') + data;
32
32
  parser.read(regex_starts_with_closing_script_tag);
33
33
 
34
- /** @type {Program} */
35
- let ast;
36
-
37
- try {
38
- ast = acorn.parse(source, parser.root.comments, parser.ts, true);
39
- } catch (err) {
40
- parser.acorn_error(err);
41
- }
34
+ const ast = acorn.parse(source, parser.root.comments, parser.ts, true);
42
35
 
43
36
  ast.start = script_start;
44
37
 
@@ -392,12 +392,7 @@ function open(parser) {
392
392
 
393
393
  let function_expression = matched
394
394
  ? /** @type {ArrowFunctionExpression} */ (
395
- parse_expression_at(
396
- prelude + `${params} => {}`,
397
- parser.root.comments,
398
- parser.ts,
399
- params_start
400
- )
395
+ parse_expression_at(parser, prelude + `${params} => {}`, params_start)
401
396
  )
402
397
  : { params: [] };
403
398
 
@@ -10,7 +10,7 @@ export function visit_function(node, context) {
10
10
  for (const [name] of context.state.scope.references) {
11
11
  const binding = context.state.scope.get(name);
12
12
 
13
- if (binding && binding.scope.function_depth < context.state.scope.function_depth) {
13
+ if (binding && binding.scope !== context.state.scope) {
14
14
  context.state.expression.references.add(binding);
15
15
  }
16
16
  }
@@ -352,7 +352,7 @@ export function client_component(analysis, options) {
352
352
  )
353
353
  );
354
354
  } else if (dev) {
355
- component_returned_object.push(b.spread(b.call(b.id('$.legacy_api'))));
355
+ component_returned_object.unshift(b.spread(b.call(b.id('$.legacy_api'))));
356
356
  }
357
357
 
358
358
  const push_args = [b.id('$$props'), b.literal(analysis.runes)];
@@ -42,6 +42,7 @@ import { DEV } from 'esm-env';
42
42
  import { derived_safe_equal } from '../../reactivity/deriveds.js';
43
43
  import { current_batch } from '../../reactivity/batch.js';
44
44
  import * as e from '../../errors.js';
45
+ import { tag } from '../../dev/tracing.js';
45
46
 
46
47
  // When making substantive changes to this file, validate them with the each block stress test:
47
48
  // https://svelte.dev/playground/1972b2cf46564476ad8c8c6405b23b7b
@@ -205,6 +206,10 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
205
206
  return is_array(collection) ? collection : collection == null ? [] : array_from(collection);
206
207
  });
207
208
 
209
+ if (DEV) {
210
+ tag(each_array, '{#each ...}');
211
+ }
212
+
208
213
  /** @type {V[]} */
209
214
  var array;
210
215
 
@@ -172,6 +172,12 @@ export class Batch {
172
172
  */
173
173
  #skipped_branches = new Map();
174
174
 
175
+ /**
176
+ * Inverse of #skipped_branches which we need to tell prior batches to unskip them when committing
177
+ * @type {Set<Effect>}
178
+ */
179
+ #unskipped_branches = new Set();
180
+
175
181
  is_fork = false;
176
182
 
177
183
  #decrement_queued = false;
@@ -215,28 +221,31 @@ export class Batch {
215
221
  if (!this.#skipped_branches.has(effect)) {
216
222
  this.#skipped_branches.set(effect, { d: [], m: [] });
217
223
  }
224
+ this.#unskipped_branches.delete(effect);
218
225
  }
219
226
 
220
227
  /**
221
228
  * Remove an effect from the #skipped_branches map and reschedule
222
229
  * any tracked dirty/maybe_dirty child effects
223
230
  * @param {Effect} effect
231
+ * @param {(e: Effect) => void} callback
224
232
  */
225
- unskip_effect(effect) {
233
+ unskip_effect(effect, callback = (e) => this.schedule(e)) {
226
234
  var tracked = this.#skipped_branches.get(effect);
227
235
  if (tracked) {
228
236
  this.#skipped_branches.delete(effect);
229
237
 
230
238
  for (var e of tracked.d) {
231
239
  set_signal_status(e, DIRTY);
232
- this.schedule(e);
240
+ callback(e);
233
241
  }
234
242
 
235
243
  for (e of tracked.m) {
236
244
  set_signal_status(e, MAYBE_DIRTY);
237
- this.schedule(e);
245
+ callback(e);
238
246
  }
239
247
  }
248
+ this.#unskipped_branches.add(effect);
240
249
  }
241
250
 
242
251
  #process() {
@@ -349,7 +358,9 @@ export class Batch {
349
358
  next_batch.#process();
350
359
  }
351
360
 
352
- if (!batches.has(this)) {
361
+ // In sync mode flushSync can cause #commit to wrongfully think that there needs to be a rebase, so we only do it in async mode
362
+ // TODO fix the underlying cause, otherwise this will likely regress when non-async mode is removed
363
+ if (async_mode_flag && !batches.has(this)) {
353
364
  this.#commit();
354
365
  }
355
366
  }
@@ -419,18 +430,22 @@ export class Batch {
419
430
  * Associate a change to a given source with the current
420
431
  * batch, noting its previous and current values
421
432
  * @param {Value} source
422
- * @param {any} old_value
433
+ * @param {any} value
423
434
  * @param {boolean} [is_derived]
424
435
  */
425
- capture(source, old_value, is_derived = false) {
426
- if (old_value !== UNINITIALIZED && !this.previous.has(source)) {
427
- this.previous.set(source, old_value);
436
+ capture(source, value, is_derived = false) {
437
+ if (source.v !== UNINITIALIZED && !this.previous.has(source)) {
438
+ this.previous.set(source, source.v);
428
439
  }
429
440
 
430
441
  // Don't save errors in `batch_values`, or they won't be thrown in `runtime.js#get`
431
442
  if ((source.f & ERROR_VALUE) === 0) {
432
- this.current.set(source, [source.v, is_derived]);
433
- batch_values?.set(source, source.v);
443
+ this.current.set(source, [value, is_derived]);
444
+ batch_values?.set(source, value);
445
+ }
446
+
447
+ if (!this.is_fork) {
448
+ source.v = value;
434
449
  }
435
450
  }
436
451
 
@@ -526,6 +541,19 @@ export class Batch {
526
541
  invariant(batch.#roots.length === 0, 'Batch has scheduled roots');
527
542
  }
528
543
 
544
+ // A batch was unskipped in a later batch -> tell prior batches to unskip it, too
545
+ if (is_earlier) {
546
+ for (const unskipped of this.#unskipped_branches) {
547
+ batch.unskip_effect(unskipped, (e) => {
548
+ if ((e.f & (BLOCK_EFFECT | ASYNC)) !== 0) {
549
+ batch.schedule(e);
550
+ } else {
551
+ batch.#defer_effects([e]);
552
+ }
553
+ });
554
+ }
555
+ }
556
+
529
557
  batch.activate();
530
558
 
531
559
  /** @type {Set<Value>} */
@@ -787,6 +815,7 @@ export class Batch {
787
815
  }
788
816
  }
789
817
 
818
+ // TODO Svelte@6 think about removing the callback argument.
790
819
  /**
791
820
  * Synchronously flush any pending updates.
792
821
  * Returns void if no callback is provided, otherwise returns the result of calling the callback.
@@ -1162,11 +1191,6 @@ export function fork(fn) {
1162
1191
 
1163
1192
  flushSync(fn);
1164
1193
 
1165
- // revert state changes
1166
- for (var [source, value] of batch.previous) {
1167
- source.v = value;
1168
- }
1169
-
1170
1194
  return {
1171
1195
  commit: async () => {
1172
1196
  if (committed) {
@@ -384,7 +384,6 @@ export function execute_derived(derived) {
384
384
  * @returns {void}
385
385
  */
386
386
  export function update_derived(derived) {
387
- var old_value = derived.v;
388
387
  var value = execute_derived(derived);
389
388
 
390
389
  if (!derived.equals(value)) {
@@ -395,8 +394,11 @@ export function update_derived(derived) {
395
394
  // otherwise, the next time we get here after a 'real world' state
396
395
  // change, `derived.equals` may incorrectly return `true`
397
396
  if (!current_batch?.is_fork || derived.deps === null) {
398
- derived.v = value;
399
- current_batch?.capture(derived, old_value, true);
397
+ if (current_batch !== null) {
398
+ current_batch.capture(derived, value, true);
399
+ } else {
400
+ derived.v = value;
401
+ }
400
402
 
401
403
  // deriveds without dependencies should never be recomputed
402
404
  if (derived.deps === null) {
@@ -180,18 +180,10 @@ export function set(source, value, should_proxy = false) {
180
180
  */
181
181
  export function internal_set(source, value, updated_during_traversal = null) {
182
182
  if (!source.equals(value)) {
183
- var old_value = source.v;
184
-
185
- if (is_destroying_effect) {
186
- old_values.set(source, value);
187
- } else {
188
- old_values.set(source, old_value);
189
- }
190
-
191
- source.v = value;
183
+ old_values.set(source, is_destroying_effect ? value : source.v);
192
184
 
193
185
  var batch = Batch.ensure();
194
- batch.capture(source, old_value);
186
+ batch.capture(source, value);
195
187
 
196
188
  if (DEV) {
197
189
  if (tracing_mode_flag || active_effect !== null) {
@@ -399,7 +399,14 @@ function remove_reaction(signal, dependency) {
399
399
  derived.f &= ~WAS_MARKED;
400
400
  }
401
401
 
402
- update_derived_status(derived);
402
+ // In a fork it's possible that a derived is executed and gets reactions, then commits, but is
403
+ // never re-executed. This is possible when the derived is only executed once in the context
404
+ // of a new branch which happens before fork.commit() runs. In this case, the derived still has
405
+ // UNINITIALIZED as its value, and then when it's loosing its reactions we need to ensure it stays
406
+ // DIRTY so it is reexecuted once someone wants its value again.
407
+ if (derived.v !== UNINITIALIZED) {
408
+ update_derived_status(derived);
409
+ }
403
410
 
404
411
  // freeze any effects inside this derived
405
412
  freeze_derived_effects(derived);
@@ -105,6 +105,18 @@ export function invalid_csp() {
105
105
  throw error;
106
106
  }
107
107
 
108
+ /**
109
+ * The `idPrefix` option cannot include `--`.
110
+ * @returns {never}
111
+ */
112
+ export function invalid_id_prefix() {
113
+ const error = new Error(`invalid_id_prefix\nThe \`idPrefix\` option cannot include \`--\`.\nhttps://svelte.dev/e/invalid_id_prefix`);
114
+
115
+ error.name = 'Svelte error';
116
+
117
+ throw error;
118
+ }
119
+
108
120
  /**
109
121
  * `%name%(...)` is not available on the server
110
122
  * @param {string} name
@@ -759,6 +759,10 @@ export class Renderer {
759
759
  * @returns {Renderer}
760
760
  */
761
761
  static #open_render(mode, component, options) {
762
+ if (options.idPrefix?.includes('--')) {
763
+ e.invalid_id_prefix();
764
+ }
765
+
762
766
  var previous_context = ssr_context;
763
767
 
764
768
  try {
@@ -95,6 +95,10 @@ export class SvelteDate extends Date {
95
95
  return date_proto[method].apply(this, args);
96
96
  });
97
97
 
98
+ if (DEV) {
99
+ tag(d, `SvelteDate.${method}()`);
100
+ }
101
+
98
102
  this.#deriveds.set(method, d);
99
103
 
100
104
  set_active_reaction(reaction);
package/src/version.js CHANGED
@@ -4,5 +4,5 @@
4
4
  * The current version, as set in package.json.
5
5
  * @type {string}
6
6
  */
7
- export const VERSION = '5.55.1';
7
+ export const VERSION = '5.55.2';
8
8
  export const PUBLIC_VERSION = '5';