@lova/mem-vfs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -0
- package/dist/core/vfs-directory.d.ts +35 -0
- package/dist/core/vfs-directory.d.ts.map +1 -0
- package/dist/core/vfs-directory.js +78 -0
- package/dist/core/vfs-directory.js.map +1 -0
- package/dist/core/vfs-file.d.ts +25 -0
- package/dist/core/vfs-file.d.ts.map +1 -0
- package/dist/core/vfs-file.js +60 -0
- package/dist/core/vfs-file.js.map +1 -0
- package/dist/core/vfs-node.d.ts +42 -0
- package/dist/core/vfs-node.d.ts.map +1 -0
- package/dist/core/vfs-node.js +69 -0
- package/dist/core/vfs-node.js.map +1 -0
- package/dist/core/vfs-symlink.d.ts +21 -0
- package/dist/core/vfs-symlink.d.ts.map +1 -0
- package/dist/core/vfs-symlink.js +41 -0
- package/dist/core/vfs-symlink.js.map +1 -0
- package/dist/core/vfs.d.ts +107 -0
- package/dist/core/vfs.d.ts.map +1 -0
- package/dist/core/vfs.js +775 -0
- package/dist/core/vfs.js.map +1 -0
- package/dist/errors/file-system-errors.d.ts +79 -0
- package/dist/errors/file-system-errors.d.ts.map +1 -0
- package/dist/errors/file-system-errors.js +127 -0
- package/dist/errors/file-system-errors.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/path/path-normalizer.d.ts +23 -0
- package/dist/path/path-normalizer.d.ts.map +1 -0
- package/dist/path/path-normalizer.js +159 -0
- package/dist/path/path-normalizer.js.map +1 -0
- package/dist/path/path-resolver.d.ts +31 -0
- package/dist/path/path-resolver.d.ts.map +1 -0
- package/dist/path/path-resolver.js +68 -0
- package/dist/path/path-resolver.js.map +1 -0
- package/dist/path/path-validator.d.ts +12 -0
- package/dist/path/path-validator.d.ts.map +1 -0
- package/dist/path/path-validator.js +87 -0
- package/dist/path/path-validator.js.map +1 -0
- package/dist/types/index.d.ts +171 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +29 -0
- package/dist/types/index.js.map +1 -0
- package/dist/watcher/debouncer.d.ts +31 -0
- package/dist/watcher/debouncer.d.ts.map +1 -0
- package/dist/watcher/debouncer.js +66 -0
- package/dist/watcher/debouncer.js.map +1 -0
- package/dist/watcher/watcher-events.d.ts +30 -0
- package/dist/watcher/watcher-events.d.ts.map +1 -0
- package/dist/watcher/watcher-events.js +52 -0
- package/dist/watcher/watcher-events.js.map +1 -0
- package/dist/watcher/watcher.d.ts +57 -0
- package/dist/watcher/watcher.d.ts.map +1 -0
- package/dist/watcher/watcher.js +194 -0
- package/dist/watcher/watcher.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# mem-vfs
|
|
2
|
+
|
|
3
|
+
High-performance in-memory virtual file system for Node.js with symlink support, file watching, and snapshot/rollback capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Complete File System API**: readFile, writeFile, appendFile, deleteFile, copyFile, moveFile
|
|
8
|
+
- **Directory Operations**: createDirectory, readDirectory, deleteDirectory (with recursive option)
|
|
9
|
+
- **Symbolic Links**: createSymlink, readSymlink, isSymlink with loop detection
|
|
10
|
+
- **Glob Pattern Matching**: Full glob support with maxDepth, followSymlinks, ignore patterns
|
|
11
|
+
- **Snapshots & Rollback**: Create snapshots, restore state, compute diffs
|
|
12
|
+
- **JSON Import/Export**: Load from and export to JSON structure
|
|
13
|
+
- **Path Utilities**: normalize, resolve, relative, join, dirname, basename
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install mem-vfs
|
|
19
|
+
# or
|
|
20
|
+
pnpm add mem-vfs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createVFS } from 'mem-vfs';
|
|
27
|
+
|
|
28
|
+
const vfs = createVFS();
|
|
29
|
+
|
|
30
|
+
// Write and read files
|
|
31
|
+
await vfs.writeFile('/src/index.ts', 'export const hello = "world";');
|
|
32
|
+
const content = await vfs.readFile('/src/index.ts', 'utf-8');
|
|
33
|
+
|
|
34
|
+
// Create directories
|
|
35
|
+
await vfs.createDirectory('/src/utils', true);
|
|
36
|
+
|
|
37
|
+
// Glob search
|
|
38
|
+
const tsFiles = await vfs.glob('**/*.ts');
|
|
39
|
+
|
|
40
|
+
// Symbolic links
|
|
41
|
+
await vfs.createSymlink('/src', '/link-to-src');
|
|
42
|
+
|
|
43
|
+
// Snapshots
|
|
44
|
+
const snapshotId = vfs.createSnapshot('before-refactor');
|
|
45
|
+
// ... make changes ...
|
|
46
|
+
vfs.restoreSnapshot(snapshotId);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API Reference
|
|
50
|
+
|
|
51
|
+
### File Operations
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Read file (returns string with encoding, Buffer without)
|
|
55
|
+
await vfs.readFile(path: string, encoding?: BufferEncoding): Promise<string | Buffer>
|
|
56
|
+
|
|
57
|
+
// Write file (auto-creates parent directories)
|
|
58
|
+
await vfs.writeFile(path: string, content: string | Buffer): Promise<void>
|
|
59
|
+
|
|
60
|
+
// Append to file
|
|
61
|
+
await vfs.appendFile(path: string, content: string | Buffer): Promise<void>
|
|
62
|
+
|
|
63
|
+
// Delete file
|
|
64
|
+
await vfs.deleteFile(path: string): Promise<void>
|
|
65
|
+
|
|
66
|
+
// Copy file
|
|
67
|
+
await vfs.copyFile(src: string, dest: string): Promise<void>
|
|
68
|
+
|
|
69
|
+
// Move file
|
|
70
|
+
await vfs.moveFile(src: string, dest: string): Promise<void>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Directory Operations
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Create directory (recursive option creates parent directories)
|
|
77
|
+
await vfs.createDirectory(path: string, recursive?: boolean): Promise<void>
|
|
78
|
+
|
|
79
|
+
// Read directory contents
|
|
80
|
+
await vfs.readDirectory(path: string): Promise<DirectoryEntry[]>
|
|
81
|
+
|
|
82
|
+
// Delete directory (recursive option deletes contents)
|
|
83
|
+
await vfs.deleteDirectory(path: string, recursive?: boolean): Promise<void>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Status Queries
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
await vfs.exists(path: string): Promise<boolean>
|
|
90
|
+
await vfs.isFile(path: string): Promise<boolean>
|
|
91
|
+
await vfs.isDirectory(path: string): Promise<boolean>
|
|
92
|
+
await vfs.isSymlink(path: string): Promise<boolean>
|
|
93
|
+
await vfs.getStats(path: string): Promise<FileStats>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Symbolic Links
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// Create symlink
|
|
100
|
+
await vfs.createSymlink(target: string, linkPath: string): Promise<void>
|
|
101
|
+
|
|
102
|
+
// Read symlink target
|
|
103
|
+
await vfs.readSymlink(linkPath: string): Promise<string>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Glob
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const files = await vfs.glob(pattern: string, options?: GlobOptions): Promise<string[]>
|
|
110
|
+
|
|
111
|
+
// Options:
|
|
112
|
+
interface GlobOptions {
|
|
113
|
+
cwd?: string; // Working directory
|
|
114
|
+
ignore?: string[]; // Ignore patterns
|
|
115
|
+
dot?: boolean; // Include dotfiles
|
|
116
|
+
absolute?: boolean; // Return absolute paths
|
|
117
|
+
onlyFiles?: boolean; // Only return files
|
|
118
|
+
onlyDirectories?: boolean; // Only return directories
|
|
119
|
+
followSymlinks?: boolean; // Follow symbolic links
|
|
120
|
+
maxDepth?: number; // Maximum traversal depth
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Snapshots
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Create snapshot
|
|
128
|
+
const id = vfs.createSnapshot(name?: string): SnapshotId
|
|
129
|
+
|
|
130
|
+
// Restore snapshot
|
|
131
|
+
vfs.restoreSnapshot(id: SnapshotId): void
|
|
132
|
+
|
|
133
|
+
// Get snapshot info
|
|
134
|
+
vfs.getSnapshotInfo(id: SnapshotId): SnapshotInfo | undefined
|
|
135
|
+
|
|
136
|
+
// List all snapshots
|
|
137
|
+
vfs.listSnapshots(): SnapshotInfo[]
|
|
138
|
+
|
|
139
|
+
// Delete snapshot
|
|
140
|
+
vfs.deleteSnapshot(id: SnapshotId): boolean
|
|
141
|
+
|
|
142
|
+
// Compute diff between snapshots
|
|
143
|
+
vfs.diff(fromId?: SnapshotId, toId?: SnapshotId): FileDiff[]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### JSON Import/Export
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Load from JSON structure
|
|
150
|
+
await vfs.fromJSON({
|
|
151
|
+
'src': {
|
|
152
|
+
'index.ts': 'export {}',
|
|
153
|
+
'utils': {
|
|
154
|
+
'helper.ts': 'export function help() {}'
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
'README.md': '# Project'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Export to JSON
|
|
161
|
+
const json = vfs.toJSON(): DirectoryJSON
|
|
162
|
+
|
|
163
|
+
// Reset file system
|
|
164
|
+
vfs.reset(): void
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Configuration
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const vfs = createVFS({
|
|
171
|
+
caseSensitive: true, // Case-sensitive paths (default: true)
|
|
172
|
+
defaultFileMode: 0o644, // Default file permissions
|
|
173
|
+
defaultDirectoryMode: 0o755, // Default directory permissions
|
|
174
|
+
maxSymlinkDepth: 40, // Maximum symlink resolution depth
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Error Handling
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import {
|
|
182
|
+
FileNotFoundError,
|
|
183
|
+
DirectoryNotFoundError,
|
|
184
|
+
DirectoryNotEmptyError,
|
|
185
|
+
NotAFileError,
|
|
186
|
+
NotADirectoryError,
|
|
187
|
+
SymlinkLoopError,
|
|
188
|
+
InvalidPathError
|
|
189
|
+
} from 'mem-vfs';
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
await vfs.readFile('/nonexistent');
|
|
193
|
+
} catch (error) {
|
|
194
|
+
if (error instanceof FileNotFoundError) {
|
|
195
|
+
console.log('File not found:', error.path);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Path Utilities
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import {
|
|
204
|
+
normalizePath,
|
|
205
|
+
dirname,
|
|
206
|
+
basename,
|
|
207
|
+
extname,
|
|
208
|
+
join,
|
|
209
|
+
resolve,
|
|
210
|
+
relative,
|
|
211
|
+
isAbsolute
|
|
212
|
+
} from 'mem-vfs';
|
|
213
|
+
|
|
214
|
+
normalizePath('/a/b/../c/./d') // '/a/c/d'
|
|
215
|
+
dirname('/path/to/file.txt') // '/path/to'
|
|
216
|
+
basename('/path/to/file.txt') // 'file.txt'
|
|
217
|
+
join('/a', 'b', 'c') // '/a/b/c'
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 目錄節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** VFS 目錄節點 */
|
|
7
|
+
export declare class VFSDirectory extends VFSNode {
|
|
8
|
+
readonly type = VFSNodeType.Directory;
|
|
9
|
+
/** 子節點 */
|
|
10
|
+
private readonly children;
|
|
11
|
+
constructor(name: string, mode?: number);
|
|
12
|
+
/** 取得大小(子節點數量 * 4096,模擬目錄大小) */
|
|
13
|
+
get size(): number;
|
|
14
|
+
/** 取得子節點數量 */
|
|
15
|
+
get childCount(): number;
|
|
16
|
+
/** 是否為空目錄 */
|
|
17
|
+
get isEmpty(): boolean;
|
|
18
|
+
/** 取得子節點 */
|
|
19
|
+
getChild(name: string): VFSNode | undefined;
|
|
20
|
+
/** 檢查子節點是否存在 */
|
|
21
|
+
hasChild(name: string): boolean;
|
|
22
|
+
/** 新增子節點 */
|
|
23
|
+
addChild(node: VFSNode): void;
|
|
24
|
+
/** 移除子節點 */
|
|
25
|
+
removeChild(name: string): boolean;
|
|
26
|
+
/** 取得所有子節點名稱 */
|
|
27
|
+
getChildNames(): string[];
|
|
28
|
+
/** 取得所有子節點 */
|
|
29
|
+
getChildren(): VFSNode[];
|
|
30
|
+
/** 迭代子節點 */
|
|
31
|
+
entries(): IterableIterator<[string, VFSNode]>;
|
|
32
|
+
/** 深拷貝 */
|
|
33
|
+
clone(): VFSDirectory;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=vfs-directory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-directory.d.ts","sourceRoot":"","sources":["../../src/core/vfs-directory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,eAAe;AACf,qBAAa,YAAa,SAAQ,OAAO;IACvC,QAAQ,CAAC,IAAI,yBAAyB;IAEtC,UAAU;IACV,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;gBAEhD,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAA+B;IAI/D,gCAAgC;IAChC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,cAAc;IACd,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,aAAa;IACb,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,YAAY;IACZ,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAK3C,gBAAgB;IAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI/B,YAAY;IACZ,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAK7B,YAAY;IACZ,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAUlC,gBAAgB;IAChB,aAAa,IAAI,MAAM,EAAE;IAIzB,cAAc;IACd,WAAW,IAAI,OAAO,EAAE;IAKxB,YAAY;IACX,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAI/C,UAAU;IACV,KAAK,IAAI,YAAY;CAetB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 目錄節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** 預設目錄模式 */
|
|
7
|
+
const DEFAULT_DIRECTORY_MODE = 0o755;
|
|
8
|
+
/** VFS 目錄節點 */
|
|
9
|
+
export class VFSDirectory extends VFSNode {
|
|
10
|
+
type = VFSNodeType.Directory;
|
|
11
|
+
/** 子節點 */
|
|
12
|
+
children = new Map();
|
|
13
|
+
constructor(name, mode = DEFAULT_DIRECTORY_MODE) {
|
|
14
|
+
super(name, mode);
|
|
15
|
+
}
|
|
16
|
+
/** 取得大小(子節點數量 * 4096,模擬目錄大小) */
|
|
17
|
+
get size() {
|
|
18
|
+
return 4096;
|
|
19
|
+
}
|
|
20
|
+
/** 取得子節點數量 */
|
|
21
|
+
get childCount() {
|
|
22
|
+
return this.children.size;
|
|
23
|
+
}
|
|
24
|
+
/** 是否為空目錄 */
|
|
25
|
+
get isEmpty() {
|
|
26
|
+
return this.children.size === 0;
|
|
27
|
+
}
|
|
28
|
+
/** 取得子節點 */
|
|
29
|
+
getChild(name) {
|
|
30
|
+
this.touch();
|
|
31
|
+
return this.children.get(name);
|
|
32
|
+
}
|
|
33
|
+
/** 檢查子節點是否存在 */
|
|
34
|
+
hasChild(name) {
|
|
35
|
+
return this.children.has(name);
|
|
36
|
+
}
|
|
37
|
+
/** 新增子節點 */
|
|
38
|
+
addChild(node) {
|
|
39
|
+
this.children.set(node.name, node);
|
|
40
|
+
this.markModified();
|
|
41
|
+
}
|
|
42
|
+
/** 移除子節點 */
|
|
43
|
+
removeChild(name) {
|
|
44
|
+
const result = this.children.delete(name);
|
|
45
|
+
if (result) {
|
|
46
|
+
this.markModified();
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/** 取得所有子節點名稱 */
|
|
51
|
+
getChildNames() {
|
|
52
|
+
return Array.from(this.children.keys());
|
|
53
|
+
}
|
|
54
|
+
/** 取得所有子節點 */
|
|
55
|
+
getChildren() {
|
|
56
|
+
this.touch();
|
|
57
|
+
return Array.from(this.children.values());
|
|
58
|
+
}
|
|
59
|
+
/** 迭代子節點 */
|
|
60
|
+
*entries() {
|
|
61
|
+
yield* this.children.entries();
|
|
62
|
+
}
|
|
63
|
+
/** 深拷貝 */
|
|
64
|
+
clone() {
|
|
65
|
+
const cloned = new VFSDirectory(this.name, this.mode);
|
|
66
|
+
cloned.uid = this.uid;
|
|
67
|
+
cloned.gid = this.gid;
|
|
68
|
+
cloned.createdTime = new Date(this.createdTime);
|
|
69
|
+
cloned.modifiedTime = new Date(this.modifiedTime);
|
|
70
|
+
cloned.accessedTime = new Date(this.accessedTime);
|
|
71
|
+
// 深拷貝子節點
|
|
72
|
+
for (const [name, node] of this.children) {
|
|
73
|
+
cloned.children.set(name, node.clone());
|
|
74
|
+
}
|
|
75
|
+
return cloned;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=vfs-directory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-directory.js","sourceRoot":"","sources":["../../src/core/vfs-directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 檔案節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** VFS 檔案節點 */
|
|
7
|
+
export declare class VFSFile extends VFSNode {
|
|
8
|
+
readonly type = VFSNodeType.File;
|
|
9
|
+
/** 檔案內容 */
|
|
10
|
+
private content;
|
|
11
|
+
constructor(name: string, content?: string | Buffer, mode?: number);
|
|
12
|
+
/** 取得大小 */
|
|
13
|
+
get size(): number;
|
|
14
|
+
/** 讀取內容 */
|
|
15
|
+
read(encoding?: BufferEncoding): string | Buffer;
|
|
16
|
+
/** 寫入內容 */
|
|
17
|
+
write(data: string | Buffer): void;
|
|
18
|
+
/** 追加內容 */
|
|
19
|
+
append(data: string | Buffer): void;
|
|
20
|
+
/** 截斷內容 */
|
|
21
|
+
truncate(length?: number): void;
|
|
22
|
+
/** 深拷貝 */
|
|
23
|
+
clone(): VFSFile;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=vfs-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-file.d.ts","sourceRoot":"","sources":["../../src/core/vfs-file.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,eAAe;AACf,qBAAa,OAAQ,SAAQ,OAAO;IAClC,QAAQ,CAAC,IAAI,oBAAoB;IAEjC,WAAW;IACX,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,MAAM,GAAG,MAAwB,EAAE,IAAI,GAAE,MAA0B;IAKtG,WAAW;IACX,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,WAAW;IACX,IAAI,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,MAAM;IAUhD,WAAW;IACX,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKlC,WAAW;IACX,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMnC,WAAW;IACX,QAAQ,CAAC,MAAM,GAAE,MAAU,GAAG,IAAI;IASlC,UAAU;IACV,KAAK,IAAI,OAAO;CAUjB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 檔案節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** 預設檔案模式 */
|
|
7
|
+
const DEFAULT_FILE_MODE = 0o644;
|
|
8
|
+
/** VFS 檔案節點 */
|
|
9
|
+
export class VFSFile extends VFSNode {
|
|
10
|
+
type = VFSNodeType.File;
|
|
11
|
+
/** 檔案內容 */
|
|
12
|
+
content;
|
|
13
|
+
constructor(name, content = Buffer.alloc(0), mode = DEFAULT_FILE_MODE) {
|
|
14
|
+
super(name, mode);
|
|
15
|
+
this.content = typeof content === 'string' ? Buffer.from(content, 'utf-8') : content;
|
|
16
|
+
}
|
|
17
|
+
/** 取得大小 */
|
|
18
|
+
get size() {
|
|
19
|
+
return this.content.length;
|
|
20
|
+
}
|
|
21
|
+
/** 讀取內容 */
|
|
22
|
+
read(encoding) {
|
|
23
|
+
this.touch();
|
|
24
|
+
if (encoding) {
|
|
25
|
+
return this.content.toString(encoding);
|
|
26
|
+
}
|
|
27
|
+
return Buffer.from(this.content);
|
|
28
|
+
}
|
|
29
|
+
/** 寫入內容 */
|
|
30
|
+
write(data) {
|
|
31
|
+
this.content = typeof data === 'string' ? Buffer.from(data, 'utf-8') : Buffer.from(data);
|
|
32
|
+
this.markModified();
|
|
33
|
+
}
|
|
34
|
+
/** 追加內容 */
|
|
35
|
+
append(data) {
|
|
36
|
+
const appendBuffer = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
|
|
37
|
+
this.content = Buffer.concat([this.content, appendBuffer]);
|
|
38
|
+
this.markModified();
|
|
39
|
+
}
|
|
40
|
+
/** 截斷內容 */
|
|
41
|
+
truncate(length = 0) {
|
|
42
|
+
if (length >= this.content.length) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.content = this.content.subarray(0, length);
|
|
46
|
+
this.markModified();
|
|
47
|
+
}
|
|
48
|
+
/** 深拷貝 */
|
|
49
|
+
clone() {
|
|
50
|
+
const cloned = new VFSFile(this.name, Buffer.from(this.content), this.mode);
|
|
51
|
+
cloned.uid = this.uid;
|
|
52
|
+
cloned.gid = this.gid;
|
|
53
|
+
// 時間屬性需要重新賦值(因為 readonly 是在 constructor 設定的)
|
|
54
|
+
cloned.createdTime = new Date(this.createdTime);
|
|
55
|
+
cloned.modifiedTime = new Date(this.modifiedTime);
|
|
56
|
+
cloned.accessedTime = new Date(this.accessedTime);
|
|
57
|
+
return cloned;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=vfs-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-file.js","sourceRoot":"","sources":["../../src/core/vfs-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 節點基礎類別
|
|
3
|
+
*/
|
|
4
|
+
import type { FileStats } from '../types/index.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** VFS 節點基礎類別 */
|
|
7
|
+
export declare abstract class VFSNode {
|
|
8
|
+
/** 節點名稱 */
|
|
9
|
+
readonly name: string;
|
|
10
|
+
/** 節點類型 */
|
|
11
|
+
abstract readonly type: VFSNodeType;
|
|
12
|
+
/** 建立時間 */
|
|
13
|
+
readonly createdTime: Date;
|
|
14
|
+
/** 修改時間 */
|
|
15
|
+
modifiedTime: Date;
|
|
16
|
+
/** 存取時間 */
|
|
17
|
+
accessedTime: Date;
|
|
18
|
+
/** 檔案模式 */
|
|
19
|
+
mode: number;
|
|
20
|
+
/** 使用者 ID */
|
|
21
|
+
uid: number;
|
|
22
|
+
/** 群組 ID */
|
|
23
|
+
gid: number;
|
|
24
|
+
constructor(name: string, mode?: number);
|
|
25
|
+
/** 是否為檔案 */
|
|
26
|
+
get isFile(): boolean;
|
|
27
|
+
/** 是否為目錄 */
|
|
28
|
+
get isDirectory(): boolean;
|
|
29
|
+
/** 是否為符號連結 */
|
|
30
|
+
get isSymlink(): boolean;
|
|
31
|
+
/** 取得大小(由子類別實作) */
|
|
32
|
+
abstract get size(): number;
|
|
33
|
+
/** 取得統計資訊 */
|
|
34
|
+
getStats(): FileStats;
|
|
35
|
+
/** 更新存取時間 */
|
|
36
|
+
touch(): void;
|
|
37
|
+
/** 更新修改時間 */
|
|
38
|
+
markModified(): void;
|
|
39
|
+
/** 深拷貝(由子類別實作) */
|
|
40
|
+
abstract clone(): VFSNode;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=vfs-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-node.d.ts","sourceRoot":"","sources":["../../src/core/vfs-node.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,iBAAiB;AACjB,8BAAsB,OAAO;IAC3B,WAAW;IACX,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,WAAW;IACX,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAEpC,WAAW;IACX,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAE3B,WAAW;IACX,YAAY,EAAE,IAAI,CAAC;IAEnB,WAAW;IACX,YAAY,EAAE,IAAI,CAAC;IAEnB,WAAW;IACX,IAAI,EAAE,MAAM,CAAC;IAEb,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IAEZ,YAAY;IACZ,GAAG,EAAE,MAAM,CAAC;gBAEA,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc;IAY9C,YAAY;IACZ,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,YAAY;IACZ,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,cAAc;IACd,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,mBAAmB;IACnB,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC;IAE5B,aAAa;IACb,QAAQ,IAAI,SAAS;IAerB,aAAa;IACb,KAAK,IAAI,IAAI;IAIb,aAAa;IACb,YAAY,IAAI,IAAI;IAMpB,kBAAkB;IAClB,QAAQ,CAAC,KAAK,IAAI,OAAO;CAC1B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 節點基礎類別
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNodeType } from '../types/index.js';
|
|
5
|
+
/** VFS 節點基礎類別 */
|
|
6
|
+
export class VFSNode {
|
|
7
|
+
/** 節點名稱 */
|
|
8
|
+
name;
|
|
9
|
+
/** 建立時間 */
|
|
10
|
+
createdTime;
|
|
11
|
+
/** 修改時間 */
|
|
12
|
+
modifiedTime;
|
|
13
|
+
/** 存取時間 */
|
|
14
|
+
accessedTime;
|
|
15
|
+
/** 檔案模式 */
|
|
16
|
+
mode;
|
|
17
|
+
/** 使用者 ID */
|
|
18
|
+
uid;
|
|
19
|
+
/** 群組 ID */
|
|
20
|
+
gid;
|
|
21
|
+
constructor(name, mode = 0o644) {
|
|
22
|
+
this.name = name;
|
|
23
|
+
this.mode = mode;
|
|
24
|
+
this.uid = 0;
|
|
25
|
+
this.gid = 0;
|
|
26
|
+
const now = new Date();
|
|
27
|
+
this.createdTime = now;
|
|
28
|
+
this.modifiedTime = now;
|
|
29
|
+
this.accessedTime = now;
|
|
30
|
+
}
|
|
31
|
+
/** 是否為檔案 */
|
|
32
|
+
get isFile() {
|
|
33
|
+
return this.type === VFSNodeType.File;
|
|
34
|
+
}
|
|
35
|
+
/** 是否為目錄 */
|
|
36
|
+
get isDirectory() {
|
|
37
|
+
return this.type === VFSNodeType.Directory;
|
|
38
|
+
}
|
|
39
|
+
/** 是否為符號連結 */
|
|
40
|
+
get isSymlink() {
|
|
41
|
+
return this.type === VFSNodeType.Symlink;
|
|
42
|
+
}
|
|
43
|
+
/** 取得統計資訊 */
|
|
44
|
+
getStats() {
|
|
45
|
+
return {
|
|
46
|
+
isFile: this.isFile,
|
|
47
|
+
isDirectory: this.isDirectory,
|
|
48
|
+
isSymlink: this.isSymlink,
|
|
49
|
+
size: this.size,
|
|
50
|
+
createdTime: this.createdTime,
|
|
51
|
+
modifiedTime: this.modifiedTime,
|
|
52
|
+
accessedTime: this.accessedTime,
|
|
53
|
+
mode: this.mode,
|
|
54
|
+
uid: this.uid,
|
|
55
|
+
gid: this.gid,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** 更新存取時間 */
|
|
59
|
+
touch() {
|
|
60
|
+
this.accessedTime = new Date();
|
|
61
|
+
}
|
|
62
|
+
/** 更新修改時間 */
|
|
63
|
+
markModified() {
|
|
64
|
+
const now = new Date();
|
|
65
|
+
this.modifiedTime = now;
|
|
66
|
+
this.accessedTime = now;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=vfs-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-node.js","sourceRoot":"","sources":["../../src/core/vfs-node.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,iBAAiB;AACjB,MAAM,OAAgB,OAAO;IAC3B,WAAW;IACF,IAAI,CAAS;IAKtB,WAAW;IACF,WAAW,CAAO;IAE3B,WAAW;IACX,YAAY,CAAO;IAEnB,WAAW;IACX,YAAY,CAAO;IAEnB,WAAW;IACX,IAAI,CAAS;IAEb,aAAa;IACb,GAAG,CAAS;IAEZ,YAAY;IACZ,GAAG,CAAS;IAEZ,YAAY,IAAY,EAAE,OAAe,KAAK;QAC5C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QAEb,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;IAC1B,CAAC;IAED,YAAY;IACZ,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI,CAAC;IACxC,CAAC;IAED,YAAY;IACZ,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,SAAS,CAAC;IAC7C,CAAC;IAED,cAAc;IACd,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,OAAO,CAAC;IAC3C,CAAC;IAKD,aAAa;IACb,QAAQ;QACN,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC;IACJ,CAAC;IAED,aAAa;IACb,KAAK;QACH,IAAI,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,aAAa;IACb,YAAY;QACV,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC;IAC1B,CAAC;CAIF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 符號連結節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** VFS 符號連結節點 */
|
|
7
|
+
export declare class VFSSymlink extends VFSNode {
|
|
8
|
+
readonly type = VFSNodeType.Symlink;
|
|
9
|
+
/** 目標路徑 */
|
|
10
|
+
private targetPath;
|
|
11
|
+
constructor(name: string, target: string, mode?: number);
|
|
12
|
+
/** 取得大小(目標路徑的長度) */
|
|
13
|
+
get size(): number;
|
|
14
|
+
/** 取得目標路徑 */
|
|
15
|
+
get target(): string;
|
|
16
|
+
/** 設定目標路徑 */
|
|
17
|
+
setTarget(target: string): void;
|
|
18
|
+
/** 深拷貝 */
|
|
19
|
+
clone(): VFSSymlink;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=vfs-symlink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-symlink.d.ts","sourceRoot":"","sources":["../../src/core/vfs-symlink.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,iBAAiB;AACjB,qBAAa,UAAW,SAAQ,OAAO;IACrC,QAAQ,CAAC,IAAI,uBAAuB;IAEpC,WAAW;IACX,OAAO,CAAC,UAAU,CAAS;gBAEf,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,MAA6B;IAK7E,oBAAoB;IACpB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,aAAa;IACb,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,aAAa;IACb,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/B,UAAU;IACV,KAAK,IAAI,UAAU;CASpB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS 符號連結節點
|
|
3
|
+
*/
|
|
4
|
+
import { VFSNode } from './vfs-node.js';
|
|
5
|
+
import { VFSNodeType } from '../types/index.js';
|
|
6
|
+
/** 預設符號連結模式 */
|
|
7
|
+
const DEFAULT_SYMLINK_MODE = 0o777;
|
|
8
|
+
/** VFS 符號連結節點 */
|
|
9
|
+
export class VFSSymlink extends VFSNode {
|
|
10
|
+
type = VFSNodeType.Symlink;
|
|
11
|
+
/** 目標路徑 */
|
|
12
|
+
targetPath;
|
|
13
|
+
constructor(name, target, mode = DEFAULT_SYMLINK_MODE) {
|
|
14
|
+
super(name, mode);
|
|
15
|
+
this.targetPath = target;
|
|
16
|
+
}
|
|
17
|
+
/** 取得大小(目標路徑的長度) */
|
|
18
|
+
get size() {
|
|
19
|
+
return Buffer.byteLength(this.targetPath, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
/** 取得目標路徑 */
|
|
22
|
+
get target() {
|
|
23
|
+
return this.targetPath;
|
|
24
|
+
}
|
|
25
|
+
/** 設定目標路徑 */
|
|
26
|
+
setTarget(target) {
|
|
27
|
+
this.targetPath = target;
|
|
28
|
+
this.markModified();
|
|
29
|
+
}
|
|
30
|
+
/** 深拷貝 */
|
|
31
|
+
clone() {
|
|
32
|
+
const cloned = new VFSSymlink(this.name, this.targetPath, this.mode);
|
|
33
|
+
cloned.uid = this.uid;
|
|
34
|
+
cloned.gid = this.gid;
|
|
35
|
+
cloned.createdTime = new Date(this.createdTime);
|
|
36
|
+
cloned.modifiedTime = new Date(this.modifiedTime);
|
|
37
|
+
cloned.accessedTime = new Date(this.accessedTime);
|
|
38
|
+
return cloned;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=vfs-symlink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vfs-symlink.js","sourceRoot":"","sources":["../../src/core/vfs-symlink.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,eAAe;AACf,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC,iBAAiB;AACjB,MAAM,OAAO,UAAW,SAAQ,OAAO;IAC5B,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC;IAEpC,WAAW;IACH,UAAU,CAAS;IAE3B,YAAY,IAAY,EAAE,MAAc,EAAE,OAAe,oBAAoB;QAC3E,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;IAC3B,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI;QACN,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,aAAa;IACb,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,aAAa;IACb,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC;QACzB,IAAI,CAAC,YAAY,EAAE,CAAC;IACtB,CAAC;IAED,UAAU;IACV,KAAK;QACH,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACtB,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,MAAgC,CAAC,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3E,MAAM,CAAC,YAAY,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,MAAM,CAAC,YAAY,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|