Convert src/compiler/compile/render_dom/wrappers/IfBlock.ts to JavaScript

pull/8569/head
Simon Holthausen 3 years ago
parent 05e5b38a84
commit 9f5f54f88c

@ -1,52 +1,60 @@
import Wrapper from './shared/Wrapper'; import Wrapper from './shared/Wrapper.js';
import Renderer from '../Renderer'; import create_debugging_comment from './shared/create_debugging_comment.js';
import Block from '../Block'; import FragmentWrapper from './Fragment.js';
import EachBlock from '../../nodes/EachBlock';
import IfBlock from '../../nodes/IfBlock';
import create_debugging_comment from './shared/create_debugging_comment';
import ElseBlock from '../../nodes/ElseBlock';
import FragmentWrapper from './Fragment';
import { b, x } from 'code-red'; import { b, x } from 'code-red';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import { is_head } from './shared/is_head'; import { is_head } from './shared/is_head.js';
import { Identifier, Node } from 'estree'; import { push_array } from '../../../utils/push_array.js';
import { push_array } from '../../../utils/push_array'; import { add_const_tags, add_const_tags_context } from './shared/add_const_tags.js';
import { add_const_tags, add_const_tags_context } from './shared/add_const_tags';
type DetachingOrNull = 'detaching' | null; /** @param {import('../../nodes/ElseBlock.js').default} node */
function is_else_if(node) {
function is_else_if(node: ElseBlock) {
return node && node.children.length === 1 && node.children[0].type === 'IfBlock'; return node && node.children.length === 1 && node.children[0].type === 'IfBlock';
} }
/** @extends Wrapper */
class IfBlockBranch extends Wrapper { class IfBlockBranch extends Wrapper {
block: Block;
fragment: FragmentWrapper;
dependencies?: string[];
condition?: any;
snippet?: Node;
is_dynamic: boolean;
node: IfBlock | ElseBlock;
/** @type {import('../Block.js').default} */
block;
/** @type {import('./Fragment.js').default} */
fragment;
/** @type {string[]} */
dependencies;
/** @type {any} */
condition;
/** @type {import('estree').Node} */
snippet;
/** @type {boolean} */
is_dynamic;
/** @type {import('../../nodes/IfBlock.js').default | import('../../nodes/ElseBlock.js').default} */
node;
/** */
var = null; var = null;
get_ctx_name: Node | undefined;
constructor( /** @type {import('estree').Node | undefined} */
renderer: Renderer, get_ctx_name;
block: Block,
parent: IfBlockWrapper, /**
node: IfBlock | ElseBlock, * @param {import('../Renderer.js').default} renderer
strip_whitespace: boolean, * @param {import('../Block.js').default} block
next_sibling: Wrapper * @param {IfBlockWrapper} parent
) { * @param {import('../../nodes/IfBlock.js').default | import('../../nodes/ElseBlock.js').default} node
* @param {boolean} strip_whitespace
* @param {import('./shared/Wrapper.js').default} next_sibling
*/
constructor(renderer, block, parent, node, strip_whitespace, next_sibling) {
super(renderer, block, parent, node); super(renderer, block, parent, node);
const { expression } = /** @type {import('../../nodes/IfBlock.js').default} */ (node);
const { expression } = node as IfBlock;
const is_else = !expression; const is_else = !expression;
if (expression) { if (expression) {
this.dependencies = expression.dynamic_dependencies(); this.dependencies = expression.dynamic_dependencies();
// TODO is this the right rule? or should any non-reference count? // TODO is this the right rule? or should any non-reference count?
// const should_cache = !is_reference(expression.node, null) && dependencies.length > 0; // const should_cache = !is_reference(expression.node, null) && dependencies.length > 0;
let should_cache = false; let should_cache = false;
@ -57,145 +65,124 @@ class IfBlockBranch extends Wrapper {
} }
} }
}); });
if (should_cache) { if (should_cache) {
this.condition = block.get_unique_name('show_if'); this.condition = block.get_unique_name('show_if');
this.snippet = expression.manipulate(block) as Node; this.snippet = /** @type {import('estree').Node} */ (expression.manipulate(block));
} else { }
else {
this.condition = expression.manipulate(block); this.condition = expression.manipulate(block);
} }
} }
add_const_tags_context(renderer, this.node.const_tags); add_const_tags_context(renderer, this.node.const_tags);
this.block = block.child({ this.block = block.child({
comment: create_debugging_comment(node, parent.renderer.component), comment: create_debugging_comment(node, parent.renderer.component),
name: parent.renderer.component.get_unique_name( name: parent.renderer.component.get_unique_name(is_else ? 'create_else_block' : 'create_if_block'),
is_else ? 'create_else_block' : 'create_if_block' type: ( /** @type {import('../../nodes/IfBlock.js').default} */(node)).expression ? 'if' : 'else'
),
type: (node as IfBlock).expression ? 'if' : 'else'
}); });
this.fragment = new FragmentWrapper(renderer, this.block, node.children, parent, strip_whitespace, next_sibling);
this.fragment = new FragmentWrapper(
renderer,
this.block,
node.children,
parent,
strip_whitespace,
next_sibling
);
this.is_dynamic = this.block.dependencies.size > 0; this.is_dynamic = this.block.dependencies.size > 0;
if (node.const_tags.length > 0) { if (node.const_tags.length > 0) {
this.get_ctx_name = parent.renderer.component.get_unique_name( this.get_ctx_name = parent.renderer.component.get_unique_name(is_else ? 'get_else_ctx' : 'get_if_ctx');
is_else ? 'get_else_ctx' : 'get_if_ctx'
);
} }
} }
} }
/** @extends Wrapper */
export default class IfBlockWrapper extends Wrapper { export default class IfBlockWrapper extends Wrapper {
node: IfBlock;
branches: IfBlockBranch[];
needs_update = false;
var: Identifier = { type: 'Identifier', name: 'if_block' }; /** @type {import('../../nodes/IfBlock.js').default} */
node;
constructor( /** @type {IfBlockBranch[]} */
renderer: Renderer, branches;
block: Block, /** */
parent: Wrapper, needs_update = false;
node: EachBlock,
strip_whitespace: boolean,
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
/** @type {import('estree').Identifier} */
var = { type: 'Identifier', name: 'if_block' };
/**
* @param {import('../Renderer.js').default} renderer
* @param {import('../Block.js').default} block
* @param {import('./shared/Wrapper.js').default} parent
* @param {import('../../nodes/EachBlock.js').default} node
* @param {boolean} strip_whitespace
* @param {import('./shared/Wrapper.js').default} next_sibling
*/
constructor(renderer, block, parent, node, strip_whitespace, next_sibling) {
super(renderer, block, parent, node);
this.branches = []; this.branches = [];
const blocks: Block[] = []; /** @type {import('../Block.js').default[]} */
const blocks = [];
let is_dynamic = false; let is_dynamic = false;
let has_intros = false; let has_intros = false;
let has_outros = false; let has_outros = false;
const create_branches = (node: IfBlock) => { /** @param {import('../../nodes/IfBlock.js').default} node */
const create_branches = (node) => {
const branch = new IfBlockBranch(renderer, block, this, node, strip_whitespace, next_sibling); const branch = new IfBlockBranch(renderer, block, this, node, strip_whitespace, next_sibling);
this.branches.push(branch); this.branches.push(branch);
blocks.push(branch.block); blocks.push(branch.block);
block.add_dependencies(node.expression.dependencies); block.add_dependencies(node.expression.dependencies);
if (branch.block.dependencies.size > 0) { if (branch.block.dependencies.size > 0) {
// the condition, or its contents, is dynamic // the condition, or its contents, is dynamic
is_dynamic = true; is_dynamic = true;
block.add_dependencies(branch.block.dependencies); block.add_dependencies(branch.block.dependencies);
} }
if (branch.dependencies && branch.dependencies.length > 0) { if (branch.dependencies && branch.dependencies.length > 0) {
// the condition itself is dynamic // the condition itself is dynamic
this.needs_update = true; this.needs_update = true;
} }
if (branch.block.has_intros)
if (branch.block.has_intros) has_intros = true; has_intros = true;
if (branch.block.has_outros) has_outros = true; if (branch.block.has_outros)
has_outros = true;
if (is_else_if(node.else)) { if (is_else_if(node.else)) {
create_branches(node.else.children[0] as IfBlock); create_branches(/** @type {import('../../nodes/IfBlock.js').default} */ (node.else.children[0]));
} else if (node.else) { }
const branch = new IfBlockBranch( else if (node.else) {
renderer, const branch = new IfBlockBranch(renderer, block, this, node.else, strip_whitespace, next_sibling);
block,
this,
node.else,
strip_whitespace,
next_sibling
);
this.branches.push(branch); this.branches.push(branch);
blocks.push(branch.block); blocks.push(branch.block);
if (branch.block.dependencies.size > 0) { if (branch.block.dependencies.size > 0) {
is_dynamic = true; is_dynamic = true;
block.add_dependencies(branch.block.dependencies); block.add_dependencies(branch.block.dependencies);
} }
if (branch.block.has_intros)
if (branch.block.has_intros) has_intros = true; has_intros = true;
if (branch.block.has_outros) has_outros = true; if (branch.block.has_outros)
has_outros = true;
} }
}; };
create_branches(this.node); create_branches(this.node);
blocks.forEach((block) => { blocks.forEach((block) => {
block.has_update_method = is_dynamic; block.has_update_method = is_dynamic;
block.has_intro_method = has_intros; block.has_intro_method = has_intros;
block.has_outro_method = has_outros; block.has_outro_method = has_outros;
}); });
push_array(renderer.blocks, blocks); push_array(renderer.blocks, blocks);
} }
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) { /**
* @param {import('../Block.js').default} block
* @param {import('estree').Identifier} parent_node
* @param {import('estree').Identifier} parent_nodes
*/
render(block, parent_node, parent_nodes) {
const name = this.var; const name = this.var;
const needs_anchor = this.next const needs_anchor = this.next
? !this.next.is_dom_node() ? !this.next.is_dom_node()
: !parent_node || !this.parent.is_dom_node(); : !parent_node || !this.parent.is_dom_node();
const anchor = needs_anchor const anchor = needs_anchor
? block.get_unique_name(`${this.var.name}_anchor`) ? block.get_unique_name(`${this.var.name}_anchor`)
: (this.next && this.next.var) || 'null'; : (this.next && this.next.var) || 'null';
const has_else = !this.branches[this.branches.length - 1].condition; const has_else = !this.branches[this.branches.length - 1].condition;
const if_exists_condition = has_else ? null : name; const if_exists_condition = has_else ? null : name;
const dynamic = this.branches[0].block.has_update_method; // can use [0] as proxy for all, since they necessarily have the same value const dynamic = this.branches[0].block.has_update_method; // can use [0] as proxy for all, since they necessarily have the same value
const has_intros = this.branches[0].block.has_intro_method; const has_intros = this.branches[0].block.has_intro_method;
const has_outros = this.branches[0].block.has_outro_method; const has_outros = this.branches[0].block.has_outro_method;
const has_transitions = has_intros || has_outros; const has_transitions = has_intros || has_outros;
this.branches.forEach((branch) => { this.branches.forEach((branch) => {
if (branch.get_ctx_name) { if (branch.get_ctx_name) {
this.renderer.blocks.push(b ` this.renderer.blocks.push(b `
@ -207,78 +194,65 @@ export default class IfBlockWrapper extends Wrapper {
`); `);
} }
}); });
const vars = { name, anchor, if_exists_condition, has_else, has_transitions }; const vars = { name, anchor, if_exists_condition, has_else, has_transitions };
const detaching: DetachingOrNull = parent_node && !is_head(parent_node) ? null : 'detaching'; /** @type {DetachingOrNull} */
const detaching = parent_node && !is_head(parent_node) ? null : 'detaching';
if (this.node.else) { if (this.node.else) {
this.branches.forEach((branch) => { this.branches.forEach((branch) => {
if (branch.snippet) block.add_variable(branch.condition); if (branch.snippet)
block.add_variable(branch.condition);
}); });
if (has_outros) { if (has_outros) {
this.render_compound_with_outros( this.render_compound_with_outros(block, parent_node, parent_nodes, dynamic, vars, detaching);
block,
parent_node,
parent_nodes,
dynamic,
vars,
detaching
);
block.chunks.outro.push(b `@transition_out(${name});`); block.chunks.outro.push(b `@transition_out(${name});`);
} else { }
else {
this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching); this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching);
} }
} else { }
else {
this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching); this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching);
if (has_outros) { if (has_outros) {
block.chunks.outro.push(b `@transition_out(${name});`); block.chunks.outro.push(b `@transition_out(${name});`);
} }
} }
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.create.push(b `if (${if_exists_condition}) ${name}.c();`); block.chunks.create.push(b `if (${if_exists_condition}) ${name}.c();`);
} else { }
else {
block.chunks.create.push(b `${name}.c();`); block.chunks.create.push(b `${name}.c();`);
} }
if (parent_nodes && this.renderer.options.hydratable) { if (parent_nodes && this.renderer.options.hydratable) {
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.claim.push(b `if (${if_exists_condition}) ${name}.l(${parent_nodes});`); block.chunks.claim.push(b `if (${if_exists_condition}) ${name}.l(${parent_nodes});`);
} else { }
else {
block.chunks.claim.push(b `${name}.l(${parent_nodes});`); block.chunks.claim.push(b `${name}.l(${parent_nodes});`);
} }
} }
if (has_intros || has_outros) { if (has_intros || has_outros) {
block.chunks.intro.push(b `@transition_in(${name});`); block.chunks.intro.push(b `@transition_in(${name});`);
} }
if (needs_anchor) { if (needs_anchor) {
block.add_element( block.add_element(
anchor as Identifier,
x`@empty()`,
parent_nodes && x`@empty()`,
parent_node
);
}
/** @type {import('estree').Identifier} */ (anchor), x `@empty()`, parent_nodes && x `@empty()`, parent_node);
}
this.branches.forEach((branch) => { this.branches.forEach((branch) => {
branch.fragment.render(branch.block, null, x`#nodes` as unknown as Identifier); branch.fragment.render(branch.block, null, /** @type {unknown} */ /** @type {import('estree').Identifier} */ ((x `#nodes`)));
}); });
} }
render_compound( /**
block: Block, * @param {import('../Block.js').default} block
parent_node: Identifier, * @param {import('estree').Identifier} parent_node
_parent_nodes: Identifier, * @param {import('estree').Identifier} _parent_nodes
dynamic: boolean, * @param {boolean} dynamic
{ name, anchor, has_else, if_exists_condition, has_transitions }, * @param {any}
detaching: DetachingOrNull * @param {DetachingOrNull} detaching
) { */
render_compound(block, parent_node, _parent_nodes, dynamic, { name, anchor, has_else, if_exists_condition, has_transitions }, detaching) {
const select_block_type = this.renderer.component.get_unique_name('select_block_type'); const select_block_type = this.renderer.component.get_unique_name('select_block_type');
const current_block_type = block.get_unique_name('current_block_type'); const current_block_type = block.get_unique_name('current_block_type');
const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name); const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name);
@ -286,42 +260,34 @@ export default class IfBlockWrapper extends Wrapper {
? block.get_unique_name('select_block_ctx') ? block.get_unique_name('select_block_ctx')
: null; : null;
const if_ctx = select_block_ctx ? x `${select_block_ctx}(#ctx, ${current_block_type})` : x `#ctx`; const if_ctx = select_block_ctx ? x `${select_block_ctx}(#ctx, ${current_block_type})` : x `#ctx`;
const get_block = has_else const get_block = has_else
? x `${current_block_type}(${if_ctx})` ? x `${current_block_type}(${if_ctx})`
: x `${current_block_type} && ${current_block_type}(${if_ctx})`; : x `${current_block_type} && ${current_block_type}(${if_ctx})`;
if (this.needs_update) { if (this.needs_update) {
block.chunks.init.push(b ` block.chunks.init.push(b `
function ${select_block_type}(#ctx, #dirty) { function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ dependencies, condition, snippet }) => { ${this.branches.map(({ dependencies, condition, snippet }) => {
return b`${ return b `${snippet && dependencies.length > 0
snippet && dependencies.length > 0
? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;` ? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;`
: null : null}`;
}`;
})} })}
${this.branches.map(({ condition, snippet, block }) => ${this.branches.map(({ condition, snippet, block }) => condition
condition
? b ` ? b `
${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`} ${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${block.name};` if (${condition}) return ${block.name};`
: b`return ${block.name};` : b `return ${block.name};`)}
)}
} }
`); `);
} else { }
else {
block.chunks.init.push(b ` block.chunks.init.push(b `
function ${select_block_type}(#ctx, #dirty) { function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ condition, snippet, block }) => ${this.branches.map(({ condition, snippet, block }) => condition
condition
? b `if (${snippet || condition}) return ${block.name};` ? b `if (${snippet || condition}) return ${block.name};`
: b`return ${block.name};` : b `return ${block.name};`)}
)}
} }
`); `);
} }
if (need_select_block_ctx) { if (need_select_block_ctx) {
// if all branches needs create a context // if all branches needs create a context
if (this.branches.every((branch) => branch.get_ctx_name)) { if (this.branches.every((branch) => branch.get_ctx_name)) {
@ -336,7 +302,8 @@ export default class IfBlockWrapper extends Wrapper {
.filter(Boolean)} .filter(Boolean)}
} }
`); `);
} else { }
else {
// when not all branches need to create a new context, // when not all branches need to create a new context,
// this code is simpler // this code is simpler
block.chunks.init.push(b ` block.chunks.init.push(b `
@ -353,26 +320,20 @@ export default class IfBlockWrapper extends Wrapper {
`); `);
} }
} }
block.chunks.init.push(b ` block.chunks.init.push(b `
let ${current_block_type} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}); let ${current_block_type} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()});
let ${name} = ${get_block}; let ${name} = ${get_block};
`); `);
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : '#anchor'; const anchor_node = parent_node ? 'null' : '#anchor';
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.mount.push( block.chunks.mount.push(b `if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});`);
b`if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});` }
); else {
} else {
block.chunks.mount.push(b `${name}.m(${initial_mount_node}, ${anchor_node});`); block.chunks.mount.push(b `${name}.m(${initial_mount_node}, ${anchor_node});`);
} }
if (this.needs_update) { if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const change_block = b ` const change_block = b `
${if_exists_condition ? b `if (${if_exists_condition}) ${name}.d(1)` : b `${name}.d(1)`}; ${if_exists_condition ? b `if (${if_exists_condition}) ${name}.d(1)` : b `${name}.d(1)`};
${name} = ${get_block}; ${name} = ${get_block};
@ -382,7 +343,6 @@ export default class IfBlockWrapper extends Wrapper {
${name}.m(${update_mount_node}, ${anchor}); ${name}.m(${update_mount_node}, ${anchor});
} }
`; `;
if (dynamic) { if (dynamic) {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${current_block_type} === (${current_block_type} = ${select_block_type}(#ctx, #dirty)) && ${name}) { if (${current_block_type} === (${current_block_type} = ${select_block_type}(#ctx, #dirty)) && ${name}) {
@ -391,44 +351,48 @@ export default class IfBlockWrapper extends Wrapper {
${change_block} ${change_block}
} }
`); `);
} else { }
else {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${current_block_type} !== (${current_block_type} = ${select_block_type}(#ctx, #dirty))) { if (${current_block_type} !== (${current_block_type} = ${select_block_type}(#ctx, #dirty))) {
${change_block} ${change_block}
} }
`); `);
} }
} else if (dynamic) { }
else if (dynamic) {
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`);
} else { }
else {
block.chunks.update.push(b `${name}.p(${if_ctx}, #dirty);`); block.chunks.update.push(b `${name}.p(${if_ctx}, #dirty);`);
} }
} }
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.destroy.push(b ` block.chunks.destroy.push(b `
if (${if_exists_condition}) { if (${if_exists_condition}) {
${name}.d(${detaching}); ${name}.d(${detaching});
} }
`); `);
} else { }
else {
block.chunks.destroy.push(b ` block.chunks.destroy.push(b `
${name}.d(${detaching}); ${name}.d(${detaching});
`); `);
} }
} }
// if any of the siblings have outros, we need to keep references to the blocks // if any of the siblings have outros, we need to keep references to the blocks
// (TODO does this only apply to bidi transitions?) // (TODO does this only apply to bidi transitions?)
render_compound_with_outros(
block: Block, /**
parent_node: Identifier, * @param {import('../Block.js').default} block
_parent_nodes: Identifier, * @param {import('estree').Identifier} parent_node
dynamic: boolean, * @param {import('estree').Identifier} _parent_nodes
{ name, anchor, has_else, has_transitions, if_exists_condition }, * @param {boolean} dynamic
detaching: DetachingOrNull * @param {any}
) { * @param {DetachingOrNull} detaching
*/
render_compound_with_outros(block, parent_node, _parent_nodes, dynamic, { name, anchor, has_else, has_transitions, if_exists_condition }, detaching) {
const select_block_type = this.renderer.component.get_unique_name('select_block_type'); const select_block_type = this.renderer.component.get_unique_name('select_block_type');
const current_block_type_index = block.get_unique_name('current_block_type_index'); const current_block_type_index = block.get_unique_name('current_block_type_index');
const previous_block_index = block.get_unique_name('previous_block_index'); const previous_block_index = block.get_unique_name('previous_block_index');
@ -441,14 +405,11 @@ export default class IfBlockWrapper extends Wrapper {
const if_ctx = select_block_ctx const if_ctx = select_block_ctx
? x `${select_block_ctx}(#ctx, ${current_block_type_index})` ? x `${select_block_ctx}(#ctx, ${current_block_type_index})`
: x `#ctx`; : x `#ctx`;
const if_current_block_type_index = has_else const if_current_block_type_index = has_else
? (nodes: Node[]) => nodes ? (nodes) => nodes
: (nodes: Node[]) => b`if (~${current_block_type_index}) { ${nodes} }`; : (nodes) => b `if (~${current_block_type_index}) { ${nodes} }`;
block.add_variable(current_block_type_index); block.add_variable(current_block_type_index);
block.add_variable(name); block.add_variable(name);
block.chunks.init.push(b ` block.chunks.init.push(b `
const ${if_block_creators} = [ const ${if_block_creators} = [
${this.branches.map((branch) => branch.block.name)} ${this.branches.map((branch) => branch.block.name)}
@ -456,38 +417,29 @@ export default class IfBlockWrapper extends Wrapper {
const ${if_blocks} = []; const ${if_blocks} = [];
${ ${this.needs_update
this.needs_update
? b ` ? b `
function ${select_block_type}(#ctx, #dirty) { function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ dependencies, condition, snippet }) => { ${this.branches.map(({ dependencies, condition, snippet }) => {
return b`${ return b `${snippet && dependencies.length > 0
snippet && dependencies.length > 0
? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;` ? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;`
: null : null}`;
}`;
})} })}
${this.branches.map(({ condition, snippet }, i) => ${this.branches.map(({ condition, snippet }, i) => condition
condition
? b ` ? b `
${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`} ${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${i};` if (${condition}) return ${i};`
: b`return ${i};` : b `return ${i};`)}
)}
${!has_else && b `return -1;`} ${!has_else && b `return -1;`}
} }
` `
: b ` : b `
function ${select_block_type}(#ctx, #dirty) { function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ condition, snippet }, i) => ${this.branches.map(({ condition, snippet }, i) => condition ? b `if (${snippet || condition}) return ${i};` : b `return ${i};`)}
condition ? b`if (${snippet || condition}) return ${i};` : b`return ${i};`
)}
${!has_else && b `return -1;`} ${!has_else && b `return -1;`}
} }
` `}
}
`); `);
if (need_select_block_ctx) { if (need_select_block_ctx) {
// if all branches needs create a context // if all branches needs create a context
if (this.branches.every((branch) => branch.get_ctx_name)) { if (this.branches.every((branch) => branch.get_ctx_name)) {
@ -502,7 +454,8 @@ export default class IfBlockWrapper extends Wrapper {
.filter(Boolean)} .filter(Boolean)}
} }
`); `);
} else { }
else {
// when not all branches need to create a new context, // when not all branches need to create a new context,
// this code is simpler // this code is simpler
block.chunks.init.push(b ` block.chunks.init.push(b `
@ -517,32 +470,24 @@ export default class IfBlockWrapper extends Wrapper {
`); `);
} }
} }
if (has_else) { if (has_else) {
block.chunks.init.push(b ` block.chunks.init.push(b `
${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}); ${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()});
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx}); ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx});
`); `);
} else { }
else {
block.chunks.init.push(b ` block.chunks.init.push(b `
if (~(${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}))) { if (~(${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}))) {
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx}); ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx});
} }
`); `);
} }
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : '#anchor'; const anchor_node = parent_node ? 'null' : '#anchor';
block.chunks.mount.push(if_current_block_type_index(b `${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`));
block.chunks.mount.push(
if_current_block_type_index(
b`${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`
)
);
if (this.needs_update) { if (this.needs_update) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const destroy_old_block = b ` const destroy_old_block = b `
@group_outros(); @group_outros();
@transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => { @transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => {
@ -550,7 +495,6 @@ export default class IfBlockWrapper extends Wrapper {
}); });
@check_outros(); @check_outros();
`; `;
const create_new_block = b ` const create_new_block = b `
${name} = ${if_blocks}[${current_block_type_index}]; ${name} = ${if_blocks}[${current_block_type_index}];
if (!${name}) { if (!${name}) {
@ -562,7 +506,6 @@ export default class IfBlockWrapper extends Wrapper {
${has_transitions && b `@transition_in(${name}, 1);`} ${has_transitions && b `@transition_in(${name}, 1);`}
${name}.m(${update_mount_node}, ${anchor}); ${name}.m(${update_mount_node}, ${anchor});
`; `;
const change_block = has_else const change_block = has_else
? b ` ? b `
${destroy_old_block} ${destroy_old_block}
@ -580,12 +523,10 @@ export default class IfBlockWrapper extends Wrapper {
${name} = null; ${name} = null;
} }
`; `;
block.chunks.update.push(b ` block.chunks.update.push(b `
let ${previous_block_index} = ${current_block_type_index}; let ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(#ctx, #dirty); ${current_block_type_index} = ${select_block_type}(#ctx, #dirty);
`); `);
if (dynamic) { if (dynamic) {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${current_block_type_index} === ${previous_block_index}) { if (${current_block_type_index} === ${previous_block_index}) {
@ -594,60 +535,54 @@ export default class IfBlockWrapper extends Wrapper {
${change_block} ${change_block}
} }
`); `);
} else { }
else {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${current_block_type_index} !== ${previous_block_index}) { if (${current_block_type_index} !== ${previous_block_index}) {
${change_block} ${change_block}
} }
`); `);
} }
} else if (dynamic) { }
else if (dynamic) {
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`);
} else { }
else {
block.chunks.update.push(b `${name}.p(${if_ctx}, #dirty);`); block.chunks.update.push(b `${name}.p(${if_ctx}, #dirty);`);
} }
} }
block.chunks.destroy.push(if_current_block_type_index(b `${if_blocks}[${current_block_type_index}].d(${detaching});`));
block.chunks.destroy.push(
if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].d(${detaching});`)
);
} }
render_simple( /**
block: Block, * @param {import('../Block.js').default} block
parent_node: Identifier, * @param {import('estree').Identifier} parent_node
_parent_nodes: Identifier, * @param {import('estree').Identifier} _parent_nodes
dynamic: boolean, * @param {boolean} dynamic
{ name, anchor, if_exists_condition, has_transitions }, * @param {any}
detaching: DetachingOrNull * @param {DetachingOrNull} detaching
) { */
render_simple(block, parent_node, _parent_nodes, dynamic, { name, anchor, if_exists_condition, has_transitions }, detaching) {
const branch = this.branches[0]; const branch = this.branches[0];
const if_ctx = branch.get_ctx_name ? x `${branch.get_ctx_name}(#ctx)` : x `#ctx`; const if_ctx = branch.get_ctx_name ? x `${branch.get_ctx_name}(#ctx)` : x `#ctx`;
if (branch.snippet)
if (branch.snippet) block.add_variable(branch.condition, branch.snippet); block.add_variable(branch.condition, branch.snippet);
block.chunks.init.push(b ` block.chunks.init.push(b `
let ${name} = ${branch.condition} && ${branch.block.name}(${if_ctx}); let ${name} = ${branch.condition} && ${branch.block.name}(${if_ctx});
`); `);
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : '#anchor'; const anchor_node = parent_node ? 'null' : '#anchor';
block.chunks.mount.push(b `if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`); block.chunks.mount.push(b `if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`);
if (branch.dependencies.length > 0) { if (branch.dependencies.length > 0) {
const update_mount_node = this.get_update_mount_node(anchor); const update_mount_node = this.get_update_mount_node(anchor);
const enter = b ` const enter = b `
if (${name}) { if (${name}) {
${dynamic && b `${name}.p(${if_ctx}, #dirty);`} ${dynamic && b `${name}.p(${if_ctx}, #dirty);`}
${ ${has_transitions &&
has_transitions &&
b `if (${block.renderer.dirty(branch.dependencies)}) { b `if (${block.renderer.dirty(branch.dependencies)}) {
@transition_in(${name}, 1); @transition_in(${name}, 1);
}` }`}
}
} else { } else {
${name} = ${branch.block.name}(${if_ctx}); ${name} = ${branch.block.name}(${if_ctx});
${name}.c(); ${name}.c();
@ -655,15 +590,9 @@ export default class IfBlockWrapper extends Wrapper {
${name}.m(${update_mount_node}, ${anchor}); ${name}.m(${update_mount_node}, ${anchor});
} }
`; `;
if (branch.snippet) { if (branch.snippet) {
block.chunks.update.push( block.chunks.update.push(b `if (${block.renderer.dirty(branch.dependencies)}) ${branch.condition} = ${branch.snippet}`);
b`if (${block.renderer.dirty(branch.dependencies)}) ${branch.condition} = ${
branch.snippet
}`
);
} }
// no `p()` here — we don't want to update outroing nodes, // no `p()` here — we don't want to update outroing nodes,
// as that will typically result in glitching // as that will typically result in glitching
if (branch.block.has_outro_method) { if (branch.block.has_outro_method) {
@ -678,7 +607,8 @@ export default class IfBlockWrapper extends Wrapper {
@check_outros(); @check_outros();
} }
`); `);
} else { }
else {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${branch.condition}) { if (${branch.condition}) {
${enter} ${enter}
@ -688,20 +618,25 @@ export default class IfBlockWrapper extends Wrapper {
} }
`); `);
} }
} else if (dynamic) { }
else if (dynamic) {
block.chunks.update.push(b ` block.chunks.update.push(b `
if (${branch.condition}) ${name}.p(${if_ctx}, #dirty); if (${branch.condition}) ${name}.p(${if_ctx}, #dirty);
`); `);
} }
if (if_exists_condition) { if (if_exists_condition) {
block.chunks.destroy.push(b ` block.chunks.destroy.push(b `
if (${if_exists_condition}) ${name}.d(${detaching}); if (${if_exists_condition}) ${name}.d(${detaching});
`); `);
} else { }
else {
block.chunks.destroy.push(b ` block.chunks.destroy.push(b `
${name}.d(${detaching}); ${name}.d(${detaching});
`); `);
} }
} }
} }
/** @typedef {'detaching' | null} DetachingOrNull */

Loading…
Cancel
Save