Skip to content

Commit

Permalink
Format
Browse files Browse the repository at this point in the history
  • Loading branch information
atjn committed Jul 19, 2024
1 parent 013205a commit 6ee47db
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 353 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ permissions:
security-events: write

jobs:

codeql:

strategy:
fail-fast: false
matrix:
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ on:
pull_request:
branches: [master]
schedule:
- cron: "7 4 19 * *"
- cron: "7 4 19 * *"

permissions:
contents: read

jobs:

test:

strategy:
fail-fast: false
matrix:
Expand All @@ -33,7 +31,6 @@ jobs:
runs-on: ${{ matrix.os }}

steps:

- name: Checkout code
uses: actions/checkout@v3

Expand Down
45 changes: 25 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Get the size of a folder by iterating through its sub-files and -folders.
If you don't care about the details and just want a quick implementation, you can use:

```js
getFolderSize.loose('/path/to/folder');
getFolderSize.loose("/path/to/folder");
```

Example:

```js
import getFolderSize from 'get-folder-size';
import getFolderSize from "get-folder-size";

const myFolder = '/path/to/my/folder';
const myFolder = "/path/to/my/folder";

const size = await getFolderSize.loose(myFolder);
console.log(`The folder is ${size} bytes large`);
Expand All @@ -27,6 +27,7 @@ console.log(`That is the same as ${(size / 1000 / 1000).toFixed(2)} MB`);
When reading the size of a folder, read errors can randomly occur for a number of reasons, especially if a different process is altering files in the same folder at the same time. There are three different ways to call this package, depending on how you want to handle those errors:

### `getFolderSize(path, [options]): object`

The default method will return an object with the size of the folder and a list of encountered errors:

```js
Expand All @@ -43,11 +44,13 @@ If no errors were encountered, `errors` will be `null`. If errors were encounter
This method is great if you want to implement custom logic based on the errors that were encountered.

### `getFolderSize.loose(path, [options]): number | bigint`

The `loose` method will return the folder size directly and ignore any errors it encounters, which means the returned folder size could be smaller than the real folder size.

This method is great if the precise size isn't too important, for example when used only to display the folder size to the user.

### `getFolderSize.strict(path, [options]): number | bigint`

The `strict` method will return the folder size directly, but throw an error if it encounters any read errors.

This method is great if you need a very accurate number. You will have to implement some sort of error handling to use it reliably.
Expand All @@ -57,14 +60,11 @@ This method is great if you need a very accurate number. You will have to implem
Any of the three methods can also take an `options` object:

```js
getFolderSize(
'/path/to/folder',
{
bigint: true,
ignore: /pattern/,
fs: customFS,
}
)
getFolderSize("/path/to/folder", {
bigint: true,
ignore: /pattern/,
fs: customFS,
});
```

If the `bigint` option is set to true, the folder size is returned as a BigInt instead of the default Number.
Expand All @@ -80,6 +80,7 @@ You can run this module from your command line:
```bash
get-folder-size --folder="/my/folder" --ignore="node_modules"
```

The optional `ignore` statement takes a regex pattern.

## FAQ
Expand All @@ -91,14 +92,14 @@ If a file is passed to `get-folder-size`, it will simply return the size of the
Example:

```js
import getItemSize from 'get-folder-size';

for(const path of [
'/path/to/small/file.txt',
'/path/to/small/folder/',
'/path/to/large/file.js',
'/path/to/large/folder/',
]){
import getItemSize from "get-folder-size";

for (const path of [
"/path/to/small/file.txt",
"/path/to/small/folder/",
"/path/to/large/file.js",
"/path/to/large/folder/",
]) {
console.log(await getItemSize.strict(path));
}

Expand All @@ -107,25 +108,29 @@ for(const path of [
// 402
// 348614
// 674362319

```

### Does it return actual size or size on disk?

