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.
- package/compiler/index.js +1 -1
- package/package.json +8 -8
- package/src/compiler/errors.js +10 -0
- package/src/compiler/migrate/index.js +15 -4
- package/src/compiler/phases/1-parse/acorn.js +36 -2
- package/src/compiler/phases/1-parse/index.js +23 -22
- package/src/compiler/phases/1-parse/read/context.js +3 -18
- package/src/compiler/phases/1-parse/read/expression.js +110 -2
- package/src/compiler/phases/1-parse/read/script.js +1 -1
- package/src/compiler/phases/1-parse/read/style.js +3 -5
- package/src/compiler/phases/1-parse/state/element.js +68 -40
- package/src/compiler/phases/1-parse/state/tag.js +8 -6
- package/src/compiler/phases/1-parse/utils/html.js +2 -0
- package/src/compiler/phases/1-parse/utils/whitespace.js +18 -0
- package/src/compiler/phases/2-analyze/css/css-prune.js +7 -6
- package/src/compiler/phases/2-analyze/index.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/BindDirective.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/ClassDeclaration.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/FunctionDeclaration.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/Identifier.js +1 -2
- package/src/compiler/phases/2-analyze/visitors/LetDirective.js +22 -0
- package/src/compiler/phases/2-analyze/visitors/SvelteBody.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/SvelteDocument.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/SvelteWindow.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/VariableDeclarator.js +2 -2
- package/src/compiler/phases/2-analyze/visitors/shared/a11y/constants.js +1 -1
- package/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js +3 -3
- package/src/compiler/phases/2-analyze/visitors/shared/utils.js +0 -38
- package/src/compiler/phases/3-transform/client/utils.js +0 -38
- package/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js +2 -2
- package/src/compiler/phases/3-transform/client/visitors/AwaitExpression.js +2 -1
- package/src/compiler/phases/3-transform/client/visitors/CallExpression.js +1 -2
- package/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +3 -8
- package/src/compiler/phases/3-transform/client/visitors/shared/events.js +3 -2
- package/src/compiler/phases/3-transform/server/visitors/shared/element.js +8 -0
- package/src/compiler/phases/3-transform/utils.js +1 -1
- package/src/compiler/phases/nodes.js +30 -0
- package/src/compiler/phases/scope.js +85 -2
- package/src/compiler/print/index.js +3 -1
- package/src/compiler/state.js +9 -5
- package/src/compiler/utils/ast.js +2 -5
- package/src/compiler/utils/compile_diagnostic.js +1 -1
- package/src/compiler/utils/extract_svelte_ignore.js +1 -1
- package/src/compiler/utils/mapped_code.js +13 -1
- package/src/index-client.js +1 -1
- package/src/internal/client/constants.js +0 -9
- package/src/internal/client/dev/debug.js +0 -2
- package/src/internal/client/dev/tracing.js +3 -1
- package/src/internal/client/dom/blocks/boundary.js +39 -8
- package/src/internal/client/dom/blocks/each.js +8 -6
- package/src/internal/client/dom/blocks/svelte-element.js +3 -1
- package/src/internal/client/dom/css.js +1 -1
- package/src/internal/client/dom/elements/attributes.js +168 -148
- package/src/internal/client/dom/elements/bindings/document.js +3 -2
- package/src/internal/client/dom/elements/events.js +6 -1
- package/src/internal/client/dom/elements/transitions.js +3 -3
- package/src/internal/client/error-handling.js +5 -1
- package/src/internal/client/errors.js +0 -16
- package/src/internal/client/proxy.js +12 -7
- package/src/internal/client/reactivity/async.js +5 -0
- package/src/internal/client/reactivity/batch.js +103 -75
- package/src/internal/client/reactivity/deriveds.js +0 -3
- package/src/internal/client/reactivity/sources.js +31 -19
- package/src/internal/client/reactivity/utils.js +2 -23
- package/src/internal/client/runtime.js +18 -25
- package/src/internal/server/context.js +9 -2
- package/src/internal/server/index.js +9 -2
- package/src/internal/server/renderer.js +101 -69
- package/src/internal/shared/errors.js +16 -0
- package/src/reactivity/date.js +2 -2
- package/src/reactivity/url-search-params.js +1 -1
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
- package/src/compiler/phases/1-parse/utils/create.js +0 -16
- package/src/compiler/phases/2-analyze/visitors/shared/special-element.js +0 -16
- package/src/compiler/utils/push_array.js +0 -13
- /package/src/compiler/{phases/2-analyze/utils → utils}/check_graph_for_cycles.js +0 -0
- /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(
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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 '../../
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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
|
|
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 '
|
|
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" />
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 '
|
|
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
|
-
|
|
757
|
+
if (node.then || node.catch) {
|
|
758
|
+
context.write('{:');
|
|
759
|
+
}
|
|
758
760
|
} else {
|
|
759
761
|
context.write(' ');
|
|
760
762
|
}
|