ktfile 0.0.1 → 0.0.2
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/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/CONTRIBUTING.md +291 -0
- package/README.md +431 -2
- package/index.min.js +1 -1
- package/package.json +3 -3
- /package/types/{kfile.d.ts → ktfile.d.ts} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: "[BUG]"
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: OguzhanUmutlu
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Environment:**
|
|
11
|
+
|
|
12
|
+
- OS: [e.g. Windows 10, macOS 12, Ubuntu 20.04]
|
|
13
|
+
- Node.js: [e.g. 16.14.0]
|
|
14
|
+
- KTFile: [e.g. 1.0.0]
|
|
15
|
+
|
|
16
|
+
**Description:**
|
|
17
|
+
Clear description of the bug
|
|
18
|
+
|
|
19
|
+
**Reproduction:**
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// Minimal code example
|
|
23
|
+
const file = fileSync('./example.txt');
|
|
24
|
+
// Steps to reproduce...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Expected Behavior:**
|
|
28
|
+
What should happen
|
|
29
|
+
|
|
30
|
+
**Actual Behavior:**
|
|
31
|
+
What actually happens
|
|
32
|
+
|
|
33
|
+
**Additional Context:**
|
|
34
|
+
Any other relevant information
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: "[FEATURE]"
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: OguzhanUmutlu
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Feature Description:**
|
|
11
|
+
Clear description of the proposed feature
|
|
12
|
+
|
|
13
|
+
**Use Case:**
|
|
14
|
+
Why is this feature needed? What problem does it solve?
|
|
15
|
+
|
|
16
|
+
**Proposed API:**
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// Example of how the feature might work
|
|
20
|
+
file.newMethod(parameters);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Alternatives Considered:**
|
|
24
|
+
What other approaches did you consider?
|
|
25
|
+
|
|
26
|
+
**Additional Context:**
|
|
27
|
+
Any other relevant information
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Contributing to KTFile
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to KTFile! This document provides guidelines and information for
|
|
4
|
+
contributors.
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
|
|
8
|
+
- [Getting Started](#getting-started)
|
|
9
|
+
- [Development Setup](#development-setup)
|
|
10
|
+
- [Project Structure](#project-structure)
|
|
11
|
+
- [Development Workflow](#development-workflow)
|
|
12
|
+
- [Code Style Guidelines](#code-style-guidelines)
|
|
13
|
+
- [Testing](#testing)
|
|
14
|
+
- [Submitting Changes](#submitting-changes)
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
|
|
18
|
+
### Prerequisites
|
|
19
|
+
|
|
20
|
+
- Node.js (version 14 or higher recommended)
|
|
21
|
+
- npm or yarn package manager
|
|
22
|
+
- Git
|
|
23
|
+
|
|
24
|
+
### Fork and Clone
|
|
25
|
+
|
|
26
|
+
1. Fork the repository on GitHub
|
|
27
|
+
2. Clone your fork locally:
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/YOUR_USERNAME/ktfile.git
|
|
30
|
+
cd ktfile
|
|
31
|
+
```
|
|
32
|
+
3. Add the original repository as upstream:
|
|
33
|
+
```bash
|
|
34
|
+
git remote add upstream https://github.com/OguzhanUmutlu/ktfile.git
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Development Setup
|
|
38
|
+
|
|
39
|
+
1. Install dependencies:
|
|
40
|
+
```bash
|
|
41
|
+
npm install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. Build the project:
|
|
45
|
+
```bash
|
|
46
|
+
npm run build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
3. Run tests:
|
|
50
|
+
```bash
|
|
51
|
+
npm test
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Project Structure
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
ktfile/
|
|
58
|
+
├── src/ # TypeScript source files
|
|
59
|
+
│ ├── async/ # Async file system implementations
|
|
60
|
+
│ │ ├── FileAsync.ts # Main async file class
|
|
61
|
+
│ │ └── IAsyncFS.ts # Async file system interface
|
|
62
|
+
│ ├── sync/ # Sync file system implementations
|
|
63
|
+
│ │ ├── FileSync.ts # Main sync file class
|
|
64
|
+
│ │ └── ISyncFS.ts # Sync file system interface
|
|
65
|
+
│ ├── IFile.ts # Base file interface
|
|
66
|
+
│ ├── Utils.ts # Utility functions
|
|
67
|
+
│ └── ktfile.ts # Main entry point
|
|
68
|
+
├── types/ # Generated TypeScript declarations
|
|
69
|
+
├── dist/ # Compiled JavaScript output
|
|
70
|
+
├── tests/ # Test files
|
|
71
|
+
│ ├── test.ts # Main test suite
|
|
72
|
+
│ ├── test.html # Browser tests
|
|
73
|
+
│ └── clean.js # Test cleanup utility
|
|
74
|
+
├── rollup.config.mjs # Build configuration
|
|
75
|
+
├── tsconfig.json # TypeScript configuration
|
|
76
|
+
├── index.min.js # Minified distribution file
|
|
77
|
+
└── package.json # Project metadata
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Key Files
|
|
81
|
+
|
|
82
|
+
- **`src/ktfile.ts`**: Main entry point, exports public API
|
|
83
|
+
- **`src/sync/FileSync.ts`**: Synchronous file operations implementation
|
|
84
|
+
- **`src/async/FileAsync.ts`**: Asynchronous file operations implementation
|
|
85
|
+
- **`src/IFile.ts`**: Base interface shared by both sync and async implementations
|
|
86
|
+
- **`src/Utils.ts`**: Shared utility functions
|
|
87
|
+
|
|
88
|
+
## Development Workflow
|
|
89
|
+
|
|
90
|
+
### Branch Strategy
|
|
91
|
+
|
|
92
|
+
1. Create a feature branch from `main`:
|
|
93
|
+
```bash
|
|
94
|
+
git checkout -b feature/your-feature-name
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
2. Make your changes and commit them with descriptive messages
|
|
98
|
+
|
|
99
|
+
3. Keep your branch up to date with upstream:
|
|
100
|
+
```bash
|
|
101
|
+
git fetch upstream
|
|
102
|
+
git rebase upstream/main
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
4. Push your branch and create a pull request
|
|
106
|
+
|
|
107
|
+
### Building
|
|
108
|
+
|
|
109
|
+
The project uses Rollup for building. Available scripts:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm run build # Build TypeScript and create distributions
|
|
113
|
+
npm run build:types # Generate type declarations only
|
|
114
|
+
npm run dev # Watch mode for development
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### File System Abstractions
|
|
118
|
+
|
|
119
|
+
KTFile uses interface-based abstractions to support different environments:
|
|
120
|
+
|
|
121
|
+
- **`ISyncFS`**: Interface for synchronous file system operations
|
|
122
|
+
- **`IAsyncFS`**: Interface for asynchronous file system operations
|
|
123
|
+
|
|
124
|
+
When adding new functionality:
|
|
125
|
+
|
|
126
|
+
1. Add the method signature to the appropriate interface
|
|
127
|
+
2. Implement it in both sync and async file classes
|
|
128
|
+
3. Ensure cross-platform compatibility
|
|
129
|
+
|
|
130
|
+
## Code Style Guidelines
|
|
131
|
+
|
|
132
|
+
### TypeScript Standards
|
|
133
|
+
|
|
134
|
+
- Use TypeScript strict mode
|
|
135
|
+
- Provide explicit type annotations for public APIs
|
|
136
|
+
- Use meaningful variable and function names
|
|
137
|
+
- Follow existing naming conventions:
|
|
138
|
+
- Classes: `PascalCase`
|
|
139
|
+
- Methods/properties: `camelCase`
|
|
140
|
+
- Constants: `UPPER_SNAKE_CASE`
|
|
141
|
+
|
|
142
|
+
### Code Formatting
|
|
143
|
+
|
|
144
|
+
- Use 4 spaces for indentation
|
|
145
|
+
- Use semicolons
|
|
146
|
+
- Use double quotes for strings
|
|
147
|
+
- Maximum line length: 120 characters
|
|
148
|
+
|
|
149
|
+
### Error Handling
|
|
150
|
+
|
|
151
|
+
- Methods should return `null` on failure rather than throwing exceptions
|
|
152
|
+
- Use `| null` return types for operations that can fail
|
|
153
|
+
- Document when methods can return `null` and why
|
|
154
|
+
|
|
155
|
+
### Example Code Style
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
export class FileSync extends IFile<ISyncFS> {
|
|
159
|
+
/**
|
|
160
|
+
* Reads file content as string or Buffer
|
|
161
|
+
* @param encoding Optional text encoding
|
|
162
|
+
* @returns File content or null if read fails
|
|
163
|
+
*/
|
|
164
|
+
read(encoding?: BufferEncoding): string | null;
|
|
165
|
+
read(): Buffer | null;
|
|
166
|
+
read(encoding?: BufferEncoding): string | Buffer | null {
|
|
167
|
+
try {
|
|
168
|
+
// Implementation here
|
|
169
|
+
return this.fs.readFileSync(this.path, encoding);
|
|
170
|
+
} catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Testing
|
|
178
|
+
|
|
179
|
+
### Running Tests
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm test # Run all tests
|
|
183
|
+
npm run test:node # Run Node.js tests only
|
|
184
|
+
npm run test:browser # Run browser tests only
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Test Structure
|
|
188
|
+
|
|
189
|
+
- Tests are located in the `tests/` directory
|
|
190
|
+
- Main test suite: `tests/test.ts`
|
|
191
|
+
- Browser compatibility tests: `tests/test.html`
|
|
192
|
+
- Test cleanup utility: `tests/clean.js`
|
|
193
|
+
|
|
194
|
+
### Writing Tests
|
|
195
|
+
|
|
196
|
+
When adding new features:
|
|
197
|
+
|
|
198
|
+
1. Add tests for both sync and async implementations
|
|
199
|
+
2. Test error conditions (methods returning `null`)
|
|
200
|
+
3. Test cross-platform behavior where applicable
|
|
201
|
+
4. Include edge cases and boundary conditions
|
|
202
|
+
|
|
203
|
+
Example test pattern:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// Test successful operation
|
|
207
|
+
const file = fileSync('./test-file.txt');
|
|
208
|
+
file.write('test content');
|
|
209
|
+
assert.strictEqual(file.read(), 'test content');
|
|
210
|
+
|
|
211
|
+
// Test error condition
|
|
212
|
+
const nonexistent = fileSync('./nonexistent.txt');
|
|
213
|
+
assert.strictEqual(nonexistent.read(), null);
|
|
214
|
+
|
|
215
|
+
// Test async equivalent
|
|
216
|
+
const asyncFile = fileAsync('./test-file.txt');
|
|
217
|
+
await asyncFile.write('test content');
|
|
218
|
+
assert.strictEqual(await asyncFile.read(), 'test content');
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Submitting Changes
|
|
222
|
+
|
|
223
|
+
### Pull Request Guidelines
|
|
224
|
+
|
|
225
|
+
1. **Clear Title**: Use a descriptive title that summarizes the change
|
|
226
|
+
2. **Description**: Include:
|
|
227
|
+
- What the change does
|
|
228
|
+
- Why it's needed
|
|
229
|
+
- Any breaking changes
|
|
230
|
+
- Testing performed
|
|
231
|
+
|
|
232
|
+
3. **Code Quality**:
|
|
233
|
+
- Ensure all tests pass
|
|
234
|
+
- Follow coding standards
|
|
235
|
+
- Update documentation if needed
|
|
236
|
+
- Add tests for new functionality
|
|
237
|
+
|
|
238
|
+
4. **Commit Messages**:
|
|
239
|
+
- Use clear, descriptive commit messages
|
|
240
|
+
- Reference issue numbers when applicable
|
|
241
|
+
- Use imperative mood: "Add feature" not "Added feature"
|
|
242
|
+
|
|
243
|
+
### Pull Request Template
|
|
244
|
+
|
|
245
|
+
```markdown
|
|
246
|
+
## Description
|
|
247
|
+
|
|
248
|
+
Brief description of changes
|
|
249
|
+
|
|
250
|
+
## Type of Change
|
|
251
|
+
|
|
252
|
+
- [ ] Bug fix
|
|
253
|
+
- [ ] New feature
|
|
254
|
+
- [ ] Breaking change
|
|
255
|
+
- [ ] Documentation update
|
|
256
|
+
|
|
257
|
+
## Testing
|
|
258
|
+
|
|
259
|
+
- [ ] Tests pass locally
|
|
260
|
+
- [ ] Added tests for new functionality
|
|
261
|
+
- [ ] Tested on multiple platforms (if applicable)
|
|
262
|
+
|
|
263
|
+
## Checklist
|
|
264
|
+
|
|
265
|
+
- [ ] Code follows project style guidelines
|
|
266
|
+
- [ ] Self-review completed
|
|
267
|
+
- [ ] Documentation updated (if needed)
|
|
268
|
+
- [ ] No breaking changes (or breaking changes documented)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Debugging
|
|
272
|
+
|
|
273
|
+
- Test both sync and async implementations
|
|
274
|
+
- Verify behavior in both Node.js and browser environments
|
|
275
|
+
|
|
276
|
+
## Getting Help
|
|
277
|
+
|
|
278
|
+
- **Documentation**: Check the README and inline code documentation
|
|
279
|
+
- **Issues**: Search existing issues for similar problems
|
|
280
|
+
- **Discussions**: Use GitHub Discussions for questions and ideas
|
|
281
|
+
- **Contact**: Reach out to maintainers through GitHub
|
|
282
|
+
|
|
283
|
+
## Recognition
|
|
284
|
+
|
|
285
|
+
Contributors will be recognized in:
|
|
286
|
+
|
|
287
|
+
- GitHub contributors list
|
|
288
|
+
- Release notes (for significant contributions)
|
|
289
|
+
- Documentation acknowledgments
|
|
290
|
+
|
|
291
|
+
Thank you for contributing to KTFile! 🎉
|
package/README.md
CHANGED
|
@@ -1,2 +1,431 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# KTFile
|
|
2
|
+
|
|
3
|
+
A powerful, cross-platform file system library for JavaScript/TypeScript that provides both synchronous and asynchronous APIs with a clean, object-oriented interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **Dual API**: Both synchronous (`FileSync`) and asynchronous (`FileAsync`) operations
|
|
8
|
+
- 🔧 **Cross-platform**: Works in Node.js and other JavaScript environments
|
|
9
|
+
- 📁 **Rich file operations**: Create, read, write, copy, move, delete files and directories
|
|
10
|
+
- 🎯 **Type-safe**: Full TypeScript support with detailed type definitions
|
|
11
|
+
- 🔗 **Path manipulation**: Intuitive path joining and navigation
|
|
12
|
+
- 📊 **File metadata**: Access file properties like size, timestamps, permissions
|
|
13
|
+
- 🔄 **Directory traversal**: Walk through directory trees with generators
|
|
14
|
+
- 📝 **Multiple formats**: Support for text, binary, and JSON file operations
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install ktfile
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Basic Usage
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import { fileSync, fileAsync, File } from 'ktfile';
|
|
28
|
+
|
|
29
|
+
// Synchronous API
|
|
30
|
+
const file = fileSync('/path/to/file.txt');
|
|
31
|
+
file.write('Hello, world!');
|
|
32
|
+
console.log(file.read()); // "Hello, world!"
|
|
33
|
+
|
|
34
|
+
// Asynchronous API
|
|
35
|
+
const asyncFile = fileAsync('/path/to/file.txt');
|
|
36
|
+
await asyncFile.write('Hello, async world!');
|
|
37
|
+
console.log(await asyncFile.read()); // "Hello, async world!"
|
|
38
|
+
|
|
39
|
+
// Alternative syntax
|
|
40
|
+
const file2 = new File('/another/path');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Node.js Setup
|
|
44
|
+
|
|
45
|
+
The library automatically initializes with Node.js `fs` module when available. For custom environments:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
import { initFS } from 'ktfile';
|
|
49
|
+
import fs from 'fs';
|
|
50
|
+
|
|
51
|
+
initFS(fs);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API Reference
|
|
55
|
+
|
|
56
|
+
### FileSync Class
|
|
57
|
+
|
|
58
|
+
#### Properties
|
|
59
|
+
|
|
60
|
+
- `fs: ISyncFS` - The underlying file system instance
|
|
61
|
+
- `canExecute: boolean` - File execute permission
|
|
62
|
+
- `canRead: boolean` - File read permission
|
|
63
|
+
- `canWrite: boolean` - File write permission
|
|
64
|
+
- `creationTime: Date | null` - File creation timestamp
|
|
65
|
+
- `lastModified: Date | null` - Last modification timestamp
|
|
66
|
+
- `lastAccess: Date | null` - Last access timestamp
|
|
67
|
+
- `exists: boolean | null` - Whether the file exists
|
|
68
|
+
- `name: string` - File name with extension
|
|
69
|
+
- `nameWithoutExtension: string` - File name without extension
|
|
70
|
+
- `extension: string` - File extension
|
|
71
|
+
- `parent: FileSync | null` - Parent directory
|
|
72
|
+
- `uri: string` - File URI
|
|
73
|
+
- `separator: string` - Path separator for the platform
|
|
74
|
+
- `isDirectory: boolean | null` - Whether this is a directory
|
|
75
|
+
- `isFile: boolean | null` - Whether this is a regular file
|
|
76
|
+
- `isHidden: boolean` - Whether the file is hidden
|
|
77
|
+
- `isSymbolicLink: boolean | null` - Whether this is a symbolic link
|
|
78
|
+
- `size: number | null` - File size in bytes
|
|
79
|
+
- `sizeKB: number | null` - File size in kilobytes
|
|
80
|
+
- `sizeMB: number | null` - File size in megabytes
|
|
81
|
+
- `sizeGB: number | null` - File size in gigabytes
|
|
82
|
+
|
|
83
|
+
#### Methods
|
|
84
|
+
|
|
85
|
+
##### Path Operations
|
|
86
|
+
```javascript
|
|
87
|
+
// Join paths
|
|
88
|
+
const newPath = file.to('subdirectory', 'file.txt');
|
|
89
|
+
|
|
90
|
+
// Check if path contains another path
|
|
91
|
+
const contains = parentDir.contains(childFile);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
##### File Creation and Deletion
|
|
95
|
+
```javascript
|
|
96
|
+
// Create file
|
|
97
|
+
file.createFile();
|
|
98
|
+
|
|
99
|
+
// Create temporary file
|
|
100
|
+
const tempFile = FileSync.createTempFile(directory, 'prefix', '.tmp');
|
|
101
|
+
|
|
102
|
+
// Delete file or directory
|
|
103
|
+
file.delete(recursive = false, force = false);
|
|
104
|
+
|
|
105
|
+
// Schedule deletion on exit
|
|
106
|
+
file.deleteOnExit(recursive = false);
|
|
107
|
+
|
|
108
|
+
// Clear directory contents
|
|
109
|
+
directory.clear(recursive = true);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
##### Directory Operations
|
|
113
|
+
```javascript
|
|
114
|
+
// Create directory
|
|
115
|
+
directory.mkdir(recursive = false);
|
|
116
|
+
|
|
117
|
+
// Create directory tree
|
|
118
|
+
directory.mkdirs();
|
|
119
|
+
|
|
120
|
+
// List files in directory
|
|
121
|
+
const files = directory.listFiles();
|
|
122
|
+
const filenames = directory.listFilenames();
|
|
123
|
+
|
|
124
|
+
// Walk directory tree
|
|
125
|
+
for (const file of directory.walk()) {
|
|
126
|
+
console.log(file.name);
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
##### File Operations
|
|
131
|
+
```javascript
|
|
132
|
+
// Copy file
|
|
133
|
+
file.copyTo(destination, overwrite = false, recursive = false);
|
|
134
|
+
|
|
135
|
+
// Move/rename file
|
|
136
|
+
file.renameTo(newLocation, overwrite = false, recursive = false);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
##### Reading Files
|
|
140
|
+
```javascript
|
|
141
|
+
// Read as string
|
|
142
|
+
const content = file.read('utf8');
|
|
143
|
+
|
|
144
|
+
// Read as Buffer
|
|
145
|
+
const buffer = file.read();
|
|
146
|
+
|
|
147
|
+
// Read lines as array
|
|
148
|
+
const lines = file.readLines('utf8');
|
|
149
|
+
|
|
150
|
+
// Read JSON
|
|
151
|
+
const data = file.readJSON();
|
|
152
|
+
|
|
153
|
+
// Read symbolic link target
|
|
154
|
+
const target = symlink.readlink();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
##### Writing Files
|
|
158
|
+
```javascript
|
|
159
|
+
// Write string or Buffer
|
|
160
|
+
file.write('content', 'utf8');
|
|
161
|
+
file.write(buffer);
|
|
162
|
+
|
|
163
|
+
// Write with custom encoder
|
|
164
|
+
file.write(data, { write: () => data });
|
|
165
|
+
|
|
166
|
+
// Write JSON
|
|
167
|
+
file.writeJSON({ key: 'value' });
|
|
168
|
+
|
|
169
|
+
// Append to file
|
|
170
|
+
file.append('more content', 'utf8');
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### FileAsync Class
|
|
174
|
+
|
|
175
|
+
The `FileAsync` class provides Promise-based asynchronous operations with a similar API to `FileSync`:
|
|
176
|
+
|
|
177
|
+
#### Properties
|
|
178
|
+
|
|
179
|
+
- `fs: IAsyncFS` - The underlying async file system instance
|
|
180
|
+
- `name: string` - File name with extension
|
|
181
|
+
- `nameWithoutExtension: string` - File name without extension
|
|
182
|
+
- `extension: string` - File extension
|
|
183
|
+
- `parent: FileAsync | null` - Parent directory
|
|
184
|
+
- `uri: string` - File URI
|
|
185
|
+
- `separator: string` - Path separator for the platform
|
|
186
|
+
- `isHidden: boolean` - Whether the file is hidden
|
|
187
|
+
- `sync: FileSync` - Access to synchronous version of this file
|
|
188
|
+
|
|
189
|
+
#### Methods
|
|
190
|
+
|
|
191
|
+
All methods that return metadata or perform operations are asynchronous and return Promises:
|
|
192
|
+
|
|
193
|
+
##### Permission Methods
|
|
194
|
+
```javascript
|
|
195
|
+
// Check permissions
|
|
196
|
+
const canRead = await file.canRead();
|
|
197
|
+
const canWrite = await file.canWrite();
|
|
198
|
+
const canExecute = await file.canExecute();
|
|
199
|
+
|
|
200
|
+
// Set permissions
|
|
201
|
+
await file.setReadable(true);
|
|
202
|
+
await file.setWritable(false);
|
|
203
|
+
await file.setExecutable(true);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
##### Metadata Methods
|
|
207
|
+
```javascript
|
|
208
|
+
// Get timestamps
|
|
209
|
+
const created = await file.creationTime();
|
|
210
|
+
const modified = await file.lastModified();
|
|
211
|
+
const accessed = await file.lastAccess();
|
|
212
|
+
|
|
213
|
+
// Set timestamps
|
|
214
|
+
await file.setCreationTime(new Date());
|
|
215
|
+
await file.setLastModified(new Date());
|
|
216
|
+
|
|
217
|
+
// File information
|
|
218
|
+
const exists = await file.exists();
|
|
219
|
+
const isDir = await file.isDirectory();
|
|
220
|
+
const isFile = await file.isFile();
|
|
221
|
+
const isLink = await file.isSymbolicLink();
|
|
222
|
+
|
|
223
|
+
// File sizes
|
|
224
|
+
const bytes = await file.size();
|
|
225
|
+
const kb = await file.sizeKB();
|
|
226
|
+
const mb = await file.sizeMB();
|
|
227
|
+
const gb = await file.sizeGB();
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
##### File Operations
|
|
231
|
+
```javascript
|
|
232
|
+
// Create and delete
|
|
233
|
+
await file.createFile();
|
|
234
|
+
await file.delete(recursive, force);
|
|
235
|
+
await directory.clear(recursive);
|
|
236
|
+
|
|
237
|
+
// Copy and move
|
|
238
|
+
await file.copyTo(destination, overwrite, recursive);
|
|
239
|
+
await file.renameTo(newLocation, overwrite, recursive);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
##### Directory Operations
|
|
243
|
+
```javascript
|
|
244
|
+
// Create directories
|
|
245
|
+
await directory.mkdir(recursive);
|
|
246
|
+
await directory.mkdirs();
|
|
247
|
+
|
|
248
|
+
// List contents
|
|
249
|
+
const files = await directory.listFiles();
|
|
250
|
+
const filenames = await directory.listFilenames();
|
|
251
|
+
|
|
252
|
+
// Walk directory tree (AsyncGenerator)
|
|
253
|
+
for await (const file of directory.walk()) {
|
|
254
|
+
console.log(file.name);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
##### Reading Files
|
|
259
|
+
```javascript
|
|
260
|
+
// Read file contents
|
|
261
|
+
const content = await file.read('utf8');
|
|
262
|
+
const buffer = await file.read();
|
|
263
|
+
const lines = await file.readLines('utf8');
|
|
264
|
+
const data = await file.readJSON();
|
|
265
|
+
|
|
266
|
+
// Read symbolic link
|
|
267
|
+
const target = await symlink.readlink();
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
##### Writing Files
|
|
271
|
+
```javascript
|
|
272
|
+
// Write content
|
|
273
|
+
await file.write('content', 'utf8');
|
|
274
|
+
await file.write(buffer);
|
|
275
|
+
await file.writeJSON({ key: 'value' });
|
|
276
|
+
await file.append('more content', 'utf8');
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
##### Static Methods
|
|
280
|
+
```javascript
|
|
281
|
+
// Create temporary file
|
|
282
|
+
const tempFile = FileAsync.createTempFile(directory, 'prefix', '.tmp');
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Examples
|
|
286
|
+
|
|
287
|
+
### Working with Directories
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
import { fileSync } from 'ktfile';
|
|
291
|
+
|
|
292
|
+
const projectDir = fileSync('./my-project');
|
|
293
|
+
|
|
294
|
+
// Create project structure
|
|
295
|
+
projectDir.mkdirs();
|
|
296
|
+
projectDir.to('src').mkdir();
|
|
297
|
+
projectDir.to('tests').mkdir();
|
|
298
|
+
projectDir.to('docs').mkdir();
|
|
299
|
+
|
|
300
|
+
// Create files
|
|
301
|
+
const packageJson = projectDir.to('package.json');
|
|
302
|
+
packageJson.writeJSON({
|
|
303
|
+
name: 'my-project',
|
|
304
|
+
version: '1.0.0'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const readme = projectDir.to('README.md');
|
|
308
|
+
readme.write('# My Project\n\nDescription here...');
|
|
309
|
+
|
|
310
|
+
// List all files
|
|
311
|
+
for (const file of projectDir.walk()) {
|
|
312
|
+
if (file.isFile) {
|
|
313
|
+
console.log(`File: ${file.name} (${file.sizeKB} KB)`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### File Manipulation
|
|
319
|
+
|
|
320
|
+
```javascript
|
|
321
|
+
import { fileSync } from 'ktfile';
|
|
322
|
+
|
|
323
|
+
const sourceFile = fileSync('./data.json');
|
|
324
|
+
const backupFile = fileSync('./backup/data-backup.json');
|
|
325
|
+
|
|
326
|
+
// Create backup directory
|
|
327
|
+
backupFile.parent?.mkdirs();
|
|
328
|
+
|
|
329
|
+
// Copy file
|
|
330
|
+
sourceFile.copyTo(backupFile, true);
|
|
331
|
+
|
|
332
|
+
// Read and modify JSON
|
|
333
|
+
const data = sourceFile.readJSON();
|
|
334
|
+
data.lastBackup = new Date().toISOString();
|
|
335
|
+
sourceFile.writeJSON(data);
|
|
336
|
+
|
|
337
|
+
console.log(`Backup created: ${backupFile.size} bytes`);
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Async Operations
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
import { fileAsync } from 'ktfile';
|
|
344
|
+
|
|
345
|
+
async function processFiles() {
|
|
346
|
+
const directory = fileAsync('./uploads');
|
|
347
|
+
const files = await directory.listFiles();
|
|
348
|
+
|
|
349
|
+
for (const file of files || []) {
|
|
350
|
+
if (file.extension === '.txt') {
|
|
351
|
+
const content = await file.read('utf8');
|
|
352
|
+
const processed = content.toUpperCase();
|
|
353
|
+
|
|
354
|
+
const outputFile = file.parent?.to('processed', file.name);
|
|
355
|
+
await outputFile?.parent?.mkdirs();
|
|
356
|
+
await outputFile?.write(processed);
|
|
357
|
+
|
|
358
|
+
console.log(`Processed: ${file.name}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
processFiles().catch(console.error);
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Temporary Files
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
import { FileSync, fileSync } from 'ktfile';
|
|
370
|
+
|
|
371
|
+
const tempDir = fileSync('./temp');
|
|
372
|
+
tempDir.mkdirs();
|
|
373
|
+
|
|
374
|
+
// Create temporary file
|
|
375
|
+
const tempFile = FileSync.createTempFile(tempDir, 'data-', '.json');
|
|
376
|
+
tempFile.writeJSON({ processing: true, timestamp: Date.now() });
|
|
377
|
+
|
|
378
|
+
// Use the temporary file
|
|
379
|
+
console.log(`Temp file created: ${tempFile.name}`);
|
|
380
|
+
|
|
381
|
+
// Clean up on exit
|
|
382
|
+
tempFile.deleteOnExit();
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Error Handling
|
|
386
|
+
|
|
387
|
+
Methods return `null` when operations fail, allowing for graceful error handling:
|
|
388
|
+
|
|
389
|
+
```javascript
|
|
390
|
+
const file = fileSync('./nonexistent.txt');
|
|
391
|
+
|
|
392
|
+
const content = file.read();
|
|
393
|
+
if (content === null) {
|
|
394
|
+
console.log('File does not exist or cannot be read');
|
|
395
|
+
} else {
|
|
396
|
+
console.log('File content:', content);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Check existence before operations
|
|
400
|
+
if (file.exists) {
|
|
401
|
+
file.delete();
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Cross-Platform Compatibility
|
|
406
|
+
|
|
407
|
+
KTFile handles platform differences automatically:
|
|
408
|
+
|
|
409
|
+
```javascript
|
|
410
|
+
const file = fileSync('./path/to/file.txt');
|
|
411
|
+
|
|
412
|
+
// Uses correct separator for platform
|
|
413
|
+
console.log(file.separator); // '/' on Unix, '\' on Windows
|
|
414
|
+
|
|
415
|
+
// Paths are normalized automatically
|
|
416
|
+
const nested = file.parent?.to('..', 'sibling', 'file.txt');
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
MIT License
|
|
422
|
+
|
|
423
|
+
See the [LICENSE](LICENSE) file for details.
|
|
424
|
+
|
|
425
|
+
## Contributing
|
|
426
|
+
|
|
427
|
+
Contributions are welcome! Please read the [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
|
|
428
|
+
|
|
429
|
+
## Support
|
|
430
|
+
|
|
431
|
+
If you find this library useful, please consider starring the repository on GitHub and sharing it with others!
|
package/index.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let t=[];function s(s,e=t){s.startsWith("/")?(e=[],s=s.slice(1)):e=[...e];const i=s.split("/");for(const t of i)".."===t?e.pop():"."!==t&&""!==t&&e.push(t);return e}"undefined"!=typeof process&&"cwd"in process&&"function"==typeof process.cwd&&(t=s(process.cwd()));const e=new Map;function i(t,s,e){const i=t.listeners(s);t.removeAllListeners(s);for(const n of i)n!==e&&t.on(s,n);t.on(s,e)}function n(){for(const[t,s]of e.entries())new d(t).delete(s);e.clear(),"undefined"!=typeof process?(process.off("SIGINT",r),process.off("SIGTERM",l),process.off("exit",n)):"undefined"!=typeof window&&(window.removeEventListener("beforeunload",n),window.removeEventListener("pagehide",n))}function r(){n(),process.exit(130)}function l(){n(),process.exit(143)}function a(){"undefined"!=typeof process?(i(process,"exit",n),i(process,"SIGINT",r),i(process,"SIGTERM",l)):"undefined"!=typeof window&&(window.addEventListener("beforeunload",n),window.addEventListener("pagehide",n))}class h{split;constructor(t){this.split="string"==typeof t?s(t):[...t]}get fullPath(){return 0===this.split.length?this.separator:this.split.join(this.separator)}createWriteStream(t){if("object"==typeof this.fs&&"createWriteStream"in this.fs&&"function"==typeof this.fs.createWriteStream)return this.fs.createWriteStream(this.split.join("/"),t);throw new Error("File system does not support createWriteStream")}createReadStream(t){if("object"==typeof this.fs&&"createReadStream"in this.fs&&"function"==typeof this.fs.createReadStream)return this.fs.createReadStream(this.split.join("/"),t);throw new Error("File system does not support createReadStream")}createAppendStream(t){if("object"==typeof this.fs&&"createWriteStream"in this.fs&&"function"==typeof this.fs.createWriteStream)return this.fs.createWriteStream(this.split.join("/"),{flags:"a",encoding:t});throw new Error("File system does not support createAppendStream")}createInputStream(t){if("object"==typeof this.fs&&"createReadStream"in this.fs&&"function"==typeof this.fs.createReadStream)return this.fs.createReadStream(this.split.join("/"),{flags:"r",encoding:t});throw new Error("File system does not support createInputStream")}}async function u(t){try{return t().then(()=>!0).catch(()=>!1)}catch(t){return!1}}async function f(t){try{return t().then(t=>t).catch(()=>null)}catch(t){return null}}class c extends h{static fs;static createTempFile(t,s="kfile-temp",e=".tmp"){if(!("mkdTemp"in c.fs))throw new Error("mkdTemp is not available in the current FS.");const i=t?t.fullPath:".",n=this.fs.mkdtemp(`${i}/${s}-`);return new c(`${n}${e}`)}get fs(){return c.fs}canExecute(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.X_OK??1))}async setExecutable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?493:420))?this:null}canRead(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.R_OK??4))}async setReadable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?420:0))?this:null}canWrite(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.W_OK??2))}async setWritable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?420:292))?this:null}creationTime(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.birthtime).catch(()=>null))}async setCreationTime(t){return await u(()=>this.fs.utimes(this.fullPath,t,t))?this:null}async lastModified(){return await f(()=>this.fs.stat(this.fullPath).then(t=>t.mtime).catch(()=>null))}async setLastModified(t){return await u(()=>this.fs.utimes(this.fullPath,t,t))?this:null}exists(){return f(()=>this.fs.exists(this.fullPath))}lastAccess(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.atime).catch(()=>null))}get name(){return this.fullPath.split(this.separator).pop()||""}get nameWithoutExtension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?t:t.substring(0,s)}get extension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?"":t.substring(s+1)}get parent(){return 0===this.split.length?null:new c(this.split.slice(0,-1))}get uri(){return`file://${this.fullPath}`}get separator(){return"sep"in this.fs&&"string"==typeof this.fs.sep?this.fs.sep:"/"}isDirectory(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.isDirectory()).catch(()=>null))}isFile(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.isFile()).catch(()=>null))}get isHidden(){return this.name.startsWith(".")||this.fullPath.split(this.separator).some(t=>t.startsWith("."))}isSymbolicLink(){return f(()=>this.fs.lstat(this.fullPath).then(t=>t.isSymbolicLink()).catch(()=>null))}size(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.size).catch(()=>null))}async sizeKB(){const t=await this.size();return null!==t?t/1024:null}async sizeMB(){const t=await this.size();return null!==t?t/1048576:null}async sizeGB(){const t=await this.size();return null!==t?t/1073741824:null}to(...t){return new c(this.fullPath+"/"+t.join("/"))}contains(t){if(t.split.length<=this.split.length)return!1;for(let s=0;s<this.split.length;s++)if(this.split[s]!==t.split[s])return!1;return!0}async createFile(){return await this.exists()?await this.isFile()?this:null:await this.write("")?this:null}async delete(t,s=t){if(t){if("rmSync"in this.fs)return await u(()=>this.fs.rm(this.fullPath,{recursive:!0,force:s}))?this:null;if("rmdirSync"in this.fs)return await u(()=>this.fs.rmdir(this.fullPath,{recursive:!0}))?this:null;let t=!1;for(const s of await this.listFiles()||[])await s.delete(!0)||(t=!0);if(t)return null}return await u(()=>this.fs.unlink(this.fullPath))?this:null}deleteOnExit(t){e.set(this.fullPath,t),a()}async clear(t){if(t){const t=await this.listFiles();if(null===t)return null;let s=!1;for(const e of t||[])await e.delete(!0)||(s=!0);return s?null:this}return await this.write(""),null}async listFiles(){if(!this.isDirectory)return null;const t=await f(()=>this.fs.readdir(this.fullPath));return t?t.map(t=>new c(`${this.fullPath}/${t}`)):null}listFilenames(){return f(()=>this.fs.readdir(this.fullPath))}async mkdir(t=!1){return await u(()=>this.fs.mkdir(this.fullPath,{recursive:t}))?this:null}async mkdirs(){return await this.mkdir(!0)?this:null}async renameTo(t,s,e){return this.fullPath===t.fullPath?this:!t.exists||s||await t.delete(e)?(e&&await(this.parent?.mkdirs()),await u(()=>this.fs.rename(this.fullPath,t.fullPath))?this:null):null}async copyTo(t,s,e){if(this.fullPath===t.fullPath)return this;if(!this.exists)return null;if(t.exists&&!s&&!await t.delete(e))return null;if(this.isFile){const s=await this.read();return null===s?null:await t.write(s)?this:null}if(!await t.mkdir(e))return null;const i=await this.listFiles();if(null===i)return null;let n=!1;for(const r of i){const i=t.to(r.name);await r.copyTo(i,s,e)||(n=!0)}return n?null:this}async*walk(){if(this.isDirectory){yield this;for(const t of await this.listFiles()||[])yield*t.walk()}else yield this}read(t){return f(()=>this.fs.readFile(this.fullPath,t))}async readLines(t="utf8"){const s=await this.read(t);return"string"==typeof s?s.split(/\r?\n/):null}async readJSON(){const t=await this.read("utf8");if("string"!=typeof t)return null;try{return JSON.parse(t)}catch(t){return null}}async readlink(){if(!this.isSymbolicLink)return null;const t=await f(()=>this.fs.readlink(this.fullPath));return t?new c(t):null}async write(t,s){return null!==s&&"object"==typeof s&&"write"in s&&"function"==typeof s.write&&(t=s.write()),await u(()=>this.fs.writeFile(this.fullPath,t,s))?this:null}async writeJSON(t){return await u(()=>this.write(JSON.stringify(t,null,2)))?this:null}async append(t,s){return await u(()=>this.fs.appendFile(this.fullPath,t,s))?this:null}get sync(){return new d(this.split)}}function o(t){try{return t(),!0}catch(t){return!1}}function p(t){try{return t()}catch(t){return null}}class d extends h{static fs;static createTempFile(t,s="kfile-temp",e=".tmp"){if(!("mkdTempSync"in d.fs))throw new Error("mkdTempSync is not available in the current FS.");const i=t?t.fullPath:".",n=this.fs.mkdtempSync(`${i}/${s}-`);return new d(`${n}${e}`)}get fs(){return d.fs}get canExecute(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.X_OK??1))}set canExecute(t){o(()=>this.fs.chmodSync(this.fullPath,t?493:420))}get canRead(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.R_OK??4))}set canRead(t){o(()=>this.fs.chmodSync(this.fullPath,t?420:0))}get canWrite(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.W_OK??2))}set canWrite(t){o(()=>this.fs.chmodSync(this.fullPath,t?420:292))}get creationTime(){return p(()=>this.fs.statSync(this.fullPath).birthtime)}set creationTime(t){o(()=>this.fs.utimesSync(this.fullPath,t,t))}get lastModified(){return p(()=>this.fs.statSync(this.fullPath).mtime)}set lastModified(t){o(()=>this.fs.utimesSync(this.fullPath,t,t))}get exists(){return p(()=>this.fs.existsSync(this.fullPath))}get lastAccess(){return p(()=>this.fs.statSync(this.fullPath).atime)}get name(){return this.fullPath.split(this.separator).pop()||""}get nameWithoutExtension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?t:t.substring(0,s)}get extension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?"":t.substring(s+1)}get parent(){return 0===this.split.length?null:new d(this.split.slice(0,-1))}get uri(){return`file://${this.fullPath}`}get separator(){return"sep"in this.fs&&"string"==typeof this.fs.sep?this.fs.sep:"/"}get isDirectory(){return p(()=>this.fs.statSync(this.fullPath).isDirectory())}get isFile(){return p(()=>this.fs.statSync(this.fullPath).isFile())}get isHidden(){return this.name.startsWith(".")||this.fullPath.split(this.separator).some(t=>t.startsWith("."))}get isSymbolicLink(){return p(()=>this.fs.lstatSync(this.fullPath).isSymbolicLink())}get size(){return p(()=>this.fs.statSync(this.fullPath).size)}get sizeKB(){const t=this.size;return null!==t?t/1024:null}get sizeMB(){const t=this.size;return null!==t?t/1048576:null}get sizeGB(){const t=this.size;return null!==t?t/1073741824:null}to(...t){return new d(this.fullPath+"/"+t.join("/"))}contains(t){if(t.split.length<=this.split.length)return!1;for(let s=0;s<this.split.length;s++)if(this.split[s]!==t.split[s])return!1;return!0}createFile(){return this.exists?this.isFile?this:null:this.write("")?this:null}delete(t,s=t){if(t){if("rmSync"in this.fs)return o(()=>this.fs.rmSync(this.fullPath,{recursive:!0,force:s}))?this:null;if("rmdirSync"in this.fs)return o(()=>this.fs.rmdirSync(this.fullPath,{recursive:!0}))?this:null;let t=!1;for(const s of this.listFiles()||[])s.delete(!0)||(t=!0);if(t)return null}return o(()=>this.fs.unlinkSync(this.fullPath))?this:null}deleteOnExit(t){e.set(this.fullPath,t),a()}clear(t){if(t){const t=this.listFiles();if(null===t)return null;let s=!1;for(const e of t||[])e.delete(!0)||(s=!0);return s?null:this}return this.write(""),null}listFiles(){if(!this.isDirectory)return null;const t=p(()=>this.fs.readdirSync(this.fullPath));return t?t.map(t=>new d(`${this.fullPath}/${t}`)):null}listFilenames(){return p(()=>this.fs.readdirSync(this.fullPath))}mkdir(t=!1){return o(()=>this.fs.mkdirSync(this.fullPath,{recursive:t}))?this:null}mkdirs(){return this.mkdir(!0)?this:null}renameTo(t,s,e){return this.fullPath===t.fullPath?this:!t.exists||s||t.delete(e)?(e&&this.parent?.mkdirs(),o(()=>this.fs.renameSync(this.fullPath,t.fullPath))?this:null):null}copyTo(t,s,e){if(this.fullPath===t.fullPath)return this;if(!this.exists)return null;if(t.exists&&!s&&!t.delete(e))return null;if(this.isFile){const s=this.read();return null===s?null:t.write(s)?this:null}if(!t.mkdir(e))return null;const i=this.listFiles();if(null===i)return null;let n=!1;for(const r of i){const i=t.to(r.name);r.copyTo(i,s,e)||(n=!0)}return n?null:this}*walk(){if(this.isDirectory){yield this;for(const t of this.listFiles()||[])yield*t.walk()}else yield this}read(t){return p(()=>this.fs.readFileSync(this.fullPath,t))}readLines(t="utf8"){const s=this.read(t);return"string"==typeof s?s.split(/\r?\n/):null}readJSON(){const t=this.read("utf8");if("string"!=typeof t)return null;try{return JSON.parse(t)}catch(t){return null}}readlink(){if(!this.isSymbolicLink)return null;const t=p(()=>this.fs.readlinkSync(this.fullPath));return t?new d(t):null}write(t,s){return null!==s&&"object"==typeof s&&"write"in s&&"function"==typeof s.write&&(t=s.write()),o(()=>this.fs.writeFileSync(this.fullPath,t,s))?this:null}writeJSON(t){return o(()=>this.write(JSON.stringify(t,null,2)))?this:null}append(t,s){return o(()=>this.fs.appendFileSync(this.fullPath,t,s))?this:null}get async(){return new c(this.split)}}function y(t){d.fs=t,c.fs=t.promises}function m(t){return new d(t)}function w(t){return new c(t)}if("undefined"!=typeof process)try{y(await import("fs"))}catch{}export{d as File,c as FileAsync,d as FileSync,w as fileAsync,m as fileSync,y as initFS};
|
|
1
|
+
let t=[];function s(s,e=t){s.startsWith("/")?(e=[],s=s.slice(1)):e=[...e];const i=s.split("/");for(const t of i)".."===t?e.pop():"."!==t&&""!==t&&e.push(t);return e}"undefined"!=typeof process&&"cwd"in process&&"function"==typeof process.cwd&&(t=s(process.cwd()));const e=new Map;function i(t,s,e){const i=t.listeners(s);t.removeAllListeners(s);for(const n of i)n!==e&&t.on(s,n);t.on(s,e)}function n(){for(const[t,s]of e.entries())new d(t).delete(s);e.clear(),"undefined"!=typeof process?(process.off("SIGINT",r),process.off("SIGTERM",l),process.off("exit",n)):"undefined"!=typeof window&&(window.removeEventListener("beforeunload",n),window.removeEventListener("pagehide",n))}function r(){n(),process.exit(130)}function l(){n(),process.exit(143)}function a(){"undefined"!=typeof process?(i(process,"exit",n),i(process,"SIGINT",r),i(process,"SIGTERM",l)):"undefined"!=typeof window&&(window.addEventListener("beforeunload",n),window.addEventListener("pagehide",n))}class h{split;constructor(t){this.split="string"==typeof t?s(t):[...t]}get fullPath(){return 0===this.split.length?this.separator:this.split.join(this.separator)}createWriteStream(t){if("object"==typeof this.fs&&"createWriteStream"in this.fs&&"function"==typeof this.fs.createWriteStream)return this.fs.createWriteStream(this.split.join("/"),t);throw new Error("File system does not support createWriteStream")}createReadStream(t){if("object"==typeof this.fs&&"createReadStream"in this.fs&&"function"==typeof this.fs.createReadStream)return this.fs.createReadStream(this.split.join("/"),t);throw new Error("File system does not support createReadStream")}createAppendStream(t){if("object"==typeof this.fs&&"createWriteStream"in this.fs&&"function"==typeof this.fs.createWriteStream)return this.fs.createWriteStream(this.split.join("/"),{flags:"a",encoding:t});throw new Error("File system does not support createAppendStream")}createInputStream(t){if("object"==typeof this.fs&&"createReadStream"in this.fs&&"function"==typeof this.fs.createReadStream)return this.fs.createReadStream(this.split.join("/"),{flags:"r",encoding:t});throw new Error("File system does not support createInputStream")}}async function u(t){try{return t().then(()=>!0).catch(()=>!1)}catch(t){return!1}}async function f(t){try{return t().then(t=>t).catch(()=>null)}catch(t){return null}}class c extends h{static fs;static createTempFile(t,s="ktfile-temp",e=".tmp"){if(!("mkdTemp"in c.fs))throw new Error("mkdTemp is not available in the current FS.");const i=t?t.fullPath:".",n=this.fs.mkdtemp(`${i}/${s}-`);return new c(`${n}${e}`)}get fs(){return c.fs}canExecute(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.X_OK??1))}async setExecutable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?493:420))?this:null}canRead(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.R_OK??4))}async setReadable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?420:0))?this:null}canWrite(){return u(()=>this.fs.access(this.fullPath,this.fs?.constants?.W_OK??2))}async setWritable(t=!0){return await u(()=>this.fs.chmod(this.fullPath,t?420:292))?this:null}creationTime(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.birthtime).catch(()=>null))}async setCreationTime(t){return await u(()=>this.fs.utimes(this.fullPath,t,t))?this:null}async lastModified(){return await f(()=>this.fs.stat(this.fullPath).then(t=>t.mtime).catch(()=>null))}async setLastModified(t){return await u(()=>this.fs.utimes(this.fullPath,t,t))?this:null}exists(){return f(()=>this.fs.exists(this.fullPath))}lastAccess(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.atime).catch(()=>null))}get name(){return this.fullPath.split(this.separator).pop()||""}get nameWithoutExtension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?t:t.substring(0,s)}get extension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?"":t.substring(s+1)}get parent(){return 0===this.split.length?null:new c(this.split.slice(0,-1))}get uri(){return`file://${this.fullPath}`}get separator(){return"sep"in this.fs&&"string"==typeof this.fs.sep?this.fs.sep:"/"}isDirectory(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.isDirectory()).catch(()=>null))}isFile(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.isFile()).catch(()=>null))}get isHidden(){return this.name.startsWith(".")||this.fullPath.split(this.separator).some(t=>t.startsWith("."))}isSymbolicLink(){return f(()=>this.fs.lstat(this.fullPath).then(t=>t.isSymbolicLink()).catch(()=>null))}size(){return f(()=>this.fs.stat(this.fullPath).then(t=>t.size).catch(()=>null))}async sizeKB(){const t=await this.size();return null!==t?t/1024:null}async sizeMB(){const t=await this.size();return null!==t?t/1048576:null}async sizeGB(){const t=await this.size();return null!==t?t/1073741824:null}to(...t){return new c(this.fullPath+"/"+t.join("/"))}contains(t){if(t.split.length<=this.split.length)return!1;for(let s=0;s<this.split.length;s++)if(this.split[s]!==t.split[s])return!1;return!0}async createFile(){return await this.exists()?await this.isFile()?this:null:await this.write("")?this:null}async delete(t,s=t){if(t){if("rmSync"in this.fs)return await u(()=>this.fs.rm(this.fullPath,{recursive:!0,force:s}))?this:null;if("rmdirSync"in this.fs)return await u(()=>this.fs.rmdir(this.fullPath,{recursive:!0}))?this:null;let t=!1;for(const s of await this.listFiles()||[])await s.delete(!0)||(t=!0);if(t)return null}return await u(()=>this.fs.unlink(this.fullPath))?this:null}deleteOnExit(t){e.set(this.fullPath,t),a()}async clear(t){if(t){const t=await this.listFiles();if(null===t)return null;let s=!1;for(const e of t||[])await e.delete(!0)||(s=!0);return s?null:this}return await this.write(""),null}async listFiles(){if(!this.isDirectory)return null;const t=await f(()=>this.fs.readdir(this.fullPath));return t?t.map(t=>new c(`${this.fullPath}/${t}`)):null}listFilenames(){return f(()=>this.fs.readdir(this.fullPath))}async mkdir(t=!1){return await u(()=>this.fs.mkdir(this.fullPath,{recursive:t}))?this:null}async mkdirs(){return await this.mkdir(!0)?this:null}async renameTo(t,s,e){return this.fullPath===t.fullPath?this:!t.exists||s||await t.delete(e)?(e&&await(this.parent?.mkdirs()),await u(()=>this.fs.rename(this.fullPath,t.fullPath))?this:null):null}async copyTo(t,s,e){if(this.fullPath===t.fullPath)return this;if(!this.exists)return null;if(t.exists&&!s&&!await t.delete(e))return null;if(this.isFile){const s=await this.read();return null===s?null:await t.write(s)?this:null}if(!await t.mkdir(e))return null;const i=await this.listFiles();if(null===i)return null;let n=!1;for(const r of i){const i=t.to(r.name);await r.copyTo(i,s,e)||(n=!0)}return n?null:this}async*walk(){if(this.isDirectory){yield this;for(const t of await this.listFiles()||[])yield*t.walk()}else yield this}read(t){return f(()=>this.fs.readFile(this.fullPath,t))}async readLines(t="utf8"){const s=await this.read(t);return"string"==typeof s?s.split(/\r?\n/):null}async readJSON(){const t=await this.read("utf8");if("string"!=typeof t)return null;try{return JSON.parse(t)}catch(t){return null}}async readlink(){if(!this.isSymbolicLink)return null;const t=await f(()=>this.fs.readlink(this.fullPath));return t?new c(t):null}async write(t,s){return null!==s&&"object"==typeof s&&"write"in s&&"function"==typeof s.write&&(t=s.write()),await u(()=>this.fs.writeFile(this.fullPath,t,s))?this:null}async writeJSON(t){return await u(()=>this.write(JSON.stringify(t,null,2)))?this:null}async append(t,s){return await u(()=>this.fs.appendFile(this.fullPath,t,s))?this:null}get sync(){return new d(this.split)}}function o(t){try{return t(),!0}catch(t){return!1}}function p(t){try{return t()}catch(t){return null}}class d extends h{static fs;static createTempFile(t,s="ktfile-temp",e=".tmp"){if(!("mkdTempSync"in d.fs))throw new Error("mkdTempSync is not available in the current FS.");const i=t?t.fullPath:".",n=this.fs.mkdtempSync(`${i}/${s}-`);return new d(`${n}${e}`)}get fs(){return d.fs}get canExecute(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.X_OK??1))}set canExecute(t){o(()=>this.fs.chmodSync(this.fullPath,t?493:420))}get canRead(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.R_OK??4))}set canRead(t){o(()=>this.fs.chmodSync(this.fullPath,t?420:0))}get canWrite(){return o(()=>this.fs.accessSync(this.fullPath,this.fs?.constants?.W_OK??2))}set canWrite(t){o(()=>this.fs.chmodSync(this.fullPath,t?420:292))}get creationTime(){return p(()=>this.fs.statSync(this.fullPath).birthtime)}set creationTime(t){o(()=>this.fs.utimesSync(this.fullPath,t,t))}get lastModified(){return p(()=>this.fs.statSync(this.fullPath).mtime)}set lastModified(t){o(()=>this.fs.utimesSync(this.fullPath,t,t))}get exists(){return p(()=>this.fs.existsSync(this.fullPath))}get lastAccess(){return p(()=>this.fs.statSync(this.fullPath).atime)}get name(){return this.fullPath.split(this.separator).pop()||""}get nameWithoutExtension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?t:t.substring(0,s)}get extension(){const t=this.name,s=t.lastIndexOf(".");return-1===s?"":t.substring(s+1)}get parent(){return 0===this.split.length?null:new d(this.split.slice(0,-1))}get uri(){return`file://${this.fullPath}`}get separator(){return"sep"in this.fs&&"string"==typeof this.fs.sep?this.fs.sep:"/"}get isDirectory(){return p(()=>this.fs.statSync(this.fullPath).isDirectory())}get isFile(){return p(()=>this.fs.statSync(this.fullPath).isFile())}get isHidden(){return this.name.startsWith(".")||this.fullPath.split(this.separator).some(t=>t.startsWith("."))}get isSymbolicLink(){return p(()=>this.fs.lstatSync(this.fullPath).isSymbolicLink())}get size(){return p(()=>this.fs.statSync(this.fullPath).size)}get sizeKB(){const t=this.size;return null!==t?t/1024:null}get sizeMB(){const t=this.size;return null!==t?t/1048576:null}get sizeGB(){const t=this.size;return null!==t?t/1073741824:null}to(...t){return new d(this.fullPath+"/"+t.join("/"))}contains(t){if(t.split.length<=this.split.length)return!1;for(let s=0;s<this.split.length;s++)if(this.split[s]!==t.split[s])return!1;return!0}createFile(){return this.exists?this.isFile?this:null:this.write("")?this:null}delete(t,s=t){if(t){if("rmSync"in this.fs)return o(()=>this.fs.rmSync(this.fullPath,{recursive:!0,force:s}))?this:null;if("rmdirSync"in this.fs)return o(()=>this.fs.rmdirSync(this.fullPath,{recursive:!0}))?this:null;let t=!1;for(const s of this.listFiles()||[])s.delete(!0)||(t=!0);if(t)return null}return o(()=>this.fs.unlinkSync(this.fullPath))?this:null}deleteOnExit(t){e.set(this.fullPath,t),a()}clear(t){if(t){const t=this.listFiles();if(null===t)return null;let s=!1;for(const e of t||[])e.delete(!0)||(s=!0);return s?null:this}return this.write(""),null}listFiles(){if(!this.isDirectory)return null;const t=p(()=>this.fs.readdirSync(this.fullPath));return t?t.map(t=>new d(`${this.fullPath}/${t}`)):null}listFilenames(){return p(()=>this.fs.readdirSync(this.fullPath))}mkdir(t=!1){return o(()=>this.fs.mkdirSync(this.fullPath,{recursive:t}))?this:null}mkdirs(){return this.mkdir(!0)?this:null}renameTo(t,s,e){return this.fullPath===t.fullPath?this:!t.exists||s||t.delete(e)?(e&&this.parent?.mkdirs(),o(()=>this.fs.renameSync(this.fullPath,t.fullPath))?this:null):null}copyTo(t,s,e){if(this.fullPath===t.fullPath)return this;if(!this.exists)return null;if(t.exists&&!s&&!t.delete(e))return null;if(this.isFile){const s=this.read();return null===s?null:t.write(s)?this:null}if(!t.mkdir(e))return null;const i=this.listFiles();if(null===i)return null;let n=!1;for(const r of i){const i=t.to(r.name);r.copyTo(i,s,e)||(n=!0)}return n?null:this}*walk(){if(this.isDirectory){yield this;for(const t of this.listFiles()||[])yield*t.walk()}else yield this}read(t){return p(()=>this.fs.readFileSync(this.fullPath,t))}readLines(t="utf8"){const s=this.read(t);return"string"==typeof s?s.split(/\r?\n/):null}readJSON(){const t=this.read("utf8");if("string"!=typeof t)return null;try{return JSON.parse(t)}catch(t){return null}}readlink(){if(!this.isSymbolicLink)return null;const t=p(()=>this.fs.readlinkSync(this.fullPath));return t?new d(t):null}write(t,s){return null!==s&&"object"==typeof s&&"write"in s&&"function"==typeof s.write&&(t=s.write()),o(()=>this.fs.writeFileSync(this.fullPath,t,s))?this:null}writeJSON(t){return o(()=>this.write(JSON.stringify(t,null,2)))?this:null}append(t,s){return o(()=>this.fs.appendFileSync(this.fullPath,t,s))?this:null}get async(){return new c(this.split)}}function y(t){d.fs=t,c.fs=t.promises}function m(t){return new d(t)}function w(t){return new c(t)}if("undefined"!=typeof process)try{y(await import("fs"))}catch{}export{d as File,c as FileAsync,d as FileSync,w as fileAsync,m as fileSync,y as initFS};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ktfile",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Fluent, modern and chainable File API\n\n",
|
|
5
5
|
"main": "index.min.js",
|
|
6
|
-
"types": "types/
|
|
6
|
+
"types": "types/ktfile.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"test": "tsx tests/test.ts",
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"repository": {
|
|
41
41
|
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/OguzhanUmutlu/
|
|
42
|
+
"url": "git+https://github.com/OguzhanUmutlu/ktfile.git"
|
|
43
43
|
}
|
|
44
44
|
}
|
|
File without changes
|