pull/3539/head
Richard Harris 6 years ago
parent 1091d23ed1
commit fe7d0d371b

@ -838,7 +838,7 @@ export default class Component {
} }
if (value) { if (value) {
return `$$invalidate('${name}', ${value})`; return x`$$invalidate('${name}', ${value})`;
} }
// if this is a reactive declaration, invalidate dependencies recursively // if this is a reactive declaration, invalidate dependencies recursively

@ -1,4 +1,4 @@
import { b, x } from 'code-red'; import { b, x, p } from 'code-red';
import { stringify, escape } from '../utils/stringify'; import { stringify, escape } from '../utils/stringify';
import Component from '../Component'; import Component from '../Component';
import Renderer from './Renderer'; import Renderer from './Renderer';
@ -8,7 +8,7 @@ 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'; import Block from './Block';
import { ClassDeclaration, FunctionExpression } from 'estree'; import { ClassDeclaration, FunctionExpression, Node } from 'estree';
export default function dom( export default function dom(
component: Component, component: Component,
@ -82,12 +82,12 @@ export default function dom(
const set = (uses_props || writable_props.length > 0 || component.slots.size > 0) const set = (uses_props || writable_props.length > 0 || component.slots.size > 0)
? x` ? x`
${$$props} => { ${$$props} => {
${uses_props && component.invalidate('$$props', b`$$props = @assign(@assign({}, $$props), $$new_props)`)} ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)}
${writable_props.map(prop => ${writable_props.map(prop =>
b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};` b`if ('${prop.export_name}' in ${$$props}) ${component.invalidate(prop.name, `${prop.name} = ${$$props}.${prop.export_name}`)};`
)} )}
${component.slots.size > 0 && ${component.slots.size > 0 &&
b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`} b`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`}
} }
` `
: null; : null;
@ -261,9 +261,9 @@ export default function dom(
const filtered_declarations = component.vars const filtered_declarations = component.vars
.filter(v => ((v.referenced || v.export_name) && !v.hoistable)) .filter(v => ((v.referenced || v.export_name) && !v.hoistable))
.map(v => v.name); .map(v => p`${v.name}`);
if (uses_props) filtered_declarations.push(`$$props: $$props = ${component.helper('exclude_internal_props')}($$props)`); if (uses_props) filtered_declarations.push(p`$$props: $$props = ${component.helper('exclude_internal_props')}($$props)`);
const filtered_props = props.filter(prop => { const filtered_props = props.filter(prop => {
const variable = component.var_lookup.get(prop.name); const variable = component.var_lookup.get(prop.name);
@ -276,11 +276,11 @@ export default function dom(
const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
if (component.slots.size > 0) { if (component.slots.size > 0) {
filtered_declarations.push('$$slots', '$$scope'); filtered_declarations.push(p`$$slots`, p`$$scope`);
} }
if (renderer.binding_groups.length > 0) { if (renderer.binding_groups.length > 0) {
filtered_declarations.push(`$$binding_groups`); filtered_declarations.push(p`$$binding_groups`);
} }
const has_definition = ( const has_definition = (
@ -319,30 +319,29 @@ export default function dom(
.map(({ name }) => `$$self.$$.on_destroy.push(() => $$unsubscribe_${name.slice(1)}());`); .map(({ name }) => `$$self.$$.on_destroy.push(() => $$unsubscribe_${name.slice(1)}());`);
if (has_definition) { if (has_definition) {
const reactive_declarations = []; const reactive_declarations: (Node | Node[]) = [];
const fixed_reactive_declarations = []; // not really 'reactive' but whatever const fixed_reactive_declarations = []; // not really 'reactive' but whatever
component.reactive_declarations component.reactive_declarations.forEach(d => {
.forEach(_d => { const dependencies = Array.from(d.dependencies);
// const dependencies = Array.from(d.dependencies); const uses_props = !!dependencies.find(n => n === '$$props');
// const uses_props = !!dependencies.find(n => n === '$$props');
const condition = !uses_props && dependencies
// const condition = !uses_props && dependencies .filter(n => {
// .filter(n => { const variable = component.var_lookup.get(n);
// const variable = component.var_lookup.get(n); return variable && (variable.writable || variable.mutated);
// return variable && (variable.writable || variable.mutated); })
// }) .map(n => x`$$dirty.${n}`)
// .map(n => `$$dirty.${n}`).join(' || '); .reduce((lhs, rhs) => x`${lhs} || ${rhs}`);
throw new Error(`bad`); let statement = d.node;
// let snippet = `[✂${d.node.body.start}-${d.node.end}✂]`; if (condition) statement = b`if (${condition}) { ${statement} }`[0];
// if (condition) snippet = `if (${condition}) { ${snippet} }`;
if (condition || uses_props) {
// if (condition || uses_props) { reactive_declarations.push(statement);
// reactive_declarations.push(snippet); } else {
// } else { fixed_reactive_declarations.push(statement);
// fixed_reactive_declarations.push(snippet); }
// }
}); });
const injected = Array.from(component.injected_reactive_declaration_vars).filter(name => { const injected = Array.from(component.injected_reactive_declaration_vars).filter(name => {
@ -365,7 +364,7 @@ export default function dom(
let unknown_props_check; let unknown_props_check;
if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) { if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) {
unknown_props_check = b` unknown_props_check = b`
const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}]; const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`)}];
@_Object.keys($$props).forEach(key => { @_Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`); if (!writable_props.includes(key) && !key.startsWith('$$')) @_console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
}); });
@ -374,13 +373,17 @@ export default function dom(
const return_value = { const return_value = {
type: 'ObjectExpression', type: 'ObjectExpression',
properties: filtered_declarations.map(name => { properties: filtered_declarations
const id = { type: 'Identifier', name }; };
const reactive_dependencies = {
type: 'ObjectPattern',
properties: Array.from(all_reactive_dependencies).map(name => {
return { return {
type: 'Property', type: 'Property',
key: id, kind: 'init',
value: id, key: { type: 'Identifier', name },
kind: 'init' value: { type: 'Literal', value: 1 }
}; };
}) })
}; };
@ -412,7 +415,7 @@ export default function dom(
${injected.length && `let ${injected.join(', ')};`} ${injected.length && `let ${injected.join(', ')};`}
${reactive_declarations.length > 0 && b` ${reactive_declarations.length > 0 && b`
$$self.$$.update = ($$dirty = { ${Array.from(all_reactive_dependencies).map(n => `${n}: 1`).join(', ')} }) => { $$self.$$.update = ($$dirty = ${reactive_dependencies}) => {
${reactive_declarations} ${reactive_declarations}
}; };
`} `}

@ -7,6 +7,7 @@ import { b, x } from 'code-red';
import Expression from '../../../nodes/shared/Expression'; import Expression from '../../../nodes/shared/Expression';
import Text from '../../../nodes/Text'; import Text from '../../../nodes/Text';
import { changed } from '../shared/changed'; import { changed } from '../shared/changed';
import { Literal } from 'estree';
export default class AttributeWrapper { export default class AttributeWrapper {
node: Attribute; node: Attribute;
@ -173,7 +174,7 @@ export default class AttributeWrapper {
? b`@set_input_type(${element.var}, ${value});` ? b`@set_input_type(${element.var}, ${value});`
: property_name : property_name
? b`${element.var}.${property_name} = ${value};` ? b`${element.var}.${property_name} = ${value};`
: b`${method}(${element.var}, "${name}", ${value});` : b`${method}(${element.var}, "${name}", ${value.type === 'Literal' && (value as Literal).value === true ? x`""` : value});`
); );
block.chunks.hydrate.push(statement); block.chunks.hydrate.push(statement);

@ -341,8 +341,8 @@ export default class IfBlockWrapper extends Wrapper {
const if_blocks = block.get_unique_name(`if_blocks`); const if_blocks = block.get_unique_name(`if_blocks`);
const if_current_block_type_index = has_else const if_current_block_type_index = has_else
? '' ? nodes => nodes
: `if (~${current_block_type_index}) `; : nodes => b`if (~${current_block_type_index}) { ${nodes} }`;
block.add_variable(current_block_type_index); block.add_variable(current_block_type_index);
block.add_variable(name); block.add_variable(name);
@ -350,7 +350,7 @@ export default class IfBlockWrapper extends Wrapper {
/* eslint-disable @typescript-eslint/indent,indent */ /* eslint-disable @typescript-eslint/indent,indent */
block.chunks.init.push(b` block.chunks.init.push(b`
const ${if_block_creators} = [ const ${if_block_creators} = [
${this.branches.map(branch => branch.block.name).join(',\n')} ${this.branches.map(branch => branch.block.name)}
]; ];
const ${if_blocks} = []; const ${if_blocks} = [];
@ -393,9 +393,10 @@ export default class IfBlockWrapper extends Wrapper {
const initial_mount_node = parent_node || '#target'; const initial_mount_node = parent_node || '#target';
const anchor_node = parent_node ? 'null' : 'anchor'; const anchor_node = parent_node ? 'null' : 'anchor';
throw new Error(`womp womp`);
block.chunks.mount.push( block.chunks.mount.push(
b`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});` if_current_block_type_index(
b`${if_blocks}[${current_block_type_index}].m(${initial_mount_node}, ${anchor_node});`
)
); );
if (this.needs_update) { if (this.needs_update) {
@ -442,7 +443,7 @@ export default class IfBlockWrapper extends Wrapper {
let ${previous_block_index} = ${current_block_type_index}; let ${previous_block_index} = ${current_block_type_index};
${current_block_type_index} = ${select_block_type}(#changed, #ctx); ${current_block_type_index} = ${select_block_type}(#changed, #ctx);
if (${current_block_type_index} === ${previous_block_index}) { if (${current_block_type_index} === ${previous_block_index}) {
${if_current_block_type_index}${if_blocks}[${current_block_type_index}].p(#changed, #ctx); ${if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].p(#changed, #ctx);`)}
} else { } else {
${change_block} ${change_block}
} }
@ -460,9 +461,9 @@ export default class IfBlockWrapper extends Wrapper {
block.chunks.update.push(b`${name}.p(#changed, #ctx);`); block.chunks.update.push(b`${name}.p(#changed, #ctx);`);
} }
block.chunks.destroy.push(b` block.chunks.destroy.push(
${if_current_block_type_index}${if_blocks}[${current_block_type_index}].d(${detaching}); if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].d(${detaching});`)
`); );
} }
render_simple( render_simple(

@ -3,7 +3,7 @@ import Renderer from '../../Renderer';
import Block from '../../Block'; import Block from '../../Block';
import InlineComponent from '../../../nodes/InlineComponent'; import InlineComponent from '../../../nodes/InlineComponent';
import FragmentWrapper from '../Fragment'; import FragmentWrapper from '../Fragment';
import { quote_name_if_necessary, quote_prop_if_necessary, sanitize } from '../../../../utils/names'; import { quote_name_if_necessary, sanitize } from '../../../../utils/names';
import add_to_set from '../../../utils/add_to_set'; import add_to_set from '../../../utils/add_to_set';
import { b, x } from 'code-red'; import { b, x } from 'code-red';
import Attribute from '../../../nodes/Attribute'; import Attribute from '../../../nodes/Attribute';
@ -15,7 +15,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope';
import is_dynamic from '../shared/is_dynamic'; import is_dynamic from '../shared/is_dynamic';
import bind_this from '../shared/bind_this'; import bind_this from '../shared/bind_this';
import { changed } from '../shared/changed'; import { changed } from '../shared/changed';
import { Node, Identifier } from 'estree'; import { Node, Identifier, Expression } from 'estree';
export default class InlineComponentWrapper extends Wrapper { export default class InlineComponentWrapper extends Wrapper {
var: Identifier; var: Identifier;
@ -124,7 +124,7 @@ export default class InlineComponentWrapper extends Wrapper {
const uses_spread = !!this.node.attributes.find(a => a.is_spread); const uses_spread = !!this.node.attributes.find(a => a.is_spread);
let attribute_object; let attribute_object = x`{}`;
if (this.node.attributes.length > 0 || this.node.bindings.length > 0 || this.slots.size > 0) { if (this.node.attributes.length > 0 || this.node.bindings.length > 0 || this.slots.size > 0) {
if (!uses_spread && this.node.bindings.length === 0) { if (!uses_spread && this.node.bindings.length === 0) {
@ -165,7 +165,7 @@ export default class InlineComponentWrapper extends Wrapper {
value: attr.get_value(block) value: attr.get_value(block)
} }
}).concat(initial_props.properties) }).concat(initial_props.properties)
}; } as Expression;
} }
component_opts.properties.push({ component_opts.properties.push({
@ -175,13 +175,13 @@ export default class InlineComponentWrapper extends Wrapper {
value: attribute_object value: attribute_object
}); });
} else { } else {
props = block.get_unique_name(`${name.name}_props`);
component_opts.properties.push({ component_opts.properties.push({
type: 'Property', type: 'Property',
kind: 'init', kind: 'init',
key: { type: 'Identifier', name: 'props' }, key: { type: 'Identifier', name: 'props' },
value: props value: props
}); });
props = block.get_unique_name(`${name}_props`);
} }
} }
@ -241,7 +241,7 @@ export default class InlineComponentWrapper extends Wrapper {
const { name, dependencies } = attr; const { name, dependencies } = attr;
const condition = dependencies.size > 0 && (dependencies.size !== all_dependencies.size) const condition = dependencies.size > 0 && (dependencies.size !== all_dependencies.size)
? `(${Array.from(dependencies).map(d => `changed.${d}`).join(' || ')})` ? changed(Array.from(dependencies))
: null; : null;
if (attr.is_spread) { if (attr.is_spread) {
@ -254,16 +254,16 @@ export default class InlineComponentWrapper extends Wrapper {
} }
changes.push(condition ? `${condition} && ${value_object}` : value_object); changes.push(condition ? `${condition} && ${value_object}` : value_object);
} else { } else {
const obj = `{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`; const obj = x`{ ${quote_name_if_necessary(name)}: ${attr.get_value(block)} }`;
initial_props.push(obj); initial_props.push(obj);
changes.push(condition ? `${condition} && ${obj}` : `${levels}[${i}]`); changes.push(condition ? x`${condition} && ${obj}` : x`${levels}[${i}]`);
} }
}); });
block.chunks.init.push(b` block.chunks.init.push(b`
const ${levels} = [ const ${levels} = [
${initial_props.join(',\n')} ${initial_props}
]; ];
`); `);
@ -278,7 +278,7 @@ export default class InlineComponentWrapper extends Wrapper {
updates.push(b` updates.push(b`
const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [ const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [
${changes.join(',\n')} ${changes}
]) : {} ]) : {}
`); `);
} else { } else {
@ -293,7 +293,7 @@ export default class InlineComponentWrapper extends Wrapper {
const condition = changed(dependencies); const condition = changed(dependencies);
updates.push(b` updates.push(b`
if (${condition}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)}; if (${condition}) ${name_changes}.${attribute.name} = ${attribute.get_value(block)};
`); `);
} }
}); });
@ -301,7 +301,10 @@ export default class InlineComponentWrapper extends Wrapper {
} }
if (non_let_dependencies.length > 0) { if (non_let_dependencies.length > 0) {
updates.push(b`if (${changed(non_let_dependencies)} ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`); updates.push(b`
if (${changed(non_let_dependencies)}) {
${name_changes}.$$scope = { changed: #changed, ctx: #ctx };
}`);
} }
const munged_bindings = this.node.bindings.map(binding => { const munged_bindings = this.node.bindings.map(binding => {
@ -311,7 +314,7 @@ export default class InlineComponentWrapper extends Wrapper {
return bind_this(component, block, binding, this.var); return bind_this(component, block, binding, this.var);
} }
const id = component.get_unique_name(`${this.var}_${binding.name}_binding`); const id = component.get_unique_name(`${this.var.name}_${binding.name}_binding`);
component.add_var({ component.add_var({
name: id.name, name: id.name,
@ -326,13 +329,13 @@ export default class InlineComponentWrapper extends Wrapper {
statements.push(b` statements.push(b`
if (${snippet} !== void 0) { if (${snippet} !== void 0) {
${props}${quote_prop_if_necessary(binding.name)} = ${snippet}; ${props}.${binding.name} = ${snippet};
}` }`
); );
updates.push(b` updates.push(b`
if (!${updating} && ${[...binding.expression.dependencies].map((dependency: string) => `changed.${dependency}`).join(' || ')}) { if (!${updating} && ${changed(Array.from(binding.expression.dependencies))}) {
${name_changes}${quote_prop_if_necessary(binding.name)} = ${snippet}; ${name_changes}.${binding.name} = ${snippet};
} }
`); `);
@ -353,11 +356,22 @@ export default class InlineComponentWrapper extends Wrapper {
const value = block.get_unique_name('value'); const value = block.get_unique_name('value');
const args: any[] = [value]; const args: any[] = [value];
if (contextual_dependencies.length > 0) { if (contextual_dependencies.length > 0) {
args.push(x`{ ${contextual_dependencies.join(', ')} }`); args.push({
type: 'ObjectPattern',
properties: contextual_dependencies.map(name => {
const id = { type: 'Identifier', name };
return {
type: 'Property',
kind: 'init',
key: id,
value: id
};
})
});
block.chunks.init.push(b` block.chunks.init.push(b`
function ${name}(${value}) { function ${id}(${value}) {
#ctx.${name}.call(null, ${value}, #ctx); #ctx.${id}.call(null, ${value}, #ctx);
${updating} = true; ${updating} = true;
@add_flush_callback(() => ${updating} = false); @add_flush_callback(() => ${updating} = false);
} }
@ -367,7 +381,7 @@ export default class InlineComponentWrapper extends Wrapper {
} else { } else {
block.chunks.init.push(b` block.chunks.init.push(b`
function ${id}(${value}) { function ${id}(${value}) {
#ctx.${name}.call(null, ${value}); #ctx.${id}.call(null, ${value});
${updating} = true; ${updating} = true;
@add_flush_callback(() => ${updating} = false); @add_flush_callback(() => ${updating} = false);
} }
@ -375,7 +389,7 @@ export default class InlineComponentWrapper extends Wrapper {
} }
const body = b` const body = b`
function ${id}(${args.join(', ')}) { function ${id}(${args}) {
${lhs} = ${value}; ${lhs} = ${value};
${component.invalidate(dependencies[0])}; ${component.invalidate(dependencies[0])};
} }
@ -383,7 +397,7 @@ export default class InlineComponentWrapper extends Wrapper {
component.partly_hoisted.push(body); component.partly_hoisted.push(body);
return `@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`; return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`;
}); });
const munged_handlers = this.node.handlers.map(handler => { const munged_handlers = this.node.handlers.map(handler => {

@ -44,7 +44,7 @@ export default function bind_this(component: Component, block: Block, binding: B
if (contextual_dependencies.length) { if (contextual_dependencies.length) {
component.partly_hoisted.push(b` component.partly_hoisted.push(b`
function ${fn}(${['$$value', ...contextual_dependencies].join(', ')}) { function ${fn}(${['$$value', ...contextual_dependencies]}) {
if (${lhs} === $$value) return; if (${lhs} === $$value) return;
@binding_callbacks[$$value ? 'unshift' : 'push'](() => { @binding_callbacks[$$value ? 'unshift' : 'push'](() => {
${body} ${body}
@ -59,12 +59,12 @@ export default function bind_this(component: Component, block: Block, binding: B
block.add_variable(id, x`#ctx.${id}`); block.add_variable(id, x`#ctx.${id}`);
} }
const assign = block.get_unique_name(`assign_${variable}`); const assign = block.get_unique_name(`assign_${variable.name}`);
const unassign = block.get_unique_name(`unassign_${variable}`); const unassign = block.get_unique_name(`unassign_${variable.name}`);
block.chunks.init.push(b` block.chunks.init.push(b`
const ${assign} = () => #ctx.${fn}(${[variable].concat(args).join(', ')}); const ${assign} = () => #ctx.${fn}(${[variable].concat(args)});
const ${unassign} = () => #ctx.${fn}(${['null'].concat(args).join(', ')}); const ${unassign} = () => #ctx.${fn}(${['null'].concat(args)});
`); `);
const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || '); const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || ');
@ -75,7 +75,7 @@ export default function bind_this(component: Component, block: Block, binding: B
block.chunks.update.push(b` block.chunks.update.push(b`
if (${condition}) { if (${condition}) {
${unassign}(); ${unassign}();
${args.map(a => `${a} = #ctx.${a}`).join(', ')}; ${args.map(a => b`${a} = #ctx.${a}`)};
${assign}(); ${assign}();
}` }`
); );

@ -3,7 +3,7 @@ import { Node, Identifier } from 'estree';
export default function flatten_reference(node: Node) { export default function flatten_reference(node: Node) {
// TODO temporary (#3539) // TODO temporary (#3539)
if ((node as any).type === 'Expression') { if ((node as any).type === 'Expression') {
throw new Error('bad'); throw new Error('flatten_reference bad');
} }
const nodes = []; const nodes = [];

@ -1,4 +1,4 @@
export function snip(expression) { export function snip(expression) {
throw new Error(`bad`); throw new Error(`snip bad`);
return `[✂${expression.node.start}-${expression.node.end}✂]`; return `[✂${expression.node.start}-${expression.node.end}✂]`;
} }
Loading…
Cancel
Save