175 lines
4.4 KiB
TypeScript
175 lines
4.4 KiB
TypeScript
import type { FileNode } from "../types";
|
|
|
|
export const addPaths = (node: FileNode, parentPath: string = ""): FileNode => {
|
|
const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name;
|
|
const newNode = { ...node, path: currentPath };
|
|
if (newNode.children) {
|
|
newNode.children = newNode.children.map((child) =>
|
|
addPaths(child, currentPath),
|
|
);
|
|
}
|
|
return newNode;
|
|
};
|
|
|
|
export const getAllFolderPaths = (node: FileNode): string[] => {
|
|
let paths: string[] = [];
|
|
if (node.type === "folder") {
|
|
paths.push(node.path || node.name);
|
|
if (node.children) {
|
|
node.children.forEach((child) => {
|
|
paths = [...paths, ...getAllFolderPaths(child)];
|
|
});
|
|
}
|
|
}
|
|
return paths;
|
|
};
|
|
|
|
export const findNode = (node: FileNode, path: string): FileNode | null => {
|
|
if (node.path === path) return node;
|
|
if (node.children) {
|
|
for (const child of node.children) {
|
|
const found = findNode(child, path);
|
|
if (found) return found;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const deleteNode = (node: FileNode, path: string): FileNode | null => {
|
|
if (node.path === path) return null;
|
|
|
|
if (node.children) {
|
|
const filtered = node.children.filter((child) => child.path !== path);
|
|
const mapped = filtered
|
|
.map((child) => deleteNode(child, path))
|
|
.filter((child): child is FileNode => child !== null);
|
|
return { ...node, children: mapped };
|
|
}
|
|
return node;
|
|
};
|
|
|
|
export const addNode = (
|
|
node: FileNode,
|
|
parentPath: string,
|
|
newNode: FileNode,
|
|
): FileNode => {
|
|
if (node.path === parentPath) {
|
|
const newPath = addPaths(newNode, node.path);
|
|
return { ...node, children: [...(node.children || []), newPath] };
|
|
}
|
|
if (node.children) {
|
|
return {
|
|
...node,
|
|
children: node.children.map((child) =>
|
|
addNode(child, parentPath, newNode),
|
|
),
|
|
};
|
|
}
|
|
return node;
|
|
};
|
|
|
|
export const renameNode = (
|
|
node: FileNode,
|
|
oldPath: string,
|
|
newName: string,
|
|
): FileNode | null => {
|
|
if (node.path === oldPath) {
|
|
const pathParts = node.path?.split("/") || [];
|
|
pathParts[pathParts.length - 1] = newName;
|
|
const newPath = pathParts.join("/");
|
|
const renamedNode = { ...node, name: newName, path: newPath };
|
|
|
|
if (renamedNode.children) {
|
|
renamedNode.children = renamedNode.children.map((child) => {
|
|
const oldChildPath = child.path || "";
|
|
const newChildPath = oldChildPath.replace(oldPath, newPath);
|
|
return (
|
|
renameNode(
|
|
child,
|
|
oldChildPath,
|
|
newChildPath.split("/").pop() || "",
|
|
) || child
|
|
);
|
|
});
|
|
}
|
|
return renamedNode;
|
|
}
|
|
|
|
if (node.children) {
|
|
return {
|
|
...node,
|
|
children: node.children.map(
|
|
(child) => renameNode(child, oldPath, newName) || child,
|
|
),
|
|
};
|
|
}
|
|
return node;
|
|
};
|
|
|
|
export const filterTree = (node: FileNode, query: string): FileNode | null => {
|
|
if (!query) return node;
|
|
const lowerQuery = query.toLowerCase();
|
|
|
|
if (node.type === "file") {
|
|
if (node.name.toLowerCase().includes(lowerQuery)) return node;
|
|
return null;
|
|
}
|
|
|
|
if (node.children) {
|
|
const filteredChildren = node.children
|
|
.map((child) => filterTree(child, query))
|
|
.filter((child): child is FileNode => child !== null);
|
|
|
|
if (filteredChildren.length > 0) {
|
|
return { ...node, children: filteredChildren };
|
|
}
|
|
}
|
|
|
|
if (node.name.toLowerCase().includes(lowerQuery)) return node;
|
|
return null;
|
|
};
|
|
|
|
export const collectPathsToExpand = (
|
|
node: FileNode,
|
|
query: string,
|
|
): Set<string> => {
|
|
const paths = new Set<string>();
|
|
if (!query) return paths;
|
|
|
|
const lowerQuery = query.toLowerCase();
|
|
|
|
const search = (n: FileNode, currentPath: string) => {
|
|
if (n.name.toLowerCase().includes(lowerQuery)) {
|
|
const pathParts = currentPath.split("/");
|
|
for (let i = 1; i < pathParts.length; i++) {
|
|
paths.add(pathParts.slice(0, i).join("/"));
|
|
}
|
|
}
|
|
if (n.children) {
|
|
n.children.forEach((child) => {
|
|
const childPath = child.path || `${currentPath}/${child.name}`;
|
|
search(child, childPath);
|
|
});
|
|
}
|
|
};
|
|
|
|
search(node, node.path || node.name);
|
|
return paths;
|
|
};
|
|
|
|
export const getLanguage = (path: string) => {
|
|
const ext = path.split(".").pop();
|
|
const map: Record<string, string> = {
|
|
py: "python",
|
|
js: "javascript",
|
|
ts: "typescript",
|
|
jsx: "javascript",
|
|
tsx: "typescript",
|
|
json: "json",
|
|
md: "markdown",
|
|
css: "css",
|
|
html: "html",
|
|
};
|
|
return map[ext || ""] || "plaintext";
|
|
};
|