npm package: @naoclis/onyx-tools
Description: TypeScript utility classes for file system management, date formatting, image handling and HTTP API calls — built for Node.js and Next.js projects.
Author: Nicolas Castelli
Latest version: 1.0.32

# @naoclis/onyx-tools

A collection of TypeScript utility classes for Node.js and Next.js projects, covering file system management, date manipulation, number formatting, array operations, image handling, and API communication.

---

## Installation

```bash
npm install @naoclis/onyx-tools
```

---

## Available Classes

| Class | Import path | Environment |
|---|---|---|
| `MyFileTools` | `@naoclis/onyx-tools` | Node.js (server) |
| `MyDateTools` | `@naoclis/onyx-tools` | Universal |
| `MyNumTools` | `@naoclis/onyx-tools` | Universal |
| `MyArrayTools` | `@naoclis/onyx-tools` | Universal |
| `MyImageTools` | `@naoclis/onyx-tools` | Node.js (server) |
| `MyAPICore` | `@naoclis/onyx-tools/front` | Browser / Next.js |

---

## MyFileTools

File system utility class for managing files and directories.

```ts
import MyFileTools from '@naoclis/onyx-tools';
const fh = new MyFileTools();
```

### Directory management

| Method | Description |
|---|---|
| `createDirectory(directory)` | Creates a directory recursively if it doesn't exist |
| `removeDirectory(directoryPath)` | Deletes a directory and all its contents |
| `emptyDirectory(directoryPath)` | Empties a directory without deleting it |
| `getDirsInDirectory(path)` | Returns the list of subdirectory names in a directory |
| `loopOnDirectory(directory, extensions?)` | Returns `{ path, name }` for each matching file (default: `csv`, `json`) |
| `getAllFilesInDir(dir, mode?)` | Recursively returns all paths (`"FILE"`, `"DIR"`, or `"ALL"`) |
| `cloneFilesPathInTargetDir(origin, pathParts, targetDirName)` | Replicates a folder structure in a target directory |

### File manipulation

| Method | Description |
|---|---|
| `fileExists(path)` | Returns `true` if the file or directory exists |
| `copyFile(source, target)` | Copies a file synchronously |
| `moveFile(source, target)` | Moves (renames) a file synchronously |
| `removeFile(name)` | Deletes a file if it exists |
| `manipulateFile(path, name, ext, mode, line)` | Creates, overwrites or appends to a file |
| `manipulateFileAtPath(path, mode, line)` | Same as above but with a full path directly |

**Modes (`FileMode`):**

- `"create"` — creates an empty file
- `"override"` / `"overwrite"` — overwrites the file with the given content
- `"append"` — appends content to the end of the file

**Shorthand to write a file in one call:**

```ts
// Instead of override + append, write directly:
fh.manipulateFileAtPath('src/assets/logs/error.json', 'override', JSON.stringify(data, null, 2));
```

### Reading files

| Method | Description |
|---|---|
| `readFileLines(path)` | Reads a file and returns an array of lines |
| `readJSONFile(path)` | Reads and parses a JSON file, returns `null` on error |
| `getFileDates(filePath)` | Returns `{ creationDate, modificationDate }` as timestamps |
| `getFileCreationDate(path)` | Returns the creation date as a `Date` object |

### Async

| Method | Description |
|---|---|
| `saveFileFromUrl(fileUrl, destinationPath)` | Downloads a file from a URL and saves it locally |

---

## MyDateTools

Static utility class for date formatting, parsing and manipulation.

```ts
import { MyDateTools } from '@naoclis/onyx-tools';
```

All methods are **static** — no instantiation needed.

### Date formatting

| Method | Description |
|---|---|
| `getCurrentDate(format?, dateSep?, timeSep?)` | Returns today's date as a formatted string |
| `formatDate(timestamp, format?, dateSep?, timeSep?)` | Converts a timestamp to a formatted date string |
| `reformatDateString(dateStr, inputFormat, outputFormat)` | Reformats a date string from one format to another |

**Available formats for `getCurrentDate` / `formatDate`:**

| Format key | Example output |
|---|---|
| `"YMD"` | `2025/03/12` |
| `"YMD HIS"` | `2025/03/12 14:30:00` |
| `"YMD-HIS"` | `2025/03/12-14:30:00` |
| `"DMY"` | `12/03/2025` |
| `"DMY HIS"` | `12/03/2025 14:30:00` |

```ts
MyDateTools.getCurrentDate('DMY', '/');          // "18/03/2026"
MyDateTools.formatDate(Date.now(), 'YMD', '-');  // "2026-03-18"
```

**`reformatDateString` — flexible date converter:**

```ts
MyDateTools.reformatDateString('03/12/2025', 'DD/MM/YYYY', 'YYYY-MM-DD');
// → "2025-12-03"

MyDateTools.reformatDateString('2025-12-03 14:23:45', 'YYYY-MM-DD HH:mm:ss', 'DD/MM/YYYY à HHhmm');
// → "03/12/2025 à 14h23"
```

### Date calculations

| Method | Description |
|---|---|
| `diffInDaysDirectional(date1, date2)` | Returns the signed difference in days between two `DD/MM/YYYY` dates |
| `shiftDateByDays(nbOfDays)` | Shifts today's date by N days (negative to go back). Normalized to midnight — hours/minutes/seconds are ignored |
| `toTimestamp(year, month, day, h?, m?, s?)` | Converts date parts to a Unix timestamp |
| `transformDatetoISODateForMongoDB(date)` | Converts a `DD/MM/YYYY` date to a UTC `Date` for MongoDB |

