Lint and format src/compiler/compile/render_dom/wrappers/EachBlock.js

pull/8569/head
Simon Holthausen 3 years ago
parent caab2e0e56
commit 57f5f5e3a4

@ -8,7 +8,6 @@ import Expression from '../../nodes/shared/Expression.js';
/** @extends Wrapper */
export class ElseBlockWrapper extends Wrapper {
/** @type {import('../../nodes/ElseBlock.js').default} */
node;
@ -39,14 +38,20 @@ export class ElseBlockWrapper extends Wrapper {
name: this.renderer.component.get_unique_name('create_else_block'),
type: 'else'
});
this.fragment = new FragmentWrapper(renderer, this.block, this.node.children, parent, strip_whitespace, next_sibling);
this.fragment = new FragmentWrapper(
renderer,
this.block,
this.node.children,
parent,
strip_whitespace,
next_sibling
);
this.is_dynamic = this.block.dependencies.size > 0;
}
}
/** @extends Wrapper */
export default class EachBlockWrapper extends Wrapper {
/** @type {import('../Block.js').default} */
block;
@ -99,8 +104,7 @@ export default class EachBlockWrapper extends Wrapper {
const { dependencies } = node.expression;
block.add_dependencies(dependencies);
this.node.contexts.forEach((context) => {
if (context.type !== 'DestructuredVariable')
return;
if (context.type !== 'DestructuredVariable') return;
renderer.add_to_context(context.key.name, true);
});
add_const_tags_context(renderer, this.node.const_tags);
@ -117,15 +121,15 @@ export default class EachBlockWrapper extends Wrapper {
this.index_name = this.node.index
? { type: 'Identifier', name: this.node.index }
: renderer.component.get_unique_name(`${this.node.context}_index`);
const fixed_length = node.expression.node.type === 'ArrayExpression' &&
const fixed_length =
node.expression.node.type === 'ArrayExpression' &&
node.expression.node.elements.every((element) => element.type !== 'SpreadElement')
? node.expression.node.elements.length
: null;
// hack the sourcemap, so that if data is missing the bug
// is easy to find
let c = this.node.start + 2;
while (renderer.component.source[c] !== 'e')
c += 1;
while (renderer.component.source[c] !== 'e') c += 1;
const start = renderer.component.locate(c);
const end = { line: start.line, column: start.column + 4 };
const length = {
@ -144,19 +148,23 @@ export default class EachBlockWrapper extends Wrapper {
iterations,
// optimisation for array literal
fixed_length,
data_length: fixed_length === null ? x `${each_block_value}.${length}` : fixed_length,
view_length: fixed_length === null ? x `${iterations}.length` : fixed_length
data_length: fixed_length === null ? x`${each_block_value}.${length}` : fixed_length,
view_length: fixed_length === null ? x`${iterations}.length` : fixed_length
};
const object = get_object(node.expression.node);
const store = object.type === 'Identifier' && object.name[0] === '$' ? object.name.slice(1) : null;
const store =
object.type === 'Identifier' && object.name[0] === '$' ? object.name.slice(1) : null;
node.contexts.forEach((prop) => {
if (prop.type !== 'DestructuredVariable')
return;
if (prop.type !== 'DestructuredVariable') return;
this.block.bindings.set(prop.key.name, {
object: this.vars.each_block_value,
property: this.index_name,
modifier: prop.modifier,
snippet: prop.modifier(/** @type {import('estree').Node} */ (x `${this.vars.each_block_value}[${this.index_name}]`)),
snippet: prop.modifier(
/** @type {import('estree').Node} */ (
x`${this.vars.each_block_value}[${this.index_name}]`
)
),
store
});
});
@ -164,9 +172,23 @@ export default class EachBlockWrapper extends Wrapper {
this.block.get_unique_name(this.node.index); // this prevents name collisions (#1254)
}
renderer.blocks.push(this.block);
this.fragment = new FragmentWrapper(renderer, this.block, node.children, this, strip_whitespace, next_sibling);
this.fragment = new FragmentWrapper(
renderer,
this.block,
node.children,
this,
strip_whitespace,
next_sibling
);
if (this.node.else) {
this.else = new ElseBlockWrapper(renderer, block, this, this.node.else, strip_whitespace, next_sibling);
this.else = new ElseBlockWrapper(
renderer,
block,
this,
this.node.else,
strip_whitespace,
next_sibling
);
renderer.blocks.push(this.else.block);
if (this.else.is_dynamic) {
this.block.add_dependencies(this.else.block.dependencies);
@ -184,17 +206,16 @@ export default class EachBlockWrapper extends Wrapper {
* @param {import('estree').Identifier} parent_nodes
*/
render(block, parent_node, parent_nodes) {
if (this.fragment.nodes.length === 0)
return;
if (this.fragment.nodes.length === 0) return;
const { renderer } = this;
const { component } = renderer;
const needs_anchor = this.next
? !this.next.is_dom_node()
: !parent_node || !this.parent.is_dom_node();
const snippet = this.node.expression.manipulate(block);
block.chunks.init.push(b `let ${this.vars.each_block_value} = ${snippet};`);
block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`);
if (this.renderer.options.dev) {
block.chunks.init.push(b `@validate_each_argument(${this.vars.each_block_value});`);
block.chunks.init.push(b`@validate_each_argument(${this.vars.each_block_value});`);
}
/** @type {import('estree').Identifier} */
@ -211,8 +232,8 @@ export default class EachBlockWrapper extends Wrapper {
/** @type {import('estree').Identifier} */
const update_mount_node = this.get_update_mount_node(
/** @type {import('estree').Identifier} */ (update_anchor_node));
/** @type {import('estree').Identifier} */ (update_anchor_node)
);
const args = {
block,
parent_node,
@ -235,12 +256,11 @@ export default class EachBlockWrapper extends Wrapper {
this.dependencies = all_dependencies;
if (this.node.key) {
this.render_keyed(args);
}
else {
} else {
this.render_unkeyed(args);
}
if (this.block.has_intro_method || this.block.has_outro_method) {
block.chunks.intro.push(b `
block.chunks.intro.push(b`
for (let #i = 0; #i < ${this.vars.data_length}; #i += 1) {
@transition_in(${this.vars.iterations}[#i]);
}
@ -248,74 +268,78 @@ export default class EachBlockWrapper extends Wrapper {
}
if (needs_anchor) {
block.add_element(
/** @type {import('estree').Identifier} */ (update_anchor_node), x `@empty()`, parent_nodes && x `@empty()`, parent_node);
/** @type {import('estree').Identifier} */ (update_anchor_node),
x`@empty()`,
parent_nodes && x`@empty()`,
parent_node
);
}
if (this.else) {
let else_ctx = x `#ctx`;
let else_ctx = x`#ctx`;
if (this.else.node.const_tags.length > 0) {
const get_ctx_name = this.renderer.component.get_unique_name('get_else_ctx');
this.renderer.blocks.push(b `
this.renderer.blocks.push(b`
function ${get_ctx_name}(#ctx) {
const child_ctx = #ctx.slice();
${add_const_tags(block, this.else.node.const_tags, 'child_ctx')}
return child_ctx;
}
`);
else_ctx = x `${get_ctx_name}(#ctx)`;
else_ctx = x`${get_ctx_name}(#ctx)`;
}
const each_block_else = component.get_unique_name(`${this.var.name}_else`);
block.chunks.init.push(b `let ${each_block_else} = null;`);
block.chunks.init.push(b`let ${each_block_else} = null;`);
// TODO neaten this up... will end up with an empty line in the block
block.chunks.init.push(b `
block.chunks.init.push(b`
if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(${else_ctx});
}
`);
block.chunks.create.push(b `
block.chunks.create.push(b`
if (${each_block_else}) {
${each_block_else}.c();
}
`);
if (this.renderer.options.hydratable) {
block.chunks.claim.push(b `
block.chunks.claim.push(b`
if (${each_block_else}) {
${each_block_else}.l(${parent_nodes});
}
`);
}
block.chunks.mount.push(b `
block.chunks.mount.push(b`
if (${each_block_else}) {
${each_block_else}.m(${initial_mount_node}, ${initial_anchor_node});
}
`);
const has_transitions = !!(this.else.block.has_intro_method || this.else.block.has_outro_method);
const has_transitions = !!(
this.else.block.has_intro_method || this.else.block.has_outro_method
);
const destroy_block_else = this.else.block.has_outro_method
? b `
? b`
@group_outros();
@transition_out(${each_block_else}, 1, 1, () => {
${each_block_else} = null;
});
@check_outros();`
: b `
: b`
${each_block_else}.d(1);
${each_block_else} = null;`;
if (this.else.block.has_update_method) {
this.updates.push(b `
this.updates.push(b`
if (!${this.vars.data_length} && ${each_block_else}) {
${each_block_else}.p(${else_ctx}, #dirty);
} else if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(${else_ctx});
${each_block_else}.c();
${has_transitions && b `@transition_in(${each_block_else}, 1);`}
${has_transitions && b`@transition_in(${each_block_else}, 1);`}
${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
} else if (${each_block_else}) {
${destroy_block_else};
}
`);
}
else {
this.updates.push(b `
} else {
this.updates.push(b`
if (${this.vars.data_length}) {
if (${each_block_else}) {
${destroy_block_else};
@ -323,46 +347,60 @@ export default class EachBlockWrapper extends Wrapper {
} else if (!${each_block_else}) {
${each_block_else} = ${this.else.block.name}(${else_ctx});
${each_block_else}.c();
${has_transitions && b `@transition_in(${each_block_else}, 1);`}
${has_transitions && b`@transition_in(${each_block_else}, 1);`}
${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
}
`);
}
block.chunks.destroy.push(b `
block.chunks.destroy.push(b`
if (${each_block_else}) ${each_block_else}.d(${parent_node ? '' : 'detaching'});
`);
}
if (this.updates.length) {
block.chunks.update.push(b `
block.chunks.update.push(b`
if (${block.renderer.dirty(Array.from(all_dependencies))}) {
${this.updates}
}
`);
}
this.fragment.render(this.block, null, /** @type {import('estree').Identifier} */ (x `#nodes`));
this.fragment.render(this.block, null, /** @type {import('estree').Identifier} */ (x`#nodes`));
if (this.else) {
this.else.fragment.render(this.else.block, null, /** @type {import('estree').Identifier} */ (x `#nodes`));
this.else.fragment.render(
this.else.block,
null,
/** @type {import('estree').Identifier} */ (x`#nodes`)
);
}
this.context_props = this.node.contexts.map((prop) => {
if (prop.type === 'DestructuredVariable') {
/** @param {string} name */
const to_ctx = (name) => renderer.context_lookup.has(name)
? x `child_ctx[${renderer.context_lookup.get(name).index}]`
: ( /** @type {import('estree').Node} */({ type: 'Identifier', name }));
return b `child_ctx[${renderer.context_lookup.get(prop.key.name).index}] = ${prop.default_modifier(prop.modifier(x `list[i]`), to_ctx)};`;
}
else {
const expression = new Expression(this.renderer.component, this.node, this.node.scope, prop.key);
return b `const ${prop.property_name} = ${expression.manipulate(block, 'child_ctx')};`;
const to_ctx = (name) =>
renderer.context_lookup.has(name)
? x`child_ctx[${renderer.context_lookup.get(name).index}]`
: /** @type {import('estree').Node} */ ({ type: 'Identifier', name });
return b`child_ctx[${
renderer.context_lookup.get(prop.key.name).index
}] = ${prop.default_modifier(prop.modifier(x`list[i]`), to_ctx)};`;
} else {
const expression = new Expression(
this.renderer.component,
this.node,
this.node.scope,
prop.key
);
return b`const ${prop.property_name} = ${expression.manipulate(block, 'child_ctx')};`;
}
});
if (this.node.has_binding)
this.context_props.push(b `child_ctx[${renderer.context_lookup.get(this.vars.each_block_value.name).index}] = list;`);
this.context_props.push(
b`child_ctx[${renderer.context_lookup.get(this.vars.each_block_value.name).index}] = list;`
);
if (this.node.has_binding || this.node.has_index_binding || this.node.index)
this.context_props.push(b `child_ctx[${renderer.context_lookup.get(this.index_name.name).index}] = i;`);
this.context_props.push(
b`child_ctx[${renderer.context_lookup.get(this.index_name.name).index}] = i;`
);
// TODO which is better — Object.create(array) or array.slice()?
renderer.blocks.push(b `
renderer.blocks.push(b`
function ${this.vars.get_each_context}(#ctx, list, i) {
const child_ctx = #ctx.slice();
${this.context_props}
@ -383,43 +421,53 @@ export default class EachBlockWrapper extends Wrapper {
* update_mount_node: import('estree').Identifier;
* }}
*/
render_keyed({ block, parent_node, parent_nodes, snippet, initial_anchor_node, initial_mount_node, update_anchor_node, update_mount_node }) {
render_keyed({
block,
parent_node,
parent_nodes,
snippet,
initial_anchor_node,
initial_mount_node,
update_anchor_node,
update_mount_node
}) {
const { create_each_block, iterations, data_length, view_length } = this.vars;
const get_key = block.get_unique_name('get_key');
const lookup = block.get_unique_name(`${this.var.name}_lookup`);
block.add_variable(iterations, x `[]`);
block.add_variable(lookup, x `new @_Map()`);
block.add_variable(iterations, x`[]`);
block.add_variable(lookup, x`new @_Map()`);
if (this.fragment.nodes[0].is_dom_node()) {
this.block.first = this.fragment.nodes[0].var;
}
else {
} else {
this.block.first = this.block.get_unique_name('first');
this.block.add_element(this.block.first, x `@empty()`, parent_nodes && x `@empty()`, null);
this.block.add_element(this.block.first, x`@empty()`, parent_nodes && x`@empty()`, null);
}
block.chunks.init.push(b `
block.chunks.init.push(b`
const ${get_key} = #ctx => ${this.node.key.manipulate(block)};
${this.renderer.options.dev &&
b `@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});`}
${
this.renderer.options.dev &&
b`@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});`
}
for (let #i = 0; #i < ${data_length}; #i += 1) {
let child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i);
let key = ${get_key}(child_ctx);
${lookup}.set(key, ${iterations}[#i] = ${create_each_block}(key, child_ctx));
}
`);
block.chunks.create.push(b `
block.chunks.create.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].c();
}
`);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(b `
block.chunks.claim.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].l(${parent_nodes});
}
`);
}
block.chunks.mount.push(b `
block.chunks.mount.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
if (${iterations}[#i]) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
@ -436,29 +484,39 @@ export default class EachBlockWrapper extends Wrapper {
: '@destroy_block';
if (this.dependencies.size) {
this.block.maintain_context = true;
this.updates.push(b `
this.updates.push(b`
${this.vars.each_block_value} = ${snippet};
${this.renderer.options.dev && b `@validate_each_argument(${this.vars.each_block_value});`}
${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`}
${this.block.has_outros && b `@group_outros();`}
${this.node.has_animation &&
b `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`}
${this.renderer.options.dev &&
b `@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});`}
${iterations} = @update_keyed_each(${iterations}, #dirty, ${get_key}, ${dynamic ? 1 : 0}, #ctx, ${this.vars.each_block_value}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${this.vars.get_each_context});
${this.node.has_animation &&
b `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`}
${this.block.has_outros && b `@check_outros();`}
${this.block.has_outros && b`@group_outros();`}
${
this.node.has_animation &&
b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`
}
${
this.renderer.options.dev &&
b`@validate_each_keys(#ctx, ${this.vars.each_block_value}, ${this.vars.get_each_context}, ${get_key});`
}
${iterations} = @update_keyed_each(${iterations}, #dirty, ${get_key}, ${dynamic ? 1 : 0}, #ctx, ${
this.vars.each_block_value
}, ${lookup}, ${update_mount_node}, ${destroy}, ${create_each_block}, ${update_anchor_node}, ${
this.vars.get_each_context
});
${
this.node.has_animation &&
b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`
}
${this.block.has_outros && b`@check_outros();`}
`);
}
if (this.block.has_outros) {
block.chunks.outro.push(b `
block.chunks.outro.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
@transition_out(${iterations}[#i]);
}
`);
}
block.chunks.destroy.push(b `
block.chunks.destroy.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].d(${parent_node ? null : 'detaching'});
}
@ -475,28 +533,36 @@ export default class EachBlockWrapper extends Wrapper {
* update_mount_node: import('estree').Identifier;
* }}
*/
render_unkeyed({ block, parent_nodes, snippet, initial_anchor_node, initial_mount_node, update_anchor_node, update_mount_node }) {
render_unkeyed({
block,
parent_nodes,
snippet,
initial_anchor_node,
initial_mount_node,
update_anchor_node,
update_mount_node
}) {
const { create_each_block, iterations, fixed_length, data_length, view_length } = this.vars;
block.chunks.init.push(b `
block.chunks.init.push(b`
let ${iterations} = [];
for (let #i = 0; #i < ${data_length}; #i += 1) {
${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i));
}
`);
block.chunks.create.push(b `
block.chunks.create.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].c();
}
`);
if (parent_nodes && this.renderer.options.hydratable) {
block.chunks.claim.push(b `
block.chunks.claim.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
${iterations}[#i].l(${parent_nodes});
}
`);
}
block.chunks.mount.push(b `
block.chunks.mount.push(b`
for (let #i = 0; #i < ${view_length}; #i += 1) {
if (${iterations}[#i]) {
${iterations}[#i].m(${initial_mount_node}, ${initial_anchor_node});
@ -506,19 +572,19 @@ export default class EachBlockWrapper extends Wrapper {
if (this.dependencies.size) {
const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method);
const for_loop_body = this.block.has_update_method
? b `
? b`
if (${iterations}[#i]) {
${iterations}[#i].p(child_ctx, #dirty);
${has_transitions && b `@transition_in(${this.vars.iterations}[#i], 1);`}
${has_transitions && b`@transition_in(${this.vars.iterations}[#i], 1);`}
} else {
${iterations}[#i] = ${create_each_block}(child_ctx);
${iterations}[#i].c();
${has_transitions && b `@transition_in(${this.vars.iterations}[#i], 1);`}
${has_transitions && b`@transition_in(${this.vars.iterations}[#i], 1);`}
${iterations}[#i].m(${update_mount_node}, ${update_anchor_node});
}
`
: has_transitions
? b `
? b`
if (${iterations}[#i]) {
@transition_in(${this.vars.iterations}[#i], 1);
} else {
@ -528,7 +594,7 @@ export default class EachBlockWrapper extends Wrapper {
${iterations}[#i].m(${update_mount_node}, ${update_anchor_node});
}
`
: b `
: b`
if (!${iterations}[#i]) {
${iterations}[#i] = ${create_each_block}(child_ctx);
${iterations}[#i].c();
@ -541,33 +607,34 @@ export default class EachBlockWrapper extends Wrapper {
let remove_old_blocks;
if (this.block.has_outros) {
const out = block.get_unique_name('out');
block.chunks.init.push(b `
block.chunks.init.push(b`
const ${out} = i => @transition_out(${iterations}[i], 1, 1, () => {
${iterations}[i] = null;
});
`);
remove_old_blocks = b `
remove_old_blocks = b`
@group_outros();
for (#i = ${data_length}; #i < ${view_length}; #i += 1) {
${out}(#i);
}
@check_outros();
`;
}
else {
remove_old_blocks = b `
for (${this.block.has_update_method ? null : x `#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) {
} else {
remove_old_blocks = b`
for (${this.block.has_update_method ? null : x`#i = ${data_length}`}; #i < ${
this.block.has_update_method ? view_length : '#old_length'
}; #i += 1) {
${iterations}[#i].d(1);
}
${!fixed_length && b `${view_length} = ${data_length};`}
${!fixed_length && b`${view_length} = ${data_length};`}
`;
}
// We declare `i` as block scoped here, as the `remove_old_blocks` code
// may rely on continuing where this iteration stopped.
const update = b `
${!this.block.has_update_method && b `const #old_length = ${this.vars.each_block_value}.length;`}
const update = b`
${!this.block.has_update_method && b`const #old_length = ${this.vars.each_block_value}.length;`}
${this.vars.each_block_value} = ${snippet};
${this.renderer.options.dev && b `@validate_each_argument(${this.vars.each_block_value});`}
${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`}
let #i;
for (#i = ${start}; #i < ${data_length}; #i += 1) {
@ -581,17 +648,13 @@ export default class EachBlockWrapper extends Wrapper {
this.updates.push(update);
}
if (this.block.has_outros) {
block.chunks.outro.push(b `
block.chunks.outro.push(b`
${iterations} = ${iterations}.filter(@_Boolean);
for (let #i = 0; #i < ${view_length}; #i += 1) {
@transition_out(${iterations}[#i]);
}
`);
}
block.chunks.destroy.push(b `@destroy_each(${iterations}, detaching);`);
block.chunks.destroy.push(b`@destroy_each(${iterations}, detaching);`);
}
}

Loading…
Cancel
Save