svelte 5.57.0 → 5.57.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.
Files changed (78) hide show
  1. package/compiler/index.js +1 -1
  2. package/package.json +8 -8
  3. package/src/compiler/errors.js +10 -0
  4. package/src/compiler/migrate/index.js +15 -4
  5. package/src/compiler/phases/1-parse/acorn.js +36 -2
  6. package/src/compiler/phases/1-parse/index.js +23 -22
  7. package/src/compiler/phases/1-parse/read/context.js +3 -18
  8. package/src/compiler/phases/1-parse/read/expression.js +110 -2
  9. package/src/compiler/phases/1-parse/read/script.js +1 -1
  10. package/src/compiler/phases/1-parse/read/style.js +3 -5
  11. package/src/compiler/phases/1-parse/state/element.js +68 -40
  12. package/src/compiler/phases/1-parse/state/tag.js +8 -6
  13. package/src/compiler/phases/1-parse/utils/html.js +2 -0
  14. package/src/compiler/phases/1-parse/utils/whitespace.js +18 -0
  15. package/src/compiler/phases/2-analyze/css/css-prune.js +7 -6
  16. package/src/compiler/phases/2-analyze/index.js +1 -1
  17. package/src/compiler/phases/2-analyze/visitors/BindDirective.js +1 -1
  18. package/src/compiler/phases/2-analyze/visitors/ClassDeclaration.js +1 -1
  19. package/src/compiler/phases/2-analyze/visitors/FunctionDeclaration.js +1 -1
  20. package/src/compiler/phases/2-analyze/visitors/Identifier.js +1 -2
  21. package/src/compiler/phases/2-analyze/visitors/LetDirective.js +22 -0
  22. package/src/compiler/phases/2-analyze/visitors/SvelteBody.js +1 -1
  23. package/src/compiler/phases/2-analyze/visitors/SvelteDocument.js +1 -1
  24. package/src/compiler/phases/2-analyze/visitors/SvelteWindow.js +1 -1
  25. package/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +2 -2
  26. package/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js +1 -1
  27. package/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js +3 -3
  28. package/src/compiler/phases/2-analyze/visitors/shared/utils.js +0 -38
  29. package/src/compiler/phases/3-transform/client/utils.js +0 -38
  30. package/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +2 -2
  31. package/src/compiler/phases/3-transform/client/visitors/AwaitExpression.js +2 -1
  32. package/src/compiler/phases/3-transform/client/visitors/CallExpression.js +1 -2
  33. package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +3 -8
  34. package/src/compiler/phases/3-transform/client/visitors/shared/events.js +3 -2
  35. package/src/compiler/phases/3-transform/server/visitors/shared/element.js +8 -0
  36. package/src/compiler/phases/3-transform/utils.js +1 -1
  37. package/src/compiler/phases/nodes.js +30 -0
  38. package/src/compiler/phases/scope.js +85 -2
  39. package/src/compiler/print/index.js +3 -1
  40. package/src/compiler/state.js +9 -5
  41. package/src/compiler/utils/ast.js +2 -5
  42. package/src/compiler/utils/compile_diagnostic.js +1 -1
  43. package/src/compiler/utils/extract_svelte_ignore.js +1 -1
  44. package/src/compiler/utils/mapped_code.js +13 -1
  45. package/src/index-client.js +1 -1
  46. package/src/internal/client/constants.js +0 -9
  47. package/src/internal/client/dev/debug.js +0 -2
  48. package/src/internal/client/dev/tracing.js +3 -1
  49. package/src/internal/client/dom/blocks/boundary.js +39 -8
  50. package/src/internal/client/dom/blocks/each.js +8 -6
  51. package/src/internal/client/dom/blocks/svelte-element.js +3 -1
  52. package/src/internal/client/dom/css.js +1 -1
  53. package/src/internal/client/dom/elements/attributes.js +168 -148
  54. package/src/internal/client/dom/elements/bindings/document.js +3 -2
  55. package/src/internal/client/dom/elements/events.js +6 -1
  56. package/src/internal/client/dom/elements/transitions.js +3 -3
  57. package/src/internal/client/error-handling.js +5 -1
  58. package/src/internal/client/errors.js +0 -16
  59. package/src/internal/client/proxy.js +12 -7
  60. package/src/internal/client/reactivity/async.js +5 -0
  61. package/src/internal/client/reactivity/batch.js +103 -75
  62. package/src/internal/client/reactivity/deriveds.js +0 -3
  63. package/src/internal/client/reactivity/sources.js +31 -19
  64. package/src/internal/client/reactivity/utils.js +2 -23
  65. package/src/internal/client/runtime.js +18 -25
  66. package/src/internal/server/context.js +9 -2
  67. package/src/internal/server/index.js +9 -2
  68. package/src/internal/server/renderer.js +101 -69
  69. package/src/internal/shared/errors.js +16 -0
  70. package/src/reactivity/date.js +2 -2
  71. package/src/reactivity/url-search-params.js +1 -1
  72. package/src/version.js +1 -1
  73. package/types/index.d.ts.map +1 -1
  74. package/src/compiler/phases/1-parse/utils/create.js +0 -16
  75. package/src/compiler/phases/2-analyze/visitors/shared/special-element.js +0 -16
  76. package/src/compiler/utils/push_array.js +0 -13
  77. /package/src/compiler/{phases/2-analyze/utils → utils}/check_graph_for_cycles.js +0 -0
  78. /package/src/compiler/{phases/1-parse/utils → utils}/fuzzymatch.js +0 -0
