@ooneex/fs 0.0.17 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  # @ooneex/fs
2
2
 
3
- A comprehensive file system utilities library for TypeScript applications with async support and streaming capabilities. This package provides intuitive `File` and `Directory` classes for reading, writing, copying, and manipulating files and directories with proper error handling.
3
+ Async file system utilities for reading, writing, copying, and watching files and directories with type-safe error handling and stream support. This package provides intuitive `File` and `Directory` classes for managing files and directories with proper error handling, streaming, and glob pattern matching.
4
4
 
5
5
  ![Bun](https://img.shields.io/badge/Bun-Compatible-orange?style=flat-square&logo=bun)
6
- ![Deno](https://img.shields.io/badge/Deno-Compatible-blue?style=flat-square&logo=deno)
7
- ![Node.js](https://img.shields.io/badge/Node.js-Compatible-green?style=flat-square&logo=node.js)
8
6
  ![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square&logo=typescript)
9
7
  ![MIT License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)
10
8
 
@@ -14,42 +12,26 @@ A comprehensive file system utilities library for TypeScript applications with a
14
12
 
15
13
  ✅ **Directory Management** - Create, list, copy, move, and watch directories
16
14
 
17
- ✅ **Streaming Support** - Stream file contents as text, bytes, or JSON objects
15
+ ✅ **Streaming Support** - Stream file contents as text, bytes, or JSON objects via async generators
18
16
 
19
17
  ✅ **Async/Await** - Full async support for all I/O operations
20
18
 
21
- ✅ **Type-Safe** - Full TypeScript support with proper type definitions
19
+ ✅ **Type-Safe** - Full TypeScript support with `IFile` and `IDirectory` interfaces
22
20
 
23
- ✅ **Error Handling** - Custom exceptions with detailed error information
21
+ ✅ **Error Handling** - Dedicated `FileException` and `DirectoryException` classes
24
22
 
25
- ✅ **URL Downloads** - Download files from URLs directly to disk
23
+ ✅ **Pattern Matching** - Filter files and directories using regular expression patterns
26
24
 
27
- ✅ **Glob Patterns** - Filter files and directories using glob patterns
25
+ ✅ **File Watching** - Watch directories for changes with recursive support and event callbacks
28
26
 
29
- ✅ **File Watching** - Watch directories for changes with recursive support
27
+ ✅ **Buffered Writing** - Efficient file writing via Bun's `FileSink` writer API
30
28
 
31
29
  ## Installation
32
30
 
33
- ### Bun
34
31
  ```bash
35
32
  bun add @ooneex/fs
36
33
  ```
37
34
 
38
- ### pnpm
39
- ```bash
40
- pnpm add @ooneex/fs
41
- ```
42
-
43
- ### Yarn
44
- ```bash
45
- yarn add @ooneex/fs
46
- ```
47
-
48
- ### npm
49
- ```bash
50
- npm install @ooneex/fs
51
- ```
52
-
53
35
  ## Usage
54
36
 
55
37
  ### File Operations
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Dirent as Dirent2, Stats as Stats2 } from "node:fs";
2
2
  import { Dirent, Stats } from "node:fs";
3
- import { watch as watch_odwmqucckw } from "node:fs";
3
+ import { watch as watch_jekclobzjd } from "node:fs";
4
4
  /**
5
5
  * Interface for file operations.
6
6
  *
@@ -152,41 +152,39 @@ interface IFile {
152
152
  * @example
153
153
  * ```typescript
154
154
  * const stream = file.stream();
155
- * for await (const chunk of stream) {
155
+ * for await (const chunk of file.stream()) {
156
156
  * console.log(chunk);
157
157
  * }
158
158
  * ```
159
159
  */
160
- stream: () => ReadableStream<Uint8Array>;
160
+ stream: () => AsyncGenerator<Uint8Array>;
161
161
  /**
162
- * Returns a ReadableStream for incremental file reading as text.
162
+ * Returns an async generator for incremental file reading as text.
163
163
  *
164
- * @returns A ReadableStream of string chunks
164
+ * @returns An async generator that yields string chunks
165
165
  *
166
166
  * @example
167
167
  * ```typescript
168
- * const stream = file.streamAsText();
169
- * for await (const chunk of stream) {
168
+ * for await (const chunk of file.streamAsText()) {
170
169
  * console.log(chunk);
171
170
  * }
172
171
  * ```
173
172
  */
174
- streamAsText: () => ReadableStream<string>;
173
+ streamAsText: () => AsyncGenerator<string>;
175
174
  /**
176
- * Returns a ReadableStream for incremental JSON parsing from a JSON array file.
175
+ * Returns an async generator for incremental JSON parsing from a JSON array file.
177
176
  *
178
177
  * @typeParam T - The expected type of each JSON element
179
- * @returns A ReadableStream of parsed JSON elements
178
+ * @returns An async generator that yields parsed JSON elements
180
179
  *
181
180
  * @example
182
181
  * ```typescript
183
- * const stream = file.streamAsJson<{ id: number }>();
184
- * for await (const item of stream) {
182
+ * for await (const item of file.streamAsJson<{ id: number }>()) {
185
183
  * console.log(item.id);
186
184
  * }
187
185
  * ```
188
186
  */
189
- streamAsJson: <T = unknown>() => ReadableStream<T>;
187
+ streamAsJson: <T = unknown>() => AsyncGenerator<T>;
190
188
  /**
191
189
  * Writes data to the file, overwriting existing content.
192
190
  *
@@ -233,18 +231,6 @@ interface IFile {
233
231
  */
234
232
  delete: () => Promise<void>;
235
233
  /**
236
- * Downloads a file from a URL and saves it to this file's path.
237
- *
238
- * @param url - The URL to download the file from
239
- * @returns A promise that resolves to the number of bytes written
240
- *
241
- * @example
242
- * ```typescript
243
- * const bytes = await file.download("https://example.com/image.png");
244
- * ```
245
- */
246
- download: (url: string | URL) => Promise<number>;
247
- /**
248
234
  * Returns a FileSink for incremental writing.
249
235
  *
250
236
  * @param options - Optional configuration for the writer
@@ -453,40 +439,52 @@ interface IDirectory {
453
439
  * Gets a list of files (not directories) in the directory.
454
440
  *
455
441
  * @param options - Optional configuration for getting files
456
- * @returns A promise that resolves to an array of File instances
442
+ * @returns An async generator that yields File instances
457
443
  *
458
444
  * @example
459
445
  * ```typescript
460
446
  * // Get immediate files
461
- * const files = await dir.getFiles();
447
+ * for await (const file of dir.getFiles()) {
448
+ * console.log(file.getName());
449
+ * }
462
450
  *
463
451
  * // Get all files recursively
464
- * const allFiles = await dir.getFiles({ recursive: true });
452
+ * for await (const file of dir.getFiles({ recursive: true })) {
453
+ * console.log(file.getName());
454
+ * }
465
455
  *
466
456
  * // Get only TypeScript files
467
- * const tsFiles = await dir.getFiles({ pattern: /\.ts$/ });
457
+ * for await (const file of dir.getFiles({ pattern: /\.ts$/ })) {
458
+ * console.log(file.getName());
459
+ * }
468
460
  * ```
469
461
  */
470
- getFiles: (options?: DirectoryGetFilesOptionsType) => Promise<IFile[]>;
462
+ getFiles: (options?: DirectoryGetFilesOptionsType) => AsyncGenerator<IFile>;
471
463
  /**
472
464
  * Gets a list of subdirectories (not files) in the directory.
473
465
  *
474
466
  * @param options - Optional configuration for getting directories
475
- * @returns A promise that resolves to an array of Directory instances
467
+ * @returns An async generator that yields Directory instances
476
468
  *
477
469
  * @example
478
470
  * ```typescript
479
471
  * // Get immediate subdirectories
480
- * const dirs = await dir.getDirectories();
472
+ * for await (const subdir of dir.getDirectories()) {
473
+ * console.log(subdir.getName());
474
+ * }
481
475
  *
482
476
  * // Get all subdirectories recursively
483
- * const allDirs = await dir.getDirectories({ recursive: true });
477
+ * for await (const subdir of dir.getDirectories({ recursive: true })) {
478
+ * console.log(subdir.getName());
479
+ * }
484
480
  *
485
481
  * // Get only directories starting with "test"
486
- * const testDirs = await dir.getDirectories({ pattern: /^test/ });
482
+ * for await (const subdir of dir.getDirectories({ pattern: /^test/ })) {
483
+ * console.log(subdir.getName());
484
+ * }
487
485
  * ```
488
486
  */
489
- getDirectories: (options?: DirectoryGetDirectoriesOptionsType) => Promise<IDirectory[]>;
487
+ getDirectories: (options?: DirectoryGetDirectoriesOptionsType) => AsyncGenerator<IDirectory>;
490
488
  /**
491
489
  * Changes to a subdirectory and returns a new Directory instance.
492
490
  *
@@ -872,7 +870,7 @@ type DirectoryWatchCallbackType = (event: DirectoryWatchEventType, filename: str
872
870
  * });
873
871
  * ```
874
872
  */
875
- type DirectoryWatcherType = ReturnType<typeof watch_odwmqucckw>;
873
+ type DirectoryWatcherType = ReturnType<typeof watch_jekclobzjd>;
876
874
  /**
877
875
  * A class for performing directory operations using Bun's optimized fs APIs.
878
876
  *
@@ -1186,12 +1184,12 @@ declare class Directory implements IDirectory {
1186
1184
  */
1187
1185
  getSize(): Promise<number>;
1188
1186
  /**
1189
- * Gets a list of files (not directories) in the directory.
1187
+ * Gets files (not directories) in the directory as an async generator.
1190
1188
  *
1191
1189
  * @param options - Optional configuration for getting files
1192
1190
  * @param options.recursive - Get files recursively from subdirectories (default: false)
1193
1191
  * @param options.pattern - Regular expression to filter files by name
1194
- * @returns A promise that resolves to an array of File instances
1192
+ * @returns An async generator that yields File instances
1195
1193
  * @throws {DirectoryException} If the files cannot be listed
1196
1194
  *
1197
1195
  * @example
@@ -1199,29 +1197,29 @@ declare class Directory implements IDirectory {
1199
1197
  * const dir = new Directory("/path/to/directory");
1200
1198
  *
1201
1199
  * // Get immediate files only
1202
- * const files = await dir.getFiles();
1203
- * for (const file of files) {
1200
+ * for await (const file of dir.getFiles()) {
1204
1201
  * console.log(file.getName());
1205
1202
  * }
1206
1203
  *
1207
1204
  * // Get all files recursively
1208
- * const allFiles = await dir.getFiles({ recursive: true });
1205
+ * for await (const file of dir.getFiles({ recursive: true })) {
1206
+ * console.log(file.getName());
1207
+ * }
1209
1208
  *
1210
1209
  * // Get only TypeScript files
1211
- * const tsFiles = await dir.getFiles({ pattern: /\.ts$/ });
1212
- *
1213
- * // Get TypeScript files recursively
1214
- * const allTsFiles = await dir.getFiles({ recursive: true, pattern: /\.tsx?$/ });
1210
+ * for await (const file of dir.getFiles({ pattern: /\.ts$/ })) {
1211
+ * console.log(file.getName());
1212
+ * }
1215
1213
  * ```
1216
1214
  */
1217
- getFiles(options?: DirectoryGetFilesOptionsType): Promise<IFile[]>;
1215
+ getFiles(options?: DirectoryGetFilesOptionsType): AsyncGenerator<IFile>;
1218
1216
  /**
1219
- * Gets a list of subdirectories (not files) in the directory.
1217
+ * Gets subdirectories (not files) in the directory as an async generator.
1220
1218
  *
1221
1219
  * @param options - Optional configuration for getting directories
1222
1220
  * @param options.recursive - Get directories recursively from subdirectories (default: false)
1223
1221
  * @param options.pattern - Regular expression to filter directories by name
1224
- * @returns A promise that resolves to an array of Directory instances
1222
+ * @returns An async generator that yields Directory instances
1225
1223
  * @throws {DirectoryException} If the directories cannot be listed
1226
1224
  *
1227
1225
  * @example
@@ -1229,22 +1227,22 @@ declare class Directory implements IDirectory {
1229
1227
  * const dir = new Directory("/path/to/directory");
1230
1228
  *
1231
1229
  * // Get immediate subdirectories only
1232
- * const dirs = await dir.getDirectories();
1233
- * for (const subdir of dirs) {
1230
+ * for await (const subdir of dir.getDirectories()) {
1234
1231
  * console.log(subdir.getName());
1235
1232
  * }
1236
1233
  *
1237
1234
  * // Get all subdirectories recursively
1238
- * const allDirs = await dir.getDirectories({ recursive: true });
1235
+ * for await (const subdir of dir.getDirectories({ recursive: true })) {
1236
+ * console.log(subdir.getName());
1237
+ * }
1239
1238
  *
1240
1239
  * // Get only directories starting with "test"
1241
- * const testDirs = await dir.getDirectories({ pattern: /^test/ });
1242
- *
1243
- * // Get directories recursively matching pattern
1244
- * const srcDirs = await dir.getDirectories({ recursive: true, pattern: /^src/ });
1240
+ * for await (const subdir of dir.getDirectories({ pattern: /^test/ })) {
1241
+ * console.log(subdir.getName());
1242
+ * }
1245
1243
  * ```
1246
1244
  */
1247
- getDirectories(options?: DirectoryGetDirectoriesOptionsType): Promise<IDirectory[]>;
1245
+ getDirectories(options?: DirectoryGetDirectoriesOptionsType): AsyncGenerator<IDirectory>;
1248
1246
  /**
1249
1247
  * Changes to a subdirectory and returns a new Directory instance.
1250
1248
  *
@@ -1483,58 +1481,55 @@ declare class File implements IFile {
1483
1481
  */
1484
1482
  bytes(): Promise<Uint8Array>;
1485
1483
  /**
1486
- * Returns a ReadableStream for incremental file reading.
1484
+ * Returns an async generator for incremental file reading.
1487
1485
  *
1488
- * @returns A ReadableStream of Uint8Array chunks
1486
+ * @returns An async generator that yields Uint8Array chunks
1489
1487
  *
1490
1488
  * @example
1491
1489
  * ```typescript
1492
1490
  * const file = new File("/path/to/large-file.txt");
1493
- * const stream = file.stream();
1494
1491
  *
1495
- * for await (const chunk of stream) {
1492
+ * for await (const chunk of file.stream()) {
1496
1493
  * console.log(`Received ${chunk.length} bytes`);
1497
1494
  * }
1498
1495
  * ```
1499
1496
  */
1500
- stream(): ReadableStream<Uint8Array>;
1497
+ stream(): AsyncGenerator<Uint8Array>;
1501
1498
  /**
1502
- * Returns a ReadableStream for incremental file reading as text.
1499
+ * Returns an async generator for incremental file reading as text.
1503
1500
  *
1504
- * @returns A ReadableStream of string chunks
1501
+ * @returns An async generator that yields string chunks
1505
1502
  *
1506
1503
  * @example
1507
1504
  * ```typescript
1508
1505
  * const file = new File("/path/to/large-file.txt");
1509
- * const stream = file.streamAsText();
1510
1506
  *
1511
- * for await (const chunk of stream) {
1507
+ * for await (const chunk of file.streamAsText()) {
1512
1508
  * console.log(`Received text: ${chunk}`);
1513
1509
  * }
1514
1510
  * ```
1515
1511
  */
1516
- streamAsText(): ReadableStream<string>;
1512
+ streamAsText(): AsyncGenerator<string>;
1517
1513
  /**
1518
- * Returns a ReadableStream for incremental JSON parsing from a JSON array file.
1514
+ * Returns an async generator for incremental JSON parsing from a JSON array file.
1519
1515
  *
1520
- * Reads a file containing a JSON array and streams each parsed element individually.
1516
+ * Reads a file containing a JSON array and yields each parsed element individually.
1521
1517
  * This is useful for processing large JSON array files without loading everything into memory.
1522
1518
  *
1523
1519
  * @typeParam T - The expected type of each JSON element
1524
- * @returns A ReadableStream of parsed JSON elements
1520
+ * @returns An async generator that yields parsed JSON elements
1525
1521
  *
1526
1522
  * @example
1527
1523
  * ```typescript
1528
1524
  * // For a file containing: [{"id": 1}, {"id": 2}, {"id": 3}]
1529
1525
  * const file = new File("/path/to/data.json");
1530
- * const stream = file.streamAsJson<{ id: number }>();
1531
1526
  *
1532
- * for await (const item of stream) {
1527
+ * for await (const item of file.streamAsJson<{ id: number }>()) {
1533
1528
  * console.log(item.id); // 1, 2, 3
1534
1529
  * }
1535
1530
  * ```
1536
1531
  */
1537
- streamAsJson<T = unknown>(): ReadableStream<T>;
1532
+ streamAsJson<T = unknown>(): AsyncGenerator<T>;
1538
1533
  /**
1539
1534
  * Writes data to the file, overwriting existing content.
1540
1535
  *
@@ -1612,26 +1607,7 @@ declare class File implements IFile {
1612
1607
  * ```
1613
1608
  */
1614
1609
  delete(): Promise<void>;
1615
- /**
1616
- * Downloads a file from a URL and saves it to this file's path.
1617
- *
1618
- * @param url - The URL to download the file from
1619
- * @returns A promise that resolves to the number of bytes written
1620
- * @throws {FileException} If the download or write operation fails
1621
- *
1622
- * @example
1623
- * ```typescript
1624
- * const file = new File("/path/to/image.png");
1625
- *
1626
- * // Download from URL
1627
- * const bytes = await file.download("https://example.com/image.png");
1628
- * console.log(`Downloaded ${bytes} bytes`);
1629
- *
1630
- * // Download with URL object
1631
- * await file.download(new URL("https://example.com/data.json"));
1632
- * ```
1633
- */
1634
- download(url: string | URL): Promise<number>;
1610
+ static download(url: string | URL, out: string): Promise<IFile>;
1635
1611
  /**
1636
1612
  * Returns a FileSink for incremental writing.
1637
1613
  *
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{watch as F}from"fs";import{cp as S,mkdir as m,readdir as B,rename as g,rm as P}from"fs/promises";import{basename as w,dirname as D,join as _}from"path";import{Exception as k}from"@ooneex/exception";import{HttpStatus as T}from"@ooneex/http-status";class Q extends k{constructor(H,R={}){super(H,{status:T.Code.InternalServerError,data:R});this.name="DirectoryException"}}import{basename as v,dirname as E,extname as j,join as x}from"path";import{Exception as N}from"@ooneex/exception";import{HttpStatus as z}from"@ooneex/http-status";class V extends N{constructor(H,R={}){super(H,{status:z.Code.InternalServerError,data:R});this.name="FileException"}}class U{path;options;constructor(H,R){let J=H instanceof URL?H.pathname:H,q=J.startsWith("/"),K=x(...J.split(/[/\\]/));this.path=q?`/${K}`:K,this.options=R}getBunFile(){return Bun.file(this.path,this.options)}getPath(){return this.path}getName(){return v(this.path)}getExtension(){let H=j(this.path);return H.startsWith(".")?H.slice(1):H}getDirectory(){return new $(E(this.path))}getSize(){return this.getBunFile().size}getType(){return this.getBunFile().type}async exists(){try{return(await this.getBunFile().stat()).isFile()}catch{return!1}}async text(){try{return await this.getBunFile().text()}catch(H){throw new V(`Failed to read file as text: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async json(){try{return await this.getBunFile().json()}catch(H){throw new V(`Failed to read file as JSON: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async arrayBuffer(){try{return await this.getBunFile().arrayBuffer()}catch(H){throw new V(`Failed to read file as ArrayBuffer: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async bytes(){try{return await this.getBunFile().bytes()}catch(H){throw new V(`Failed to read file as Uint8Array: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}stream(){return this.getBunFile().stream()}streamAsText(){let H=this.getBunFile().stream(),R=new TextDecoder;return new ReadableStream({async start(J){let q=H.getReader();try{while(!0){let{done:K,value:Y}=await q.read();if(K)break;J.enqueue(R.decode(Y,{stream:!0}))}J.close()}catch(K){J.error(K)}finally{q.releaseLock()}}})}streamAsJson(){let H=this.getBunFile().stream(),R=new TextDecoder,J="",q=0,K=!1,Y=!1,G=-1,O=!1;return new ReadableStream({async start(I){let C=H.getReader();try{while(!0){let{done:M,value:L}=await C.read();if(M)break;J+=R.decode(L,{stream:!0});let X=0;while(X<J.length){let Z=J[X];if(Y){Y=!1,X++;continue}if(Z==="\\"&&K){Y=!0,X++;continue}if(Z==='"'){K=!K,X++;continue}if(K){X++;continue}if(Z==="["&&!O){O=!0,X++;continue}if(Z==="{"||Z==="["){if(q===0)G=X;q++}else if(Z==="}"||Z==="]"){if(q--,q===0&&G!==-1){let W=J.slice(G,X+1);try{let A=JSON.parse(W);I.enqueue(A)}catch{}J=J.slice(X+1),X=-1,G=-1}}X++}}I.close()}catch(M){I.error(M)}finally{C.releaseLock()}}})}async write(H){try{return await Bun.write(this.path,H)}catch(R){throw new V(`Failed to write to file: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async append(H){try{let R=this.getBunFile(),q=await R.exists()?await R.bytes():new Uint8Array(0),K=typeof H==="string"?new TextEncoder().encode(H):H,Y=new Uint8Array(q.length+K.length);return Y.set(q),Y.set(K,q.length),await Bun.write(this.path,Y)}catch(R){throw new V(`Failed to append to file: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async copy(H){try{return await Bun.write(H,this.getBunFile()),new U(H)}catch(R){throw new V(`Failed to copy file: ${this.path}`,{path:this.path,destination:H,error:R instanceof Error?R.message:String(R)})}}async delete(){try{await this.getBunFile().delete()}catch(H){throw new V(`Failed to delete file: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async download(H){try{let R=await fetch(H);if(!R.ok)throw new V(`HTTP error: ${R.status} ${R.statusText}`);return await Bun.write(this.path,R)}catch(R){throw new V(`Failed to download file from URL: ${H.toString()}`,{path:this.path,url:H.toString(),error:R instanceof Error?R.message:String(R)})}}writer(H){return this.getBunFile().writer(H)}}class ${path;constructor(H){let R=H.startsWith("/"),J=_(...H.split(/[/\\]/));this.path=R?`/${J}`:J}getPath(){return this.path}getName(){return w(this.path)}getParent(){return D(this.path)}async exists(){try{return(await Bun.file(this.path).stat()).isDirectory()}catch{return!1}}async mkdir(H){try{await m(this.path,{recursive:H?.recursive??!0,mode:H?.mode})}catch(R){throw new Q(`Failed to create directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async rm(H){try{await P(this.path,{recursive:H?.recursive??!0,force:H?.force??!1})}catch(R){throw new Q(`Failed to delete directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async ls(H){try{return await B(this.path,{recursive:H?.recursive??!1})}catch(R){throw new Q(`Failed to list directory contents: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async lsWithTypes(H){try{return await B(this.path,{withFileTypes:!0,recursive:H?.recursive??!1})}catch(R){throw new Q(`Failed to list directory contents with types: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async cp(H,R){try{await S(this.path,H,{recursive:R?.recursive??!0,force:R?.overwrite??!1})}catch(J){throw new Q(`Failed to copy directory: ${this.path}`,{path:this.path,destination:H,error:J instanceof Error?J.message:String(J)})}}async mv(H){try{await g(this.path,H)}catch(R){throw new Q(`Failed to move directory: ${this.path}`,{path:this.path,destination:H,error:R instanceof Error?R.message:String(R)})}}async stat(){try{return await Bun.file(this.path).stat()}catch(H){throw new Q(`Failed to get directory stats: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}watch(H,R){return F(this.path,{recursive:R?.recursive??!1},H)}async isEmpty(){try{return(await B(this.path)).length===0}catch(H){throw new Q(`Failed to check if directory is empty: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async getSize(){try{return await this.calculateSize(this.path)}catch(H){throw new Q(`Failed to calculate directory size: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async getFiles(H){try{let J=(await B(this.path,{withFileTypes:!0,recursive:H?.recursive??!1})).filter((q)=>q.isFile()).map((q)=>{if(q.parentPath&&q.parentPath!==this.path){let K=q.parentPath.slice(this.path.length+1);return _(K,q.name)}return q.name});if(H?.pattern){let q=H.pattern;J=J.filter((K)=>q.test(K))}return J.map((q)=>new U(_(this.path,q)))}catch(R){throw new Q(`Failed to get files from directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async getDirectories(H){try{let J=(await B(this.path,{withFileTypes:!0,recursive:H?.recursive??!1})).filter((q)=>q.isDirectory()).map((q)=>{if(q.parentPath&&q.parentPath!==this.path){let K=q.parentPath.slice(this.path.length+1);return _(K,q.name)}return q.name});if(H?.pattern){let q=H.pattern;J=J.filter((K)=>q.test(K))}return J.map((q)=>new $(_(this.path,q)))}catch(R){throw new Q(`Failed to get directories from directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}cd(...H){return new $(_(this.path,...H))}async calculateSize(H){let R=0,J=await B(H,{withFileTypes:!0});for(let q of J){let K=_(H,q.name);if(q.isDirectory())R+=await this.calculateSize(K);else if(q.isFile())R+=Bun.file(K).size}return R}}export{V as FileException,U as File,Q as DirectoryException,$ as Directory};
2
+ import{watch as k}from"fs";import{cp as z,mkdir as v,readdir as U,rename as E,rm as j}from"fs/promises";import{basename as x,dirname as S,join as Z}from"path";import{Exception as M}from"@ooneex/exception";import{HttpStatus as O}from"@ooneex/http-status";class Q extends M{constructor(H,R={}){super(H,{status:O.Code.InternalServerError,data:R});this.name="DirectoryException"}}import{basename as W,dirname as A,extname as T,join as N}from"path";import{Exception as C}from"@ooneex/exception";import{HttpStatus as L}from"@ooneex/http-status";class V extends C{constructor(H,R={}){super(H,{status:L.Code.InternalServerError,data:R});this.name="FileException"}}class ${path;options;constructor(H,R){let q=H instanceof URL?H.pathname:H,J=q.startsWith("/"),K=N(...q.split(/[/\\]/));this.path=J?`/${K}`:K,this.options=R}getBunFile(){return Bun.file(this.path,this.options)}getPath(){return this.path}getName(){return W(this.path)}getExtension(){let H=T(this.path);return H.startsWith(".")?H.slice(1):H}getDirectory(){return new B(A(this.path))}getSize(){return this.getBunFile().size}getType(){return this.getBunFile().type}async exists(){try{return(await this.getBunFile().stat()).isFile()}catch{return!1}}async text(){try{return await this.getBunFile().text()}catch(H){throw new V(`Failed to read file as text: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async json(){try{return await this.getBunFile().json()}catch(H){throw new V(`Failed to read file as JSON: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async arrayBuffer(){try{return await this.getBunFile().arrayBuffer()}catch(H){throw new V(`Failed to read file as ArrayBuffer: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async bytes(){try{return await this.getBunFile().bytes()}catch(H){throw new V(`Failed to read file as Uint8Array: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async*stream(){let H=this.getBunFile().stream().getReader();try{while(!0){let{done:R,value:q}=await H.read();if(R)break;yield q}}finally{H.releaseLock()}}async*streamAsText(){let H=new TextDecoder;for await(let R of this.stream())yield H.decode(R,{stream:!0})}async*streamAsJson(){let H="",R=0,q=!1,J=!1,K=-1,_=!1;for await(let G of this.streamAsText()){H+=G;let X=0;while(X<H.length){let Y=H[X];if(J){J=!1,X++;continue}if(Y==="\\"&&q){J=!0,X++;continue}if(Y==='"'){q=!q,X++;continue}if(q){X++;continue}if(Y==="["&&!_){_=!0,X++;continue}if(Y==="{"||Y==="["){if(R===0)K=X;R++}else if(Y==="}"||Y==="]"){if(R--,R===0&&K!==-1){let I=H.slice(K,X+1);try{yield JSON.parse(I)}catch{}H=H.slice(X+1),X=-1,K=-1}}X++}}}async write(H){try{return await Bun.write(this.path,H)}catch(R){throw new V(`Failed to write to file: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async append(H){try{let R=this.getBunFile(),J=await R.exists()?await R.bytes():new Uint8Array(0),K=typeof H==="string"?new TextEncoder().encode(H):H,_=new Uint8Array(J.length+K.length);return _.set(J),_.set(K,J.length),await Bun.write(this.path,_)}catch(R){throw new V(`Failed to append to file: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async copy(H){try{return await Bun.write(H,this.getBunFile()),new $(H)}catch(R){throw new V(`Failed to copy file: ${this.path}`,{path:this.path,destination:H,error:R instanceof Error?R.message:String(R)})}}async delete(){try{await this.getBunFile().delete()}catch(H){throw new V(`Failed to delete file: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}static async download(H,R){try{let q=await fetch(H);if(!q.ok)throw new V(`HTTP error: ${q.status} ${q.statusText}`);return await Bun.write(R,q),new $(R)}catch(q){throw new V(`Failed to download file from URL: ${H.toString()}`,{path:R,url:H.toString(),error:q instanceof Error?q.message:String(q)})}}writer(H){return this.getBunFile().writer(H)}}class B{path;constructor(H){let R=H.startsWith("/"),q=Z(...H.split(/[/\\]/));this.path=R?`/${q}`:q}getPath(){return this.path}getName(){return x(this.path)}getParent(){return S(this.path)}async exists(){try{return(await Bun.file(this.path).stat()).isDirectory()}catch{return!1}}async mkdir(H){try{await v(this.path,{recursive:H?.recursive??!0,mode:H?.mode})}catch(R){throw new Q(`Failed to create directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async rm(H){try{await j(this.path,{recursive:H?.recursive??!0,force:H?.force??!1})}catch(R){throw new Q(`Failed to delete directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async ls(H){try{return await U(this.path,{recursive:H?.recursive??!1})}catch(R){throw new Q(`Failed to list directory contents: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async lsWithTypes(H){try{return await U(this.path,{withFileTypes:!0,recursive:H?.recursive??!1})}catch(R){throw new Q(`Failed to list directory contents with types: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async cp(H,R){try{await z(this.path,H,{recursive:R?.recursive??!0,force:R?.overwrite??!1})}catch(q){throw new Q(`Failed to copy directory: ${this.path}`,{path:this.path,destination:H,error:q instanceof Error?q.message:String(q)})}}async mv(H){try{await E(this.path,H)}catch(R){throw new Q(`Failed to move directory: ${this.path}`,{path:this.path,destination:H,error:R instanceof Error?R.message:String(R)})}}async stat(){try{return await Bun.file(this.path).stat()}catch(H){throw new Q(`Failed to get directory stats: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}watch(H,R){return k(this.path,{recursive:R?.recursive??!1},H)}async isEmpty(){try{return(await U(this.path)).length===0}catch(H){throw new Q(`Failed to check if directory is empty: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async getSize(){try{return await this.calculateSize(this.path)}catch(H){throw new Q(`Failed to calculate directory size: ${this.path}`,{path:this.path,error:H instanceof Error?H.message:String(H)})}}async*getFiles(H){try{let R=await U(this.path,{withFileTypes:!0,recursive:H?.recursive??!1});for(let q of R){if(!q.isFile())continue;let J;if(q.parentPath&&q.parentPath!==this.path){let K=q.parentPath.slice(this.path.length+1);J=Z(K,q.name)}else J=q.name;if(H?.pattern&&!H.pattern.test(J))continue;yield new $(Z(this.path,J))}}catch(R){throw new Q(`Failed to get files from directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}async*getDirectories(H){try{let R=await U(this.path,{withFileTypes:!0,recursive:H?.recursive??!1});for(let q of R){if(!q.isDirectory())continue;let J;if(q.parentPath&&q.parentPath!==this.path){let K=q.parentPath.slice(this.path.length+1);J=Z(K,q.name)}else J=q.name;if(H?.pattern&&!H.pattern.test(J))continue;yield new B(Z(this.path,J))}}catch(R){throw new Q(`Failed to get directories from directory: ${this.path}`,{path:this.path,error:R instanceof Error?R.message:String(R)})}}cd(...H){return new B(Z(this.path,...H))}async calculateSize(H){let R=0,q=await U(H,{withFileTypes:!0});for(let J of q){let K=Z(H,J.name);if(J.isDirectory())R+=await this.calculateSize(K);else if(J.isFile())R+=Bun.file(K).size}return R}}export{V as FileException,$ as File,Q as DirectoryException,B as Directory};
3
3
 
4
- //# debugId=329F88F8B0F876C764756E2164756E21
4
+ //# debugId=1E8724F72312714C64756E2164756E21
package/dist/index.js.map CHANGED
@@ -2,12 +2,12 @@
2
2
  "version": 3,
3
3
  "sources": ["src/Directory.ts", "src/DirectoryException.ts", "src/File.ts", "src/FileException.ts"],
4
4
  "sourcesContent": [
5
- "import type { Dirent, Stats } from \"node:fs\";\nimport { watch } from \"node:fs\";\nimport { cp, mkdir, readdir, rename, rm } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { DirectoryException } from \"./DirectoryException\";\nimport { File } from \"./File\";\nimport type {\n DirectoryCopyOptionsType,\n DirectoryCreateOptionsType,\n DirectoryDeleteOptionsType,\n DirectoryGetDirectoriesOptionsType,\n DirectoryGetFilesOptionsType,\n DirectoryListOptionsType,\n DirectoryWatchCallbackType,\n DirectoryWatcherType,\n DirectoryWatchOptionsType,\n IDirectory,\n IFile,\n} from \"./types\";\n\n/**\n * A class for performing directory operations using Bun's optimized fs APIs.\n *\n * @example\n * ```typescript\n * import { Directory } from \"@ooneex/fs\";\n *\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Create directory\n * await dir.mkdir();\n *\n * // List contents\n * const files = await dir.ls();\n *\n * // Check if empty\n * if (await dir.isEmpty()) {\n * await dir.rm();\n * }\n * ```\n */\nexport class Directory implements IDirectory {\n private readonly path: string;\n\n /**\n * Creates a new Directory instance.\n *\n * @param path - The directory path as a string\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const homeDir = new Directory(\"~/Documents\");\n * const relativeDir = new Directory(\"./src\");\n * ```\n */\n constructor(path: string) {\n const isAbsolute = path.startsWith(\"/\");\n const normalized = join(...path.split(/[/\\\\]/));\n this.path = isAbsolute ? `/${normalized}` : normalized;\n }\n\n /**\n * Returns the directory path.\n *\n * @returns The absolute or relative path of the directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getPath()); // \"/path/to/mydir\"\n * ```\n */\n public getPath(): string {\n return this.path;\n }\n\n /**\n * Returns the directory name.\n *\n * @returns The base name of the directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getName()); // \"mydir\"\n * ```\n */\n public getName(): string {\n return basename(this.path);\n }\n\n /**\n * Returns the parent directory path.\n *\n * @returns The path of the parent directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getParent()); // \"/path/to\"\n * ```\n */\n public getParent(): string {\n return dirname(this.path);\n }\n\n /**\n * Checks if the directory exists.\n *\n * @returns A promise that resolves to true if the directory exists\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * if (await dir.exists()) {\n * console.log(\"Directory exists!\");\n * } else {\n * await dir.mkdir();\n * }\n * ```\n */\n public async exists(): Promise<boolean> {\n try {\n const stats = await Bun.file(this.path).stat();\n return stats.isDirectory();\n } catch {\n return false;\n }\n }\n\n /**\n * Creates the directory on disk.\n *\n * @param options - Optional configuration for directory creation\n * @param options.recursive - Create parent directories if needed (default: true)\n * @param options.mode - Directory permissions (e.g., 0o755)\n * @throws {DirectoryException} If the directory cannot be created\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/new/nested/directory\");\n *\n * // Create with all parent directories (default behavior)\n * await dir.mkdir();\n *\n * // Create with specific permissions\n * await dir.mkdir({ mode: 0o700 });\n *\n * // Create without recursive (fails if parent doesn't exist)\n * await dir.mkdir({ recursive: false });\n * ```\n */\n public async mkdir(options?: DirectoryCreateOptionsType): Promise<void> {\n try {\n await mkdir(this.path, {\n recursive: options?.recursive ?? true,\n mode: options?.mode,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to create directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Deletes the directory from disk.\n *\n * @param options - Optional configuration for directory deletion\n * @param options.recursive - Delete contents recursively (default: true)\n * @param options.force - Ignore errors if directory doesn't exist (default: false)\n * @throws {DirectoryException} If the directory cannot be deleted\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Delete directory and all contents\n * await dir.rm();\n *\n * // Delete only if empty\n * await dir.rm({ recursive: false });\n *\n * // Delete without throwing if doesn't exist\n * await dir.rm({ force: true });\n * ```\n */\n public async rm(options?: DirectoryDeleteOptionsType): Promise<void> {\n try {\n await rm(this.path, {\n recursive: options?.recursive ?? true,\n force: options?.force ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to delete directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Lists the contents of the directory.\n *\n * @param options - Optional configuration for listing\n * @param options.recursive - List contents recursively (default: false)\n * @returns A promise that resolves to an array of file/directory names\n * @throws {DirectoryException} If the directory cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // List immediate contents\n * const files = await dir.ls();\n * console.log(files); // [\"file1.txt\", \"file2.txt\", \"subdir\"]\n *\n * // List all contents recursively\n * const allFiles = await dir.ls({ recursive: true });\n * console.log(allFiles); // [\"file1.txt\", \"file2.txt\", \"subdir\", \"subdir/nested.txt\"]\n * ```\n */\n public async ls(options?: DirectoryListOptionsType): Promise<string[]> {\n try {\n const entries = await readdir(this.path, {\n recursive: options?.recursive ?? false,\n });\n return entries as string[];\n } catch (error) {\n throw new DirectoryException(`Failed to list directory contents: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Lists the contents of the directory with type information.\n *\n * @param options - Optional configuration for listing\n * @param options.recursive - List contents recursively (default: false)\n * @returns A promise that resolves to an array of Dirent objects\n * @throws {DirectoryException} If the directory cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const entries = await dir.lsWithTypes();\n *\n * for (const entry of entries) {\n * if (entry.isFile()) {\n * console.log(`File: ${entry.name}`);\n * } else if (entry.isDirectory()) {\n * console.log(`Directory: ${entry.name}`);\n * } else if (entry.isSymbolicLink()) {\n * console.log(`Symlink: ${entry.name}`);\n * }\n * }\n * ```\n */\n public async lsWithTypes(options?: DirectoryListOptionsType): Promise<Dirent[]> {\n try {\n return await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to list directory contents with types: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Copies the directory to a destination path.\n *\n * @param destination - The destination directory path\n * @param options - Optional configuration for copying\n * @param options.recursive - Copy contents recursively (default: true)\n * @param options.overwrite - Overwrite existing files (default: false)\n * @throws {DirectoryException} If the directory cannot be copied\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/source\");\n *\n * // Copy directory and all contents\n * await dir.cp(\"/path/to/destination\");\n *\n * // Copy with overwrite\n * await dir.cp(\"/path/to/destination\", { overwrite: true });\n *\n * // Copy only the directory structure (no files)\n * await dir.cp(\"/path/to/destination\", { recursive: false });\n * ```\n */\n public async cp(destination: string, options?: DirectoryCopyOptionsType): Promise<void> {\n try {\n await cp(this.path, destination, {\n recursive: options?.recursive ?? true,\n force: options?.overwrite ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to copy directory: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Moves (renames) the directory to a new location.\n *\n * @param destination - The new directory path\n * @throws {DirectoryException} If the directory cannot be moved\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/oldname\");\n *\n * // Rename directory\n * await dir.mv(\"/path/to/newname\");\n *\n * // Move to different location\n * await dir.mv(\"/different/path/dirname\");\n * ```\n */\n public async mv(destination: string): Promise<void> {\n try {\n await rename(this.path, destination);\n } catch (error) {\n throw new DirectoryException(`Failed to move directory: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns the directory statistics.\n *\n * @returns A promise that resolves to a Stats object\n * @throws {DirectoryException} If stats cannot be retrieved\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const stats = await dir.stat();\n *\n * console.log(stats.isDirectory()); // true\n * console.log(stats.mode); // 16877 (permissions)\n * console.log(stats.mtime); // Date object (modification time)\n * console.log(stats.birthtime); // Date object (creation time)\n * ```\n */\n public async stat(): Promise<Stats> {\n try {\n return await Bun.file(this.path).stat();\n } catch (error) {\n throw new DirectoryException(`Failed to get directory stats: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Watches the directory for changes.\n *\n * @param callback - Function called when changes are detected\n * @param options - Optional configuration for watching\n * @param options.recursive - Watch subdirectories recursively (default: false)\n * @returns A FSWatcher that can be closed to stop watching\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Watch for changes\n * const watcher = dir.watch((event, filename) => {\n * console.log(`${event}: ${filename}`);\n * });\n *\n * // Watch recursively\n * const recursiveWatcher = dir.watch(\n * (event, filename) => console.log(event, filename),\n * { recursive: true }\n * );\n *\n * // Stop watching\n * watcher.close();\n *\n * // Handle close with SIGINT\n * process.on(\"SIGINT\", () => {\n * watcher.close();\n * process.exit(0);\n * });\n * ```\n */\n public watch(callback: DirectoryWatchCallbackType, options?: DirectoryWatchOptionsType): DirectoryWatcherType {\n return watch(this.path, { recursive: options?.recursive ?? false }, callback);\n }\n\n /**\n * Checks if the directory is empty.\n *\n * @returns A promise that resolves to true if the directory has no contents\n * @throws {DirectoryException} If the directory cannot be checked\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * if (await dir.isEmpty()) {\n * console.log(\"Directory is empty\");\n * await dir.rm();\n * } else {\n * console.log(\"Directory has contents\");\n * }\n * ```\n */\n public async isEmpty(): Promise<boolean> {\n try {\n const entries = await readdir(this.path);\n return entries.length === 0;\n } catch (error) {\n throw new DirectoryException(`Failed to check if directory is empty: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Calculates the total size of all contents in the directory.\n *\n * @returns A promise that resolves to the total size in bytes\n * @throws {DirectoryException} If the size cannot be calculated\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const sizeBytes = await dir.getSize();\n *\n * // Format as human-readable\n * const sizeMB = (sizeBytes / (1024 * 1024)).toFixed(2);\n * console.log(`Directory size: ${sizeMB} MB`);\n * ```\n */\n public async getSize(): Promise<number> {\n try {\n return await this.calculateSize(this.path);\n } catch (error) {\n throw new DirectoryException(`Failed to calculate directory size: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Gets a list of files (not directories) in the directory.\n *\n * @param options - Optional configuration for getting files\n * @param options.recursive - Get files recursively from subdirectories (default: false)\n * @param options.pattern - Regular expression to filter files by name\n * @returns A promise that resolves to an array of File instances\n * @throws {DirectoryException} If the files cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Get immediate files only\n * const files = await dir.getFiles();\n * for (const file of files) {\n * console.log(file.getName());\n * }\n *\n * // Get all files recursively\n * const allFiles = await dir.getFiles({ recursive: true });\n *\n * // Get only TypeScript files\n * const tsFiles = await dir.getFiles({ pattern: /\\.ts$/ });\n *\n * // Get TypeScript files recursively\n * const allTsFiles = await dir.getFiles({ recursive: true, pattern: /\\.tsx?$/ });\n * ```\n */\n public async getFiles(options?: DirectoryGetFilesOptionsType): Promise<IFile[]> {\n try {\n const entries = await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n\n let filePaths = entries\n .filter((entry) => entry.isFile())\n .map((entry) => {\n if (entry.parentPath && entry.parentPath !== this.path) {\n const relativePath = entry.parentPath.slice(this.path.length + 1);\n return join(relativePath, entry.name);\n }\n return entry.name;\n });\n\n if (options?.pattern) {\n const pattern = options.pattern;\n filePaths = filePaths.filter((filePath) => pattern.test(filePath));\n }\n\n return filePaths.map((filePath) => new File(join(this.path, filePath)));\n } catch (error) {\n throw new DirectoryException(`Failed to get files from directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Gets a list of subdirectories (not files) in the directory.\n *\n * @param options - Optional configuration for getting directories\n * @param options.recursive - Get directories recursively from subdirectories (default: false)\n * @param options.pattern - Regular expression to filter directories by name\n * @returns A promise that resolves to an array of Directory instances\n * @throws {DirectoryException} If the directories cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Get immediate subdirectories only\n * const dirs = await dir.getDirectories();\n * for (const subdir of dirs) {\n * console.log(subdir.getName());\n * }\n *\n * // Get all subdirectories recursively\n * const allDirs = await dir.getDirectories({ recursive: true });\n *\n * // Get only directories starting with \"test\"\n * const testDirs = await dir.getDirectories({ pattern: /^test/ });\n *\n * // Get directories recursively matching pattern\n * const srcDirs = await dir.getDirectories({ recursive: true, pattern: /^src/ });\n * ```\n */\n public async getDirectories(options?: DirectoryGetDirectoriesOptionsType): Promise<IDirectory[]> {\n try {\n const entries = await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n\n let dirPaths = entries\n .filter((entry) => entry.isDirectory())\n .map((entry) => {\n if (entry.parentPath && entry.parentPath !== this.path) {\n const relativePath = entry.parentPath.slice(this.path.length + 1);\n return join(relativePath, entry.name);\n }\n return entry.name;\n });\n\n if (options?.pattern) {\n const pattern = options.pattern;\n dirPaths = dirPaths.filter((dirPath) => pattern.test(dirPath));\n }\n\n return dirPaths.map((dirPath) => new Directory(join(this.path, dirPath)));\n } catch (error) {\n throw new DirectoryException(`Failed to get directories from directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Changes to a subdirectory and returns a new Directory instance.\n *\n * @param paths - The relative path segments to the subdirectory\n * @returns A new Directory instance pointing to the subdirectory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/project\");\n *\n * // Navigate to subdirectory\n * const srcDir = dir.cd(\"src\");\n * console.log(srcDir.getPath()); // \"/path/to/project/src\"\n *\n * // Navigate multiple levels with multiple args\n * const componentsDir = dir.cd(\"src\", \"components\", \"ui\");\n * console.log(componentsDir.getPath()); // \"/path/to/project/src/components/ui\"\n *\n * // Navigate to parent\n * const parentDir = dir.cd(\"..\");\n * console.log(parentDir.getPath()); // \"/path/to\"\n *\n * // Chain navigation\n * const deepDir = dir.cd(\"src\").cd(\"components\").cd(\"ui\");\n * ```\n */\n public cd(...paths: string[]): IDirectory {\n return new Directory(join(this.path, ...paths));\n }\n\n private async calculateSize(dirPath: string): Promise<number> {\n let totalSize = 0;\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n totalSize += await this.calculateSize(fullPath);\n } else if (entry.isFile()) {\n totalSize += Bun.file(fullPath).size;\n }\n }\n\n return totalSize;\n }\n}\n",
5
+ "import type { Dirent, Stats } from \"node:fs\";\nimport { watch } from \"node:fs\";\nimport { cp, mkdir, readdir, rename, rm } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { DirectoryException } from \"./DirectoryException\";\nimport { File } from \"./File\";\nimport type {\n DirectoryCopyOptionsType,\n DirectoryCreateOptionsType,\n DirectoryDeleteOptionsType,\n DirectoryGetDirectoriesOptionsType,\n DirectoryGetFilesOptionsType,\n DirectoryListOptionsType,\n DirectoryWatchCallbackType,\n DirectoryWatcherType,\n DirectoryWatchOptionsType,\n IDirectory,\n IFile,\n} from \"./types\";\n\n/**\n * A class for performing directory operations using Bun's optimized fs APIs.\n *\n * @example\n * ```typescript\n * import { Directory } from \"@ooneex/fs\";\n *\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Create directory\n * await dir.mkdir();\n *\n * // List contents\n * const files = await dir.ls();\n *\n * // Check if empty\n * if (await dir.isEmpty()) {\n * await dir.rm();\n * }\n * ```\n */\nexport class Directory implements IDirectory {\n private readonly path: string;\n\n /**\n * Creates a new Directory instance.\n *\n * @param path - The directory path as a string\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const homeDir = new Directory(\"~/Documents\");\n * const relativeDir = new Directory(\"./src\");\n * ```\n */\n constructor(path: string) {\n const isAbsolute = path.startsWith(\"/\");\n const normalized = join(...path.split(/[/\\\\]/));\n this.path = isAbsolute ? `/${normalized}` : normalized;\n }\n\n /**\n * Returns the directory path.\n *\n * @returns The absolute or relative path of the directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getPath()); // \"/path/to/mydir\"\n * ```\n */\n public getPath(): string {\n return this.path;\n }\n\n /**\n * Returns the directory name.\n *\n * @returns The base name of the directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getName()); // \"mydir\"\n * ```\n */\n public getName(): string {\n return basename(this.path);\n }\n\n /**\n * Returns the parent directory path.\n *\n * @returns The path of the parent directory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/mydir\");\n * console.log(dir.getParent()); // \"/path/to\"\n * ```\n */\n public getParent(): string {\n return dirname(this.path);\n }\n\n /**\n * Checks if the directory exists.\n *\n * @returns A promise that resolves to true if the directory exists\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * if (await dir.exists()) {\n * console.log(\"Directory exists!\");\n * } else {\n * await dir.mkdir();\n * }\n * ```\n */\n public async exists(): Promise<boolean> {\n try {\n const stats = await Bun.file(this.path).stat();\n return stats.isDirectory();\n } catch {\n return false;\n }\n }\n\n /**\n * Creates the directory on disk.\n *\n * @param options - Optional configuration for directory creation\n * @param options.recursive - Create parent directories if needed (default: true)\n * @param options.mode - Directory permissions (e.g., 0o755)\n * @throws {DirectoryException} If the directory cannot be created\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/new/nested/directory\");\n *\n * // Create with all parent directories (default behavior)\n * await dir.mkdir();\n *\n * // Create with specific permissions\n * await dir.mkdir({ mode: 0o700 });\n *\n * // Create without recursive (fails if parent doesn't exist)\n * await dir.mkdir({ recursive: false });\n * ```\n */\n public async mkdir(options?: DirectoryCreateOptionsType): Promise<void> {\n try {\n await mkdir(this.path, {\n recursive: options?.recursive ?? true,\n mode: options?.mode,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to create directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Deletes the directory from disk.\n *\n * @param options - Optional configuration for directory deletion\n * @param options.recursive - Delete contents recursively (default: true)\n * @param options.force - Ignore errors if directory doesn't exist (default: false)\n * @throws {DirectoryException} If the directory cannot be deleted\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Delete directory and all contents\n * await dir.rm();\n *\n * // Delete only if empty\n * await dir.rm({ recursive: false });\n *\n * // Delete without throwing if doesn't exist\n * await dir.rm({ force: true });\n * ```\n */\n public async rm(options?: DirectoryDeleteOptionsType): Promise<void> {\n try {\n await rm(this.path, {\n recursive: options?.recursive ?? true,\n force: options?.force ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to delete directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Lists the contents of the directory.\n *\n * @param options - Optional configuration for listing\n * @param options.recursive - List contents recursively (default: false)\n * @returns A promise that resolves to an array of file/directory names\n * @throws {DirectoryException} If the directory cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // List immediate contents\n * const files = await dir.ls();\n * console.log(files); // [\"file1.txt\", \"file2.txt\", \"subdir\"]\n *\n * // List all contents recursively\n * const allFiles = await dir.ls({ recursive: true });\n * console.log(allFiles); // [\"file1.txt\", \"file2.txt\", \"subdir\", \"subdir/nested.txt\"]\n * ```\n */\n public async ls(options?: DirectoryListOptionsType): Promise<string[]> {\n try {\n const entries = await readdir(this.path, {\n recursive: options?.recursive ?? false,\n });\n return entries as string[];\n } catch (error) {\n throw new DirectoryException(`Failed to list directory contents: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Lists the contents of the directory with type information.\n *\n * @param options - Optional configuration for listing\n * @param options.recursive - List contents recursively (default: false)\n * @returns A promise that resolves to an array of Dirent objects\n * @throws {DirectoryException} If the directory cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const entries = await dir.lsWithTypes();\n *\n * for (const entry of entries) {\n * if (entry.isFile()) {\n * console.log(`File: ${entry.name}`);\n * } else if (entry.isDirectory()) {\n * console.log(`Directory: ${entry.name}`);\n * } else if (entry.isSymbolicLink()) {\n * console.log(`Symlink: ${entry.name}`);\n * }\n * }\n * ```\n */\n public async lsWithTypes(options?: DirectoryListOptionsType): Promise<Dirent[]> {\n try {\n return await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to list directory contents with types: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Copies the directory to a destination path.\n *\n * @param destination - The destination directory path\n * @param options - Optional configuration for copying\n * @param options.recursive - Copy contents recursively (default: true)\n * @param options.overwrite - Overwrite existing files (default: false)\n * @throws {DirectoryException} If the directory cannot be copied\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/source\");\n *\n * // Copy directory and all contents\n * await dir.cp(\"/path/to/destination\");\n *\n * // Copy with overwrite\n * await dir.cp(\"/path/to/destination\", { overwrite: true });\n *\n * // Copy only the directory structure (no files)\n * await dir.cp(\"/path/to/destination\", { recursive: false });\n * ```\n */\n public async cp(destination: string, options?: DirectoryCopyOptionsType): Promise<void> {\n try {\n await cp(this.path, destination, {\n recursive: options?.recursive ?? true,\n force: options?.overwrite ?? false,\n });\n } catch (error) {\n throw new DirectoryException(`Failed to copy directory: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Moves (renames) the directory to a new location.\n *\n * @param destination - The new directory path\n * @throws {DirectoryException} If the directory cannot be moved\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/oldname\");\n *\n * // Rename directory\n * await dir.mv(\"/path/to/newname\");\n *\n * // Move to different location\n * await dir.mv(\"/different/path/dirname\");\n * ```\n */\n public async mv(destination: string): Promise<void> {\n try {\n await rename(this.path, destination);\n } catch (error) {\n throw new DirectoryException(`Failed to move directory: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns the directory statistics.\n *\n * @returns A promise that resolves to a Stats object\n * @throws {DirectoryException} If stats cannot be retrieved\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const stats = await dir.stat();\n *\n * console.log(stats.isDirectory()); // true\n * console.log(stats.mode); // 16877 (permissions)\n * console.log(stats.mtime); // Date object (modification time)\n * console.log(stats.birthtime); // Date object (creation time)\n * ```\n */\n public async stat(): Promise<Stats> {\n try {\n return await Bun.file(this.path).stat();\n } catch (error) {\n throw new DirectoryException(`Failed to get directory stats: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Watches the directory for changes.\n *\n * @param callback - Function called when changes are detected\n * @param options - Optional configuration for watching\n * @param options.recursive - Watch subdirectories recursively (default: false)\n * @returns A FSWatcher that can be closed to stop watching\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Watch for changes\n * const watcher = dir.watch((event, filename) => {\n * console.log(`${event}: ${filename}`);\n * });\n *\n * // Watch recursively\n * const recursiveWatcher = dir.watch(\n * (event, filename) => console.log(event, filename),\n * { recursive: true }\n * );\n *\n * // Stop watching\n * watcher.close();\n *\n * // Handle close with SIGINT\n * process.on(\"SIGINT\", () => {\n * watcher.close();\n * process.exit(0);\n * });\n * ```\n */\n public watch(callback: DirectoryWatchCallbackType, options?: DirectoryWatchOptionsType): DirectoryWatcherType {\n return watch(this.path, { recursive: options?.recursive ?? false }, callback);\n }\n\n /**\n * Checks if the directory is empty.\n *\n * @returns A promise that resolves to true if the directory has no contents\n * @throws {DirectoryException} If the directory cannot be checked\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * if (await dir.isEmpty()) {\n * console.log(\"Directory is empty\");\n * await dir.rm();\n * } else {\n * console.log(\"Directory has contents\");\n * }\n * ```\n */\n public async isEmpty(): Promise<boolean> {\n try {\n const entries = await readdir(this.path);\n return entries.length === 0;\n } catch (error) {\n throw new DirectoryException(`Failed to check if directory is empty: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Calculates the total size of all contents in the directory.\n *\n * @returns A promise that resolves to the total size in bytes\n * @throws {DirectoryException} If the size cannot be calculated\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n * const sizeBytes = await dir.getSize();\n *\n * // Format as human-readable\n * const sizeMB = (sizeBytes / (1024 * 1024)).toFixed(2);\n * console.log(`Directory size: ${sizeMB} MB`);\n * ```\n */\n public async getSize(): Promise<number> {\n try {\n return await this.calculateSize(this.path);\n } catch (error) {\n throw new DirectoryException(`Failed to calculate directory size: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Gets files (not directories) in the directory as an async generator.\n *\n * @param options - Optional configuration for getting files\n * @param options.recursive - Get files recursively from subdirectories (default: false)\n * @param options.pattern - Regular expression to filter files by name\n * @returns An async generator that yields File instances\n * @throws {DirectoryException} If the files cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Get immediate files only\n * for await (const file of dir.getFiles()) {\n * console.log(file.getName());\n * }\n *\n * // Get all files recursively\n * for await (const file of dir.getFiles({ recursive: true })) {\n * console.log(file.getName());\n * }\n *\n * // Get only TypeScript files\n * for await (const file of dir.getFiles({ pattern: /\\.ts$/ })) {\n * console.log(file.getName());\n * }\n * ```\n */\n public async *getFiles(options?: DirectoryGetFilesOptionsType): AsyncGenerator<IFile> {\n try {\n const entries = await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n\n let filePath: string;\n if (entry.parentPath && entry.parentPath !== this.path) {\n const relativePath = entry.parentPath.slice(this.path.length + 1);\n filePath = join(relativePath, entry.name);\n } else {\n filePath = entry.name;\n }\n\n if (options?.pattern && !options.pattern.test(filePath)) continue;\n\n yield new File(join(this.path, filePath));\n }\n } catch (error) {\n throw new DirectoryException(`Failed to get files from directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Gets subdirectories (not files) in the directory as an async generator.\n *\n * @param options - Optional configuration for getting directories\n * @param options.recursive - Get directories recursively from subdirectories (default: false)\n * @param options.pattern - Regular expression to filter directories by name\n * @returns An async generator that yields Directory instances\n * @throws {DirectoryException} If the directories cannot be listed\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/directory\");\n *\n * // Get immediate subdirectories only\n * for await (const subdir of dir.getDirectories()) {\n * console.log(subdir.getName());\n * }\n *\n * // Get all subdirectories recursively\n * for await (const subdir of dir.getDirectories({ recursive: true })) {\n * console.log(subdir.getName());\n * }\n *\n * // Get only directories starting with \"test\"\n * for await (const subdir of dir.getDirectories({ pattern: /^test/ })) {\n * console.log(subdir.getName());\n * }\n * ```\n */\n public async *getDirectories(options?: DirectoryGetDirectoriesOptionsType): AsyncGenerator<IDirectory> {\n try {\n const entries = await readdir(this.path, {\n withFileTypes: true,\n recursive: options?.recursive ?? false,\n });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n let dirPath: string;\n if (entry.parentPath && entry.parentPath !== this.path) {\n const relativePath = entry.parentPath.slice(this.path.length + 1);\n dirPath = join(relativePath, entry.name);\n } else {\n dirPath = entry.name;\n }\n\n if (options?.pattern && !options.pattern.test(dirPath)) continue;\n\n yield new Directory(join(this.path, dirPath));\n }\n } catch (error) {\n throw new DirectoryException(`Failed to get directories from directory: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Changes to a subdirectory and returns a new Directory instance.\n *\n * @param paths - The relative path segments to the subdirectory\n * @returns A new Directory instance pointing to the subdirectory\n *\n * @example\n * ```typescript\n * const dir = new Directory(\"/path/to/project\");\n *\n * // Navigate to subdirectory\n * const srcDir = dir.cd(\"src\");\n * console.log(srcDir.getPath()); // \"/path/to/project/src\"\n *\n * // Navigate multiple levels with multiple args\n * const componentsDir = dir.cd(\"src\", \"components\", \"ui\");\n * console.log(componentsDir.getPath()); // \"/path/to/project/src/components/ui\"\n *\n * // Navigate to parent\n * const parentDir = dir.cd(\"..\");\n * console.log(parentDir.getPath()); // \"/path/to\"\n *\n * // Chain navigation\n * const deepDir = dir.cd(\"src\").cd(\"components\").cd(\"ui\");\n * ```\n */\n public cd(...paths: string[]): IDirectory {\n return new Directory(join(this.path, ...paths));\n }\n\n private async calculateSize(dirPath: string): Promise<number> {\n let totalSize = 0;\n const entries = await readdir(dirPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name);\n if (entry.isDirectory()) {\n totalSize += await this.calculateSize(fullPath);\n } else if (entry.isFile()) {\n totalSize += Bun.file(fullPath).size;\n }\n }\n\n return totalSize;\n }\n}\n",
6
6
  "import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class DirectoryException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"DirectoryException\";\n }\n}\n",
7
- "import { basename, dirname, extname, join } from \"node:path\";\nimport type { BunFile } from \"bun\";\nimport { Directory } from \"./Directory\";\nimport { FileException } from \"./FileException\";\nimport type {\n BunFileSinkType,\n FileOptionsType,\n FileWriteDataType,\n FileWriterOptionsType,\n IDirectory,\n IFile,\n} from \"./types\";\n\n/**\n * A class for performing file operations using Bun's optimized file I/O APIs.\n *\n * @example\n * ```typescript\n * import { File } from \"@ooneex/fs\";\n *\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Read file content\n * const content = await file.text();\n *\n * // Write to file\n * await file.write(\"Hello, World!\");\n *\n * // Check if file exists\n * if (await file.exists()) {\n * console.log(\"File exists!\");\n * }\n * ```\n */\nexport class File implements IFile {\n private readonly path: string;\n private readonly options: FileOptionsType | undefined;\n\n /**\n * Creates a new File instance.\n *\n * @param path - The file path as a string or URL\n * @param options - Optional configuration options\n *\n * @example\n * ```typescript\n * // Using string path\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Using URL\n * const file = new File(new URL(\"file:///path/to/file.txt\"));\n *\n * // With custom MIME type\n * const file = new File(\"/path/to/file\", { type: \"application/json\" });\n * ```\n */\n constructor(path: string | URL, options?: FileOptionsType) {\n const pathStr = path instanceof URL ? path.pathname : path;\n const isAbsolute = pathStr.startsWith(\"/\");\n const normalized = join(...pathStr.split(/[/\\\\]/));\n this.path = isAbsolute ? `/${normalized}` : normalized;\n this.options = options;\n }\n\n private getBunFile(): BunFile {\n return Bun.file(this.path, this.options);\n }\n\n /**\n * Returns the file path.\n *\n * @returns The absolute or relative path of the file\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getPath()); // \"/path/to/document.pdf\"\n * ```\n */\n public getPath(): string {\n return this.path;\n }\n\n /**\n * Returns the file name including extension.\n *\n * @returns The base name of the file\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getName()); // \"document.pdf\"\n * ```\n */\n public getName(): string {\n return basename(this.path);\n }\n\n /**\n * Returns the file extension without the leading dot.\n *\n * @returns The file extension or empty string if none\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getExtension()); // \"pdf\"\n *\n * const noExt = new File(\"/path/to/README\");\n * console.log(noExt.getExtension()); // \"\"\n * ```\n */\n public getExtension(): string {\n const ext = extname(this.path);\n return ext.startsWith(\".\") ? ext.slice(1) : ext;\n }\n\n /**\n * Returns the directory containing the file.\n *\n * @returns The parent directory as an IDirectory instance\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * const dir = file.getDirectory();\n * console.log(dir.getPath()); // \"/path/to\"\n * ```\n */\n public getDirectory(): IDirectory {\n return new Directory(dirname(this.path));\n }\n\n /**\n * Returns the file size in bytes.\n *\n * @returns The size of the file in bytes, or 0 if file doesn't exist\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getSize()); // 1024\n * ```\n */\n public getSize(): number {\n return this.getBunFile().size;\n }\n\n /**\n * Returns the MIME type of the file.\n *\n * @returns The MIME type string (e.g., \"text/plain\", \"application/json\")\n *\n * @example\n * ```typescript\n * const txtFile = new File(\"/path/to/file.txt\");\n * console.log(txtFile.getType()); // \"text/plain;charset=utf-8\"\n *\n * const jsonFile = new File(\"/path/to/data.json\");\n * console.log(jsonFile.getType()); // \"application/json;charset=utf-8\"\n * ```\n */\n public getType(): string {\n return this.getBunFile().type;\n }\n\n /**\n * Checks if the file exists on disk.\n *\n * @returns A promise that resolves to true if the file exists\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n *\n * if (await file.exists()) {\n * console.log(\"File exists!\");\n * } else {\n * console.log(\"File not found\");\n * }\n * ```\n */\n public async exists(): Promise<boolean> {\n try {\n const stats = await this.getBunFile().stat();\n return stats.isFile();\n } catch {\n return false;\n }\n }\n\n /**\n * Reads the file content as a string.\n *\n * @returns A promise that resolves to the file content as a string\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n * const content = await file.text();\n * console.log(content); // \"Hello, World!\"\n * ```\n */\n public async text(): Promise<string> {\n try {\n return await this.getBunFile().text();\n } catch (error) {\n throw new FileException(`Failed to read file as text: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads and parses the file content as JSON.\n *\n * @typeParam T - The expected type of the parsed JSON\n * @returns A promise that resolves to the parsed JSON object\n * @throws {FileException} If the file cannot be read or parsed\n *\n * @example\n * ```typescript\n * interface Config {\n * name: string;\n * version: number;\n * }\n *\n * const file = new File(\"/path/to/config.json\");\n * const config = await file.json<Config>();\n * console.log(config.name); // \"my-app\"\n * ```\n */\n public async json<T = unknown>(): Promise<T> {\n try {\n return (await this.getBunFile().json()) as T;\n } catch (error) {\n throw new FileException(`Failed to read file as JSON: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads the file content as an ArrayBuffer.\n *\n * @returns A promise that resolves to the file content as an ArrayBuffer\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/binary.bin\");\n * const buffer = await file.arrayBuffer();\n * const view = new DataView(buffer);\n * console.log(view.getInt32(0)); // First 4 bytes as int32\n * ```\n */\n public async arrayBuffer(): Promise<ArrayBuffer> {\n try {\n return await this.getBunFile().arrayBuffer();\n } catch (error) {\n throw new FileException(`Failed to read file as ArrayBuffer: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads the file content as a Uint8Array.\n *\n * @returns A promise that resolves to the file content as a Uint8Array\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/binary.bin\");\n * const bytes = await file.bytes();\n * console.log(bytes[0]); // First byte\n * console.log(bytes.length); // Total bytes\n * ```\n */\n public async bytes(): Promise<Uint8Array> {\n try {\n return await this.getBunFile().bytes();\n } catch (error) {\n throw new FileException(`Failed to read file as Uint8Array: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns a ReadableStream for incremental file reading.\n *\n * @returns A ReadableStream of Uint8Array chunks\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/large-file.txt\");\n * const stream = file.stream();\n *\n * for await (const chunk of stream) {\n * console.log(`Received ${chunk.length} bytes`);\n * }\n * ```\n */\n public stream(): ReadableStream<Uint8Array> {\n return this.getBunFile().stream();\n }\n\n /**\n * Returns a ReadableStream for incremental file reading as text.\n *\n * @returns A ReadableStream of string chunks\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/large-file.txt\");\n * const stream = file.streamAsText();\n *\n * for await (const chunk of stream) {\n * console.log(`Received text: ${chunk}`);\n * }\n * ```\n */\n public streamAsText(): ReadableStream<string> {\n const byteStream = this.getBunFile().stream();\n const decoder = new TextDecoder();\n\n return new ReadableStream<string>({\n async start(controller) {\n const reader = byteStream.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n controller.enqueue(decoder.decode(value, { stream: true }));\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n }\n\n /**\n * Returns a ReadableStream for incremental JSON parsing from a JSON array file.\n *\n * Reads a file containing a JSON array and streams each parsed element individually.\n * This is useful for processing large JSON array files without loading everything into memory.\n *\n * @typeParam T - The expected type of each JSON element\n * @returns A ReadableStream of parsed JSON elements\n *\n * @example\n * ```typescript\n * // For a file containing: [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]\n * const file = new File(\"/path/to/data.json\");\n * const stream = file.streamAsJson<{ id: number }>();\n *\n * for await (const item of stream) {\n * console.log(item.id); // 1, 2, 3\n * }\n * ```\n */\n public streamAsJson<T = unknown>(): ReadableStream<T> {\n const byteStream = this.getBunFile().stream();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let depth = 0;\n let inString = false;\n let isEscape = false;\n let objectStart = -1;\n let arrayStarted = false;\n\n return new ReadableStream<T>({\n async start(controller) {\n const reader = byteStream.getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n let i = 0;\n while (i < buffer.length) {\n const char = buffer[i];\n\n if (isEscape) {\n isEscape = false;\n i++;\n continue;\n }\n\n if (char === \"\\\\\" && inString) {\n isEscape = true;\n i++;\n continue;\n }\n\n if (char === '\"') {\n inString = !inString;\n i++;\n continue;\n }\n\n if (inString) {\n i++;\n continue;\n }\n\n if (char === \"[\" && !arrayStarted) {\n arrayStarted = true;\n i++;\n continue;\n }\n\n if (char === \"{\" || char === \"[\") {\n if (depth === 0) {\n objectStart = i;\n }\n depth++;\n } else if (char === \"}\" || char === \"]\") {\n depth--;\n if (depth === 0 && objectStart !== -1) {\n const jsonStr = buffer.slice(objectStart, i + 1);\n try {\n const parsed = JSON.parse(jsonStr) as T;\n controller.enqueue(parsed);\n } catch {\n // Skip invalid JSON\n }\n buffer = buffer.slice(i + 1);\n i = -1;\n objectStart = -1;\n }\n }\n\n i++;\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n } finally {\n reader.releaseLock();\n }\n },\n });\n }\n\n /**\n * Writes data to the file, overwriting existing content.\n *\n * @param data - The data to write (string, Blob, ArrayBuffer, TypedArray, or Response)\n * @returns A promise that resolves to the number of bytes written\n * @throws {FileException} If the file cannot be written\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Write string\n * await file.write(\"Hello, World!\");\n *\n * // Write Uint8Array\n * await file.write(new Uint8Array([72, 101, 108, 108, 111]));\n *\n * // Write from Response\n * const response = await fetch(\"https://example.com/data\");\n * await file.write(response);\n * ```\n */\n public async write(data: FileWriteDataType): Promise<number> {\n try {\n return await Bun.write(this.path, data as Parameters<typeof Bun.write>[1]);\n } catch (error) {\n throw new FileException(`Failed to write to file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Appends data to the end of the file.\n *\n * @param data - The data to append (string or Uint8Array)\n * @returns A promise that resolves to the total number of bytes in the file\n * @throws {FileException} If the file cannot be appended to\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/log.txt\");\n *\n * // Append string\n * await file.append(\"New log entry\\n\");\n *\n * // Append binary data\n * await file.append(new Uint8Array([10, 20, 30]));\n * ```\n */\n public async append(data: string | Uint8Array): Promise<number> {\n try {\n const bunFile = this.getBunFile();\n const fileExists = await bunFile.exists();\n const existingContent = fileExists ? await bunFile.bytes() : new Uint8Array(0);\n\n const newData = typeof data === \"string\" ? new TextEncoder().encode(data) : data;\n\n const combined = new Uint8Array(existingContent.length + newData.length);\n combined.set(existingContent);\n combined.set(newData, existingContent.length);\n\n return await Bun.write(this.path, combined);\n } catch (error) {\n throw new FileException(`Failed to append to file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Copies the file to a destination path.\n *\n * @param destination - The destination file path\n * @returns A promise that resolves to a new File instance for the copied file\n * @throws {FileException} If the file cannot be copied\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/original.txt\");\n * const copiedFile = await file.copy(\"/path/to/backup.txt\");\n *\n * // The original file is preserved\n * console.log(await file.exists()); // true\n * // Access the copied file\n * console.log(await copiedFile.text()); // same content as original\n * ```\n */\n public async copy(destination: string): Promise<IFile> {\n try {\n await Bun.write(destination, this.getBunFile());\n return new File(destination);\n } catch (error) {\n throw new FileException(`Failed to copy file: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Deletes the file from disk.\n *\n * @throws {FileException} If the file cannot be deleted\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/temp.txt\");\n *\n * if (await file.exists()) {\n * await file.delete();\n * console.log(\"File deleted\");\n * }\n * ```\n */\n public async delete(): Promise<void> {\n try {\n await this.getBunFile().delete();\n } catch (error) {\n throw new FileException(`Failed to delete file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Downloads a file from a URL and saves it to this file's path.\n *\n * @param url - The URL to download the file from\n * @returns A promise that resolves to the number of bytes written\n * @throws {FileException} If the download or write operation fails\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/image.png\");\n *\n * // Download from URL\n * const bytes = await file.download(\"https://example.com/image.png\");\n * console.log(`Downloaded ${bytes} bytes`);\n *\n * // Download with URL object\n * await file.download(new URL(\"https://example.com/data.json\"));\n * ```\n */\n public async download(url: string | URL): Promise<number> {\n try {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new FileException(`HTTP error: ${response.status} ${response.statusText}`);\n }\n\n return await Bun.write(this.path, response);\n } catch (error) {\n throw new FileException(`Failed to download file from URL: ${url.toString()}`, {\n path: this.path,\n url: url.toString(),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns a FileSink for incremental writing.\n *\n * @param options - Optional configuration for the writer\n * @returns A FileSink instance for buffered writing\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/output.txt\");\n * const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB buffer\n *\n * writer.write(\"Line 1\\n\");\n * writer.write(\"Line 2\\n\");\n * writer.flush(); // Flush buffer to disk\n *\n * writer.write(\"Line 3\\n\");\n * writer.end(); // Flush and close\n * ```\n */\n public writer(options?: FileWriterOptionsType): BunFileSinkType {\n return this.getBunFile().writer(options);\n }\n}\n",
7
+ "import { basename, dirname, extname, join } from \"node:path\";\nimport type { BunFile } from \"bun\";\nimport { Directory } from \"./Directory\";\nimport { FileException } from \"./FileException\";\nimport type {\n BunFileSinkType,\n FileOptionsType,\n FileWriteDataType,\n FileWriterOptionsType,\n IDirectory,\n IFile,\n} from \"./types\";\n\n/**\n * A class for performing file operations using Bun's optimized file I/O APIs.\n *\n * @example\n * ```typescript\n * import { File } from \"@ooneex/fs\";\n *\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Read file content\n * const content = await file.text();\n *\n * // Write to file\n * await file.write(\"Hello, World!\");\n *\n * // Check if file exists\n * if (await file.exists()) {\n * console.log(\"File exists!\");\n * }\n * ```\n */\nexport class File implements IFile {\n private readonly path: string;\n private readonly options: FileOptionsType | undefined;\n\n /**\n * Creates a new File instance.\n *\n * @param path - The file path as a string or URL\n * @param options - Optional configuration options\n *\n * @example\n * ```typescript\n * // Using string path\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Using URL\n * const file = new File(new URL(\"file:///path/to/file.txt\"));\n *\n * // With custom MIME type\n * const file = new File(\"/path/to/file\", { type: \"application/json\" });\n * ```\n */\n constructor(path: string | URL, options?: FileOptionsType) {\n const pathStr = path instanceof URL ? path.pathname : path;\n const isAbsolute = pathStr.startsWith(\"/\");\n const normalized = join(...pathStr.split(/[/\\\\]/));\n this.path = isAbsolute ? `/${normalized}` : normalized;\n this.options = options;\n }\n\n private getBunFile(): BunFile {\n return Bun.file(this.path, this.options);\n }\n\n /**\n * Returns the file path.\n *\n * @returns The absolute or relative path of the file\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getPath()); // \"/path/to/document.pdf\"\n * ```\n */\n public getPath(): string {\n return this.path;\n }\n\n /**\n * Returns the file name including extension.\n *\n * @returns The base name of the file\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getName()); // \"document.pdf\"\n * ```\n */\n public getName(): string {\n return basename(this.path);\n }\n\n /**\n * Returns the file extension without the leading dot.\n *\n * @returns The file extension or empty string if none\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getExtension()); // \"pdf\"\n *\n * const noExt = new File(\"/path/to/README\");\n * console.log(noExt.getExtension()); // \"\"\n * ```\n */\n public getExtension(): string {\n const ext = extname(this.path);\n return ext.startsWith(\".\") ? ext.slice(1) : ext;\n }\n\n /**\n * Returns the directory containing the file.\n *\n * @returns The parent directory as an IDirectory instance\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * const dir = file.getDirectory();\n * console.log(dir.getPath()); // \"/path/to\"\n * ```\n */\n public getDirectory(): IDirectory {\n return new Directory(dirname(this.path));\n }\n\n /**\n * Returns the file size in bytes.\n *\n * @returns The size of the file in bytes, or 0 if file doesn't exist\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/document.pdf\");\n * console.log(file.getSize()); // 1024\n * ```\n */\n public getSize(): number {\n return this.getBunFile().size;\n }\n\n /**\n * Returns the MIME type of the file.\n *\n * @returns The MIME type string (e.g., \"text/plain\", \"application/json\")\n *\n * @example\n * ```typescript\n * const txtFile = new File(\"/path/to/file.txt\");\n * console.log(txtFile.getType()); // \"text/plain;charset=utf-8\"\n *\n * const jsonFile = new File(\"/path/to/data.json\");\n * console.log(jsonFile.getType()); // \"application/json;charset=utf-8\"\n * ```\n */\n public getType(): string {\n return this.getBunFile().type;\n }\n\n /**\n * Checks if the file exists on disk.\n *\n * @returns A promise that resolves to true if the file exists\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n *\n * if (await file.exists()) {\n * console.log(\"File exists!\");\n * } else {\n * console.log(\"File not found\");\n * }\n * ```\n */\n public async exists(): Promise<boolean> {\n try {\n const stats = await this.getBunFile().stat();\n return stats.isFile();\n } catch {\n return false;\n }\n }\n\n /**\n * Reads the file content as a string.\n *\n * @returns A promise that resolves to the file content as a string\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n * const content = await file.text();\n * console.log(content); // \"Hello, World!\"\n * ```\n */\n public async text(): Promise<string> {\n try {\n return await this.getBunFile().text();\n } catch (error) {\n throw new FileException(`Failed to read file as text: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads and parses the file content as JSON.\n *\n * @typeParam T - The expected type of the parsed JSON\n * @returns A promise that resolves to the parsed JSON object\n * @throws {FileException} If the file cannot be read or parsed\n *\n * @example\n * ```typescript\n * interface Config {\n * name: string;\n * version: number;\n * }\n *\n * const file = new File(\"/path/to/config.json\");\n * const config = await file.json<Config>();\n * console.log(config.name); // \"my-app\"\n * ```\n */\n public async json<T = unknown>(): Promise<T> {\n try {\n return (await this.getBunFile().json()) as T;\n } catch (error) {\n throw new FileException(`Failed to read file as JSON: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads the file content as an ArrayBuffer.\n *\n * @returns A promise that resolves to the file content as an ArrayBuffer\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/binary.bin\");\n * const buffer = await file.arrayBuffer();\n * const view = new DataView(buffer);\n * console.log(view.getInt32(0)); // First 4 bytes as int32\n * ```\n */\n public async arrayBuffer(): Promise<ArrayBuffer> {\n try {\n return await this.getBunFile().arrayBuffer();\n } catch (error) {\n throw new FileException(`Failed to read file as ArrayBuffer: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Reads the file content as a Uint8Array.\n *\n * @returns A promise that resolves to the file content as a Uint8Array\n * @throws {FileException} If the file cannot be read\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/binary.bin\");\n * const bytes = await file.bytes();\n * console.log(bytes[0]); // First byte\n * console.log(bytes.length); // Total bytes\n * ```\n */\n public async bytes(): Promise<Uint8Array> {\n try {\n return await this.getBunFile().bytes();\n } catch (error) {\n throw new FileException(`Failed to read file as Uint8Array: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns an async generator for incremental file reading.\n *\n * @returns An async generator that yields Uint8Array chunks\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/large-file.txt\");\n *\n * for await (const chunk of file.stream()) {\n * console.log(`Received ${chunk.length} bytes`);\n * }\n * ```\n */\n public async *stream(): AsyncGenerator<Uint8Array> {\n const reader = this.getBunFile().stream().getReader();\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n yield value;\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n /**\n * Returns an async generator for incremental file reading as text.\n *\n * @returns An async generator that yields string chunks\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/large-file.txt\");\n *\n * for await (const chunk of file.streamAsText()) {\n * console.log(`Received text: ${chunk}`);\n * }\n * ```\n */\n public async *streamAsText(): AsyncGenerator<string> {\n const decoder = new TextDecoder();\n\n for await (const chunk of this.stream()) {\n yield decoder.decode(chunk, { stream: true });\n }\n }\n\n /**\n * Returns an async generator for incremental JSON parsing from a JSON array file.\n *\n * Reads a file containing a JSON array and yields each parsed element individually.\n * This is useful for processing large JSON array files without loading everything into memory.\n *\n * @typeParam T - The expected type of each JSON element\n * @returns An async generator that yields parsed JSON elements\n *\n * @example\n * ```typescript\n * // For a file containing: [{\"id\": 1}, {\"id\": 2}, {\"id\": 3}]\n * const file = new File(\"/path/to/data.json\");\n *\n * for await (const item of file.streamAsJson<{ id: number }>()) {\n * console.log(item.id); // 1, 2, 3\n * }\n * ```\n */\n public async *streamAsJson<T = unknown>(): AsyncGenerator<T> {\n let buffer = \"\";\n let depth = 0;\n let inString = false;\n let isEscape = false;\n let objectStart = -1;\n let arrayStarted = false;\n\n for await (const chunk of this.streamAsText()) {\n buffer += chunk;\n\n let i = 0;\n while (i < buffer.length) {\n const char = buffer[i];\n\n if (isEscape) {\n isEscape = false;\n i++;\n continue;\n }\n\n if (char === \"\\\\\" && inString) {\n isEscape = true;\n i++;\n continue;\n }\n\n if (char === '\"') {\n inString = !inString;\n i++;\n continue;\n }\n\n if (inString) {\n i++;\n continue;\n }\n\n if (char === \"[\" && !arrayStarted) {\n arrayStarted = true;\n i++;\n continue;\n }\n\n if (char === \"{\" || char === \"[\") {\n if (depth === 0) {\n objectStart = i;\n }\n depth++;\n } else if (char === \"}\" || char === \"]\") {\n depth--;\n if (depth === 0 && objectStart !== -1) {\n const jsonStr = buffer.slice(objectStart, i + 1);\n try {\n yield JSON.parse(jsonStr) as T;\n } catch {\n // Skip invalid JSON\n }\n buffer = buffer.slice(i + 1);\n i = -1;\n objectStart = -1;\n }\n }\n\n i++;\n }\n }\n }\n\n /**\n * Writes data to the file, overwriting existing content.\n *\n * @param data - The data to write (string, Blob, ArrayBuffer, TypedArray, or Response)\n * @returns A promise that resolves to the number of bytes written\n * @throws {FileException} If the file cannot be written\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/file.txt\");\n *\n * // Write string\n * await file.write(\"Hello, World!\");\n *\n * // Write Uint8Array\n * await file.write(new Uint8Array([72, 101, 108, 108, 111]));\n *\n * // Write from Response\n * const response = await fetch(\"https://example.com/data\");\n * await file.write(response);\n * ```\n */\n public async write(data: FileWriteDataType): Promise<number> {\n try {\n return await Bun.write(this.path, data as Parameters<typeof Bun.write>[1]);\n } catch (error) {\n throw new FileException(`Failed to write to file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Appends data to the end of the file.\n *\n * @param data - The data to append (string or Uint8Array)\n * @returns A promise that resolves to the total number of bytes in the file\n * @throws {FileException} If the file cannot be appended to\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/log.txt\");\n *\n * // Append string\n * await file.append(\"New log entry\\n\");\n *\n * // Append binary data\n * await file.append(new Uint8Array([10, 20, 30]));\n * ```\n */\n public async append(data: string | Uint8Array): Promise<number> {\n try {\n const bunFile = this.getBunFile();\n const fileExists = await bunFile.exists();\n const existingContent = fileExists ? await bunFile.bytes() : new Uint8Array(0);\n\n const newData = typeof data === \"string\" ? new TextEncoder().encode(data) : data;\n\n const combined = new Uint8Array(existingContent.length + newData.length);\n combined.set(existingContent);\n combined.set(newData, existingContent.length);\n\n return await Bun.write(this.path, combined);\n } catch (error) {\n throw new FileException(`Failed to append to file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Copies the file to a destination path.\n *\n * @param destination - The destination file path\n * @returns A promise that resolves to a new File instance for the copied file\n * @throws {FileException} If the file cannot be copied\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/original.txt\");\n * const copiedFile = await file.copy(\"/path/to/backup.txt\");\n *\n * // The original file is preserved\n * console.log(await file.exists()); // true\n * // Access the copied file\n * console.log(await copiedFile.text()); // same content as original\n * ```\n */\n public async copy(destination: string): Promise<IFile> {\n try {\n await Bun.write(destination, this.getBunFile());\n return new File(destination);\n } catch (error) {\n throw new FileException(`Failed to copy file: ${this.path}`, {\n path: this.path,\n destination,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Deletes the file from disk.\n *\n * @throws {FileException} If the file cannot be deleted\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/temp.txt\");\n *\n * if (await file.exists()) {\n * await file.delete();\n * console.log(\"File deleted\");\n * }\n * ```\n */\n public async delete(): Promise<void> {\n try {\n await this.getBunFile().delete();\n } catch (error) {\n throw new FileException(`Failed to delete file: ${this.path}`, {\n path: this.path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n public static async download(url: string | URL, out: string): Promise<IFile> {\n try {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new FileException(`HTTP error: ${response.status} ${response.statusText}`);\n }\n\n await Bun.write(out, response);\n\n return new File(out);\n } catch (error) {\n throw new FileException(`Failed to download file from URL: ${url.toString()}`, {\n path: out,\n url: url.toString(),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n /**\n * Returns a FileSink for incremental writing.\n *\n * @param options - Optional configuration for the writer\n * @returns A FileSink instance for buffered writing\n *\n * @example\n * ```typescript\n * const file = new File(\"/path/to/output.txt\");\n * const writer = file.writer({ highWaterMark: 1024 * 1024 }); // 1MB buffer\n *\n * writer.write(\"Line 1\\n\");\n * writer.write(\"Line 2\\n\");\n * writer.flush(); // Flush buffer to disk\n *\n * writer.write(\"Line 3\\n\");\n * writer.end(); // Flush and close\n * ```\n */\n public writer(options?: FileWriterOptionsType): BunFileSinkType {\n return this.getBunFile().writer(options);\n }\n}\n",
8
8
  "import { Exception } from \"@ooneex/exception\";\nimport { HttpStatus } from \"@ooneex/http-status\";\n\nexport class FileException extends Exception {\n constructor(message: string, data: Record<string, unknown> = {}) {\n super(message, {\n status: HttpStatus.Code.InternalServerError,\n data,\n });\n this.name = \"FileException\";\n }\n}\n"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "329F88F8B0F876C764756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "1E8724F72312714C64756E2164756E21",
12
12
  "names": []
13
13
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ooneex/fs",
3
- "description": "File system utilities for reading, writing, and manipulating files and directories with async support and error handling",
4
- "version": "0.0.17",
3
+ "description": "Async file system utilities for reading, writing, copying, and watching files and directories with type-safe error handling and stream support",
4
+ "version": "1.0.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist",
@@ -28,8 +28,8 @@
28
28
  "test": "bun test tests"
29
29
  },
30
30
  "dependencies": {
31
- "@ooneex/exception": "0.0.16",
32
- "@ooneex/http-status": "0.0.16"
31
+ "@ooneex/exception": "0.0.18",
32
+ "@ooneex/http-status": "0.0.18"
33
33
  },
34
34
  "keywords": [
35
35
  "bun",