Add FilePathSet
This commit is contained in:
42
extensions/ql-vscode/src/common/file-path-set.ts
Normal file
42
extensions/ql-vscode/src/common/file-path-set.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user