pull/3539/head
Richard Harris 6 years ago
parent 12e7b5ecf5
commit 6514b142dc

@ -300,8 +300,13 @@ export default class Component {
walk(program, { walk(program, {
enter: (node) => { enter: (node) => {
if (node.type === 'Identifier' && node.name[0] === '@') { if (node.type === 'Identifier' && node.name[0] === '@') {
const alias = this.helper(node.name.slice(1)); if (node.name[1] === '_') {
node.name = alias.name; const alias = this.global(node.name.slice(2));
node.name = alias.name;
} else {
const alias = this.helper(node.name.slice(1));
node.name = alias.name;
}
} }
} }
}); });
@ -1223,7 +1228,7 @@ export default class Component {
} }
qualify(name) { qualify(name) {
if (name === `$$props`) return `ctx.$$props`; if (name === `$$props`) return `#ctx.$$props`;
const variable = this.var_lookup.get(name); const variable = this.var_lookup.get(name);
@ -1233,7 +1238,7 @@ export default class Component {
if (variable.hoistable) return name; if (variable.hoistable) return name;
return `ctx.${name}`; return `#ctx.${name}`;
} }
warn_if_undefined(name: string, node, template_scope: TemplateScope) { warn_if_undefined(name: string, node, template_scope: TemplateScope) {

@ -58,10 +58,11 @@ function esm(
source: { type: 'Literal', value: internal_path } source: { type: 'Literal', value: internal_path }
} }
const internal_globals = globals.length > 0 &&{ const internal_globals = globals.length > 0 && {
type: 'VariableDeclaration', type: 'VariableDeclaration',
kind: 'const', kind: 'const',
declarations: [{ declarations: [{
type: 'VariableDeclarator',
id: { id: {
type: 'ObjectPattern', type: 'ObjectPattern',
properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({ properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({
@ -70,10 +71,11 @@ function esm(
shorthand: false, shorthand: false,
computed: false, computed: false,
key: { type: 'Identifier', name: g.name }, key: { type: 'Identifier', name: g.name },
value: { type: 'Identifier', name: g.alias } value: g.alias,
kind: 'init'
})) }))
}, },
init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } init: helpers.find(({ name }) => name === 'globals').alias
}] }]
}; };
@ -135,7 +137,7 @@ function cjs(
}] }]
}; };
const internal_globals = globals.length > 0 &&{ const internal_globals = globals.length > 0 && {
type: 'VariableDeclaration', type: 'VariableDeclaration',
kind: 'const', kind: 'const',
declarations: [{ declarations: [{
@ -148,10 +150,11 @@ function cjs(
shorthand: false, shorthand: false,
computed: false, computed: false,
key: { type: 'Identifier', name: g.name }, key: { type: 'Identifier', name: g.name },
value: { type: 'Identifier', name: g.alias } value: g.alias,
kind: 'init'
})) }))
}, },
init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias } init: helpers.find(({ name }) => name === 'globals').alias
}] }]
}; };
@ -182,7 +185,7 @@ function cjs(
program.body = b` program.body = b`
"use strict"; "use strict";
${internal_requires} ${internal_requires}
// ${internal_globals} ${internal_globals}
${user_requires} ${user_requires}
${program.body} ${program.body}

@ -68,7 +68,7 @@ export default class Binding extends Node {
if (!this.expression.node.computed) prop = `'${prop}'`; if (!this.expression.node.computed) prop = `'${prop}'`;
obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`; obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`;
} else { } else {
obj = 'ctx'; obj = '#ctx';
prop = `'${name}'`; prop = `'${name}'`;
} }

@ -66,6 +66,6 @@ export default class EventHandler extends Node {
if (this.expression) this.expression.manipulate(block); if (this.expression) this.expression.manipulate(block);
// this.component.add_reference(this.handler_name); // this.component.add_reference(this.handler_name);
return `ctx.${this.handler_name}`; return `#ctx.${this.handler_name}`;
} }
} }

