Skip to content

Commit 41a7936

Browse files
committed
feat: walk json model can delete nodes
Signed-off-by: Christian Stewart <christian@aperture.us>
1 parent 8aae726 commit 41a7936

File tree

1 file changed

+44
-8
lines changed

1 file changed

+44
-8
lines changed

src/model/walk.ts

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
11
import { IJsonModel, IJsonBorderNode, IJsonRowNode, IJsonTabSetNode, IJsonTabNode } from "./IJsonModel";
22

3+
/** Union type representing all possible node types in the JSON model */
34
export type JsonNode = IJsonBorderNode | IJsonRowNode | IJsonTabSetNode | IJsonTabNode;
4-
export type ModelVisitor = (node: JsonNode, parent: JsonNode | null) => boolean | void;
5+
export interface VisitorResult {
6+
/** If true, do not process any children of the current node */
7+
skipChildren?: boolean;
8+
/** If true, remove the current node from its parent's children array */
9+
delete?: boolean;
10+
}
11+
12+
/**
13+
* Function type for visiting nodes in the model tree
14+
* @param node The current node being visited
15+
* @param parent The parent of the current node, or null for top-level nodes
16+
* @returns
17+
* - void/true to continue normally
18+
* - false to stop traversal completely
19+
* - VisitorResult to control traversal or delete nodes
20+
*/
21+
export type ModelVisitor = (node: JsonNode, parent: JsonNode | null) => void | boolean | VisitorResult;
522

623
/**
724
* Finds a node by its ID in the model tree
@@ -15,9 +32,9 @@ export function findJsonNodeById(model: IJsonModel, id: string): JsonNode | unde
1532
walkJsonModel(model, (node) => {
1633
if ("id" in node && node.id === id) {
1734
result = node;
18-
return false; // stop walking
35+
return { skipChildren: true }; // found it, no need to check children
1936
}
20-
return true;
37+
return true
2138
});
2239

2340
return result;
@@ -27,7 +44,11 @@ export function findJsonNodeById(model: IJsonModel, id: string): JsonNode | unde
2744
* Walks an IJsonModel tree using a stack-based approach, calling visitor for each node.
2845
* The walk processes borders first, then traverses the main layout in a depth-first manner.
2946
* @param model The model to traverse
30-
* @param visitor Callback called for each node in the tree. Return false to stop the traversal.
47+
* @param visitor Callback called for each node in the tree. The visitor can:
48+
* - Return false to stop the traversal completely
49+
* - Return {skipChildren: true} to skip processing children
50+
* - Return {delete: true} to remove the current node from its parent
51+
* - Return nothing or true to continue normally
3152
* The visitor receives the current node and its parent (null for top-level nodes).
3253
*/
3354
export function walkJsonModel(model: IJsonModel, visitor: ModelVisitor): void {
@@ -48,13 +69,28 @@ export function walkJsonModel(model: IJsonModel, visitor: ModelVisitor): void {
4869
while (stack.length > 0) {
4970
const [node, parent] = stack.pop()!;
5071

51-
// Visit current node, stop if visitor returns false
52-
if (visitor(node, parent) === false) {
72+
// Visit current node
73+
const result = visitor(node, parent);
74+
75+
// Handle different return types
76+
if (result === false) {
5377
break;
5478
}
5579

56-
// Add children to stack in reverse order so they're processed in forward order
57-
if ("children" in node) {
80+
const visitorResult = typeof result === 'object' ? result : undefined;
81+
82+
// Handle deletion if requested
83+
if (visitorResult?.delete && parent && "children" in parent) {
84+
const index = parent.children.findIndex(child => child === node);
85+
if (index !== -1) {
86+
parent.children.splice(index, 1);
87+
continue;
88+
}
89+
}
90+
91+
// Skip children if requested or process them
92+
if (!visitorResult?.skipChildren && "children" in node) {
93+
// Add children to stack in reverse order so they're processed in forward order
5894
for (let i = node.children.length - 1; i >= 0; i--) {
5995
stack.push([node.children[i], node]);
6096
}

0 commit comments

Comments
 (0)