fork of hey-api/openapi-ts because I need some additional things
1import type { StructureItem, StructureShell } from './types';
2
3export class StructureNode {
4 /** Nested nodes within this node. */
5 children: Map<string, StructureNode> = new Map();
6 /** Items contained in this node. */
7 items: Array<StructureItem> = [];
8 /** The name of this node (e.g., "Users", "Accounts"). */
9 name: string;
10 /** Parent node in the hierarchy. Undefined if this is the root node. */
11 parent?: StructureNode;
12 /** Shell claimed for this node. */
13 shell?: StructureShell;
14 /** Source of the claimed shell. */
15 shellSource?: symbol;
16 /** True if this is a virtual root. */
17 virtual: boolean;
18
19 constructor(
20 name: string,
21 parent?: StructureNode,
22 options?: {
23 virtual?: boolean;
24 },
25 ) {
26 this.name = name;
27 this.parent = parent;
28 this.virtual = options?.virtual ?? false;
29 }
30
31 get isRoot(): boolean {
32 return !this.parent;
33 }
34
35 /**
36 * Gets or creates a child node.
37 *
38 * If the child doesn't exist, it's created automatically.
39 *
40 * @param name - The name of the child node
41 * @returns The child node instance
42 */
43 child(name: string): StructureNode {
44 if (!this.children.has(name)) {
45 this.children.set(name, new StructureNode(name, this));
46 }
47 return this.children.get(name)!;
48 }
49
50 /**
51 * Gets the full path of this node in the hierarchy.
52 *
53 * @returns An array of node names from the root to this node
54 */
55 getPath(): ReadonlyArray<string> {
56 const path: Array<string> = [];
57 // eslint-disable-next-line @typescript-eslint/no-this-alias
58 let cursor: StructureNode | undefined = this;
59 while (cursor) {
60 path.unshift(cursor.name);
61 cursor = cursor.parent;
62 }
63 return path;
64 }
65
66 /**
67 * Yields items from a specific source with typed data.
68 *
69 * @param source - The source symbol to filter by
70 * @returns Generator of items from that source
71 */
72 *itemsFrom<T = unknown>(source: symbol): Generator<StructureItem & { data: T }> {
73 for (const item of this.items) {
74 if (item.source === source) {
75 yield item as StructureItem & { data: T };
76 }
77 }
78 }
79
80 /**
81 * Walk all nodes in the structure (depth-first, post-order).
82 *
83 * @returns Generator of all structure nodes
84 */
85 *walk(): Generator<StructureNode> {
86 for (const node of this.children.values()) {
87 yield* node.walk();
88 }
89 yield this;
90 }
91}