|
|
|
|
@ -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 = {
|
|
|
|
|
@ -148,15 +152,19 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
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,8 +206,7 @@ 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
|
|
|
|
|
@ -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,8 +256,7 @@ 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) {
|
|
|
|
|
@ -248,8 +268,11 @@ 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`;
|
|
|
|
|
@ -289,7 +312,9 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
${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`
|
|
|
|
|
@group_outros();
|
|
|
|
|
@ -313,8 +338,7 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
${destroy_block_else};
|
|
|
|
|
}
|
|
|
|
|
`);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
this.updates.push(b`
|
|
|
|
|
if (${this.vars.data_length}) {
|
|
|
|
|
if (${each_block_else}) {
|
|
|
|
|
@ -341,26 +365,40 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
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);
|
|
|
|
|
: /** @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`
|
|
|
|
|
function ${this.vars.get_each_context}(#ctx, list, i) {
|
|
|
|
|
@ -383,7 +421,16 @@ 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`);
|
|
|
|
|
@ -391,16 +438,17 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
@ -441,13 +489,23 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
${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.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();`}
|
|
|
|
|
`);
|
|
|
|
|
}
|
|
|
|
|
@ -475,7 +533,15 @@ 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`
|
|
|
|
|
let ${iterations} = [];
|
|
|
|
|
@ -553,10 +619,11 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
}
|
|
|
|
|
@check_outros();
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} 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) {
|
|
|
|
|
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};`}
|
|
|
|
|
@ -591,7 +658,3 @@ export default class EachBlockWrapper extends Wrapper {
|
|
|
|
|
block.chunks.destroy.push(b`@destroy_each(${iterations}, detaching);`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|