diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index a50e78662f..9618a0d854 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -167,6 +167,10 @@ export default class Renderer { head = x`#ctx[${i}]`; } } else { + if (i === undefined) { + throw new Error(`attempted to reference unknown value`); + } + head = x`#ctx[${i}]`; } diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts index a0859cfced..3f82bfb584 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/index.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts @@ -191,7 +191,7 @@ export default class ElementWrapper extends Wrapper { if (!seen.has(l.name.name)) lets.push(l); }); - const fn = get_context_merger(lets); + const fn = get_context_merger(this.renderer, lets); (owner as unknown as InlineComponentWrapper).slots.set(name, { block: child_block, diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 023f258dd2..b4a2d13d53 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -73,6 +73,10 @@ export default class InlineComponentWrapper extends Wrapper { }; if (this.node.children.length) { + this.node.lets.forEach(l => { + renderer.add_to_context(l.value.name, true); + }); + const default_slot = block.child({ comment: create_debugging_comment(node, renderer.component), name: renderer.component.get_unique_name(`create_default_slot`), @@ -81,7 +85,7 @@ export default class InlineComponentWrapper extends Wrapper { this.renderer.blocks.push(default_slot); - const fn = get_context_merger(this.node.lets); + const fn = get_context_merger(this.renderer, this.node.lets); this.slots.set('default', { block: default_slot, diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index dc0905f076..044eb04583 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -66,7 +66,6 @@ export default class SlotWrapper extends Wrapper { get_slot_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_changes`); get_slot_context_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_context`); - const context = get_slot_data(this.node.values); const changes = x`{}` as ObjectExpression; const dependencies = new Set(); @@ -99,14 +98,9 @@ export default class SlotWrapper extends Wrapper { } }); - const arg = dependencies.size > 0 && { - type: 'ObjectPattern', - properties: Array.from(dependencies).map(name => p`${name}`) - }; - renderer.blocks.push(b` - const ${get_slot_changes_fn} = (${arg}) => (${changes}); - const ${get_slot_context_fn} = (${arg}) => (${context}); + const ${get_slot_changes_fn} = #changes => #changes; + const ${get_slot_context_fn} = #ctx => ${get_slot_data(block, this.node.values)}; `); } else { get_slot_changes_fn = 'null'; 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 8c27e8b503..e6b4d9a420 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,7 +1,8 @@ import Let from '../../../nodes/Let'; -import { x } from 'code-red'; +import { x, p } from 'code-red'; +import Renderer from '../../Renderer'; -export function get_context_merger(lets: Let[]) { +export function get_context_merger(renderer: Renderer, lets: Let[]) { if (lets.length === 0) return null; const input = { @@ -14,7 +15,7 @@ export function get_context_merger(lets: Let[]) { })) }; - const names = new Set(); + const names: Set = new Set(); lets.forEach(l => { l.names.forEach(name => { names.add(name); @@ -23,16 +24,7 @@ export function get_context_merger(lets: Let[]) { const output = { type: 'ObjectExpression', - properties: Array.from(names).map(name => { - const id = { type: 'Identifier', name }; - - return { - type: 'Property', - kind: 'init', - key: id, - value: id - }; - }) + properties: Array.from(names).map(name => p`${renderer.context_lookup.get(name)}: ${name}`) }; return x`(${input}) => (${output})`; diff --git a/src/compiler/compile/utils/get_slot_data.ts b/src/compiler/compile/utils/get_slot_data.ts index 936dc85977..87811684a3 100644 --- a/src/compiler/compile/utils/get_slot_data.ts +++ b/src/compiler/compile/utils/get_slot_data.ts @@ -1,26 +1,27 @@ import Attribute from '../nodes/Attribute'; import { p, x } from 'code-red'; import { string_literal } from './stringify'; +import Block from '../render_dom/Block'; -export default function get_slot_data(values: Map) { +export default function get_slot_data(block: Block, values: Map) { return { type: 'ObjectExpression', properties: Array.from(values.values()) .filter(attribute => attribute.name !== 'name') .map(attribute => { - const value = get_value(attribute); + const value = get_value(block, attribute); return p`${attribute.name}: ${value}`; }) }; } // TODO fairly sure this is duplicated at least once -function get_value(attribute: Attribute) { +function get_value(block: Block, 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) + .map(chunk => chunk.type === 'Text' ? string_literal(chunk.data) : chunk.manipulate(block)) .reduce((lhs, rhs) => x`${lhs} + ${rhs}`); if (attribute.chunks.length > 1 && attribute.chunks[0].type !== 'Text') { diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index f526926229..fab44f80db 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -71,15 +71,15 @@ export function create_slot(definition, ctx, $$scope, fn) { } export function get_slot_context(definition, ctx, $$scope, fn) { - return definition[1] - ? assign({}, assign($$scope.ctx, definition[1](fn ? fn(ctx) : {}))) + return definition[1] && fn + ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx; } export function get_slot_changes(definition, $$scope, changed, fn) { - return definition[1] - ? assign({}, assign($$scope.changed || {}, definition[1](fn ? fn(changed) : {}))) - : $$scope.changed || {}; + return definition[1] && fn + ? $$scope.changed | definition[1](fn(changed)) + : $$scope.changed; } export function exclude_internal_props(props) {