chore: rename internal object properties (#9532)

* chore: rename internal object properties

chore: rename internal object properties

order properties and add comments

add missing remove_in_transitions

* jsdoc
pull/9535/head
Dominic Gannaway 2 years ago committed by GitHub
parent 5458ea7735
commit 5809ac6758
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: rename internal object properties

@ -12,87 +12,123 @@ export const DYNAMIC_ELEMENT_BLOCK = 8;
export const SNIPPET_BLOCK = 9; export const SNIPPET_BLOCK = 9;
/** /**
* @param {Node} container
* @param {boolean} intro * @param {boolean} intro
* @returns {import('./types.js').RootBlock} * @returns {import('./types.js').RootBlock}
*/ */
export function create_root_block(container, intro) { export function create_root_block(intro) {
return { return {
dom: null, // dom
effect: null, d: null,
container, // effect
intro, e: null,
parent: null, // intro
transition: null, i: intro,
type: ROOT_BLOCK // parent
p: null,
// transition
r: null,
// type
t: ROOT_BLOCK
}; };
} }
/** @returns {import('./types.js').IfBlock} */ /** @returns {import('./types.js').IfBlock} */
export function create_if_block() { export function create_if_block() {
return { return {
current: false, // current
dom: null, c: false,
effect: null, // dom
parent: /** @type {import('./types.js').Block} */ (current_block), d: null,
transition: null, // effect
type: IF_BLOCK e: null,
// parent
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// type
t: IF_BLOCK
}; };
} }
/** @returns {import('./types.js').KeyBlock} */ /** @returns {import('./types.js').KeyBlock} */
export function create_key_block() { export function create_key_block() {
return { return {
dom: null, // dom
effect: null, d: null,
parent: /** @type {import('./types.js').Block} */ (current_block), // effect
transition: null, e: null,
type: KEY_BLOCK // parent
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// type
t: KEY_BLOCK
}; };
} }
/** @returns {import('./types.js').HeadBlock} */ /** @returns {import('./types.js').HeadBlock} */
export function create_head_block() { export function create_head_block() {
return { return {
dom: null, // dom
effect: null, d: null,
parent: /** @type {import('./types.js').Block} */ (current_block), // effect
transition: null, e: null,
type: HEAD_BLOCK // parent
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// type
t: HEAD_BLOCK
}; };
} }
/** @returns {import('./types.js').DynamicElementBlock} */ /** @returns {import('./types.js').DynamicElementBlock} */
export function create_dynamic_element_block() { export function create_dynamic_element_block() {
return { return {
dom: null, // dom
effect: null, d: null,
parent: /** @type {import('./types.js').Block} */ (current_block), // effect
transition: null, e: null,
type: DYNAMIC_ELEMENT_BLOCK // parent
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// type
t: DYNAMIC_ELEMENT_BLOCK
}; };
} }
/** @returns {import('./types.js').DynamicComponentBlock} */ /** @returns {import('./types.js').DynamicComponentBlock} */
export function create_dynamic_component_block() { export function create_dynamic_component_block() {
return { return {
dom: null, // dom
effect: null, d: null,
parent: /** @type {import('./types.js').Block} */ (current_block), // effect
transition: null, e: null,
type: DYNAMIC_COMPONENT_BLOCK // parent
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// type
t: DYNAMIC_COMPONENT_BLOCK
}; };
} }
/** @returns {import('./types.js').AwaitBlock} */ /** @returns {import('./types.js').AwaitBlock} */
export function create_await_block() { export function create_await_block() {
return { return {
dom: null, // dom
effect: null, d: null,
parent: /** @type {import('./types.js').Block} */ (current_block), // effect
pending: true, e: null,
transition: null, // parent
type: AWAIT_BLOCK p: /** @type {import('./types.js').Block} */ (current_block),
// pending
n: true,
// transition
r: null,
// type
t: AWAIT_BLOCK
}; };
} }
@ -103,15 +139,23 @@ export function create_await_block() {
*/ */
export function create_each_block(flags, anchor) { export function create_each_block(flags, anchor) {
return { return {
anchor, // anchor
dom: null, a: anchor,
flags, // dom
items: [], d: null,
effect: null, // flags
parent: /** @type {import('./types.js').Block} */ (current_block), f: flags,
transition: null, // items
transitions: [], v: [],
type: EACH_BLOCK // effect
e: null,
p: /** @type {import('./types.js').Block} */ (current_block),
// transition
r: null,
// transitions
s: [],
// type
t: EACH_BLOCK
}; };
} }
@ -123,25 +167,38 @@ export function create_each_block(flags, anchor) {
*/ */
export function create_each_item_block(item, index, key) { export function create_each_item_block(item, index, key) {
return { return {
dom: null, // dom
effect: null, d: null,
index, // effect
key, e: null,
item, i: index,
parent: /** @type {import('./types.js').EachBlock} */ (current_block), // key
transition: null, k: key,
transitions: null, // item
type: EACH_ITEM_BLOCK v: item,
// parent
p: /** @type {import('./types.js').EachBlock} */ (current_block),
// transition
r: null,
// transitions
s: null,
// type
t: EACH_ITEM_BLOCK
}; };
} }
/** @returns {import('./types.js').SnippetBlock} */ /** @returns {import('./types.js').SnippetBlock} */
export function create_snippet_block() { export function create_snippet_block() {
return { return {
dom: null, // dom
parent: /** @type {import('./types.js').Block} */ (current_block), d: null,
effect: null, // parent
transition: null, p: /** @type {import('./types.js').Block} */ (current_block),
type: SNIPPET_BLOCK // effect
e: null,
// transition
r: null,
// type
t: SNIPPET_BLOCK
}; };
} }

@ -112,7 +112,7 @@ export function reconcile_html(dom, value, svg) {
* @returns {Text | Element | Comment} * @returns {Text | Element | Comment}
*/ */
function insert_each_item_block(block, dom, is_controlled, sibling) { function insert_each_item_block(block, dom, is_controlled, sibling) {
var current = /** @type {import('./types.js').TemplateNode} */ (block.dom); var current = /** @type {import('./types.js').TemplateNode} */ (block.d);
if (sibling === null) { if (sibling === null) {
if (is_controlled) { if (is_controlled) {
return insert(current, /** @type {Element} */ (dom), null); return insert(current, /** @type {Element} */ (dom), null);
@ -128,7 +128,7 @@ function insert_each_item_block(block, dom, is_controlled, sibling) {
* @returns {Text | Element | Comment} * @returns {Text | Element | Comment}
*/ */
function get_first_child(block) { function get_first_child(block) {
var current = block.dom; var current = block.d;
if (is_array(current)) { if (is_array(current)) {
return /** @type {Text | Element | Comment} */ (current[0]); return /** @type {Text | Element | Comment} */ (current[0]);
} }
@ -147,9 +147,9 @@ function destroy_active_transition_blocks(active_transitions) {
var transition; var transition;
for (; i < length; i++) { for (; i < length; i++) {
block = active_transitions[i]; block = active_transitions[i];
transition = block.transition; transition = block.r;
if (transition !== null) { if (transition !== null) {
block.transition = null; block.r = null;
destroy_each_item_block(block, null, false); destroy_each_item_block(block, null, false);
} }
} }
@ -177,8 +177,8 @@ export function reconcile_indexed_array(
flags, flags,
apply_transitions apply_transitions
) { ) {
var a_blocks = each_block.items; var a_blocks = each_block.v;
var active_transitions = each_block.transitions; var active_transitions = each_block.s;
/** @type {number | void} */ /** @type {number | void} */
var a = a_blocks.length; var a = a_blocks.length;
@ -245,7 +245,7 @@ export function reconcile_indexed_array(
} }
} }
} }
each_block.items = b_blocks; each_block.v = b_blocks;
} }
// Reconcile arrays by the equality of the elements in the array. This algorithm // Reconcile arrays by the equality of the elements in the array. This algorithm
// is based on Ivi's reconcilation logic: // is based on Ivi's reconcilation logic:
@ -275,9 +275,9 @@ export function reconcile_tracked_array(
apply_transitions, apply_transitions,
keys keys
) { ) {
var a_blocks = each_block.items; var a_blocks = each_block.v;
const is_computed_key = keys !== null; const is_computed_key = keys !== null;
var active_transitions = each_block.transitions; var active_transitions = each_block.s;
/** @type {number | void} */ /** @type {number | void} */
var a = a_blocks.length; var a = a_blocks.length;
@ -352,7 +352,7 @@ export function reconcile_tracked_array(
// Step 1 // Step 1
outer: while (true) { outer: while (true) {
// From the end // From the end
while (a_blocks[a_end].key === key) { while (a_blocks[a_end].k === key) {
block = a_blocks[a_end--]; block = a_blocks[a_end--];
item = array[b_end]; item = array[b_end];
if (should_update_block) { if (should_update_block) {
@ -368,7 +368,7 @@ export function reconcile_tracked_array(
item = array[start]; item = array[start];
key = is_computed_key ? keys[start] : item; key = is_computed_key ? keys[start] : item;
// At the start // At the start
while (start <= a_end && start <= b_end && a_blocks[start].key === key) { while (start <= a_end && start <= b_end && a_blocks[start].k === key) {
item = array[start]; item = array[start];
block = a_blocks[start]; block = a_blocks[start];
if (should_update_block) { if (should_update_block) {
@ -410,7 +410,7 @@ export function reconcile_tracked_array(
map_set(item_index, key, a); map_set(item_index, key, a);
} }
for (b = start; b <= a_end; ++b) { for (b = start; b <= a_end; ++b) {
a = map_get(item_index, /** @type {V} */ (a_blocks[b].key)); a = map_get(item_index, /** @type {V} */ (a_blocks[b].k));
block = a_blocks[b]; block = a_blocks[b];
if (a !== undefined) { if (a !== undefined) {
pos = pos < a ? a : MOVED_BLOCK; pos = pos < a ? a : MOVED_BLOCK;
@ -464,7 +464,7 @@ export function reconcile_tracked_array(
} }
} }
} }
each_block.items = b_blocks; each_block.v = b_blocks;
} }
// Longest Increased Subsequence algorithm. // Longest Increased Subsequence algorithm.

@ -193,7 +193,7 @@ function close_template(dom, is_fragment, anchor) {
if (anchor !== null && current_hydration_fragment === null) { if (anchor !== null && current_hydration_fragment === null) {
insert(current, null, anchor); insert(current, null, anchor);
} }
block.dom = current; block.d = current;
} }
/** /**
@ -1366,15 +1366,16 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
let has_mounted = false; let has_mounted = false;
let has_mounted_branch = false; let has_mounted_branch = false;
block.transition = block.r =
/** /**
* @param {import('./types.js').Transition} transition * @param {import('./types.js').Transition} transition
* @returns {void} * @returns {void}
*/ */
(transition) => { (transition) => {
if (block.current) { // block.current
if (block.c) {
consequent_transitions.add(transition); consequent_transitions.add(transition);
transition.finished(() => { transition.f(() => {
consequent_transitions.delete(transition); consequent_transitions.delete(transition);
remove_in_transitions(consequent_transitions); remove_in_transitions(consequent_transitions);
if (consequent_transitions.size === 0) { if (consequent_transitions.size === 0) {
@ -1383,7 +1384,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
}); });
} else { } else {
alternate_transitions.add(transition); alternate_transitions.add(transition);
transition.finished(() => { transition.f(() => {
alternate_transitions.delete(transition); alternate_transitions.delete(transition);
remove_in_transitions(alternate_transitions); remove_in_transitions(alternate_transitions);
if (alternate_transitions.size === 0) { if (alternate_transitions.size === 0) {
@ -1395,8 +1396,8 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
const if_effect = render_effect( const if_effect = render_effect(
() => { () => {
const result = !!condition_fn(); const result = !!condition_fn();
if (block.current !== result || !has_mounted) { if (block.c !== result || !has_mounted) {
block.current = result; block.c = result;
if (has_mounted) { if (has_mounted) {
if (result) { if (result) {
remove_in_transitions(alternate_transitions); remove_in_transitions(alternate_transitions);
@ -1454,7 +1455,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
remove(consequent_dom); remove(consequent_dom);
consequent_dom = null; consequent_dom = null;
} }
if (block.current) { if (block.c) {
consequent_fn(anchor_node); consequent_fn(anchor_node);
if (!has_mounted_branch) { if (!has_mounted_branch) {
// Restore previous fragment so that Svelte continues to operate in hydration mode // Restore previous fragment so that Svelte continues to operate in hydration mode
@ -1462,8 +1463,8 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
has_mounted_branch = true; has_mounted_branch = true;
} }
} }
consequent_dom = block.dom; consequent_dom = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true true
@ -1475,7 +1476,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
remove(alternate_dom); remove(alternate_dom);
alternate_dom = null; alternate_dom = null;
} }
if (!block.current) { if (!block.c) {
if (alternate_fn !== null) { if (alternate_fn !== null) {
alternate_fn(anchor_node); alternate_fn(anchor_node);
} }
@ -1485,8 +1486,8 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
has_mounted_branch = true; has_mounted_branch = true;
} }
} }
alternate_dom = block.dom; alternate_dom = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true true
@ -1501,7 +1502,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) {
destroy_signal(consequent_effect); destroy_signal(consequent_effect);
destroy_signal(alternate_effect); destroy_signal(alternate_effect);
}); });
block.effect = if_effect; block.e = if_effect;
} }
export { if_block as if }; export { if_block as if };
@ -1520,10 +1521,10 @@ export function head(render_fn) {
try { try {
const head_effect = render_effect( const head_effect = render_effect(
() => { () => {
const current = block.dom; const current = block.d;
if (current !== null) { if (current !== null) {
remove(current); remove(current);
block.dom = null; block.d = null;
} }
let anchor = null; let anchor = null;
if (current_hydration_fragment === null) { if (current_hydration_fragment === null) {
@ -1536,12 +1537,12 @@ export function head(render_fn) {
false false
); );
push_destroy_fn(head_effect, () => { push_destroy_fn(head_effect, () => {
const current = block.dom; const current = block.d;
if (current !== null) { if (current !== null) {
remove(current); remove(current);
} }
}); });
block.effect = head_effect; block.e = head_effect;
} finally { } finally {
set_current_hydration_fragment(previous_hydration_fragment); set_current_hydration_fragment(previous_hydration_fragment);
} }
@ -1554,7 +1555,7 @@ export function head(render_fn) {
* @returns {void} * @returns {void}
*/ */
function swap_block_dom(block, from, to) { function swap_block_dom(block, from, to) {
const dom = block.dom; const dom = block.d;
if (is_array(dom)) { if (is_array(dom)) {
for (let i = 0; i < dom.length; i++) { for (let i = 0; i < dom.length; i++) {
if (dom[i] === from) { if (dom[i] === from) {
@ -1563,7 +1564,7 @@ function swap_block_dom(block, from, to) {
} }
} }
} else if (dom === from) { } else if (dom === from) {
block.dom = to; block.d = to;
} }
} }
@ -1607,7 +1608,7 @@ export function element(anchor_node, tag_fn, render_fn, is_svg = false) {
: null; : null;
const prev_element = element; const prev_element = element;
if (prev_element !== null) { if (prev_element !== null) {
block.dom = null; block.d = null;
} }
element = next_element; element = next_element;
if (element !== null && render_fn !== null) { if (element !== null && render_fn !== null) {
@ -1629,7 +1630,7 @@ export function element(anchor_node, tag_fn, render_fn, is_svg = false) {
if (element !== null) { if (element !== null) {
insert(element, null, anchor_node); insert(element, null, anchor_node);
if (has_prev_element) { if (has_prev_element) {
const parent_block = block.parent; const parent_block = block.p;
swap_block_dom(parent_block, prev_element, element); swap_block_dom(parent_block, prev_element, element);
} }
} }
@ -1640,12 +1641,12 @@ export function element(anchor_node, tag_fn, render_fn, is_svg = false) {
push_destroy_fn(element_effect, () => { push_destroy_fn(element_effect, () => {
if (element !== null) { if (element !== null) {
remove(element); remove(element);
block.dom = null; block.d = null;
element = null; element = null;
} }
destroy_signal(render_effect_signal); destroy_signal(render_effect_signal);
}); });
block.effect = element_effect; block.e = element_effect;
} }
/** /**
@ -1664,26 +1665,26 @@ export function component(anchor_node, component_fn, render_fn) {
/** @type {null | ((props: P) => void)} */ /** @type {null | ((props: P) => void)} */
let component = null; let component = null;
block.transition = block.r =
/** /**
* @param {import('./types.js').Transition} transition * @param {import('./types.js').Transition} transition
* @returns {void} * @returns {void}
*/ */
(transition) => { (transition) => {
const render = /** @type {import('./types.js').Render} */ (current_render); const render = /** @type {import('./types.js').Render} */ (current_render);
const transitions = render.transitions; const transitions = render.s;
transitions.add(transition); transitions.add(transition);
transition.finished(() => { transition.f(() => {
transitions.delete(transition); transitions.delete(transition);
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.effect !== null) { if (render.e !== null) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
destroy_signal(render.effect); destroy_signal(render.e);
render.effect = null; render.e = null;
} }
} }
}); });
@ -1691,29 +1692,29 @@ export function component(anchor_node, component_fn, render_fn) {
const create_render_effect = () => { const create_render_effect = () => {
/** @type {import('./types.js').Render} */ /** @type {import('./types.js').Render} */
const render = { const render = {
dom: null, d: null,
effect: null, e: null,
transitions: new Set(), s: new Set(),
prev: current_render p: current_render
}; };
// Managed effect // Managed effect
const effect = render_effect( const effect = render_effect(
() => { () => {
const current = block.dom; const current = block.d;
if (current !== null) { if (current !== null) {
remove(current); remove(current);
block.dom = null; block.d = null;
} }
if (component) { if (component) {
render_fn(component); render_fn(component);
} }
render.dom = block.dom; render.d = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true true
); );
render.effect = effect; render.e = effect;
current_render = render; current_render = render;
}; };
const render = () => { const render = () => {
@ -1722,14 +1723,15 @@ export function component(anchor_node, component_fn, render_fn) {
create_render_effect(); create_render_effect();
return; return;
} }
const transitions = render.transitions; const transitions = render.s;
remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
if (render.effect) { if (render.e) {
execute_effect(render.effect); execute_effect(render.e);
} else { } else {
create_render_effect(); create_render_effect();
} }
@ -1752,18 +1754,18 @@ export function component(anchor_node, component_fn, render_fn) {
push_destroy_fn(component_effect, () => { push_destroy_fn(component_effect, () => {
let render = current_render; let render = current_render;
while (render !== null) { while (render !== null) {
const dom = render.dom; const dom = render.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
const effect = render.effect; const effect = render.e;
if (effect !== null) { if (effect !== null) {
destroy_signal(effect); destroy_signal(effect);
} }
render = render.prev; render = render.p;
} }
}); });
block.effect = component_effect; block.e = component_effect;
} }
/** /**
@ -1791,26 +1793,26 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
/** @type {unknown} */ /** @type {unknown} */
let error = UNINITIALIZED; let error = UNINITIALIZED;
let pending = false; let pending = false;
block.transition = block.r =
/** /**
* @param {import('./types.js').Transition} transition * @param {import('./types.js').Transition} transition
* @returns {void} * @returns {void}
*/ */
(transition) => { (transition) => {
const render = /** @type {import('./types.js').Render} */ (current_render); const render = /** @type {import('./types.js').Render} */ (current_render);
const transitions = render.transitions; const transitions = render.s;
transitions.add(transition); transitions.add(transition);
transition.finished(() => { transition.f(() => {
transitions.delete(transition); transitions.delete(transition);
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.effect !== null) { if (render.e !== null) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
destroy_signal(render.effect); destroy_signal(render.e);
render.effect = null; render.e = null;
} }
} }
}); });
@ -1818,35 +1820,38 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
const create_render_effect = () => { const create_render_effect = () => {
/** @type {import('./types.js').Render} */ /** @type {import('./types.js').Render} */
const render = { const render = {
dom: null, d: null,
effect: null, e: null,
transitions: new Set(), s: new Set(),
prev: current_render p: current_render
}; };
const effect = render_effect( const effect = render_effect(
() => { () => {
if (error === UNINITIALIZED) { if (error === UNINITIALIZED) {
if (resolved_value === UNINITIALIZED) { if (resolved_value === UNINITIALIZED) {
block.pending = true; // pending = true
block.n = true;
if (pending_fn !== null) { if (pending_fn !== null) {
pending_fn(anchor_node); pending_fn(anchor_node);
} }
} else if (then_fn !== null) { } else if (then_fn !== null) {
block.pending = false; // pending = false
block.n = false;
then_fn(anchor_node, resolved_value); then_fn(anchor_node, resolved_value);
} }
} else if (catch_fn !== null) { } else if (catch_fn !== null) {
block.pending = false; // pending = false
block.n = false;
catch_fn(anchor_node, error); catch_fn(anchor_node, error);
} }
render.dom = block.dom; render.d = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true, true,
true true
); );
render.effect = effect; render.e = effect;
current_render = render; current_render = render;
}; };
const render = () => { const render = () => {
@ -1855,15 +1860,15 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
create_render_effect(); create_render_effect();
return; return;
} }
const transitions = render.transitions; const transitions = render.s;
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
if (render.effect) { if (render.e) {
execute_effect(render.effect); execute_effect(render.e);
} else { } else {
create_render_effect(); create_render_effect();
} }
@ -1918,18 +1923,18 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) {
let render = current_render; let render = current_render;
latest_token = {}; latest_token = {};
while (render !== null) { while (render !== null) {
const dom = render.dom; const dom = render.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
const effect = render.effect; const effect = render.e;
if (effect !== null) { if (effect !== null) {
destroy_signal(effect); destroy_signal(effect);
} }
render = render.prev; render = render.p;
} }
}); });
block.effect = await_effect; block.e = await_effect;
} }
export { await_block as await }; export { await_block as await };
@ -1950,26 +1955,26 @@ export function key(anchor_node, key, render_fn) {
/** @type {V | typeof UNINITIALIZED} */ /** @type {V | typeof UNINITIALIZED} */
let key_value = UNINITIALIZED; let key_value = UNINITIALIZED;
let mounted = false; let mounted = false;
block.transition = block.r =
/** /**
* @param {import('./types.js').Transition} transition * @param {import('./types.js').Transition} transition
* @returns {void} * @returns {void}
*/ */
(transition) => { (transition) => {
const render = /** @type {import('./types.js').Render} */ (current_render); const render = /** @type {import('./types.js').Render} */ (current_render);
const transitions = render.transitions; const transitions = render.s;
transitions.add(transition); transitions.add(transition);
transition.finished(() => { transition.f(() => {
transitions.delete(transition); transitions.delete(transition);
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.effect !== null) { if (render.e !== null) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
destroy_signal(render.effect); destroy_signal(render.e);
render.effect = null; render.e = null;
} }
} }
}); });
@ -1977,22 +1982,22 @@ export function key(anchor_node, key, render_fn) {
const create_render_effect = () => { const create_render_effect = () => {
/** @type {import('./types.js').Render} */ /** @type {import('./types.js').Render} */
const render = { const render = {
dom: null, d: null,
effect: null, e: null,
transitions: new Set(), s: new Set(),
prev: current_render p: current_render
}; };
const effect = render_effect( const effect = render_effect(
() => { () => {
render_fn(anchor_node); render_fn(anchor_node);
render.dom = block.dom; render.d = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true, true,
true true
); );
render.effect = effect; render.e = effect;
current_render = render; current_render = render;
}; };
const render = () => { const render = () => {
@ -2001,15 +2006,15 @@ export function key(anchor_node, key, render_fn) {
create_render_effect(); create_render_effect();
return; return;
} }
const transitions = render.transitions; const transitions = render.s;
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (render.dom !== null) { if (render.d !== null) {
remove(render.dom); remove(render.d);
render.dom = null; render.d = null;
} }
if (render.effect) { if (render.e) {
execute_effect(render.effect); execute_effect(render.e);
} else { } else {
create_render_effect(); create_render_effect();
} }
@ -2036,18 +2041,18 @@ export function key(anchor_node, key, render_fn) {
push_destroy_fn(key_effect, () => { push_destroy_fn(key_effect, () => {
let render = current_render; let render = current_render;
while (render !== null) { while (render !== null) {
const dom = render.dom; const dom = render.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
const effect = render.effect; const effect = render.e;
if (effect !== null) { if (effect !== null) {
destroy_signal(effect); destroy_signal(effect);
} }
render = render.prev; render = render.p;
} }
}); });
block.effect = key_effect; block.e = key_effect;
} }
/** /**
@ -2055,7 +2060,7 @@ export function key(anchor_node, key, render_fn) {
* @returns {Text | Element | Comment} * @returns {Text | Element | Comment}
*/ */
function get_first_element(block) { function get_first_element(block) {
const current = block.dom; const current = block.d;
if (is_array(current)) { if (is_array(current)) {
for (let i = 0; i < current.length; i++) { for (let i = 0; i < current.length; i++) {
const node = current[i]; const node = current[i];
@ -2076,17 +2081,17 @@ function get_first_element(block) {
*/ */
export function update_each_item_block(block, item, index, type) { export function update_each_item_block(block, item, index, type) {
if ((type & EACH_ITEM_REACTIVE) !== 0) { if ((type & EACH_ITEM_REACTIVE) !== 0) {
set_signal_value(block.item, item); set_signal_value(block.v, item);
} }
const transitions = block.transitions; const transitions = block.s;
const index_is_reactive = (type & EACH_INDEX_REACTIVE) !== 0; const index_is_reactive = (type & EACH_INDEX_REACTIVE) !== 0;
// Handle each item animations // Handle each item animations
if (transitions !== null && (type & EACH_KEYED) !== 0) { if (transitions !== null && (type & EACH_KEYED) !== 0) {
let prev_index = block.index; let prev_index = block.i;
if (index_is_reactive) { if (index_is_reactive) {
prev_index = /** @type {import('./types.js').Signal<number>} */ (prev_index).v; prev_index = /** @type {import('./types.js').Signal<number>} */ (prev_index).v;
} }
const items = block.parent.items; const items = block.p.v;
if (prev_index !== index && /** @type {number} */ (index) < items.length) { if (prev_index !== index && /** @type {number} */ (index) < items.length) {
const from_dom = /** @type {Element} */ (get_first_element(block)); const from_dom = /** @type {Element} */ (get_first_element(block));
const from = from_dom.getBoundingClientRect(); const from = from_dom.getBoundingClientRect();
@ -2096,9 +2101,9 @@ export function update_each_item_block(block, item, index, type) {
} }
} }
if (index_is_reactive) { if (index_is_reactive) {
set_signal_value(/** @type {import('./types.js').Signal<number>} */ (block.index), index); set_signal_value(/** @type {import('./types.js').Signal<number>} */ (block.i), index);
} else { } else {
block.index = index; block.i = index;
} }
} }
@ -2115,18 +2120,18 @@ export function destroy_each_item_block(
apply_transitions, apply_transitions,
controlled = false controlled = false
) { ) {
const transitions = block.transitions; const transitions = block.s;
if (apply_transitions && transitions !== null) { if (apply_transitions && transitions !== null) {
trigger_transitions(transitions, 'out'); trigger_transitions(transitions, 'out');
if (transition_block !== null) { if (transition_block !== null) {
transition_block.push(block); transition_block.push(block);
} }
} else { } else {
const dom = block.dom; const dom = block.d;
if (!controlled && dom !== null) { if (!controlled && dom !== null) {
remove(dom); remove(dom);
} }
destroy_signal(/** @type {import('./types.js').EffectSignal} */ (block.effect)); destroy_signal(/** @type {import('./types.js').EffectSignal} */ (block.e));
} }
} }
@ -2146,12 +2151,12 @@ export function each_item_block(item, key, index, render_fn, flags) {
const effect = render_effect( const effect = render_effect(
/** @param {import('./types.js').EachItemBlock} block */ /** @param {import('./types.js').EachItemBlock} block */
(block) => { (block) => {
render_fn(null, block.item, block.index); render_fn(null, block.v, block.i);
}, },
block, block,
true true
); );
block.effect = effect; block.e = effect;
return block; return block;
} }
@ -2182,23 +2187,23 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
/** @type {null | import('./types.js').EffectSignal} */ /** @type {null | import('./types.js').EffectSignal} */
let render = null; let render = null;
block.transition = block.r =
/** @param {import('./types.js').Transition} transition */ /** @param {import('./types.js').Transition} transition */
(transition) => { (transition) => {
const fallback = /** @type {import('./types.js').Render} */ (current_fallback); const fallback = /** @type {import('./types.js').Render} */ (current_fallback);
const transitions = fallback.transitions; const transitions = fallback.s;
transitions.add(transition); transitions.add(transition);
transition.finished(() => { transition.f(() => {
transitions.delete(transition); transitions.delete(transition);
remove_in_transitions(transitions); remove_in_transitions(transitions);
if (transitions.size === 0) { if (transitions.size === 0) {
if (fallback.effect !== null) { if (fallback.e !== null) {
if (fallback.dom !== null) { if (fallback.d !== null) {
remove(fallback.dom); remove(fallback.d);
fallback.dom = null; fallback.d = null;
} }
destroy_signal(fallback.effect); destroy_signal(fallback.e);
fallback.effect = null; fallback.e = null;
} }
} }
}); });
@ -2206,33 +2211,33 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
const create_fallback_effect = () => { const create_fallback_effect = () => {
/** @type {import('./types.js').Render} */ /** @type {import('./types.js').Render} */
const fallback = { const fallback = {
dom: null, d: null,
effect: null, e: null,
transitions: new Set(), s: new Set(),
prev: current_fallback p: current_fallback
}; };
// Managed effect // Managed effect
const effect = render_effect( const effect = render_effect(
() => { () => {
const dom = block.dom; const dom = block.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
block.dom = null; block.d = null;
} }
let anchor = block.anchor; let anchor = block.a;
const is_controlled = (block.flags & EACH_IS_CONTROLLED) !== 0; const is_controlled = (block.f & EACH_IS_CONTROLLED) !== 0;
if (is_controlled) { if (is_controlled) {
anchor = empty(); anchor = empty();
block.anchor.appendChild(anchor); block.a.appendChild(anchor);
} }
/** @type {(anchor: Node) => void} */ (fallback_fn)(anchor); /** @type {(anchor: Node) => void} */ (fallback_fn)(anchor);
fallback.dom = block.dom; fallback.d = block.d;
block.dom = null; block.d = null;
}, },
block, block,
true true
); );
fallback.effect = effect; fallback.e = effect;
current_fallback = fallback; current_fallback = fallback;
}; };
const each = render_effect( const each = render_effect(
@ -2249,16 +2254,16 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
} }
if (fallback_fn !== null) { if (fallback_fn !== null) {
if (array.length === 0) { if (array.length === 0) {
if (block.items.length !== 0 || render === null) { if (block.v.length !== 0 || render === null) {
create_fallback_effect(); create_fallback_effect();
} }
} else if (block.items.length === 0 && current_fallback !== null) { } else if (block.v.length === 0 && current_fallback !== null) {
const fallback = current_fallback; const fallback = current_fallback;
const transitions = fallback.transitions; const transitions = fallback.s;
if (transitions.size === 0) { if (transitions.size === 0) {
if (fallback.dom !== null) { if (fallback.d !== null) {
remove(fallback.dom); remove(fallback.d);
fallback.dom = null; fallback.d = null;
} }
} else { } else {
trigger_transitions(transitions, 'out'); trigger_transitions(transitions, 'out');
@ -2275,35 +2280,35 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re
render = render_effect( render = render_effect(
/** @param {import('./types.js').EachBlock} block */ /** @param {import('./types.js').EachBlock} block */
(block) => { (block) => {
const flags = block.flags; const flags = block.f;
const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
const anchor_node = block.anchor; const anchor_node = block.a;
reconcile_fn(array, block, anchor_node, is_controlled, render_fn, flags, true, keys); reconcile_fn(array, block, anchor_node, is_controlled, render_fn, flags, true, keys);
}, },
block, block,
true true
); );
push_destroy_fn(each, () => { push_destroy_fn(each, () => {
const flags = block.flags; const flags = block.f;
const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
const anchor_node = block.anchor; const anchor_node = block.a;
let fallback = current_fallback; let fallback = current_fallback;
while (fallback !== null) { while (fallback !== null) {
const dom = fallback.dom; const dom = fallback.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
const effect = fallback.effect; const effect = fallback.e;
if (effect !== null) { if (effect !== null) {
destroy_signal(effect); destroy_signal(effect);
} }
fallback = fallback.prev; fallback = fallback.p;
} }
// Clear the array // Clear the array
reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys); reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys);
destroy_signal(/** @type {import('./types.js').EffectSignal} */ (render)); destroy_signal(/** @type {import('./types.js').EffectSignal} */ (render));
}); });
block.effect = each; block.e = each;
} }
/** /**
@ -3071,7 +3076,7 @@ export function mount(component, options) {
init_operations(); init_operations();
const registered_events = new Set(); const registered_events = new Set();
const container = options.target; const container = options.target;
const block = create_root_block(container, options.intro || false); const block = create_root_block(options.intro || false);
const first_child = /** @type {ChildNode} */ (container.firstChild); const first_child = /** @type {ChildNode} */ (container.firstChild);
const hydration_fragment = get_hydration_fragment(first_child); const hydration_fragment = get_hydration_fragment(first_child);
const previous_hydration_fragment = current_hydration_fragment; const previous_hydration_fragment = current_hydration_fragment;
@ -3094,7 +3099,7 @@ export function mount(component, options) {
push({}); push({});
/** @type {import('../client/types.js').ComponentContext} */ ( /** @type {import('../client/types.js').ComponentContext} */ (
current_component_context current_component_context
).context = options.context; ).c = options.context;
} }
// @ts-expect-error the public typings are not what the actual function looks like // @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 || {}, options.events || {});
@ -3105,7 +3110,7 @@ export function mount(component, options) {
block, block,
true true
); );
block.effect = effect; block.e = effect;
} catch (error) { } catch (error) {
if (options.recover !== false && hydration_fragment !== null) { if (options.recover !== false && hydration_fragment !== null) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@ -3153,14 +3158,14 @@ export function mount(component, options) {
container.removeEventListener(event_name, bound_event_listener); container.removeEventListener(event_name, bound_event_listener);
} }
root_event_handles.delete(event_handle); root_event_handles.delete(event_handle);
const dom = block.dom; const dom = block.d;
if (dom !== null) { if (dom !== null) {
remove(dom); remove(dom);
} }
if (hydration_fragment !== null) { if (hydration_fragment !== null) {
remove(hydration_fragment); remove(hydration_fragment);
} }
destroy_signal(/** @type {import('./types.js').EffectSignal} */ (block.effect)); destroy_signal(/** @type {import('./types.js').EffectSignal} */ (block.e));
} }
]; ];
} }
@ -3196,8 +3201,8 @@ export function snippet_effect(create_snippet) {
render_effect(() => { render_effect(() => {
create_snippet(); create_snippet();
return () => { return () => {
if (block.dom !== null) { if (block.d !== null) {
remove(block.dom); remove(block.d);
} }
}; };
}, block); }, block);
@ -3233,57 +3238,3 @@ function get_root_for_style(node) {
} }
return /** @type {Document} */ (node.ownerDocument); return /** @type {Document} */ (node.ownerDocument);
} }
/**
* @param {string} message
* @param {string} filename
* @param {Array<{ line: number; highlight: boolean; source: string }>} [code_highlights]
* @returns {void}
*/
export function compile_error(message, filename, code_highlights) {
// Construct error page
const page = document.createElement('div');
const container = document.createElement('div');
const pre = document.createElement('pre');
const h1 = document.createElement('h1');
const h2 = document.createElement('h2');
const p = document.createElement('p');
h1.textContent = 'Compilation Error';
h2.textContent = message;
p.textContent = filename;
pre.appendChild(h1);
pre.appendChild(h2);
if (code_highlights) {
const code_container = document.createElement('div');
for (const line of code_highlights) {
const code_line = document.createElement('div');
const code_line_number = document.createElement('span');
code_line_number.textContent = String(line.line);
const code_source = document.createElement('span');
code_source.textContent = line.source;
if (line.highlight) {
code_line.style.cssText = 'padding:8px;background:#333;color:#fff';
} else {
code_line.style.cssText = 'padding:8px;background:#000;color:#999';
}
code_line_number.style.cssText = 'color:#888;padding:0 15px 0 5px;text-align:right;';
code_line.appendChild(code_line_number);
code_line.appendChild(code_source);
code_container.appendChild(code_line);
}
pre.appendChild(code_container);
}
h1.style.cssText = 'color:#ff5555;font-weight:normal;margin-top:0;padding:0;font-size:20px;';
h2.style.cssText =
'color:#ccc;font-weight:normal;margin-top:0;padding:0;font-size:16px;white-space:normal;';
p.style.cssText = 'color: #999;';
page.style.cssText =
'z-index:9999;margin:0;position:fixed;top: 0;left: 0;height:100%;width:100%;background:rgba(0,0,0,0.66)';
container.style.cssText = `background:#181818;margin:30px auto;padding:25px 40px;position:relative;color:#d8d8d8;border-radius:6px 6px 8px 8px;width:800px;font-family:'SF Mono', SFMono-Regular, ui-monospace,'DejaVu Sans Mono', Menlo, Consolas, monospace;;border-top:8px solid #ff5555;`;
pre.appendChild(p);
container.appendChild(pre);
page.appendChild(container);
document.body.appendChild(page);
// eslint-disable-next-line no-console
console.error('[Compilation Error] ' + message);
}

@ -94,15 +94,24 @@ export function set_is_ssr(ssr) {
export function create_component_context(props) { export function create_component_context(props) {
const parent = current_component_context; const parent = current_component_context;
return { return {
effects: null, // accessors
props, a: null,
parent, // context
accessors: null, c: null,
context: null, // effects
immutable: false, e: null,
mounted: false, // immutable
runes: false, i: false,
update_callbacks: null // mounted
m: false,
// parent
p: parent,
// props
s: props,
// runes
r: false,
// update_callbacks
u: null
}; };
} }
@ -112,7 +121,7 @@ export function create_component_context(props) {
*/ */
function is_runes(context) { function is_runes(context) {
const component_context = context || current_component_context; const component_context = context || current_component_context;
return component_context !== null && component_context.runes; return component_context !== null && component_context.r;
} }
/** /**
@ -139,14 +148,19 @@ function default_equals(a, b) {
* @returns {import('./types.js').SourceSignal<V>} * @returns {import('./types.js').SourceSignal<V>}
*/ */
function create_source_signal(flags, value) { function create_source_signal(flags, value) {
return { const source = {
// consumers
c: null, c: null,
// We can remove this if we get rid of beforeUpdate/afterUpdate // equals
x: null,
e: null, e: null,
// flags
f: flags, f: flags,
v: value // value
v: value,
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
x: null
}; };
return source;
} }
/** /**
@ -158,16 +172,26 @@ function create_source_signal(flags, value) {
*/ */
function create_computation_signal(flags, value, block) { function create_computation_signal(flags, value, block) {
return { return {
// block
b: block, b: block,
// consumers
c: null, c: null,
x: null, // destroy
d: null, d: null,
y: null, // equals
e: null, e: null,
// flags
f: flags, f: flags,
// init
i: null, i: null,
// references
r: null, r: null,
v: value // value
v: value,
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
x: null,
// destroy
y: null
}; };
} }
@ -252,8 +276,9 @@ function execute_signal_fn(signal) {
current_untracking = false; current_untracking = false;
// Render effects are invoked when the UI is about to be updated - run beforeUpdate at that point // Render effects are invoked when the UI is about to be updated - run beforeUpdate at that point
if (is_render_effect && current_component_context?.update_callbacks != null) { if (is_render_effect && current_component_context?.u != null) {
current_component_context.update_callbacks.execute(); // update_callbacks.execute()
current_component_context.u.e();
} }
try { try {
@ -978,12 +1003,12 @@ export function set_signal_value(signal, value) {
// then we will need to manually invoke the beforeUpdate/afterUpdate logic. // then we will need to manually invoke the beforeUpdate/afterUpdate logic.
// TODO: should we put this being a is_runes check and only run it in non-runes mode? // TODO: should we put this being a is_runes check and only run it in non-runes mode?
if (current_effect === null && current_queued_pre_and_render_effects.length === 0) { if (current_effect === null && current_queued_pre_and_render_effects.length === 0) {
const update_callbacks = component_context?.update_callbacks; const update_callbacks = component_context?.u;
if (update_callbacks != null) { if (update_callbacks != null) {
update_callbacks.before.forEach(/** @param {any} c */ (c) => c()); update_callbacks.b.forEach(/** @param {any} c */ (c) => c());
const managed = managed_effect(() => { const managed = managed_effect(() => {
destroy_signal(managed); destroy_signal(managed);
update_callbacks.after.forEach(/** @param {any} c */ (c) => c()); update_callbacks.a.forEach(/** @param {any} c */ (c) => c());
}); });
} }
} }
@ -1070,7 +1095,7 @@ function get_equals_method(equals) {
return equals; return equals;
} }
const context = current_component_context; const context = current_component_context;
if (context && !context.immutable) { if (context && !context.i) {
return safe_equal; return safe_equal;
} }
return default_equals; return default_equals;
@ -1126,7 +1151,7 @@ export function user_effect(init) {
const apply_component_effect_heuristics = const apply_component_effect_heuristics =
current_effect.f & RENDER_EFFECT && current_effect.f & RENDER_EFFECT &&
current_component_context !== null && current_component_context !== null &&
!current_component_context.mounted; !current_component_context.m;
const effect = internal_create_effect( const effect = internal_create_effect(
EFFECT, EFFECT,
init, init,
@ -1136,11 +1161,10 @@ export function user_effect(init) {
); );
if (apply_component_effect_heuristics) { if (apply_component_effect_heuristics) {
let effects = /** @type {import('./types.js').ComponentContext} */ (current_component_context) let effects = /** @type {import('./types.js').ComponentContext} */ (current_component_context)
.effects; .e;
if (effects === null) { if (effects === null) {
effects = /** @type {import('./types.js').ComponentContext} */ ( effects = /** @type {import('./types.js').ComponentContext} */ (current_component_context).e =
current_component_context [];
).effects = [];
} }
effects.push(effect); effects.push(effect);
} }
@ -1350,7 +1374,7 @@ export function prop_source(props_obj, key, default_value, call_default_value) {
// Needs special equality checking because the prop in the // Needs special equality checking because the prop in the
// parent could be changed through `foo.bar = 'new value'`. // parent could be changed through `foo.bar = 'new value'`.
const immutable = /** @type {import('./types.js').ComponentContext} */ (current_component_context) const immutable = /** @type {import('./types.js').ComponentContext} */ (current_component_context)
.immutable; .i;
let ignore_next1 = false; let ignore_next1 = false;
let ignore_next2 = false; let ignore_next2 = false;
@ -1462,10 +1486,10 @@ export function get_or_init_context_map() {
if (component_context === null) { if (component_context === null) {
throw new Error('Context can only be used during component initialisation.'); throw new Error('Context can only be used during component initialisation.');
} }
let context_map = component_context.context; let context_map = component_context.c;
if (context_map === null) { if (context_map === null) {
const parent_context = get_parent_context(component_context); const parent_context = get_parent_context(component_context);
context_map = component_context.context = new Map(parent_context || undefined); context_map = component_context.c = new Map(parent_context || undefined);
} }
return context_map; return context_map;
} }
@ -1475,13 +1499,13 @@ export function get_or_init_context_map() {
* @returns {Map<unknown, unknown> | null} * @returns {Map<unknown, unknown> | null}
*/ */
function get_parent_context(component_context) { function get_parent_context(component_context) {
let parent = component_context.parent; let parent = component_context.p;
while (parent !== null) { while (parent !== null) {
const context_map = parent.context; const context_map = parent.c;
if (context_map !== null) { if (context_map !== null) {
return context_map; return context_map;
} }
parent = parent.parent; parent = parent.p;
} }
return null; return null;
} }
@ -1656,8 +1680,8 @@ export function onDestroy(fn) {
*/ */
export function push(props, runes = false, immutable = false) { export function push(props, runes = false, immutable = false) {
const context_stack_item = create_component_context(props); const context_stack_item = create_component_context(props);
context_stack_item.runes = runes; context_stack_item.r = runes;
context_stack_item.immutable = immutable; context_stack_item.i = immutable;
current_component_context = context_stack_item; current_component_context = context_stack_item;
} }
@ -1669,16 +1693,16 @@ export function pop(accessors) {
const context_stack_item = current_component_context; const context_stack_item = current_component_context;
if (context_stack_item !== null) { if (context_stack_item !== null) {
if (accessors !== undefined) { if (accessors !== undefined) {
context_stack_item.accessors = accessors; context_stack_item.a = accessors;
} }
const effects = context_stack_item.effects; const effects = context_stack_item.e;
if (effects !== null) { if (effects !== null) {
context_stack_item.effects = null; context_stack_item.e = null;
for (let i = 0; i < effects.length; i++) { for (let i = 0; i < effects.length; i++) {
schedule_effect(effects[i], false); schedule_effect(effects[i], false);
} }
} }
current_component_context = context_stack_item.parent; current_component_context = context_stack_item.p;
context_stack_item.mounted = true; context_stack_item.m = true;
} }
} }

@ -267,7 +267,7 @@ function create_transition(dom, init, direction, effect) {
let cancelled = false; let cancelled = false;
const create_animation = () => { const create_animation = () => {
let payload = /** @type {import('./types.js').TransitionPayload} */ (transition.payload); let payload = /** @type {import('./types.js').TransitionPayload} */ (transition.p);
if (typeof payload === 'function') { if (typeof payload === 'function') {
// @ts-ignore // @ts-ignore
payload = payload({ direction: curr_direction }); payload = payload({ direction: curr_direction });
@ -332,12 +332,14 @@ function create_transition(dom, init, direction, effect) {
/** @type {import('./types.js').Transition} */ /** @type {import('./types.js').Transition} */
const transition = { const transition = {
effect, e: effect,
init, i: init,
payload: null, // payload
p: null,
// finished
/** @param {() => void} fn */ /** @param {() => void} fn */
finished(fn) { f(fn) {
subs.push(fn); subs.push(fn);
}, },
in() { in() {
@ -353,7 +355,8 @@ function create_transition(dom, init, direction, effect) {
} }
/** @type {Animation | TickAnimation} */ (animation).play(); /** @type {Animation | TickAnimation} */ (animation).play();
}, },
out() { // out
o() {
const needs_reverse = direction === 'both' && curr_direction !== 'out'; const needs_reverse = direction === 'both' && curr_direction !== 'out';
curr_direction = 'out'; curr_direction = 'out';
if (animation === null || cancelled) { if (animation === null || cancelled) {
@ -367,18 +370,20 @@ function create_transition(dom, init, direction, effect) {
/** @type {Animation | TickAnimation} */ (animation).play(); /** @type {Animation | TickAnimation} */ (animation).play();
} }
}, },
cancel() { // cancel
c() {
/** @type {Animation | TickAnimation} */ (animation).cancel(); /** @type {Animation | TickAnimation} */ (animation).cancel();
cancelled = true; cancelled = true;
}, },
cleanup() { // cleanup
x() {
for (const sub of subs) { for (const sub of subs) {
sub(); sub();
} }
subs = []; subs = [];
}, },
direction, r: direction,
dom d: dom
}; };
return transition; return transition;
} }
@ -388,13 +393,14 @@ function create_transition(dom, init, direction, effect) {
* @returns {boolean} * @returns {boolean}
*/ */
function is_transition_block(block) { function is_transition_block(block) {
const type = block.t;
return ( return (
block.type === IF_BLOCK || type === IF_BLOCK ||
block.type === EACH_ITEM_BLOCK || type === EACH_ITEM_BLOCK ||
block.type === KEY_BLOCK || type === KEY_BLOCK ||
block.type === AWAIT_BLOCK || type === AWAIT_BLOCK ||
block.type === DYNAMIC_COMPONENT_BLOCK || type === DYNAMIC_COMPONENT_BLOCK ||
(block.type === EACH_BLOCK && block.items.length === 0) (type === EACH_BLOCK && block.v.length === 0)
); );
} }
@ -418,26 +424,26 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global)
let transition_block = block; let transition_block = block;
while (transition_block !== null) { while (transition_block !== null) {
if (is_transition_block(transition_block)) { if (is_transition_block(transition_block)) {
if (transition_block.type === EACH_ITEM_BLOCK) { if (transition_block.t === EACH_ITEM_BLOCK) {
// Lazily apply the each block transition // Lazily apply the each block transition
transition_block.transition = each_item_transition; transition_block.r = each_item_transition;
transition_block = transition_block.parent; transition_block = transition_block.p;
} else if (transition_block.type === AWAIT_BLOCK && transition_block.pending) { } else if (transition_block.t === AWAIT_BLOCK && transition_block.n /* pending */) {
skip_intro = false; skip_intro = false;
} }
if (skip_intro) { if (skip_intro) {
skip_intro = transition_block.effect === null; skip_intro = transition_block.e === null;
} }
if (!skip_intro || !global) { if (!skip_intro || !global) {
break; break;
} }
} else if ( } else if (
transition_block.type === ROOT_BLOCK && transition_block.t === ROOT_BLOCK &&
(transition_block.effect !== null || transition_block.intro) (transition_block.e !== null || transition_block.i)
) { ) {
skip_intro = false; skip_intro = false;
} }
transition_block = transition_block.parent; transition_block = transition_block.p;
} }
/** @type {import('./types.js').Transition} */ /** @type {import('./types.js').Transition} */
@ -464,7 +470,7 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global)
const show_intro = !skip_intro && (is_intro || direction === 'both'); const show_intro = !skip_intro && (is_intro || direction === 'both');
if (show_intro) { if (show_intro) {
transition.payload = transition.init(); transition.p = transition.i();
} }
const effect = managed_pre_effect(() => { const effect = managed_pre_effect(() => {
@ -478,15 +484,14 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global)
/** @type {import('./types.js').Block | null} */ /** @type {import('./types.js').Block | null} */
let transition_block = block; let transition_block = block;
while (transition_block !== null) { while (transition_block !== null) {
const parent = transition_block.parent; const parent = transition_block.p;
if (is_transition_block(transition_block)) { if (is_transition_block(transition_block)) {
if (transition_block.transition !== null) { if (transition_block.r !== null) {
transition_block.transition(transition); transition_block.r(transition);
} }
if ( if (
parent === null || parent === null ||
(!global && (!global && (transition_block.t !== IF_BLOCK || parent.t !== IF_BLOCK || parent.c))
(transition_block.type !== IF_BLOCK || parent.type !== IF_BLOCK || parent.current))
) { ) {
break; break;
} }
@ -499,7 +504,7 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global)
if (direction === 'key') { if (direction === 'key') {
effect(() => { effect(() => {
return () => { return () => {
transition.cleanup(); transition.x();
}; };
}); });
} }
@ -509,9 +514,10 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global)
* @param {Set<import('./types.js').Transition>} transitions * @param {Set<import('./types.js').Transition>} transitions
*/ */
export function remove_in_transitions(transitions) { export function remove_in_transitions(transitions) {
for (let other of transitions) { for (let transition of transitions) {
if (other.direction === 'in') { const direction = transition.r;
transitions.delete(other); if (direction === 'in') {
transitions.delete(transition);
} }
} }
} }
@ -526,27 +532,27 @@ export function trigger_transitions(transitions, target_direction, from) {
/** @type {Array<() => void>} */ /** @type {Array<() => void>} */
const outros = []; const outros = [];
for (const transition of transitions) { for (const transition of transitions) {
const direction = transition.direction; const direction = transition.r;
if (target_direction === 'in') { if (target_direction === 'in') {
if (direction === 'in' || direction === 'both') { if (direction === 'in' || direction === 'both') {
transition.in(); transition.in();
} else { } else {
transition.cancel(); transition.c();
} }
transition.dom.inert = false; transition.d.inert = false;
mark_subtree_inert(transition.effect, false); mark_subtree_inert(transition.e, false);
} else if (target_direction === 'key') { } else if (target_direction === 'key') {
if (direction === 'key') { if (direction === 'key') {
transition.payload = transition.init(/** @type {DOMRect} */ (from)); transition.p = transition.i(/** @type {DOMRect} */ (from));
transition.in(); transition.in();
} }
} else { } else {
if (direction === 'out' || direction === 'both') { if (direction === 'out' || direction === 'both') {
transition.payload = transition.init(); transition.p = transition.i();
outros.push(transition.out); outros.push(transition.o);
} }
transition.dom.inert = true; transition.d.inert = true;
mark_subtree_inert(transition.effect, true); mark_subtree_inert(transition.e, true);
} }
} }
if (outros.length > 0) { if (outros.length > 0) {
@ -568,33 +574,33 @@ export function trigger_transitions(transitions, target_direction, from) {
*/ */
function each_item_transition(transition) { function each_item_transition(transition) {
const block = this; const block = this;
const each_block = block.parent; const each_block = block.p;
const is_controlled = (each_block.flags & EACH_IS_CONTROLLED) !== 0; const is_controlled = (each_block.f & EACH_IS_CONTROLLED) !== 0;
// Disable optimization // Disable optimization
if (is_controlled) { if (is_controlled) {
const anchor = empty(); const anchor = empty();
each_block.flags ^= EACH_IS_CONTROLLED; each_block.f ^= EACH_IS_CONTROLLED;
append_child(/** @type {Element} */ (each_block.anchor), anchor); append_child(/** @type {Element} */ (each_block.a), anchor);
each_block.anchor = anchor; each_block.a = anchor;
} }
if (transition.direction === 'key' && (each_block.flags & EACH_IS_ANIMATED) === 0) { if (transition.r === 'key' && (each_block.f & EACH_IS_ANIMATED) === 0) {
each_block.flags |= EACH_IS_ANIMATED; each_block.f |= EACH_IS_ANIMATED;
} }
let transitions = block.transitions; let transitions = block.s;
if (transitions === null) { if (transitions === null) {
block.transitions = transitions = new Set(); block.s = transitions = new Set();
} }
transition.finished(() => { transition.f(() => {
if (transitions !== null) { if (transitions !== null) {
transitions.delete(transition); transitions.delete(transition);
if (transition.direction !== 'key') { if (transition.r !== 'key') {
for (let other of transitions) { for (let other of transitions) {
if (other.direction === 'key' || other.direction === 'in') { if (other.r === 'key' || other.r === 'in') {
transitions.delete(other); transitions.delete(other);
} }
} }
if (transitions.size === 0) { if (transitions.size === 0) {
block.transitions = null; block.s = null;
destroy_each_item_block(block, null, true); destroy_each_item_block(block, null, true);
} }
} }

@ -30,28 +30,42 @@ export type Store<V> = {
set(value: V): void; set(value: V): void;
}; };
// For all the core internal objects, we use signal character property strings.
// This not only reduces code-size and parsing, but it also improves the performance
// when the JS VM JITs the code.
export type ComponentContext = { export type ComponentContext = {
props: MaybeSignal<Record<string, unknown>>; /** props */
accessors: Record<string, any> | null; s: MaybeSignal<Record<string, unknown>>;
effects: null | Array<EffectSignal>; /** accessors */
mounted: boolean; a: Record<string, any> | null;
parent: null | ComponentContext; /** effectgs */
context: null | Map<unknown, unknown>; e: null | Array<EffectSignal>;
immutable: boolean; /** mounted */
runes: boolean; m: boolean;
update_callbacks: null | { /** parent */
before: Array<() => void>; p: null | ComponentContext;
after: Array<() => void>; /** context */
execute: () => void; c: null | Map<unknown, unknown>;
/** immutable */
i: boolean;
/** runes */
r: boolean;
/** update_callbacks */
u: null | {
/** before */
b: Array<() => void>;
/** after */
a: Array<() => void>;
/** execute */
e: () => void;
}; };
}; };
// For both SourceSignal and ComputationSignal, we use signal character property string. // We keep two shapes rather than a single monomorphic shape to improve the memory usage.
// This now only reduces code-size and parsing, but it also improves the performance of the JIT compiler. // Source signals don't need the same shape as they simply don't do as much as computations
// It's likely not to have any real wins wwhen the JIT is disabled. Lastly, we keep two shapes rather than // (effects and derived signals). Thus we can improve the memory profile at the slight cost
// a single monomorphic shape to improve the memory usage. Source signals don't need the same shape as they // of some runtime performance.
// simply don't do as much as computations (effects and derived signals). Thus we can improve the memory
// profile at the slight cost of some runtime performance.
export type SourceSignal<V = unknown> = { export type SourceSignal<V = unknown> = {
/** consumers: Signals that read from the current signal */ /** consumers: Signals that read from the current signal */
@ -114,108 +128,177 @@ export type BlockType =
export type TemplateNode = Text | Element | Comment; export type TemplateNode = Text | Element | Comment;
export type Transition = { export type Transition = {
effect: EffectSignal; /** effect */
payload: null | TransitionPayload; e: EffectSignal;
init: (from?: DOMRect) => TransitionPayload; /** payload */
finished: (fn: () => void) => void; p: null | TransitionPayload;
/** init */
i: (from?: DOMRect) => TransitionPayload;
/** finished */
f: (fn: () => void) => void;
in: () => void; in: () => void;
out: () => void; /** out */
cancel: () => void; o: () => void;
cleanup: () => void; /** cancel */
direction: 'in' | 'out' | 'both' | 'key'; c: () => void;
dom: HTMLElement; /** cleanup */
x: () => void;
/** direction */
r: 'in' | 'out' | 'both' | 'key';
/** dom */
d: HTMLElement;
}; };
export type RootBlock = { export type RootBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
container: Node; /** effect */
intro: boolean; e: null | ComputationSignal;
parent: null; /** intro */
transition: null | ((transition: Transition) => void); i: boolean;
type: typeof ROOT_BLOCK; /** parent */
p: null;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof ROOT_BLOCK;
}; };
export type IfBlock = { export type IfBlock = {
current: boolean; /** current */
dom: null | TemplateNode | Array<TemplateNode>; c: boolean;
effect: null | ComputationSignal; /** dom */
parent: Block; d: null | TemplateNode | Array<TemplateNode>;
transition: null | ((transition: Transition) => void); /** effect */
type: typeof IF_BLOCK; e: null | ComputationSignal;
/** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof IF_BLOCK;
}; };
export type KeyBlock = { export type KeyBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
parent: Block; /** effect */
transition: null | ((transition: Transition) => void); e: null | ComputationSignal;
type: typeof KEY_BLOCK; /** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof KEY_BLOCK;
}; };
export type HeadBlock = { export type HeadBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
parent: Block; /** effect */
transition: null | ((transition: Transition) => void); e: null | ComputationSignal;
type: typeof HEAD_BLOCK; /** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof HEAD_BLOCK;
}; };
export type DynamicElementBlock = { export type DynamicElementBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
parent: Block; /** effect */
transition: null | ((transition: Transition) => void); e: null | ComputationSignal;
type: typeof DYNAMIC_ELEMENT_BLOCK; /** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof DYNAMIC_ELEMENT_BLOCK;
}; };
export type DynamicComponentBlock = { export type DynamicComponentBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
parent: Block; /** effect */
transition: null | ((transition: Transition) => void); e: null | ComputationSignal;
type: typeof DYNAMIC_COMPONENT_BLOCK; /** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof DYNAMIC_COMPONENT_BLOCK;
}; };
export type AwaitBlock = { export type AwaitBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
parent: Block; /** effect */
pending: boolean; e: null | ComputationSignal;
transition: null | ((transition: Transition) => void); /** parent */
type: typeof AWAIT_BLOCK; p: Block;
/** pending */
n: boolean;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof AWAIT_BLOCK;
}; };
export type EachBlock = { export type EachBlock = {
anchor: Element | Comment; /** anchor */
flags: number; a: Element | Comment;
dom: null | TemplateNode | Array<TemplateNode>; /** flags */
items: EachItemBlock[]; f: number;
effect: null | ComputationSignal; /** dom */
parent: Block; d: null | TemplateNode | Array<TemplateNode>;
transition: null | ((transition: Transition) => void); /** items */
transitions: Array<EachItemBlock>; v: EachItemBlock[];
type: typeof EACH_BLOCK; /** effewct */
e: null | ComputationSignal;
/** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** transitions */
s: Array<EachItemBlock>;
/** type */
t: typeof EACH_BLOCK;
}; };
export type EachItemBlock = { export type EachItemBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | ComputationSignal; d: null | TemplateNode | Array<TemplateNode>;
item: any | Signal<any>; /** effect */
index: number | Signal<number>; e: null | ComputationSignal;
key: unknown; /** item */
parent: EachBlock; v: any | Signal<any>;
transition: null | ((transition: Transition) => void); /** index */
transitions: null | Set<Transition>; i: number | Signal<number>;
type: typeof EACH_ITEM_BLOCK; /** key */
k: unknown;
/** parent */
p: EachBlock;
/** transition */
r: null | ((transition: Transition) => void);
/** transitions */
s: null | Set<Transition>;
/** type */
t: typeof EACH_ITEM_BLOCK;
}; };
export type SnippetBlock = { export type SnippetBlock = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
parent: Block; d: null | TemplateNode | Array<TemplateNode>;
effect: null | ComputationSignal; /** parent */
transition: null; p: Block;
type: typeof SNIPPET_BLOCK; /** effect */
e: null | ComputationSignal;
/** transition */
r: null;
/** type */
t: typeof SNIPPET_BLOCK;
}; };
export type Block = export type Block =
@ -264,10 +347,14 @@ export type StoreReferencesContainer = Record<
export type ActionPayload<P> = { destroy?: () => void; update?: (value: P) => void }; export type ActionPayload<P> = { destroy?: () => void; update?: (value: P) => void };
export type Render = { export type Render = {
dom: null | TemplateNode | Array<TemplateNode>; /** dom */
effect: null | EffectSignal; d: null | TemplateNode | Array<TemplateNode>;
transitions: Set<Transition>; /** effect */
prev: Render | null; e: null | EffectSignal;
/** transitions */
s: Set<Transition>;
/** prev */
p: Render | null;
}; };
export type Raf = { export type Raf = {

@ -121,9 +121,8 @@ export function render(component, options) {
if (options.context) { if (options.context) {
$.push({}); $.push({});
/** @type {import('../client/types.js').ComponentContext} */ ( /** @type {import('../client/types.js').ComponentContext} */ ($.current_component_context).c =
$.current_component_context options.context;
).context = options.context;
} }
component(payload, options.props, {}, {}); component(payload, options.props, {}, {});
if (options.context) { if (options.context) {

@ -140,7 +140,7 @@ export function createEventDispatcher() {
return (type, detail, options) => { return (type, detail, options) => {
const $$events = /** @type {Record<string, Function | Function[]>} */ ( const $$events = /** @type {Record<string, Function | Function[]>} */ (
unwrap(component_context.props).$$events unwrap(component_context.s).$$events
); );
const events = $$events?.[/** @type {any} */ (type)]; const events = $$events?.[/** @type {any} */ (type)];
@ -151,9 +151,9 @@ export function createEventDispatcher() {
const event = create_custom_event(/** @type {string} */ (type), detail, options); const event = create_custom_event(/** @type {string} */ (type), detail, options);
for (const fn of callbacks) { for (const fn of callbacks) {
if (is_signal(fn)) { if (is_signal(fn)) {
get(fn).call(component_context.accessors, event); get(fn).call(component_context.a, event);
} else { } else {
fn.call(component_context.accessors, event); fn.call(component_context.a, event);
} }
} }
return !event.defaultPrevented; return !event.defaultPrevented;
@ -167,17 +167,17 @@ function init_update_callbacks() {
let called_before = false; let called_before = false;
let called_after = false; let called_after = false;
/** @type {NonNullable<import('../internal/client/types.js').ComponentContext['update_callbacks']>} */ /** @type {NonNullable<import('../internal/client/types.js').ComponentContext['u']>} */
const update_callbacks = { const update_callbacks = {
before: [], b: [],
after: [], a: [],
execute() { e() {
if (!called_before) { if (!called_before) {
called_before = true; called_before = true;
// TODO somehow beforeUpdate ran twice on mount in Svelte 4 if it causes a render // TODO somehow beforeUpdate ran twice on mount in Svelte 4 if it causes a render
// possibly strategy to get this back if needed: analyse beforeUpdate function for assignements to state, // possibly strategy to get this back if needed: analyse beforeUpdate function for assignements to state,
// if yes, add a call to the component to force-run beforeUpdate once. // if yes, add a call to the component to force-run beforeUpdate once.
untrack(() => update_callbacks.before.forEach(/** @param {any} c */ (c) => c())); untrack(() => update_callbacks.b.forEach(/** @param {any} c */ (c) => c()));
flush_local_render_effects(); flush_local_render_effects();
// beforeUpdate can run again once if afterUpdate causes another update, // beforeUpdate can run again once if afterUpdate causes another update,
// but afterUpdate shouldn't be called again in that case to prevent infinite loops // but afterUpdate shouldn't be called again in that case to prevent infinite loops
@ -185,7 +185,7 @@ function init_update_callbacks() {
user_effect(() => { user_effect(() => {
called_before = false; called_before = false;
called_after = true; called_after = true;
untrack(() => update_callbacks.after.forEach(/** @param {any} c */ (c) => c())); untrack(() => update_callbacks.a.forEach(/** @param {any} c */ (c) => c()));
// managed_effect so that it's not cleaned up when the parent effect is cleaned up // managed_effect so that it's not cleaned up when the parent effect is cleaned up
const managed = managed_effect(() => { const managed = managed_effect(() => {
destroy_signal(managed); destroy_signal(managed);
@ -223,10 +223,10 @@ export function beforeUpdate(fn) {
throw new Error('beforeUpdate can only be used during component initialisation.'); throw new Error('beforeUpdate can only be used during component initialisation.');
} }
if (component_context.update_callbacks === null) { if (component_context.u === null) {
component_context.update_callbacks = init_update_callbacks(); component_context.u = init_update_callbacks();
} }
component_context.update_callbacks.before.push(fn); component_context.u.b.push(fn);
} }
/** /**
@ -247,10 +247,10 @@ export function afterUpdate(fn) {
throw new Error('afterUpdate can only be used during component initialisation.'); throw new Error('afterUpdate can only be used during component initialisation.');
} }
if (component_context.update_callbacks === null) { if (component_context.u === null) {
component_context.update_callbacks = init_update_callbacks(); component_context.u = init_update_callbacks();
} }
component_context.update_callbacks.after.push(fn); component_context.u.a.push(fn);
} }
// TODO bring implementations in here // TODO bring implementations in here

Loading…
Cancel
Save