I have created a function that generates a path of the target node from the root of the tree. But there is a small bug that i am stuck on.
Implementation:
interface FSNode {
name: string;
id: string;
type: 'file' | 'dir';
isPlaceholder?: boolean;
showIcons: boolean;
ext?: string;
children?: FSNode[];
}
const getFSNodePath = (tree: Array<FSNode>, targetNode: FSNode) => {
let currentPath = '';
function buildPath(subTree: Array<FSNode>, targetNode: FSNode): string | undefined{
for(const node of subTree){
// loop all and find if the node matches the target
if(node.id === targetNode.id){
// add the targetn node to path end
currentPath = currentPath '/' node.name;
return currentPath;
} else if(node.children){
// if it doesn't match, check if it has children
// if children present, check the node in them ( recursion )
// before checking the children, add the node name to path ( to build the path name )
currentPath = currentPath '/' node.name;
const path = buildPath(node.children, targetNode);
// only return(stop) the fn when there is any path ( coming from above case node.id === targetNode.id );
// if there is no path, means it couldn't find any thing, don't return ( stop ) because need to check the children
// of other nodes as well and if we return the loop will also stop.
if(path) return path;
}
}
}
const path = buildPath(tree, targetNode);
return path;
};
Bug:
- src
- app.js
- components
- index.html
if I want a path for index.html, the code first runs through the first two root nodes. It first checks the src folder and then its children. If it doesn't find the target node in its children, the code checks the second root node and eventually the third and returns the path. But it returns a wrong path something like this - /src/index.html
instead of /index.html
.
The possible solution to this would be to reset the currentPath
variable to empty strings after we get out of the nested folders. But i am not able figure out that where should i reset the currentPath variable.
CodePudding user response:
Every call of your buildPath
function is modifying the same currentPath
, so "/src"
is attached when it enters the first subtree, and not removed when exiting it.
To avoid this, make the path an argument of buildPath
:
const getFSNodePath = (root: FSNode, targetNode: FSNode): string => {
/**
* returns the path as an array of tree nodes, from `root` to `targetNode`
* or `null` if no child under the `path` matches the targetNode
*/
const buildPath = (currentPath: FsNode[], targetNode: FSNode): FSNode[] | null => {
const currentNode = currentPath[currentPath.length - 1];
if (currentNode.id === targetNode.id) return currentPath;
for (const child of currentNode.children ?? []) {
const pathFound = buildPath(currentPath.concat(child), targetNode);
if (pathFound) return pathFound;
}
return null;
}
const path = findPath([rootNode], targetNode) ?? []
return path.reduce((joined, node) => `${joined}/${node.name}`, '')
}
CodePudding user response:
The hint from @Naren worked. By passing the path to the buildPath function it resets the path when the function returns.
const getFSNodePath = (tree: Array<FSNode>, targetNode: FSNode) => {
function buildPath(subTree: Array<FSNode>, targetNode: FSNode, currentPath: string): string | undefined{
for(const node of subTree){
// loop all and find if the node matches the target
if(node.id === targetNode.id){
// add the targetn node to path end
return currentPath '/' node.name;
} else if(node.children){
// if it doesn't match, check if it has children
// if children present, check the node in them ( recursion )
// before checking the children, add the node name to path ( to build the path name )
const path = buildPath(node.children, targetNode, currentPath '/' node.name);
// only return(stop) the fn when there is any path ( coming from above case node.id === targetNode.id );
// if there is no path, means it couldn't find any thing, don't return ( stop ) because need to check the children
// of other nodes as well and if we return the loop will also stop.
if(path) return path;
}
}
}
const path = buildPath(tree, targetNode, '');
return path;
};