This module calculates the actual folder size, and not the size on disk. [Read about the difference here.](https://web.archive.org/web/20140712235443/https://stackoverflow.com/questions/15470787/please-help-me-understand-size-vs-size-on-disk)

### How do I import it from a CommonJS module?

CommonJS modules do not support the `import..from` method, but they do support this method:

```js
const getFolderSize = (await import("get-folder-size")).default;
```

Note that this import only works inside an async function.

If you want to use the `require` method, consider just staying on v2. You can make v2 return a promise by importing it this way:

```js
const util = require("util");
const getFolderSize = util.promisify(require("get-folder-size"));
```

If none of these methods work for you, [send us a detailed explanation of your issue](https://github.com/alessioalex/get-folder-size/issues), and we will take a look at it.

### How do I use it?
Expand Down
18 changes: 9 additions & 9 deletions bin/get-folder-size.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#!/usr/bin/env node

import getFolderSize from '../index.js';
import gar from 'gar';
import path from 'path';
import getFolderSize from "../index.js";
import gar from "gar";
import path from "path";

const argv = gar(process.argv.slice(2));

// --folder or -f or last argument passed
const folder = argv.folder || argv.f || argv._[argv._.length - 1];

if (!folder) {
console.error('missing folder argument');
console.error('\n Usage:\n');
console.error('get-folder-size --folder=/home/alex/www');
process.exit(1);
console.error("missing folder argument");
console.error("\n Usage:\n");
console.error("get-folder-size --folder=/home/alex/www");
process.exit(1);
}

const ignore = argv.ignore ? new RegExp(argv.ignore) : null;

const size = await getFolderSize.strict(path.resolve(folder), {ignore});
console.log((size / 1000 / 1000).toFixed(2) + ' MB');
const size = await getFolderSize.strict(path.resolve(folder), { ignore });
console.log((size / 1000 / 1000).toFixed(2) + " MB");
15 changes: 6 additions & 9 deletions example.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@

import path from 'path';
import getFolderSize from './index.js';
import path from "path";
import getFolderSize from "./index.js";

if (!process.env.FOLDER) {
throw new Error('FOLDER env var needed');
throw new Error("FOLDER env var needed");
}

getFolderSize.strict(path.resolve(process.env.FOLDER)).then(size => {

console.log(size + ' bytes');
console.log((size / 1000 / 1000).toFixed(2) + ' MB');

getFolderSize.strict(path.resolve(process.env.FOLDER)).then((size) => {
console.log(size + " bytes");
console.log((size / 1000 / 1000).toFixed(2) + " MB");
});
109 changes: 61 additions & 48 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

import { join as joinPaths } from 'path';
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.
Expand All @@ -14,7 +13,9 @@ import { join as joinPaths } from 'path';
*
* @returns {Promise<{size: number | bigint, errors: Array<Error> | 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}); }
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.
Expand All @@ -29,7 +30,8 @@ export default async function getFolderSize (itemPath, options) { return await c
*
* @returns {Promise<number | bigint>} - The size of the folder in bytes.
*/
getFolderSize.loose = async (itemPath, options) => await core(itemPath, options);
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.
Expand All @@ -44,57 +46,68 @@ getFolderSize.loose = async (itemPath, options) => await core(itemPath, options)
*
* @returns {Promise<number | bigint>} - The size of the folder in bytes.
*/
getFolderSize.strict = async (itemPath, options) => await core(itemPath, options, {strict: true});
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 = [];

async function core (rootItemPath, options = {}, returnType = {}) {
const fs = options.fs || await import('fs/promises');

const fileSizes = new Map();
const errors = [];

await processItem(rootItemPath);
await processItem(rootItemPath);

async function processItem(itemPath) {
if(options.ignore?.test(itemPath)) return;
async function processItem(itemPath) {
if (options.ignore?.test(itemPath)) return;

const stats = returnType.strict ? await fs.lstat(itemPath, {bigint: true}) : await fs.lstat(itemPath, {bigint: true}).catch(error => errors.push(error));
if(typeof stats !== 'object') return;
fileSizes.set(stats.ino, stats.size);
const stats = returnType.strict
? await fs.lstat(itemPath, { bigint: true })
: await fs
.lstat(itemPath, { bigint: true })
.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))
)
);
}
}
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)),
),
);
}
}

let folderSize = Array.from(fileSizes.values()).reduce((total, fileSize) => total + fileSize, 0n);

if(!options.bigint) {
if(folderSize > BigInt(Number.MAX_SAFE_INTEGER)){
const error = new RangeError('The folder size is too large to return as a Number. You can instruct this package to return a BigInt instead.');
if(returnType.strict){
throw error;
}else{
errors.push(error);
}
}
folderSize = Number(folderSize);
}
let folderSize = Array.from(fileSizes.values()).reduce(
(total, fileSize) => total + fileSize,
0n,
);

if (returnType.errors) {
return {
size: folderSize,
errors: errors.length > 0 ? errors : null,
};
} else {
return folderSize;
}
if (!options.bigint) {
if (folderSize > BigInt(Number.MAX_SAFE_INTEGER)) {
const error = new RangeError(
"The folder size is too large to return as a Number. You can instruct this package to return a BigInt instead.",
);
if (returnType.strict) {
throw error;
} else {
errors.push(error);
}
}
folderSize = Number(folderSize);
}

if (returnType.errors) {
return {
size: folderSize,
errors: errors.length > 0 ? errors : null,
};
} else {
return folderSize;
}
}
Loading

0 comments on commit 6ee47db

Please sign in to comment.