Skip to content

Commit

Permalink
Added FileListState
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Apr 9, 2024
1 parent 4e84e12 commit b841332
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/FileListState.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { FileListDir } from "./api/FileListDir";
import { FileListSort } from "./sort/FileListSort";

export interface FileListState {
readonly offset: number;
readonly index: number;
readonly currDir: FileListDir;
readonly selectedNames: Set<string>;
readonly isActive: boolean;
readonly diskSpace?: number;
readonly sort: FileListSort;
}
76 changes: 76 additions & 0 deletions src/FileListState.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* @typedef {import("./api/FileListItem").FileListItem} FileListItem
* @typedef {import("./FileListState").FileListState} FileListState
*/

import { isSet } from "node:util/types";
import SortMode from "./sort/SortMode.mjs";

/**
* @returns {FileListState}
*/
function FileListState() {
return {
offset: 0,
index: 0,
currDir: { path: "", isRoot: false, items: [] },
selectedNames: new Set(),
isActive: false,
sort: { mode: SortMode.Name, asc: true },
};
}

/** @type {(s: FileListState) => FileListItem | undefined} */
FileListState.currentItem = (s) => {
const itemIndex = s.offset + s.index;
if (itemIndex >= 0 && itemIndex < s.currDir.items.length) {
return s.currDir.items[itemIndex];
}
return undefined;
};

/** @type {(s: FileListState) => FileListItem[]} */
FileListState.selectedItems = (s) => {
if (s.selectedNames.size > 0) {
return s.currDir.items.filter((i) => {
return s.selectedNames.has(i.name);
});
}
return [];
};

/** @type {(s: any) => boolean} */
FileListState.isFileListState = (s) => {
return (
!!s &&
typeof s.offset === "number" &&
typeof s.index === "number" &&
isFileListDir(s.currDir) &&
isSet(s.selectedNames) &&
typeof s.isActive === "boolean" &&
isFileListSort(s.sort)
);
};

/**
* @param {any} d
* @returns {boolean}
*/
function isFileListDir(d) {
return (
!!d &&
typeof d.path === "string" &&
typeof d.isRoot === "boolean" &&
Array.isArray(d.items)
);
}

/**
* @param {any} s
* @returns {boolean}
*/
function isFileListSort(s) {
return !!s && typeof s.mode === "string" && typeof s.asc === "boolean";
}

export default FileListState;
148 changes: 148 additions & 0 deletions test/FileListState.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/**
* @typedef {import("../src/api/FileListDir").FileListDir} FileListDir
*/
import assert from "node:assert/strict";
import SortMode from "../src/sort/SortMode.mjs";
import FileListItem from "../src/api/FileListItem.mjs";
import FileListState from "../src/FileListState.mjs";

const { describe, it } = await (async () => {
// @ts-ignore
const module = process.isBun ? "bun:test" : "node:test";
// @ts-ignore
return process.isBun // @ts-ignore
? Promise.resolve({ describe: (_, fn) => fn(), it: test })
: import(module);
})();

const { currentItem, selectedItems, isFileListState } = FileListState;

