Skip to content

Commit 68fda3a

Browse files
committed
Anchor: support circular/mutual parenting with visited set to prevent infinite recursion
1 parent c1458c5 commit 68fda3a

2 files changed

Lines changed: 16 additions & 6 deletions

File tree

Anchor/2.1.0/anchor.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,11 @@ var Anchor = Anchor || (() => {
715715
* If onlyComponents is provided, only those components are applied.
716716
* Otherwise, all tracked but UNLOCKED components are applied.
717717
*/
718-
const applyAnchorToChild = (childId, onlyComponents) => {
718+
const applyAnchorToChild = (childId, onlyComponents, visited) => {
719+
if (!visited) visited = new Set();
720+
if (visited.has(childId)) return;
721+
visited.add(childId);
722+
719723
const s = state[SCRIPT_NAME];
720724
const info = s.anchorInfoByChildId[childId];
721725
if (!info) { setAnchor(childId, undefined); return; }
@@ -803,7 +807,7 @@ var Anchor = Anchor || (() => {
803807
// Propagate to this child's own children (if it is also an anchor)
804808
if (childId in s.anchorChildrenByAnchorId) {
805809
Object.keys(s.anchorChildrenByAnchorId[childId])
806-
.forEach(grandchildId => applyAnchorToChild(grandchildId));
810+
.forEach(grandchildId => applyAnchorToChild(grandchildId, undefined, visited));
807811
}
808812
};
809813

@@ -880,8 +884,9 @@ var Anchor = Anchor || (() => {
880884

881885
// Case 2: changed object is an anchor — push to children for their unlocked components
882886
if (id in s.anchorChildrenByAnchorId) {
887+
const visited = new Set([id]);
883888
Object.keys(s.anchorChildrenByAnchorId[id])
884-
.forEach(childId => applyAnchorToChild(childId));
889+
.forEach(childId => applyAnchorToChild(childId, undefined, visited));
885890
}
886891

887892
refreshObjState(obj);

Anchor/anchor.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,11 @@ var Anchor = Anchor || (() => {
715715
* If onlyComponents is provided, only those components are applied.
716716
* Otherwise, all tracked but UNLOCKED components are applied.
717717
*/
718-
const applyAnchorToChild = (childId, onlyComponents) => {
718+
const applyAnchorToChild = (childId, onlyComponents, visited) => {
719+
if (!visited) visited = new Set();
720+
if (visited.has(childId)) return;
721+
visited.add(childId);
722+
719723
const s = state[SCRIPT_NAME];
720724
const info = s.anchorInfoByChildId[childId];
721725
if (!info) { setAnchor(childId, undefined); return; }
@@ -803,7 +807,7 @@ var Anchor = Anchor || (() => {
803807
// Propagate to this child's own children (if it is also an anchor)
804808
if (childId in s.anchorChildrenByAnchorId) {
805809
Object.keys(s.anchorChildrenByAnchorId[childId])
806-
.forEach(grandchildId => applyAnchorToChild(grandchildId));
810+
.forEach(grandchildId => applyAnchorToChild(grandchildId, undefined, visited));
807811
}
808812
};
809813

@@ -880,8 +884,9 @@ var Anchor = Anchor || (() => {
880884

881885
// Case 2: changed object is an anchor — push to children for their unlocked components
882886
if (id in s.anchorChildrenByAnchorId) {
887+
const visited = new Set([id]);
883888
Object.keys(s.anchorChildrenByAnchorId[id])
884-
.forEach(childId => applyAnchorToChild(childId));
889+
.forEach(childId => applyAnchorToChild(childId, undefined, visited));
885890
}
886891

887892
refreshObjState(obj);

0 commit comments

Comments
 (0)