[Utils] Fix findInTree (#32)

This commit is contained in:
redstonekasi 2023-03-08 01:39:11 +01:00 committed by GitHub
parent 2201ff3a1d
commit c54f9fe426
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 30 deletions

7
src/def.d.ts vendored
View file

@ -35,7 +35,8 @@ interface Logger {
verbose: LoggerFunction;
}
type SearchFilter = (tree: any) => boolean;
type SearchTree = Record<string, any>;
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<Response>;
unfreeze: (obj: object) => object;
};

View file

@ -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<FindInTreeOptions>, 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 });
}
export default (
tree: SearchTree,
filter: SearchFilter,
{
walkable = [],
ignore = [],
maxDepth = 100
}: FindInTreeOptions = {},
): any | undefined => treeSearch(tree, filter, { walkable, ignore, maxDepth }, 0);