Skip to content

Commit

Permalink
feat: Expose MemoryHfsVolume, add copyObject and moveObject (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
nzakas authored Apr 26, 2024
1 parent bb7045e commit ad00da4
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/memory/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
*/

export * from "./memory-hfs.js";
export { MemoryHfsVolume } from "./memory-hfs-volume.js";
export { Hfs } from "@humanfs/core";
64 changes: 64 additions & 0 deletions packages/memory/src/memory-hfs-volume.js
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,70 @@ export class MemoryHfsVolume {
}));
}

/**
* Moves an object to a new parent.
* @param {string} id The ID of the object to move.
* @param {string} parentId The ID of the new parent directory.
* @returns {void}
* @throws {NotFoundError} If the object or parent is not found.
* @throws {DirectoryError} If the parent is not a directory.
*/
moveObject(id, parentId) {
const object = this.#objects.get(id);

if (!object) {
throw new NotFoundError(`moveObject ${id}`);
}

const parent = this.#objects.get(parentId);

if (!parent) {
throw new NotFoundError(`moveObject ${parentId}`);
}

if (parent.kind !== "directory") {
throw new DirectoryError(`moveObject ${parentId}`);
}

const directory = /** @type {MemoryHfsDirectory} */ (parent);

object.parent.delete(object.name);
directory.add(object);
}

/**
* Copies an object to a new parent.
* @param {string} id The ID of the object to copy.
* @param {string} parentId The ID of the new parent directory.
* @returns {void}
* @throws {NotFoundError} If the object or parent is not found.
* @throws {DirectoryError} If the parent is not a directory.
* @throws {DirectoryError} If the parent is a file.
*/
copyObject(id, parentId) {
const object = this.#objects.get(id);

if (!object) {
throw new NotFoundError(`copyObject ${id}`);
}

const parent = this.#objects.get(parentId);

if (!parent) {
throw new NotFoundError(`copyObject ${parentId}`);
}

if (parent.kind !== "directory") {
throw new DirectoryError(`copyObject ${parentId}`);
}

const directory = /** @type {MemoryHfsDirectory} */ (parent);
const copy = object.clone();

directory.add(copy);
this.#objects.set(copy.id, copy);
}

//-----------------------------------------------------------------------------
// Path-Based Methods
//-----------------------------------------------------------------------------
Expand Down
90 changes: 90 additions & 0 deletions packages/memory/tests/memory-hfs-volume.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,4 +475,94 @@ describe("MemoryHfsVolume", () => {
assert.throws(() => volume.readDirectoryObject(id), /EISDIR/);
});
});

describe("moveObject()", () => {
it("should move a file to a new location", () => {
volume.writeFile("file.txt", HELLO_WORLD);
volume.mkdirp("dir");

const id = volume.getObjectIdFromPath("file.txt");
const parentId = volume.getObjectIdFromPath("dir");
volume.moveObject(id, parentId);

const file = volume.readFile("dir/file.txt");
assert.deepEqual(file, HELLO_WORLD);
});

it("should move a directory to a new location", () => {
volume.mkdirp("dir");
volume.mkdirp("dir2");

const id = volume.getObjectIdFromPath("dir");
const parentId = volume.getObjectIdFromPath("dir2");
volume.moveObject(id, parentId);

const stat = volume.stat("dir2/dir");
assert.strictEqual(stat.kind, "directory");
});

it("should throw an error when the ID doesn't exist", () => {
assert.throws(() => volume.moveObject("file-1", "dir-1"), /ENOENT/);
});

it("should throw an error when the parent ID doesn't exist", () => {
volume.writeFile("file.txt", HELLO_WORLD);
const id = volume.getObjectIdFromPath("file.txt");
assert.throws(() => volume.moveObject(id, "dir-1"), /ENOENT/);
});

it("should throw an error when the parent ID is a file", () => {
volume.writeFile("file.txt", HELLO_WORLD);
volume.writeFile("file2.txt", HELLO_WORLD);

const id = volume.getObjectIdFromPath("file.txt");
const parentId = volume.getObjectIdFromPath("file2.txt");
assert.throws(() => volume.moveObject(id, parentId), /EISDIR/);
});
});

describe("copyObject()", () => {
it("should copy a file to a new location", () => {
volume.writeFile("file.txt", HELLO_WORLD);
volume.mkdirp("dir");

const id = volume.getObjectIdFromPath("file.txt");
const parentId = volume.getObjectIdFromPath("dir");
volume.copyObject(id, parentId);

const file = volume.readFile("dir/file.txt");
assert.deepEqual(file, HELLO_WORLD);
});

it("should copy a directory to a new location", () => {
volume.mkdirp("dir");
volume.mkdirp("dir2");

const id = volume.getObjectIdFromPath("dir");
const parentId = volume.getObjectIdFromPath("dir2");
volume.copyObject(id, parentId);

const stat = volume.stat("dir2/dir");
assert.strictEqual(stat.kind, "directory");
});

it("should throw an error when the ID doesn't exist", () => {
assert.throws(() => volume.copyObject("file-1", "dir-1"), /ENOENT/);
});

it("should throw an error when the parent ID doesn't exist", () => {
volume.writeFile("file.txt", HELLO_WORLD);
const id = volume.getObjectIdFromPath("file.txt");
assert.throws(() => volume.copyObject(id, "dir-1"), /ENOENT/);
});

it("should throw an error when the parent ID is a file", () => {
volume.writeFile("file.txt", HELLO_WORLD);
volume.writeFile("file2.txt", HELLO_WORLD);

const id = volume.getObjectIdFromPath("file.txt");
const parentId = volume.getObjectIdFromPath("file2.txt");
assert.throws(() => volume.copyObject(id, parentId), /EISDIR/);
});
});
});

0 comments on commit ad00da4

Please sign in to comment.