From 8ba809ded14de725dd58ca0b14cc51ba360efb5d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 16 May 2018 00:07:06 -0400 Subject: [PATCH] add snapshot test --- .../expected-bundle.js | 589 ++++++++++++++++++ .../each-block-keyed-animated/expected.js | 131 ++++ .../each-block-keyed-animated/input.html | 23 + 3 files changed, 743 insertions(+) create mode 100644 test/js/samples/each-block-keyed-animated/expected-bundle.js create mode 100644 test/js/samples/each-block-keyed-animated/expected.js create mode 100644 test/js/samples/each-block-keyed-animated/input.html diff --git a/test/js/samples/each-block-keyed-animated/expected-bundle.js b/test/js/samples/each-block-keyed-animated/expected-bundle.js new file mode 100644 index 0000000000..54876c6152 --- /dev/null +++ b/test/js/samples/each-block-keyed-animated/expected-bundle.js @@ -0,0 +1,589 @@ +function noop() {} + +function assign(tar, src) { + for (var k in src) tar[k] = src[k]; + return tar; +} + +function appendNode(node, target) { + target.appendChild(node); +} + +function insertNode(node, target, anchor) { + target.insertBefore(node, anchor); +} + +function detachNode(node) { + node.parentNode.removeChild(node); +} + +function createElement(name) { + return document.createElement(name); +} + +function createText(data) { + return document.createTextNode(data); +} + +function createComment() { + return document.createComment(''); +} + +function linear(t) { + return t; +} + +function generateRule({ a, b, delta, duration }, ease, fn) { + const step = 16.666 / duration; + let keyframes = '{\n'; + + for (let p = 0; p <= 1; p += step) { + const t = a + delta * ease(p); + keyframes += p * 100 + `%{${fn(t, 1 - t)}}\n`; + } + + return keyframes + `100% {${fn(b, 1 - b)}}\n}`; +} + +// https://github.com/darkskyapp/string-hash/blob/master/index.js +function hash(str) { + let hash = 5381; + let i = str.length; + + while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i); + return hash >>> 0; +} + +var transitionManager = { + running: false, + transitions: [], + bound: null, + stylesheet: null, + activeRules: {}, + promise: null, + + add(transition) { + this.transitions.push(transition); + + if (!this.running) { + this.running = true; + requestAnimationFrame(this.bound || (this.bound = this.next.bind(this))); + } + }, + + addRule(rule, name) { + if (!this.stylesheet) { + const style = createElement('style'); + document.head.appendChild(style); + transitionManager.stylesheet = style.sheet; + } + + if (!this.activeRules[name]) { + this.activeRules[name] = true; + this.stylesheet.insertRule(`@keyframes ${name} ${rule}`, this.stylesheet.cssRules.length); + } + }, + + next() { + this.running = false; + + const now = window.performance.now(); + let i = this.transitions.length; + + while (i--) { + const transition = this.transitions[i]; + + if (transition.program && now >= transition.program.end) { + transition.done(); + } + + if (transition.pending && now >= transition.pending.start) { + transition.start(transition.pending); + } + + if (transition.running) { + transition.update(now); + this.running = true; + } else if (!transition.pending) { + this.transitions.splice(i, 1); + } + } + + if (this.running) { + requestAnimationFrame(this.bound); + } else if (this.stylesheet) { + let i = this.stylesheet.cssRules.length; + while (i--) this.stylesheet.deleteRule(i); + this.activeRules = {}; + } + }, + + deleteRule(node, name) { + node.style.animation = node.style.animation + .split(', ') + .filter(anim => anim && anim.indexOf(name) === -1) + .join(', '); + }, + + groupOutros() { + this.outros = { + remaining: 0, + callbacks: [] + }; + }, + + wait() { + if (!transitionManager.promise) { + transitionManager.promise = Promise.resolve(); + transitionManager.promise.then(() => { + transitionManager.promise = null; + }); + } + + return transitionManager.promise; + } +}; + +function wrapAnimation(node, from, fn, params) { + if (!from) return; + + const to = node.getBoundingClientRect(); + if (from.left === to.left && from.right === to.right && from.top === to.top && from.bottom === to.bottom) return; + + const info = fn(node, { from, to }, params); + + const duration = 'duration' in info ? info.duration : 300; + const delay = 'delay' in info ? info.delay : 0; + const ease = info.easing || linear; + const start = window.performance.now() + delay; + const end = start + duration; + + const program = { + a: 0, + t: 0, + b: 1, + delta: 1, + duration, + start, + end + }; + + const cssText = node.style.cssText; + + const animation = { + pending: delay ? program : null, + program: delay ? null : program, + running: true, + + start() { + if (info.css) { + if (delay) node.style.cssText = cssText; + + const rule = generateRule(program, ease, info.css); + program.name = `__svelte_${hash(rule)}`; + + transitionManager.addRule(rule, program.name); + + node.style.animation = (node.style.animation || '') + .split(', ') + .filter(anim => anim && (program.delta < 0 || !/__svelte/.test(anim))) + .concat(`${program.name} ${program.duration}ms linear 1 forwards`) + .join(', '); + } + + animation.program = program; + animation.pending = null; + }, + + update: now => { + const p = now - program.start; + const t = program.a + program.delta * ease(p / program.duration); + if (info.tick) info.tick(t, 1 - t); + }, + + done() { + if (info.tick) info.tick(1, 0); + animation.stop(); + }, + + stop() { + if (info.css) transitionManager.deleteRule(node, program.name); + animation.running = false; + } + }; + + transitionManager.add(animation); + + if (info.tick) info.tick(0, 1); + + if (delay) { + if (info.css) node.style.cssText += info.css(0, 1); + } else { + animation.start(); + } + + return animation; +} + +function fixPosition(node) { + const style = getComputedStyle(node); + + if (style.position !== 'absolute' && style.position !== 'fixed') { + const { width, height } = style; + const a = node.getBoundingClientRect(); + node.style.position = 'absolute'; + node.style.width = width; + node.style.height = height; + const b = node.getBoundingClientRect(); + + if (a.left !== b.left || a.top !== b.top) { + const style = getComputedStyle(node); + const transform = style.transform === 'none' ? '' : style.transform; + + node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`; + } + } +} + +function destroyBlock(block, lookup) { + block.d(1); + lookup[block.key] = null; +} + +function outroAndDestroyBlock(block, lookup) { + block.o(function() { + destroyBlock(block, lookup); + }); +} + +function fixAndOutroAndDestroyBlock(block, lookup) { + block.f(); + outroAndDestroyBlock(block, lookup); +} + +function updateKeyedEach(old_blocks, component, changed, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block, intro_method, next, get_context) { + var o = old_blocks.length; + var n = list.length; + + var i = o; + var old_indexes = {}; + while (i--) old_indexes[old_blocks[i].key] = i; + + var new_blocks = []; + var new_lookup = {}; + var deltas = {}; + + var i = n; + while (i--) { + var child_ctx = get_context(ctx, list, i); + var key = get_key(child_ctx); + var block = lookup[key]; + + if (!block) { + block = create_each_block(component, key, child_ctx); + block.c(); + } else if (dynamic) { + block.p(changed, child_ctx); + } + + new_blocks[i] = new_lookup[key] = block; + + if (key in old_indexes) deltas[key] = Math.abs(i - old_indexes[key]); + } + + var will_move = {}; + var did_move = {}; + + function insert(block) { + block[intro_method](node, next); + lookup[block.key] = block; + next = block.first; + n--; + } + + while (o && n) { + var new_block = new_blocks[n - 1]; + var old_block = old_blocks[o - 1]; + var new_key = new_block.key; + var old_key = old_block.key; + + if (new_block === old_block) { + // do nothing + next = new_block.first; + o--; + n--; + } + + else if (!new_lookup[old_key]) { + // remove old block + destroy(old_block, lookup); + o--; + } + + else if (!lookup[new_key] || will_move[new_key]) { + insert(new_block); + } + + else if (did_move[old_key]) { + o--; + + } else if (deltas[new_key] > deltas[old_key]) { + did_move[new_key] = true; + insert(new_block); + + } else { + will_move[old_key] = true; + o--; + } + } + + while (o--) { + var old_block = old_blocks[o]; + if (!new_lookup[old_block.key]) destroy(old_block, lookup); + } + + while (n) insert(new_blocks[n - 1]); + + return new_blocks; +} + +function blankObject() { + return Object.create(null); +} + +function destroy(detach) { + this.destroy = noop; + this.fire('destroy'); + this.set = noop; + + this._fragment.d(detach !== false); + this._fragment = null; + this._state = {}; +} + +function _differs(a, b) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +function fire(eventName, data) { + var handlers = + eventName in this._handlers && this._handlers[eventName].slice(); + if (!handlers) return; + + for (var i = 0; i < handlers.length; i += 1) { + var handler = handlers[i]; + + if (!handler.__calling) { + handler.__calling = true; + handler.call(this, data); + handler.__calling = false; + } + } +} + +function get() { + return this._state; +} + +function init(component, options) { + component._handlers = blankObject(); + component._bind = options._bind; + + component.options = options; + component.root = options.root || component; + component.store = component.root.store || options.store; +} + +function on(eventName, handler) { + var handlers = this._handlers[eventName] || (this._handlers[eventName] = []); + handlers.push(handler); + + return { + cancel: function() { + var index = handlers.indexOf(handler); + if (~index) handlers.splice(index, 1); + } + }; +} + +function set(newState) { + this._set(assign({}, newState)); + if (this.root._lock) return; + this.root._lock = true; + callAll(this.root._beforecreate); + callAll(this.root._oncreate); + callAll(this.root._aftercreate); + this.root._lock = false; +} + +function _set(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (this._differs(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign(assign({}, oldState), newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + this.fire("state", { changed: changed, current: this._state, previous: oldState }); + this._fragment.p(changed, this._state); + this.fire("update", { changed: changed, current: this._state, previous: oldState }); + } +} + +function callAll(fns) { + while (fns && fns.length) fns.shift()(); +} + +function _mount(target, anchor) { + this._fragment[this._fragment.i ? 'i' : 'm'](target, anchor || null); +} + +var proto = { + destroy, + get, + fire, + on, + set, + _recompute: noop, + _set, + _mount, + _differs +}; + +/* generated by Svelte vX.Y.Z */ + +function foo(node, animation, params) { + const dx = animation.from.left - animation.to.left; + const dy = animation.from.top - animation.to.top; + + return { + delay: params.delay, + duration: 100, + tick: (t, u) => { + node.dx = u * dx; + node.dy = u * dy; + } + }; +} +function create_main_fragment(component, ctx) { + var each_blocks_1 = [], each_lookup = blankObject(), each_anchor; + + var each_value = ctx.things; + + const get_key = ctx => ctx.thing.id; + + for (var i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context(ctx, each_value, i); + let key = get_key(child_ctx); + each_blocks_1[i] = each_lookup[key] = create_each_block(component, key, child_ctx); + } + + return { + c() { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].c(); + + each_anchor = createComment(); + }, + + m(target, anchor) { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].m(target, anchor); + + insertNode(each_anchor, target, anchor); + }, + + p(changed, ctx) { + const each_value = ctx.things; + for (let i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].r(); + each_blocks_1 = updateKeyedEach(each_blocks_1, component, changed, get_key, 1, ctx, each_value, each_lookup, each_anchor.parentNode, fixAndOutroAndDestroyBlock, create_each_block, "m", each_anchor, get_each_context); + for (let i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].a(); + }, + + d(detach) { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].d(detach); + + if (detach) { + detachNode(each_anchor); + } + } + }; +} + +// (1:0) {#each things as thing (thing.id)} +function create_each_block(component, key_1, ctx) { + var div, text_value = ctx.thing.name, text, rect, animation; + + return { + key: key_1, + + first: null, + + c() { + div = createElement("div"); + text = createText(text_value); + this.first = div; + }, + + m(target, anchor) { + insertNode(div, target, anchor); + appendNode(text, div); + }, + + p(changed, ctx) { + if ((changed.things) && text_value !== (text_value = ctx.thing.name)) { + text.data = text_value; + } + }, + + r() { + rect = div.getBoundingClientRect(); + }, + + f() { + fixPosition(div); + if (animation) animation.stop(); + }, + + a() { + if (animation) animation.stop(); + animation = wrapAnimation(div, rect, foo, {}); + }, + + d(detach) { + if (detach) { + detachNode(div); + } + } + }; +} + +function get_each_context(ctx, list, i) { + const child_ctx = Object.create(ctx); + child_ctx.thing = list[i]; + child_ctx.each_value = list; + child_ctx.thing_index = i; + return child_ctx; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + this._intro = true; + + this._fragment = create_main_fragment(this, this._state); + + if (options.target) { + this._fragment.c(); + this._mount(options.target, options.anchor); + } +} + +assign(SvelteComponent.prototype, proto); + +export default SvelteComponent; diff --git a/test/js/samples/each-block-keyed-animated/expected.js b/test/js/samples/each-block-keyed-animated/expected.js new file mode 100644 index 0000000000..99ff9b03fe --- /dev/null +++ b/test/js/samples/each-block-keyed-animated/expected.js @@ -0,0 +1,131 @@ +/* generated by Svelte vX.Y.Z */ +import { appendNode, assign, blankObject, createComment, createElement, createText, detachNode, fixAndOutroAndDestroyBlock, fixPosition, init, insertNode, proto, updateKeyedEach, wrapAnimation } from "svelte/shared.js"; + +function foo(node, animation, params) { + const dx = animation.from.left - animation.to.left; + const dy = animation.from.top - animation.to.top; + + return { + delay: params.delay, + duration: 100, + tick: (t, u) => { + node.dx = u * dx; + node.dy = u * dy; + } + }; +}; + +function create_main_fragment(component, ctx) { + var each_blocks_1 = [], each_lookup = blankObject(), each_anchor; + + var each_value = ctx.things; + + const get_key = ctx => ctx.thing.id; + + for (var i = 0; i < each_value.length; i += 1) { + let child_ctx = get_each_context(ctx, each_value, i); + let key = get_key(child_ctx); + each_blocks_1[i] = each_lookup[key] = create_each_block(component, key, child_ctx); + } + + return { + c() { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].c(); + + each_anchor = createComment(); + }, + + m(target, anchor) { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].m(target, anchor); + + insertNode(each_anchor, target, anchor); + }, + + p(changed, ctx) { + const each_value = ctx.things; + for (let i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].r(); + each_blocks_1 = updateKeyedEach(each_blocks_1, component, changed, get_key, 1, ctx, each_value, each_lookup, each_anchor.parentNode, fixAndOutroAndDestroyBlock, create_each_block, "m", each_anchor, get_each_context); + for (let i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].a(); + }, + + d(detach) { + for (i = 0; i < each_blocks_1.length; i += 1) each_blocks_1[i].d(detach); + + if (detach) { + detachNode(each_anchor); + } + } + }; +} + +// (1:0) {#each things as thing (thing.id)} +function create_each_block(component, key_1, ctx) { + var div, text_value = ctx.thing.name, text, rect, animation; + + return { + key: key_1, + + first: null, + + c() { + div = createElement("div"); + text = createText(text_value); + this.first = div; + }, + + m(target, anchor) { + insertNode(div, target, anchor); + appendNode(text, div); + }, + + p(changed, ctx) { + if ((changed.things) && text_value !== (text_value = ctx.thing.name)) { + text.data = text_value; + } + }, + + r() { + rect = div.getBoundingClientRect(); + }, + + f() { + fixPosition(div); + if (animation) animation.stop(); + }, + + a() { + if (animation) animation.stop(); + animation = wrapAnimation(div, rect, foo, {}); + }, + + d(detach) { + if (detach) { + detachNode(div); + } + } + }; +} + +function get_each_context(ctx, list, i) { + const child_ctx = Object.create(ctx); + child_ctx.thing = list[i]; + child_ctx.each_value = list; + child_ctx.thing_index = i; + return child_ctx; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign({}, options.data); + this._intro = true; + + this._fragment = create_main_fragment(this, this._state); + + if (options.target) { + this._fragment.c(); + this._mount(options.target, options.anchor); + } +} + +assign(SvelteComponent.prototype, proto); +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/each-block-keyed-animated/input.html b/test/js/samples/each-block-keyed-animated/input.html new file mode 100644 index 0000000000..8c2e2f872b --- /dev/null +++ b/test/js/samples/each-block-keyed-animated/input.html @@ -0,0 +1,23 @@ +{#each things as thing (thing.id)} +
{thing.name}
+{/each} + + \ No newline at end of file