```ts
MyDateTools.diffInDaysDirectional('20/03/2026', '18/03/2026'); // 2
MyDateTools.shiftDateByDays(-7);  // date string from 7 days ago
```

---

## MyNumTools

Static utility class for number parsing, rounding and formatting.

```ts
import { MyNumTools } from '@naoclis/onyx-tools';
```

All methods are **static**.

| Method | Description |
|---|---|
| `convertEnglishNumber(numValue)` | Parses an English-formatted number string (`"1,500,000"` or `"150 000"`) to a plain number string |
| `isZeroEquivalent(numValue)` | Returns `true` if the number is so close to zero it can be treated as such (tolerance: `1e-5`) |
| `makeItZeroIfNearZero(numValue)` | Returns `0` if the value is near-zero, otherwise returns the value unchanged |
| `roundStrNumber(strNum, nbDecimals?)` | Rounds a numeric string to N decimal places (default: `7`) |
| `scientific(num, nbOfDecimals?)` | Formats a number with thousands spaces and fixed decimals, Excel-style (default: `2`) |

```ts
MyNumTools.convertEnglishNumber('1,500,000');   // "1500000"
MyNumTools.convertEnglishNumber('150 000');     // "150000"

MyNumTools.roundStrNumber('3.14159265', 4);     // 3.1416

MyNumTools.scientific(1500000.5);               // "1 500 000.50"
MyNumTools.scientific(-42.1);                   // "- 42.10"

MyNumTools.isZeroEquivalent(0.000001);          // true
MyNumTools.makeItZeroIfNearZero(0.000001);      // 0
```

---

## MyArrayTools

Static utility class for sorting, filtering and comparing arrays.

```ts
import { MyArrayTools } from '@naoclis/onyx-tools';
```

All methods are **static**.

| Method | Description |
|---|---|
| `sortArrayOfObjetsByAttribute(arr, key, direction?)` | Sorts an array of objects by a given key. Direction: `"ASC"` (default) or `"DES"` |
| `sortedArrayByDate(arr, key, direction?)` | Sorts an array of objects by a date field in `DD/MM/YYYY` format |
| `getUniqueValuesForField(rows, field)` | Returns the unique values for a given field across an array of objects |
| `compareTwoStringsArray(source, target)` | Returns the elements present in `source` but missing from `target` (case-insensitive) |
| `findDuplicates(arr)` | Returns each duplicated string once, regardless of how many times it appears |

```ts
MyArrayTools.sortArrayOfObjetsByAttribute(users, 'name', 'ASC');

MyArrayTools.sortedArrayByDate(transactions, 'transactionDate', 'DES');

MyArrayTools.getUniqueValuesForField(rows, 'category');
// → ["food", "transport", "health"]

MyArrayTools.compareTwoStringsArray(['a', 'b', 'c'], ['a', 'c']);
// → ["b"]

MyArrayTools.findDuplicates(['foo', 'bar', 'foo', 'foo', 'baz', 'bar']);
// → ["foo", "bar"]
```

---

## MyImageTools

Static utility class for downloading and inspecting images.

```ts
import { MyImageTools } from '@naoclis/onyx-tools';
```

All methods are **static**.

| Method | Description |
|---|---|
| `saveImageFromURLToFolder(saveMode, scanDir, imageName, imageUrl, ext?)` | Downloads and saves an image from a URL. `saveMode`: `"override"` pour écraser, `"keep"` pour ignorer si existant. Default extension: `jpg` |
| `getImageDimensions(path)` | Returns `{ width, height }` for a local image, or `null` on error |

```ts
await MyImageTools.saveImageFromURLToFolder('override', './images', 'photo', 'https://example.com/photo.jpg');

const { width, height } = MyImageTools.getImageDimensions('./images/photo.jpg');
```

---

## MyAPICore

Lightweight wrapper around the native `fetch` API for making HTTP requests in Next.js or browser environments.

```ts
import { MyAPICore } from '@naoclis/onyx-tools/front';

const api = new MyAPICore('users');
```

Reads the base URL from `process.env.NEXT_PUBLIC_API_URL`.

### Constructor

```ts
new MyAPICore(prefix: string, headers?: any)
```

- `prefix` — API route prefix (e.g. `"users"` → `API_URL/users/...`)
- `headers` — Pass `null` to send requests without headers. Defaults to `Content-Type: application/json`.

### Methods

| Method | Description |
|---|---|
| `get<T>(endpoint)` | Performs a GET request and returns the parsed JSON response as `T \| null` |
| `post<T, B>(endpoint, data)` | Performs a POST request with a JSON body and returns the parsed JSON response as `T \| null` |

```ts
const api = new MyAPICore('products');

const products = await api.get<Product[]>('list');
// → GET NEXT_PUBLIC_API_URL/products/list
// Retourne Product[] | null (null si erreur HTTP ou réseau)

const result = await api.post<CreateResponse, CreateBody>('create', { name: 'Item', price: 42 });
// → POST NEXT_PUBLIC_API_URL/products/create
```

---

## Dependencies

| Package | Usage |
|---|---|
| `axios` | File download from URL |
| `image-size` | Image dimension detection |

---

## Author

**Nicolas Castelli** — [dev@naoclis.com](mailto:dev@naoclis.com)

---

## License

ISC