"use strict"; function lineageEdgeFamily(family = world.family || {}) { return family || {}; } let lineageRelationIndexCache = { family: null, version: null, index: null }; function lineageAddParentEdge(childId, parentId, known, parentsByChild, childrenByParent) { return globalThis.TarinaiFamilyGraph.addParentEdge(childId, parentId, known, parentsByChild, childrenByParent); } function lineageBuildRelationIndex(family) { return globalThis.TarinaiFamilyGraph.buildRelationIndex(family); } function lineageRelationIndex(family = world.family || {}) { family = lineageEdgeFamily(family); if (family !== (world.family || {})) return lineageBuildRelationIndex(family); const version = world.familyVersion || 0; if (lineageRelationIndexCache.family !== family || lineageRelationIndexCache.version !== version) { lineageRelationIndexCache = { family, version, index: lineageBuildRelationIndex(family) }; } return lineageRelationIndexCache.index; } function lineageMutualParentIds(n, family = world.family || {}, idSet = null) { const seen = new Set(); const parents = []; if (!n?.id) return parents; const relationIndex = lineageRelationIndex(family); const candidates = new Set((n.parents || []).filter(Boolean)); // Runtime updates can briefly touch one side first; recover the reciprocal // edge from the relation index so the archive does not flicker. for (const parentId of relationIndex.parentsByChild.get(n.id) || []) candidates.add(parentId); for (const id of candidates) { if (!id || id === n.id || seen.has(id)) continue; if (idSet && !idSet.has(id)) continue; const parent = family[id]; if (!parent) continue; const childListsParent = Array.isArray(n.parents) && n.parents.includes(id); const parentListsChild = Array.isArray(parent.children) && parent.children.includes(n.id); if (!childListsParent && !parentListsChild) continue; seen.add(id); parents.push(id); } parents.sort((a, b) => lineageNodeSort(family[a], family[b])); return parents; } function lineageMutualChildIds(n, family = world.family || {}, idSet = null) { const seen = new Set(); const children = []; if (!n?.id) return children; const relationIndex = lineageRelationIndex(family); const candidates = new Set((n.children || []).filter(Boolean)); // Same recovery as above, in the opposite direction. for (const childId of relationIndex.childrenByParent.get(n.id) || []) candidates.add(childId); for (const id of candidates) { if (!id || id === n.id || seen.has(id)) continue; if (idSet && !idSet.has(id)) continue; const child = family[id]; if (!child) continue; const parentListsChild = Array.isArray(n.children) && n.children.includes(id); const childListsParent = Array.isArray(child.parents) && child.parents.includes(n.id); if (!parentListsChild && !childListsParent) continue; seen.add(id); children.push(id); } children.sort((a, b) => lineageNodeSort(family[a], family[b])); return children; }