diff --git a/public/index.html b/public/index.html
index d8609908..fe323ed0 100644
--- a/public/index.html
+++ b/public/index.html
@@ -10,7 +10,7 @@
-
+
diff --git a/scripts/hello.js b/scripts/hello.js
index a79db86b..04831efe 100644
--- a/scripts/hello.js
+++ b/scripts/hello.js
@@ -1,5 +1,90 @@
import chalk from "chalk";
import chalkTable from "chalk-table";
+import { join as joinPaths } from "path";
+
+
+/**
+ * Returns an object containing the size of the folder and a list of errors encountered while traversing the folder.
+ *
+ * If any errors are returned, the returned folder size is likely smaller than the real folder size.
+ *
+ * @param {string} itemPath - Path of the folder.
+ * @param {object} [options] - Options.
+ * @param {object} [options.ignore] - If a file's path matches this regex object, its size is not counted.
+ * @param {object} [options.fs] - The filesystem that should be used. Uses node fs by default.
+ *
+ * @returns {Promise<{size: number, errors: Array | null}>} - An object containing the size of the folder in bytes and a list of encountered errors.
+ */
+export default async function getFolderSize (itemPath, options) { return await core(itemPath, options, {errors: true}) }
+
+/**
+ * Returns the size of the folder. If any errors are encountered while traversing the folder, they are silently ignored.
+ *
+ * The returned folder size might be smaller than the real folder size. It is impossible to know for sure, since errors are ignored.
+ *
+ * @param {string} itemPath - Path of the folder.
+ * @param {object} [options] - Options.
+ * @param {object} [options.ignore] - If a file's path matches this regex object, its size is not counted.
+ * @param {object} [options.fs] - The filesystem that should be used. Uses node fs by default.
+ *
+ * @returns {Promise} - The size of the folder in bytes.
+ */
+getFolderSize.loose = async (itemPath, options) => await core(itemPath, options);
+
+/**
+ * Returns the size of the folder. If any errors are encountered while traversing the folder, this method will throw an error.
+ *
+ * Because errors will otherwise make this method fail, the returned folder size will always be accurate.
+ *
+ * @param {string} itemPath - Path of the folder.
+ * @param {object} [options] - Options.
+ * @param {object} [options.ignore] - If a file's path matches this regex object, its size is not counted.
+ * @param {object} [options.fs] - The filesystem that should be used. Uses node fs by default.
+ *
+ * @returns {Promise} - The size of the folder in bytes.
+ */
+getFolderSize.strict = async (itemPath, options) => await core(itemPath, options, {strict: true});
+
+
+
+async function core (rootItemPath, options = {}, returnType = {}) {
+ const fs = options.fs || await import('fs/promises');
+
+ const fileSizes = new Map();
+ const errors = [];
+
+ await processItem(rootItemPath);
+
+ async function processItem(itemPath) {
+ if(options.ignore?.test(itemPath)) return;
+
+ const stats = returnType.strict ? await fs.lstat(itemPath) : await fs.lstat(itemPath).catch(error => errors.push(error));
+ if(typeof stats !== 'object') return;
+ fileSizes.set(stats.ino, stats.size);
+
+ if(stats.isDirectory()) {
+ const directoryItems = returnType.strict ? await fs.readdir(itemPath) : await fs.readdir(itemPath).catch(error => errors.push(error));
+ if(typeof directoryItems !== 'object') return;
+ await Promise.all(
+ directoryItems.map(directoryItem =>
+ processItem(joinPaths(itemPath, directoryItem))
+ )
+ );
+ }
+ }
+
+ const folderSize = Array.from(fileSizes.values()).reduce((total, fileSize) => total + fileSize, 0);
+
+ if (returnType.errors) {
+ return {
+ size: folderSize,
+ errors: errors.length > 0 ? errors : null,
+ }
+ } else {
+ return folderSize;
+ }
+
+}
console.log(
" ██╗ ██╗ ███████╗ ██╗ ██████╗ ██████╗ ███╗ ███╗ ███████╗\n" +
@@ -28,3 +113,7 @@ const table = chalkTable(options, [
]);
console.log(table);
+
+
+const size = await getFolderSize.loose("./");
+console.log(`Repository folder size after installation: ${(size / 1000 / 1000).toFixed(2)} MB`);
diff --git a/src/helpers/cells/cells-manipulator.test.ts b/src/helpers/cells/cells-manipulator.test.ts
index 630d984c..46a053a8 100644
--- a/src/helpers/cells/cells-manipulator.test.ts
+++ b/src/helpers/cells/cells-manipulator.test.ts
@@ -1,8 +1,54 @@
-import { incrementNeighbours } from "@helpers/cells";
-import { CellState, Field } from "@helpers/field";
+import { CellState, Field } from "../field";
+import { checkItemInField, getNeighbours, incrementNeighbours } from "./cells-manipulator";
const { empty, bomb } = CellState;
+describe("Check neighbours selectors", function () {
+ it("should render with [0, 0] as coordinates value", function () {
+ expect(getNeighbours([0, 0])).toStrictEqual({
+ top: [-1, 0],
+ topRight: [-1, 1],
+ right: [0, 1],
+ rightBottom: [1, 1],
+ bottom: [1, 0],
+ bottomLeft: [1, -1],
+ left: [0, -1],
+ leftTop: [-1, 1],
+ });
+ });
+
+ it("should render with [3, 3] as coordinates value", function () {
+ expect(getNeighbours([3, 3])).toStrictEqual({
+ top: [2, 3],
+ topRight: [2, 4],
+ right: [3, 4],
+ rightBottom: [4, 4],
+ bottom: [4, 3],
+ bottomLeft: [4, 2],
+ left: [3, 2],
+ leftTop: [2, 2],
+ });
+ });
+});
+
+describe("checkItemField fn() test", function () {
+ describe("simple cases", function () {
+ const field: Field = [[empty]];
+
+ it("should out of y range", function () {
+ expect(checkItemInField([1, 0], field)).toBe(false);
+ });
+
+ it("should out of x range", function () {
+ expect(checkItemInField([0, -1], field)).toBe(false);
+ });
+
+ it("should in x and y range", function () {
+ expect(checkItemInField([0, 0], field)).toBe(true);
+ });
+ });
+});
+
describe("Check Increment Neighbours on each cells", () => {
describe("Simple Cases", function () {
it("should have Field with only one item", function () {
diff --git a/src/helpers/cells/cells-manipulator.ts b/src/helpers/cells/cells-manipulator.ts
index d23c2af6..a53dfdea 100644
--- a/src/helpers/cells/cells-manipulator.ts
+++ b/src/helpers/cells/cells-manipulator.ts
@@ -1,4 +1,4 @@
-import { Cell, Coordinates, Field } from "@helpers/field";
+import { Cell, Coordinates, Field } from "../field";
/**
* Get neighbour cells indexes