class ViewModel::Migrator

def migrate!(serialization)

def migrate!(serialization)
  references = (serialization['references'] ||= {})
  # First visit everything except references; there's no issue with adding
  # new references during this.
  migrate_tree!(serialization.except('references'), references: references)
  # While visiting references itself, we need to take care that we can
  # concurrently modify them (e.g. by adding new referenced views).
  # Moreover, such added references must themselves be visited, as they'll
  # be synthesized at the current version and so may need to be migrated
  # down to the client's requested version.
  visited_refs = []
  loop do
    unvisited_refs = references.keys - visited_refs
    break if unvisited_refs.empty?
    unvisited_refs.each do |ref|
      migrate_tree!(references[ref], references: references)
    end
    visited_refs.concat(unvisited_refs)
  end
  GarbageCollection.garbage_collect_references!(serialization)
  if references.empty?
    serialization.delete('references')
  end
end