71 lines
3 KiB
JavaScript
71 lines
3 KiB
JavaScript
"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;
|
|
}
|