Merge branch 'elliott/variadic-snippets' of github.com:sveltejs/svelte into elliott/variadic-snippets

pull/10320/head
S. Elliott Johnson 6 months ago
commit 979170ce05

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve nested effect heuristics

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve ssr template code generation

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: make `@types/estree` a dependency

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve template literal expression output generation

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve outro behavior with transitions

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve intro transitions on dynamic mount

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: remove internal functions from `svelte/transition` exports

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve code generation

@ -10,10 +10,13 @@
},
"changesets": [
"afraid-moose-matter",
"angry-books-jam",
"beige-flies-wash",
"beige-rabbits-shave",
"brave-walls-destroy",
"breezy-carrots-flash",
"bright-peas-juggle",
"bright-snakes-sing",
"brown-spoons-boil",
"chatty-cups-drop",
"chatty-taxis-juggle",
@ -38,6 +41,8 @@
"early-ads-tie",
"eight-steaks-shout",
"eighty-bikes-camp",
"eighty-days-cheat",
"empty-bulldogs-exercise",
"empty-crabs-think",
"fair-crabs-check",
"famous-knives-sneeze",
@ -73,6 +78,7 @@
"itchy-terms-guess",
"khaki-mails-draw",
"khaki-moose-arrive",
"kind-baboons-approve",
"kind-deers-lay",
"kind-eagles-join",
"large-clouds-carry",
@ -91,6 +97,7 @@
"lovely-items-turn",
"lovely-rules-eat",
"lucky-schools-hang",
"lucky-toes-begin",
"moody-frogs-exist",
"moody-owls-cry",
"nasty-lions-double",
@ -98,6 +105,7 @@
"neat-dingos-clap",
"new-boats-wait",
"ninety-dingos-walk",
"odd-buckets-lie",
"odd-needles-joke",
"odd-schools-wait",
"odd-shoes-cheat",
@ -120,6 +128,7 @@
"rare-pears-whisper",
"real-guests-do",
"red-doors-own",
"rich-cobras-exist",
"rich-sheep-burn",
"rich-tables-sing",
"rotten-bags-type",
@ -128,6 +137,7 @@
"serious-socks-cover",
"serious-zebras-scream",
"seven-deers-jam",
"seven-jobs-sniff",
"seven-ravens-check",
"sharp-gorillas-impress",
"sharp-kids-happen",
@ -137,16 +147,21 @@
"short-buses-camp",
"slimy-clouds-talk",
"slimy-walls-draw",
"slow-beds-shave",
"slow-chefs-dream",
"slow-wombats-reply",
"small-papayas-laugh",
"smart-parents-swim",
"smart-zebras-pay",
"soft-clocks-remember",
"soft-geese-learn",
"soft-tigers-wink",
"sour-forks-stare",
"sour-rules-march",
"sour-weeks-fix",
"spicy-plums-admire",
"spotty-pens-agree",
"spotty-spiders-compare",
"stale-books-perform",
"stale-comics-look",
"strong-gifts-smoke",
@ -160,9 +175,11 @@
"tall-garlics-try",
"tall-shrimps-worry",
"tall-tigers-wait",
"tame-spies-drum",
"tasty-numbers-perform",
"ten-foxes-repeat",
"ten-peaches-sleep",
"ten-ties-repair",
"ten-worms-reflect",
"thin-foxes-lick",
"thirty-flowers-sit",

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: simplify event delegation logic, only delegate event attributes

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: adjust `$inspect.with` type

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: further animation transition improvements

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve how transitions are handled on mount

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve animation transition heuristics

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: adjust `parse` return type

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: prevent transition action overfiring

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve event handling compatibility with delegation

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: ensure topological order for render effects

@ -22,13 +22,6 @@ body:
placeholder: I would like to see...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: "Please provide a clear and concise description of any alternative solutions or features you've considered."
validations:
required: true
- type: dropdown
id: importance
attributes:

@ -0,0 +1,7 @@
{
"drips": {
"ethereum": {
"ownedBy": "0x99D414693dD65E4a0664a16D155dB66283A162D1"
}
}
}

@ -16,7 +16,7 @@
? people.filter((person) => {
const name = `${person.last}, ${person.first}`;
return name.toLowerCase().startsWith(prefix.toLowerCase());
})
})
: people;
$: selected = filteredPeople[i];

@ -18,8 +18,8 @@
"build:sites": "pnpm -r --filter=./sites/* build",
"preview-site": "npm run build --prefix sites/svelte-5-preview",
"check": "cd packages/svelte && pnpm build && cd ../../ && pnpm -r check",
"format": "prettier --write --plugin prettier-plugin-svelte .",
"lint": "prettier --check --plugin prettier-plugin-svelte . && eslint ./",
"format": "prettier --write .",
"lint": "prettier --check . && eslint ./",
"test": "vitest run --coverage",
"test-output": "vitest run --reporter=json --outputFile=sites/svelte-5-preview/src/routes/status/results.json",
"changeset:version": "changeset version && pnpm -r generate:version && git add --all",
@ -38,9 +38,14 @@
"eslint-plugin-lube": "^0.1.7",
"jsdom": "22.0.0",
"playwright": "^1.35.1",
"prettier": "^3.0.1",
"prettier-plugin-svelte": "^3.0.3",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"typescript": "^5.2.2",
"vitest": "^0.34.6"
},
"pnpm": {
"overrides": {
"jimp>xml2js": "^0.6.0"
}
}
}

