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

@ -300,10 +300,15 @@ export default class Component {
walk(program, {
enter: (node) => {
if (node.type === 'Identifier' && node.name[0] === '@') {
if (node.name[1] === '_') {
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;
}
}
}
});
const referenced_globals = Array.from(
@ -1223,7 +1228,7 @@ export default class Component {
}
qualify(name) {
if (name === `$$props`) return `ctx.$$props`;
if (name === `$$props`) return `#ctx.$$props`;
const variable = this.var_lookup.get(name);
@ -1233,7 +1238,7 @@ export default class Component {
if (variable.hoistable) return name;
return `ctx.${name}`;
return `#ctx.${name}`;
}
warn_if_undefined(name: string, node, template_scope: TemplateScope) {

@ -62,6 +62,7 @@ function esm(
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: {
type: 'ObjectPattern',
properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({
@ -70,10 +71,11 @@ function esm(
shorthand: false,
computed: false,
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
}]
};
@ -148,10 +150,11 @@ function cjs(
shorthand: false,
computed: false,
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`
"use strict";
${internal_requires}
// ${internal_globals}
${internal_globals}
${user_requires}
${program.body}

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

@ -66,6 +66,6 @@ export default class EventHandler extends Node {
if (this.expression) this.expression.manipulate(block);
// 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 {
// 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);
node.name = id;

@ -1,6 +1,5 @@
import Renderer from './Renderer';
import Wrapper from './wrappers/shared/Wrapper';
import { escape } from '../utils/stringify';
import { b, x } from 'code-red';
import { Node, Identifier } from '../../interfaces';
@ -397,16 +396,15 @@ export default class Block {
render() {
const key = this.key && { type: 'Identifier', name: this.get_unique_name('key') };
const id = { type: 'Identifier', name: this.name };
const args: any[] = [x`#ctx`];
if (key) args.unshift(key);
// TODO include this.comment
// ${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
return b`
${this.comment && `// ${escape(this.comment, { only_escape_at_symbol: true })}`}
function ${id}(${args}) {
function ${this.name}(${args}) {
${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 { extract_names } from '../utils/scope';
import { invalidate } from '../utils/invalidate';
import Block from './Block';
export default function dom(
component: Component,
@ -52,7 +53,12 @@ export default function dom(
// TODO the deconflicted names of blocks are reversed... should set them here
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) {
block.chunks.claim.push(
@ -230,7 +236,7 @@ export default function dom(
}
body.push(b`
function create_fragment(ctx) {
function create_fragment(#ctx) {
${block.get_contents()}
}

@ -137,7 +137,7 @@ export default class AwaitBlockWrapper extends Wrapper {
block.maintain_context = true;
const info_props = [
'ctx',
'#ctx',
'current: null',
'token: null',
this.pending.block.name && `pending: ${this.pending.block.name}`,
@ -197,7 +197,7 @@ export default class AwaitBlockWrapper extends Wrapper {
);
block.chunks.update.push(
b`${info}.ctx = ctx;`
b`${info}.ctx = #ctx;`
);
if (this.pending.block.has_update_method) {
@ -205,7 +205,7 @@ export default class AwaitBlockWrapper extends Wrapper {
if (${conditions.join(' && ')}) {
// nothing
} else {
${info}.block.p(changed, @assign(@assign({}, ctx), ${info}.resolved));
${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved));
}
`);
} else {
@ -216,7 +216,7 @@ export default class AwaitBlockWrapper extends Wrapper {
} else {
if (this.pending.block.has_update_method) {
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;
data_length: string;
view_length: string;
length: string;
}
context_props: string[];
@ -104,27 +103,32 @@ export default class EachBlockWrapper extends Wrapper {
? node.expression.node.elements.length
: null;
// TODO
// 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;
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');
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 = {
create_each_block: this.block.name,
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,
length: `[✂${c}-${c+4}✂]`,
// optimisation for array literal
fixed_length,
data_length: fixed_length === null ? `${each_block_value}.[✂${c}-${c+4}✂]` : fixed_length,
view_length: fixed_length === null ? `${iterations}.[✂${c}-${c+4}✂]` : 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 store =
@ -185,18 +189,18 @@ export default class EachBlockWrapper extends Wrapper {
? !this.next.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.node.index) this.context_props.push(`child_ctx.${this.index_name} = i;`);
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(b`child_ctx.${this.index_name} = i;`);
const snippet = this.node.expression.manipulate(block);
block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`);
renderer.blocks.push(b`
function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = @_Object.create(ctx);
function ${this.vars.get_each_context}(#ctx, list, i) {
const child_ctx = @_Object.create(#ctx);
${this.context_props}
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
block.chunks.init.push(b`
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();
}
`);
@ -265,9 +269,9 @@ export default class EachBlockWrapper extends Wrapper {
if (this.else.block.has_update_method) {
block.chunks.update.push(b`
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}) {
${each_block_else} = ${this.else.block.name}(ctx);
${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else}.c();
${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
} else if (${each_block_else}) {
@ -283,7 +287,7 @@ export default class EachBlockWrapper extends Wrapper {
${each_block_else} = null;
}
} 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}.m(${update_mount_node}, ${update_anchor_node});
}
@ -323,8 +327,8 @@ export default class EachBlockWrapper extends Wrapper {
}) {
const {
create_each_block,
length,
iterations,
data_length,
view_length
} = this.vars;
@ -347,12 +351,12 @@ export default class EachBlockWrapper extends Wrapper {
}
block.chunks.init.push(b`
const ${get_key} = ctx => ${
const ${get_key} = #ctx => ${
// @ts-ignore todo: probably error
this.node.key.render()};
for (let #i = 0; #i < ${this.vars.each_block_value}.${length}; #i += 1) {
let child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i);
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));
}
@ -393,7 +397,7 @@ export default class EachBlockWrapper extends Wrapper {
${this.block.has_outros && `@group_outros();`}
${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.block.has_outros && `@check_outros();`}
`);
@ -432,7 +436,6 @@ export default class EachBlockWrapper extends Wrapper {
}) {
const {
create_each_block,
length,
iterations,
fixed_length,
data_length,
@ -443,7 +446,7 @@ export default class EachBlockWrapper extends Wrapper {
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));
${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);
});
const condition = Array.from(all_dependencies)
.map(dependency => `changed.${dependency}`)
.join(' || ');
let condition;
if (all_dependencies.size > 0) {
// 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);
if (condition !== '') {
if (condition) {
const for_loop_body = this.block.has_update_method
? b`
if (${iterations}[#i]) {
@ -525,17 +534,17 @@ export default class EachBlockWrapper extends Wrapper {
`);
remove_old_blocks = b`
@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);
}
@check_outros();
`;
} else {
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);
}
${!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};
let #i;
for (#i = ${start}; #i < ${this.vars.each_block_value}.${length}; #i += 1) {
const child_ctx = ${this.vars.get_each_context}(ctx, ${this.vars.each_block_value}, #i);
for (#i = ${start}; #i < ${data_length}; #i += 1) {
const child_ctx = ${this.vars.get_each_context}(#ctx, ${this.vars.each_block_value}, #i);
${for_loop_body}
}

@ -1,4 +1,4 @@
import { b } from 'code-red';
import { b, x } from 'code-red';
import Wrapper from './Wrapper';
import Renderer from '../../Renderer';
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 (dependencies.length > 0) {
const changed_check = (
(block.has_outros ? `!#current || ` : '') +
dependencies.map((dependency: string) => `changed.${dependency}`).join(' || ')
);
let condition = x`#changed.${dependencies[0]}`;
for (let i = 1; i < dependencies.length; i += 1) {
condition = x`${condition} || #changed.${dependencies[i]}`;
}
if (block.has_outros) {
condition = x`!#current || ${condition}`;
}
const update_cached_value = `${value} !== (${value} = ${snippet} + "")`;
const update_cached_value = x`${value} !== (${value} = ${snippet} + "")`;
const condition = this.node.should_cache
? `(${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)}`);
}

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

Loading…
Cancel
Save