@ -325,6 +325,16 @@ export default class Expression {
else { else {
// we need a combo block/init recipe // we need a combo block/init recipe
node.params.unshift({
type: 'ObjectPattern',
properties: Array.from(contextual_dependencies).map(name => ({
type: 'Property',
kind: 'init',
key: { type: 'Identifier', name },
value: { type: 'Identifier', name }
}))
});
component.partly_hoisted.push(declaration); component.partly_hoisted.push(declaration);
node.name = id; node.name = id;

@ -1,6 +1,5 @@
import Renderer from './Renderer'; import Renderer from './Renderer';
import Wrapper from './wrappers/shared/Wrapper'; import Wrapper from './wrappers/shared/Wrapper';
import { escape } from '../utils/stringify';
import { b, x } from 'code-red'; import { b, x } from 'code-red';
import { Node, Identifier } from '../../interfaces'; import { Node, Identifier } from '../../interfaces';
@ -397,16 +396,15 @@ export default class Block {
render() { render() {
const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') }; const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') };
const id = { type: 'Identifier', name: this.name };
const args: any[] = [x`#ctx`]; const args: any[] = [x`#ctx`];
if (key) args.unshift(key); if (key) args.unshift(key);
// TODO include this.comment // TODO include this.comment
// ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
return b` return b`
${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`} function ${this.name}(${args}) {
function ${id}(${args}) {
${this.get_contents(key)} ${this.get_contents(key)}
} }
`; `;

@ -9,6 +9,7 @@ import { stringify_props } from '../utils/stringify_props';
import add_to_set from '../utils/add_to_set'; import add_to_set from '../utils/add_to_set';
import { extract_names } from '../utils/scope'; import { extract_names } from '../utils/scope';
import { invalidate } from '../utils/invalidate'; import { invalidate } from '../utils/invalidate';
import Block from './Block';
export default function dom( export default function dom(
component: Component, component: Component,
@ -52,7 +53,12 @@ export default function dom(
// TODO the deconflicted names of blocks are reversed... should set them here // TODO the deconflicted names of blocks are reversed... should set them here
const blocks = renderer.blocks.slice().reverse(); const blocks = renderer.blocks.slice().reverse();
body.push(...blocks); body.push(...blocks.map(block => {
// TODO this is a horrible mess — renderer.blocks
// contains a mixture of Blocks and Nodes
if ((block as Block).render) return (block as Block).render();
return block;
}));
if (options.dev && !options.hydratable) { if (options.dev && !options.hydratable) {
block.chunks.claim.push( block.chunks.claim.push(
@ -230,7 +236,7 @@ export default function dom(
} }
body.push(b` body.push(b`
function create_fragment(ctx) { function create_fragment(#ctx) {
${block.get_contents()} ${block.get_contents()}
} }

@ -137,7 +137,7 @@ export default class AwaitBlockWrapper extends Wrapper {
block.maintain_context = true; block.maintain_context = true;
const info_props = [ const info_props = [
'ctx', '#ctx',
'current: null', 'current: null',
'token: null', 'token: null',
this.pending.block.name && `pending: ${this.pending.block.name}`, this.pending.block.name && `pending: ${this.pending.block.name}`,
@ -197,7 +197,7 @@ export default class AwaitBlockWrapper extends Wrapper {
); );
block.chunks.update.push( block.chunks.update.push(
b`${info}.ctx = ctx;` b`${info}.ctx = #ctx;`
); );
if (this.pending.block.has_update_method) { if (this.pending.block.has_update_method) {
@ -205,7 +205,7 @@ export default class AwaitBlockWrapper extends Wrapper {
if (${conditions.join(' && ')}) { if (${conditions.join(' && ')}) {
// nothing // nothing
} else { } else {
${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved)); ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved));
} }
`); `);
} else { } else {
@ -216,7 +216,7 @@ export default class AwaitBlockWrapper extends Wrapper {
} else { } else {
if (this.pending.block.has_update_method) { if (this.pending.block.has_update_method) {
block.chunks.update.push(b` block.chunks.update.push(b`
${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved)); ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved));
`); `);
} }
} }

