diff --git a/src/def.d.ts b/src/def.d.ts index 3f4d11d..43531a6 100644 --- a/src/def.d.ts +++ b/src/def.d.ts @@ -35,7 +35,8 @@ interface Logger { verbose: LoggerFunction; } -type SearchFilter = (tree: any) => boolean; +type SearchTree = Record; +type SearchFilter = (tree: SearchTree) => boolean; interface FindInTreeOptions { walkable?: string[]; ignore?: string[]; @@ -349,8 +350,8 @@ interface VendettaObject { }; utils: { copyText: (content: string) => void; - findInReactTree: (tree: { [key: string]: any }, filter: SearchFilter) => any; - findInTree: (tree: { [key: string]: any }, filter: SearchFilter, options: FindInTreeOptions) => any; + findInReactTree: (tree: SearchTree, filter: SearchFilter) => any; + findInTree: (tree: SearchTree, filter: SearchFilter, options: FindInTreeOptions) => any; safeFetch: (input: RequestInfo, options: RequestInit) => Promise; unfreeze: (obj: object) => object; }; diff --git a/src/lib/utils/findInTree.ts b/src/lib/utils/findInTree.ts index 449e665..f8a19cd 100644 --- a/src/lib/utils/findInTree.ts +++ b/src/lib/utils/findInTree.ts @@ -1,38 +1,45 @@ +// This has been completely reimplemented at this point, but the disclaimer at the end of disclaimers still counts. // https://github.com/Cordwood/Cordwood/blob/91c0b971bbf05e112927df75415df99fa105e1e7/src/lib/utils/findInTree.ts -import { FindInTreeOptions, SearchFilter } from "@types"; +import { FindInTreeOptions, SearchTree, SearchFilter } from "@types"; -export default function findInTree(tree: { [key: string]: any }, filter: SearchFilter, { walkable = [], ignore = [], maxDepth = 100 }: FindInTreeOptions = {}): any { - let iteration = 0; +function treeSearch(tree: SearchTree, filter: SearchFilter, opts: Required, depth: number): any { + if (depth > opts.maxDepth) return; + if (!tree) return; - function doSearch(tree: { [key: string]: any }, filter: SearchFilter, { walkable = [], ignore = [] }: FindInTreeOptions = {}): any { - iteration += 1; - if (iteration > maxDepth) return; + try { + if (filter(tree)) return tree; + } catch {} - if (typeof filter === "string") { - if (tree.hasOwnProperty(filter)) return tree[filter]; - } else if (filter(tree)) return tree; + if (Array.isArray(tree)) { + for (const item of tree) { + if (typeof item !== "object" || item === null) continue; - if (!tree) return; - - if (Array.isArray(tree)) { - for (const item of tree) { - const found = doSearch(item, filter, { walkable, ignore }); + try { + const found = treeSearch(item, filter, opts, depth + 1); if (found) return found; - } - } else if (typeof tree === "object") { - for (const key of Object.keys(tree)) { - if (walkable != null && walkable.includes(key)) continue; + } catch {} + } + } else if (typeof tree === "object") { + for (const key of Object.keys(tree)) { + if (typeof tree[key] !== "object" || tree[key] === null) continue; + if (opts.walkable.length && !opts.walkable.includes(key)) continue; + if (opts.ignore.includes(key)) continue; - if (ignore.includes(key)) continue; - - try { - const found = doSearch(tree[key], filter, { walkable, ignore }); - if (found) return found; - } catch {} - } + try { + const found = treeSearch(tree[key], filter, opts, depth + 1); + if (found) return found; + } catch {} } } +} - return doSearch(tree, filter, { walkable, ignore }); -} \ No newline at end of file +export default ( + tree: SearchTree, + filter: SearchFilter, + { + walkable = [], + ignore = [], + maxDepth = 100 + }: FindInTreeOptions = {}, +): any | undefined => treeSearch(tree, filter, { walkable, ignore, maxDepth }, 0);