Skip to content

Commit 27ab7aa

Browse files
.
1 parent 163a484 commit 27ab7aa

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.commonmark.node;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* Immutable configuration for limiting node traversal depth.
7+
* <p>
8+
* Traversal limits are enforced by {@link AbstractVisitor#visitChildren(Node)} and renderer recursion through the
9+
* public renderer contexts. Helper traversals outside those entry points need to opt in explicitly.
10+
*/
11+
public final class NodeTraversal {
12+
13+
public enum LimitExceededBehavior {
14+
FAIL_FAST,
15+
SUCCEED_LOSSY
16+
}
17+
18+
private static final NodeTraversal UNLIMITED = new NodeTraversal(null, null);
19+
20+
private final Integer maxDepth;
21+
private final LimitExceededBehavior limitExceededBehavior;
22+
23+
private NodeTraversal(Integer maxDepth, LimitExceededBehavior limitExceededBehavior) {
24+
this.maxDepth = maxDepth;
25+
this.limitExceededBehavior = limitExceededBehavior;
26+
}
27+
28+
public static NodeTraversal unlimited() {
29+
return UNLIMITED;
30+
}
31+
32+
public static NodeTraversal failFast(int maxDepth) {
33+
return limited(maxDepth, LimitExceededBehavior.FAIL_FAST);
34+
}
35+
36+
public static NodeTraversal succeedLossy(int maxDepth) {
37+
return limited(maxDepth, LimitExceededBehavior.SUCCEED_LOSSY);
38+
}
39+
40+
public boolean isUnlimited() {
41+
return maxDepth == null;
42+
}
43+
44+
/**
45+
* @return the inclusive max depth, or {@code null} if this traversal is unlimited
46+
*/
47+
public Integer getMaxDepth() {
48+
return maxDepth;
49+
}
50+
51+
/**
52+
* @return the behavior when the depth limit is exceeded, or {@code null} if this traversal is unlimited
53+
*/
54+
public LimitExceededBehavior getLimitExceededBehavior() {
55+
return limitExceededBehavior;
56+
}
57+
58+
@Override
59+
public boolean equals(Object o) {
60+
if (this == o) {
61+
return true;
62+
}
63+
if (!(o instanceof NodeTraversal)) {
64+
return false;
65+
}
66+
NodeTraversal that = (NodeTraversal) o;
67+
return Objects.equals(maxDepth, that.maxDepth) && limitExceededBehavior == that.limitExceededBehavior;
68+
}
69+
70+
@Override
71+
public int hashCode() {
72+
return Objects.hash(maxDepth, limitExceededBehavior);
73+
}
74+
75+
@Override
76+
public String toString() {
77+
if (isUnlimited()) {
78+
return "NodeTraversal.unlimited()";
79+
}
80+
return "NodeTraversal." + (limitExceededBehavior == LimitExceededBehavior.FAIL_FAST ? "failFast(" : "succeedLossy(") + maxDepth + ")";
81+
}
82+
83+
private static NodeTraversal limited(int maxDepth, LimitExceededBehavior limitExceededBehavior) {
84+
if (maxDepth < 0) {
85+
throw new IllegalArgumentException("maxDepth must be >= 0");
86+
}
87+
return new NodeTraversal(maxDepth, Objects.requireNonNull(limitExceededBehavior, "limitExceededBehavior must not be null"));
88+
}
89+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.commonmark.node;
2+
3+
/**
4+
* Thrown when a traversal attempts to descend beyond its configured max depth.
5+
*/
6+
public final class NodeTraversalLimitExceededException extends RuntimeException {
7+
8+
private final int maxDepth;
9+
private final int attemptedDepth;
10+
11+
public NodeTraversalLimitExceededException(int maxDepth, int attemptedDepth) {
12+
super("Node traversal exceeded max depth of " + maxDepth + " when attempting to visit child depth " + attemptedDepth);
13+
this.maxDepth = maxDepth;
14+
this.attemptedDepth = attemptedDepth;
15+
}
16+
17+
public int getMaxDepth() {
18+
return maxDepth;
19+
}
20+
21+
public int getAttemptedDepth() {
22+
return attemptedDepth;
23+
}
24+
}

0 commit comments

Comments
 (0)