UNPKG

ember-legacy-class-transform

Version:
197 lines 5.83 kB
import { LinkedList, ListNode, dict, expect } from '@glimmer/util'; export class ListItem extends ListNode { constructor(iterable, result) { super(iterable.valueReferenceFor(result)); this.retained = false; this.seen = false; this.key = result.key; this.iterable = iterable; this.memo = iterable.memoReferenceFor(result); } update(item) { this.retained = true; this.iterable.updateValueReference(this.value, item); this.iterable.updateMemoReference(this.memo, item); } shouldRemove() { return !this.retained; } reset() { this.retained = false; this.seen = false; } } export class IterationArtifacts { constructor(iterable) { this.map = dict(); this.list = new LinkedList(); this.tag = iterable.tag; this.iterable = iterable; } isEmpty() { let iterator = this.iterator = this.iterable.iterate(); return iterator.isEmpty(); } iterate() { let iterator = this.iterator || this.iterable.iterate(); this.iterator = null; return iterator; } has(key) { return !!this.map[key]; } get(key) { return this.map[key]; } wasSeen(key) { let node = this.map[key]; return node && node.seen; } append(item) { let { map, list, iterable } = this; let node = map[item.key] = new ListItem(iterable, item); list.append(node); return node; } insertBefore(item, reference) { let { map, list, iterable } = this; let node = map[item.key] = new ListItem(iterable, item); node.retained = true; list.insertBefore(node, reference); return node; } move(item, reference) { let { list } = this; item.retained = true; list.remove(item); list.insertBefore(item, reference); } remove(item) { let { list } = this; list.remove(item); delete this.map[item.key]; } nextNode(item) { return this.list.nextNode(item); } head() { return this.list.head(); } } export class ReferenceIterator { // if anyone needs to construct this object with something other than // an iterable, let @wycats know. constructor(iterable) { this.iterator = null; let artifacts = new IterationArtifacts(iterable); this.artifacts = artifacts; } next() { let { artifacts } = this; let iterator = this.iterator = this.iterator || artifacts.iterate(); let item = iterator.next(); if (!item) return null; return artifacts.append(item); } } var Phase; (function (Phase) { Phase[Phase["Append"] = 0] = "Append"; Phase[Phase["Prune"] = 1] = "Prune"; Phase[Phase["Done"] = 2] = "Done"; })(Phase || (Phase = {})); export class IteratorSynchronizer { constructor({ target, artifacts }) { this.target = target; this.artifacts = artifacts; this.iterator = artifacts.iterate(); this.current = artifacts.head(); } sync() { let phase = Phase.Append; while (true) { switch (phase) { case Phase.Append: phase = this.nextAppend(); break; case Phase.Prune: phase = this.nextPrune(); break; case Phase.Done: this.nextDone(); return; } } } advanceToKey(key) { let { current, artifacts } = this; let seek = current; while (seek && seek.key !== key) { seek.seen = true; seek = artifacts.nextNode(seek); } this.current = seek && artifacts.nextNode(seek); } nextAppend() { let { iterator, current, artifacts } = this; let item = iterator.next(); if (item === null) { return this.startPrune(); } let { key } = item; if (current && current.key === key) { this.nextRetain(item); } else if (artifacts.has(key)) { this.nextMove(item); } else { this.nextInsert(item); } return Phase.Append; } nextRetain(item) { let { artifacts, current } = this; current = expect(current, 'BUG: current is empty'); current.update(item); this.current = artifacts.nextNode(current); this.target.retain(item.key, current.value, current.memo); } nextMove(item) { let { current, artifacts, target } = this; let { key } = item; let found = artifacts.get(item.key); found.update(item); if (artifacts.wasSeen(item.key)) { artifacts.move(found, current); target.move(found.key, found.value, found.memo, current ? current.key : null); } else { this.advanceToKey(key); } } nextInsert(item) { let { artifacts, target, current } = this; let node = artifacts.insertBefore(item, current); target.insert(node.key, node.value, node.memo, current ? current.key : null); } startPrune() { this.current = this.artifacts.head(); return Phase.Prune; } nextPrune() { let { artifacts, target, current } = this; if (current === null) { return Phase.Done; } let node = current; this.current = artifacts.nextNode(node); if (node.shouldRemove()) { artifacts.remove(node); target.delete(node.key); } else { node.reset(); } return Phase.Prune; } nextDone() { this.target.done(); } }