Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: CI & Publish Package to npmjs

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test

- name: Build package
run: npm run build

publish:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
run: npm ci

- name: Build package
run: npm run build

- name: Check version and Publish
run: |
LOCAL_VERSION=$(node -p "require('./package.json').version")
NPM_VERSION=$(npm view bytes-kit version 2>/dev/null || echo "0.0.0")

if [ "$LOCAL_VERSION" != "$NPM_VERSION" ]; then
echo "New version detected ($LOCAL_VERSION). Publishing to npm..."
npm publish
else
echo "Version $LOCAL_VERSION is already published on npm. Skipping publication."
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
110 changes: 90 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ A lightweight, type-safe, and zero-dependency utility for formatting, parsing, c
- 📦 **Dual package** (CommonJS & ES Modules)
- 🔒 **Fully type-safe** with TypeScript types included
- ⚙️ **Highly customizable** (decimal places, binary vs. decimal units, spacing, custom forced units)
- 🌍 **Global Configuration** with customizable error handling (throwOnError, onError)
- 🧭 **Parsing & Manipulation** (parse strings back to bytes, compare sizes, get differences, calculate stats on collections)
- 🌍 **Localization support** using `Intl.NumberFormat`

Expand All @@ -21,6 +22,28 @@ npm install bytes-kit

---

## Global Configuration

You can configure global defaults once. Per-call options always take precedence.

```typescript
import bytes from 'bytes-kit';

bytes.defaultConfig({
binary: true,
space: false,
throwOnError: false, // Don't crash on invalid input
onError(error) {
console.error('[App error handler]', error.message);
}
});
```

* `bytes.getConfig()`: Returns a read-only clone of the current configuration.
* `bytes.resetConfig()`: Restores config back to factory defaults.

---

## Usage

### 1. Formatting Bytes
Expand Down Expand Up @@ -48,26 +71,61 @@ parseBytes('100'); // => 100
```

### 3. Comparing Byte Sizes
Finds the larger or smaller value between two inputs. Accepts both `number` and `string` types.
Finds the larger or smaller value between two inputs. Returns a formatted string.

```typescript
import { getLargerByte, getSmallerByte } from 'bytes-kit';

getLargerByte('1.5 MB', '2000 KB'); // => 2000000 (which is 2 MB)
getSmallerByte('1.5 MB', 2000000); // => 1500000 (which is 1.5 MB)
getLargerByte('1.5 MB', '2000 KB'); // => '2 MB'
getSmallerByte('1.5 MB', 2000000); // => '1.5 MB'
```

### 4. Byte Difference
Computes the difference between two byte sizes (`a - b`).
### 4. Byte Equality & Difference
Checks equality or computes the difference between two byte sizes (`a - b`).

```typescript
import { diffBytes } from 'bytes-kit';
import { isEqualBytes, diffBytes } from 'bytes-kit';

diffBytes('1.5 MB', '500 KB'); // => 1000000 (1 MB)
diffBytes('500 KB', '1.5 MB'); // => -1000000 (-1 MB)
isEqualBytes('1 MB', '1000 KB'); // => true
isEqualBytes('1 MiB', '1024 KiB'); // => true

diffBytes('1.5 MB', '500 KB'); // => '1 MB'
diffBytes('500 KB', '1.5 MB'); // => '-1 MB'
```

### 5. Analyzing Collections
### 5. Summing Collections
Sums an array of byte sizes and returns the formatted sum.

```typescript
import { sumBytes } from 'bytes-kit';

sumBytes(['1 MB', '500 KB']); // => '1.5 MB'
```

### 6. Sorting Collections
Sorts an array of byte values while preserving their original formats (string or number). Returns a new array.

```typescript
import { sortBytes } from 'bytes-kit';

sortBytes(['1 MB', '200 KB', '2 GB']); // => ['200 KB', '1 MB', '2 GB']
sortBytes(['1 MB', '200 KB', '2 GB'], 'desc'); // => ['2 GB', '1 MB', '200 KB']
```

### 7. Helper Utilities
Validate representations or detect units:

```typescript
import { isValidByte, detectUnit } from 'bytes-kit';

isValidByte('1 MB'); // => true
isValidByte('invalid'); // => false

