UNPKG

neverland-bench

Version:
1,748 lines (1,434 loc) 64.4 kB
var neverland = (function (exports) { 'use strict'; /*! (c) Andrea Giammarchi - ISC */ var self = null || /* istanbul ignore next */ {}; try { self.WeakMap = WeakMap; } catch (WeakMap) { // this could be better but 90% of the time // it's everything developers need as fallback self.WeakMap = function (id, Object) { var dP = Object.defineProperty; var hOP = Object.hasOwnProperty; var proto = WeakMap.prototype; proto["delete"] = function (key) { return this.has(key) && delete key[this._]; }; proto.get = function (key) { return this.has(key) ? key[this._] : void 0; }; proto.has = function (key) { return hOP.call(key, this._); }; proto.set = function (key, value) { dP(key, this._, { configurable: true, value: value }); return this; }; return WeakMap; function WeakMap(iterable) { dP(this, '_', { value: '_@ungap/weakmap' + id++ }); if (iterable) iterable.forEach(add, this); } function add(pair) { this.set(pair[0], pair[1]); } }(Math.random(), Object); } var WeakMap$1 = self.WeakMap; var isNoOp = (typeof document === "undefined" ? "undefined" : typeof(document)) !== 'object'; var _templateLiteral = function templateLiteral(tl) { var RAW = 'raw'; var isBroken = function isBroken(UA) { return /(Firefox|Safari)\/(\d+)/.test(UA) && !/(Chrom[eium]+|Android)\/(\d+)/.test(UA); }; var broken = isBroken((document.defaultView.navigator || {}).userAgent); var FTS = !(RAW in tl) || tl.propertyIsEnumerable(RAW) || !Object.isFrozen(tl[RAW]); if (broken || FTS) { var forever = {}; var foreverCache = function foreverCache(tl) { for (var key = '.', i = 0; i < tl.length; i++) { key += tl[i].length + '.' + tl[i]; } return forever[key] || (forever[key] = tl); }; // Fallback TypeScript shenanigans if (FTS) _templateLiteral = foreverCache; // try fast path for other browsers: // store the template as WeakMap key // and forever cache it only when it's not there. // this way performance is still optimal, // penalized only when there are GC issues else { var wm = new WeakMap$1(); var set = function set(tl, unique) { wm.set(tl, unique); return unique; }; _templateLiteral = function templateLiteral(tl) { return wm.get(tl) || set(tl, foreverCache(tl)); }; } } else { isNoOp = true; } return TL(tl); }; function TL(tl) { return isNoOp ? tl : _templateLiteral(tl); } function tta (template) { var length = arguments.length; var args = [TL(template)]; var i = 1; while (i < length) { args.push(arguments[i++]); } return args; } /*! (c) Andrea Giammarchi - ISC */ var self$1 = null || /* istanbul ignore next */ {}; self$1.CustomEvent = typeof CustomEvent === 'function' ? CustomEvent : function (__p__) { CustomEvent[__p__] = new CustomEvent('').constructor[__p__]; return CustomEvent; function CustomEvent(type, init) { if (!init) init = {}; var e = document.createEvent('CustomEvent'); e.initCustomEvent(type, !!init.bubbles, !!init.cancelable, init.detail); return e; } }('prototype'); var CustomEvent$1 = self$1.CustomEvent; /*! (c) Andrea Giammarchi - ISC */ var self$2 = null || /* istanbul ignore next */ {}; try { self$2.WeakSet = WeakSet; } catch (WeakSet) { // requires a global WeakMap (IE11+) (function (WeakMap) { var all = new WeakMap(); var proto = WeakSet.prototype; proto.add = function (value) { return all.get(this).set(value, 1), this; }; proto["delete"] = function (value) { return all.get(this)["delete"](value); }; proto.has = function (value) { return all.get(this).has(value); }; self$2.WeakSet = WeakSet; function WeakSet(iterable) { all.set(this, new WeakMap()); if (iterable) iterable.forEach(this.add, this); } })(WeakMap); } var WeakSet$1 = self$2.WeakSet; /*! (c) Andrea Giammarchi */ function disconnected(poly) { var Event = poly.Event; var WeakSet = poly.WeakSet; var notObserving = true; var observer = null; return function observe(node) { if (notObserving) { notObserving = !notObserving; observer = new WeakSet(); startObserving(node.ownerDocument); } observer.add(node); return node; }; function startObserving(document) { var connected = new WeakSet(); var disconnected = new WeakSet(); try { new MutationObserver(changes).observe(document, { subtree: true, childList: true }); } catch (o_O) { var timer = 0; var records = []; var reschedule = function reschedule(record) { records.push(record); clearTimeout(timer); timer = setTimeout(function () { changes(records.splice(timer = 0, records.length)); }, 0); }; document.addEventListener('DOMNodeRemoved', function (event) { reschedule({ addedNodes: [], removedNodes: [event.target] }); }, true); document.addEventListener('DOMNodeInserted', function (event) { reschedule({ addedNodes: [event.target], removedNodes: [] }); }, true); } function changes(records) { for (var record, length = records.length, i = 0; i < length; i++) { record = records[i]; dispatchAll(record.removedNodes, 'disconnected', disconnected, connected); dispatchAll(record.addedNodes, 'connected', connected, disconnected); } } function dispatchAll(nodes, type, wsin, wsout) { for (var node, event = new Event(type), length = nodes.length, i = 0; i < length; (node = nodes[i++]).nodeType === 1 && dispatchTarget(node, event, type, wsin, wsout)) { } } function dispatchTarget(node, event, type, wsin, wsout) { if (observer.has(node) && !wsin.has(node)) { wsout["delete"](node); wsin.add(node); node.dispatchEvent(event); /* // The event is not bubbling (perf reason: should it?), // hence there's no way to know if // stop/Immediate/Propagation() was called. // Should DOM Level 0 work at all? // I say it's a YAGNI case for the time being, // and easy to implement in user-land. if (!event.cancelBubble) { var fn = node['on' + type]; if (fn) fn.call(node, event); } */ } for (var // apparently is node.children || IE11 ... ^_^;; // https://github.com/WebReflection/disconnected/issues/1 children = node.children || [], length = children.length, i = 0; i < length; dispatchTarget(children[i++], event, type, wsin, wsout)) { } } } } /*! (c) Andrea Giammarchi - ISC */ var curr = null; var augmentor = function augmentor(fn) { var stack = []; return function hook() { var prev = curr; var after = []; curr = { hook: hook, args: arguments, stack: stack, i: 0, after: after }; try { return fn.apply(null, arguments); } finally { curr = prev; for (var i = 0, length = after.length; i < length; i++) { after[i](); } } }; }; var contextual = function contextual(fn) { var context = null; var augmented = augmentor(function () { return fn.apply(context, arguments); }); return function () { context = this; return augmented.apply(this, arguments); }; }; var current = function current() { return curr; }; function different(value, i) { return value !== this[i]; } var isFunction = function isFunction(fn) { return typeof fn === 'function'; }; var compat = typeof cancelAnimationFrame === 'function'; var cAF = compat ? cancelAnimationFrame : clearTimeout; var rAF = compat ? requestAnimationFrame : setTimeout; function reraf(limit) { var force, timer, callback, self, args; reset(); return function reschedule(_callback, _self, _args) { callback = _callback; self = _self; args = _args; if (!timer) timer = rAF(invoke); if (--force < 0) stop(true); return stop; }; function invoke() { reset(); callback.apply(self, args || []); } function reset() { force = limit || Infinity; timer = compat ? 0 : null; } function stop(flush) { var didStop = !!timer; if (didStop) { cAF(timer); if (flush) invoke(); } return didStop; } } /*! (c) Andrea Giammarchi - ISC */ var updates = new WeakMap(); var update = function update(hook, ctx, args) { hook.apply(ctx, args); }; var defaults = { sync: false, always: false }; var useState = function useState(value, options) { var state = current(); var i = state.i++; var hook = state.hook, args = state.args, stack = state.stack; var _ref = options || defaults, sync = _ref.sync, always = _ref.always; if (stack.length <= i) { stack[i] = isFunction(value) ? value() : value; if (!updates.has(hook)) updates.set(hook, sync ? update : reraf()); } return [stack[i], function (value) { var newValue = isFunction(value) ? value(stack[i]) : value; if (always || stack[i] !== newValue) { stack[i] = newValue; updates.get(hook)(hook, null, args); } }]; }; /*! (c) Andrea Giammarchi - ISC */ var hooks = new WeakMap(); var invoke = function invoke(_ref) { var hook = _ref.hook, args = _ref.args; hook.apply(null, args); }; var createContext = function createContext(value) { var context = { value: value, provide: provide }; hooks.set(context, []); return context; }; var useContext = function useContext(context) { var _current = current(), hook = _current.hook, args = _current.args; var stack = hooks.get(context); var info = { hook: hook, args: args }; if (!stack.some(update$1, info)) stack.push(info); return context.value; }; function provide(value) { if (this.value !== value) { this.value = value; hooks.get(this).forEach(invoke); } } function update$1(_ref2) { var hook = _ref2.hook; return hook === this.hook; } /*! (c) Andrea Giammarchi - ISC */ var effects = new WeakMap(); var stop = function stop() {}; var createEffect = function createEffect(sync) { return function (effect, guards) { var state = current(); var i = state.i++; var hook = state.hook, stack = state.stack, after = state.after; if (i < stack.length) { var info = stack[i]; var clean = info.clean, update = info.update, values = info.values; if (!guards || guards.some(different, values)) { info.values = guards; if (clean) { info.clean = null; clean(); } var invoke = function invoke() { info.clean = effect(); }; if (sync) after.push(invoke);else update(invoke); } } else { if (!effects.has(hook)) effects.set(hook, { stack: [], update: reraf() }); var details = effects.get(hook); var _info = { clean: null, stop: stop, update: details.update, values: guards }; stack[i] = _info; details.stack.push(_info); var _invoke = function _invoke() { _info.clean = effect(); }; if (sync) after.push(_invoke);else _info.stop = details.update(_invoke); } }; }; var useEffect = createEffect(false); var useLayoutEffect = createEffect(true); var dropEffect = function dropEffect(hook) { if (effects.has(hook)) effects.get(hook).stack.forEach(function (info) { var clean = info.clean, stop = info.stop; stop(); if (clean) { info.clean = null; clean(); } }); }; /*! (c) Andrea Giammarchi - ISC */ var useMemo = function useMemo(memo, guards) { var state = current(); var i = state.i++; var stack = state.stack; if (!guards || stack.length <= i || guards.some(different, stack[i].values)) stack[i] = { current: memo(), values: guards }; return stack[i].current; }; var useCallback = function useCallback(fn, guards) { return useMemo(function () { return fn; }, guards); }; /*! (c) Andrea Giammarchi - ISC */ var useReducer = function useReducer(reducer, value, init, options) { var fn = typeof init === 'function'; // avoid `cons [state, update] = ...` Babel destructuring bloat var pair = useState(fn ? init(value) : value, fn ? options : init); return [pair[0], function (value) { pair[1](reducer(pair[0], value)); }]; }; /*! (c) Andrea Giammarchi - ISC */ var useRef = function useRef(value) { var state = current(); var i = state.i++; var stack = state.stack; return i < stack.length ? stack[i] : stack[i] = { current: value }; }; /*! (c) Andrea Giammarchi - ISC */ var find = function find(node) { var childNodes = node.childNodes; var length = childNodes.length; var i = 0; while (i < length) { var child = childNodes[i++]; if (child.nodeType === 1) return child; } throw 'unobservable'; }; var observe = disconnected({ Event: CustomEvent$1, WeakSet: WeakSet$1 }); var observer = function observer(element, handler) { var nodeType = element.nodeType; if (nodeType) { var node = nodeType === 1 ? element : find(element); observe(node); node.addEventListener('disconnected', handler, false); } else { var value = element.valueOf(); // give a chance to facades to return a reasonable value if (value !== element) observer(value, handler); } }; var effect = false; var augmentor$1 = function augmentor$1(fn) { var hook = augmentor(fn); var handler = null; return function () { effect = false; var node = hook.apply(this, arguments); if (effect) { effect = false; observer(node, handler || (handler = dropEffect.bind(null, hook))); } return node; }; }; function useEffect$1() { effect = true; return useEffect.apply(null, arguments); } /*! (c) Andrea Giammarchi - ISC */ // Custom var UID = '-' + Math.random().toFixed(6) + '%'; // Edge issue! var UID_IE = false; try { if (!function (template, content, tabindex) { return content in template && (template.innerHTML = '<p ' + tabindex + '="' + UID + '"></p>', template[content].childNodes[0].getAttribute(tabindex) == UID); }(document.createElement('template'), 'content', 'tabindex')) { UID = '_dt: ' + UID.slice(1, -1) + ';'; UID_IE = true; } } catch (meh) {} var UIDC = '<!--' + UID + '-->'; // DOM var COMMENT_NODE = 8; var ELEMENT_NODE = 1; var TEXT_NODE = 3; var SHOULD_USE_TEXT_CONTENT = /^(?:style|textarea)$/i; var VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)$/i; /*! (c) Andrea Giammarchi - ISC */ function domsanitizer (template) { return template.join(UIDC).replace(selfClosing, fullClosing).replace(attrSeeker, attrReplacer); } var spaces = ' \\f\\n\\r\\t'; var almostEverything = '[^' + spaces + '\\/>"\'=]+'; var attrName = '[' + spaces + ']+' + almostEverything; var tagName = '<([A-Za-z]+[A-Za-z0-9:._-]*)((?:'; var attrPartials = '(?:\\s*=\\s*(?:\'[^\']*?\'|"[^"]*?"|<[^>]*?>|' + almostEverything.replace('\\/', '') + '))?)'; var attrSeeker = new RegExp(tagName + attrName + attrPartials + '+)([' + spaces + ']*/?>)', 'g'); var selfClosing = new RegExp(tagName + attrName + attrPartials + '*)([' + spaces + ']*/>)', 'g'); var findAttributes = new RegExp('(' + attrName + '\\s*=\\s*)([\'"]?)' + UIDC + '\\2', 'gi'); function attrReplacer($0, $1, $2, $3) { return '<' + $1 + $2.replace(findAttributes, replaceAttributes) + $3; } function replaceAttributes($0, $1, $2) { return $1 + ($2 || '"') + UID + ($2 || '"'); } function fullClosing($0, $1, $2) { return VOID_ELEMENTS.test($1) ? $0 : '<' + $1 + $2 + '></' + $1 + '>'; } /*! (c) Andrea Giammarchi - ISC */ var createContent = function (document) { var FRAGMENT = 'fragment'; var TEMPLATE = 'template'; var HAS_CONTENT = 'content' in create(TEMPLATE); var createHTML = HAS_CONTENT ? function (html) { var template = create(TEMPLATE); template.innerHTML = html; return template.content; } : function (html) { var content = create(FRAGMENT); var template = create(TEMPLATE); var childNodes = null; if (/^[^\S]*?<(col(?:group)?|t(?:head|body|foot|r|d|h))/i.test(html)) { var selector = RegExp.$1; template.innerHTML = '<table>' + html + '</table>'; childNodes = template.querySelectorAll(selector); } else { template.innerHTML = html; childNodes = template.childNodes; } append(content, childNodes); return content; }; return function createContent(markup, type) { return (type === 'svg' ? createSVG : createHTML)(markup); }; function append(root, childNodes) { var length = childNodes.length; while (length--) { root.appendChild(childNodes[0]); } } function create(element) { return element === FRAGMENT ? document.createDocumentFragment() : document.createElementNS('http://www.w3.org/1999/xhtml', element); } // it could use createElementNS when hasNode is there // but this fallback is equally fast and easier to maintain // it is also battle tested already in all IE function createSVG(svg) { var content = create(FRAGMENT); var template = create('div'); template.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg">' + svg + '</svg>'; append(content, template.firstChild.childNodes); return content; } }(document); /*! (c) Andrea Giammarchi - ISC */ var self$3 = null || /* istanbul ignore next */ {}; try { self$3.Map = Map; } catch (Map) { self$3.Map = function Map() { var i = 0; var k = []; var v = []; return { "delete": function _delete(key) { var had = contains(key); if (had) { k.splice(i, 1); v.splice(i, 1); } return had; }, forEach: function forEach(callback, context) { k.forEach(function (key, i) { callback.call(context, v[i], key, this); }, this); }, get: function get(key) { return contains(key) ? v[i] : void 0; }, has: function has(key) { return contains(key); }, set: function set(key, value) { v[contains(key) ? i : k.push(key) - 1] = value; return this; } }; function contains(v) { i = k.indexOf(v); return -1 < i; } }; } var Map$1 = self$3.Map; var iOF = [].indexOf; var append = function append(get, parent, children, start, end, before) { var isSelect = 'selectedIndex' in parent; var noSelection = isSelect; while (start < end) { var child = get(children[start], 1); parent.insertBefore(child, before); if (isSelect && noSelection && child.selected) { noSelection = !noSelection; var selectedIndex = parent.selectedIndex; parent.selectedIndex = selectedIndex < 0 ? start : iOF.call(parent.querySelectorAll('option'), child); } start++; } }; var eqeq = function eqeq(a, b) { return a == b; }; var identity = function identity(O) { return O; }; var indexOf = function indexOf(moreNodes, moreStart, moreEnd, lessNodes, lessStart, lessEnd, compare) { var length = lessEnd - lessStart; /* istanbul ignore if */ if (length < 1) return -1; while (moreEnd - moreStart >= length) { var m = moreStart; var l = lessStart; while (m < moreEnd && l < lessEnd && compare(moreNodes[m], lessNodes[l])) { m++; l++; } if (l === lessEnd) return moreStart; moreStart = m + 1; } return -1; }; var isReversed = function isReversed(futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare) { while (currentStart < currentEnd && compare(currentNodes[currentStart], futureNodes[futureEnd - 1])) { currentStart++; futureEnd--; } return futureEnd === 0; }; var next = function next(get, list, i, length, before) { return i < length ? get(list[i], 0) : 0 < i ? get(list[i - 1], -0).nextSibling : before; }; var remove = function remove(get, children, start, end) { while (start < end) { drop(get(children[start++], -1)); } }; // - - - - - - - - - - - - - - - - - - - // diff related constants and utilities // - - - - - - - - - - - - - - - - - - - var DELETION = -1; var INSERTION = 1; var SKIP = 0; var SKIP_OND = 50; var HS = function HS(futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges) { var k = 0; /* istanbul ignore next */ var minLen = futureChanges < currentChanges ? futureChanges : currentChanges; var link = Array(minLen++); var tresh = Array(minLen); tresh[0] = -1; for (var i = 1; i < minLen; i++) { tresh[i] = currentEnd; } var keymap = new Map$1(); for (var _i = currentStart; _i < currentEnd; _i++) { keymap.set(currentNodes[_i], _i); } for (var _i2 = futureStart; _i2 < futureEnd; _i2++) { var idxInOld = keymap.get(futureNodes[_i2]); if (idxInOld != null) { k = findK(tresh, minLen, idxInOld); /* istanbul ignore else */ if (-1 < k) { tresh[k] = idxInOld; link[k] = { newi: _i2, oldi: idxInOld, prev: link[k - 1] }; } } } k = --minLen; --currentEnd; while (tresh[k] > currentEnd) { --k; } minLen = currentChanges + futureChanges - k; var diff = Array(minLen); var ptr = link[k]; --futureEnd; while (ptr) { var _ptr = ptr, newi = _ptr.newi, oldi = _ptr.oldi; while (futureEnd > newi) { diff[--minLen] = INSERTION; --futureEnd; } while (currentEnd > oldi) { diff[--minLen] = DELETION; --currentEnd; } diff[--minLen] = SKIP; --futureEnd; --currentEnd; ptr = ptr.prev; } while (futureEnd >= futureStart) { diff[--minLen] = INSERTION; --futureEnd; } while (currentEnd >= currentStart) { diff[--minLen] = DELETION; --currentEnd; } return diff; }; // this is pretty much the same petit-dom code without the delete map part // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L556-L561 var OND = function OND(futureNodes, futureStart, rows, currentNodes, currentStart, cols, compare) { var length = rows + cols; var v = []; var d, k, r, c, pv, cv, pd; outer: for (d = 0; d <= length; d++) { /* istanbul ignore if */ if (d > SKIP_OND) return null; pd = d - 1; /* istanbul ignore next */ pv = d ? v[d - 1] : [0, 0]; cv = v[d] = []; for (k = -d; k <= d; k += 2) { if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) { c = pv[pd + k + 1]; } else { c = pv[pd + k - 1] + 1; } r = c - k; while (c < cols && r < rows && compare(currentNodes[currentStart + c], futureNodes[futureStart + r])) { c++; r++; } if (c === cols && r === rows) { break outer; } cv[d + k] = c; } } var diff = Array(d / 2 + length / 2); var diffIdx = diff.length - 1; for (d = v.length - 1; d >= 0; d--) { while (c > 0 && r > 0 && compare(currentNodes[currentStart + c - 1], futureNodes[futureStart + r - 1])) { // diagonal edge = equality diff[diffIdx--] = SKIP; c--; r--; } if (!d) break; pd = d - 1; /* istanbul ignore next */ pv = d ? v[d - 1] : [0, 0]; k = c - r; if (k === -d || k !== d && pv[pd + k - 1] < pv[pd + k + 1]) { // vertical edge = insertion r--; diff[diffIdx--] = INSERTION; } else { // horizontal edge = deletion c--; diff[diffIdx--] = DELETION; } } return diff; }; var applyDiff = function applyDiff(diff, get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before) { var live = new Map$1(); var length = diff.length; var currentIndex = currentStart; var i = 0; while (i < length) { switch (diff[i++]) { case SKIP: futureStart++; currentIndex++; break; case INSERTION: // TODO: bulk appends for sequential nodes live.set(futureNodes[futureStart], 1); append(get, parentNode, futureNodes, futureStart++, futureStart, currentIndex < currentLength ? get(currentNodes[currentIndex], 0) : before); break; case DELETION: currentIndex++; break; } } i = 0; while (i < length) { switch (diff[i++]) { case SKIP: currentStart++; break; case DELETION: // TODO: bulk removes for sequential nodes if (live.has(currentNodes[currentStart])) currentStart++;else remove(get, currentNodes, currentStart++, currentStart); break; } } }; var findK = function findK(ktr, length, j) { var lo = 1; var hi = length; while (lo < hi) { var mid = (lo + hi) / 2 >>> 0; if (j < ktr[mid]) hi = mid;else lo = mid + 1; } return lo; }; var smartDiff = function smartDiff(get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before) { applyDiff(OND(futureNodes, futureStart, futureChanges, currentNodes, currentStart, currentChanges, compare) || HS(futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges), get, parentNode, futureNodes, futureStart, currentNodes, currentStart, currentLength, before); }; var drop = function drop(node) { return (node.remove || dropChild).call(node); }; function dropChild() { var parentNode = this.parentNode; /* istanbul ignore else */ if (parentNode) parentNode.removeChild(this); } /*! (c) 2018 Andrea Giammarchi (ISC) */ var domdiff = function domdiff(parentNode, // where changes happen currentNodes, // Array of current items/nodes futureNodes, // Array of future items/nodes options // optional object with one of the following properties // before: domNode // compare(generic, generic) => true if same generic // node(generic) => Node ) { if (!options) options = {}; var compare = options.compare || eqeq; var get = options.node || identity; var before = options.before == null ? null : get(options.before, 0); var currentLength = currentNodes.length; var currentEnd = currentLength; var currentStart = 0; var futureEnd = futureNodes.length; var futureStart = 0; // common prefix while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentStart], futureNodes[futureStart])) { currentStart++; futureStart++; } // common suffix while (currentStart < currentEnd && futureStart < futureEnd && compare(currentNodes[currentEnd - 1], futureNodes[futureEnd - 1])) { currentEnd--; futureEnd--; } var currentSame = currentStart === currentEnd; var futureSame = futureStart === futureEnd; // same list if (currentSame && futureSame) return futureNodes; // only stuff to add if (currentSame && futureStart < futureEnd) { append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentStart, currentLength, before)); return futureNodes; } // only stuff to remove if (futureSame && currentStart < currentEnd) { remove(get, currentNodes, currentStart, currentEnd); return futureNodes; } var currentChanges = currentEnd - currentStart; var futureChanges = futureEnd - futureStart; var i = -1; // 2 simple indels: the shortest sequence is a subsequence of the longest if (currentChanges < futureChanges) { i = indexOf(futureNodes, futureStart, futureEnd, currentNodes, currentStart, currentEnd, compare); // inner diff if (-1 < i) { append(get, parentNode, futureNodes, futureStart, i, get(currentNodes[currentStart], 0)); append(get, parentNode, futureNodes, i + currentChanges, futureEnd, next(get, currentNodes, currentEnd, currentLength, before)); return futureNodes; } } /* istanbul ignore else */ else if (futureChanges < currentChanges) { i = indexOf(currentNodes, currentStart, currentEnd, futureNodes, futureStart, futureEnd, compare); // outer diff if (-1 < i) { remove(get, currentNodes, currentStart, i); remove(get, currentNodes, i + futureChanges, currentEnd); return futureNodes; } } // common case with one replacement for many nodes // or many nodes replaced for a single one /* istanbul ignore else */ if (currentChanges < 2 || futureChanges < 2) { append(get, parentNode, futureNodes, futureStart, futureEnd, get(currentNodes[currentStart], 0)); remove(get, currentNodes, currentStart, currentEnd); return futureNodes; } // the half match diff part has been skipped in petit-dom // https://github.com/yelouafi/petit-dom/blob/bd6f5c919b5ae5297be01612c524c40be45f14a7/src/vdom.js#L391-L397 // accordingly, I think it's safe to skip in here too // if one day it'll come out like the speediest thing ever to do // then I might add it in here too // Extra: before going too fancy, what about reversed lists ? // This should bail out pretty quickly if that's not the case. if (currentChanges === futureChanges && isReversed(futureNodes, futureEnd, currentNodes, currentStart, currentEnd, compare)) { append(get, parentNode, futureNodes, futureStart, futureEnd, next(get, currentNodes, currentEnd, currentLength, before)); return futureNodes; } // last resort through a smart diff smartDiff(get, parentNode, futureNodes, futureStart, futureEnd, futureChanges, currentNodes, currentStart, currentEnd, currentChanges, currentLength, compare, before); return futureNodes; }; /*! (c) Andrea Giammarchi - ISC */ var importNode = function (document, appendChild, cloneNode, createTextNode, importNode) { var _native = importNode in document; // IE 11 has problems with cloning templates: // it "forgets" empty childNodes. This feature-detects that. var fragment = document.createDocumentFragment(); fragment[appendChild](document[createTextNode]('g')); fragment[appendChild](document[createTextNode]('')); var content = _native ? document[importNode](fragment, true) : fragment[cloneNode](true); return content.childNodes.length < 2 ? function importNode(node, deep) { var clone = node[cloneNode](); for (var childNodes = node.childNodes || [], length = childNodes.length, i = 0; deep && i < length; i++) { clone[appendChild](importNode(childNodes[i], deep)); } return clone; } : _native ? document[importNode] : function (node, deep) { return node[cloneNode](!!deep); }; }(document, 'appendChild', 'cloneNode', 'createTextNode', 'importNode'); var trim = ''.trim || function () { return String(this).replace(/^\s+|\s+/g, ''); }; function find$1(node, path) { var length = path.length; var i = 0; while (i < length) { node = node.childNodes[path[i++]]; } return node; } function parse(node, holes, parts, path) { var childNodes = node.childNodes; var length = childNodes.length; var i = 0; while (i < length) { var child = childNodes[i]; switch (child.nodeType) { case ELEMENT_NODE: var childPath = path.concat(i); parseAttributes(child, holes, parts, childPath); parse(child, holes, parts, childPath); break; case COMMENT_NODE: var textContent = child.textContent; if (textContent === UID) { parts.shift(); holes.push( // basicHTML or other non standard engines // might end up having comments in nodes // where they shouldn't, hence this check. SHOULD_USE_TEXT_CONTENT.test(node.nodeName) ? Text(node, path) : Any(child, path.concat(i))); } else { switch (textContent.slice(0, 2)) { case '/*': if (textContent.slice(-2) !== '*/') break; case "\uD83D\uDC7B": // ghost node.removeChild(child); i--; length--; } } break; case TEXT_NODE: // the following ignore is actually covered by browsers // only basicHTML ends up on previous COMMENT_NODE case // instead of TEXT_NODE because it knows nothing about // special style or textarea behavior /* istanbul ignore if */ if (SHOULD_USE_TEXT_CONTENT.test(node.nodeName) && trim.call(child.textContent) === UIDC) { parts.shift(); holes.push(Text(node, path)); } break; } i++; } } function parseAttributes(node, holes, parts, path) { var cache = new Map$1(); var attributes = node.attributes; var remove = []; var array = remove.slice.call(attributes, 0); var length = array.length; var i = 0; while (i < length) { var attribute = array[i++]; var direct = attribute.value === UID; var sparse; if (direct || 1 < (sparse = attribute.value.split(UIDC)).length) { var name = attribute.name; // the following ignore is covered by IE // and the IE9 double viewBox test /* istanbul ignore else */ if (!cache.has(name)) { var realName = parts.shift().replace(direct ? /^(?:|[\S\s]*?\s)(\S+?)\s*=\s*('|")?$/ : // TODO: while working on yet another IE/Edge bug I've realized // the current not direct logic easily breaks there // because the `name` might not be the real needed one. // Use a better RegExp to find last attribute instead // of trusting `name` is what we are looking for. // Thanks IE/Edge, I hate you both. new RegExp('^(?:|[\\S\\s]*?\\s)(' + name + ')\\s*=\\s*(\'|")[\\S\\s]*', 'i'), '$1'); var value = attributes[realName] || // the following ignore is covered by browsers // while basicHTML is already case-sensitive /* istanbul ignore next */ attributes[realName.toLowerCase()]; cache.set(name, value); if (direct) holes.push(Attr(value, path, realName, null));else { var skip = sparse.length - 2; while (skip--) { parts.shift(); } holes.push(Attr(value, path, realName, sparse)); } } remove.push(attribute); } } length = remove.length; i = 0; /* istanbul ignore next */ var cleanValue = 0 < length && UID_IE && !('ownerSVGElement' in node); while (i < length) { // Edge HTML bug #16878726 var attr = remove[i++]; // IE/Edge bug lighterhtml#63 - clean the value or it'll persist /* istanbul ignore next */ if (cleanValue) attr.value = ''; // IE/Edge bug lighterhtml#64 - don't use removeAttributeNode node.removeAttribute(attr.name); } // This is a very specific Firefox/Safari issue // but since it should be a not so common pattern, // it's probably worth patching regardless. // Basically, scripts created through strings are death. // You need to create fresh new scripts instead. // TODO: is there any other node that needs such nonsense? var nodeName = node.nodeName; if (/^script$/i.test(nodeName)) { // this used to be like that // var script = createElement(node, nodeName); // then Edge arrived and decided that scripts created // through template documents aren't worth executing // so it became this ... hopefully it won't hurt in the wild var script = document.createElement(nodeName); length = attributes.length; i = 0; while (i < length) { script.setAttributeNode(attributes[i++].cloneNode(true)); } script.textContent = node.textContent; node.parentNode.replaceChild(script, node); } } function Any(node, path) { return { type: 'any', node: node, path: path }; } function Attr(node, path, name, sparse) { return { type: 'attr', node: node, path: path, name: name, sparse: sparse }; } function Text(node, path) { return { type: 'text', node: node, path: path }; } // globals var parsed = new WeakMap$1(); var referenced = new WeakMap$1(); function createInfo(options, template) { var markup = (options.convert || domsanitizer)(template); var transform = options.transform; if (transform) markup = transform(markup); var content = createContent(markup, options.type); cleanContent(content); var holes = []; parse(content, holes, template.slice(0), []); var info = { content: content, updates: function updates(content) { var updates = []; var len = holes.length; var i = 0; var off = 0; while (i < len) { var info = holes[i++]; var node = find$1(content, info.path); switch (info.type) { case 'any': updates.push({ fn: options.any(node, []), sparse: false }); break; case 'attr': var sparse = info.sparse; var fn = options.attribute(node, info.name, info.node); if (sparse === null) updates.push({ fn: fn, sparse: false });else { off += sparse.length - 2; updates.push({ fn: fn, sparse: true, values: sparse }); } break; case 'text': updates.push({ fn: options.text(node), sparse: false }); node.textContent = ''; break; } } len += off; return function () { var length = arguments.length; if (len !== length - 1) { throw new Error(length - 1 + ' values instead of ' + len + '\n' + template.join('${value}')); } var i = 1; var off = 1; while (i < length) { var update = updates[i - off]; if (update.sparse) { var values = update.values; var value = values[0]; var j = 1; var l = values.length; off += l - 2; while (j < l) { value += arguments[i++] + values[j++]; } update.fn(value); } else update.fn(arguments[i++]); } return content; }; } }; parsed.set(template, info); return info; } function createDetails(options, template) { var info = parsed.get(template) || createInfo(options, template); var content = importNode.call(document, info.content, true); var details = { content: content, template: template, updates: info.updates(content) }; referenced.set(options, details); return details; } function domtagger(options) { return function (template) { var details = referenced.get(options); if (details == null || details.template !== template) details = createDetails(options, template); details.updates.apply(null, arguments); return details.content; }; } function cleanContent(fragment) { var childNodes = fragment.childNodes; var i = childNodes.length; while (i--) { var child = childNodes[i]; if (child.nodeType !== 1 && trim.call(child.textContent).length === 0) { fragment.removeChild(child); } } } /*! (c) Andrea Giammarchi - ISC */ var hyperStyle = function () { var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i; var hyphen = /([^A-Z])([A-Z]+)/g; return function hyperStyle(node, original) { return 'ownerSVGElement' in node ? svg(node, original) : update(node.style, false); }; function ized($0, $1, $2) { return $1 + '-' + $2.toLowerCase(); } function svg(node, original) { var style; if (original) style = original.cloneNode(true);else { node.setAttribute('style', '--hyper:style;'); style = node.getAttributeNode('style'); } style.value = ''; node.setAttributeNode(style); return update(style, true); } function toStyle(object) { var key, css = []; for (key in object) { css.push(key.replace(hyphen, ized), ':', object[key], ';'); } return css.join(''); } function update(style, isSVG) { var oldType, oldValue; return function (newValue) { var info, key, styleValue, value; switch (typeof(newValue)) { case 'object': if (newValue) { if (oldType === 'object') { if (!isSVG) { if (oldValue !== newValue) { for (key in oldValue) { if (!(key in newValue)) { style[key] = ''; } } } } } else { if (isSVG) style.value = '';else style.cssText = ''; } info = isSVG ? {} : style; for (key in newValue) { value = newValue[key]; styleValue = typeof value === 'number' && !IS_NON_DIMENSIONAL.test(key) ? value + 'px' : value; if (!isSVG && /^--/.test(key)) info.setProperty(key, styleValue);else info[key] = styleValue; } oldType = 'object'; if (isSVG) style.value = toStyle(oldValue = info);else oldValue = newValue; break; } default: if (oldValue != newValue) { oldType = 'string'; oldValue = newValue; if (isSVG) style.value = newValue || '';else style.cssText = newValue || ''; } break; } }; } }(); /*! (c) Andrea Giammarchi - ISC */ var Wire = function (slice, proto) { proto = Wire.prototype; proto.ELEMENT_NODE = 1; proto.nodeType = 111; proto.remove = function (keepFirst) { var childNodes = this.childNodes; var first = this.firstChild; var last = this.lastChild; this._ = null; if (keepFirst && childNodes.length === 2) { last.parentNode.removeChild(last); } else { var range = this.ownerDocument.createRange(); range.setStartBefore(keepFirst ? childNodes[1] : first); range.setEndAfter(last); range.deleteContents(); } return first; }; proto.valueOf = function (forceAppend) { var fragment = this._; var noFragment = fragment == null; if (noFragment) fragment = this._ = this.ownerDocument.createDocumentFragment(); if (noFragment || forceAppend) { for (var n = this.childNodes, i = 0, l = n.length; i < l; i++) { fragment.appendChild(n[i]); } } return fragment; }; return Wire; function Wire(childNodes) { var nodes = this.childNodes = slice.call(childNodes, 0); this.firstChild = nodes[0]; this.lastChild = nodes[nodes.length - 1]; this.ownerDocument = nodes[0].ownerDocument; this._ = null; } }([].slice); var isArray = Array.isArray; var create = Object.create, freeze = Object.freeze; var wireType = Wire.prototype.nodeType; var OWNER_SVG_ELEMENT = 'ownerSVGElement'; // returns nodes from wires and components var asNode = function asNode(item, i) { return item.nodeType === wireType ? 1 / i < 0 ? i ? item.remove(true) : item.lastChild : i ? item.valueOf(true) : item.firstChild : item; }; // returns true if domdiff can handle the value var canDiff = function canDiff(value) { return 'ELEMENT_NODE' in value; }; // generic attributes helpers var hyperAttribute = function hyperAttribute(node, original) { var oldValue; var owner = false; var attribute = original.cloneNode(true); return function (newValue) { if (oldValue !== newValue) { oldValue = newValue; if (attribute.value !== newValue) { if (newValue == null) { if (owner) { owner = false; node.removeAttributeNode(attribute); } attribute.value = newValue; } else { attribute.value = newValue; if (!owner) { owner = true; node.setAttributeNode(attribute); } } } } }; }; // events attributes helpers var hyperEvent = function hyperEvent(node, name) { var oldValue; var type = name.slice(2); if (name.toLowerCase() in node) type = type.toLowerCase(); return function (newValue) { if (oldValue !== newValue) { if (oldValue) node.removeEventListener(type, oldValue, false); oldValue = newValue; if (newValue) node.addEventListener(type, newValue, false); } }; }; // special attributes helpers var hyperProperty = function hyperProperty(node, name) { var oldValue; return function (newValue) { if (oldValue !== newValue) { oldValue = newValue; if (node[name] !== newValue) { if (newValue == null) { // cleanup before dropping the attribute to fix IE/Edge gotcha node[name] = ''; node.removeAttribute(name); } else node[name] = newValue; } } }; }; // special hooks helpers var hyperRef = function hyperRef(node) { return function (ref) { ref.current = node; }; }; var hyperSetter = function hyperSetter(node, name, svg) { return svg ? function (value) { try { node[name] = value; } catch (nope) { node.setAttribute(name, value); } } : function (value) { node[name] = value; }; }; // list of attributes that should not be directly assigned var readOnly = /^(?:form|list)$/i; // reused every slice time var slice = [].slice; // simplifies text node creation var text = function text(node, _text) { return node.ownerDocument.createTextNode(_text); }; function Tagger(type) { this.type = type; return domtagger(this); } Tagger.prototype = { // there are four kind of attributes, and related behavior: // * events, with a name starting with `on`, to add/remove event listeners // * special, with a name present in their inherited prototype, accessed directly // * regular, accessed through get/setAttribute standard DOM methods // * style, the only regular attribute that also accepts an object as value // so that you can style=${{width: 120}}. In this case, the behavior has been // fully inspired by Preact library and its simplicity. attribute: function attribute(node, name, original) { switch (name) { case 'class': if (OWNER_SVG_ELEMENT in node) return hyperAttribute(node, original); name = 'className'; case 'data': case 'props': return hyperProperty(node, name); case 'style': return hyperStyle(node, original, OWNER_SVG_ELEMENT in node); case 'ref': return hyperRef(node); default: if (name.slice(0, 1) === '.') return hyperSetter(node, name.slice(1), OWNER_SVG_ELEMENT in node); if (name.slice(0, 2) === 'on') return hyperEvent(n