@ -59,7 +59,6 @@ export default class EachBlockWrapper extends Wrapper {
fixed_length: number; fixed_length: number;
data_length: string; data_length: string;
view_length: string; view_length: string;
length: string;
} }
context_props: string[]; context_props: string[];
@ -104,27 +103,32 @@ export default class EachBlockWrapper extends Wrapper {
? node.expression.node.elements.length ? node.expression.node.elements.length
: null; : null;
// TODO
// hack the sourcemap, so that if data is missing the bug // hack the sourcemap, so that if data is missing the bug
// is easy to find // is easy to find
let c = this.node.start + 2; let c = this.node.start + 2;
while (renderer.component.source[c] !== 'e') c += 1; while (renderer.component.source[c] !== 'e') c += 1;
const length = {
type: 'Identifier',
name: 'length',
// TODO this format may be incorrect
start: c,
end: c + 4
};
// renderer.component.code.overwrite(c, c + 4, 'length'); // renderer.component.code.overwrite(c, c + 4, 'length');
const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`); const each_block_value = renderer.component.get_unique_name(`${this.var.name}_value`);
const iterations = block.get_unique_name(`${this.var}_blocks`); const iterations = block.get_unique_name(`${this.var.name}_blocks`);
this.vars = { this.vars = {
create_each_block: this.block.name, create_each_block: this.block.name,
each_block_value, each_block_value,
get_each_context: renderer.component.get_unique_name(`get_${this.var}_context`), get_each_context: renderer.component.get_unique_name(`get_${this.var.name}_context`),
iterations, iterations,
length: `[✂${c}-${c+4}✂]`,
// optimisation for array literal // optimisation for array literal
fixed_length, fixed_length,
data_length: fixed_length === null ? `${each_block_value}.[✂${c}-${c+4}✂]` : fixed_length, data_length: fixed_length === null ? x`${each_block_value}.${length}` : fixed_length,
view_length: fixed_length === null ? `${iterations}.[✂${c}-${c+4}✂]` : fixed_length view_length: fixed_length === null ? x`${iterations}.length` : fixed_length
}; };
const store = const store =
@ -185,18 +189,18 @@ export default class EachBlockWrapper extends Wrapper {
? !this.next.is_dom_node() : ? !this.next.is_dom_node() :
!parent_node || !this.parent.is_dom_node(); !parent_node || !this.parent.is_dom_node();
this.context_props = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = ${attach_head('list[i]', prop.tail)};`); this.context_props = this.node.contexts.map(prop => b`child_ctx.${prop.key.name} = ${attach_head('list[i]', prop.tail)};`);
if (this.node.has_binding) this.context_props.push(`child_ctx.${this.vars.each_block_value} = list;`); if (this.node.has_binding) this.context_props.push(b`child_ctx.${this.vars.each_block_value} = list;`);
if (this.node.has_binding || this.node.index) this.context_props.push(`child_ctx.${this.index_name} = i;`); if (this.node.has_binding || this.node.index) this.context_props.push(b`child_ctx.${this.index_name} = i;`);
const snippet = this.node.expression.manipulate(block); 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};`);
renderer.blocks.push(b` renderer.blocks.push(b`
function ${this.vars.get_each_context}(ctx, list, i) { function ${this.vars.get_each_context}(#ctx, list, i) {
const child_ctx = @_Object.create(ctx); const child_ctx = @_Object.create(#ctx);
${this.context_props} ${this.context_props}
return child_ctx; return child_ctx;
} }
@ -251,7 +255,7 @@ export default class EachBlockWrapper extends Wrapper {
// TODO neaten this up... will end up with an empty line in the block // 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}) { if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else}.c(); ${each_block_else}.c();
} }
`); `);
@ -265,9 +269,9 @@ export default class EachBlockWrapper extends Wrapper {
if (this.else.block.has_update_method) { if (this.else.block.has_update_method) {
block.chunks.update.push(b` block.chunks.update.push(b`
if (!${this.vars.data_length} && ${each_block_else}) { if (!${this.vars.data_length} && ${each_block_else}) {
${each_block_else}.p(changed, ctx); ${each_block_else}.p(changed, #ctx);
} else if (!${this.vars.data_length}) { } else if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else}.c(); ${each_block_else}.c();
${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); ${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
} else if (${each_block_else}) { } else if (${each_block_else}) {
@ -283,7 +287,7 @@ export default class EachBlockWrapper extends Wrapper {
${each_block_else} = null; ${each_block_else} = null;
} }
} else if (!${each_block_else}) { } else if (!${each_block_else}) {
${each_block_else} = ${this.else.block.name}(ctx); ${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else}.c(); ${each_block_else}.c();
${each_block_else}.m(${update_mount_node}, ${update_anchor_node}); ${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
} }
@ -323,8 +327,8 @@ export default class EachBlockWrapper extends Wrapper {
}) { }) {
const { const {
create_each_block, create_each_block,
length,
iterations, iterations,
data_length,
view_length view_length
} = this.vars; } = this.vars;
@ -347,12 +351,12 @@ export default class EachBlockWrapper extends Wrapper {
} }
block.chunks.init.push(b` block.chunks.init.push(b`
const ${get_key} = ctx => ${ const ${get_key} = #ctx => ${
// @ts-ignore todo: probably error // @ts-ignore todo: probably error
this.node.key.render()}; this.node.key.render()};
for (let #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) { 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 child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i);
let key = ${get_key}(child_ctx); let key = ${get_key}(child_ctx);
${lookup}.set(key, ${iterations}[#i] = ${create_each_block}(key, child_ctx)); ${lookup}.set(key, ${iterations}[#i] = ${create_each_block}(key, child_ctx));
} }
@ -393,7 +397,7 @@ export default class EachBlockWrapper extends Wrapper {
${this.block.has_outros && `@group_outros();`} ${this.block.has_outros && `@group_outros();`}
${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`} ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`}
${iterations} = @update_keyed_each(${iterations}, changed, ${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}); ${iterations} = @update_keyed_each(${iterations}, changed, ${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 && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`} ${this.node.has_animation && `for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].a();`}
${this.block.has_outros && `@check_outros();`} ${this.block.has_outros && `@check_outros();`}
`); `);
@ -432,7 +436,6 @@ export default class EachBlockWrapper extends Wrapper {
}) { }) {
const { const {
create_each_block, create_each_block,
length,
iterations, iterations,
fixed_length, fixed_length,
data_length, data_length,
@ -443,7 +446,7 @@ export default class EachBlockWrapper extends Wrapper {
let ${iterations} = []; let ${iterations} = [];
for (let #i = 0; #i < ${data_length}; #i += 1) { 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)); ${iterations}[#i] = ${create_each_block}(${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i));
} }
`); `);
@ -473,13 +476,19 @@ export default class EachBlockWrapper extends Wrapper {
all_dependencies.add(dependency); all_dependencies.add(dependency);
}); });
const condition = Array.from(all_dependencies) let condition;
.map(dependency => `changed.${dependency}`) if (all_dependencies.size > 0) {
.join(' || '); // TODO make this more elegant somehow?
const array = Array.from(all_dependencies);
let condition = x`#changed.${array[0]}`;
for (let i = 1; i < array.length; i += 1) {
condition = x`${condition} || #changed.${array[i]}`;
}
}
const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method); const has_transitions = !!(this.block.has_intro_method || this.block.has_outro_method);
if (condition !== '') { if (condition) {
const for_loop_body = this.block.has_update_method const for_loop_body = this.block.has_update_method
? b` ? b`
if (${iterations}[#i]) { if (${iterations}[#i]) {
@ -525,17 +534,17 @@ export default class EachBlockWrapper extends Wrapper {
`); `);
remove_old_blocks = b` remove_old_blocks = b`
@group_outros(); @group_outros();
for (#i = ${this.vars.each_block_value}.${length}; #i < ${view_length}; #i += 1) { for (#i = ${data_length}; #i < ${view_length}; #i += 1) {
${out}(#i); ${out}(#i);
} }
@check_outros(); @check_outros();
`; `;
} else { } else {
remove_old_blocks = b` remove_old_blocks = b`
for (${this.block.has_update_method ? `` : `#i = ${this.vars.each_block_value}.${length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) { for (${this.block.has_update_method ? `` : `#i = ${data_length}`}; #i < ${this.block.has_update_method ? view_length : '#old_length'}; #i += 1) {
${iterations}[#i].d(1); ${iterations}[#i].d(1);
} }
${!fixed_length && `${view_length} = ${this.vars.each_block_value}.${length};`} ${!fixed_length && `${view_length} = ${data_length};`}
`; `;
} }
@ -546,8 +555,8 @@ export default class EachBlockWrapper extends Wrapper {
${this.vars.each_block_value} = ${snippet}; ${this.vars.each_block_value} = ${snippet};
let #i; let #i;
for (#i = ${start}; #i < ${this.vars.each_block_value}.${length}; #i += 1) { for (#i = ${start}; #i < ${data_length}; #i += 1) {
const child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i); const child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i);
${for_loop_body} ${for_loop_body}
} }

@ -1,4 +1,4 @@
import { b } from 'code-red'; import { b, x } from 'code-red';
import Wrapper from './Wrapper'; import Wrapper from './Wrapper';
import Renderer from '../../Renderer'; import Renderer from '../../Renderer';
import Block from '../../Block'; import Block from '../../Block';
@ -29,16 +29,20 @@ export default class Tag extends Wrapper {
if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string if (this.node.should_cache) block.add_variable(value, snippet); // TODO may need to coerce snippet to string
if (dependencies.length > 0) { if (dependencies.length > 0) {
const changed_check = ( let condition = x`#changed.${dependencies[0]}`;
(block.has_outros ? `!#current || ` : '') + for (let i = 1; i < dependencies.length; i += 1) {
dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ') condition = x`${condition} || #changed.${dependencies[i]}`;
); }
const update_cached_value = `${value} !== (${value} = ${snippet} + "")`; if (block.has_outros) {
condition = x`!#current || ${condition}`;
}
const condition = this.node.should_cache const update_cached_value = x`${value} !== (${value} = ${snippet} + "")`;
? `(${changed_check}) && ${update_cached_value}`
: changed_check; if (this.node.should_cache) {
condition = x`${condition} && ${update_cached_value}`;
}
block.chunks.update.push(b`if (${condition}) ${update(content as Node)}`); block.chunks.update.push(b`if (${condition}) ${update(content as Node)}`);
} }

@ -102,6 +102,7 @@ export function init(component, options, instance, create_fragment, not_equal, p
$$.ctx = instance $$.ctx = instance
? instance(component, props, (key, ret, value = ret) => { ? instance(component, props, (key, ret, value = ret) => {
console.log(`invalidating`, key, ret, value);
if ($$.ctx && not_equal($$.ctx[key], $$.ctx[key] = value)) { if ($$.ctx && not_equal($$.ctx[key], $$.ctx[key] = value)) {
if ($$.bound[key]) $$.bound[key](value); if ($$.bound[key]) $$.bound[key](value);
if (ready) make_dirty(component, key); if (ready) make_dirty(component, key);

Loading…
Cancel
Save