detectUnit('5 GiB'); // => 'GiB'
detectUnit('500'); // => 'B'
```

### 8. Analyzing Collections
Parses a list of mixed sizes and returns an analysis object:

```typescript
Expand All @@ -77,9 +135,9 @@ const stats = analyzeBytes(['500 KB', '1.2 MB', 3000000, '4.5 MiB']);
/*
Returns:
{
largest: 4718592, // 4.5 MiB
smallest: 500000, // 500 KB
average: 2354648 // 2.35 MB
largest: '4.72 MB',
smallest: '500 KB',
average: '2.35 MB'
}
*/
```
Expand All @@ -104,17 +162,29 @@ Formats a numeric number of bytes.
### `parseBytes(input: string): number`
Parses a string size back to bytes. Supports standard decimal (B, KB, MB...) and binary (KiB, MiB, GiB...) units case-insensitively.

### `getLargerByte(a: number | string, b: number | string): number`
Compares `a` and `b` and returns the larger size in bytes.
### `getLargerByte(a: number | string, b: number | string, options?: FormatOptions): string`
Compares `a` and `b` and returns the larger size formatted as a string.

### `getSmallerByte(a: number | string, b: number | string, options?: FormatOptions): string`
Compares `a` and `b` and returns the smaller size formatted as a string.

### `diffBytes(a: number | string, b: number | string, options?: FormatOptions): string`
Returns the difference `a - b` formatted as a string.

### `isEqualBytes(a: number | string, b: number | string): boolean`
Returns true if `a` and `b` represent equivalent byte capacities.

### `sumBytes(values: (number | string)[], options?: FormatOptions): string`
Sums the array of byte sizes and returns the formatted sum.

### `getSmallerByte(a: number | string, b: number | string): number`
Compares `a` and `b` and returns the smaller size in bytes.
### `sortBytes(values: (number | string)[], order?: 'asc' | 'desc'): (number | string)[]`
Sorts the collection of byte sizes and returns a new sorted array.

### `diffBytes(a: number | string, b: number | string): number`
Returns the difference `a - b` in bytes.
### `isValidByte(value: number | string): boolean`
Returns true if `value` is a valid byte representation.

### `analyzeBytes(inputs: (number | string)[]): ByteStats`
Returns the `largest`, `smallest`, and `average` byte sizes from an array of mixed byte inputs.
### `detectUnit(value: string): UnitType`
Returns the detected `UnitType` symbol of the byte representation.

---

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 15 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bytes-kit",
"version": "1.1.0",
"description": "A comprehensive bytes toolkit for formatting, parsing, and working with byte sizes.",
"version": "1.2.0",
"description": "Utilities for formatting, parsing, and working with byte sizes.",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
Expand All @@ -26,6 +26,7 @@
"homepage": "https://github.com/cool-Dev-master/bytes-kit#readme",
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"clean": "rm -rf dist",
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
"play": "tsx playground.ts",
"test": "vitest run",
Expand All @@ -41,13 +42,23 @@
"keywords": [
"bytes",
"byte",
"bytes-kit",
"byte-kit",
"format",
"formatter",
"toolkit",
"size",
"human-readable",
"parser"
"parser",
"bytes-converter",
"filesize",
"binary"
],
"sideEffects": false,
"author": "Cool Dev Master <cooldev.master@gmail.com>",
"license": "MIT"
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/cool-Dev-master"
}
}
91 changes: 61 additions & 30 deletions playground.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,83 @@
import {
import bytes, {
formatBytes,
parseBytes,
getLargerByte,
getSmallerByte,
isEqualBytes,
diffBytes,
sumBytes,
sortBytes,
analyzeBytes,
isValidByte,
detectUnit,
} from './src/index.js';

console.log('=== Bytes Kit Playground ===\n');

// 1. Formatting Bytes
console.log('--- 1. Formatting Bytes ---');
const bytes = 123456789;
console.log(`Input value: ${bytes} bytes`);
console.log('Default format: ', formatBytes(bytes));
console.log('Binary units: ', formatBytes(bytes, { binary: true }));
console.log('Fixed decimals (3): ', formatBytes(bytes, { decimalPlaces: 3, fixedDecimals: true }));
console.log('German locale: ', formatBytes(bytes, { locale: 'de-DE' }));
// 1. Configure Defaults
bytes.defaultConfig({
binary: true,
space: false,
throwOnError: false,
onError(err) {
console.log('[Global Config onError Hook] Caught error:', err.message);
}
});

console.log('--- 1. Configuration Check ---');
console.log('Current Config:', bytes.getConfig());
console.log();

// 2. Formatting Bytes
console.log('--- 2. Formatting Bytes ---');
const bytesVal = 123456789;
console.log(`Input value: ${bytesVal} bytes`);
console.log('Default format (binary & no space via config):', formatBytes(bytesVal));
console.log('Per-call override (decimal & space): ', formatBytes(bytesVal, { binary: false, space: true }));
console.log();

// 2. Parsing Bytes
console.log('--- 2. Parsing Byte Strings ---');
// 3. Parsing Bytes
console.log('--- 3. Parsing Byte Strings ---');
const string1 = '1.5 MB';
const string2 = '20 KiB';
console.log(`parseBytes("${string1}"):`, parseBytes(string1), 'bytes');
console.log(`parseBytes("${string2}"):`, parseBytes(string2), 'bytes');
console.log();

// 3. Finding Larger / Smaller Sizes (mixed arguments, returns string)
console.log('--- 3. Larger / Smaller Comparisons ---');
const sizeA = '1.5 MB';
const sizeB = '2000 KB'; // 2.0 MB
console.log(`getLargerByte("${sizeA}", "${sizeB}"): `, getLargerByte(sizeA, sizeB));
console.log(`getSmallerByte("${sizeA}", "${sizeB}"): `, getSmallerByte(sizeA, sizeB));
// 4. Verification & Helpers
console.log('--- 4. Verification & Helpers ---');
console.log('isValidByte("1.5 MB"):', isValidByte('1.5 MB'));
console.log('isValidByte("abc"): ', isValidByte('abc'));
console.log('detectUnit("5 GiB"): ', detectUnit('5 GiB'));
console.log('detectUnit("500"): ', detectUnit('500'));
console.log();

// 5. Comparisons, Equality & Differences
console.log('--- 5. Comparisons, Equality & Differences ---');
console.log('isEqualBytes("1 MB", "1000 KB"): ', isEqualBytes('1 MB', '1000 KB'));
console.log('getLargerByte("1.5 MB", "2000 KB"):', getLargerByte('1.5 MB', '2000 KB'));
console.log('getSmallerByte("1.5 MB", 2000000): ', getSmallerByte('1.5 MB', 2000000));
console.log('diffBytes("1.5 MB", "500 KB"): ', diffBytes('1.5 MB', '500 KB'));
console.log();

// 6. Math & Collection Operations
console.log('--- 6. Math & Collection Operations ---');
const arr = ['1 MB', '500 KB', '2 GB'];
console.log('Array of sizes:', arr);
console.log('sumBytes(arr): ', sumBytes(arr));
console.log('sumBytes(arr, { unit: "MB" }): ', sumBytes(arr, { unit: 'MB' }));
console.log('sortBytes(arr): ', sortBytes(arr));
console.log('analyzeBytes(arr):', analyzeBytes(arr));
console.log();

// 4. Calculating Difference (returns string)
console.log('--- 4. Difference ---');
console.log(`diffBytes("1.5 MB", "500 KB"): `, diffBytes('1.5 MB', '500 KB'));
console.log(`diffBytes("500 KB", "1.5 MB"): `, diffBytes('500 KB', '1.5 MB'));
// 7. Error Handling Fallback Check
console.log('--- 7. Error Handling Fallback Check ---');
console.log('isValidByte("invalid"): ', isValidByte('invalid')); // never calls onError
console.log('parseBytes("invalid"): ', parseBytes('invalid')); // calls onError, returns 0
console.log('sumBytes(["1 MB", "invalid"]): ', sumBytes(['1 MB', 'invalid'])); // calls onError, returns fallback
console.log();

// 5. Analyzing Collection Stats (returns formatted strings)
console.log('--- 5. Collection Analysis ---');
const fileSizes = ['500 KB', '1.2 MB', 3000000, '4.5 MiB'];
const stats = analyzeBytes(fileSizes);
console.log('Input Array:', fileSizes);
console.log('Stats:');
console.log(' Largest: ', stats.largest);
console.log(' Smallest: ', stats.smallest);
console.log(' Average: ', stats.average);
// Reset config
bytes.resetConfig();
console.log('--- 8. Configuration Reset ---');
console.log('Reset Config:', bytes.getConfig());
Loading
Loading