Skip to content

Commit 1bfd839

Browse files
committed
Merge branch 'main' into inline-vars
2 parents 317282d + 363f4a0 commit 1bfd839

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+516
-64
lines changed

.changeset/brave-doors-compete.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: visit expression for `svelte:component` references

.changeset/chatty-snails-train.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure signal graph is consistent before triggering $inspect signals

.changeset/five-birds-check.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: widen ownership upon property access if necessary

.changeset/five-suns-roll.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: don't show `state_referenced_locally` warning on types

.changeset/fuzzy-tigers-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure locally mutated bindable props persist with spreading props

.changeset/rotten-actors-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure unowned derived signals correctly re-connect to graph

.changeset/selfish-trainers-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure inner script tags are properly removed

.changeset/strange-trains-destroy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
chore: improve ssr parent validation

.changeset/tame-frogs-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: prevent nullish snippet for rendering empty content

documentation/docs/98-reference/20-svelte.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte
33
---
44

5-
<!-- @include svelte -->
5+
> MODULE: svelte

documentation/docs/98-reference/21-svelte-action.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/action
33
---
44

5-
<!-- @include svelte/action -->
5+
> MODULE: svelte/action

documentation/docs/98-reference/21-svelte-animate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/animate
33
---
44

5-
<!-- @include svelte/animate -->
5+
> MODULE: svelte/animate

documentation/docs/98-reference/21-svelte-compiler.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/compiler
33
---
44

5-
<!-- @include svelte/compiler -->
5+
> MODULE: svelte/compiler

documentation/docs/98-reference/21-svelte-easing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/easing
33
---
44

5-
<!-- @include svelte/easing -->
5+
> MODULE: svelte/easing

documentation/docs/98-reference/21-svelte-events.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/events
33
---
44

5-
<!-- @include svelte/events -->
5+
> MODULE: svelte/events

documentation/docs/98-reference/21-svelte-legacy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/legacy
33
---
44

5-
<!-- @include svelte/legacy -->
5+
> MODULE: svelte/legacy

documentation/docs/98-reference/21-svelte-motion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/motion
33
---
44

5-
<!-- @include svelte/motion -->
5+
> MODULE: svelte/motion

documentation/docs/98-reference/21-svelte-reactivity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/reactivity
33
---
44

5-
<!-- @include svelte/reactivity -->
5+
> MODULE: svelte/reactivity

documentation/docs/98-reference/21-svelte-server.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/server
33
---
44

5-
<!-- @include svelte/server -->
5+
> MODULE: svelte/server

documentation/docs/98-reference/21-svelte-store.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/store
33
---
44

5-
<!-- @include svelte/store -->
5+
> MODULE: svelte/store

documentation/docs/98-reference/21-svelte-transition.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
title: svelte/transition
33
---
44

5-
<!-- @include svelte/transition -->
5+
> MODULE: svelte/transition

