Compare commits

..

No commits in common. "master" and "v11.0.7" have entirely different histories.

11 changed files with 4128 additions and 8897 deletions

View File

@ -1,357 +0,0 @@
# Changelog
## 2025-01-29 - 11.2.0 - feat(fs)
Enhanced copy method with optional replaceTargetDir option for directory replacement
- Added optional 'replaceTargetDir' option to 'copy' and 'copySync' methods in 'fs.ts'.
- The 'replaceTargetDir' option allows replacing the target directory if both source and target are directories.
## 2025-01-29 - 11.1.9 - fix(fs)
Fix directory handling in copy and copySync functions
- Ensured existing directories at destination are removed before copying over them in async copy.
- Added a similar check and handling for synchronous copySync when destination is a directory.
## 2025-01-29 - 11.1.8 - fix(fs)
Fixed copy and copySync functions to ensure they always overwrite files.
- Fixed bug in copy function where files were not being overwritten when they already existed at the destination.
- Fixed bug in copySync function to ensure files are overwritten to match the async function's behavior.
## 2025-01-29 - 11.1.7 - fix(fs)
Refactor copy and copySync functions to simplify return type
- Changed the return type of fs.copy and fs.copySync from boolean to void.
- Removed unnecessary promise handling in fs.copy.
## 2025-01-29 - 11.1.6 - fix(fs)
Fix issues with fs file copy functions.
- Updated dependencies in package.json.
- Corrected comments for asynchronous and synchronous file copy functions in fs.ts.
## 2025-01-07 - 11.1.5 - fix(fs)
Improve waitForFileToBeReady function to handle directories and file stabilization
- Enhanced the waitForFileToBeReady to handle directory paths by checking for file existence within directories and waiting for stabilization.
- Modified the watcher logic to cater to changes when monitoring directories for file appearance.
- Introduced a helper function to ensure paths exist and another to resolve the first file in directories.
- Corrected logic for polling and stabilizing files within directories.
## 2025-01-07 - 11.1.4 - fix(fs)
Fix file existence check in waitForFileToBeReady method.
- Ensured that the directory and file exist before setting up the watcher in waitForFileToBeReady.
- Changed ensureDirectoryExists to ensureFileExists for correct file path verification.
- Handled ENOENT errors correctly to retry file existence checks until timeout is reached.
## 2025-01-07 - 11.1.3 - fix(fs)
Fix TypeScript type issue in fs module
- Corrected a TypeScript type in the fs module's checkFileStability function.
## 2025-01-07 - 11.1.2 - fix(fs)
Fix issues in file stability check and directory existence verification in fs module
- Removed unused variable 'isFileAvailable' in 'waitForFileToBeReady'.
- Fixed logic for ensuring the target directory exists before setting up file stability watcher.
- Refactored directory existence logic into 'ensureDirectoryExists' function.
## 2025-01-07 - 11.1.1 - fix(fs)
Improve waitForFileToBeReady function for file stability detection
- Enhanced error handling and file stability checks in waitForFileToBeReady function
- Added timeout feature for file readiness check
- Improved directory access check before file availability check
## 2025-01-07 - 11.1.0 - feat(SmartFile)
Add rename functionality to SmartFile class
- Implemented a new method to rename a file within the SmartFile class.
- The rename method updates the file path and optionally writes the renamed file to the disk.
## 2024-12-15 - 11.0.23 - fix(fs)
Handle errors in toObjectSync method
- Added error handling in toObjectSync function to capture and provide more informative error messages.
## 2024-06-23 - 11.0.22 - fix(core)
Update dependencies and changelog
- Updated @push.rocks/smartstream to ^3.0.44
- Updated glob to ^10.4.2
- Updated @types/node to ^20.14.8
## 2024-06-23 - 11.0.21 - fix(dependencies)
Update dependencies to latest versions
- Updated @push.rocks/smartpromise to ^4.0.4
- Updated @push.rocks/smartstream to ^3.0.44
- Updated glob to ^10.4.2
- Updated @types/node to ^20.14.8
## 2024-06-07 - 11.0.20 - Changelog
11.0.20
## 2024-06-07 - 11.0.19 - fix(core): update
11.0.19
- fix(core): update
## 2024-06-07 - 11.0.18 - fix(core): update
11.0.18
- fix(core): update
## 2024-06-06 - 11.0.17 - fix(core): update
11.0.17
- fix(core): update
## 2024-06-06 - 11.0.16 - fix(core): update
11.0.16
- fix(core): update
## 2024-05-29 - 11.0.16 - update description
11.0.16
- update description
## 2024-05-17 - 11.0.15 - fix(core): update
11.0.15
- fix(core): update
## 2024-04-14 - 11.0.14 - update tsconfig
11.0.14
- update tsconfig
## 2024-04-12 - 11.0.13 - fix(core): update
11.0.13
- fix(core): update
## 2024-04-12 - 11.0.12 - fix(core): update
11.0.12
- fix(core): update
## 2024-04-12 - 11.0.11 - fix(core): update
11.0.11
- fix(core): update
## 2024-04-03 - 11.0.10 - fix(core): update
11.0.10
- fix(core): update
## 2024-04-03 - 11.0.9 - fix(core): update
11.0.9
- fix(core): update
## 2024-04-02 - 11.0.8 - fix(core): update
11.0.8
- fix(core): update
## 2024-04-02 - 11.0.7 - fix(core): update
11.0.7
- fix(core): update
## 2024-04-02 - 11.0.6 - fix(core): update
11.0.6
- fix(core): update
## 2024-04-01 - 11.0.5 - update npmextra.json
11.0.5
- update npmextra.json: githost
## 2024-04-01 - 11.0.4 - fix(core): update
11.0.4
- fix(core): update
## 2023-11-24 - 11.0.3 - fix(core): update
11.0.3
- fix(core): update
## 2023-11-07 - 11.0.2 - fix(core): update
11.0.2
- fix(core): update
## 2023-11-07 - 11.0.1 - fix(core): update
11.0.1
- fix(core): update
## 2023-11-06 - 11.0.0 - fix(core): update
11.0.0
- fix(core): update
## 2023-11-06 - 10.0.40 - BREAKING CHANGE(core): update
10.0.40
- BREAKING CHANGE(core): update
## 2023-11-04 - 10.0.39 - fix(core): update
10.0.39
- fix(core): update
## 2023-11-04 - 10.0.38 - fix(core): update
10.0.38
- fix(core): update
## 2023-11-04 - 10.0.37 - fix(core): update
10.0.37
- fix(core): update
## 2023-11-03 - 10.0.36 - fix(core): update
10.0.36
- fix(core): update
## 2023-11-03 - 10.0.35 - fix(core): update
10.0.35
- fix(core): update
## 2023-11-03 - 10.0.34 - fix(core): update
10.0.34
- fix(core): update
## 2023-11-03 - 10.0.33 - fix(core): update
10.0.33
- fix(core): update
## 2023-10-12 - 10.0.32 - fix(core): update
10.0.32
- fix(core): update
## 2023-09-22 - 10.0.31 - fix(core): update
10.0.31
- fix(core): update
## 2023-08-31 - 10.0.30 - fix(core): update
10.0.30
- fix(core): update
## 2023-08-23 - 10.0.29 - fix(core): update
10.0.29
- fix(core): update
## 2023-07-12 - 10.0.28 - fix(core): update
10.0.28
- fix(core): update
## 2023-07-10 - 10.0.27 - fix(core): update
10.0.27
- fix(core): update
## 2023-07-10 - 10.0.26 - fix(core): update
10.0.26
- fix(core): update
## 2023-07-08 - 10.0.25 - fix(core): update
10.0.25
- fix(core): update
## 2023-06-25 - 10.0.24 to 10.0.14 - Series of Fixes
10.0.24 to 10.0.14
- Series of fixes in the core module
## 2023-01-09 - 10.0.13 to 10.0.6 - Series of Fixes
10.0.13 to 10.0.6
- Series of fixes in the core module
## 2022-09-05 - 10.0.5 to 10.0.3 - Series of Fixes
10.0.5 to 10.0.3
- Series of fixes in the core module
## 2022-06-07 - 10.0.2 to 10.0.1 - Series of Fixes
10.0.2 to 10.0.1
- Series of fixes in the core module
## 2022-06-07 - 9.0.7 - BREAKING CHANGE(core): switch to esm
9.0.7
- BREAKING CHANGE(core): switch to esm
## 2022-03-11 - 9.0.6 to 9.0.2 - Series of Fixes
9.0.6 to 9.0.2
- Series of fixes in the core module
## 2021-12-01 - 9.0.1 - fix(core): update
9.0.1
- fix(core): update
## 2021-12-01 - 9.0.0 - fix(absolute pathing)
9.0.0
- add functions for easily getting absolute paths
## 2021-11-30 - 8.0.11 - BREAKING CHANGE(relative pathing)
8.0.11
- improved relative pathing
## 2020-08-10 - 8.0.10 to 7.0.12 - Series of Fixes and Updates
8.0.10 to 7.0.12
- Series of fixes in the core module
- BREAKING CHANGE(Smartfile class): switch to a Buffer-only approach
## 2019-02-17 - 7.0.0 - fix(core): update dependencies
7.0.0
- fix(core): update dependencies
## 2019-01-27 - 6.0.12 - BREAKING CHANGE(smartfile.fs.fileExists)
6.0.12
- now returns a Promise<boolean>
## 2018-08-19 - 6.0.11 to 6.0.6 - Series of Fixes
6.0.11 to 6.0.6
- Series of fixes in core and dependencies
## 2018-07-03 - 6.0.5 to 5.0.0 - Series of Fixes
6.0.5 to 5.0.0
- Series of fixes in core and dependencies
## 2018-02-16 - 4.2.28 - BREAKING CHANGE(scope)
4.2.28
- switch to pushrocks scope

