Skip to content

Commit 726c153

Browse files
committed
Merge branch 'main' into each-without-as
2 parents abdf456 + 6a5f30b commit 726c153

File tree

41 files changed

+318
-325
lines changed

Some content is hidden

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

41 files changed

+318
-325
lines changed

.changeset/unlucky-icons-sit.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- [ ] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
55
- [ ] This message body should clearly illustrate what problems it solves.
66
- [ ] Ideally, include a test that fails without this PR but passes with it.
7+
- [ ] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`).
78

89
### Tests and linting
910

documentation/docs/07-misc/03-typescript.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ In case you're writing a component that wraps a native element, you may want to
142142
</script>
143143
144144
<button {...rest}>
145-
{@render children()}
145+
{@render children?.()}
146146
</button>
147147
```
148148

@@ -156,7 +156,7 @@ Not all elements have a dedicated type definition. For those without one, use `S
156156
</script>
157157
158158
<div {...rest}>
159-
{@render children()}
159+
{@render children?.()}
160160
</div>
161161
```
162162

packages/svelte/CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# svelte
22

3+
## 5.2.7
4+
5+
### Patch Changes
6+
7+
- fix: always use set for private identifiers ([#14378](https://github.com/sveltejs/svelte/pull/14378))
8+
9+
## 5.2.6
10+
11+
### Patch Changes
12+
13+
- fix: remove template expression inlining ([#14374](https://github.com/sveltejs/svelte/pull/14374))
14+
15+
## 5.2.5
16+
17+
### Patch Changes
18+
19+
- fix: correctly handle srcObject attribute on video elements ([#14369](https://github.com/sveltejs/svelte/pull/14369))
20+
21+
- add `contentvisibilityautostatechange` event to element definitions ([#14373](https://github.com/sveltejs/svelte/pull/14373))
22+
23+
- fix: tighten up `export default` validation ([#14368](https://github.com/sveltejs/svelte/pull/14368))
24+
25+
- fix: include method definitions in class private fields ([#14365](https://github.com/sveltejs/svelte/pull/14365))
26+
327
## 5.2.4
428

529
### Patch Changes

packages/svelte/elements.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ export type AnimationEventHandler<T extends EventTarget> = EventHandler<Animatio
6060
export type TransitionEventHandler<T extends EventTarget> = EventHandler<TransitionEvent, T>;
6161
export type MessageEventHandler<T extends EventTarget> = EventHandler<MessageEvent, T>;
6262
export type ToggleEventHandler<T extends EventTarget> = EventHandler<ToggleEvent, T>;
63+
export type ContentVisibilityAutoStateChangeEventHandler<T extends EventTarget> = EventHandler<
64+
ContentVisibilityAutoStateChangeEvent,
65+
T
66+
>;
6367

6468
export type FullAutoFill =
6569
| AutoFill
@@ -157,6 +161,20 @@ export interface DOMAttributes<T extends EventTarget> {
157161
ontoggle?: ToggleEventHandler<T> | undefined | null;
158162
ontogglecapture?: ToggleEventHandler<T> | undefined | null;
159163

164+
// Content visibility Events
165+
'on:contentvisibilityautostatechange'?:
166+
| ContentVisibilityAutoStateChangeEventHandler<T>
167+
| undefined
168+
| null;
169+
oncontentvisibilityautostatechange?:
170+
| ContentVisibilityAutoStateChangeEventHandler<T>
171+
| undefined
172+
| null;
173+
oncontentvisibilityautostatechangecapture?:
174+
| ContentVisibilityAutoStateChangeEventHandler<T>
175+
| undefined
176+
| null;
177+
160178
// Keyboard Events
161179
'on:keydown'?: KeyboardEventHandler<T> | undefined | null;
162180
onkeydown?: KeyboardEventHandler<T> | undefined | null;

packages/svelte/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "svelte",
33
"description": "Cybernetically enhanced web apps",
44
"license": "MIT",
5-
"version": "5.2.4",
5+
"version": "5.2.7",
66
"type": "module",
77
"types": "./types/index.d.ts",
88
"engines": {

packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/** @import { ArrowFunctionExpression, Expression, FunctionDeclaration, FunctionExpression } from 'estree' */
22
/** @import { AST, DelegatedEvent, SvelteNode } from '#compiler' */
33
/** @import { Context } from '../types' */
4-
import { is_boolean_attribute, is_capture_event, is_delegated } from '../../../../utils.js';
4+
import { cannot_be_set_statically, is_capture_event, is_delegated } from '../../../../utils.js';
55
import {
66
get_attribute_chunks,
77
get_attribute_expression,
@@ -30,12 +30,12 @@ export function Attribute(node, context) {
3030
}
3131
}
3232

33-
if (node.name.startsWith('on')) {
33+
if (is_event_attribute(node)) {
3434
mark_subtree_dynamic(context.path);
3535
}
3636

37-
if (parent.type === 'RegularElement' && is_boolean_attribute(node.name.toLowerCase())) {
38-
node.metadata.expression.can_inline = false;
37+
if (cannot_be_set_statically(node.name)) {
38+
mark_subtree_dynamic(context.path);
3939
}
4040

4141
if (node.value !== true) {
@@ -51,7 +51,6 @@ export function Attribute(node, context) {
5151

5252
node.metadata.expression.has_state ||= chunk.metadata.expression.has_state;
5353
node.metadata.expression.has_call ||= chunk.metadata.expression.has_call;
54-
node.metadata.expression.can_inline &&= chunk.metadata.expression.can_inline;
5554
}
5655

5756
if (is_event_attribute(node)) {

packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ export function CallExpression(node, context) {
179179
if (!is_pure(node.callee, context) || context.state.expression.dependencies.size > 0) {
180180
context.state.expression.has_call = true;
181181
context.state.expression.has_state = true;
182-
context.state.expression.can_inline = false;
183-
mark_subtree_dynamic(context.path);
184182
}
185183
}
186184
}

packages/svelte/src/compiler/phases/2-analyze/visitors/ExportDefaultDeclaration.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1-
/** @import { ExportDefaultDeclaration, Node } from 'estree' */
1+
/** @import { ExportDefaultDeclaration } from 'estree' */
22
/** @import { Context } from '../types' */
33
import * as e from '../../../errors.js';
4+
import { validate_export } from './shared/utils.js';
45

56
/**
67
* @param {ExportDefaultDeclaration} node
78
* @param {Context} context
89
*/
910
export function ExportDefaultDeclaration(node, context) {
10-
if (context.state.ast_type === 'instance') {
11+
if (!context.state.ast_type /* .svelte.js module */) {
12+
if (node.declaration.type === 'Identifier') {
13+
validate_export(node, context.state.scope, node.declaration.name);
14+
}
15+
} else {
1116
e.module_illegal_default_export(node);
1217
}
1318

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
/** @import { ExportSpecifier, Node } from 'estree' */
2-
/** @import { Binding } from '#compiler' */
1+
/** @import { ExportSpecifier } from 'estree' */
32
/** @import { Context } from '../types' */
4-
/** @import { Scope } from '../../scope' */
5-
import * as e from '../../../errors.js';
3+
import { validate_export } from './shared/utils.js';
64

75
/**
86
* @param {ExportSpecifier} node
@@ -30,22 +28,3 @@ export function ExportSpecifier(node, context) {
3028
validate_export(node, context.state.scope, local_name);
3129
}
3230
}
33-
34-
/**
35-
*
36-
* @param {Node} node
37-
* @param {Scope} scope
38-
* @param {string} name
39-
*/
40-
function validate_export(node, scope, name) {
41-
const binding = scope.get(name);
42-
if (!binding) return;
43-
44-
if (binding.kind === 'derived') {
45-
e.derived_invalid_export(node);
46-
}
47-
48-
if ((binding.kind === 'state' || binding.kind === 'raw_state') && binding.reassigned) {
49-
e.state_invalid_export(node);
50-
}
51-
}

packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/** @import { Context } from '../types' */
33
import { is_tag_valid_with_parent } from '../../../../html-tree-validation.js';
44
import * as e from '../../../errors.js';
5+
import { mark_subtree_dynamic } from './shared/fragment.js';
56

67
/**
78
* @param {AST.ExpressionTag} node
@@ -14,5 +15,9 @@ export function ExpressionTag(node, context) {
1415
}
1516
}
1617

18+
// TODO ideally we wouldn't do this here, we'd just do it on encountering
19+
// an `Identifier` within the tag. But we currently need to handle `{42}` etc
20+
mark_subtree_dynamic(context.path);
21+
1722
context.next({ ...context.state, expression: node.metadata.expression });
1823
}

packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/** @import { Expression, Identifier } from 'estree' */
2+
/** @import { EachBlock } from '#compiler' */
23
/** @import { Context } from '../types' */
34
import is_reference from 'is-reference';
45
import { should_proxy } from '../../3-transform/client/utils.js';
@@ -19,6 +20,8 @@ export function Identifier(node, context) {
1920
return;
2021
}
2122

23+
mark_subtree_dynamic(context.path);
24+
2225
// If we are using arguments outside of a function, then throw an error
2326
if (
2427
node.name === 'arguments' &&
@@ -84,12 +87,6 @@ export function Identifier(node, context) {
8487
}
8588
}
8689

87-
// no binding means global, and we can't inline e.g. `<span>{location}</span>`
88-
// because it could change between component renders. if there _is_ a
89-
// binding and it is outside module scope, the expression cannot
90-
// be inlined (TODO allow inlining in more cases - e.g. primitive consts)
91-
let can_inline = !!binding && !binding.scope.parent && binding.kind === 'normal';
92-
9390
if (binding) {
9491
if (context.state.expression) {
9592
context.state.expression.dependencies.add(binding);
@@ -125,12 +122,4 @@ export function Identifier(node, context) {
125122
w.reactive_declaration_module_script_dependency(node);
126123
}
127124
}
128-
129-
if (!can_inline) {
130-
if (context.state.expression) {
131-
context.state.expression.can_inline = false;
132-
}
133-
134-
mark_subtree_dynamic(context.path);
135-
}
136125
}

packages/svelte/src/compiler/phases/2-analyze/visitors/MemberExpression.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ export function MemberExpression(node, context) {
2020

2121
if (context.state.expression && !is_pure(node, context)) {
2222
context.state.expression.has_state = true;
23-
context.state.expression.can_inline = false;
24-
25-
mark_subtree_dynamic(context.path);
2623
}
2724

2825
if (!is_safe_identifier(node, context.state.scope)) {

packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,6 @@ export function RegularElement(node, context) {
7575
node.attributes.push(create_attribute('value', child.start, child.end, [child]));
7676
}
7777

78-
if (
79-
node.attributes.some(
80-
(attribute) =>
81-
attribute.type === 'Attribute' &&
82-
(attribute.name === 'autofocus' || attribute.name === 'muted')
83-
)
84-
) {
85-
mark_subtree_dynamic(context.path);
86-
}
87-
8878
const binding = context.state.scope.get(node.name);
8979
if (
9080
binding !== null &&

packages/svelte/src/compiler/phases/2-analyze/visitors/TaggedTemplateExpression.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export function TaggedTemplateExpression(node, context) {
1010
if (context.state.expression && !is_pure(node.tag, context)) {
1111
context.state.expression.has_call = true;
1212
context.state.expression.has_state = true;
13-
context.state.expression.can_inline = false;
1413
}
1514

1615
if (node.tag.type === 'Identifier') {

packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/** @import { AssignmentExpression, Expression, Literal, Pattern, PrivateIdentifier, Super, UpdateExpression, VariableDeclarator } from 'estree' */
1+
/** @import { AssignmentExpression, Expression, Literal, Node, Pattern, PrivateIdentifier, Super, UpdateExpression, VariableDeclarator } from 'estree' */
22
/** @import { AST, Binding } from '#compiler' */
33
/** @import { AnalysisState, Context } from '../../types' */
44
/** @import { Scope } from '../../../scope' */
@@ -263,3 +263,22 @@ export function validate_identifier_name(binding, function_depth) {
263263
}
264264
}
265265
}
266+
267+
/**
268+
* Checks that the exported name is not a derived or reassigned state variable.
269+
* @param {Node} node
270+
* @param {Scope} scope
271+
* @param {string} name
272+
*/
273+
export function validate_export(node, scope, name) {
274+
const binding = scope.get(name);
275+
if (!binding) return;
276+
277+
if (binding.kind === 'derived') {
278+
e.derived_invalid_export(node);
279+
}
280+
281+
if ((binding.kind === 'state' || binding.kind === 'raw_state') && binding.reassigned) {
282+
e.state_invalid_export(node);
283+
}
284+
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
/** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */
44
/** @import { Analysis } from '../../types.js' */
55
/** @import { Scope } from '../../scope.js' */
6+
import * as b from '../../../utils/builders.js';
7+
import { extract_identifiers, is_simple_expression } from '../../../utils/ast.js';
68
import {
7-
PROPS_IS_BINDABLE,
8-
PROPS_IS_IMMUTABLE,
99
PROPS_IS_LAZY_INITIAL,
10+
PROPS_IS_IMMUTABLE,
1011
PROPS_IS_RUNES,
11-
PROPS_IS_UPDATED
12+
PROPS_IS_UPDATED,
13+
PROPS_IS_BINDABLE
1214
} from '../../../../constants.js';
1315
import { dev } from '../../../state.js';
14-
import { extract_identifiers, is_simple_expression } from '../../../utils/ast.js';
15-
import * as b from '../../../utils/builders.js';
1616
import { get_value } from './visitors/shared/declarations.js';
1717

1818
/**

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

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,26 @@ function build_assignment(operator, left, right, context) {
3232
if (
3333
context.state.analysis.runes &&
3434
left.type === 'MemberExpression' &&
35-
left.object.type === 'ThisExpression'
35+
left.property.type === 'PrivateIdentifier'
3636
) {
37-
if (left.property.type === 'PrivateIdentifier') {
38-
const private_state = context.state.private_state.get(left.property.name);
39-
40-
if (private_state !== undefined) {
41-
let transformed = false;
42-
let value = /** @type {Expression} */ (
43-
context.visit(build_assignment_value(operator, left, right))
44-
);
45-
46-
if (should_proxy(value, context.state.scope)) {
47-
transformed = true;
48-
value =
49-
private_state.kind === 'raw_state'
50-
? value
51-
: build_proxy_reassignment(value, b.member(b.this, private_state.id));
52-
}
53-
54-
if (!context.state.in_constructor) {
55-
return b.call('$.set', left, value);
56-
} else if (transformed) {
57-
return b.assignment(operator, /** @type {Pattern} */ (context.visit(left)), value);
58-
}
37+
const private_state = context.state.private_state.get(left.property.name);
38+
39+
if (private_state !== undefined) {
40+
let value = /** @type {Expression} */ (
41+
context.visit(build_assignment_value(operator, left, right))
42+
);
43+
44+
if (private_state.kind !== 'raw_state' && should_proxy(value, context.state.scope)) {
45+
value = build_proxy_reassignment(value, b.member(b.this, private_state.id));
5946
}
47+
48+
if (context.state.in_constructor) {
49+
// inside the constructor, we can assign to `this.#foo.v` rather than using `$.set`,
50+
// since nothing is tracking the signal at this point
51+
return b.assignment(operator, /** @type {Pattern} */ (context.visit(left)), value);
52+
}
53+
54+
return b.call('$.set', left, value);
6055
}
6156
}
6257

0 commit comments

Comments
 (0)