All files / src/shared/lib/entities buildEntityNavigatorItems.ts

0% Statements 0/49
0% Branches 0/24
0% Functions 0/9
0% Lines 0/46

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119                                                                                                                                                                                                                                             
type Entity = {
  id: string;
  name: string;
};
 
export type EntityNavigatorItem<T> = {
  id: string;
  type: "entity" | "folder";
  name: string;
  filename: string;
  nestLevel?: number;
  entity?: T;
};
 
const collator = new Intl.Collator(undefined, {
  numeric: true,
  sensitivity: "base",
});
 
const sortByName = (a: Entity, b: Entity) => {
  return collator.compare(a.name, b.name);
};
 
export const entityParentFolders = <T extends { name: string }>(
  entity: T
): string[] => {
  const parts = entity.name.split(/[/\\]/).slice(0, -1);
  const folders: string[] = [];
  while (parts.length > 0) {
    folders.push(parts.join("/"));
    folders.push(parts.join("\\"));
    parts.pop();
  }
  return folders;
};
 
export const buildEntityNavigatorItems = <T extends Entity>(
  entities: T[],
  openFolders: string[],
  searchTerm: string,
  customSort?: (a: T, b: T) => number,
  nestOffset = 0
): EntityNavigatorItem<T>[] => {
  const result: EntityNavigatorItem<T>[] = [];
  const uniqueFolders = new Set<string>();
 
  const isVisible = (filename: string, nestLevel?: number): boolean => {
    Iif (nestLevel === undefined || nestLevel === nestOffset) return true;
    const pathSegments = filename.split(/[\\/]/);
    pathSegments.pop();
    let pathCheck = "";
    return pathSegments.every((segment, index) => {
      pathCheck += (index ? "/" : "") + segment;
      return openFolders.includes(pathCheck);
    });
  };
 
  Iif (searchTerm.length > 0) {
    const searchTermUpperCase = searchTerm.toLocaleUpperCase();
    entities
      .filter((s) => s.name.toLocaleUpperCase().includes(searchTermUpperCase))
      .sort(customSort ?? sortByName)
      .forEach((entity) => {
        result.push({
          id: entity.id,
          type: "entity",
          name: entity.name,
          filename: entity.name.replace(/.*[/\\]/, ""),
          nestLevel: nestOffset,
          entity,
        });
      });
    return result;
  }
 
  entities
    .slice()
    .sort(customSort ?? sortByName)
    .forEach((entity) => {
      const path = entity.name;
      const parts = path.split(/[\\/]/);
      let currentPath = "";
 
      parts.forEach((part, index) => {
        const isLast = index === parts.length - 1;
        currentPath += (currentPath ? "/" : "") + part;
        if (isLast) {
          const nestLevel =
            nestOffset + (parts.length > 1 ? parts.length - 1 : 0);
          Iif (!isVisible(currentPath, nestLevel)) {
            return;
          }
          result.push({
            id: entity.id,
            type: "entity",
            name: currentPath,
            filename: part,
            nestLevel,
            entity,
          });
        } else Iif (!uniqueFolders.has(currentPath)) {
          Iif (!isVisible(currentPath, index + nestOffset)) {
            return;
          }
          uniqueFolders.add(currentPath);
          result.push({
            id: currentPath,
            type: "folder",
            name: currentPath,
            filename: part,
            nestLevel: index + nestOffset,
          });
        }
      });
    });
 
  return result;
};