working: update file-graph-algorithm

This commit is contained in:
Chen, Tai-Lin committed 2023-08-25 20:05:28 +08:00
1 parent ab570e9c1b
commit 821896f292
5 files changed
+162 -36

No files matched your search

+7
View File
@@ -12,3 +12,10 @@ export class ParentNotExistsError extends Error {
this.name = 'ParentNotExistsError' this.name = 'ParentNotExistsError'
} }
} }
export class FileNotExistsError extends Error {
constructor(message) {
super(message)
this.name = 'FileNotExistsError'
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { basename } from './utils' import { basename } from './utils.js'
export default class File { export default class File {
constructor({ path, type, discovered }) { constructor({ path, type, discovered }) {
+39 -16
View File
@@ -1,35 +1,54 @@
import FileNode from './fileNode.js' import FileNode from './fileNode.js'
import { FileNotExistsError } from './errors.js'
export default class FileGraph { export default class FileGraph {
constructor(root) { constructor(root) {
this.root = new FileNode(root) this.root = new FileNode(root)
} }
add(file) { add(files) {
// Logic to add the file node to the graph // Logic to add the file node to the graph
// You can implement the logic to find the appropriate location in the file graph // You can implement the logic to find the appropriate location in the file graph
// If the file node already exists, throw an error // If the file node already exists, throw an error
const newNode = new FileNode(file) files.forEach((file) => {
this.root.addChild(newNode, { makeParents: true }) this.root.addChild(file, { makeParents: true })
})
} }
remove(file) { remove(files) {
// Logic to remove a file node from the graph // Logic to remove a file node from the graph
// If the file node is a folder, also remove all children // If the file node is a folder, also remove all children
// If the file node doesn't exist, throw an error // If the file node doesn't exist, throw an error
const nodeToRemove = this.findNode(file) files.forEach((file) => {
if (nodeToRemove) { const pathFolders = file.path
const parentNode = this.findParentNode(file) .split('/')
if (parentNode) { .filter((folder) => folder.length > 0)
parentNode.children = parentNode.children.filter( const fileName = pathFolders.pop()
(child) => child !== nodeToRemove let currentNode = this.root
for (const folder of pathFolders) {
currentNode = currentNode.children.find(
(child) => child.name === folder
)
if (!currentNode) {
throw new FileNotExistsError(
`File not found: ${fileToFind.path}, ${this.toString()}`
)
}
}
if (!currentNode.children.some((child) => child.name === fileName)) {
throw new FileNotExistsError(
`File not found: ${file.path}, ${this.toString()}`
)
} else {
currentNode.children = currentNode.children.filter(
(child) => child.name !== fileName
) )
} }
} else { })
throw new Error(`File node not found: ${file.path}`)
}
} }
discover(eventFiles) { discover(eventFiles) {
@@ -37,13 +56,17 @@ export default class FileGraph {
// Overwrite the file graph with the provided files // Overwrite the file graph with the provided files
// Remove file nodes that don't exist anymore and add new ones // Remove file nodes that don't exist anymore and add new ones
const updatedNodes = eventFiles.map((file) => new FileNode(file)) const newRoot = new FileNode({
this.root = new FileNode({
path: '/', path: '/',
type: 'folder', type: 'folder',
discovered: true, discovered: true,
children: updatedNodes,
}) })
eventFiles.forEach((file) => {
newRoot.addChild(file, { makeParents: true })
})
this.root = newRoot
} }
handleEvent(event) { handleEvent(event) {
+110
View File
@@ -0,0 +1,110 @@
import FileGraph from './fileGraph.js'
import FileNode from './fileNode.js'
describe('FileGraph', () => {
let root
beforeEach(() => {
root = new FileNode({
path: '/',
type: 'folder',
discovered: true,
})
})
test('add files to graph', () => {
const fileGraph = new FileGraph(root)
const filesToAdd = [
{
path: '/home/user/file1.txt',
type: 'file',
discovered: true,
},
{
path: '/home/user/folder1',
type: 'folder',
discovered: true,
},
]
fileGraph.add(filesToAdd)
console.log(fileGraph.root.toString())
expect(fileGraph.root.children.length).toBe(1)
expect(fileGraph.root.children[0].children[0].children.length).toBe(2)
})
test('remove files from graph', () => {
const fileGraph = new FileGraph(root)
const filesToAdd = [
{
path: '/home/user/file1.txt',
type: 'file',
discovered: true,
},
{
path: '/home/user/folder1',
type: 'folder',
discovered: true,
},
]
fileGraph.add(filesToAdd)
const filesToRemove = [
{
path: '/home/user/folder1',
type: 'folder',
},
]
fileGraph.remove(filesToRemove)
console.log(fileGraph.root.toString())
expect(fileGraph.root.children[0].children[0].children.length).toBe(1)
})
test('discover new files', () => {
const fileGraph = new FileGraph(root)
const filesToAdd = [
{
path: '/home/user/file1.txt',
type: 'file',
discovered: true,
},
{
path: '/home/user/folder1',
type: 'folder',
discovered: true,
},
]
fileGraph.add(filesToAdd)
expect(fileGraph.root.children[0].children[0].children.length).toBe(2)
const newFiles = [
{
path: '/home/newfile.txt',
type: 'file',
discovered: true,
},
{
path: '/home/user/file1.txt',
type: 'file',
discovered: true,
},
]
fileGraph.discover(newFiles)
console.log(fileGraph.root.toString())
expect(fileGraph.root.children[0].children.length).toBe(2)
expect(fileGraph.root.children[0].children[0].name).toBe('newfile.txt')
expect(fileGraph.root.children[0].children[0].children[0].name).toBe(
'file1.txt'
)
})
})
+5 -19
View File
@@ -1,5 +1,9 @@
import File from './file.js' import File from './file.js'
import { DuplicateItemError, ParentNotExistsError } from './errors.js' import {
DuplicateItemError,
ParentNotExistsError,
FileNotExistsError,
} from './errors.js'
import { basename, dirname } from './utils.js' import { basename, dirname } from './utils.js'
export default class FileNode extends File { export default class FileNode extends File {
@@ -92,22 +96,4 @@ export default class FileNode extends File {
.join('') .join('')
return `${indent}${this.name}${suffix}\n${childrenString}` return `${indent}${this.name}${suffix}\n${childrenString}`
} }
findNode(fileToFind) {
const pathFolders = fileToFind.path
.split('/')
.filter((folder) => folder.length > 0)
let currentNode = this
for (const folder of pathFolders) {
currentNode = currentNode.children.find(
(child) => child.name === folder && child.type === 'folder'
)
if (!currentNode) {
return null
}
}
return currentNode
}
} }