@@ -3,11 +3,10 @@
3
3
  /** @import { Parser } from '../index.js' */
4
4
  import { walk } from 'zimmerframe';
5
5
  import * as e from '../../../errors.js';
6
- import { ExpressionMetadata } from '../../nodes.js';
6
+ import { create_fragment, ExpressionMetadata } from '../../nodes.js';
7
7
  import { parse_expression_at, parse_statement_at } from '../acorn.js';
8
8
  import read_pattern from '../read/context.js';
9
9
  import read_expression, { get_loose_identifier } from '../read/expression.js';
10
- import { create_fragment } from '../utils/create.js';
11
10
  import { find_matching_bracket, match_bracket } from '../utils/bracket.js';
12
11
 
13
12
  const regex_whitespace_with_closing_curly_brace = /\s*}/y;
@@ -488,12 +487,13 @@ function open(parser) {
488
487
  parser.eat(')', true);
489
488
  }
490
489
 
491
- const prelude = parser.template.slice(0, params_start).replace(/\S/g, ' ');
492
- const params = parser.template.slice(params_start, parser.index);
493
-
494
490
  let function_expression = matched
495
491
  ? /** @type {ArrowFunctionExpression} */ (
496
- parse_expression_at(parser, prelude + `${params} => {}`, params_start)
492
+ parse_expression_at(
493
+ parser,
494
+ parser.template.slice(0, parser.index) + ' => {}',
495
+ params_start
496
+ )
497
497
  )
498
498
  : { params: [] };
499
499
 