describe("FileListState.test.mjs", () => {
it("should create new state when FileListState()", () => {
//when
const result = FileListState();

//then
assert.deepEqual(result, {
offset: 0,
index: 0,
currDir: { path: "", isRoot: false, items: [] },
selectedNames: new Set(),
isActive: false,
sort: { mode: SortMode.Name, asc: true },
});
});

it("should return current item depending on state when currentItem", () => {
//given
const item1 = FileListItem("dir 1");
const item2 = FileListItem("file 1");
/** @type {FileListDir} */
const currDir = { path: "/folder", isRoot: false, items: [item1, item2] };
const s = FileListState();

//when & then
assert.deepEqual(currentItem(s), undefined);
assert.deepEqual(currentItem({ ...s, index: 1 }), undefined);
assert.deepEqual(currentItem({ ...s, offset: 1 }), undefined);
assert.deepEqual(currentItem({ ...s, currDir }), item1);
assert.deepEqual(currentItem({ ...s, index: 1, currDir }), item2);
assert.deepEqual(currentItem({ ...s, offset: 1, currDir }), item2);
assert.deepEqual(
currentItem({ ...s, offset: 1, index: 1, currDir }),
undefined
);
});

it("should return selected items depending on state when selectedItems", () => {
//given
const item1 = FileListItem("dir 1");
const item2 = FileListItem("file 1");
/** @type {FileListDir} */
const currDir = { path: "/folder", isRoot: false, items: [item1, item2] };
const s = FileListState();

//when & then
assert.deepEqual(selectedItems(s), []);
assert.deepEqual(selectedItems({ ...s, currDir }), []);
assert.deepEqual(
selectedItems({ ...s, currDir, selectedNames: new Set(["file 123"]) }),
[]
);
assert.deepEqual(
selectedItems({ ...s, currDir, selectedNames: new Set(["dir 1"]) }),
[item1]
);
assert.deepEqual(
selectedItems({ ...s, currDir, selectedNames: new Set(["file 1"]) }),
[item2]
);
assert.deepEqual(
selectedItems({
...s,
currDir,
selectedNames: new Set(["file 1", "dir 1"]),
}),
[item1, item2]
);
});

it("should check if valid state instance when isFileListState", () => {
//given
const item1 = FileListItem("dir 1");
const item2 = FileListItem("file 1");
/** @type {FileListDir} */
const currDir = { path: "/folder", isRoot: false, items: [item1, item2] };
const s = FileListState();

//when & then
assert.deepEqual(isFileListState(s), true);
assert.deepEqual(isFileListState({ ...s, currDir }), true);
assert.deepEqual(isFileListState({ ...s, additional: "any" }), true);
assert.deepEqual(isFileListState(undefined), false);
assert.deepEqual(isFileListState(null), false);
assert.deepEqual(isFileListState(""), false);
assert.deepEqual(isFileListState(123), false);
assert.deepEqual(isFileListState({}), false);
assert.deepEqual(isFileListState([]), false);
assert.deepEqual(isFileListState({ ...s, offset: true }), false);
assert.deepEqual(isFileListState({ ...s, index: "" }), false);
assert.deepEqual(isFileListState({ ...s, currDir: "" }), false);
assert.deepEqual(isFileListState({ ...s, currDir: {} }), false);
assert.deepEqual(isFileListState({ ...s, currDir: undefined }), false);
assert.deepEqual(isFileListState({ ...s, currDir: null }), false);
assert.deepEqual(
isFileListState({ ...s, currDir: { ...currDir, items: new Set() } }),
false
);
assert.deepEqual(
isFileListState({ ...s, currDir: { ...currDir, isRoot: "" } }),
false
);
assert.deepEqual(
isFileListState({ ...s, currDir: { ...currDir, path: true } }),
false
);
assert.deepEqual(isFileListState({ ...s, selectedNames: [] }), false);
assert.deepEqual(isFileListState({ ...s, selectedNames: "" }), false);
assert.deepEqual(isFileListState({ ...s, selectedNames: {} }), false);
assert.deepEqual(
isFileListState({ ...s, selectedNames: undefined }),
false
);
assert.deepEqual(isFileListState({ ...s, selectedNames: null }), false);
assert.deepEqual(isFileListState({ ...s, isActive: "" }), false);
assert.deepEqual(isFileListState({ ...s, sort: "" }), false);
assert.deepEqual(isFileListState({ ...s, sort: {} }), false);
assert.deepEqual(isFileListState({ ...s, sort: undefined }), false);
assert.deepEqual(isFileListState({ ...s, sort: null }), false);
assert.deepEqual(
isFileListState({ ...s, sort: { ...s.sort, mode: 123 } }),
false
);
assert.deepEqual(
isFileListState({ ...s, sort: { ...s.sort, asc: "false" } }),
false
);
});
});
2 changes: 2 additions & 0 deletions test/all.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
await import("./FileListState.test.mjs");

await import("./api/FileListItem.test.mjs");

await import("./sort/FileListSort.test.mjs");

0 comments on commit b841332

Please sign in to comment.