From 46e655915365794fa108c4a2d8397394849e06ac Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 9 Dec 2019 16:19:18 -0500 Subject: [PATCH] handle slot updates when parent component has a bitmask overflow --- .../wrappers/shared/get_slot_definition.ts | 69 +++++++++++++++---- src/runtime/internal/utils.ts | 12 +++- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/compiler/compile/render_dom/wrappers/shared/get_slot_definition.ts b/src/compiler/compile/render_dom/wrappers/shared/get_slot_definition.ts index 24ca813684..44fc980c9d 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/get_slot_definition.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/get_slot_definition.ts @@ -2,6 +2,7 @@ import Let from '../../../nodes/Let'; import { x, p } from 'code-red'; import Block from '../../Block'; import TemplateScope from '../../../nodes/shared/TemplateScope'; +import { BinaryExpression } from 'estree'; export function get_slot_definition(block: Block, scope: TemplateScope, lets: Let[]) { if (lets.length === 0) return { block, scope }; @@ -28,21 +29,65 @@ export function get_slot_definition(block: Block, scope: TemplateScope, lets: Le properties: Array.from(names).map(name => p`${block.renderer.context_lookup.get(name).index}: ${name}`) }; - const changes = Array.from(names) - .map(name => { - const { context_lookup } = block.renderer; + const { context_lookup } = block.renderer; - const literal = { - type: 'Literal', - get value() { + let expression; + + // i am well aware that this code is gross + // TODO make it less gross + const changes = { + get type() { + if (block.renderer.context_overflow) return 'ArrayExpression'; + + expression = Array.from(names) + .map(name => { const i = context_lookup.get(name).index.value as number; - return 1 << i; - } - }; + return x`${name} ? ${1 << i} : 0`; + }) + .reduce((lhs, rhs) => x`${lhs} | ${rhs}`) as BinaryExpression; + + return expression.type; + }, + get elements() { + const grouped = []; + + Array.from(names).forEach(name => { + const i = context_lookup.get(name).index.value as number; + const g = Math.floor(i / 31); - return x`${name} ? ${literal} : 0`; - }) - .reduce((lhs, rhs) => x`${lhs} | ${rhs}`); + if (!grouped[g]) grouped[g] = []; + grouped[g].push({ name, n: i % 31 }); + }); + + const elements = []; + + for (let g = 0; g < grouped.length; g += 1) { + elements[g] = grouped[g] + ? grouped[g] + .map(({ name, n }) => x`${name} ? ${1 << n} : 0`) + .reduce((lhs, rhs) => x`${lhs} | ${rhs}`) + : x`0`; + } + + return elements; + }, + get test() { + return expression.test; + }, + get consequent() { + return expression.consequent; + }, + get alternate() { + return expression.alternate; + }, + get left() { + return expression.left; + }, + get right() { + return expression.right; + }, + operator: '|' + }; return { block, diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 7e8769cd88..fb2554ad78 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -77,9 +77,15 @@ export function get_slot_context(definition, ctx, $$scope, fn) { } export function get_slot_changes(definition, $$scope, dirty, fn) { - return definition[2] && fn - ? $$scope.dirty | definition[2](fn(dirty)) - : $$scope.dirty; + if (definition[2] && fn) { + const lets = definition[2](fn(dirty)); + + return typeof $$scope.dirty === 'object' + ? $$scope.dirty.map((n, i) => n | lets[i]) + : $$scope.dirty | lets; + } + + return $$scope.dirty; } export function exclude_internal_props(props) {