@@ -532,6 +532,7 @@ function next(parser) {
532
532
  if (block.type === 'IfBlock') {
533
533
  if (!parser.eat('else')) e.expected_token(start, '{:else} or {:else if}');
534
534
  if (parser.eat('if')) e.block_invalid_elseif(start);
535
+ if (block.alternate) e.block_duplicate_clause(start, '{:else}');
535
536
 
536
537
  parser.allow_whitespace();
537
538
 
@@ -580,6 +581,7 @@ function next(parser) {
580
581
 
581
582
  if (block.type === 'EachBlock') {
582
583
  if (!parser.eat('else')) e.expected_token(start, '{:else}');
584
+ if (block.fallback) e.block_duplicate_clause(start, '{:else}');
583
585
 
584
586
  parser.allow_whitespace();
585
587
  parser.eat('}', true);
@@ -38,6 +38,8 @@ const entity_pattern_attr_value = get_entity_pattern(true);
38
38
  * @param {boolean} is_attribute_value
39
39
  */
40
40
  export function decode_character_references(html, is_attribute_value) {
41
+ if (html.indexOf('&') === -1) return html; // fast path
42
+
41
43
  const entity_pattern = is_attribute_value ? entity_pattern_attr_value : entity_pattern_content;
42
44
  return html.replace(
43
45
  entity_pattern,
@@ -0,0 +1,18 @@
1
+ /** @param {number} cc */
2
+ export function is_whitespace(cc) {
3
+ // fast path for common whitespace
4
+ if (cc === 32 || (cc <= 13 && cc >= 9)) return true;
5
+ // rare whitespace — \u00a0, \u1680, \u2000-\u200a, \u2028, \u2029, \u202f, \u205f, \u3000, \ufeff
6
+ if (cc < 160) return false;
7
+ return (
8
+ cc === 160 ||
9
+ cc === 5760 ||
10
+ (cc >= 8192 && cc <= 8202) ||
11
+ cc === 8232 ||
12
+ cc === 8233 ||
13
+ cc === 8239 ||
14
+ cc === 8287 ||
15
+ cc === 12288 ||
16
+ cc === 65279
17
+ );
18
+ }
@@ -145,6 +145,12 @@ export function prune(stylesheet, elements) {
145
145
  },
146
146
  ComplexSelector(node) {
147
147
  const selectors = get_relative_selectors(node);
148
+ const rule = /** @type {Compiler.AST.CSS.Rule} */ (node.metadata.rule);
149
+
150
+ // Global and ICSS export rules do not depend on an element in this component
151
+ if (every_is_global(selectors, 0, selectors.length, rule)) {
152
+ node.metadata.used = true;
153
+ }
148
154
 
149
155
  for (const element of elements) {
150
156
  seen.clear();
@@ -153,12 +159,7 @@ export function prune(stylesheet, elements) {
153
159
  // Elements rendered through <svelte:head> are not style-scopable.
154
160
  // Prevent css hash injection (class="s-...") on tags like <meta>, <link>, <script>.
155
161
  !is_inside_svelte_head(element) &&
156
- apply_selector(
157
- selectors,
158
- /** @type {Compiler.AST.CSS.Rule} */ (node.metadata.rule),
159
- element,
160
- BACKWARD
161
- )
162
+ apply_selector(selectors, rule, element, BACKWARD)
162
163
  ) {
163
164
  node.metadata.used = true;
164
165
  }
@@ -14,7 +14,7 @@ import {
14
14
  } from '../../utils/ast.js';
15
15
  import * as b from '#compiler/builders';
16
16
  import { Scope, ScopeRoot, create_scopes, get_rune, set_scope } from '../scope.js';
17
- import check_graph_for_cycles from './utils/check_graph_for_cycles.js';
17
+ import check_graph_for_cycles from '../../utils/check_graph_for_cycles.js';
18
18
  import { create_attribute, is_custom_element_node } from '../nodes.js';
19
19
  import { analyze_css } from './css/css-analyze.js';
20
20
  import { prune } from './css/css-prune.js';
@@ -9,7 +9,7 @@ import { validate_assignment } from './shared/utils.js';
9
9
  import * as e from '../../../errors.js';
10
10
  import * as w from '../../../warnings.js';
11
11
  import { binding_properties } from '../../bindings.js';
12
- import fuzzymatch from '../../1-parse/utils/fuzzymatch.js';
12
+ import fuzzymatch from '../../../utils/fuzzymatch.js';
13
13
  import { is_content_editable_binding, is_svg } from '../../../../utils.js';
14
14
  import { mark_subtree_dynamic } from './shared/fragment.js';
15
15
 
@@ -1,7 +1,7 @@
1
1
  /** @import { ClassDeclaration } from 'estree' */
2
2
  /** @import { Context } from '../types' */
3
3
  import * as w from '../../../warnings.js';
4
- import { validate_identifier_name } from './shared/utils.js';
4
+ import { validate_identifier_name } from '../../scope.js';
5
5
 
6
6
  /**
7
7
  * @param {ClassDeclaration} node
@@ -1,7 +1,7 @@
1
1
  /** @import { FunctionDeclaration } from 'estree' */
2
2
  /** @import { Context } from '../types' */
3
3
  import { visit_function } from './shared/function.js';
4
- import { validate_identifier_name } from './shared/utils.js';
4
+ import { validate_identifier_name } from '../../scope.js';
5
5
 
6
6
  /**
7
7
  * @param {FunctionDeclaration} node
@@ -1,12 +1,11 @@
1
1
  /** @import { Expression, Identifier } from 'estree' */
2
2
  /** @import { Context } from '../types' */
3
3
  import is_reference from 'is-reference';
4
- import { should_proxy } from '../../3-transform/client/utils.js';
4
+ import { should_proxy, get_rune } from '../../scope.js';
5
5
  import * as e from '../../../errors.js';
6
6
  import * as w from '../../../warnings.js';
7
7
  import { is_rune } from '../../../../utils.js';
8
8
  import { mark_subtree_dynamic } from './shared/fragment.js';
9
- import { get_rune } from '../../scope.js';
10
9
  import { is_component_node } from '../../nodes.js';
11
10
 
12
11
  /**
@@ -1,6 +1,7 @@
1
1
  /** @import { AST } from '#compiler' */
2
2
  /** @import { Context } from '../types' */
3
3
  import * as e from '../../../errors.js';
4
+ import { determine_slot } from '../../../utils/slot.js';
4
5
 
5
6
  /**
6
7
  * @param {AST.LetDirective} node
@@ -21,4 +22,25 @@ export function LetDirective(node, context) {
21
22
  ) {
22
23
  e.let_directive_invalid_placement(node);
23
24
  }
25
+
26
+ // an explicit `children` snippet replaces the default slot content, so the `let:`
27
+ // directive would never be provided. if the component has a `slot` attribute, the
28
+ // directive applies to the component itself instead, which is fine
29
+ if (
30
+ (parent.type === 'Component' ||
31
+ parent.type === 'SvelteComponent' ||
32
+ parent.type === 'SvelteSelf') &&
33
+ !determine_slot(parent) &&
34
+ parent.fragment.nodes.some(
35
+ (child) => child.type === 'SnippetBlock' && child.expression.name === 'children'
36
+ )
37
+ ) {
38
+ const { expression } = node;
39
+ const pattern =
40
+ expression === null || (expression.type === 'Identifier' && expression.name === node.name)
41
+ ? node.name
42
+ : `${node.name}: ${context.state.analysis.source.slice(expression.start, expression.end)}`;
43
+
44
+ e.let_directive_snippet_conflict(node, pattern);
45
+ }
24
46
  }
@@ -2,7 +2,7 @@
2
2
  /** @import { Context } from '../types' */
3
3
  import * as e from '../../../errors.js';
4
4
  import { is_event_attribute } from '../../../utils/ast.js';
5
- import { disallow_children } from './shared/special-element.js';
5
+ import { disallow_children } from '../../nodes.js';
6
6
  import { check_global_event_reference } from './shared/utils.js';
7
7
 
8
8
  /**
@@ -1,6 +1,6 @@
1
1
  /** @import { AST } from '#compiler' */
2
2
  /** @import { Context } from '../types' */
3
- import { disallow_children } from './shared/special-element.js';
3
+ import { disallow_children } from '../../nodes.js';
4
4
  import * as e from '../../../errors.js';
5
5
  import { is_event_attribute } from '../../../utils/ast.js';
6
6
  import { check_global_event_reference } from './shared/utils.js';
@@ -1,6 +1,6 @@
1
1
  /** @import { AST } from '#compiler' */
2
2
  /** @import { Context } from '../types' */
3
- import { disallow_children } from './shared/special-element.js';
3
+ import { disallow_children } from '../../nodes.js';
4
4
  import * as e from '../../../errors.js';
5
5
  import { is_event_attribute } from '../../../utils/ast.js';
6
6
  import { check_global_event_reference } from './shared/utils.js';
@@ -1,8 +1,8 @@
1
1
  /** @import { Expression, Identifier, Literal, VariableDeclarator } from 'estree' */
2
2
  /** @import { Binding } from '#compiler' */
3
3
  /** @import { Context } from '../types' */
4
- import { get_rune } from '../../scope.js';
5
- import { ensure_no_module_import_conflict, validate_identifier_name } from './shared/utils.js';
4
+ import { get_rune, validate_identifier_name } from '../../scope.js';
5
+ import { ensure_no_module_import_conflict } from './shared/utils.js';
6
6
  import * as e from '../../../errors.js';
7
7
  import * as w from '../../../warnings.js';
8
8
  import { extract_paths } from '../../../utils/ast.js';
@@ -4,7 +4,7 @@ import { roles as roles_map, elementRoles } from 'aria-query';
4
4
  import { AXObjects, elementAXObjects } from 'axobject-query';
5
5
 
6
6
  export const aria_attributes =
7
- 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(
7
+ 'activedescendant atomic autocomplete braillelabel brailleroledescription busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(
8
8
  ' '
9
9
  );
10
10
 
@@ -45,7 +45,7 @@ import {
45
45
  import { is_event_attribute, is_text_attribute } from '../../../../../utils/ast.js';
46
46
  import { list } from '../../../../../utils/string.js';
47
47
  import { walk } from 'zimmerframe';
48
- import fuzzymatch from '../../../../1-parse/utils/fuzzymatch.js';
48
+ import fuzzymatch from '../../../../../utils/fuzzymatch.js';
49
49
  import { is_content_editable_binding } from '../../../../../../utils.js';
50
50
  import * as w from '../../../../../warnings.js';
51
51
 
@@ -173,8 +173,8 @@ export function check_element(node, context) {
173
173
  current_role === get_implicit_role(node.name, attribute_map) &&
174
174
  // <ul role="list"> is ok because CSS list-style:none removes the semantics and this is a way to bring them back
175
175
  !['ul', 'ol', 'li', 'menu'].includes(node.name) &&
176
- // <a role="link" /> is ok because without href the a tag doesn't have a role of link
177
- !(node.name === 'a' && !attribute_map.has('href'))
176
+ // <a role="link" /> and <area role="link" /> are ok because without href they don't have a role of link
177
+ !((node.name === 'a' || node.name === 'area') && !attribute_map.has('href'))
178
178
  ) {
179
179
  w.a11y_no_redundant_roles(attribute, current_role);
180
180
  }
@@ -246,44 +246,6 @@ export function is_pure(node, context) {
246
246
  return false;
247
247
  }
248
248
 
249
- /**
250
- * Checks if the name is valid, which it is when it's not starting with (or is) a dollar sign or if it's a function parameter.
251
- * The second argument is the depth of the scope, which is there for backwards compatibility reasons: In Svelte 4, you
252
- * were allowed to define `$`-prefixed variables anywhere below the top level of components. Once legacy mode is gone, this
253
- * argument can be removed / the call sites adjusted accordingly.
254
- * @param {Binding | null} binding
255
- * @param {number | undefined} [function_depth]
256
- */
257
- export function validate_identifier_name(binding, function_depth) {
258
- if (!binding) return;
259
-
260
- const declaration_kind = binding.declaration_kind;
261
-
262
- if (
263
- declaration_kind !== 'synthetic' &&
264
- declaration_kind !== 'param' &&
265
- declaration_kind !== 'rest_param' &&
266
- (!function_depth || function_depth <= 1)
267
- ) {
268
- const node = binding.node;
269
-
270
- if (node.name === '$') {
271
- e.dollar_binding_invalid(node);
272
- } else if (
273
- node.name.startsWith('$') &&
274
- // import type { $Type } from "" - these are normally already filtered out,
275
- // but for the migration they aren't, and throwing here is preventing the migration to complete
276
- // TODO -> once migration script is gone we can remove this check
277
- !(
278
- binding.initial?.type === 'ImportDeclaration' &&
279
- /** @type {any} */ (binding.initial).importKind === 'type'
280
- )
281
- ) {
282
- e.dollar_prefix_invalid(node);
283
- }
284
- }
285
- }
286
-
287
249
  /**
288
250
  * Checks that the exported name is not a derived or reassigned state variable.
289
251
  * @param {Node} node
@@ -127,44 +127,6 @@ export function is_prop_source(binding, state) {
127
127
  );
128
128
  }
129
129
 
130
- /**
131
- * @param {Expression} node
132
- * @param {Scope | null} scope
133
- */
134
- export function should_proxy(node, scope) {
135
- if (
136
- !node ||
137
- node.type === 'Literal' ||
138
- node.type === 'TemplateLiteral' ||
139
- node.type === 'ArrowFunctionExpression' ||
140
- node.type === 'FunctionExpression' ||
141
- node.type === 'UnaryExpression' ||
142
- node.type === 'BinaryExpression' ||
143
- (node.type === 'Identifier' && node.name === 'undefined')
144
- ) {
145
- return false;
146
- }
147
-
148
- if (node.type === 'Identifier' && scope !== null) {
149
- const binding = scope.get(node.name);
150
- // Let's see if the reference is something that can be proxied
151
- if (
152
- binding !== null &&
153
- !binding.reassigned &&
154
- binding.initial !== null &&
155
- binding.initial.type !== 'FunctionDeclaration' &&
156
- binding.initial.type !== 'ClassDeclaration' &&
157
- binding.initial.type !== 'ImportDeclaration' &&
158
- binding.initial.type !== 'EachBlock' &&
159
- binding.initial.type !== 'SnippetBlock'
160
- ) {
161
- return should_proxy(binding.initial, null);
162
- }
163
- }
164
-
165
- return true;
166
- }
167
-
168
130
  /**
169
131
  * An async thunk. If an `await` inside restores the reaction context via `$.save`,
170
132
  * the body exits through `$.unsave` so the context cannot leak into foreign microtasks
@@ -9,10 +9,10 @@ import {
9
9
  is_expression_async
10
10
  } from '../../../../utils/ast.js';
11
11
  import { dev, locate_node } from '../../../../state.js';
12
- import { build_getter, should_proxy } from '../utils.js';
12
+ import { build_getter } from '../utils.js';
13
+ import { should_proxy, get_rune } from '../../../scope.js';
13
14
  import { visit_assignment_expression } from '../../shared/assignments.js';
14
15
  import { validate_mutation } from './shared/utils.js';
15
- import { get_rune } from '../../../scope.js';
16
16
  import { get_name } from '../../../nodes.js';
17
17
 
18
18
  /**
@@ -18,7 +18,8 @@ export function AwaitExpression(node, context) {
18
18
  // in dev, note which values are read inside a reactive expression,
19
19
  // but don't track them
20
20
  else if (dev && !is_ignored(node, 'await_reactivity_loss')) {
21
- return b.call(b.await(b.call('$.track_reactivity_loss', argument)));
21
+ // don't use b.await here, this way we preserve location information
22
+ return b.call({ ...node, argument: b.call('$.track_reactivity_loss', argument) });
22
23
  }
23
24
 
24
25
  return argument === node.argument ? node : { ...node, argument };
@@ -2,8 +2,7 @@
2
2
  /** @import { Context } from '../types' */
3
3
  import { dev, is_ignored } from '../../../../state.js';
4
4
  import * as b from '#compiler/builders';
5
- import { get_rune } from '../../../scope.js';
6
- import { should_proxy } from '../utils.js';
5
+ import { get_rune, should_proxy } from '../../../scope.js';
7
6
  import { get_inspect_args } from '../../utils.js';
8
7
 
9
8
  /**
@@ -5,14 +5,8 @@ import { dev, is_ignored, locate_node } from '../../../../state.js';
5
5
  import { extract_paths, save } from '../../../../utils/ast.js';
6
6
  import * as b from '#compiler/builders';
7
7
  import * as assert from '../../../../utils/assert.js';
8
- import { get_rune } from '../../../scope.js';
9
- import {
10
- async_thunk,
11
- get_prop_source,
12
- is_prop_source,
13
- is_state_source,
14
- should_proxy
15
- } from '../utils.js';
8
+ import { get_rune, should_proxy } from '../../../scope.js';
9
+ import { async_thunk, get_prop_source, is_prop_source, is_state_source } from '../utils.js';
16
10
  import { get_value } from './shared/declarations.js';
17
11
 
18
12
  /**
@@ -35,6 +29,7 @@ export function VariableDeclaration(node, context) {
35
29
  rune === '$inspect' ||
36
30
  rune === '$inspect.trace' ||
37
31
  rune === '$state.snapshot' ||
32
+ rune === '$state.eager' ||
38
33
  rune === '$host'
39
34
  ) {
40
35
  declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
@@ -119,8 +119,9 @@ export function build_event_handler(node, metadata, context) {
119
119
 
120
120
  // local variable can be assigned directly
121
121
  // except in dev mode where when need $.apply()
122
- // in order to handle warnings.
123
- if (!dev && binding?.declaration_kind !== 'import') {
122
+ // in order to handle warnings, or when it is
123
+ // assigned after a top-level `await`
124
+ if (!dev && binding?.declaration_kind !== 'import' && !binding?.blocker) {
124
125
  return handler;
125
126
  }
126
127
  }
@@ -80,6 +80,14 @@ export function build_element_attributes(node, context, transform) {
80
80
  ) {
81
81
  events_to_capture.add(attribute.name);
82
82
  }
83
+ } else if (
84
+ node.type === 'RegularElement' &&
85
+ node.name === 'input' &&
86
+ (attribute.name === 'defaultValue' || attribute.name === 'defaultChecked')
87
+ ) {
88
+ attributes.push(attribute);
89
+ // deopt to spread at runtime, where we can handle interaction of value/defaultValue etc
90
+ has_spread = true;
83
91
  // the defaultValue/defaultChecked properties don't exist as attributes
84
92
  } else if (attribute.name !== 'defaultValue' && attribute.name !== 'defaultChecked') {
85
93
  if (attribute.name === 'class') {
@@ -9,7 +9,7 @@ import {
9
9
  import * as e from '../../errors.js';
10
10
  import { walk } from 'zimmerframe';
11
11
  import { extract_identifiers } from '../../utils/ast.js';
12
- import check_graph_for_cycles from '../2-analyze/utils/check_graph_for_cycles.js';
12
+ import check_graph_for_cycles from '../../utils/check_graph_for_cycles.js';
13
13
  import is_reference from 'is-reference';
14
14
  import { set_scope } from '../scope.js';
15
15
 
@@ -1,6 +1,7 @@
1
1
  /** @import { Expression, PrivateIdentifier, SourceLocation } from 'estree' */
2
2
  /** @import { AST, Binding } from '#compiler' */
3
3
  import * as b from '#compiler/builders';
4
+ import * as e from '../errors.js';
4
5
 
5
6
  /**
6
7
  * All nodes that can appear elsewhere than the top level, have attributes and can contain children
@@ -45,6 +46,35 @@ export function is_custom_element_node(node) {
45
46
  );
46
47
  }
47
48
 
49
+ /**
50
+ * @param {boolean} transparent
51
+ * @returns {AST.Fragment}
52
+ */
53
+ export function create_fragment(transparent = false) {
54
+ return {
55
+ type: 'Fragment',
56
+ nodes: [],
57
+ metadata: {
58
+ transparent,
59
+ dynamic: false
60
+ }
61
+ };
62
+ }
63
+
64
+ /**
65
+ * @param {AST.SvelteBody | AST.SvelteDocument | AST.SvelteOptionsRaw | AST.SvelteWindow} node
66
+ */
67
+ export function disallow_children(node) {
68
+ const { nodes } = node.fragment;
69
+
70
+ if (nodes.length > 0) {
71
+ const first = nodes[0];
72
+ const last = nodes[nodes.length - 1];
73
+
74
+ e.svelte_meta_invalid_content({ start: first.start, end: last.end }, node.name);
75
+ }
76
+ }
77
+
48
78
  /**
49
79
  * @param {string} name
50
80
  * @param {SourceLocation | null} name_loc
@@ -14,7 +14,6 @@ import {
14
14
  } from '../utils/ast.js';
15
15
  import { is_reserved, is_rune } from '../../utils.js';
16
16
  import { determine_slot } from '../utils/slot.js';
17
- import { validate_identifier_name } from './2-analyze/visitors/shared/utils.js';
18
17
 
19
18
  const UNKNOWN = Symbol('unknown');
20
19
  /** Includes `BigInt` */
@@ -1233,6 +1232,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
1233
1232
 
1234
1233
  EachBlock(node, { state, visit }) {
1235
1234
  visit(node.expression);
1235
+ if (node.fallback) visit(node.fallback);
1236
1236
 
1237
1237
  // context and children are a new scope
1238
1238
  const scope = state.scope.child();
@@ -1278,7 +1278,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
1278
1278
  for (const child of node.body.nodes) {
1279
1279
  visit(child, { scope });
1280
1280
  }
1281
- if (node.fallback) visit(node.fallback, { scope });
1282
1281
 
1283
1282
  node.metadata = {
1284
1283
  expression: new ExpressionMetadata(),
@@ -1344,6 +1343,14 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
1344
1343
  }
1345
1344
 
1346
1345
  context.next({ scope: child_scope });
1346
+
1347
+ // the parameters and what the body declares end up in the same function
1348
+ const body_scope = /** @type {Scope} */ (scopes.get(node.body));
1349
+ for (const [name, binding] of body_scope.declarations) {
1350
+ if (child_scope.declarations.has(name)) {
1351
+ e.declaration_duplicate(binding.node, name);
1352
+ }
1353
+ }
1347
1354
  },
1348
1355
 
1349
1356
  Fragment: (node, context) => {
@@ -1469,3 +1476,79 @@ function get_global_keypath(node, scope) {
1469
1476
 
1470
1477
  return n.name + joined;
1471
1478
  }
1479
+
1480
+ /**
1481
+ * @param {Expression} node
1482
+ * @param {Scope | null} scope
1483
+ */
1484
+ export function should_proxy(node, scope) {
1485
+ if (
1486
+ !node ||
1487
+ node.type === 'Literal' ||
1488
+ node.type === 'TemplateLiteral' ||
1489
+ node.type === 'ArrowFunctionExpression' ||
1490
+ node.type === 'FunctionExpression' ||
1491
+ node.type === 'UnaryExpression' ||
1492
+ node.type === 'BinaryExpression' ||
1493
+ (node.type === 'Identifier' && node.name === 'undefined')
1494
+ ) {
1495
+ return false;
1496
+ }
1497
+
1498
+ if (node.type === 'Identifier' && scope !== null) {
1499
+ const binding = scope.get(node.name);
1500
+ // Let's see if the reference is something that can be proxied
1501
+ if (
1502
+ binding !== null &&
1503
+ !binding.reassigned &&
1504
+ binding.initial !== null &&
1505
+ binding.initial.type !== 'FunctionDeclaration' &&
1506
+ binding.initial.type !== 'ClassDeclaration' &&
1507
+ binding.initial.type !== 'ImportDeclaration' &&
1508
+ binding.initial.type !== 'EachBlock' &&
1509
+ binding.initial.type !== 'SnippetBlock'
1510
+ ) {
1511
+ return should_proxy(binding.initial, null);
1512
+ }
1513
+ }
1514
+
1515
+ return true;
1516
+ }
1517
+
1518
+ /**
1519
+ * Checks if the name is valid, which it is when it's not starting with (or is) a dollar sign or if it's a function parameter.
1520
+ * The second argument is the depth of the scope, which is there for backwards compatibility reasons: In Svelte 4, you
1521
+ * were allowed to define `$`-prefixed variables anywhere below the top level of components. Once legacy mode is gone, this
1522
+ * argument can be removed / the call sites adjusted accordingly.
1523
+ * @param {Binding | null} binding
1524
+ * @param {number | undefined} [function_depth]
1525
+ */
1526
+ export function validate_identifier_name(binding, function_depth) {
1527
+ if (!binding) return;
1528
+
1529
+ const declaration_kind = binding.declaration_kind;
1530
+
1531
+ if (
1532
+ declaration_kind !== 'synthetic' &&
1533
+ declaration_kind !== 'param' &&
1534
+ declaration_kind !== 'rest_param' &&
1535
+ (!function_depth || function_depth <= 1)
1536
+ ) {
1537
+ const node = binding.node;
1538
+
1539
+ if (node.name === '$') {
1540
+ e.dollar_binding_invalid(node);
1541
+ } else if (
1542
+ node.name.startsWith('$') &&
1543
+ // import type { $Type } from "" - these are normally already filtered out,
1544
+ // but for the migration they aren't, and throwing here is preventing the migration to complete
1545
+ // TODO -> once migration script is gone we can remove this check
1546
+ !(
1547
+ binding.initial?.type === 'ImportDeclaration' &&
1548
+ /** @type {any} */ (binding.initial).importKind === 'type'
1549
+ )
1550
+ ) {
1551
+ e.dollar_prefix_invalid(node);
1552
+ }
1553
+ }
1554
+ }
@@ -754,7 +754,9 @@ const svelte_visitors = (comments, state) => ({
754
754
  if (node.pending) {
755
755
  context.write('}');
756
756
  block(context, node.pending, state.preserve_whitespace > 0);
757
- context.write('{:');
757
+ if (node.then || node.catch) {
758
+ context.write('{:');
759
+ }
758
760
  } else {
759
761
  context.write(' ');
760
762
  }