@ -1,5 +1,55 @@
# svelte
## 5.0.0-next.35
### Patch Changes
- fix: improve nested effect heuristics ([#10171](https://github.com/sveltejs/svelte/pull/10171))
- fix: simplify event delegation logic, only delegate event attributes ([#10169](https://github.com/sveltejs/svelte/pull/10169))
- fix: prevent transition action overfiring ([#10163](https://github.com/sveltejs/svelte/pull/10163))
- fix: improve event handling compatibility with delegation ([#10168](https://github.com/sveltejs/svelte/pull/10168))
- fix: ensure topological order for render effects ([#10175](https://github.com/sveltejs/svelte/pull/10175))
## 5.0.0-next.34
### Patch Changes
- fix: make `@types/estree` a dependency ([#10150](https://github.com/sveltejs/svelte/pull/10150))
- fix: improve intro transitions on dynamic mount ([#10162](https://github.com/sveltejs/svelte/pull/10162))
- fix: improve code generation ([#10156](https://github.com/sveltejs/svelte/pull/10156))
- fix: adjust `$inspect.with` type ([`c7cb90c91`](https://github.com/sveltejs/svelte/commit/c7cb90c91cd3553ad59126267c9bfddecbb290b4))
- fix: improve how transitions are handled on mount ([#10157](https://github.com/sveltejs/svelte/pull/10157))
- fix: adjust `parse` return type ([`a271878ab`](https://github.com/sveltejs/svelte/commit/a271878abe7018923839401129b18082eb2c811a))
## 5.0.0-next.33
### Patch Changes
- fix: improve ssr template code generation ([#10151](https://github.com/sveltejs/svelte/pull/10151))
- fix: improve template literal expression output generation ([#10147](https://github.com/sveltejs/svelte/pull/10147))
## 5.0.0-next.32
### Patch Changes
- fix: improve outro behavior with transitions ([#10139](https://github.com/sveltejs/svelte/pull/10139))
- chore: remove internal functions from `svelte/transition` exports ([#10132](https://github.com/sveltejs/svelte/pull/10132))
- fix: further animation transition improvements ([#10138](https://github.com/sveltejs/svelte/pull/10138))
- fix: improve animation transition heuristics ([#10119](https://github.com/sveltejs/svelte/pull/10119))
## 5.0.0-next.31
### Patch Changes

@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
"version": "5.0.0-next.31",
"version": "5.0.0-next.35",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
@ -107,7 +107,6 @@
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-virtual": "^3.0.2",
"@types/aria-query": "^5.0.3",
"@types/estree": "^1.0.5",
"dts-buddy": "^0.4.3",
"esbuild": "^0.19.2",
"rollup": "^4.1.5",
@ -117,6 +116,7 @@
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@types/estree": "^1.0.5",
"acorn": "^8.10.0",
"acorn-typescript": "^1.4.13",
"aria-query": "^5.3.0",

@ -234,8 +234,8 @@ const attributes = {
type === 'no-each'
? `An element that uses the animate directive must be the immediate child of a keyed each block`
: type === 'each-key'
? `An element that uses the animate directive must be used inside a keyed each block. Did you forget to add a key to your each block?`
: `An element that uses the animate directive must be the sole child of a keyed each block`,
? `An element that uses the animate directive must be used inside a keyed each block. Did you forget to add a key to your each block?`
: `An element that uses the animate directive must be the sole child of a keyed each block`,
'duplicate-animation': () => `An element can only have one 'animate' directive`,
/** @param {string[] | undefined} [modifiers] */
'invalid-event-modifier': (modifiers) =>
@ -262,7 +262,7 @@ const attributes = {
? `An element can only have one '${directive1}' directive`
: `An element cannot have both ${describe(directive1)} directive and ${describe(
directive2
)} directive`;
)} directive`;
},
'invalid-let-directive-placement': () => 'let directive at invalid position'
};

@ -91,7 +91,7 @@ function handle_compile_error(error, filename, source) {
* https://svelte.dev/docs/svelte-compiler#svelte-parse
* @param {string} source
* @param {{ filename?: string; modern?: boolean }} [options]
* @returns {import('#compiler').SvelteNode | import('./types/legacy-nodes.js').LegacySvelteNode}
* @returns {import('#compiler').Root | import('./types/legacy-nodes.js').LegacyRoot}
*/
export function parse(source, options = {}) {
/** @type {import('#compiler').Root} */
@ -108,7 +108,7 @@ export function parse(source, options = {}) {
if (options.modern) {
// remove things that we don't want to treat as public API
return walk(/** @type {import('#compiler').SvelteNode} */ (ast), null, {
return walk(ast, null, {
_(node, { next }) {
// @ts-ignore
delete node.parent;

@ -33,7 +33,7 @@ function remove_surrounding_whitespace_nodes(nodes) {
* Transform our nice modern AST into the monstrosity emitted by Svelte 4
* @param {string} source
* @param {import('#compiler').Root} ast
* @returns {import('./types/legacy-nodes.js').LegacySvelteNode}
* @returns {import('./types/legacy-nodes.js').LegacyRoot}
*/
export function convert(source, ast) {
const root =
@ -41,7 +41,7 @@ export function convert(source, ast) {
ast
);
return /** @type {import('./types/legacy-nodes.js').LegacySvelteNode} */ (
return /** @type {import('./types/legacy-nodes.js').LegacyRoot} */ (
walk(root, null, {
_(node, { next }) {
// @ts-ignore
@ -108,7 +108,7 @@ export function convert(source, ast) {
// @ts-ignore
delete node.parent;
}
})
})
: undefined
};
},

@ -108,12 +108,12 @@ export default function tag(parser) {
const type = meta_tags.has(name)
? meta_tags.get(name)
: regex_capital_letter.test(name[0]) || name === 'svelte:self' || name === 'svelte:component'
? 'Component'
: name === 'title' && parent_is_head(parser.stack)
? 'TitleElement'
: name === 'slot'
? 'SlotElement'
: 'RegularElement';
? 'Component'
: name === 'title' && parent_is_head(parser.stack)
? 'TitleElement'
: name === 'slot'
? 'SlotElement'
: 'RegularElement';
/** @type {import('#compiler').ElementLike} */
// @ts-expect-error TODO can't figure out this error
@ -128,11 +128,10 @@ export default function tag(parser) {
fragment: create_fragment(true),
metadata: {
svg: false,
has_spread: false,
can_delegate_events: null
has_spread: false
},
parent: null
}
}
: {
type: /** @type {import('#compiler').ElementLike['type']} */ (type),
start,
@ -141,7 +140,7 @@ export default function tag(parser) {
attributes: [],
fragment: create_fragment(true),
parent: null
};
};
parser.allow_whitespace();

@ -275,7 +275,7 @@ export function combine_sourcemaps(filename, sourcemap_list) {
sourcemap_list,
() => null,
true // skip optional field `sourcesContent`
)
)
: remapping(
// use loader interface
sourcemap_list[0], // last map
@ -291,7 +291,7 @@ export function combine_sourcemaps(filename, sourcemap_list) {
}
),
true
);
);
if (!map.file) delete map.file; // skip optional field `file`

@ -59,27 +59,23 @@ function get_component_name(filename) {
}
/**
* @param {Pick<import('#compiler').OnDirective, 'expression'| 'name' | 'modifiers'> & { type: string }} node
* Checks if given event attribute can be delegated/hoisted and returns the corresponding info if so
* @param {string} event_name
* @param {import('estree').Expression | null} handler
* @param {import('./types').Context} context
* @returns {null | import('#compiler').DelegatedEvent}
*/
function get_delegated_event(node, context) {
const handler = node.expression;
const event_name = node.name;
function get_delegated_event(event_name, handler, context) {
// Handle delegated event handlers. Bail-out if not a delegated event.
if (!handler || node.modifiers.includes('capture') || !DelegatedEvents.includes(event_name)) {
if (!handler || !DelegatedEvents.includes(event_name)) {
return null;
}
// If we are not working with a RegularElement, then bail-out.
const element = context.path.at(-1);
if (element?.type !== 'RegularElement') {
return null;
}
// If element says we can't delegate because we have multiple OnDirectives of the same type, bail-out.
if (!element.metadata.can_delegate_events) {
return null;
}
/** @type {import('#compiler').DelegatedEvent} */
const non_hoistable = { type: 'non-hoistable' };
@ -87,7 +83,7 @@ function get_delegated_event(node, context) {
let target_function = null;
let binding = null;
if (node.type === 'Attribute' && element.metadata.has_spread) {
if (element.metadata.has_spread) {
// event attribute becomes part of the dynamic spread array
return non_hoistable;
}
@ -123,8 +119,7 @@ function get_delegated_event(node, context) {
if (element && event_name) {
if (
element.type !== 'RegularElement' ||
!determine_element_spread_and_delegatable(element).metadata.can_delegate_events ||
(element.metadata.has_spread && node.type === 'Attribute') ||
determine_element_spread(element).metadata.has_spread ||
!DelegatedEvents.includes(event_name)
) {
return non_hoistable;
@ -183,7 +178,8 @@ function get_delegated_event(node, context) {
) {
return non_hoistable;
}
// If we referebnce the index within an each block, then bail-out.
// If we reference the index within an each block, then bail-out.
if (binding !== null && binding.initial?.type === 'EachBlock') {
return non_hoistable;
}
@ -204,6 +200,7 @@ function get_delegated_event(node, context) {
}
visited_references.add(reference);
}
return { type: 'hoistable', function: target_function };
}
@ -713,12 +710,12 @@ const runes_scope_tweaker = {
rune === '$state'
? 'state'
: rune === '$state.frozen'
? 'frozen_state'
: rune === '$derived'
? 'derived'
: path.is_rest
? 'rest_prop'
: 'prop';
? 'frozen_state'
: rune === '$derived'
? 'derived'
: path.is_rest
? 'rest_prop'
: 'prop';
}
if (rune === '$props') {
@ -858,21 +855,9 @@ const common_visitors = {
});
if (is_event_attribute(node)) {
/** @type {string[]} */
const modifiers = [];
const expression = node.value[0].expression;
let name = node.name.slice(2);
if (is_capture_event(name)) {
name = name.slice(0, -7);
modifiers.push('capture');
}
const delegated_event = get_delegated_event(
{ type: node.type, name, expression, modifiers },
context
);
const delegated_event = get_delegated_event(node.name.slice(2), expression, context);
if (delegated_event !== null) {
if (delegated_event.type === 'hoistable') {
@ -1032,18 +1017,6 @@ const common_visitors = {
)
};
},
OnDirective(node, context) {
node.metadata = { delegated: null };
context.next();
const delegated_event = get_delegated_event(node, context);
if (delegated_event !== null) {
if (delegated_event.type === 'hoistable') {
delegated_event.function.metadata.hoistable = true;
}
node.metadata.delegated = delegated_event;
}
},
ArrowFunctionExpression: function_visitor,
FunctionExpression: function_visitor,
FunctionDeclaration: function_visitor,
@ -1052,7 +1025,7 @@ const common_visitors = {
node.metadata.svg = true;
}
determine_element_spread_and_delegatable(node);
determine_element_spread(node);
// Special case: Move the children of <textarea> into a value attribute if they are dynamic
if (
@ -1110,51 +1083,15 @@ const common_visitors = {
};
/**
* Check if events on this element can theoretically be delegated. They can if there's no
* possibility of an OnDirective and an event attribute on the same element, and if there's
* no OnDirectives of the same type (the latter is a bit too strict because `on:click on:click on:keyup`
* means that `on:keyup` can be delegated but we gloss over this edge case).
* @param {import('#compiler').RegularElement} node
*/
function determine_element_spread_and_delegatable(node) {
if (typeof node.metadata.can_delegate_events === 'boolean') {
return node; // did this already
}
let events = new Map();
function determine_element_spread(node) {
let has_spread = false;
let has_on = false;
let has_action_or_bind = false;
for (const attribute of node.attributes) {
if (
attribute.type === 'OnDirective' ||
(attribute.type === 'Attribute' && is_event_attribute(attribute))
) {
let event_name = attribute.name;
if (attribute.type === 'Attribute') {
event_name = get_attribute_event_name(event_name);
}
events.set(event_name, (events.get(event_name) || 0) + 1);
if (!has_on && attribute.type === 'OnDirective') {
has_on = true;
}
} else if (!has_spread && attribute.type === 'SpreadAttribute') {
if (!has_spread && attribute.type === 'SpreadAttribute') {
has_spread = true;
} else if (
!has_action_or_bind &&
((attribute.type === 'BindDirective' && attribute.name !== 'this') ||
attribute.type === 'UseDirective')
) {
has_action_or_bind = true;
}
}
node.metadata.can_delegate_events =
// Actions/bindings need the old on:-events to fire in order
!has_action_or_bind &&
// spreading events means we don't know if there's an event attribute with the same name as an on:-event
!(has_spread && has_on) &&
// multiple on:-events/event attributes with the same name
![...events.values()].some((count) => count > 1);
node.metadata.has_spread = has_spread;
return node;

@ -201,7 +201,7 @@ export function client_component(source, analysis, options) {
b.call('$.validate_store', store_reference, b.literal(name.slice(1))),
store_get
])
)
)
: b.thunk(store_get)
)
);

@ -20,11 +20,11 @@ export function get_assignment_value(node, { state, visit }) {
return operator === '='
? /** @type {import('estree').Expression} */ (visit(node.right))
: // turn something like x += 1 into x = x + 1
b.binary(
b.binary(
/** @type {import('estree').BinaryOperator} */ (operator.slice(0, -1)),
serialize_get_binding(node.left, state),
/** @type {import('estree').Expression} */ (visit(node.right))
);
);
} else if (
node.left.type === 'MemberExpression' &&
node.left.object.type === 'ThisExpression' &&
@ -35,11 +35,11 @@ export function get_assignment_value(node, { state, visit }) {
return operator === '='
? /** @type {import('estree').Expression} */ (visit(node.right))
: // turn something like x += 1 into x = x + 1
b.binary(
b.binary(
/** @type {import('estree').BinaryOperator} */ (operator.slice(0, -1)),
/** @type {import('estree').Expression} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right))
);
);
} else {
return /** @type {import('estree').Expression} */ (visit(node.right));
}
@ -217,9 +217,10 @@ function is_expression_async(expression) {
* @param {import('estree').AssignmentExpression} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, State>} context
* @param {() => any} fallback
* @param {{skip_proxy_and_freeze?: boolean}} [options]
* @returns {import('estree').Expression}
*/
export function serialize_set_binding(node, context, fallback) {
export function serialize_set_binding(node, context, fallback, options) {
const { state, visit } = context;
if (
@ -242,7 +243,7 @@ export function serialize_set_binding(node, context, fallback) {
const value = path.expression?.(b.id(tmp_id));
const assignment = b.assignment('=', path.node, value);
original_assignments.push(assignment);
assignments.push(serialize_set_binding(assignment, context, () => assignment));
assignments.push(serialize_set_binding(assignment, context, () => assignment, options));
}
if (assignments.every((assignment, i) => assignment === original_assignments[i])) {
@ -288,7 +289,11 @@ export function serialize_set_binding(node, context, fallback) {
if (private_state !== undefined) {
if (state.in_constructor) {
// See if we should wrap value in $.proxy
if (context.state.analysis.runes && should_proxy_or_freeze(value)) {
if (
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value)
) {
const assignment = fallback();
if (assignment.type === 'AssignmentExpression') {
assignment.right =
@ -302,7 +307,9 @@ export function serialize_set_binding(node, context, fallback) {
return b.call(
'$.set',
left,
context.state.analysis.runes && should_proxy_or_freeze(value)
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value)
? private_state.kind === 'frozen_state'
? b.call('$.freeze', value)
: b.call('$.proxy', value)
@ -321,6 +328,7 @@ export function serialize_set_binding(node, context, fallback) {
if (
context.state.analysis.runes &&
public_state !== undefined &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value)
) {
const assignment = fallback();
@ -387,7 +395,9 @@ export function serialize_set_binding(node, context, fallback) {
return b.call(
'$.set',
b.id(left_name),
context.state.analysis.runes && should_proxy_or_freeze(value)
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value)
? b.call('$.proxy', value)
: value
);
@ -395,7 +405,9 @@ export function serialize_set_binding(node, context, fallback) {
return b.call(
'$.set',
b.id(left_name),
context.state.analysis.runes && should_proxy_or_freeze(value)
context.state.analysis.runes &&
!options?.skip_proxy_and_freeze &&
should_proxy_or_freeze(value)
? b.call('$.freeze', value)
: value
);
@ -615,6 +627,7 @@ export function should_proxy_or_freeze(node) {
if (
!node ||
node.type === 'Literal' ||
node.type === 'TemplateLiteral' ||
node.type === 'ArrowFunctionExpression' ||
node.type === 'FunctionExpression' ||
node.type === 'UnaryExpression' ||
@ -623,6 +636,5 @@ export function should_proxy_or_freeze(node) {
) {
return false;
}
return true;
}

@ -87,8 +87,11 @@ export const javascript_visitors_runes = {
field.kind === 'state'
? b.call('$.source', should_proxy_or_freeze(init) ? b.call('$.proxy', init) : init)
: field.kind === 'frozen_state'
? b.call('$.source', should_proxy_or_freeze(init) ? b.call('$.freeze', init) : init)
: b.call('$.derived', b.thunk(init));
? b.call(
'$.source',
should_proxy_or_freeze(init) ? b.call('$.freeze', init) : init
)
: b.call('$.derived', b.thunk(init));
} else {
// if no arguments, we know it's state as `$derived()` is a compile error
value = b.call('$.source');

@ -655,15 +655,15 @@ function serialize_element_special_value_attribute(element, node_id, attribute,
// This ensures things stay in sync with the select binding
// in case of updates to the option value or new values appearing
b.call('$.selected', node_id)
])
])
: needs_option_call
? b.sequence([
inner_assignment,
// This ensures a one-way street to the DOM in case it's <select {value}>
// and not <select bind:value>
b.call('$.select_option', node_id, value)
])
: inner_assignment
? b.sequence([
inner_assignment,
// This ensures a one-way street to the DOM in case it's <select {value}>
// and not <select bind:value>
b.call('$.select_option', node_id, value)
])
: inner_assignment
);
if (is_reactive) {
@ -953,7 +953,7 @@ function serialize_inline_component(node, component_name, context) {
: b.call(
'$.spread_props',
...props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))
);
);
/** @param {import('estree').Identifier} node_id */
let fn = (node_id) =>
b.call(
@ -1309,7 +1309,7 @@ function serialize_event_handler(node, { state, visit }) {
/**
* Serializes an event handler function of the `on:` directive or an attribute starting with `on`
* @param {Pick<import('#compiler').OnDirective, 'name' | 'modifiers' | 'expression' | 'metadata'>} node
* @param {{name: string; modifiers: string[]; expression: import('estree').Expression | null; delegated?: import('#compiler').DelegatedEvent | null; }} node
* @param {import('../types.js').ComponentContext} context
*/
function serialize_event(node, context) {
@ -1318,9 +1318,9 @@ function serialize_event(node, context) {
if (node.expression) {
let handler = serialize_event_handler(node, context);
const event_name = node.name;
const delegated = node.metadata.delegated;
const delegated = node.delegated;
if (delegated !== null) {
if (delegated != null) {
let delegated_assignment;
if (!state.events.has(event_name)) {
@ -1415,7 +1415,7 @@ function serialize_event_attribute(node, context) {
name: event_name,
expression: node.value[0].expression,
modifiers,
metadata: node.metadata
delegated: node.metadata.delegated
},
context
);
@ -1657,6 +1657,11 @@ function serialize_template_literal(values, visit, state) {
if (node.type === 'Text') {
const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
last.value.raw += sanitize_template_string(node.data);
} else if (node.type === 'ExpressionTag' && node.expression.type === 'Literal') {
const last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
if (node.expression.value != null) {
last.value.raw += sanitize_template_string(node.expression.value + '');
}
} else {
if (node.type === 'ExpressionTag' && node.metadata.contains_call_expression) {
contains_call_expression = true;
@ -2344,7 +2349,7 @@ export const template_visitors = {
? b.arrow(
[b.id('$$anchor')],
/** @type {import('estree').BlockStatement} */ (context.visit(node.fallback))
)
)
: b.literal(null);
const key_function =
node.key && ((each_type & EACH_ITEM_REACTIVE) !== 0 || context.state.options.dev)
@ -2355,7 +2360,7 @@ export const template_visitors = {
b.return(/** @type {import('estree').Expression} */ (context.visit(node.key)))
)
)
)
)
: b.literal(null);
if (node.index && each_node_meta.contains_group_binding) {
@ -2417,7 +2422,7 @@ export const template_visitors = {
? b.arrow(
[b.id('$$anchor')],
/** @type {import('estree').BlockStatement} */ (context.visit(node.alternate))
)
)
: b.literal(null)
)
)
@ -2436,7 +2441,7 @@ export const template_visitors = {
? b.arrow(
[b.id('$$anchor')],
/** @type {import('estree').BlockStatement} */ (context.visit(node.pending))
)
)
: b.literal(null),
node.then
? b.arrow(
@ -2444,10 +2449,10 @@ export const template_visitors = {
? [
b.id('$$anchor'),
/** @type {import('estree').Pattern} */ (context.visit(node.value))
]
]
: [b.id('$$anchor')],
/** @type {import('estree').BlockStatement} */ (context.visit(node.then))
)
)
: b.literal(null),
node.catch
? b.arrow(
@ -2455,10 +2460,10 @@ export const template_visitors = {
? [
b.id('$$anchor'),
/** @type {import('estree').Pattern} */ (context.visit(node.error))
]
]
: [b.id('$$anchor')],
/** @type {import('estree').BlockStatement} */ (context.visit(node.catch))
)
)
: b.literal(null)
)
)
@ -2608,7 +2613,10 @@ export const template_visitors = {
serialize_set_binding(
assignment,
context,
() => /** @type {import('estree').Expression} */ (context.visit(assignment))
() => /** @type {import('estree').Expression} */ (context.visit(assignment)),
{
skip_proxy_and_freeze: true
}
)
);
@ -2877,9 +2885,9 @@ export const template_visitors = {
/** @type {import('estree').Expression} */ (node.expression).type ===
'ObjectExpression'
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.object_pattern(node.expression.properties)
b.object_pattern(node.expression.properties)
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.array_pattern(node.expression.elements),
b.array_pattern(node.expression.elements),
b.member(b.id('$$slotProps'), b.id(node.name))
),
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
@ -2972,7 +2980,7 @@ export const template_visitors = {
: b.arrow(
[b.id('$$anchor')],
b.block(create_block(node, 'fallback', node.fragment.nodes, context))
);
);
const expression = is_default
? b.member(b.id('$$props'), b.id('children'))

@ -187,10 +187,12 @@ function process_children(nodes, parent, { visit, state }) {
const node = sequence[i];
if (node.type === 'Text' || node.type === 'Comment') {
let last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
last.value.raw +=
node.type === 'Comment'
? `<!--${node.data}-->`
: sanitize_template_string(escape_html(node.data));
last.value.raw += node.type === 'Comment' ? `<!--${node.data}-->` : escape_html(node.data);
} else if (node.type === 'ExpressionTag' && node.expression.type === 'Literal') {
let last = /** @type {import('estree').TemplateElement} */ (quasis.at(-1));
if (node.expression.value != null) {
last.value.raw += escape_html(node.expression.value + '');
}
} else if (node.type === 'Anchor') {
expressions.push(node.id);
quasis.push(b.quasi('', i + 1 === sequence.length));
@ -349,11 +351,11 @@ function get_assignment_value(node, { state, visit }) {
return operator === '='
? /** @type {import('estree').Expression} */ (visit(node.right))
: // turn something like x += 1 into x = x + 1
b.binary(
b.binary(
/** @type {import('estree').BinaryOperator} */ (operator.slice(0, -1)),
serialize_get_binding(node.left, state),
/** @type {import('estree').Expression} */ (visit(node.right))
);
);
} else {
return /** @type {import('estree').Expression} */ (visit(node.right));
}
@ -778,7 +780,7 @@ function serialize_element_spread_attributes(
b.id('join')
),
b.literal(' ')
)
)
: b.literal('');
args.push(
b.object([
@ -931,7 +933,7 @@ function serialize_inline_component(node, component_name, context) {
: b.call(
'$.spread_props',
b.array(props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p)))
);
);
/** @type {import('estree').Statement} */
let statement = b.stmt(
@ -940,7 +942,7 @@ function serialize_inline_component(node, component_name, context) {
? b.call(
'$.validate_component',
typeof component_name === 'string' ? b.id(component_name) : component_name
)
)
: component_name,
b.id('$$payload'),
props_expression
@ -1032,7 +1034,7 @@ const javascript_visitors_legacy = {
'$.value_or_fallback',
prop,
/** @type {import('estree').Expression} */ (visit(declarator.init))
)
)
: prop;
declarations.push(b.declarator(declarator.id, init));
@ -1170,7 +1172,7 @@ const template_visitors = {
template: [],
init: []
}
}
}
: { ...context, state };
const { hoisted, trimmed } = clean_nodes(
@ -1494,9 +1496,9 @@ const template_visitors = {
b.let(
node.expression.type === 'ObjectExpression'
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.object_pattern(node.expression.properties)
b.object_pattern(node.expression.properties)
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
b.array_pattern(node.expression.elements),
b.array_pattern(node.expression.elements),
b.member(b.id('$$slotProps'), b.id(node.name))
),
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
@ -1712,12 +1714,12 @@ function serialize_element_attributes(node, context) {
? b.call(
b.member(attribute.expression, b.id('includes')),
serialize_attribute_value(value_attribute.value, context)
)
)
: b.binary(
'===',
attribute.expression,
serialize_attribute_value(value_attribute.value, context)
),
),
metadata: {
contains_call_expression: false,
dynamic: false

@ -198,7 +198,7 @@ export function infer_namespace(namespace, parent, nodes, path) {
const parent_node =
parent.type === 'Fragment'
? // Messy: We know that Fragment calls create_block directly, so we can do this here
path.at(-1)
path.at(-1)
: parent;
if (

@ -318,7 +318,7 @@ async function process_markup(process, source) {
string: processed.code,
map: processed.map
? // TODO: can we use decode_sourcemap?
typeof processed.map === 'string'
typeof processed.map === 'string'
? JSON.parse(processed.map)
: processed.map
: undefined,

@ -21,6 +21,13 @@ interface BaseElement extends BaseNode {
children: Array<LegacyElementLike>;
}
export interface LegacyRoot extends BaseNode {
html: LegacySvelteNode;
css?: any;
instance?: any;
module?: any;
}
export interface LegacyAction extends BaseNode {
type: 'Action';
/** The 'x' in `use:x` */

@ -204,9 +204,6 @@ export interface OnDirective extends BaseNode {
/** The 'y' in `on:x={y}` */
expression: null | Expression;
modifiers: string[]; // TODO specify
metadata: {
delegated: null | DelegatedEvent;
};
}
export type DelegatedEvent =
@ -290,12 +287,6 @@ export interface RegularElement extends BaseElement {
svg: boolean;
/** `true` if contains a SpreadAttribute */
has_spread: boolean;
/**
* `true` if events on this element can theoretically be delegated. This doesn't necessarily mean that
* a specific event will be delegated, as there are other factors which affect the final outcome.
* `null` only until it was determined whether this element can be delegated or not.
*/
can_delegate_events: boolean | null;
};
}

@ -258,7 +258,7 @@ export function combine_sourcemaps(filename, sourcemap_list) {
sourcemap_list,
() => null,
true // skip optional field `sourcesContent`
)
)
: remapping(
// use loader interface
sourcemap_list[0], // last map
@ -271,7 +271,7 @@ export function combine_sourcemaps(filename, sourcemap_list) {
}
},
true
);
);
if (!map.file) delete map.file; // skip optional field `file`
// When source maps are combined and the leading map is empty, sources is not set.
// Add the filename to the empty array in this case.

@ -59,10 +59,10 @@ export function bounceOut(t) {
return t < a
? 7.5625 * t2
: t < b
? 9.075 * t2 - 9.9 * t + 3.4
: t < c
? ca * t2 - cb * t + cc
: 10.8 * t * t - 20.52 * t + 10.72;
? 9.075 * t2 - 9.9 * t + 3.4
: t < c
? ca * t2 - cb * t + cc
: 10.8 * t * t - 20.52 * t + 10.72;
}
/**
@ -180,8 +180,8 @@ export function expoInOut(t) {
return t === 0.0 || t === 1.0
? t
: t < 0.5
? +0.5 * Math.pow(2.0, 20.0 * t - 10.0)
: -0.5 * Math.pow(2.0, 10.0 - t * 20.0) + 1.0;
? +0.5 * Math.pow(2.0, 20.0 * t - 10.0)
: -0.5 * Math.pow(2.0, 10.0 - t * 20.0) + 1.0;
}
/**

@ -25,7 +25,6 @@ import {
mutable_source,
push_destroy_fn,
render_effect,
schedule_task,
set_signal_value,
source
} from './runtime.js';
@ -134,8 +133,8 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
array = is_array(maybe_array)
? maybe_array
: maybe_array == null
? []
: Array.from(maybe_array);
? []
: Array.from(maybe_array);
if (key_fn !== null) {
keys = array.map(key_fn);
} else if ((flags & EACH_KEYED) === 0) {
@ -486,6 +485,17 @@ function reconcile_tracked_array(
key = is_computed_key ? keys[a] : item;
map_set(item_index, key, a);
}
// If keys are animated, we need to do updates before actual moves
if (is_animated) {
for (b = start; b <= a_end; ++b) {
a = map_get(item_index, /** @type {V} */ (a_blocks[b].k));
if (a !== undefined) {
item = array[a];
block = a_blocks[b];
update_each_item_block(block, item, a, flags);
}
}
}
for (b = start; b <= a_end; ++b) {
a = map_get(item_index, /** @type {V} */ (a_blocks[b].k));
block = a_blocks[b];
@ -501,22 +511,9 @@ function reconcile_tracked_array(
if (pos === MOVED_BLOCK) {
mark_lis(sources);
}
// If keys are animated, we need to do updates before actual moves
var should_create;
if (is_animated) {
var i = b_length;
while (i-- > 0) {
b_end = i + start;
a = sources[i];
if (pos === MOVED_BLOCK) {
block = b_blocks[b_end];
item = array[b_end];
update_each_item_block(block, item, b_end, flags);
}
}
}
var last_block;
var last_sibling;
var should_create;
while (b_length-- > 0) {
b_end = b_length + start;
a = sources[b_length];
@ -715,7 +712,7 @@ function update_each_item_block(block, item, index, type) {
// Handle each item animations
const each_animation = block.a;
if (transitions !== null && (type & EACH_KEYED) !== 0 && each_animation !== null) {
each_animation(block, transitions, index, index_is_reactive);
each_animation(block, transitions);
}
if (index_is_reactive) {
set_signal_value(/** @type {import('./types.js').Signal<number>} */ (block.i), index);
@ -780,8 +777,8 @@ function each_item_block(item, key, index, render_fn, flags) {
const item_value = each_item_not_reactive
? item
: (flags & EACH_IS_IMMUTABLE) === 0
? mutable_source(item)
: source(item);
? mutable_source(item)
: source(item);
const index_value = (flags & EACH_INDEX_REACTIVE) === 0 ? index : source(index);
const block = create_each_item_block(item_value, index_value, key);

@ -319,7 +319,15 @@ export function event(event_name, dom, handler, capture, passive) {
capture,
passive
};
const target_handler = handler;
/**
* @this {EventTarget}
*/
function target_handler(/** @type {Event} */ event) {
handle_event_propagation(dom, event);
if (!event.cancelBubble) {
return handler.call(this, event);
}
}
dom.addEventListener(event_name, target_handler, options);
// @ts-ignore
if (dom === document.body || dom === window || dom === document) {
@ -873,8 +881,8 @@ export function bind_resize_observer(dom, type, update) {
type === 'contentRect' || type === 'contentBoxSize'
? resize_observer_content_box
: type === 'borderBoxSize'
? resize_observer_border_box
: resize_observer_device_pixel_content_box;
? resize_observer_border_box
: resize_observer_device_pixel_content_box;
const unsub = observer.observe(dom, /** @param {any} entry */ (entry) => update(entry[type]));
render_effect(() => unsub);
}
@ -1375,7 +1383,10 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
/** @type {null | import('./types.js').TemplateNode | Array<import('./types.js').TemplateNode>} */
let alternate_dom = null;
let has_mounted = false;
let has_mounted_branch = false;
/**
* @type {import("./types.js").EffectSignal | null}
*/
let current_branch_effect = null;
const if_effect = render_effect(
() => {
@ -1432,20 +1443,24 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
);
// Managed effect
const consequent_effect = render_effect(
() => {
if (consequent_dom !== null) {
(
/** @type {any} */ _,
/** @type {import("./types.js").EffectSignal | null} */ consequent_effect
) => {
const result = block.v;
if (!result && consequent_dom !== null) {
remove(consequent_dom);
consequent_dom = null;
}
if (block.v) {
if (result && current_branch_effect !== consequent_effect) {
consequent_fn(anchor_node);
if (!has_mounted_branch) {
if (current_branch_effect === null) {
// Restore previous fragment so that Svelte continues to operate in hydration mode
set_current_hydration_fragment(previous_hydration_fragment);
has_mounted_branch = true;
}
current_branch_effect = consequent_effect;
consequent_dom = block.d;
}
consequent_dom = block.d;
block.d = null;
},
block,
@ -1454,22 +1469,26 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
block.ce = consequent_effect;
// Managed effect
const alternate_effect = render_effect(
() => {
if (alternate_dom !== null) {
(
/** @type {any} */ _,
/** @type {import("./types.js").EffectSignal | null} */ alternate_effect
) => {
const result = block.v;
if (result && alternate_dom !== null) {
remove(alternate_dom);
alternate_dom = null;
}
if (!block.v) {
if (!result && current_branch_effect !== alternate_effect) {
if (alternate_fn !== null) {
alternate_fn(anchor_node);
}
if (!has_mounted_branch) {
if (current_branch_effect === null) {
// Restore previous fragment so that Svelte continues to operate in hydration mode
set_current_hydration_fragment(previous_hydration_fragment);
has_mounted_branch = true;
}
current_branch_effect = alternate_effect;
alternate_dom = block.d;
}
alternate_dom = block.d;
block.d = null;
},
block,
@ -1587,8 +1606,8 @@ export function element(anchor_node, tag_fn, render_fn, is_svg = false) {
? current_hydration_fragment !== null
? /** @type {HTMLElement | SVGElement} */ (current_hydration_fragment[0])
: is_svg
? document.createElementNS('http://www.w3.org/2000/svg', tag)
: document.createElement(tag)
? document.createElementNS('http://www.w3.org/2000/svg', tag)
: document.createElement(tag)
: null;
const prev_element = element;
if (prev_element !== null) {
@ -2803,7 +2822,7 @@ export function mount(component, options) {
).c = options.context;
}
// @ts-expect-error the public typings are not what the actual function looks like
accessors = component(anchor, options.props || {}, options.events || {});
accessors = component(anchor, options.props || {});
if (options.context) {
pop();
}
@ -2850,7 +2869,7 @@ export function mount(component, options) {
PassiveDelegatedEvents.includes(event_name)
? {
passive: true
}
}
: undefined
);
// The document listener ensures we catch events that originate from elements that were
@ -2861,7 +2880,7 @@ export function mount(component, options) {
PassiveDelegatedEvents.includes(event_name)
? {
passive: true
}
}
: undefined
);
}

@ -38,6 +38,7 @@ let current_scheduler_mode = FLUSH_MICROTASK;
// Used for handling scheduling
let is_micro_task_queued = false;
let is_task_queued = false;
let is_raf_queued = false;
// Used for $inspect
export let is_batching_effect = false;
@ -52,7 +53,7 @@ let current_queued_effects = [];
/** @type {Array<() => void>} */
let current_queued_tasks = [];
/** @type {Array<() => void>} */
let current_queued_microtasks = [];
let current_raf_tasks = [];
let flush_count = 0;
// Handle signal reactivity tree dependencies and consumer
@ -213,6 +214,8 @@ function create_computation_signal(flags, value, block) {
f: flags,
// init
i: null,
// level
l: 0,
// references
r: null,
// value
@ -237,6 +240,8 @@ function create_computation_signal(flags, value, block) {
e: null,
// flags
f: flags,
// level
l: 0,
// init
i: null,
// references
@ -341,9 +346,13 @@ function execute_signal_fn(signal) {
try {
let res;
if (is_render_effect) {
res = /** @type {(block: import('./types.js').Block) => V} */ (init)(
/** @type {import('./types.js').Block} */ (signal.b)
);
res =
/** @type {(block: import('./types.js').Block, signal: import('./types.js').Signal) => V} */ (
init
)(
/** @type {import('./types.js').Block} */ (signal.b),
/** @type {import('./types.js').Signal} */ (signal)
);
} else {
res = /** @type {() => V} */ (init)();
}
@ -552,7 +561,7 @@ function infinite_loop_guard() {
'ERR_SVELTE_TOO_MANY_UPDATES' +
(DEV
? ': Maximum update depth exceeded. This can happen when a reactive block or effect ' +
'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
'repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops.'
: '')
);
}
@ -586,11 +595,6 @@ function flush_queued_effects(effects) {
function process_microtask() {
is_micro_task_queued = false;
if (current_queued_microtasks.length > 0) {
const tasks = current_queued_microtasks.slice();
current_queued_microtasks = [];
run_all(tasks);
}
if (flush_count > 101) {
return;
}
@ -624,8 +628,53 @@ export function schedule_effect(signal, sync) {
}
if ((flags & EFFECT) !== 0) {
current_queued_effects.push(signal);
// Prevent any nested user effects from potentially triggering
// before this effect is scheduled. We know they will be destroyed
// so we can make them inert to avoid having to find them in the
// queue and remove them.
if ((flags & MANAGED) === 0) {
mark_subtree_children_inert(signal, true);
}
} else {
current_queued_pre_and_render_effects.push(signal);
// We need to ensure we insert the signal in the right topological order. In other words,
// we need to evaluate where to insert the signal based off its level and whether or not it's
// a pre-effect and within the same block. By checking the signals in the queue in reverse order
// we can find the right place quickly. TODO: maybe opt to use a linked list rather than an array
// for these operations.
const length = current_queued_pre_and_render_effects.length;
let should_append = length === 0;
if (!should_append) {
const target_level = signal.l;
const target_block = signal.b;
const is_pre_effect = (flags & PRE_EFFECT) !== 0;
let target_signal;
let is_target_pre_effect;
let i = length;
while (true) {
target_signal = current_queued_pre_and_render_effects[--i];
if (target_signal.l <= target_level) {
if (i + 1 === length) {
should_append = true;
} else {
is_target_pre_effect = (target_signal.f & PRE_EFFECT) !== 0;
if (target_signal.b !== target_block || (is_target_pre_effect && !is_pre_effect)) {
i++;
}
current_queued_pre_and_render_effects.splice(i, 0, signal);
}
break;
}
if (i === 0) {
current_queued_pre_and_render_effects.unshift(signal);
break;
}
}
}
if (should_append) {
current_queued_pre_and_render_effects.push(signal);
}
}
}
}
@ -637,6 +686,13 @@ function process_task() {
run_all(tasks);
}
function process_raf_task() {
is_raf_queued = false;
const tasks = current_raf_tasks.slice();
current_raf_tasks = [];
run_all(tasks);
}
/**
* @param {() => void} fn
* @returns {void}
@ -653,12 +709,12 @@ export function schedule_task(fn) {
* @param {() => void} fn
* @returns {void}
*/
export function schedule_microtask(fn) {
if (!is_micro_task_queued) {
is_micro_task_queued = true;
queueMicrotask(process_microtask);
export function schedule_raf_task(fn) {
if (!is_raf_queued) {
is_raf_queued = true;
requestAnimationFrame(process_raf_task);
}
current_queued_microtasks.push(fn);
current_raf_tasks.push(fn);
}
/**
@ -721,8 +777,8 @@ export function flushSync(fn) {
if (current_queued_pre_and_render_effects.length > 0 || effects.length > 0) {
flushSync();
}
if (is_micro_task_queued) {
process_microtask();
if (is_raf_queued) {
process_raf_task();
}
if (is_task_queued) {
process_task();
@ -1010,9 +1066,26 @@ export function mutate_store(store, expression, new_value) {
/**
* @param {import('./types.js').ComputationSignal} signal
* @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void}
*/
function mark_subtree_children_inert(signal, inert, visited_blocks) {
const references = signal.r;
if (references !== null) {
let i;
for (i = 0; i < references.length; i++) {
mark_subtree_inert(references[i], inert, visited_blocks);
}
}
}
/**
* @param {import('./types.js').ComputationSignal} signal
* @param {boolean} inert
* @param {Set<import('./types.js').Block>} [visited_blocks]
* @returns {void}
*/
export function mark_subtree_inert(signal, inert) {
export function mark_subtree_inert(signal, inert, visited_blocks = new Set()) {
const flags = signal.f;
const is_already_inert = (flags & INERT) !== 0;
if (is_already_inert !== inert) {
@ -1022,34 +1095,33 @@ export function mark_subtree_inert(signal, inert) {
}
// Nested if block effects
const block = signal.b;
if (block !== null) {
if (block !== null && !visited_blocks.has(block)) {
visited_blocks.add(block);
const type = block.t;
if (type === IF_BLOCK) {
const condition_effect = block.e;
if (condition_effect !== null && block !== current_block) {
mark_subtree_inert(condition_effect, inert);
}
const consequent_effect = block.ce;
if (consequent_effect !== null) {
mark_subtree_inert(consequent_effect, inert);
if (consequent_effect !== null && block.v) {
mark_subtree_inert(consequent_effect, inert, visited_blocks);
}
const alternate_effect = block.ae;
if (alternate_effect !== null) {
mark_subtree_inert(alternate_effect, inert);
if (alternate_effect !== null && !block.v) {
mark_subtree_inert(alternate_effect, inert, visited_blocks);
}
} else if (type === EACH_BLOCK) {
const items = block.v;
for (let { e: each_item_effect } of items) {
if (each_item_effect !== null) {
mark_subtree_inert(each_item_effect, inert);
mark_subtree_inert(each_item_effect, inert, visited_blocks);
}
}
}
}
}
const references = signal.r;
if (references !== null) {
let i;
for (i = 0; i < references.length; i++) {
mark_subtree_inert(references[i], inert);
}
}
mark_subtree_children_inert(signal, inert, visited_blocks);
}
/**
@ -1109,8 +1181,8 @@ export function set_signal_value(signal, value) {
'ERR_SVELTE_UNSAFE_MUTATION' +
(DEV
? ": Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. " +
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
'to be reactive do not use the "$state" rune for that declaration.'
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
'to be reactive do not use the "$state" rune for that declaration.'
: '')
);
}
@ -1280,12 +1352,15 @@ function internal_create_effect(type, init, sync, block, schedule) {
const signal = create_computation_signal(type | DIRTY, null, block);
signal.i = init;
signal.x = current_component_context;
if (current_effect !== null) {
signal.l = current_effect.l + 1;
if ((type & MANAGED) === 0) {
push_reference(current_effect, signal);
}
}
if (schedule) {
schedule_effect(signal, sync);
}
if (current_effect !== null && (type & MANAGED) === 0) {
push_reference(current_effect, signal);
}
return signal;
}
@ -1621,7 +1696,7 @@ export function safe_not_equal(a, b) {
// eslint-disable-next-line eqeqeq
return a != a
? // eslint-disable-next-line eqeqeq
b == b
b == b
: a !== b || (a !== null && typeof a === 'object') || typeof a === 'function';
}

@ -21,7 +21,7 @@ import {
managed_effect,
managed_pre_effect,
mark_subtree_inert,
schedule_microtask,
schedule_raf_task,
untrack
} from './runtime.js';
import { raf } from './timing.js';
@ -369,6 +369,47 @@ function create_transition(dom, init, direction, effect) {
},
// out
o() {
// @ts-ignore
const has_keyed_transition = dom.__animate;
// If we're outroing an element that has an animation, then we need to fix
// its position to ensure it behaves nicely without causing layout shift.
if (has_keyed_transition) {
const style = getComputedStyle(dom);
const position = style.position;
if (position !== 'absolute' && position !== 'fixed') {
const { width, height } = style;
const a = dom.getBoundingClientRect();
dom.style.position = 'absolute';
dom.style.width = width;
dom.style.height = height;
const b = dom.getBoundingClientRect();
if (a.left !== b.left || a.top !== b.top) {
const translate = `translate(${a.left - b.left}px, ${a.top - b.top}px)`;
const existing_transform = style.transform;
if (existing_transform === 'none') {
dom.style.transform = translate;
} else {
// Previously, in the Svelte 4, we'd just apply the transform the the DOM element. However,
// because we're now using Web Animations, we can't do that as it won't work properly if the
// animation is also making use of the same transformations. So instead, we apply an
// instantaneous animation and pause it on the first frame, just applying the same behavior.
// We also need to take into consideration matrix transforms and how they might combine with
// an existing behavior that is already in progress (such as scale).
// > Follow the white rabbit.
const transform = existing_transform.startsWith('matrix(1,')
? translate
: `matrix(1,0,0,1,0,0)`;
const frame = {
transform
};
const animation = dom.animate([frame, frame], { duration: 1 });
animation.pause();
}
}
}
}
const needs_reverse = direction === 'both' && curr_direction !== 'out';
curr_direction = 'out';
if (animation === null || cancelled) {
@ -432,13 +473,18 @@ function is_transition_block(block) {
export function bind_transition(dom, get_transition_fn, props_fn, direction, global) {
const transition_effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
const block = current_block;
const is_keyed_transition = direction === 'key';
let can_show_intro_on_mount = true;
let can_apply_lazy_transitions = false;
if (is_keyed_transition) {
// @ts-ignore
dom.__animate = true;
}
/** @type {import('./types.js').Block | null} */
let transition_block = block;
while (transition_block !== null) {
main: while (transition_block !== null) {
if (is_transition_block(transition_block)) {
if (transition_block.t === EACH_ITEM_BLOCK) {
// Lazily apply the each block transition
@ -446,22 +492,31 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
transition_block.a = each_item_animate;
transition_block = transition_block.p;
} else if (transition_block.t === AWAIT_BLOCK && transition_block.n /* pending */) {
can_show_intro_on_mount = false;
can_show_intro_on_mount = true;
} else if (transition_block.t === IF_BLOCK) {
transition_block.r = if_block_transition;
if (can_show_intro_on_mount) {
/** @type {import('./types.js').Block | null} */
let if_block = transition_block;
while (if_block.t === IF_BLOCK) {
// If we have an if block parent that is currently falsy then
// we can show the intro on mount as long as that block is mounted
if (if_block.e !== null && !if_block.v) {
can_show_intro_on_mount = true;
break main;
}
if_block = if_block.p;
}
}
}
if (!can_apply_lazy_transitions && can_show_intro_on_mount) {
can_show_intro_on_mount = transition_block.e === null;
can_show_intro_on_mount = transition_block.e !== null;
}
if (!can_show_intro_on_mount || !global) {
if (can_show_intro_on_mount || !global) {
can_apply_lazy_transitions = true;
}
} else if (
!can_apply_lazy_transitions &&
transition_block.t === ROOT_BLOCK &&
(transition_block.e !== null || transition_block.i)
) {
can_show_intro_on_mount = false;
} else if (transition_block.t === ROOT_BLOCK && !can_apply_lazy_transitions) {
can_show_intro_on_mount = transition_block.e !== null || transition_block.i;
}
transition_block = transition_block.p;
}
@ -470,7 +525,9 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
let transition;
effect(() => {
let already_mounted = false;
if (transition !== undefined) {
already_mounted = true;
// Destroy any existing transitions first
transition.x();
}
@ -479,23 +536,23 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
const init = (from) =>
untrack(() => {
const props = props_fn === null ? {} : props_fn();
return direction === 'key'
return is_keyed_transition
? /** @type {import('./types.js').AnimateFn<any>} */ (transition_fn)(
dom,
{ from: /** @type {DOMRect} */ (from), to: dom.getBoundingClientRect() },
props,
{}
)
)
: /** @type {import('./types.js').TransitionFn<any>} */ (transition_fn)(dom, props, {
direction
});
});
});
transition = create_transition(dom, init, direction, transition_effect);
const is_intro = direction === 'in';
const show_intro = !can_show_intro_on_mount && (is_intro || direction === 'both');
const show_intro = can_show_intro_on_mount && (is_intro || direction === 'both');
if (show_intro) {
if (show_intro && !already_mounted) {
transition.p = transition.i();
}
@ -503,7 +560,7 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
destroy_signal(effect);
dom.inert = false;
if (show_intro) {
if (show_intro && !already_mounted) {
transition.in();
}
@ -547,6 +604,7 @@ export function trigger_transitions(transitions, target_direction, from) {
const outros = [];
for (const transition of transitions) {
const direction = transition.r;
const effect = transition.e;
if (target_direction === 'in') {
if (direction === 'in' || direction === 'both') {
transition.in();
@ -554,7 +612,7 @@ export function trigger_transitions(transitions, target_direction, from) {
transition.c();
}
transition.d.inert = false;
mark_subtree_inert(transition.e, false);
mark_subtree_inert(effect, false);
} else if (target_direction === 'key') {
if (direction === 'key') {
transition.p = transition.i(/** @type {DOMRect} */ (from));
@ -566,7 +624,7 @@ export function trigger_transitions(transitions, target_direction, from) {
outros.push(transition.o);
}
transition.d.inert = true;
mark_subtree_inert(transition.e, true);
mark_subtree_inert(effect, true);
}
}
if (outros.length > 0) {
@ -599,7 +657,8 @@ function if_block_transition(transition) {
const c = /** @type {Set<import('./types.js').Transition>} */ (consequent_transitions);
c.delete(transition);
if (c.size === 0) {
execute_effect(/** @type {import('./types.js').EffectSignal} */ (block.ce));
const consequent_effect = block.ce;
execute_effect(/** @type {import('./types.js').EffectSignal} */ (consequent_effect));
}
});
} else {
@ -612,7 +671,8 @@ function if_block_transition(transition) {
const a = /** @type {Set<import('./types.js').Transition>} */ (alternate_transitions);
a.delete(transition);
if (a.size === 0) {
execute_effect(/** @type {import('./types.js').EffectSignal} */ (block.ae));
const alternate_effect = block.ae;
execute_effect(/** @type {import('./types.js').EffectSignal} */ (alternate_effect));
}
});
}
@ -646,7 +706,8 @@ function each_item_transition(transition) {
transitions.delete(transition);
if (transition.r !== 'key') {
for (let other of transitions) {
if (other.r === 'key' || other.r === 'in') {
const type = other.r;
if (type === 'key' || type === 'in') {
transitions.delete(other);
}
}
@ -664,26 +725,18 @@ function each_item_transition(transition) {
*
* @param {import('./types.js').EachItemBlock} block
* @param {Set<import('./types.js').Transition>} transitions
* @param {number} index
* @param {boolean} index_is_reactive
*/
function each_item_animate(block, transitions, index, index_is_reactive) {
let prev_index = block.i;
if (index_is_reactive) {
prev_index = /** @type {import('./types.js').Signal<number>} */ (prev_index).v;
}
const items = block.p.v;
if (prev_index !== index && /** @type {number} */ (index) < items.length) {
const from_dom = /** @type {Element} */ (get_first_element(block));
const from = from_dom.getBoundingClientRect();
// Cancel any existing key transitions
for (const transition of transitions) {
if (transition.r === 'key') {
transition.c();
}
function each_item_animate(block, transitions) {
const from_dom = /** @type {Element} */ (get_first_element(block));
const from = from_dom.getBoundingClientRect();
// Cancel any existing key transitions
for (const transition of transitions) {
const type = transition.r;
if (type === 'key') {
transition.c();
}
schedule_microtask(() => {
trigger_transitions(transitions, 'key', from);
});
}
schedule_raf_task(() => {
trigger_transitions(transitions, 'key', from);
});
}

@ -99,11 +99,17 @@ export type ComputationSignal<V = unknown> = {
/** The types that the signal represent, as a bitwise value */
f: SignalFlags;
/** init: The function that we invoke for effects and computeds */
i: null | (() => V) | (() => void | (() => void)) | ((b: Block) => void | (() => void));
i:
| null
| (() => V)
| (() => void | (() => void))
| ((b: Block, s: Signal) => void | (() => void));
/** references: Anything that a signal owns */
r: null | ComputationSignal[];
/** value: The latest value for this signal, doubles as the teardown for effects */
v: V;
/** level: the depth from the root signal, used for ordering render/pre-effects topologically **/
l: number;
};
export type Signal<V = unknown> = SourceSignal<V> | ComputationSignal<V>;
@ -288,14 +294,7 @@ export type EachBlock = {
export type EachItemBlock = {
/** transition */
a:
| null
| ((
block: EachItemBlock,
transitions: Set<Transition>,
index: number,
index_is_reactive: boolean
) => void);
a: null | ((block: EachItemBlock, transitions: Set<Transition>) => void);
/** dom */
d: null | TemplateNode | Array<TemplateNode>;
/** effect */

@ -75,8 +75,8 @@ export function validate_each_keys(collection, key_fn) {
const array = is_array(maybe_array)
? maybe_array
: maybe_array == null
? []
: Array.from(maybe_array);
? []
: Array.from(maybe_array);
const length = array.length;
for (let i = 0; i < length; i++) {
const key = key_fn(array[i], i);

@ -178,4 +178,4 @@ declare function $props<T>(): T;
*/
declare function $inspect<T extends any[]>(
...values: T
): { with: (type: 'init' | 'update', ...values: T) => void };
): { with: (fn: (type: 'init' | 'update', ...values: T) => void) => void };

@ -214,8 +214,8 @@ export interface EventDispatcher<EventMap extends Record<string, any>> {
...args: null extends EventMap[Type]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: undefined extends EventMap[Type]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
): boolean;
}

@ -33,7 +33,7 @@ export function safe_not_equal(a, b) {
// eslint-disable-next-line eqeqeq
return a != a
? // eslint-disable-next-line eqeqeq
b == b
b == b
: a !== b || (a && typeof a === 'object') || typeof a === 'function';
}

@ -12,14 +12,14 @@ function cubic_out(t) {
* @param {number} t
* @returns {number}
*/
export function cubic_in_out(t) {
function cubic_in_out(t) {
return t < 0.5 ? 4.0 * t * t * t : 0.5 * Math.pow(2.0 * t - 2.0, 3.0) + 1.0;
}
/** @param {number | string} value
* @returns {[number, string]}
*/
export function split_css_unit(value) {
function split_css_unit(value) {
const split = typeof value === 'string' && value.match(/^\s*(-?[\d.]+)([^\s]*)\s*$/);
return split ? [parseFloat(split[1]), split[2] || 'px'] : [/** @type {number} */ (value), 'px'];
}

@ -6,5 +6,5 @@
* https://svelte.dev/docs/svelte-compiler#svelte-version
* @type {string}
*/
export const VERSION = '5.0.0-next.31';
export const VERSION = '5.0.0-next.35';
export const PUBLIC_VERSION = '5';

@ -37,8 +37,8 @@ declare global {
): Key extends keyof ElementTagNameMap
? ElementTagNameMap[Key]
: Key extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Key]
: any;
? SVGElementTagNameMap[Key]
: any;
function createElement<Elements extends IntrinsicElements, Key extends keyof Elements, T>(
// "undefined | null" because of <svelte:element>
element: Key | undefined | null,
@ -47,8 +47,8 @@ declare global {
): Key extends keyof ElementTagNameMap
? ElementTagNameMap[Key]
: Key extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Key]
: any;
? SVGElementTagNameMap[Key]
: any;
// For backwards-compatibility and ease-of-use, in case someone enhanced the typings from import('svelte/elements').HTMLAttributes/SVGAttributes
// eslint-disable-next-line @typescript-eslint/no-unused-vars

@ -53,9 +53,9 @@ export default test({
divs = target.querySelectorAll('div');
assert.ok(~divs[0].style.transform);
assert.equal(divs[1].style.transform, '');
assert.equal(divs[2].style.transform, '');
assert.equal(divs[3].style.transform, '');
assert.equal(divs[1].style.transform, 'translate(1px, 0px)');
assert.equal(divs[2].style.transform, 'translate(1px, 0px)');
assert.equal(divs[3].style.transform, 'translate(1px, 0px)');
assert.ok(~divs[4].style.transform);
raf.tick(100);

@ -20,6 +20,12 @@ export default test({
b2.click();
});
assert.deepEqual(log, ['transition 2', 'transition 1', 'transition 1']);
assert.deepEqual(log, ['transition 2']);
flushSync(() => {
b1.click();
});
assert.deepEqual(log, ['transition 2', 'transition 1']);
}
});

@ -0,0 +1,20 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1] = target.querySelectorAll('button');
flushSync(() => {
b1?.click();
});
await Promise.resolve();
assert.deepEqual(log, ['clicked button']);
}
});

@ -0,0 +1,8 @@
<script>
import { log } from './log.js';
</script>
<div on:click={(e) => { log.push('clicked div') }}>
<button onclick={(e) => { log.push('clicked button'); e.stopPropagation() }}>
Button
</button>
</div>

@ -0,0 +1,20 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1] = target.querySelectorAll('button');
flushSync(() => {
b1?.click();
});
await Promise.resolve();
assert.deepEqual(log, ['clicked button']);
}
});

@ -0,0 +1,13 @@
<script>
import { log } from './log.js';
const action = () => {}
</script>
<div use:action onclick={() => log.push('clicked container')} onkeydown={() => {}}>
<div use:action onclick={(e) => { log.push('clicked div 1') }}>
<div onclick={(e) => { log.push('clicked div 2') }}>
<button onclick={(e) => { log.push('clicked button'); e.stopPropagation() }}>
Button
</button>
</div>
</div>
</div>

@ -0,0 +1,25 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1] = target.querySelectorAll('button');
flushSync(() => {
b1?.click();
});
await Promise.resolve();
assert.deepEqual(log, [
'clicked button',
'clicked div 2',
'clicked div 1',
'clicked container'
]);
}
});

@ -0,0 +1,13 @@
<script>
import { log } from './log.js';
const action = () => {}
</script>
<div use:action onclick={() => log.push('clicked container')} onkeydown={() => {}}>
<div use:action onclick={(e) => { log.push('clicked div 1') }}>
<div onclick={(e) => { log.push('clicked div 2') }}>
<button onclick={(e) => { log.push('clicked button') }}>
Button
</button>
</div>
</div>
</div>

@ -0,0 +1,16 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
html: `<button>Click</button><p>expires in 1 click</p>`,
async test({ assert, target }) {
const [btn1] = target.querySelectorAll('button');
flushSync(() => {
btn1.click();
});
assert.htmlEqual(target.innerHTML, ``);
}
});

@ -0,0 +1,13 @@
<script>
let data = $state({ num: 1 });
function expire() {
data.num = data.num - 1;
if (data.num <= 0) data = undefined;
}
</script>
{#if data}
<button onclick={expire}>Click</button>
<p>expires in {data.num} click</p>
{/if}

@ -31,9 +31,7 @@ export default test({
b2.click();
await Promise.resolve();
assert.ok(
log[0].stack.startsWith('Error:') && log[0].stack.includes('HTMLButtonElement.on_click')
);
assert.ok(log[0].stack.startsWith('Error:') && log[0].stack.includes('HTMLButtonElement.'));
assert.deepEqual(log[1], 1);
}
});

@ -0,0 +1,28 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
import { log } from './log.js';
export default test({
before_test() {
log.length = 0;
},
async test({ assert, target }) {
const [b1] = target.querySelectorAll('button');
flushSync(() => {
b1?.click();
});
await Promise.resolve();
assert.deepEqual(log, [
'top level',
'inner',
0,
'destroy inner',
undefined,
'destroy outer',
undefined
]);
}
});

@ -0,0 +1,2 @@
/** @type {any[]} */
export const log = [];

@ -0,0 +1,21 @@
<script>
import { log } from './log.js';
let c = $state({ a: 0 });
$effect(() => {
log.push('top level')
$effect(() => {
if (c) {
$effect(() => {
log.push('inner',c.a);
return () => log.push('destroy inner', c?.a);
});
}
return () => log.push('destroy outer', c?.a);
})
});
</script>
<button onclick={() => {
c.a = 1; c = null
}}>toggle</button>

@ -45,4 +45,4 @@ export default function Main($$anchor, $$props) {
$.close_frag($$anchor, fragment);
$.pop();
}
}

@ -0,0 +1,3 @@
import { test } from '../../test';
export default test({});

@ -0,0 +1,30 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import "svelte/internal/disclose-version";
import * as $ from "svelte/internal";
export default function Each_string_template($$anchor, $$props) {
$.push($$props, false);
/* Init */
var fragment = $.comment($$anchor);
var node = $.child_frag(fragment);
$.each_indexed(
node,
() => ['foo', 'bar', 'baz'],
1,
($$anchor, thing, $$index) => {
/* Init */
var node_1 = $.space($$anchor);
/* Update */
$.text_effect(node_1, () => `${$.stringify($.unwrap(thing))}, `);
$.close($$anchor, node_1);
},
null
);
$.close_frag($$anchor, fragment);
$.pop();
}

@ -0,0 +1,22 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import * as $ from "svelte/internal/server";
export default function Each_string_template($$payload, $$props) {
$.push(false);
const anchor = $.create_anchor($$payload);
const each_array = $.ensure_array_like(['foo', 'bar', 'baz']);
$$payload.out += `${anchor}`;
for (let $$index = 0; $$index < each_array.length; $$index++) {
const thing = each_array[$$index];
const anchor_1 = $.create_anchor($$payload);
$$payload.out += `${anchor_1}${$.escape(thing)}, ${anchor_1}`;
}
$$payload.out += `${anchor}`;
$.pop();
}

@ -0,0 +1,3 @@
{#each ['foo', 'bar', 'baz'] as thing}
{thing},{' '}
{/each}

@ -0,0 +1,3 @@
import { test } from '../../test';
export default test({});

@ -0,0 +1,39 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import "svelte/internal/disclose-version";
import * as $ from "svelte/internal";
function reset(_, str, tpl) {
$.set(str, '');
$.set(str, ``);
$.set(tpl, '');
$.set(tpl, ``);
}
var frag = $.template(`<input> <input> <button>reset</button>`, true);
export default function State_proxy_literal($$anchor, $$props) {
$.push($$props, true);
let str = $.source('');
let tpl = $.source(``);
/* Init */
var fragment = $.open_frag($$anchor, true, frag);
var node = $.child_frag(fragment);
$.remove_input_attr_defaults(node);
var input = $.sibling($.sibling(node));
$.remove_input_attr_defaults(input);
var button = $.sibling($.sibling(input));
$.bind_value(node, () => $.get(str), ($$value) => $.set(str, $$value));
$.bind_value(input, () => $.get(tpl), ($$value) => $.set(tpl, $$value));
button.__click = [reset, str, tpl];
$.close_frag($$anchor, fragment);
$.pop();
}
$.delegate(["click"]);

@ -0,0 +1,20 @@
// index.svelte (Svelte VERSION)
// Note: compiler output will change before 5.0 is released!
import * as $ from "svelte/internal/server";
export default function State_proxy_literal($$payload, $$props) {
$.push(true);
let str = '';
let tpl = ``;
function reset() {
str = '';
str = ``;
tpl = '';
tpl = ``;
}
$$payload.out += `<input${$.attr("value", str, false)}> <input${$.attr("value", tpl, false)}> <button>reset</button>`;
$.pop();
}

@ -0,0 +1,17 @@
<script>
let str = $state('');
let tpl = $state(``);
function reset() {
str = '';
str = ``;
tpl = '';
tpl = ``;
}
</script>
<input bind:value={str} />
<input bind:value={tpl} />
<button onclick={reset}>reset</button>

@ -14,4 +14,4 @@ export default function Svelte_element($$anchor, $$props) {
$.element(node, tag);
$.close_frag($$anchor, fragment);
$.pop();
}
}

@ -17,7 +17,7 @@ const filter = process.env.FILTER
process.env.FILTER.startsWith('/')
? process.env.FILTER.slice(1, -1).replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
: `^${process.env.FILTER.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')}$`
)
)
: /./;
export function suite<Test extends BaseTest>(fn: (config: Test, test_dir: string) => void) {

@ -215,8 +215,8 @@ declare module 'svelte' {
...args: null extends EventMap[Type]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: undefined extends EventMap[Type]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
: [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
): boolean;
}
/**
@ -515,7 +515,7 @@ declare module 'svelte/compiler' {
export function parse(source: string, options?: {
filename?: string | undefined;
modern?: boolean | undefined;
} | undefined): SvelteNode | LegacySvelteNode;
} | undefined): Root | LegacyRoot;
/**
* @deprecated Replace this with `import { walk } from 'estree-walker'`
* */
@ -780,6 +780,13 @@ declare module 'svelte/compiler' {
children: Array<LegacyElementLike>;
}
interface LegacyRoot extends BaseNode_1 {
html: LegacySvelteNode;
css?: any;
instance?: any;
module?: any;
}
interface LegacyAction extends BaseNode_1 {
type: 'Action';
/** The 'x' in `use:x` */
@ -1235,9 +1242,6 @@ declare module 'svelte/compiler' {
/** The 'y' in `on:x={y}` */
expression: null | Expression;
modifiers: string[]; // TODO specify
metadata: {
delegated: null | DelegatedEvent;
};
}
type DelegatedEvent =
@ -1321,12 +1325,6 @@ declare module 'svelte/compiler' {
svg: boolean;
/** `true` if contains a SpreadAttribute */
has_spread: boolean;
/**
* `true` if events on this element can theoretically be delegated. This doesn't necessarily mean that
* a specific event will be delegated, as there are other factors which affect the final outcome.
* `null` only until it was determined whether this element can be delegated or not.
*/
can_delegate_events: boolean | null;
};
}
@ -2082,12 +2080,6 @@ declare module 'svelte/transition' {
duration?: number | ((len: number) => number);
easing?: EasingFunction;
}
/**
* https://svelte.dev/docs/svelte-easing
* */
export function cubic_in_out(t: number): number;
export function split_css_unit(value: number | string): [number, string];
/**
* Animates a `blur` filter alongside an element's opacity.
*
@ -2574,6 +2566,6 @@ declare function $props<T>(): T;
*/
declare function $inspect<T extends any[]>(
...values: T
): { with: (type: 'init' | 'update', ...values: T) => void };
): { with: (fn: (type: 'init' | 'update', ...values: T) => void) => void };
//# sourceMappingURL=index.d.ts.map

@ -4,6 +4,9 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
jimp>xml2js: ^0.6.0
importers:
.:
@ -45,11 +48,11 @@ importers:
specifier: ^1.35.1
version: 1.39.0
prettier:
specifier: ^3.0.1
version: 3.0.3
specifier: ^3.1.1
version: 3.1.1
prettier-plugin-svelte:
specifier: ^3.0.3
version: 3.1.0(prettier@3.0.3)(svelte@packages+svelte)
specifier: ^3.1.2
version: 3.1.2(prettier@3.1.1)(svelte@packages+svelte)
typescript:
specifier: ^5.2.2
version: 5.2.2
@ -65,6 +68,9 @@ importers:
'@jridgewell/sourcemap-codec':
specifier: ^1.4.15
version: 1.4.15
'@types/estree':
specifier: ^1.0.5
version: 1.0.5
acorn:
specifier: ^8.10.0
version: 8.11.2
@ -117,9 +123,6 @@ importers:
'@types/aria-query':
specifier: ^5.0.3
version: 5.0.4
'@types/estree':
specifier: ^1.0.5
version: 1.0.5
dts-buddy:
specifier: ^0.4.3
version: 0.4.3(typescript@5.2.2)
@ -357,11 +360,11 @@ importers:
specifier: ^9.0.0
version: 9.1.6
prettier:
specifier: ^3.1.0
version: 3.1.0
specifier: ^3.1.1
version: 3.1.1
prettier-plugin-svelte:
specifier: ^3.1.2
version: 3.1.2(prettier@3.1.0)(svelte@4.2.3)
version: 3.1.2(prettier@3.1.1)(svelte@4.2.3)
sass:
specifier: ^1.67.0
version: 1.69.5
@ -6073,24 +6076,24 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
/prettier-plugin-svelte@3.1.0(prettier@3.0.3)(svelte@packages+svelte):
resolution: {integrity: sha512-96+AZxs2ESqIFA9j+o+DHqY+BsUglezfl553LQd6VOtTyJq5GPuBEb3ElxF2cerFzKlYKttlH/VcVmRNj5oc3A==}
/prettier-plugin-svelte@3.1.2(prettier@3.1.1)(svelte@4.2.3):
resolution: {integrity: sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==}
peerDependencies:
prettier: ^3.0.0
svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
dependencies:
prettier: 3.0.3
svelte: link:packages/svelte
prettier: 3.1.1
svelte: 4.2.3
dev: true
/prettier-plugin-svelte@3.1.2(prettier@3.1.0)(svelte@4.2.3):
/prettier-plugin-svelte@3.1.2(prettier@3.1.1)(svelte@packages+svelte):
resolution: {integrity: sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==}
peerDependencies:
prettier: ^3.0.0
svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
dependencies:
prettier: 3.1.0
svelte: 4.2.3
prettier: 3.1.1
svelte: link:packages/svelte
dev: true
/prettier@2.8.8:
@ -6099,14 +6102,8 @@ packages:
hasBin: true
dev: true
/prettier@3.0.3:
resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==}
engines: {node: '>=14'}
hasBin: true
dev: true
/prettier@3.1.0:
resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==}
/prettier@3.1.1:
resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==}
engines: {node: '>=14'}
hasBin: true
dev: true

@ -298,7 +298,7 @@
status = message;
}
})
})
: null;
/**

@ -535,7 +535,7 @@ async function bundle({ uid, files }) {
exports: 'named'
// sourcemap: 'inline'
})
)?.output?.[0]
)?.output?.[0]
: null;
return {

@ -41,7 +41,7 @@
"lightningcss": "^1.21.8",
"magic-string": "^0.30.3",
"marked": "^9.0.0",
"prettier": "^3.1.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"sass": "^1.67.0",
"satori": "^0.10.4",

@ -12,7 +12,7 @@ export const GET = client_id
}).toString();
throw redirect(302, Location);
}
}
: () =>
new Response(
`

Loading…
Cancel
Save