more tidying up

pull/992/head
Rich Harris 8 years ago
parent e9dc123c45
commit ea418cd306

@ -130,15 +130,13 @@ export default class Block {
claimStatement: string,
parentNode: string
) {
const isToplevel = !parentNode;
this.addVariable(name);
this.builders.create.addLine(`${name} = ${renderStatement};`);
this.builders.claim.addLine(`${name} = ${claimStatement};`);
this.mount(name, parentNode);
if (isToplevel) {
if (!parentNode) {
this.builders.unmount.addLine(`@detachNode(${name});`);
}
}

@ -145,13 +145,11 @@ export default class EachBlock extends Node {
block.builders.init.addLine(`var ${each_block_value} = ${snippet};`);
if (this.key) {
keyed(generator, block, parentNode, parentNodes, this, snippet, vars);
this.buildKeyed(block, parentNode, parentNodes, snippet, vars);
} else {
unkeyed(generator, block, parentNode, parentNodes, this, snippet, vars);
this.buildUnkeyed(block, parentNode, parentNodes, snippet, vars);
}
const isToplevel = !parentNode;
if (needsAnchor) {
block.addElement(
anchor,
@ -231,357 +229,353 @@ export default class EachBlock extends Node {
});
}
}
}
function keyed(
generator: DomGenerator,
block: Block,
parentNode: string,
parentNodes: string,
node: EachBlock,
snippet: string,
{
each,
create_each_block,
each_block_value,
length,
params,
anchor,
mountOrIntro,
}
) {
const key = block.getUniqueName('key');
const lookup = block.getUniqueName(`${each}_lookup`);
const iteration = block.getUniqueName(`${each}_iteration`);
const head = block.getUniqueName(`${each}_head`);
const last = block.getUniqueName(`${each}_last`);
const expected = block.getUniqueName(`${each}_expected`);
block.addVariable(lookup, `@blankObject()`);
block.addVariable(head);
block.addVariable(last);
if (node.children[0] && node.children[0].type === 'Element' && !generator.components.has(node.children[0].name)) {
// TODO or text/tag/raw
node._block.first = node.children[0].var; // TODO this is highly confusing
} else {
node._block.first = node._block.getUniqueName('first');
node._block.addElement(
node._block.first,
`@createComment()`,
`@createComment()`,
null
);
}
block.builders.init.addBlock(deindent`
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
var ${key} = ${each_block_value}[#i].${node.key};
var ${iteration} = ${lookup}[${key}] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component, ${key});
if (${last}) ${last}.next = ${iteration};
${iteration}.last = ${last};
${last} = ${iteration};
if (#i === 0) ${head} = ${iteration};
}
`);
const initialMountNode = parentNode || '#target';
const updateMountNode = node.getUpdateMountNode(anchor);
const anchorNode = parentNode ? 'null' : 'anchor';
block.builders.create.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.c();
${iteration} = ${iteration}.next;
buildKeyed(
block: Block,
parentNode: string,
parentNodes: string,
snippet: string,
{
each,
create_each_block,
each_block_value,
length,
params,
anchor,
mountOrIntro,
}
`);
block.builders.claim.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.l(${parentNodes});
${iteration} = ${iteration}.next;
) {
const key = block.getUniqueName('key');
const lookup = block.getUniqueName(`${each}_lookup`);
const iteration = block.getUniqueName(`${each}_iteration`);
const head = block.getUniqueName(`${each}_head`);
const last = block.getUniqueName(`${each}_last`);
const expected = block.getUniqueName(`${each}_expected`);
block.addVariable(lookup, `@blankObject()`);
block.addVariable(head);
block.addVariable(last);
if (this.children[0] && this.children[0].type === 'Element') {
// TODO or text/tag/raw
this._block.first = this.children[0].var; // TODO this is highly confusing
} else {
this._block.first = this._block.getUniqueName('first');
this._block.addElement(
this._block.first,
`@createComment()`,
`@createComment()`,
null
);
}
`);
block.builders.mount.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.${mountOrIntro}(${initialMountNode}, ${anchorNode});
${iteration} = ${iteration}.next;
}
`);
block.builders.init.addBlock(deindent`
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
var ${key} = ${each_block_value}[#i].${this.key};
var ${iteration} = ${lookup}[${key}] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component, ${key});
const dynamic = node._block.hasUpdateMethod;
if (${last}) ${last}.next = ${iteration};
${iteration}.last = ${last};
${last} = ${iteration};
let destroy;
if (node._block.hasOutroMethod) {
const fn = block.getUniqueName(`${each}_outro`);
block.builders.init.addBlock(deindent`
function ${fn}(iteration) {
iteration.o(function() {
iteration.u();
iteration.d();
${lookup}[iteration.key] = null;
});
if (#i === 0) ${head} = ${iteration};
}
`);
destroy = deindent`
while (${expected}) {
${fn}(${expected});
${expected} = ${expected}.next;
}
const initialMountNode = parentNode || '#target';
const updateMountNode = this.getUpdateMountNode(anchor);
const anchorNode = parentNode ? 'null' : 'anchor';
for (#i = 0; #i < discard_pile.length; #i += 1) {
if (discard_pile[#i].discard) {
${fn}(discard_pile[#i]);
}
block.builders.create.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.c();
${iteration} = ${iteration}.next;
}
`;
} else {
const fn = block.getUniqueName(`${each}_destroy`);
block.builders.init.addBlock(deindent`
function ${fn}(iteration) {
iteration.u();
iteration.d();
${lookup}[iteration.key] = null;
`);
block.builders.claim.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.l(${parentNodes});
${iteration} = ${iteration}.next;
}
`);
destroy = deindent`
while (${expected}) {
${fn}(${expected});
${expected} = ${expected}.next;
block.builders.mount.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.${mountOrIntro}(${initialMountNode}, ${anchorNode});
${iteration} = ${iteration}.next;
}
`);
const dynamic = this._block.hasUpdateMethod;
for (#i = 0; #i < discard_pile.length; #i += 1) {
var ${iteration} = discard_pile[#i];
if (${iteration}.discard) {
${fn}(${iteration});
let destroy;
if (this._block.hasOutroMethod) {
const fn = block.getUniqueName(`${each}_outro`);
block.builders.init.addBlock(deindent`
function ${fn}(iteration) {
iteration.o(function() {
iteration.u();
iteration.d();
${lookup}[iteration.key] = null;
});
}
}
`;
}
`);
destroy = deindent`
while (${expected}) {
${fn}(${expected});
${expected} = ${expected}.next;
}
for (#i = 0; #i < discard_pile.length; #i += 1) {
if (discard_pile[#i].discard) {
${fn}(discard_pile[#i]);
}
}
`;
} else {
const fn = block.getUniqueName(`${each}_destroy`);
block.builders.init.addBlock(deindent`
function ${fn}(iteration) {
iteration.u();
iteration.d();
${lookup}[iteration.key] = null;
}
`);
block.builders.update.addBlock(deindent`
var ${each_block_value} = ${snippet};
destroy = deindent`
while (${expected}) {
${fn}(${expected});
${expected} = ${expected}.next;
}
var ${expected} = ${head};
var ${last} = null;
for (#i = 0; #i < discard_pile.length; #i += 1) {
var ${iteration} = discard_pile[#i];
if (${iteration}.discard) {
${fn}(${iteration});
}
}
`;
}
var discard_pile = [];
block.builders.update.addBlock(deindent`
var ${each_block_value} = ${snippet};
for (#i = 0; #i < ${each_block_value}.${length}; #i += 1) {
var ${key} = ${each_block_value}[#i].${node.key};
var ${iteration} = ${lookup}[${key}];
var ${expected} = ${head};
var ${last} = null;
${dynamic &&
`if (${iteration}) ${iteration}.p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);`}
var discard_pile = [];
if (${expected}) {
if (${key} === ${expected}.key) {
${expected} = ${expected}.next;
for (#i = 0; #i < ${each_block_value}.${length}; #i += 1) {
var ${key} = ${each_block_value}[#i].${this.key};
var ${iteration} = ${lookup}[${key}];
${dynamic &&
`if (${iteration}) ${iteration}.p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);`}
if (${expected}) {
if (${key} === ${expected}.key) {
${expected} = ${expected}.next;
} else {
if (${iteration}) {
// probably a deletion
while (${expected} && ${expected}.key !== ${key}) {
${expected}.discard = true;
discard_pile.push(${expected});
${expected} = ${expected}.next;
};
${expected} = ${expected} && ${expected}.next;
${iteration}.discard = false;
${iteration}.last = ${last};
if (!${expected}) ${iteration}.m(${updateMountNode}, ${anchor});
} else {
// key is being inserted
${iteration} = ${lookup}[${key}] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component, ${key});
${iteration}.c();
${iteration}.${mountOrIntro}(${updateMountNode}, ${expected}.first);
${expected}.last = ${iteration};
${iteration}.next = ${expected};
}
}
} else {
// we're appending from this point forward
if (${iteration}) {
// probably a deletion
while (${expected} && ${expected}.key !== ${key}) {
${expected}.discard = true;
discard_pile.push(${expected});
${expected} = ${expected}.next;
};
${expected} = ${expected} && ${expected}.next;
${iteration}.discard = false;
${iteration}.last = ${last};
if (!${expected}) ${iteration}.m(${updateMountNode}, ${anchor});
${iteration}.next = null;
${iteration}.m(${updateMountNode}, ${anchor});
} else {
// key is being inserted
${iteration} = ${lookup}[${key}] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component, ${key});
${iteration}.c();
${iteration}.${mountOrIntro}(${updateMountNode}, ${expected}.first);
${expected}.last = ${iteration};
${iteration}.next = ${expected};
${iteration}.${mountOrIntro}(${updateMountNode}, ${anchor});
}
}
} else {
// we're appending from this point forward
if (${iteration}) {
${iteration}.discard = false;
${iteration}.next = null;
${iteration}.m(${updateMountNode}, ${anchor});
} else {
${iteration} = ${lookup}[${key}] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component, ${key});
${iteration}.c();
${iteration}.${mountOrIntro}(${updateMountNode}, ${anchor});
}
if (${last}) ${last}.next = ${iteration};
${iteration}.last = ${last};
${this._block.hasIntroMethod && `${iteration}.i(${updateMountNode}, ${anchor});`}
${last} = ${iteration};
}
if (${last}) ${last}.next = ${iteration};
${iteration}.last = ${last};
${node._block.hasIntroMethod && `${iteration}.i(${updateMountNode}, ${anchor});`}
${last} = ${iteration};
}
if (${last}) ${last}.next = null;
if (${last}) ${last}.next = null;
${destroy}
${destroy}
${head} = ${lookup}[${each_block_value}[0] && ${each_block_value}[0].${this.key}];
`);
${head} = ${lookup}[${each_block_value}[0] && ${each_block_value}[0].${node.key}];
`);
if (!parentNode) {
block.builders.unmount.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.u();
${iteration} = ${iteration}.next;
}
`);
}
if (!parentNode) {
block.builders.unmount.addBlock(deindent`
block.builders.destroy.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.u();
${iteration}.d();
${iteration} = ${iteration}.next;
}
`);
}
block.builders.destroy.addBlock(deindent`
var ${iteration} = ${head};
while (${iteration}) {
${iteration}.d();
${iteration} = ${iteration}.next;
buildUnkeyed(
block: Block,
parentNode: string,
parentNodes: string,
snippet: string,
{
create_each_block,
each_block_value,
length,
iterations,
params,
anchor,
mountOrIntro,
}
`);
}
) {
block.builders.init.addBlock(deindent`
var ${iterations} = [];
function unkeyed(
generator: DomGenerator,
block: Block,
parentNode: string,
parentNodes: string,
node: EachBlock,
snippet: string,
{
create_each_block,
each_block_value,
length,
iterations,
params,
anchor,
mountOrIntro,
}
) {
block.builders.init.addBlock(deindent`
var ${iterations} = [];
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
}
`);
for (var #i = 0; #i < ${each_block_value}.${length}; #i += 1) {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
}
`);
const initialMountNode = parentNode || '#target';
const updateMountNode = this.getUpdateMountNode(anchor);
const anchorNode = parentNode ? 'null' : 'anchor';
const initialMountNode = parentNode || '#target';
const updateMountNode = node.getUpdateMountNode(anchor);
const anchorNode = parentNode ? 'null' : 'anchor';
block.builders.create.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].c();
}
`);
block.builders.create.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].c();
}
`);
block.builders.claim.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].l(${parentNodes});
}
`);
block.builders.claim.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].l(${parentNodes});
}
`);
block.builders.mount.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode});
}
`);
block.builders.mount.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].${mountOrIntro}(${initialMountNode}, ${anchorNode});
}
`);
const allDependencies = new Set(node._block.dependencies);
const { dependencies } = node.metadata;
dependencies.forEach((dependency: string) => {
allDependencies.add(dependency);
});
// TODO do this for keyed blocks as well
const condition = Array.from(allDependencies)
.map(dependency => `changed.${dependency}`)
.join(' || ');
if (condition !== '') {
const forLoopBody = node._block.hasUpdateMethod
? node._block.hasIntroMethod
const allDependencies = new Set(this._block.dependencies);
const { dependencies } = this.metadata;
dependencies.forEach((dependency: string) => {
allDependencies.add(dependency);
});
// TODO do this for keyed blocks as well
const condition = Array.from(allDependencies)
.map(dependency => `changed.${dependency}`)
.join(' || ');
if (condition !== '') {
const forLoopBody = this._block.hasUpdateMethod
? this._block.hasIntroMethod
? deindent`
if (${iterations}[#i]) {
${iterations}[#i].p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);
} else {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
}
${iterations}[#i].i(${updateMountNode}, ${anchor});
`
: deindent`
if (${iterations}[#i]) {
${iterations}[#i].p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);
} else {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
${iterations}[#i].m(${updateMountNode}, ${anchor});
}
`
: deindent`
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
${iterations}[#i].${mountOrIntro}(${updateMountNode}, ${anchor});
`;
const start = this._block.hasUpdateMethod ? '0' : `${iterations}.length`;
const outro = block.getUniqueName('outro');
const destroy = this._block.hasOutroMethod
? deindent`
if (${iterations}[#i]) {
${iterations}[#i].p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);
} else {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
function ${outro}(i) {
if (${iterations}[i]) {
${iterations}[i].o(function() {
${iterations}[i].u();
${iterations}[i].d();
${iterations}[i] = null;
});
}
}
${iterations}[#i].i(${updateMountNode}, ${anchor});
for (; #i < ${iterations}.length; #i += 1) ${outro}(#i);
`
: deindent`
if (${iterations}[#i]) {
${iterations}[#i].p(changed, ${params}, ${each_block_value}, ${each_block_value}[#i], #i);
} else {
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
${iterations}[#i].m(${updateMountNode}, ${anchor});
for (; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].u();
${iterations}[#i].d();
}
`
: deindent`
${iterations}[#i] = ${create_each_block}(${params}, ${each_block_value}, ${each_block_value}[#i], #i, #component);
${iterations}[#i].c();
${iterations}[#i].${mountOrIntro}(${updateMountNode}, ${anchor});
`;
${iterations}.length = ${each_block_value}.${length};
`;
const start = node._block.hasUpdateMethod ? '0' : `${iterations}.length`;
const outro = block.getUniqueName('outro');
const destroy = node._block.hasOutroMethod
? deindent`
function ${outro}(i) {
if (${iterations}[i]) {
${iterations}[i].o(function() {
${iterations}[i].u();
${iterations}[i].d();
${iterations}[i] = null;
});
}
}
block.builders.update.addBlock(deindent`
var ${each_block_value} = ${snippet};
for (; #i < ${iterations}.length; #i += 1) ${outro}(#i);
`
: deindent`
for (; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].u();
${iterations}[#i].d();
}
${iterations}.length = ${each_block_value}.${length};
`;
block.builders.update.addBlock(deindent`
var ${each_block_value} = ${snippet};
if (${condition}) {
for (var #i = ${start}; #i < ${each_block_value}.${length}; #i += 1) {
${forLoopBody}
}
if (${condition}) {
for (var #i = ${start}; #i < ${each_block_value}.${length}; #i += 1) {
${forLoopBody}
${destroy}
}
`);
}
${destroy}
block.builders.unmount.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].u();
}
`);
}
block.builders.unmount.addBlock(deindent`
for (var #i = 0; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].u();
}
`);
block.builders.destroy.addBlock(`@destroyEach(${iterations});`);
}
block.builders.destroy.addBlock(`@destroyEach(${iterations});`);
}
}

@ -110,7 +110,7 @@ export default class IfBlock extends Node {
const dynamic = branches[0].hasUpdateMethod; // can use [0] as proxy for all, since they necessarily have the same value
const hasOutros = branches[0].hasOutroMethod;
const vars = { name, needsAnchor, anchor, params, if_name, hasElse };
const vars = { name, anchor, params, if_name, hasElse };
if (this.else) {
if (hasOutros) {
@ -216,7 +216,7 @@ function simple(
node: Node,
branch,
dynamic,
{ name, needsAnchor, anchor, params, if_name }
{ name, anchor, params, if_name }
) {
block.builders.init.addBlock(deindent`
var ${name} = (${branch.condition}) && ${branch.block}(${params}, #component);
@ -306,7 +306,7 @@ function compound(
node: Node,
branches,
dynamic,
{ name, needsAnchor, anchor, params, hasElse, if_name }
{ name, anchor, params, hasElse, if_name }
) {
const select_block_type = generator.getUniqueName(`select_block_type`);
const current_block_type = block.getUniqueName(`current_block_type`);
@ -382,7 +382,7 @@ function compoundWithOutros(
node: Node,
branches,
dynamic,
{ name, needsAnchor, anchor, params, hasElse }
{ name, anchor, params, hasElse }
) {
const select_block_type = block.getUniqueName(`select_block_type`);
const current_block_type_index = block.getUniqueName(`current_block_type_index`);

@ -149,6 +149,8 @@ export default class Node {
}
getOrCreateAnchor(block: Block, parentNode: string) {
// TODO use this in EachBlock and IfBlock — tricky because
// children need to be created first
const needsAnchor = this.next ? !this.next.isDomNode() : !parentNode || !this.parent.isDomNode();
const anchor = needsAnchor
? block.getUniqueName(`${this.var}_anchor`)

Loading…
Cancel
Save