packages/svelte/elements.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,7 @@ export interface SvelteHTMLElements {
19341934
| string
19351935
| undefined
19361936
| {
1937-
tag: string;
1937+
tag?: string;
19381938
shadow?: 'open' | 'none' | undefined;
19391939
props?:
19401940
| Record<

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848

4949
> Failed to hydrate the application
5050
51+
## invalid_snippet
52+
53+
> Could not `{@render}` snippet due to the expression being `null` or `undefined`. Consider using optional chaining `{@render snippet?.()}`
54+
5155
## lifecycle_legacy_only
5256

5357
> `%name%(...)` cannot be used in runes mode

packages/svelte/src/compiler/phases/1-parse/remove_typescript_nodes.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ const visitors = {
7373
TSNonNullExpression(node, context) {
7474
return context.visit(node.expression);
7575
},
76+
TSTypeAnnotation() {
77+
// This isn't correct, strictly speaking, and could result in invalid ASTs (like an empty statement within function parameters),
78+
// but esrap, our printing tool, just ignores these AST nodes at invalid positions, so it's fine
79+
return b.empty;
80+
},
7681
TSInterfaceDeclaration() {
7782
return b.empty;
7883
},
@@ -94,15 +99,6 @@ const visitors = {
9499
}
95100
return node.parameter;
96101
},
97-
Identifier(node) {
98-
if (node.typeAnnotation) {
99-
return {
100-
...node,
101-
typeAnnotation: null
102-
};
103-
}
104-
return node;
105-
},
106102
FunctionExpression: remove_this_param,
107103
FunctionDeclaration: remove_this_param,
108104
TSDeclareFunction() {

packages/svelte/src/compiler/phases/3-transform/client/visitors/RenderTag.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export function RenderTag(node, context) {
3131
let snippet_function = /** @type {Expression} */ (context.visit(callee));
3232

3333
if (node.metadata.dynamic) {
34+
// If we have a chain expression then ensure a nullish snippet function gets turned into an empty one
35+
if (node.expression.type === 'ChainExpression') {
36+
snippet_function = b.logical('??', snippet_function, b.id('$.noop'));
37+
}
38+
3439
context.state.init.push(
3540
b.stmt(b.call('$.snippet', context.state.node, b.thunk(snippet_function), ...args))
3641
);

packages/svelte/src/compiler/phases/scope.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
305305
default: context.state.scope.child()
306306
};
307307

308+
if (node.type === 'SvelteComponent') {
309+
context.visit(node.expression);
310+
}
311+
308312
const default_state = determine_slot(node)
309313
? context.state
310314
: { scope: node.metadata.scopes.default };
@@ -353,7 +357,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
353357
references.push([state.scope, { node, path: path.slice() }]);
354358
}
355359
},
356-
357360
LabeledStatement(node, { path, next }) {
358361
if (path.length > 1 || !allow_reactive_declarations) return next();
359362
if (node.label.name !== '$') return next();

packages/svelte/src/html-tree-validation.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,21 +162,23 @@ export function is_tag_valid_with_ancestor(tag, ancestors) {
162162
* Returns false if the tag is not allowed inside the parent tag such that it will result
163163
* in the browser repairing the HTML, which will likely result in an error during hydration.
164164
* @param {string} tag
165-
* @param {string} parent_tag
165+
* @param {string | null} parent_tag
166166
* @returns {boolean}
167167
*/
168168
export function is_tag_valid_with_parent(tag, parent_tag) {
169-
const disallowed = disallowed_children[parent_tag];
169+
if (parent_tag !== null) {
170+
const disallowed = disallowed_children[parent_tag];
170171

171-
if (disallowed) {
172-
if ('direct' in disallowed && disallowed.direct.includes(tag)) {
173-
return false;
174-
}
175-
if ('descendant' in disallowed && disallowed.descendant.includes(tag)) {
176-
return false;
177-
}
178-
if ('only' in disallowed && disallowed.only) {
179-
return disallowed.only.includes(tag);
172+
if (disallowed) {
173+
if ('direct' in disallowed && disallowed.direct.includes(tag)) {
174+
return false;
175+
}
176+
if ('descendant' in disallowed && disallowed.descendant.includes(tag)) {
177+
return false;
178+
}
179+
if ('only' in disallowed && disallowed.only) {
180+
return disallowed.only.includes(tag);
181+
}
180182
}
181183
}
182184

packages/svelte/src/internal/client/dom/blocks/snippet.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
1111
import { create_fragment_from_html } from '../reconciler.js';
1212
import { assign_nodes } from '../template.js';
1313
import * as w from '../../warnings.js';
14+
import * as e from '../../errors.js';
1415
import { DEV } from 'esm-env';
1516
import { get_first_child, get_next_sibling } from '../operations.js';
17+
import { noop } from '../../../shared/utils.js';
1618

1719
/**
1820
* @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn
@@ -25,7 +27,8 @@ export function snippet(node, get_snippet, ...args) {
2527
var anchor = node;
2628

2729
/** @type {SnippetFn | null | undefined} */
28-
var snippet;
30+
// @ts-ignore
31+
var snippet = noop;
2932

3033
/** @type {Effect | null} */
3134
var snippet_effect;
@@ -38,9 +41,11 @@ export function snippet(node, get_snippet, ...args) {
3841
snippet_effect = null;
3942
}
4043

41-
if (snippet) {
42-
snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(anchor, ...args));
44+
if (DEV && snippet == null) {
45+
e.invalid_snippet();
4346
}
47+
48+
snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(anchor, ...args));
4449
}, EFFECT_TRANSPARENT);
4550

4651
if (hydrating) {

packages/svelte/src/internal/client/dom/template.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,26 +187,41 @@ function run_scripts(node) {
187187
// scripts were SSR'd, in which case they will run
188188
if (hydrating) return;
189189

190+
const is_fragment = node.nodeType === 11;
190191
const scripts =
191192
/** @type {HTMLElement} */ (node).tagName === 'SCRIPT'
192193
? [/** @type {HTMLScriptElement} */ (node)]
193194
: node.querySelectorAll('script');
195+
const effect = /** @type {Effect} */ (current_effect);
196+
194197
for (const script of scripts) {
195-
var clone = document.createElement('script');
198+
const clone = document.createElement('script');
196199
for (var attribute of script.attributes) {
197200
clone.setAttribute(attribute.name, attribute.value);
198201
}
199202

200203
clone.textContent = script.textContent;
201204

205+
const replace = () => {
206+
// The script has changed - if it's at the edges, the effect now points at dead nodes
207+
if (is_fragment ? node.firstChild === script : node === script) {
208+
effect.nodes_start = clone;
209+
}
210+
if (is_fragment ? node.lastChild === script : node === script) {
211+
effect.nodes_end = clone;
212+
}
213+
214+
script.replaceWith(clone);
215+
};
216+
202217
// If node === script tag, replaceWith will do nothing because there's no parent yet,
203218
// waiting until that's the case using an effect solves this.
204219
// Don't do it in other circumstances or we could accidentally execute scripts
205220
// in an adjacent @html tag that was instantiated in the meantime.
206221
if (script === node) {
207-
queue_micro_task(() => script.replaceWith(clone));
222+
queue_micro_task(replace);
208223
} else {
209-
script.replaceWith(clone);
224+
replace();
210225
}
211226
}
212227
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,22 @@ export function hydration_failed() {
210210
}
211211
}
212212

213+
/**
214+
* Could not `{@render}` snippet due to the expression being `null` or `undefined`. Consider using optional chaining `{@render snippet?.()}`
215+
* @returns {never}
216+
*/
217+
export function invalid_snippet() {
218+
if (DEV) {
219+
const error = new Error(`invalid_snippet\nCould not \`{@render}\` snippet due to the expression being \`null\` or \`undefined\`. Consider using optional chaining \`{@render snippet?.()}\``);
220+
221+
error.name = 'Svelte error';
222+
throw error;
223+
} else {
224+
// TODO print a link to the documentation
225+
throw new Error("invalid_snippet");
226+
}
227+
}
228+
213229
/**
214230
* `%name%(...)` cannot be used in runes mode
215231
* @param {string} name

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,22 @@ export function proxy(value, parent = null, prev) {
131131

132132
if (s !== undefined) {
133133
var v = get(s);
134+
135+
// In case of something like `foo = bar.map(...)`, foo would have ownership
136+
// of the array itself, while the individual items would have ownership
137+
// of the component that created bar. That means if we later do `foo[0].baz = 42`,
138+
// we could get a false-positive ownership violation, since the two proxies
139+
// are not connected to each other via the parent metadata relationship.
140+
// For this reason, we need to widen the ownership of the children
141+
// upon access when we detect they are not connected.
142+
if (DEV) {
143+
/** @type {ProxyMetadata | undefined} */
144+
var prop_metadata = v?.[STATE_SYMBOL_METADATA];
145+
if (prop_metadata && prop_metadata?.parent !== metadata) {
146+
widen_ownership(metadata, prop_metadata);
147+
}
148+
}
149+
134150
return v === UNINITIALIZED ? undefined : v;
135151
}
136152

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { equals, safe_equals } from './equality.js';
1414
import * as e from '../errors.js';
1515
import { destroy_effect } from './effects.js';
16+
import { inspect_effects, set_inspect_effects } from './sources.js';
1617

1718
/**
1819
* @template V
@@ -92,6 +93,8 @@ export function update_derived(derived) {
9293
var value;
9394

9495
if (DEV) {
96+
let prev_inspect_effects = inspect_effects;
97+
set_inspect_effects(new Set());
9598
try {
9699
if (stack.includes(derived)) {
97100
e.derived_references_self();
@@ -102,6 +105,7 @@ export function update_derived(derived) {
102105
destroy_derived_children(derived);
103106
value = update_reaction(derived);
104107
} finally {
108+
set_inspect_effects(prev_inspect_effects);
105109
stack.pop();
106110
}
107111
} else {

0 commit comments

Comments
 (0)