View File

@ -10,39 +10,14 @@
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "smartfile",
"description": "Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.",
"description": "smart ways to work with files in nodejs",
"npmPackagename": "@push.rocks/smartfile",
"license": "MIT",
"keywords": [
"file management",
"TypeScript",
"Node.js",
"file operations",
"file manipulation",
"file streaming",
"virtual directory",
"filesystem utilities",
"memory-efficient file handling",
"custom file operations",
"write files",
"read files",
"copy files",
"delete files",
"list directories",
"handle large files",
"virtual filesystems",
"buffer operations"
]
"license": "MIT"
}
},
"tsdoc": {
"classes": [
"SmartFile",
"StreamFile"
],
"descriptions": [
"the purpose of the StreamFile class is to provide a hybrid interface between streaming files and simple handling when writing and reading those files multiple times."
],
"classes": ["SmartFile", "StreamFile"],
"descriptions": ["the purpose of the StreamFile class is to provide a hybrid interface between streaming files and simple handling when writing and reading those files multiple times."],
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
}
}

View File

@ -1,8 +1,8 @@
{
"name": "@push.rocks/smartfile",
"private": false,
"version": "11.2.0",
"description": "Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.",
"version": "11.0.7",
"description": "offers smart ways to work with files in nodejs",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
@ -13,58 +13,42 @@
},
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smartfile.git"
"url": "git+https://gitlab.com/push.rocks/smartfile.git"
},
"keywords": [
"file management",
"TypeScript",
"Node.js",
"file operations",
"file manipulation",
"file streaming",
"virtual directory",
"filesystem utilities",
"memory-efficient file handling",
"custom file operations",
"write files",
"read files",
"copy files",
"delete files",
"list directories",
"handle large files",
"virtual filesystems",
"buffer operations"
"filesystem",
"json"
],
"author": "Lossless GmbH <hello@lossless.com> (https://lossless.com)",
"license": "MIT",
"bugs": {
"url": "https://gitlab.com/push.rocks/smartfile/issues"
},
"homepage": "https://code.foss.global/push.rocks/smartfile",
"homepage": "https://gitlab.com/push.rocks/smartfile#readme",
"dependencies": {
"@push.rocks/lik": "^6.1.0",
"@push.rocks/lik": "^6.0.12",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile-interfaces": "^1.0.7",
"@push.rocks/smarthash": "^3.0.4",
"@push.rocks/smartjson": "^5.0.20",
"@push.rocks/smartmime": "^2.0.4",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.2.2",
"@push.rocks/smartrequest": "^2.0.23",
"@push.rocks/smartstream": "^3.2.5",
"@push.rocks/smartjson": "^5.0.10",
"@push.rocks/smartmime": "^1.0.5",
"@push.rocks/smartpath": "^5.0.11",
"@push.rocks/smartpromise": "^4.0.2",
"@push.rocks/smartrequest": "^2.0.21",
"@push.rocks/smartstream": "^3.0.30",
"@types/fs-extra": "^11.0.4",
"@types/glob": "^8.1.0",
"@types/js-yaml": "^4.0.9",
"fs-extra": "^11.3.0",
"glob": "^11.0.1",
"fs-extra": "^11.1.1",
"glob": "^10.3.10",
"js-yaml": "^4.1.0"
},
"devDependencies": {
"@git.zone/tsbuild": "^2.2.1",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^1.0.96",
"@push.rocks/tapbundle": "^5.5.6",
"@types/node": "^22.12.0"
"@git.zone/tsbuild": "^2.1.70",
"@git.zone/tsrun": "^1.2.46",
"@git.zone/tstest": "^1.0.84",
"@push.rocks/tapbundle": "^5.0.15",
"@types/node": "^20.10.0"
},
"files": [
"ts/**/*",

11969
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@

266
readme.md
View File

@ -1,10 +1,10 @@
# @push.rocks/smartfile
> Provides a robust suite of tools for managing files in Node.js using TypeScript.
> offers smart ways to work with files in nodejs
## Install
To integrate `@push.rocks/smartfile` into your project, run:
To install `@push.rocks/smartfile`, run the following command in your project directory:
```bash
npm install @push.rocks/smartfile
@ -12,214 +12,148 @@ npm install @push.rocks/smartfile
## Usage
`@push.rocks/smartfile` offers extensive file management utilities, enabling seamless file processing with TypeScript in a Node.js environment. Below are detailed examples showcasing various features of the module.
The `@push.rocks/smartfile` library offers a comprehensive suite of tools to work with files in Node.js projects, facilitating a variety of file operations such as reading, writing, streaming, and in-memory manipulation. Below, you'll find detailed examples illustrating how to leverage the library's functionality to tackle real-world tasks.
### Quick Start
### Working with Filesystem
First, ensure you're working in an environment that supports ECMAScript modules (ESM) and TypeScript. Heres how youd generally import and use `@push.rocks/smartfile`:
#### Ensuring File and Directory Existence
```typescript
import { SmartFile, StreamFile, VirtualDirectory, fs, memory, interpreter } from '@push.rocks/smartfile';
import { fs } from '@push.rocks/smartfile';
// Ensure a file exists with initial content (Async)
await fs.ensureFile('./path/to/new/file.txt', 'Initial content');
// Ensure a directory exists (Async)
await fs.ensureDir('./path/to/new/dir');
```
### Working with `SmartFile`
#### Reading Files
To read from a file and convert it to a `SmartFile` instance:
#### Getting File Details
```typescript
const myJsonSmartFile: SmartFile = await SmartFile.fromFilePath('./somePath/data.json');
const jsonData = JSON.parse(myJsonSmartFile.contents.toString());
console.log(jsonData); // Assuming the file contains JSON content
import { fs } from '@push.rocks/smartfile';
// Check if a file exists (Async)
const exists: boolean = await fs.fileExists('./path/to/file.txt');
// Check if a path is a directory
const isDir: boolean = fs.isDirectory('./path/to/check');
```
#### Writing Files
### Reading and Writing Files
To write data to a file through a `SmartFile`:
#### Basic Reading and Writing
```typescript
const filePath: string = './output/outputData.json';
const content: string = JSON.stringify({ key: 'value' });
await memory.toFs(content, filePath);
import { SmartFile, memory } from '@push.rocks/smartfile';
// Read a file to a SmartFile instance (Async)
const smartFile: SmartFile = await SmartFile.fromFilePath('./path/to/read/file.txt');
// Write SmartFile instance to a new path (Async)
await smartFile.writeToDir('./path/to/target/dir');
// Write text content to a file (Async)
await memory.toFs('Hello SmartFile!', './path/to/output/file.txt');
```
### Streaming Large Files with `StreamFile`
When dealing with large files, you can use `StreamFile` to handle such files efficiently, minimizing memory usage:
#### Working with File Contents
```typescript
const largeFile: StreamFile = await StreamFile.fromPath('./largeInput/largeFile.mp4');
await largeFile.writeToDisk('./largeOutput/largeFileCopy.mp4');
import { SmartFile } from '@push.rocks/smartfile';
// Creating SmartFile instance from text
const smartFileFromText: SmartFile = await SmartFile.fromString('./path/to/text/file.txt', 'Text content here', 'utf8');
// Reading content from SmartFile instance
const content: string = smartFileFromText.contents.toString();
// Editing content of SmartFile
await smartFileFromText.editContentAsString(async (currentContent: string) => `Modified: ${currentContent}`);
```
### Working with Virtual Directories
Handling multiple files as if they were part of a file system:
### File Streaming
```typescript
const virtualDir = await VirtualDirectory.fromFsDirPath('./data/inputDir');
await virtualDir.saveToDisk('./data/outputDir');
import { StreamFile } from '@push.rocks/smartfile';
// Creating a StreamFile from a file path (Async)
const streamFile: StreamFile = await StreamFile.fromPath('./path/to/large/file.avi');
// Streaming file content to disk (Async)
await streamFile.writeToDisk('./path/to/target/file.avi');
```
### File System Operations
`@push.rocks/smartfile` provides a suite of utilities for common file system operations such as copying, deleting, and listing files or directories.
#### Copying a File
#### Utilizing Stream Files from URLs
```typescript
await fs.copy('./sourceFile.txt', './destinationFile.txt');
import { StreamFile } from '@push.rocks/smartfile';
// Creating a StreamFile from URL (Async)
const streamFileFromURL: StreamFile = await StreamFile.fromUrl('https://example.com/data.json');
// Accessing StreamFile content as string (Async, for textual data)
const contentAsString: string = await streamFileFromURL.getContentAsString();
```
#### Deleting a Directory
### Handling Virtual Directories
```typescript
await fs.remove('./directoryToDelete');
import { VirtualDirectory, SmartFile } from '@push.rocks/smartfile';
// Creating a virtual directory from existing directory on disk (Async)
const virtualDirectory: VirtualDirectory = await VirtualDirectory.fromFsDirPath('./path/to/source/dir');
// Adding files to virtual directory
virtualDirectory.addSmartfiles([await SmartFile.fromFilePath('./path/to/extra/file.txt')]);
// Saving virtual directory to disk (Async)
await virtualDirectory.saveToDisk('./path/to/destination/dir');
```
#### Listing Files in a Directory
#### Manipulating File Paths
```typescript
const fileList: string[] = await fs.listFiles('./someDirectory');
console.log(fileList);
import { SmartFile } from '@push.rocks/smartfile';
// Read SmartFile and change its relative path
const smartFile: SmartFile = await SmartFile.fromFilePath('./path/to/original/file.txt');
smartFile.updateFileName('newFilename.txt'); // Retains original directory but changes file name
```
### Advanced File Management
For specialized file operations, such as editing the contents of a file or streaming files from URLs, `@push.rocks/smartfile` includes advanced management features.
#### Editing a Files Contents
### Security and Hashing
```typescript
const smartFileToEdit: SmartFile = await SmartFile.fromFilePath('./editableFile.txt');
await smartFileToEdit.editContentAsString(async (content) => content.replace(/originalText/g, 'newText'));
await smartFileToEdit.write();
import { SmartFile } from '@push.rocks/smartfile';
// Creating SmartFile instance and getting hash
const smartFileForHash: SmartFile = await SmartFile.fromString('./fileForHashing.txt', 'Content for hashing', 'utf8');
const hash: string = await smartFileForHash.getHash('content'); // 'content', 'path', or 'all'
```
#### Streaming a File from a URL
### Advanced Streaming via `SmartReadStream`
For handling edge cases such as streaming large files that are being written concurrently (e.g., log files), `SmartReadStream` can be employed to monitor files for new data and stream content as it becomes available.
```typescript
const streamedFile: StreamFile = await StreamFile.fromUrl('https://example.com/file.pdf');
await streamedFile.writeToDisk('./downloadedFiles/file.pdf');
import { fsStream } from '@push.rocks/smartfile';
const smartReadStream = new fsStream.SmartReadStream('./path/to/live/file.log');
smartReadStream
.on('data', (chunk) => {
// Process streamed data
})
.on('error', (err) => {
console.error('Stream encountered an error:', err);
})
.on('end', () => {
console.log('No more data available.');
});
```
### Working with File Buffers and Streams
In conclusion, `@push.rocks/smartfile` equips developers with a highly versatile API for file manipulation, enhancing productivity in handling file operations within Node.js applications. By leveraging the examples provided, users can efficiently integrate file processing tasks into their projects, streamlining workflows and achieving granular control over file and directory management.
`@push.rocks/smartfile` allows you to easily work with files using Buffers and Streams, facilitating operations like file transformations, uploads, and downloads.
#### Creating a SmartFile from a Buffer
```typescript
const buffer: Buffer = Buffer.from('Sample data');
const bufferSmartFile: SmartFile = await SmartFile.fromBuffer('./bufferFile.txt', buffer);
await bufferSmartFile.write();
```
### Using `VirtualDirectory` for Complex File Management
`VirtualDirectory` simplifies the management of multiple files that are otherwise scattered across different directories or created at runtime.
#### Creating a `VirtualDirectory`
To create a `VirtualDirectory` from an existing file directory:
```typescript
const virtualDirectory = await VirtualDirectory.fromFsDirPath('./someDirectory');
```
#### Adding More Files
You can add more `SmartFile` instances to your `VirtualDirectory`:
```typescript
const additionalFiles = [
await SmartFile.fromFilePath('./anotherDirectory/file1.txt'),
await SmartFile.fromFilePath('./anotherDirectory/file2.txt')
];
virtualDirectory.addSmartfiles(additionalFiles);
```
#### Saving `VirtualDirectory` to Disk
Save your entire `VirtualDirectory` to disk:
```typescript
await virtualDirectory.saveToDisk('./outputDirectory');
```
### Utilizing StreamFile for Efficient File Handling
Using `StreamFile` can be especially beneficial for large files or when performing streaming operations.
#### Streaming from a URL
`StreamFile` provides capabilities to stream files directly from URLs, making it easier to work with remote content.
```typescript
const urlStreamFile: StreamFile = await StreamFile.fromUrl('https://example.com/largefile.zip');
await urlStreamFile.writeToDisk('./downloadedFiles/largefile.zip');
```
### Combining Buffer and Stream Approaches
Create `StreamFile` from a buffer for efficient, multi-use streams.
```typescript
const buffer = Buffer.from('Streaming buffer content');
const bufferStreamFile = StreamFile.fromBuffer(buffer, 'bufferBasedStream.txt');
await bufferStreamFile.writeToDisk('./streams/bufferBasedStream.txt');
```
### Read and Write Operations with StreamFile
Perform read and write operations efficiently using `StreamFile`.
```typescript
const fileStream = await StreamFile.fromPath('./inputData/largeFile.data');
await fileStream.writeToDisk('./outputData/largeFileCopy.data');
```
Check for completeness of your read and write operations, ensuring the integrity of file content.
```typescript
const readBuffer = await fileStream.getContentAsBuffer();
console.log(readBuffer.toString());
```
### Ensuring File Readiness for Streaming
Ensure a file is ready for streaming or create a custom readable stream incorporating data transformation.
```typescript
const smartReadStream = new SmartReadStream('./incomingData/sample.data');
smartReadStream.on('data', (chunk) => {
console.log('New Data Chunk:', chunk.toString());
});
```
### File Transformation with SmartReadStream
Perform transformations on the stream of data while reading:
```typescript
smartReadStream.on('data', (chunk) => {
// Perform some transformation
const transformedChunk = chunk.toString().toUpperCase();
console.log('Transformed Data Chunk:', transformedChunk);
});
```
### Streaming with SmartReadStream
Stream data from a `SmartReadStream` to a file efficiently managing large datasets.
```typescript
const transformedWriteStream = fs.createWriteStream('./processedData/transformed.data');
smartReadStream.pipe(transformedWriteStream);
```
`@push.rocks/smartfile` significantly simplifies the handling of complex file operations in Node.js projects, making these tasks straightforward while maintaining efficiency and ease of use. Explore and leverage these features to enhance your project's file management capabilities.
For more details and advanced use cases, please refer to the `@push.rocks/smartfile` documentation and explore the source code to unlock the full potential of this powerful library in your Node.js applications.
## License and Legal Information

View File

@ -1,8 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
* autocreated commitinfo by @pushrocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smartfile',
version: '11.2.0',
description: 'Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.'
version: '11.0.7',
description: 'offers smart ways to work with files in nodejs'
}

View File

@ -91,7 +91,7 @@ export class SmartFile extends plugins.smartjson.Smartjson {
});
}
public static async fromUrl(urlArg: string) {
public static async fromUrl (urlArg: string) {
const response = await plugins.smartrequest.getBinary(urlArg);
const smartfile = await SmartFile.fromBuffer(urlArg, response.body);
return smartfile;
@ -169,9 +169,7 @@ export class SmartFile extends plugins.smartjson.Smartjson {
* - no argument write to exactly where the file was picked up
*/
public async write() {
let writePath = plugins.smartpath.transform.makeAbsolute(this.path, this.base);
console.log(`writing to ${writePath}`);
await memory.toFs(this.contentBuffer, writePath);
await memory.toFs(this.contentBuffer, plugins.path.join(this.base, this.path));
}
/**
@ -212,43 +210,6 @@ export class SmartFile extends plugins.smartjson.Smartjson {
await fs.remove(plugins.path.join(this.base, this.path));
}
/**
* Renames the file to the specified new name.
* - Updates the `path` property with the new name.
* - Writes the file to the new location if it exists on disk.
* @param newName The new name of the file (including extension if applicable).
* @param writeToDisk (optional) If true, also renames the file on the disk.
* @returns The updated file path after renaming.
*/
public async rename(newName: string, writeToDisk: boolean = false): Promise<string> {
// Validate the new name
if (!newName || typeof newName !== 'string') {
throw new Error('Invalid new name provided.');
}
// Extract the directory path
const oldFilePath = this.path;
const dirPath = plugins.path.dirname(this.path);
// Create the new file path
const newFilePath = plugins.path.join(dirPath, newName);
// Update the `path` property
this.path = newFilePath;
// Optionally write the renamed file to disk
if (writeToDisk) {
const oldAbsolutePath = plugins.smartpath.transform.makeAbsolute(oldFilePath, this.base);
const newAbsolutePath = plugins.smartpath.transform.makeAbsolute(newFilePath, this.base);
// Rename the file on disk
await plugins.fsExtra.rename(oldAbsolutePath, newAbsolutePath);
}
// Return the new path
return this.path;
}
// -----------------------------------------------
// vinyl compatibility
// -----------------------------------------------
@ -343,11 +304,4 @@ export class SmartFile extends plugins.smartjson.Smartjson {
stream.push(null); // Push null to signify the end of the stream (EOF)
return stream;
}
/**
* Returns the size of the file in bytes
*/
public async getSize(): Promise<number> {
return this.contentBuffer.length;
}
}

View File

@ -10,16 +10,26 @@ type TStreamSource = (streamFile: StreamFile) => Promise<Readable>;
* It allows creating streams from a file path, a URL, or a buffer.
*/
export class StreamFile {
// INSTANCE
relativeFilePath?: string;
private streamSource: TStreamSource;
// enable stream based multi use
private cachedStreamBuffer?: Buffer;
public multiUse: boolean;
public used: boolean = false;
private constructor(streamSource: TStreamSource, relativeFilePath?: string) {
this.streamSource = streamSource;
this.relativeFilePath = relativeFilePath;
}
// STATIC
public static async fromPath(filePath: string): Promise<StreamFile> {
const streamSource: TStreamSource = async (streamFileArg) => smartfileFsStream.createReadStream(filePath);
const streamSource: TStreamSource = async (stremFileArg) => smartfileFsStream.createReadStream(filePath);
const streamFile = new StreamFile(streamSource, filePath);
streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => {
const stats = await smartfileFs.stat(filePath);
return stats.size;
}
return streamFile;
}
@ -27,10 +37,6 @@ export class StreamFile {
const streamSource: TStreamSource = async (streamFileArg) => plugins.smartrequest.getStream(url); // Replace with actual plugin method
const streamFile = new StreamFile(streamSource);
streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => {
const response = await plugins.smartrequest.getBinary(url); // TODO: switch to future .getBinaryByteLength()
return response.body.length;
}
return streamFile;
}
@ -43,7 +49,6 @@ export class StreamFile {
};
const streamFile = new StreamFile(streamSource, relativeFilePath);
streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => buffer.length;
return streamFile;
}
@ -86,22 +91,6 @@ export class StreamFile {
return streamFile;
}
// INSTANCE
relativeFilePath?: string;
private streamSource: TStreamSource;
// enable stream based multi use
private cachedStreamBuffer?: Buffer;
public multiUse: boolean;
public used: boolean = false;
public byteLengthComputeFunction: () => Promise<number>;
private constructor(streamSource: TStreamSource, relativeFilePath?: string) {
this.streamSource = streamSource;
this.relativeFilePath = relativeFilePath;
}
// METHODS
private checkMultiUse() {
@ -160,15 +149,4 @@ export class StreamFile {
const contentBuffer = await this.getContentAsBuffer();
return contentBuffer.toString(formatArg);
}
/**
* Returns the size of the file content in bytes.
*/
public async getSize(): Promise<number> {
if (this.byteLengthComputeFunction) {
return this.byteLengthComputeFunction();
} else {
return null;
}
}
}
}

230
ts/fs.ts
View File

@ -72,23 +72,25 @@ export const isFile = (pathArg): boolean => {
===============================================================*/
/**
* copies a file or directory from A to B on the local disk
* copies a file from A to B on the local disk
*/
export const copy = async (fromArg: string, toArg: string, optionsArg?: plugins.fsExtra.CopyOptions & { replaceTargetDir?: boolean }): Promise<void> => {
if (optionsArg?.replaceTargetDir && isDirectory(fromArg) && isDirectory(toArg)) {
await remove(toArg);
}
return await plugins.fsExtra.copy(fromArg, toArg, optionsArg as plugins.fsExtra.CopyOptions);
export const copy = async (fromArg: string, toArg: string): Promise<boolean> => {
const done = plugins.smartpromise.defer<boolean>();
plugins.fsExtra.copy(fromArg, toArg, {}, (err) => {
if (err) {
throw new Error(`Could not copy from ${fromArg} to ${toArg}: ${err}`);
}
done.resolve(true);
});
return done.promise;
};
/**
* copies a file or directory SYNCHRONOUSLY from A to B on the local disk
* copies a file SYNCHRONOUSLY from A to B on the local disk
*/
export const copySync = (fromArg: string, toArg: string, optionsArg?: plugins.fsExtra.CopyOptionsSync & { replaceTargetDir?: boolean }): void => {
if (optionsArg?.replaceTargetDir && isDirectory(fromArg) && isDirectory(toArg)) {
removeSync(toArg);
}
return plugins.fsExtra.copySync(fromArg, toArg, optionsArg as plugins.fsExtra.CopyOptionsSync);
export const copySync = (fromArg: string, toArg: string): boolean => {
plugins.fsExtra.copySync(fromArg, toArg);
return true;
};
/**
@ -188,8 +190,7 @@ export const removeManySync = (filePathArrayArg: string[]): void => {
===============================================================*/
/**
* reads a file content to an object
* good for JSON, YAML, TOML, etc.
*
* @param filePathArg
* @param fileTypeArg
* @returns {any}
@ -198,19 +199,14 @@ export const toObjectSync = (filePathArg, fileTypeArg?) => {
const fileString = plugins.fsExtra.readFileSync(filePathArg, 'utf8');
let fileType;
fileTypeArg ? (fileType = fileTypeArg) : (fileType = interpreter.filetype(filePathArg));
try {
return interpreter.objectFile(fileString, fileType);
} catch (err) {
err.message = `Failed to read file at ${filePathArg}` + err.message;
throw err;
}
return interpreter.objectFile(fileString, fileType);
};
/**
* reads a file content to a String
*/
export const toStringSync = (filePath: string): string => {
const encoding = plugins.smartmime.getEncodingForPathSync(filePath);
const encoding = plugins.smartmime.getEncoding(filePath);
let fileString: string | Buffer = plugins.fsExtra.readFileSync(filePath, encoding);
if (Buffer.isBuffer(fileString)) {
fileString = fileString.toString('binary');
@ -395,174 +391,53 @@ export const listFileTree = async (
/**
* Watches for file stability before resolving the promise.
* Ensures that the directory/file exists before setting up the watcher.
*
* **New behavior**: If the given path is a directory, this function will:
* 1. Wait for that directory to exist (creating a timeout if needed).
* 2. Watch the directory until at least one file appears.
* 3. Then wait for the first file in the directory to stabilize before resolving.
*
* @param fileOrDirPathArg The path of the file or directory to monitor.
* @param timeoutMs The maximum time to wait for the file to stabilize (in milliseconds). Default is 60 seconds.
* @returns A promise that resolves when the target is stable or rejects on timeout/error.
*/
export const waitForFileToBeReady = async (
fileOrDirPathArg: string,
timeoutMs: number = 60000
): Promise<void> => {
const startTime = Date.now();
/**
* Ensure that a path (file or directory) exists. If it doesn't yet exist,
* wait until it does (or time out).
* @param pathToCheck The file or directory path to check.
*/
const ensurePathExists = async (pathToCheck: string): Promise<void> => {
while (true) {
try {
await plugins.smartpromise.fromCallback((cb) =>
plugins.fs.access(pathToCheck, plugins.fs.constants.F_OK, cb)
);
return;
} catch (err: any) {
if (err.code !== 'ENOENT') {
throw err; // Propagate unexpected errors
}
if (Date.now() - startTime > timeoutMs) {
throw new Error(`Timeout waiting for path to exist: ${pathToCheck}`);
}
await plugins.smartdelay.delayFor(500);
}
}
};
/**
* Checks if a file (not directory) is stable by comparing sizes
* across successive checks.
* @param filePathArg The path of the file to check.
* @returns A promise that resolves once the file stops changing.
*/
const waitForSingleFileToBeStable = async (filePathArg: string): Promise<void> => {
export const waitForFileToBeReady = (filePathArg: string): Promise<void> => {
return new Promise(async (resolve, reject) => {
let lastFileSize = -1;
let fileIsStable = false;
// We'll create a helper for repeated stats-checking logic
const checkFileStability = async () => {
try {
const stats = await plugins.smartpromise.fromCallback<plugins.fs.Stats>((cb) =>
plugins.fs.stat(filePathArg, cb)
);
if (stats.isDirectory()) {
// If it unexpectedly turns out to be a directory here, throw
throw new Error(`Expected a file but found a directory: ${filePathArg}`);
}
if (stats.size === lastFileSize) {
let currentFileSize: number;
const deferred = plugins.smartpromise.defer();
plugins.fs.stat(filePathArg, (err, stats) => {
if (err) {
fileIsStable = true;
} else {
lastFileSize = stats.size;
fileIsStable = false;
}
} catch (err: any) {
// Ignore only if file not found
if (err.code !== 'ENOENT') {
throw err;
watcher.close();
reject(err);
return;
}
currentFileSize = stats.size;
deferred.resolve();
});
await deferred.promise;
if (currentFileSize === lastFileSize) {
fileIsStable = true;
await plugins.smartdelay.delayFor(100);
resolve();
}
lastFileSize = currentFileSize;
};
// Ensure file exists first
await ensurePathExists(filePathArg);
// Set up a watcher on the file itself
const fileWatcher = plugins.fs.watch(filePathArg, { persistent: true }, async () => {
if (!fileIsStable) {
await checkFileStability();
const watcher = plugins.fs.watch(filePathArg, (eventType, filename) => {
if (eventType === 'change') {
checkFileStability();
}
});
try {
// Poll until stable or timeout
while (!fileIsStable) {
if (Date.now() - startTime > timeoutMs) {
throw new Error(`Timeout waiting for file to stabilize: ${filePathArg}`);
}
await checkFileStability();
if (!fileIsStable) {
await plugins.smartdelay.delayFor(1000);
}
}
} finally {
fileWatcher.close();
}
};
watcher.on('error', (error) => {
watcher.close();
reject(error);
});
/**
* Main logic: check if we have a directory or file at fileOrDirPathArg.
* If directory, wait for first file in the directory to appear and stabilize.
* If file, do the old single-file wait logic.
*/
const statsForGivenPath = await (async () => {
try {
await ensurePathExists(fileOrDirPathArg);
return await plugins.smartpromise.fromCallback<plugins.fs.Stats>((cb) =>
plugins.fs.stat(fileOrDirPathArg, cb)
);
} catch (err) {
// If there's an error (including timeout), just rethrow
throw err;
}
})();
if (!statsForGivenPath.isDirectory()) {
// It's a file just do the single-file stability wait
await waitForSingleFileToBeStable(fileOrDirPathArg);
return;
}
// Otherwise, it's a directory. Wait for the first file inside to appear and be stable
const dirPath = fileOrDirPathArg;
// Helper to find the first file in the directory if it exists
const getFirstFileInDirectory = async (): Promise<string | null> => {
const entries = await plugins.smartpromise.fromCallback<string[]>((cb) =>
plugins.fs.readdir(dirPath, cb)
);
// We only want actual files, not subdirectories
for (const entry of entries) {
const entryPath = plugins.path.join(dirPath, entry);
const entryStats = await plugins.smartpromise.fromCallback<plugins.fs.Stats>((cb) =>
plugins.fs.stat(entryPath, cb)
);
if (entryStats.isFile()) {
return entryPath;
while (!fileIsStable) {
await checkFileStability();
if (!fileIsStable) {
await plugins.smartdelay.delayFor(5000);
}
}
return null;
};
// Wait for a file to appear in this directory
let firstFilePath = await getFirstFileInDirectory();
if (!firstFilePath) {
// Set up a watcher on the directory to see if a file appears
const directoryWatcher = plugins.fs.watch(dirPath, { persistent: true });
try {
// We'll poll for the existence of a file in that directory
while (!firstFilePath) {
if (Date.now() - startTime > timeoutMs) {
throw new Error(`Timeout waiting for a file to appear in directory: ${dirPath}`);
}
firstFilePath = await getFirstFileInDirectory();
if (!firstFilePath) {
await plugins.smartdelay.delayFor(1000);
}
}
} finally {
directoryWatcher.close();
}
}
// Now that we have a file path, wait for that file to stabilize
await waitForSingleFileToBeStable(firstFilePath);
watcher.close();
});
};
/**
@ -572,8 +447,8 @@ export const waitForFileToBeReady = async (
* @param fileBaseArg
*/
export let toFs = async (
fileContentArg: string | Buffer | SmartFile | StreamFile,
filePathArg: string,
fileContentArg: string | Buffer | SmartFile | StreamFile,
optionsArg: {
respectRelative?: boolean;
} = {}
@ -610,6 +485,7 @@ export let toFs = async (
return await done.promise;
};
export const stat = async (filePathArg: string) => {
return plugins.fsPromises.stat(filePathArg);
};

View File

@ -1,10 +1,9 @@
// node native scope
import * as fs from 'fs';
import * as fsPromises from 'fs/promises';
import * as path from 'path';
import * as stream from 'stream';
export { fs, fsPromises, path, stream };
export { fs, path, stream };
// @pushrocks scope
import * as lik from '@push.rocks/lik';