Add FilePathSet

This commit is contained in:
Robert
2023-06-13 12:18:23 +01:00
parent b0441956df
commit 51b94e3fed
2 changed files with 100 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import { containsPath } from "../pure/files";
/**
* A set of file paths.
*
* All paths in the set will not overlap. If a path is added to the set
* that is a parent or child of an existing path in the set, only the
* parent path will be kept.
*/
export class FilePathSet {
private paths: string[] = [];
/** Is the set currently empty */
public isEmpty(): boolean {
return this.paths.length === 0;
}
/**
* Adds the path to the set.
*
* The set will not contain overlapping paths. This means that if the
* new path is a child of an existing path in the set then it will not
* be added. And if the new path is a parent of any existing paths, then
* those existing paths will be removed. This can cause the "size" of
* the set of decrease, but it won't go from non-zero to zero.
*/
public addPath(path: string): void {
if (this.paths.some((p) => containsPath(p, path))) {
// The new path is a child of an existing path, so don't add it.
return;
} else {
// Remove any existing paths that are children of the new path.
this.paths = this.paths.filter((p) => !containsPath(path, p));
this.paths.push(path);
}
}
/** Removes and returns a path from the set, if the set of non-empty. */
public popPath(): string | undefined {
return this.paths.shift();
}
}

View File

@@ -0,0 +1,58 @@
import { FilePathSet } from "../../../src/common/file-path-set";
describe("FilePathSet", () => {
describe("isEmpty", () => {
it("should return true only when set is empty", () => {
const v = new FilePathSet();
expect(v.isEmpty()).toBe(true);
v.addPath("/foo");
expect(v.isEmpty()).toBe(false);
v.popPath();
expect(v.isEmpty()).toBe(true);
});
});
describe("addPath / popPath", () => {
it("should keep all paths when they don't overlap", () => {
const v = new FilePathSet();
v.addPath("/foo");
v.addPath("/bar");
v.addPath("/baz");
expect(v.popPath()).toBe("/foo");
expect(v.popPath()).toBe("/bar");
expect(v.popPath()).toBe("/baz");
expect(v.popPath()).toBe(undefined);
});
it("should only keep one copy of repeated paths", () => {
const v = new FilePathSet();
v.addPath("/foo");
v.addPath("/foo");
v.addPath("/foo");
expect(v.popPath()).toBe("/foo");
expect(v.popPath()).toBe(undefined);
});
it("should adding adding paths that are children of existing paths", () => {
const v = new FilePathSet();
v.addPath("/foo");
v.addPath("/foo/bar");
v.addPath("/foo/baz");
expect(v.popPath()).toBe("/foo");
expect(v.popPath()).toBe(undefined);
});
it("should remove existing paths that are children of new paths", () => {
const v = new FilePathSet();
v.addPath("/foo");
v.addPath("/bar/baz");
v.addPath("/bar/qux");
v.addPath("/bar");
expect(v.popPath()).toBe("/foo");
expect(v.popPath()).toBe("/bar");
expect(v.popPath()).toBe(undefined);
});
});
});