fork of hey-api/openapi-ts because I need some additional things
at feat/use-query-options-param 90 lines 2.3 kB view raw
1import { StructureNode } from './node'; 2import type { StructureInsert } from './types'; 3 4export class StructureModel { 5 /** Root nodes mapped by their names. */ 6 private _roots: Map<string, StructureNode> = new Map(); 7 /** Node for data without a specific root. */ 8 private _virtualRoot?: StructureNode; 9 10 /** 11 * Get all root nodes. 12 */ 13 get roots(): ReadonlyArray<StructureNode> { 14 const roots = Array.from(this._roots.values()); 15 if (this._virtualRoot) roots.unshift(this._virtualRoot); 16 return roots; 17 } 18 19 /** 20 * Insert data into the structure. 21 */ 22 insert(args: StructureInsert): void { 23 const { data, locations, source } = args; 24 for (const location of locations) { 25 const { path, shell } = location; 26 const fullPath = path.filter((s): s is string => Boolean(s)); 27 const segments = fullPath.slice(0, -1); 28 const name = fullPath[fullPath.length - 1]; 29 30 if (!name) { 31 throw new Error('Cannot insert data without path.'); 32 } 33 34 let cursor: StructureNode | null = null; 35 36 for (const segment of segments) { 37 if (!cursor) { 38 cursor = this.root(segment); 39 } else { 40 cursor = cursor.child(segment); 41 } 42 43 if (shell && !cursor.shell) { 44 cursor.shell = shell; 45 cursor.shellSource = source; 46 } 47 } 48 49 if (!cursor) { 50 cursor = this.root(null); 51 } 52 53 cursor.items.push({ data, location: fullPath, source }); 54 } 55 } 56 57 /** 58 * Gets or creates a root by name. 59 * 60 * If the root doesn't exist, it's created automatically. 61 * 62 * @param name - The name of the root 63 * @returns The root instance 64 */ 65 root(name: string | null): StructureNode { 66 if (!name) { 67 return (this._virtualRoot ??= new StructureNode('', undefined, { 68 virtual: true, 69 })); 70 } 71 if (!this._roots.has(name)) { 72 this._roots.set(name, new StructureNode(name)); 73 } 74 return this._roots.get(name)!; 75 } 76 77 /** 78 * Walk all nodes in the structure (depth-first, post-order). 79 * 80 * @returns Generator of all structure nodes 81 */ 82 *walk(): Generator<StructureNode> { 83 if (this._virtualRoot) { 84 yield* this._virtualRoot.walk(); 85 } 86 for (const root of this._roots.values()) { 87 yield* root.walk(); 88 } 89 } 90}