From 484d6efbee2367191f096e3c9de152dbe32720e8 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 12 May 2023 15:08:11 +0200 Subject: [PATCH] Lint and format src/compiler/compile/render_dom/wrappers/IfBlock.js --- .../compile/render_dom/wrappers/IfBlock.js | 956 +++++++++--------- 1 file changed, 505 insertions(+), 451 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.js b/src/compiler/compile/render_dom/wrappers/IfBlock.js index edf157b3d6..9769c68f82 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.js +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.js @@ -9,510 +9,558 @@ import { add_const_tags, add_const_tags_context } from './shared/add_const_tags. /** @param {import('../../nodes/ElseBlock.js').default} node */ function is_else_if(node) { - 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 { + /** @type {import('../Block.js').default} */ + block; - /** @type {import('../Block.js').default} */ - block; + /** @type {import('./Fragment.js').default} */ + fragment; - /** @type {import('./Fragment.js').default} */ - fragment; + /** @type {string[]} */ + dependencies; - /** @type {string[]} */ - dependencies; + /** @type {any} */ + condition; - /** @type {any} */ - condition; + /** @type {import('estree').Node} */ + snippet; - /** @type {import('estree').Node} */ - snippet; + /** @type {boolean} */ + is_dynamic; - /** @type {boolean} */ - is_dynamic; + /** @type {import('../../nodes/IfBlock.js').default | import('../../nodes/ElseBlock.js').default} */ + node; + /** */ + var = null; - /** @type {import('../../nodes/IfBlock.js').default | import('../../nodes/ElseBlock.js').default} */ - node; - /** */ - var = null; + /** @type {import('estree').Node | undefined} */ + get_ctx_name; - /** @type {import('estree').Node | undefined} */ - get_ctx_name; - - /** - * @param {import('../Renderer.js').default} renderer - * @param {import('../Block.js').default} block - * @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); - const { expression } = /** @type {import('../../nodes/IfBlock.js').default} */ (node); - const is_else = !expression; - if (expression) { - this.dependencies = expression.dynamic_dependencies(); - // TODO is this the right rule? or should any non-reference count? - // const should_cache = !is_reference(expression.node, null) && dependencies.length > 0; - let should_cache = false; - walk(expression.node, { - enter(node) { - if (node.type === 'CallExpression' || node.type === 'NewExpression') { - should_cache = true; - } - } - }); - if (should_cache) { - this.condition = block.get_unique_name('show_if'); - this.snippet = /** @type {import('estree').Node} */ (expression.manipulate(block)); - } - else { - this.condition = expression.manipulate(block); - } - } - add_const_tags_context(renderer, this.node.const_tags); - this.block = block.child({ - comment: create_debugging_comment(node, parent.renderer.component), - name: parent.renderer.component.get_unique_name(is_else ? 'create_else_block' : 'create_if_block'), - type: ( /** @type {import('../../nodes/IfBlock.js').default} */(node)).expression ? 'if' : 'else' - }); - this.fragment = new FragmentWrapper(renderer, this.block, node.children, parent, strip_whitespace, next_sibling); - this.is_dynamic = this.block.dependencies.size > 0; - if (node.const_tags.length > 0) { - this.get_ctx_name = parent.renderer.component.get_unique_name(is_else ? 'get_else_ctx' : 'get_if_ctx'); - } - } + /** + * @param {import('../Renderer.js').default} renderer + * @param {import('../Block.js').default} block + * @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); + const { expression } = /** @type {import('../../nodes/IfBlock.js').default} */ (node); + const is_else = !expression; + if (expression) { + this.dependencies = expression.dynamic_dependencies(); + // TODO is this the right rule? or should any non-reference count? + // const should_cache = !is_reference(expression.node, null) && dependencies.length > 0; + let should_cache = false; + walk(expression.node, { + enter(node) { + if (node.type === 'CallExpression' || node.type === 'NewExpression') { + should_cache = true; + } + } + }); + if (should_cache) { + this.condition = block.get_unique_name('show_if'); + this.snippet = /** @type {import('estree').Node} */ (expression.manipulate(block)); + } else { + this.condition = expression.manipulate(block); + } + } + add_const_tags_context(renderer, this.node.const_tags); + this.block = block.child({ + comment: create_debugging_comment(node, parent.renderer.component), + name: parent.renderer.component.get_unique_name( + is_else ? 'create_else_block' : 'create_if_block' + ), + type: /** @type {import('../../nodes/IfBlock.js').default} */ (node).expression + ? 'if' + : 'else' + }); + this.fragment = new FragmentWrapper( + renderer, + this.block, + node.children, + parent, + strip_whitespace, + next_sibling + ); + this.is_dynamic = this.block.dependencies.size > 0; + if (node.const_tags.length > 0) { + this.get_ctx_name = parent.renderer.component.get_unique_name( + is_else ? 'get_else_ctx' : 'get_if_ctx' + ); + } + } } /** @extends Wrapper */ export default class IfBlockWrapper extends Wrapper { + /** @type {import('../../nodes/IfBlock.js').default} */ + node; - /** @type {import('../../nodes/IfBlock.js').default} */ - node; + /** @type {IfBlockBranch[]} */ + branches; + /** */ + needs_update = false; - /** @type {IfBlockBranch[]} */ - branches; - /** */ - needs_update = false; + /** @type {import('estree').Identifier} */ + var = { type: 'Identifier', name: 'if_block' }; - /** @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 = []; - /** - * @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 = []; + /** @type {import('../Block.js').default[]} */ + const blocks = []; + let is_dynamic = false; + let has_intros = false; + let has_outros = false; - /** @type {import('../Block.js').default[]} */ - const blocks = []; - let is_dynamic = false; - let has_intros = false; - let has_outros = false; - - /** @param {import('../../nodes/IfBlock.js').default} node */ - const create_branches = (node) => { - const branch = new IfBlockBranch(renderer, block, this, node, strip_whitespace, next_sibling); - this.branches.push(branch); - blocks.push(branch.block); - block.add_dependencies(node.expression.dependencies); - if (branch.block.dependencies.size > 0) { - // the condition, or its contents, is dynamic - is_dynamic = true; - block.add_dependencies(branch.block.dependencies); - } - if (branch.dependencies && branch.dependencies.length > 0) { - // the condition itself is dynamic - this.needs_update = true; - } - if (branch.block.has_intros) - has_intros = true; - if (branch.block.has_outros) - has_outros = true; - if (is_else_if(node.else)) { - create_branches(/** @type {import('../../nodes/IfBlock.js').default} */ (node.else.children[0])); - } - else if (node.else) { - const branch = new IfBlockBranch(renderer, block, this, node.else, strip_whitespace, next_sibling); - this.branches.push(branch); - blocks.push(branch.block); - if (branch.block.dependencies.size > 0) { - is_dynamic = true; - block.add_dependencies(branch.block.dependencies); - } - if (branch.block.has_intros) - has_intros = true; - if (branch.block.has_outros) - has_outros = true; - } - }; - create_branches(this.node); - blocks.forEach((block) => { - block.has_update_method = is_dynamic; - block.has_intro_method = has_intros; - block.has_outro_method = has_outros; - }); - push_array(renderer.blocks, blocks); - } + /** @param {import('../../nodes/IfBlock.js').default} node */ + const create_branches = (node) => { + const branch = new IfBlockBranch(renderer, block, this, node, strip_whitespace, next_sibling); + this.branches.push(branch); + blocks.push(branch.block); + block.add_dependencies(node.expression.dependencies); + if (branch.block.dependencies.size > 0) { + // the condition, or its contents, is dynamic + is_dynamic = true; + block.add_dependencies(branch.block.dependencies); + } + if (branch.dependencies && branch.dependencies.length > 0) { + // the condition itself is dynamic + this.needs_update = true; + } + if (branch.block.has_intros) has_intros = true; + if (branch.block.has_outros) has_outros = true; + if (is_else_if(node.else)) { + create_branches( + /** @type {import('../../nodes/IfBlock.js').default} */ (node.else.children[0]) + ); + } else if (node.else) { + const branch = new IfBlockBranch( + renderer, + block, + this, + node.else, + strip_whitespace, + next_sibling + ); + this.branches.push(branch); + blocks.push(branch.block); + if (branch.block.dependencies.size > 0) { + is_dynamic = true; + block.add_dependencies(branch.block.dependencies); + } + if (branch.block.has_intros) has_intros = true; + if (branch.block.has_outros) has_outros = true; + } + }; + create_branches(this.node); + blocks.forEach((block) => { + block.has_update_method = is_dynamic; + block.has_intro_method = has_intros; + block.has_outro_method = has_outros; + }); + push_array(renderer.blocks, blocks); + } - /** - * @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 needs_anchor = this.next - ? !this.next.is_dom_node() - : !parent_node || !this.parent.is_dom_node(); - const anchor = needs_anchor - ? block.get_unique_name(`${this.var.name}_anchor`) - : (this.next && this.next.var) || 'null'; - const has_else = !this.branches[this.branches.length - 1].condition; - 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 has_intros = this.branches[0].block.has_intro_method; - const has_outros = this.branches[0].block.has_outro_method; - const has_transitions = has_intros || has_outros; - this.branches.forEach((branch) => { - if (branch.get_ctx_name) { - this.renderer.blocks.push(b ` + /** + * @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 needs_anchor = this.next + ? !this.next.is_dom_node() + : !parent_node || !this.parent.is_dom_node(); + const anchor = needs_anchor + ? block.get_unique_name(`${this.var.name}_anchor`) + : (this.next && this.next.var) || 'null'; + const has_else = !this.branches[this.branches.length - 1].condition; + 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 has_intros = this.branches[0].block.has_intro_method; + const has_outros = this.branches[0].block.has_outro_method; + const has_transitions = has_intros || has_outros; + this.branches.forEach((branch) => { + if (branch.get_ctx_name) { + this.renderer.blocks.push(b` function ${branch.get_ctx_name}(#ctx) { const child_ctx = #ctx.slice(); ${add_const_tags(block, branch.node.const_tags, 'child_ctx')} return child_ctx; } `); - } - }); - const vars = { name, anchor, if_exists_condition, has_else, has_transitions }; + } + }); + const vars = { name, anchor, if_exists_condition, has_else, has_transitions }; - /** @type {DetachingOrNull} */ - const detaching = parent_node && !is_head(parent_node) ? null : 'detaching'; - if (this.node.else) { - this.branches.forEach((branch) => { - if (branch.snippet) - block.add_variable(branch.condition); - }); - if (has_outros) { - this.render_compound_with_outros(block, parent_node, parent_nodes, dynamic, vars, detaching); - block.chunks.outro.push(b `@transition_out(${name});`); - } - else { - this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching); - } - } - else { - this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching); - if (has_outros) { - block.chunks.outro.push(b `@transition_out(${name});`); - } - } - if (if_exists_condition) { - block.chunks.create.push(b `if (${if_exists_condition}) ${name}.c();`); - } - else { - block.chunks.create.push(b `${name}.c();`); - } - if (parent_nodes && this.renderer.options.hydratable) { - if (if_exists_condition) { - block.chunks.claim.push(b `if (${if_exists_condition}) ${name}.l(${parent_nodes});`); - } - else { - block.chunks.claim.push(b `${name}.l(${parent_nodes});`); - } - } - if (has_intros || has_outros) { - block.chunks.intro.push(b `@transition_in(${name});`); - } - if (needs_anchor) { - block.add_element( + /** @type {DetachingOrNull} */ + const detaching = parent_node && !is_head(parent_node) ? null : 'detaching'; + if (this.node.else) { + this.branches.forEach((branch) => { + if (branch.snippet) block.add_variable(branch.condition); + }); + if (has_outros) { + this.render_compound_with_outros( + block, + parent_node, + parent_nodes, + dynamic, + vars, + detaching + ); + block.chunks.outro.push(b`@transition_out(${name});`); + } else { + this.render_compound(block, parent_node, parent_nodes, dynamic, vars, detaching); + } + } else { + this.render_simple(block, parent_node, parent_nodes, dynamic, vars, detaching); + if (has_outros) { + block.chunks.outro.push(b`@transition_out(${name});`); + } + } + if (if_exists_condition) { + block.chunks.create.push(b`if (${if_exists_condition}) ${name}.c();`); + } else { + block.chunks.create.push(b`${name}.c();`); + } + if (parent_nodes && this.renderer.options.hydratable) { + if (if_exists_condition) { + block.chunks.claim.push(b`if (${if_exists_condition}) ${name}.l(${parent_nodes});`); + } else { + block.chunks.claim.push(b`${name}.l(${parent_nodes});`); + } + } + if (has_intros || has_outros) { + block.chunks.intro.push(b`@transition_in(${name});`); + } + if (needs_anchor) { + block.add_element( + /** @type {import('estree').Identifier} */ (anchor), + x`@empty()`, + parent_nodes && x`@empty()`, + parent_node + ); + } + this.branches.forEach((branch) => { + branch.fragment.render( + branch.block, + null, + /** @type {unknown} */ /** @type {import('estree').Identifier} */ (x`#nodes`) + ); + }); + } - /** @type {import('estree').Identifier} */ (anchor), x `@empty()`, parent_nodes && x `@empty()`, parent_node); - } - this.branches.forEach((branch) => { - branch.fragment.render(branch.block, null, /** @type {unknown} */ /** @type {import('estree').Identifier} */ ((x `#nodes`))); - }); - } - - /** - * @param {import('../Block.js').default} block - * @param {import('estree').Identifier} parent_node - * @param {import('estree').Identifier} _parent_nodes - * @param {boolean} dynamic - * @param {any} - * @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 current_block_type = block.get_unique_name('current_block_type'); - const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name); - const select_block_ctx = need_select_block_ctx - ? block.get_unique_name('select_block_ctx') - : null; - const if_ctx = select_block_ctx ? x `${select_block_ctx}(#ctx, ${current_block_type})` : x `#ctx`; - const get_block = has_else - ? x `${current_block_type}(${if_ctx})` - : x `${current_block_type} && ${current_block_type}(${if_ctx})`; - if (this.needs_update) { - block.chunks.init.push(b ` + /** + * @param {import('../Block.js').default} block + * @param {import('estree').Identifier} parent_node + * @param {import('estree').Identifier} _parent_nodes + * @param {boolean} dynamic + * @param {any} + * @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 current_block_type = block.get_unique_name('current_block_type'); + const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name); + const select_block_ctx = need_select_block_ctx + ? block.get_unique_name('select_block_ctx') + : null; + const if_ctx = select_block_ctx ? x`${select_block_ctx}(#ctx, ${current_block_type})` : x`#ctx`; + const get_block = has_else + ? x`${current_block_type}(${if_ctx})` + : x`${current_block_type} && ${current_block_type}(${if_ctx})`; + if (this.needs_update) { + block.chunks.init.push(b` function ${select_block_type}(#ctx, #dirty) { ${this.branches.map(({ dependencies, condition, snippet }) => { - return b `${snippet && dependencies.length > 0 - ? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;` - : null}`; - })} - ${this.branches.map(({ condition, snippet, block }) => condition - ? b ` - ${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`} + return b`${ + snippet && dependencies.length > 0 + ? b`if (${block.renderer.dirty(dependencies)}) ${condition} = null;` + : null + }`; + })} + ${this.branches.map(({ condition, snippet, block }) => + condition + ? b` + ${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`} if (${condition}) return ${block.name};` - : b `return ${block.name};`)} + : b`return ${block.name};` + )} } `); - } - else { - block.chunks.init.push(b ` + } else { + block.chunks.init.push(b` function ${select_block_type}(#ctx, #dirty) { - ${this.branches.map(({ condition, snippet, block }) => condition - ? b `if (${snippet || condition}) return ${block.name};` - : b `return ${block.name};`)} + ${this.branches.map(({ condition, snippet, block }) => + condition + ? b`if (${snippet || condition}) return ${block.name};` + : b`return ${block.name};` + )} } `); - } - if (need_select_block_ctx) { - // if all branches needs create a context - if (this.branches.every((branch) => branch.get_ctx_name)) { - block.chunks.init.push(b ` + } + if (need_select_block_ctx) { + // if all branches needs create a context + if (this.branches.every((branch) => branch.get_ctx_name)) { + block.chunks.init.push(b` function ${select_block_ctx}(#ctx, #type) { ${this.branches - .map(({ condition, get_ctx_name, block }) => { - return condition - ? b `if (#type === ${block.name}) return ${get_ctx_name}(#ctx);` - : b `return ${get_ctx_name}(#ctx);`; - }) - .filter(Boolean)} + .map(({ condition, get_ctx_name, block }) => { + return condition + ? b`if (#type === ${block.name}) return ${get_ctx_name}(#ctx);` + : b`return ${get_ctx_name}(#ctx);`; + }) + .filter(Boolean)} } `); - } - else { - // when not all branches need to create a new context, - // this code is simpler - block.chunks.init.push(b ` + } else { + // when not all branches need to create a new context, + // this code is simpler + block.chunks.init.push(b` function ${select_block_ctx}(#ctx, #type) { ${this.branches - .map(({ get_ctx_name, block }) => { - return get_ctx_name - ? b `if (#type === ${block.name}) return ${get_ctx_name}(#ctx);` - : null; - }) - .filter(Boolean)} + .map(({ get_ctx_name, block }) => { + return get_ctx_name + ? b`if (#type === ${block.name}) return ${get_ctx_name}(#ctx);` + : null; + }) + .filter(Boolean)} return #ctx; } `); - } - } - block.chunks.init.push(b ` + } + } + block.chunks.init.push(b` let ${current_block_type} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}); let ${name} = ${get_block}; `); - const initial_mount_node = parent_node || '#target'; - const anchor_node = parent_node ? 'null' : '#anchor'; - if (if_exists_condition) { - block.chunks.mount.push(b `if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});`); - } - else { - block.chunks.mount.push(b `${name}.m(${initial_mount_node}, ${anchor_node});`); - } - if (this.needs_update) { - const update_mount_node = this.get_update_mount_node(anchor); - const change_block = b ` - ${if_exists_condition ? b `if (${if_exists_condition}) ${name}.d(1)` : b `${name}.d(1)`}; + const initial_mount_node = parent_node || '#target'; + const anchor_node = parent_node ? 'null' : '#anchor'; + if (if_exists_condition) { + block.chunks.mount.push( + b`if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});` + ); + } else { + block.chunks.mount.push(b`${name}.m(${initial_mount_node}, ${anchor_node});`); + } + if (this.needs_update) { + const update_mount_node = this.get_update_mount_node(anchor); + const change_block = b` + ${if_exists_condition ? b`if (${if_exists_condition}) ${name}.d(1)` : b`${name}.d(1)`}; ${name} = ${get_block}; if (${name}) { ${name}.c(); - ${has_transitions && b `@transition_in(${name}, 1);`} + ${has_transitions && b`@transition_in(${name}, 1);`} ${name}.m(${update_mount_node}, ${anchor}); } `; - if (dynamic) { - block.chunks.update.push(b ` + if (dynamic) { + block.chunks.update.push(b` if (${current_block_type} === (${current_block_type} = ${select_block_type}(#ctx, #dirty)) && ${name}) { ${name}.p(${if_ctx}, #dirty); } else { ${change_block} } `); - } - else { - block.chunks.update.push(b ` + } else { + block.chunks.update.push(b` if (${current_block_type} !== (${current_block_type} = ${select_block_type}(#ctx, #dirty))) { ${change_block} } `); - } - } - else if (dynamic) { - if (if_exists_condition) { - block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); - } - else { - block.chunks.update.push(b `${name}.p(${if_ctx}, #dirty);`); - } - } - if (if_exists_condition) { - block.chunks.destroy.push(b ` + } + } else if (dynamic) { + if (if_exists_condition) { + block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); + } else { + block.chunks.update.push(b`${name}.p(${if_ctx}, #dirty);`); + } + } + if (if_exists_condition) { + block.chunks.destroy.push(b` if (${if_exists_condition}) { ${name}.d(${detaching}); } `); - } - else { - block.chunks.destroy.push(b ` + } else { + block.chunks.destroy.push(b` ${name}.d(${detaching}); `); - } - } - // if any of the siblings have outros, we need to keep references to the blocks - // (TODO does this only apply to bidi transitions?) + } + } + // if any of the siblings have outros, we need to keep references to the blocks + // (TODO does this only apply to bidi transitions?) - /** - * @param {import('../Block.js').default} block - * @param {import('estree').Identifier} parent_node - * @param {import('estree').Identifier} _parent_nodes - * @param {boolean} dynamic - * @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 current_block_type_index = block.get_unique_name('current_block_type_index'); - const previous_block_index = block.get_unique_name('previous_block_index'); - const if_block_creators = block.get_unique_name('if_block_creators'); - const if_blocks = block.get_unique_name('if_blocks'); - const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name); - const select_block_ctx = need_select_block_ctx - ? block.get_unique_name('select_block_ctx') - : null; - const if_ctx = select_block_ctx - ? x `${select_block_ctx}(#ctx, ${current_block_type_index})` - : x `#ctx`; - const if_current_block_type_index = has_else - ? (nodes) => nodes - : (nodes) => b `if (~${current_block_type_index}) { ${nodes} }`; - block.add_variable(current_block_type_index); - block.add_variable(name); - block.chunks.init.push(b ` + /** + * @param {import('../Block.js').default} block + * @param {import('estree').Identifier} parent_node + * @param {import('estree').Identifier} _parent_nodes + * @param {boolean} dynamic + * @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 current_block_type_index = block.get_unique_name('current_block_type_index'); + const previous_block_index = block.get_unique_name('previous_block_index'); + const if_block_creators = block.get_unique_name('if_block_creators'); + const if_blocks = block.get_unique_name('if_blocks'); + const need_select_block_ctx = this.branches.some((branch) => branch.get_ctx_name); + const select_block_ctx = need_select_block_ctx + ? block.get_unique_name('select_block_ctx') + : null; + const if_ctx = select_block_ctx + ? x`${select_block_ctx}(#ctx, ${current_block_type_index})` + : x`#ctx`; + const if_current_block_type_index = has_else + ? (nodes) => nodes + : (nodes) => b`if (~${current_block_type_index}) { ${nodes} }`; + block.add_variable(current_block_type_index); + block.add_variable(name); + block.chunks.init.push(b` const ${if_block_creators} = [ ${this.branches.map((branch) => branch.block.name)} ]; const ${if_blocks} = []; - ${this.needs_update - ? b ` + ${ + this.needs_update + ? b` function ${select_block_type}(#ctx, #dirty) { ${this.branches.map(({ dependencies, condition, snippet }) => { - return b `${snippet && dependencies.length > 0 - ? b `if (${block.renderer.dirty(dependencies)}) ${condition} = null;` - : null}`; - })} - ${this.branches.map(({ condition, snippet }, i) => condition - ? b ` - ${snippet && b `if (${condition} == null) ${condition} = !!${snippet}`} + return b`${ + snippet && dependencies.length > 0 + ? b`if (${block.renderer.dirty(dependencies)}) ${condition} = null;` + : null + }`; + })} + ${this.branches.map(({ condition, snippet }, i) => + condition + ? b` + ${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`} if (${condition}) return ${i};` - : b `return ${i};`)} - ${!has_else && b `return -1;`} + : b`return ${i};` + )} + ${!has_else && b`return -1;`} } ` - : b ` + : b` function ${select_block_type}(#ctx, #dirty) { - ${this.branches.map(({ condition, snippet }, i) => condition ? b `if (${snippet || condition}) return ${i};` : b `return ${i};`)} - ${!has_else && b `return -1;`} + ${this.branches.map(({ condition, snippet }, i) => + condition ? b`if (${snippet || condition}) return ${i};` : b`return ${i};` + )} + ${!has_else && b`return -1;`} } - `} + ` + } `); - if (need_select_block_ctx) { - // if all branches needs create a context - if (this.branches.every((branch) => branch.get_ctx_name)) { - block.chunks.init.push(b ` + if (need_select_block_ctx) { + // if all branches needs create a context + if (this.branches.every((branch) => branch.get_ctx_name)) { + block.chunks.init.push(b` function ${select_block_ctx}(#ctx, #index) { ${this.branches - .map(({ condition, get_ctx_name }, i) => { - return condition - ? b `if (#index === ${i}) return ${get_ctx_name}(#ctx);` - : b `return ${get_ctx_name}(#ctx);`; - }) - .filter(Boolean)} + .map(({ condition, get_ctx_name }, i) => { + return condition + ? b`if (#index === ${i}) return ${get_ctx_name}(#ctx);` + : b`return ${get_ctx_name}(#ctx);`; + }) + .filter(Boolean)} } `); - } - else { - // when not all branches need to create a new context, - // this code is simpler - block.chunks.init.push(b ` + } else { + // when not all branches need to create a new context, + // this code is simpler + block.chunks.init.push(b` function ${select_block_ctx}(#ctx, #index) { ${this.branches - .map(({ get_ctx_name }, i) => { - return get_ctx_name ? b `if (#index === ${i}) return ${get_ctx_name}(#ctx);` : null; - }) - .filter(Boolean)} + .map(({ get_ctx_name }, i) => { + return get_ctx_name ? b`if (#index === ${i}) return ${get_ctx_name}(#ctx);` : null; + }) + .filter(Boolean)} return #ctx; } `); - } - } - if (has_else) { - block.chunks.init.push(b ` + } + } + if (has_else) { + block.chunks.init.push(b` ${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}); `); - } - else { - block.chunks.init.push(b ` + } else { + block.chunks.init.push(b` 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}); } `); - } - const initial_mount_node = parent_node || '#target'; - 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});`)); - if (this.needs_update) { - const update_mount_node = this.get_update_mount_node(anchor); - const destroy_old_block = b ` + } + const initial_mount_node = parent_node || '#target'; + 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});` + ) + ); + if (this.needs_update) { + const update_mount_node = this.get_update_mount_node(anchor); + const destroy_old_block = b` @group_outros(); @transition_out(${if_blocks}[${previous_block_index}], 1, 1, () => { ${if_blocks}[${previous_block_index}] = null; }); @check_outros(); `; - const create_new_block = b ` + const create_new_block = b` ${name} = ${if_blocks}[${current_block_type_index}]; if (!${name}) { ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx}); ${name}.c(); } else { - ${dynamic && b `${name}.p(${if_ctx}, #dirty);`} + ${dynamic && b`${name}.p(${if_ctx}, #dirty);`} } - ${has_transitions && b `@transition_in(${name}, 1);`} + ${has_transitions && b`@transition_in(${name}, 1);`} ${name}.m(${update_mount_node}, ${anchor}); `; - const change_block = has_else - ? b ` + const change_block = has_else + ? b` ${destroy_old_block} ${create_new_block} ` - : b ` + : b` if (${name}) { ${destroy_old_block} } @@ -523,80 +571,91 @@ export default class IfBlockWrapper extends Wrapper { ${name} = null; } `; - block.chunks.update.push(b ` + block.chunks.update.push(b` let ${previous_block_index} = ${current_block_type_index}; ${current_block_type_index} = ${select_block_type}(#ctx, #dirty); `); - if (dynamic) { - block.chunks.update.push(b ` + if (dynamic) { + block.chunks.update.push(b` if (${current_block_type_index} === ${previous_block_index}) { - ${if_current_block_type_index(b `${if_blocks}[${current_block_type_index}].p(${if_ctx}, #dirty);`)} + ${if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].p(${if_ctx}, #dirty);`)} } else { ${change_block} } `); - } - else { - block.chunks.update.push(b ` + } else { + block.chunks.update.push(b` if (${current_block_type_index} !== ${previous_block_index}) { ${change_block} } `); - } - } - else if (dynamic) { - if (if_exists_condition) { - block.chunks.update.push(b `if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); - } - else { - 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});`)); - } + } + } else if (dynamic) { + if (if_exists_condition) { + block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`); + } else { + 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});`) + ); + } - /** - * @param {import('../Block.js').default} block - * @param {import('estree').Identifier} parent_node - * @param {import('estree').Identifier} _parent_nodes - * @param {boolean} dynamic - * @param {any} - * @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 if_ctx = branch.get_ctx_name ? x `${branch.get_ctx_name}(#ctx)` : x `#ctx`; - if (branch.snippet) - block.add_variable(branch.condition, branch.snippet); - block.chunks.init.push(b ` + /** + * @param {import('../Block.js').default} block + * @param {import('estree').Identifier} parent_node + * @param {import('estree').Identifier} _parent_nodes + * @param {boolean} dynamic + * @param {any} + * @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 if_ctx = branch.get_ctx_name ? x`${branch.get_ctx_name}(#ctx)` : x`#ctx`; + if (branch.snippet) block.add_variable(branch.condition, branch.snippet); + block.chunks.init.push(b` let ${name} = ${branch.condition} && ${branch.block.name}(${if_ctx}); `); - const initial_mount_node = parent_node || '#target'; - const anchor_node = parent_node ? 'null' : '#anchor'; - block.chunks.mount.push(b `if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`); - if (branch.dependencies.length > 0) { - const update_mount_node = this.get_update_mount_node(anchor); - const enter = b ` + const initial_mount_node = parent_node || '#target'; + const anchor_node = parent_node ? 'null' : '#anchor'; + block.chunks.mount.push(b`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`); + if (branch.dependencies.length > 0) { + const update_mount_node = this.get_update_mount_node(anchor); + const enter = b` if (${name}) { - ${dynamic && b `${name}.p(${if_ctx}, #dirty);`} - ${has_transitions && - b `if (${block.renderer.dirty(branch.dependencies)}) { + ${dynamic && b`${name}.p(${if_ctx}, #dirty);`} + ${ + has_transitions && + b`if (${block.renderer.dirty(branch.dependencies)}) { @transition_in(${name}, 1); - }`} + }` + } } else { ${name} = ${branch.block.name}(${if_ctx}); ${name}.c(); - ${has_transitions && b `@transition_in(${name}, 1);`} + ${has_transitions && b`@transition_in(${name}, 1);`} ${name}.m(${update_mount_node}, ${anchor}); } `; - if (branch.snippet) { - block.chunks.update.push(b `if (${block.renderer.dirty(branch.dependencies)}) ${branch.condition} = ${branch.snippet}`); - } - // no `p()` here — we don't want to update outroing nodes, - // as that will typically result in glitching - if (branch.block.has_outro_method) { - block.chunks.update.push(b ` + if (branch.snippet) { + block.chunks.update.push( + b`if (${block.renderer.dirty(branch.dependencies)}) ${branch.condition} = ${ + branch.snippet + }` + ); + } + // no `p()` here — we don't want to update outroing nodes, + // as that will typically result in glitching + if (branch.block.has_outro_method) { + block.chunks.update.push(b` if (${branch.condition}) { ${enter} } else if (${name}) { @@ -607,9 +666,8 @@ export default class IfBlockWrapper extends Wrapper { @check_outros(); } `); - } - else { - block.chunks.update.push(b ` + } else { + block.chunks.update.push(b` if (${branch.condition}) { ${enter} } else if (${name}) { @@ -617,26 +675,22 @@ export default class IfBlockWrapper extends Wrapper { ${name} = null; } `); - } - } - else if (dynamic) { - block.chunks.update.push(b ` + } + } else if (dynamic) { + block.chunks.update.push(b` if (${branch.condition}) ${name}.p(${if_ctx}, #dirty); `); - } - if (if_exists_condition) { - block.chunks.destroy.push(b ` + } + if (if_exists_condition) { + block.chunks.destroy.push(b` if (${if_exists_condition}) ${name}.d(${detaching}); `); - } - else { - block.chunks.destroy.push(b ` + } else { + block.chunks.destroy.push(b` ${name}.d(${detaching}); `); - } - } + } + } } - /** @typedef {'detaching' | null} DetachingOrNull */ -