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