forked from rojo-rbx/rojo
51 lines
1.6 KiB
Lua
51 lines
1.6 KiB
Lua
--[[
|
|
Defines the process of "hydration" -- matching up a virtual DOM with
|
|
concrete instances and assigning them IDs.
|
|
]]
|
|
|
|
local invariant = require(script.Parent.Parent.invariant)
|
|
|
|
local function hydrate(instanceMap, virtualInstances, rootId, rootInstance)
|
|
local virtualInstance = virtualInstances[rootId]
|
|
|
|
if virtualInstance == nil then
|
|
invariant("Cannot hydrate an instance not present in virtualInstances\nID: {}", rootId)
|
|
end
|
|
|
|
instanceMap:insert(rootId, rootInstance)
|
|
|
|
local existingChildren = rootInstance:GetChildren()
|
|
|
|
-- For each existing child, we'll track whether it's been paired with an
|
|
-- instance that the Rojo server knows about.
|
|
local isExistingChildVisited = {}
|
|
for i = 1, #existingChildren do
|
|
isExistingChildVisited[i] = false
|
|
end
|
|
|
|
for _, childId in ipairs(virtualInstance.Children) do
|
|
local virtualChild = virtualInstances[childId]
|
|
|
|
for childIndex, childInstance in ipairs(existingChildren) do
|
|
if not isExistingChildVisited[childIndex] then
|
|
-- We guard accessing Name and ClassName in order to avoid
|
|
-- tripping over children of DataModel that Rojo won't have
|
|
-- permissions to access at all.
|
|
local accessSuccess, name, className = pcall(function()
|
|
return childInstance.Name, childInstance.ClassName
|
|
end)
|
|
|
|
-- This rule is very conservative and could be loosened in the
|
|
-- future, or more heuristics could be introduced.
|
|
if accessSuccess and name == virtualChild.Name and className == virtualChild.ClassName then
|
|
isExistingChildVisited[childIndex] = true
|
|
hydrate(instanceMap, virtualInstances, childId, childInstance)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return hydrate
|