if (predClassQn && resolvedArgs) {
const reduced = resolvedArgs.map(reduceTypeArg);
const matched = findMatchingInstances(predClassQn, reduced);
- for (const m of matched) {
- const mId = ensureInstanceNode(
- m, predClassQn,
- 'inst:' + m._idx
- );
- const resId = fiNodeId + '=>resolves=>' + mId;
+ if (matched.length > 0) {
+ for (const m of matched) {
+ const mId = ensureInstanceNode(
+ m, predClassQn,
+ 'inst:' + m._idx
+ );
+ const resId = fiNodeId + '=>resolves=>' + mId;
+ if (!seenNodes.has(resId)) {
+ seenNodes.add(resId);
+ els.push({ group: 'edges', data: {
+ id: resId,
+ source: fiNodeId,
+ target: mId,
+ kind: 'fam-resolves',
+ }});
+ }
+ }
+ } else if (originPredId) {
+ // No matching class instance is in our dumps — typically
+ // because the class lives in a package we didn't extract.
+ // Chain the fam-instance to the predicate node anyway so
+ // it isn't visually orphaned: the user can still see
+ // "this fam-instance is what discharges that constraint",
+ // we just can't surface the actual satisfier.
+ const resId = fiNodeId + '=>resolves=>' + originPredId;
if (!seenNodes.has(resId)) {
seenNodes.add(resId);
els.push({ group: 'edges', data: {
id: resId,
source: fiNodeId,
- target: mId,
+ target: originPredId,
kind: 'fam-resolves',
}});
}