start attempting to simplify binding code a bit

pull/1934/head
Richard Harris 7 years ago
parent 08605efcab
commit 287590e338

@ -29,7 +29,7 @@ export default class Block {
dependencies: Set<string>;
bindings: Map<string, () => { object: string, property: string, snippet: string }>;
bindings: Map<string, { object: string, property: string, snippet: string }>;
contextOwners: Map<string, EachBlockWrapper>;
builders: {

@ -97,15 +97,33 @@ export default class EachBlockWrapper extends Wrapper {
this.indexName = this.node.index || renderer.component.getUniqueName(`${this.node.context}_index`);
// 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;
renderer.component.code.overwrite(c, c + 4, 'length');
const length = `[✂${c}-${c+4}✂]`;
this.vars = {
create_each_block: this.block.name,
each_block_value: renderer.component.getUniqueName(`${this.var}_value`),
get_each_context: renderer.component.getUniqueName(`get_${this.var}_context`),
iterations: block.getUniqueName(`${this.var}_blocks`),
length: `[✂${c}-${c+4}✂]`,
// filled out later
anchor: null,
mountOrIntro: null
};
node.contexts.forEach(prop => {
this.block.contextOwners.set(prop.key.name, this);
// TODO this doesn't feel great
this.block.bindings.set(prop.key.name, () => ({
this.block.bindings.set(prop.key.name, {
object: this.vars.each_block_value,
property: this.indexName,
snippet: `${this.vars.each_block_value}[${this.indexName}]${prop.tail}`
}));
});
});
if (this.node.index) {
@ -147,30 +165,15 @@ export default class EachBlockWrapper extends Wrapper {
const { renderer } = this;
const { component } = renderer;
// hack the sourcemap, so that if data is missing the bug
// is easy to find
let c = this.node.start + 2;
while (component.source[c] !== 'e') c += 1;
component.code.overwrite(c, c + 4, 'length');
const length = `[✂${c}-${c+4}✂]`;
const needsAnchor = this.next
? !this.next.isDomNode() :
!parentNode || !this.parent.isDomNode();
this.vars = {
anchor: needsAnchor
this.vars.anchor = needsAnchor
? block.getUniqueName(`${this.var}_anchor`)
: (this.next && this.next.var) || 'null',
create_each_block: this.block.name,
each_block_value: renderer.component.getUniqueName(`${this.var}_value`),
get_each_context: renderer.component.getUniqueName(`get_${this.var}_context`),
iterations: block.getUniqueName(`${this.var}_blocks`),
length: `[✂${c}-${c+4}✂]`,
mountOrIntro: (this.block.hasIntroMethod || this.block.hasOutroMethod)
? 'i'
: 'm'
};
: (this.next && this.next.var) || 'null';
this.vars.mountOrIntro = (this.block.hasIntroMethod || this.block.hasOutroMethod) ? 'i' : 'm';
this.contextProps = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = list[i]${prop.tail};`);
@ -212,7 +215,7 @@ export default class EachBlockWrapper extends Wrapper {
// TODO neaten this up... will end up with an empty line in the block
block.builders.init.addBlock(deindent`
if (!${this.vars.each_block_value}.${length}) {
if (!${this.vars.each_block_value}.${this.vars.length}) {
${each_block_else} = ${this.else.block.name}(#component, ctx);
${each_block_else}.c();
}
@ -228,9 +231,9 @@ export default class EachBlockWrapper extends Wrapper {
if (this.else.block.hasUpdateMethod) {
block.builders.update.addBlock(deindent`
if (!${this.vars.each_block_value}.${length} && ${each_block_else}) {
if (!${this.vars.each_block_value}.${this.vars.length} && ${each_block_else}) {
${each_block_else}.p(changed, ctx);
} else if (!${this.vars.each_block_value}.${length}) {
} else if (!${this.vars.each_block_value}.${this.vars.length}) {
${each_block_else} = ${this.else.block.name}(#component, ctx);
${each_block_else}.c();
${each_block_else}.${mountOrIntro}(${initialMountNode}, ${this.vars.anchor});
@ -241,7 +244,7 @@ export default class EachBlockWrapper extends Wrapper {
`);
} else {
block.builders.update.addBlock(deindent`
if (${this.vars.each_block_value}.${length}) {
if (${this.vars.each_block_value}.${this.vars.length}) {
if (${each_block_else}) {
${each_block_else}.d(1);
${each_block_else} = null;

@ -21,7 +21,11 @@ export default class BindingWrapper {
parent: ElementWrapper;
object: string;
handler: any; // TODO
handler: {
usesContext: boolean;
mutation: string;
contextual_dependencies: Set<string>
};
updateDom: string;
initialUpdate: string;
needsLock: boolean;
@ -51,6 +55,15 @@ export default class BindingWrapper {
eachBlock.hasBinding = true;
}
this.object = getObject(this.node.expression.node).name;
// TODO unfortunate code is necessary because we need to use `ctx`
// inside the fragment, but not inside the <script>
const contextless_snippet = this.parent.renderer.component.source.slice(this.node.expression.node.start, this.node.expression.node.end);
// view to model
this.handler = getEventHandler(this, parent.renderer, block, this.object, contextless_snippet);
}
isReadOnlyMediaAttribute() {
@ -73,14 +86,8 @@ export default class BindingWrapper {
let updateConditions: string[] = [];
const { name } = getObject(this.node.expression.node);
const snippet = this.node.expression.render();
// TODO unfortunate code is necessary because we need to use `ctx`
// inside the fragment, but not inside the <script>
const contextless_snippet = this.parent.renderer.component.source.slice(this.node.expression.node.start, this.node.expression.node.end);
// special case: if you have e.g. `<input type=checkbox bind:checked=selected.done>`
// and `selected` is an object chosen with a <select>, then when `checked` changes,
// we need to tell the component to update all the values `selected` might be
@ -97,10 +104,6 @@ export default class BindingWrapper {
}
});
// view to model
const valueFromDom = getValueFromDom(renderer, this.parent, this);
const handler = getEventHandler(this, renderer, block, name, contextless_snippet, valueFromDom);
// model to view
let updateDom = getDomUpdater(parent, this, snippet);
let initialUpdate = updateDom;
@ -152,10 +155,9 @@ export default class BindingWrapper {
return {
name: this.node.name,
object: name,
handler,
object: this.object,
handler: this.handler,
snippet,
usesContext: handler.usesContext,
updateDom: updateDom,
initialUpdate: initialUpdate,
needsLock: !isReadOnly && needsLock,
@ -221,9 +223,10 @@ function getEventHandler(
renderer: Renderer,
block: Block,
name: string,
snippet: string,
value: string
snippet: string
) {
const value = getValueFromDom(renderer, binding.parent, binding);
if (binding.node.isContextual) {
let tail = '';
if (binding.node.expression.node.type === 'MemberExpression') {
@ -231,7 +234,7 @@ function getEventHandler(
tail = renderer.component.source.slice(start, end);
}
const { object, property, snippet } = block.bindings.get(name)();
const { object, property, snippet } = block.bindings.get(name);
return {
usesContext: true,

@ -520,7 +520,7 @@ export default class ElementWrapper extends Wrapper {
renderer.component.declarations.push(name);
renderer.component.template_references.add(name);
const { handler, object } = this_binding.munge(block);
const { handler, object } = this_binding;
renderer.component.partly_hoisted.push(deindent`
function ${name}($$node) {

@ -211,7 +211,7 @@ export default class InlineComponentWrapper extends Wrapper {
// bind:x={y} — we can't just do `y = x`, we need to
// to `array[index] = x;
const { name } = binding.expression.node;
const { object, property, snippet } = block.bindings.get(name)();
const { object, property, snippet } = block.bindings.get(name);
lhs = snippet;
// TODO we need to invalidate... something
@ -263,7 +263,7 @@ export default class InlineComponentWrapper extends Wrapper {
// bind:x={y} — we can't just do `y = x`, we need to
// to `array[index] = x;
const { name } = binding.expression.node;
const { object, property, snippet } = block.bindings.get(name)();
const { object, property, snippet } = block.bindings.get(name);
lhs = snippet;
contextual_dependencies.push(object, property);
}

Loading…
Cancel
Save