From 9e1bc908d324b7ff35f1c0e7848a5de9ebfd43d7 Mon Sep 17 00:00:00 2001 From: Richard Harris Date: Sun, 15 Sep 2019 00:08:56 -0400 Subject: [PATCH] ... --- src/compiler/compile/nodes/Element.ts | 2 +- src/compiler/compile/nodes/InlineComponent.ts | 2 +- src/compiler/compile/nodes/Let.ts | 11 ++-- src/compiler/compile/render_dom/index.ts | 14 ++--- .../wrappers/InlineComponent/index.ts | 2 +- .../compile/render_dom/wrappers/Slot.ts | 26 +++++---- .../wrappers/shared/get_context_merger.ts | 29 ++++++++-- .../compile/render_ssr/handlers/Slot.ts | 4 +- src/compiler/compile/utils/get_slot_data.ts | 54 +++++++++++++------ 9 files changed, 98 insertions(+), 46 deletions(-) diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 593f303a2f..2981741fa0 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -201,7 +201,7 @@ export default class Element extends Node { this.scope = scope.child(); this.lets.forEach(l => { - const dependencies = new Set([l.name]); + const dependencies = new Set([l.name.name]); l.names.forEach(name => { this.scope.add(name, dependencies, this); diff --git a/src/compiler/compile/nodes/InlineComponent.ts b/src/compiler/compile/nodes/InlineComponent.ts index 6db6f1b327..0bd1c9a6a7 100644 --- a/src/compiler/compile/nodes/InlineComponent.ts +++ b/src/compiler/compile/nodes/InlineComponent.ts @@ -90,7 +90,7 @@ export default class InlineComponent extends Node { this.scope = scope.child(); this.lets.forEach(l => { - const dependencies = new Set([l.name]); + const dependencies = new Set([l.name.name]); l.names.forEach(name => { this.scope.add(name, dependencies, this); diff --git a/src/compiler/compile/nodes/Let.ts b/src/compiler/compile/nodes/Let.ts index 8401d277eb..1e8014285a 100644 --- a/src/compiler/compile/nodes/Let.ts +++ b/src/compiler/compile/nodes/Let.ts @@ -1,20 +1,21 @@ import Node from './shared/Node'; import Component from '../Component'; import { walk } from 'estree-walker'; +import { Identifier } from 'estree'; const applicable = new Set(['Identifier', 'ObjectExpression', 'ArrayExpression', 'Property']); export default class Let extends Node { type: 'Let'; - name: string; - value: string; + name: Identifier; + value: Identifier; names: string[] = []; constructor(component: Component, parent, scope, info) { super(component, parent, scope, info); - this.name = info.name; - this.value = info.expression && `[✂${info.expression.start}-${info.expression.end}✂]`; + this.name = { type: 'Identifier', name: info.name }; + this.value = info.expression.node; if (info.expression) { walk(info.expression, { @@ -32,7 +33,7 @@ export default class Let extends Node { } }); } else { - this.names.push(this.name); + this.names.push(this.name.name); } } } \ No newline at end of file diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index ac9d33f95a..066a30563e 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -244,9 +244,9 @@ export default function dom( }); } - const args = ['$$self']; + const args = [x`$$self`]; if (props.length > 0 || component.has_reactive_assignments || component.slots.size > 0) { - args.push('$$props', '$$invalidate'); + args.push(x`$$props`, x`$$invalidate`); } body.push(b` @@ -355,10 +355,10 @@ export default function dom( const store = component.var_lookup.get(name); if (store && store.reassigned) { - return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => ($$unsubscribe_${name}(), $$unsubscribe_${name} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; + return b`let ${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => ($$unsubscribe_${name}(), $$unsubscribe_${name} = @subscribe(${name}, $$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }), ${name})`; } - return $name; + return b`let ${$name};`; }); let unknown_props_check; @@ -389,8 +389,8 @@ export default function dom( }; body.push(b` - function ${definition}(${args.join(', ')}) { - ${reactive_store_declarations.length > 0 && `let ${reactive_store_declarations.join(', ')};`} + function ${definition}(${args}) { + ${reactive_store_declarations} ${reactive_store_subscriptions} @@ -400,7 +400,7 @@ export default function dom( ${unknown_props_check} - ${component.slots.size && x`let { $$slots = {}, $$scope } = $$props;`} + ${component.slots.size && b`let { $$slots = {}, $$scope } = $$props;`} ${renderer.binding_groups.length > 0 && `const $$binding_groups = [${renderer.binding_groups.map(_ => `[]`).join(', ')}];`} diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 188e62f787..5031bb8cde 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -19,7 +19,7 @@ import { Node, Identifier, Expression } from 'estree'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; - slots: Map = new Map(); + slots: Map = new Map(); node: InlineComponent; fragment: FragmentWrapper; diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index db53685be0..f903e5cd2e 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -3,14 +3,13 @@ import Renderer from '../Renderer'; import Block from '../Block'; import Slot from '../../nodes/Slot'; import FragmentWrapper from './Fragment'; -import { b } from 'code-red'; +import { b, p, x } from 'code-red'; import { sanitize } from '../../../utils/names'; import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; -import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; import is_dynamic from './shared/is_dynamic'; -import { Identifier } from 'estree'; +import { Identifier, ObjectExpression } from 'estree'; import { changed } from './shared/changed'; export default class SlotWrapper extends Wrapper { @@ -67,8 +66,8 @@ export default class SlotWrapper extends Wrapper { get_slot_changes = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_changes`); get_slot_context = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_context`); - const context_props = get_slot_data(this.node.values, false); - const changes_props = []; + const context = get_slot_data(this.node.values, false); + const changes = x`{}` as ObjectExpression; const dependencies = new Set(); @@ -92,15 +91,22 @@ export default class SlotWrapper extends Wrapper { }); if (dynamic_dependencies.length > 0) { - changes_props.push(`${attribute.name}: ${dynamic_dependencies.join(' || ')}`); + const expression = dynamic_dependencies + .map(name => ({ type: 'Identifier', name } as any)) + .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); + + changes.properties.push(p`${attribute.name}: ${expression}`); } }); - const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : ''; + const arg = dependencies.size > 0 && { + type: 'ObjectPattern', + properties: Array.from(dependencies).map(name => p`${name}`) + }; renderer.blocks.push(b` - const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_props)}); - const ${get_slot_context} = (${arg}) => (${stringify_props(context_props)}); + const ${get_slot_changes} = (${arg}) => (${changes}); + const ${get_slot_context} = (${arg}) => (${context}); `); } else { get_slot_changes = 'null'; @@ -167,7 +173,7 @@ export default class SlotWrapper extends Wrapper { block.chunks.update.push(b` if (${slot} && ${slot}.p && ${changed(dynamic_dependencies)}) { ${slot}.p( - @get_slot_changes(${slot_definition}, #ctx, changed, ${get_slot_changes}), + @get_slot_changes(${slot_definition}, #ctx, #changed, ${get_slot_changes}), @get_slot_context(${slot_definition}, #ctx, ${get_slot_context}) ); } diff --git a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts index fafdd28951..eeec593847 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/get_context_merger.ts @@ -1,9 +1,20 @@ import Let from '../../../nodes/Let'; +import { x } from 'code-red'; export function get_context_merger(lets: Let[]) { if (lets.length === 0) return null; - const input = lets.map(l => l.value ? `${l.name}: ${l.value}` : l.name).join(', '); + console.log(lets); + + const input = { + type: 'ObjectPattern', + properties: lets.map(l => ({ + type: 'Property', + kind: 'init', + key: l.name, + value: l.value || l.name + })) + }; const names = new Set(); lets.forEach(l => { @@ -12,7 +23,19 @@ export function get_context_merger(lets: Let[]) { }); }); - const output = Array.from(names).join(', '); + const output = { + type: 'ObjectExpression', + properties: Array.from(names).map(name => { + const id = { type: 'Identifier', name }; + + return { + type: 'Property', + kind: 'init', + key: id, + value: id + }; + }) + }; - return `({ ${input} }) => ({ ${output} })`; + return x`(${input}) => (${output})`; } \ No newline at end of file diff --git a/src/compiler/compile/render_ssr/handlers/Slot.ts b/src/compiler/compile/render_ssr/handlers/Slot.ts index ef0699ee80..9eec56b359 100644 --- a/src/compiler/compile/render_ssr/handlers/Slot.ts +++ b/src/compiler/compile/render_ssr/handlers/Slot.ts @@ -8,9 +8,7 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions) const slot_data = get_slot_data(node.values, true); - const arg = slot_data.length > 0 ? `{ ${slot_data.join(', ')} }` : '{}'; - - renderer.append(`\${$$slots${prop} ? $$slots${prop}(${arg}) : \``); + renderer.append(`\${$$slots${prop} ? $$slots${prop}(${slot_data}) : \``); renderer.render(node.children, options); diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index ee64d8f1a0..cb42cece7e 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -1,19 +1,43 @@ -import { snip } from './snip'; -import { stringify_attribute } from './stringify_attribute'; import Attribute from '../nodes/Attribute'; +import { p, x } from 'code-red'; +import { string_literal } from './stringify'; export default function get_slot_data(values: Map, is_ssr: boolean) { - return Array.from(values.values()) - .filter(attribute => attribute.name !== 'name') - .map(attribute => { - const value = attribute.is_true - ? 'true' - : attribute.chunks.length === 0 - ? '""' - : attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' - ? snip(attribute.chunks[0]) - : '`' + stringify_attribute(attribute, is_ssr) + '`'; - - return `${attribute.name}: ${value}`; - }); + return { + type: 'ObjectExpression', + properties: Array.from(values.values()) + .filter(attribute => attribute.name !== 'name') + .map(attribute => { + if (is_ssr) { + throw new Error(`TODO SSR`); + } + + const value = get_value(attribute); + + // const value = attribute.is_true + // ? x`true` + // : attribute.chunks.length === 0 + // ? x`""` + // : attribute.chunks.length === 1 && attribute.chunks[0].type !== 'Text' + // ? snip(attribute.chunks[0]) + // : '`' + stringify_attribute(attribute, is_ssr) + '`'; + + return p`${attribute.name}: ${value}`; + }) + } +} + +function get_value(attribute: Attribute) { + if (attribute.is_true) return x`true`; + if (attribute.chunks.length === 0) return x`""`; + + let value = attribute.chunks + .map(chunk => chunk.type === 'Text' ? string_literal(chunk.data) : chunk.node) + .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); + + if (attribute.chunks.length > 1 && attribute.chunks[0].type !== 'Text') { + value = x`"" + ${value}`; + } + + return value; } \ No newline at end of file