vvvfs 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/README.md +12 -2
- package/dist/vvvfs.min.js +3 -3
- package/index.html +16 -12
- package/index.ts +295 -80
- package/package.json +1 -1
package/index.html
CHANGED
|
@@ -11,18 +11,22 @@
|
|
|
11
11
|
<body>
|
|
12
12
|
<script>
|
|
13
13
|
(async () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
try {
|
|
15
|
+
globalThis.vvvfs = new VVVFS();
|
|
16
|
+
await vvvfs.reset();
|
|
17
|
+
console.log(vvvfs);
|
|
18
|
+
console.log("创建文件", await vvvfs.createFile("/test.txt"));
|
|
19
|
+
console.log("写入文件", await vvvfs.writeText("/test.txt", "Hello World"));
|
|
20
|
+
console.log("文件是否存在", await vvvfs.exists("/test.txt"));
|
|
21
|
+
console.log("文件是否存在", await vvvfs.exists("/test2.txt"));
|
|
22
|
+
console.log("读取文件", await vvvfs.readText("/test.txt"));
|
|
23
|
+
console.log("复制文件", await vvvfs.copy("/test.txt", "/test2.txt"));
|
|
24
|
+
console.log("搜索文件", await vvvfs.search("test"));
|
|
25
|
+
console.log("移动文件", await vvvfs.move("/test2.txt", "/test3.txt"));
|
|
26
|
+
console.log("删除文件", await vvvfs.delete("/test.txt"));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(error);
|
|
29
|
+
}
|
|
26
30
|
})();
|
|
27
31
|
</script>
|
|
28
32
|
</body>
|
package/index.ts
CHANGED
|
@@ -2,6 +2,20 @@ import { Dexie, Table } from "dexie";
|
|
|
2
2
|
import packageJson from "./package.json" with { type: "json" };
|
|
3
3
|
import mime from "mime";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* 虚拟文件系统
|
|
7
|
+
* @author IFTC
|
|
8
|
+
* @description 虚拟文件系统
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 文件记录
|
|
13
|
+
* @param id 文件id
|
|
14
|
+
* @param name 文件名
|
|
15
|
+
* @param path 文件路径
|
|
16
|
+
* @param type 文件类型(file或dir)
|
|
17
|
+
* @param file 文件对象
|
|
18
|
+
*/
|
|
5
19
|
export interface FileRecord {
|
|
6
20
|
id?: number;
|
|
7
21
|
name: string;
|
|
@@ -10,14 +24,40 @@ export interface FileRecord {
|
|
|
10
24
|
file: File | null;
|
|
11
25
|
}
|
|
12
26
|
|
|
27
|
+
/**
|
|
28
|
+
* 虚拟文件系统数据库
|
|
29
|
+
* @param files 文件存储数据表
|
|
30
|
+
*/
|
|
13
31
|
export interface VVVFSDatabase extends Dexie {
|
|
14
32
|
files: Table<FileRecord, number>;
|
|
15
33
|
}
|
|
16
34
|
|
|
35
|
+
/**
|
|
36
|
+
* 虚拟文件系统配置项
|
|
37
|
+
* @param throwError 是否抛出错误
|
|
38
|
+
*/
|
|
39
|
+
export interface VVVFSOptions {
|
|
40
|
+
throwError: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 虚拟文件系统错误类
|
|
45
|
+
*/
|
|
46
|
+
class VVVFSError extends Error {
|
|
47
|
+
/**
|
|
48
|
+
* @param type 错误类型
|
|
49
|
+
* @param message 错误信息
|
|
50
|
+
*/
|
|
51
|
+
constructor(type: string, message: string) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "VVVFS" + type + "Error";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
17
57
|
const version = packageJson.version;
|
|
18
58
|
class VVVFS {
|
|
19
59
|
private db: VVVFSDatabase;
|
|
20
|
-
options:
|
|
60
|
+
options: VVVFSOptions;
|
|
21
61
|
/**
|
|
22
62
|
* 虚拟文件系统版本
|
|
23
63
|
*/
|
|
@@ -27,22 +67,37 @@ class VVVFS {
|
|
|
27
67
|
* @param name 虚拟文件系统名称
|
|
28
68
|
* @param options 配置项
|
|
29
69
|
*/
|
|
30
|
-
constructor(
|
|
70
|
+
constructor(
|
|
71
|
+
name = "vvvfs",
|
|
72
|
+
options = {
|
|
73
|
+
throwError: false,
|
|
74
|
+
},
|
|
75
|
+
) {
|
|
31
76
|
this.options = options;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
77
|
+
try {
|
|
78
|
+
this.db = new Dexie(name) as VVVFSDatabase;
|
|
79
|
+
this.db.version(1).stores({
|
|
80
|
+
files: "++id, name, path, type, file",
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("创建数据库失败", error);
|
|
84
|
+
throw new VVVFSError("CreateDatabase", "创建数据库失败");
|
|
85
|
+
}
|
|
36
86
|
}
|
|
37
87
|
/**
|
|
38
88
|
* 重置虚拟文件系统
|
|
39
89
|
*/
|
|
40
90
|
async reset() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
91
|
+
try {
|
|
92
|
+
await this.db.delete();
|
|
93
|
+
this.db = new Dexie(this.db.name) as VVVFSDatabase;
|
|
94
|
+
this.db.version(1).stores({
|
|
95
|
+
files: "++id, name, path, type, file",
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("重置数据库失败", error);
|
|
99
|
+
throw new VVVFSError("ResetDatabase", "重置数据库失败" + error);
|
|
100
|
+
}
|
|
46
101
|
}
|
|
47
102
|
/**
|
|
48
103
|
* 创建文件
|
|
@@ -58,7 +113,7 @@ class VVVFS {
|
|
|
58
113
|
if (!(await this.exists(parent))) {
|
|
59
114
|
await this.createDir(parent);
|
|
60
115
|
}
|
|
61
|
-
console.log(name, parent);
|
|
116
|
+
// console.log(name, parent);
|
|
62
117
|
await this.db.files.add({
|
|
63
118
|
name: name,
|
|
64
119
|
path: parent,
|
|
@@ -70,6 +125,9 @@ class VVVFS {
|
|
|
70
125
|
return true;
|
|
71
126
|
} catch (error) {
|
|
72
127
|
console.error("创建文件失败", error);
|
|
128
|
+
if (this.options.throwError) {
|
|
129
|
+
throw new VVVFSError("CreateFile", "创建文件失败" + error);
|
|
130
|
+
}
|
|
73
131
|
return false;
|
|
74
132
|
}
|
|
75
133
|
}
|
|
@@ -107,6 +165,9 @@ class VVVFS {
|
|
|
107
165
|
return true;
|
|
108
166
|
} catch (error) {
|
|
109
167
|
console.error("创建目录失败", error);
|
|
168
|
+
if (this.options.throwError) {
|
|
169
|
+
throw new VVVFSError("CreateDir", "创建目录失败" + error);
|
|
170
|
+
}
|
|
110
171
|
return false;
|
|
111
172
|
}
|
|
112
173
|
}
|
|
@@ -115,33 +176,47 @@ class VVVFS {
|
|
|
115
176
|
* @param path 文件路径
|
|
116
177
|
*/
|
|
117
178
|
async exists(path: string) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
(
|
|
121
|
-
.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
179
|
+
try {
|
|
180
|
+
const { name, parent } = parsePath(path);
|
|
181
|
+
return (
|
|
182
|
+
(await this.db.files
|
|
183
|
+
.where({
|
|
184
|
+
name: name,
|
|
185
|
+
path: parent,
|
|
186
|
+
})
|
|
187
|
+
.count()) > 0
|
|
188
|
+
);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error("判断文件是否存在失败", error);
|
|
191
|
+
if (this.options.throwError) {
|
|
192
|
+
throw new VVVFSError("Exists", "判断文件是否存在失败" + error);
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
127
196
|
}
|
|
128
197
|
/**
|
|
129
198
|
* 读取文件内容
|
|
130
199
|
* @param path 文件路径
|
|
131
200
|
*/
|
|
132
201
|
async write(path: string, content: Blob) {
|
|
133
|
-
if (!(await this.exists(path))) {
|
|
134
|
-
const success = await this.createFile(path);
|
|
135
|
-
if (!success) {
|
|
136
|
-
console.warn("创建文件失败");
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
202
|
try {
|
|
203
|
+
if (!(await this.exists(path))) {
|
|
204
|
+
const success = await this.createFile(path);
|
|
205
|
+
if (!success) {
|
|
206
|
+
console.warn("创建文件失败");
|
|
207
|
+
if (this.options.throwError) {
|
|
208
|
+
throw new VVVFSError("Write", "创建文件失败");
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
141
213
|
const { name, parent } = parsePath(path);
|
|
142
214
|
console.log(name, parent);
|
|
143
215
|
if (await this.isDir(parent + "/" + name)) {
|
|
144
216
|
console.warn("路径已存在");
|
|
217
|
+
if (this.options.throwError) {
|
|
218
|
+
throw new VVVFSError("Write", "路径已存在");
|
|
219
|
+
}
|
|
145
220
|
return false;
|
|
146
221
|
}
|
|
147
222
|
const file = new File([content], name, {
|
|
@@ -157,10 +232,16 @@ class VVVFS {
|
|
|
157
232
|
return true;
|
|
158
233
|
} else {
|
|
159
234
|
console.warn("文件记录未找到,无法写入内容");
|
|
235
|
+
if (this.options.throwError) {
|
|
236
|
+
throw new VVVFSError("Write", "文件记录未找到,无法写入内容");
|
|
237
|
+
}
|
|
160
238
|
return false;
|
|
161
239
|
}
|
|
162
240
|
} catch (error) {
|
|
163
241
|
console.error("写入文件失败", error);
|
|
242
|
+
if (this.options.throwError) {
|
|
243
|
+
throw new VVVFSError("Write", "写入文件失败" + error);
|
|
244
|
+
}
|
|
164
245
|
return false;
|
|
165
246
|
}
|
|
166
247
|
}
|
|
@@ -170,8 +251,16 @@ class VVVFS {
|
|
|
170
251
|
* @param content 文本内容
|
|
171
252
|
*/
|
|
172
253
|
async writeText(path: string, content: string) {
|
|
173
|
-
|
|
174
|
-
|
|
254
|
+
try {
|
|
255
|
+
const blob = new Blob([content], { type: "text/plain" });
|
|
256
|
+
return await this.write(path, blob);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error("写入文件失败", error);
|
|
259
|
+
if (this.options.throwError) {
|
|
260
|
+
throw new VVVFSError("Write", "写入文件失败" + error);
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
175
264
|
}
|
|
176
265
|
/**
|
|
177
266
|
* 写入JSON内容
|
|
@@ -180,22 +269,39 @@ class VVVFS {
|
|
|
180
269
|
* @param format 是否格式化
|
|
181
270
|
*/
|
|
182
271
|
async writeJson(path: string, content: Record<string, any>, format?: boolean) {
|
|
183
|
-
|
|
272
|
+
try {
|
|
273
|
+
return await this.writeText(
|
|
274
|
+
path,
|
|
275
|
+
JSON.stringify(content, null, format ? 4 : undefined),
|
|
276
|
+
);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
console.error("写入文件失败", error);
|
|
279
|
+
if (this.options.throwError) {
|
|
280
|
+
throw new VVVFSError("Write", "写入文件失败" + error);
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
184
284
|
}
|
|
185
285
|
/**
|
|
186
286
|
* 读取文件内容
|
|
187
287
|
* @param path 文件路径
|
|
188
288
|
*/
|
|
189
289
|
async read(path: string) {
|
|
190
|
-
if (!(await this.exists(path))) {
|
|
191
|
-
console.warn("文件不存在");
|
|
192
|
-
return null;
|
|
193
|
-
}
|
|
194
290
|
try {
|
|
291
|
+
if (!(await this.exists(path))) {
|
|
292
|
+
console.warn("文件不存在");
|
|
293
|
+
if (this.options.throwError) {
|
|
294
|
+
throw new VVVFSError("Read", "文件不存在");
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
195
298
|
const { name, parent } = parsePath(path);
|
|
196
299
|
return (await this.db.files.where({ name, path: parent }).first())?.file;
|
|
197
300
|
} catch (error) {
|
|
198
301
|
console.error("读取文件失败", error);
|
|
302
|
+
if (this.options.throwError) {
|
|
303
|
+
throw new VVVFSError("Read", "读取文件失败" + error);
|
|
304
|
+
}
|
|
199
305
|
return null;
|
|
200
306
|
}
|
|
201
307
|
}
|
|
@@ -204,10 +310,22 @@ class VVVFS {
|
|
|
204
310
|
* @param path 文件路径
|
|
205
311
|
*/
|
|
206
312
|
async readText(path: string) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
313
|
+
try {
|
|
314
|
+
const file = await this.read(path);
|
|
315
|
+
if (file) {
|
|
316
|
+
return await file.text();
|
|
317
|
+
} else {
|
|
318
|
+
console.warn("文件不存在");
|
|
319
|
+
if (this.options.throwError) {
|
|
320
|
+
throw new VVVFSError("Read", "文件不存在");
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error("读取文件失败", error);
|
|
326
|
+
if (this.options.throwError) {
|
|
327
|
+
throw new VVVFSError("Read", "读取文件失败" + error);
|
|
328
|
+
}
|
|
211
329
|
return null;
|
|
212
330
|
}
|
|
213
331
|
}
|
|
@@ -216,15 +334,26 @@ class VVVFS {
|
|
|
216
334
|
* @param path 文件路径
|
|
217
335
|
*/
|
|
218
336
|
async readJson(path: string) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
337
|
+
try {
|
|
338
|
+
const text = await this.readText(path);
|
|
339
|
+
if (text) {
|
|
340
|
+
try {
|
|
341
|
+
return JSON.parse(text);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
console.error("解析JSON失败", error);
|
|
344
|
+
if (this.options.throwError) {
|
|
345
|
+
throw new VVVFSError("Read", "解析JSON失败" + error);
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
225
350
|
return null;
|
|
226
351
|
}
|
|
227
|
-
}
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.error("读取文件失败", error);
|
|
354
|
+
if (this.options.throwError) {
|
|
355
|
+
throw new VVVFSError("Read", "读取文件失败" + error);
|
|
356
|
+
}
|
|
228
357
|
return null;
|
|
229
358
|
}
|
|
230
359
|
}
|
|
@@ -233,24 +362,48 @@ class VVVFS {
|
|
|
233
362
|
* @param path 文件路径
|
|
234
363
|
*/
|
|
235
364
|
async isFile(path: string) {
|
|
236
|
-
|
|
237
|
-
|
|
365
|
+
try {
|
|
366
|
+
const { name, parent } = parsePath(path);
|
|
367
|
+
return (await this.db.files.where({ name, path: parent, type: "file" }).count()) > 0;
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.error("判断文件类型失败", error);
|
|
370
|
+
if (this.options.throwError) {
|
|
371
|
+
throw new VVVFSError("IsFile", "判断文件类型失败" + error);
|
|
372
|
+
}
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
238
375
|
}
|
|
239
376
|
/**
|
|
240
377
|
* 判断是否是目录
|
|
241
378
|
* @param path 文件路径
|
|
242
379
|
*/
|
|
243
380
|
async isDir(path: string) {
|
|
244
|
-
|
|
245
|
-
|
|
381
|
+
try {
|
|
382
|
+
const { name, parent } = parsePath(path);
|
|
383
|
+
return (await this.db.files.where({ path: parent, name, type: "dir" }).count()) > 0;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
console.error("判断文件类型失败", error);
|
|
386
|
+
if (this.options.throwError) {
|
|
387
|
+
throw new VVVFSError("IsDir", "判断文件类型失败" + error);
|
|
388
|
+
}
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
246
391
|
}
|
|
247
392
|
/**
|
|
248
393
|
* 列出目录下的文件
|
|
249
394
|
* @param path 目录路径
|
|
250
395
|
*/
|
|
251
396
|
async list(path: string) {
|
|
252
|
-
|
|
253
|
-
|
|
397
|
+
try {
|
|
398
|
+
const { name, parent } = parsePath(path);
|
|
399
|
+
return (await this.db.files.where({ path: parent }).toArray()).map((file) => file.name);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error("列出目录下的文件失败", error);
|
|
402
|
+
if (this.options.throwError) {
|
|
403
|
+
throw new VVVFSError("List", "列出目录下的文件失败" + error);
|
|
404
|
+
}
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
254
407
|
}
|
|
255
408
|
/**
|
|
256
409
|
* 重命名文件
|
|
@@ -258,8 +411,14 @@ class VVVFS {
|
|
|
258
411
|
* @param newName 新文件名
|
|
259
412
|
*/
|
|
260
413
|
async rename(path: string, newName: string) {
|
|
261
|
-
if (!(await this.exists(path))) throw new Error("File not exists");
|
|
262
414
|
try {
|
|
415
|
+
if (!(await this.exists(path))) {
|
|
416
|
+
console.warn("文件不存在");
|
|
417
|
+
if (this.options.throwError) {
|
|
418
|
+
throw new VVVFSError("Rename", "文件不存在");
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
263
422
|
const { name, parent } = parsePath(path);
|
|
264
423
|
const file = await this.db.files.get({ path, name });
|
|
265
424
|
await this.db.files.put({
|
|
@@ -271,6 +430,9 @@ class VVVFS {
|
|
|
271
430
|
return true;
|
|
272
431
|
} catch (e) {
|
|
273
432
|
console.error(e);
|
|
433
|
+
if (this.options.throwError) {
|
|
434
|
+
throw new VVVFSError("Rename", "重命名文件失败" + e);
|
|
435
|
+
}
|
|
274
436
|
return false;
|
|
275
437
|
}
|
|
276
438
|
}
|
|
@@ -279,8 +441,14 @@ class VVVFS {
|
|
|
279
441
|
* @param path 文件路径
|
|
280
442
|
*/
|
|
281
443
|
async delete(path: string) {
|
|
282
|
-
if (!(await this.exists(path))) return false;
|
|
283
444
|
try {
|
|
445
|
+
if (!(await this.exists(path))) {
|
|
446
|
+
console.warn("文件不存在");
|
|
447
|
+
if (this.options.throwError) {
|
|
448
|
+
throw new VVVFSError("Delete", "文件不存在");
|
|
449
|
+
}
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
284
452
|
const { name, parent } = parsePath(path);
|
|
285
453
|
if (await this.isDir(path)) {
|
|
286
454
|
const files = await this.list(path);
|
|
@@ -301,6 +469,9 @@ class VVVFS {
|
|
|
301
469
|
}
|
|
302
470
|
} catch (e) {
|
|
303
471
|
console.error(e);
|
|
472
|
+
if (this.options.throwError) {
|
|
473
|
+
throw new VVVFSError("Delete", "删除文件失败" + e);
|
|
474
|
+
}
|
|
304
475
|
return false;
|
|
305
476
|
}
|
|
306
477
|
}
|
|
@@ -310,9 +481,21 @@ class VVVFS {
|
|
|
310
481
|
* @param newPath 新路径
|
|
311
482
|
*/
|
|
312
483
|
async move(path: string, newPath: string) {
|
|
313
|
-
if (await this.exists(newPath)) return false;
|
|
314
|
-
if (!(await this.exists(path))) return false;
|
|
315
484
|
try {
|
|
485
|
+
if (await this.exists(newPath)) {
|
|
486
|
+
console.warn("目标文件已存在");
|
|
487
|
+
if (this.options.throwError) {
|
|
488
|
+
throw new VVVFSError("Move", "目标文件已存在");
|
|
489
|
+
}
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
if (!(await this.exists(path))) {
|
|
493
|
+
console.warn("源文件不存在");
|
|
494
|
+
if (this.options.throwError) {
|
|
495
|
+
throw new VVVFSError("Move", "源文件不存在");
|
|
496
|
+
}
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
316
499
|
const { name, parent } = parsePath(path);
|
|
317
500
|
const { name: newName, parent: newParent } = parsePath(newPath);
|
|
318
501
|
await this.createDir(newParent);
|
|
@@ -329,6 +512,9 @@ class VVVFS {
|
|
|
329
512
|
return true;
|
|
330
513
|
} catch (e) {
|
|
331
514
|
console.error(e);
|
|
515
|
+
if (this.options.throwError) {
|
|
516
|
+
throw new VVVFSError("Move", "移动文件失败" + e);
|
|
517
|
+
}
|
|
332
518
|
return false;
|
|
333
519
|
}
|
|
334
520
|
}
|
|
@@ -338,9 +524,21 @@ class VVVFS {
|
|
|
338
524
|
* @param newPath 新路径
|
|
339
525
|
*/
|
|
340
526
|
async copy(path: string, newPath: string) {
|
|
341
|
-
if (await this.exists(newPath)) return false;
|
|
342
|
-
if (!(await this.exists(path))) return false;
|
|
343
527
|
try {
|
|
528
|
+
if (await this.exists(newPath)) {
|
|
529
|
+
console.warn("目标文件已存在");
|
|
530
|
+
if (this.options.throwError) {
|
|
531
|
+
throw new VVVFSError("Copy", "目标文件已存在");
|
|
532
|
+
}
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
if (!(await this.exists(path))) {
|
|
536
|
+
console.warn("源文件不存在");
|
|
537
|
+
if (this.options.throwError) {
|
|
538
|
+
throw new VVVFSError("Copy", "源文件不存在");
|
|
539
|
+
}
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
344
542
|
const { name, parent } = parsePath(path);
|
|
345
543
|
const { name: newName, parent: newParent } = parsePath(newPath);
|
|
346
544
|
await this.createDir(newParent);
|
|
@@ -356,6 +554,9 @@ class VVVFS {
|
|
|
356
554
|
return true;
|
|
357
555
|
} catch (e) {
|
|
358
556
|
console.error(e);
|
|
557
|
+
if (this.options.throwError) {
|
|
558
|
+
throw new VVVFSError("Copy", "复制文件失败" + e);
|
|
559
|
+
}
|
|
359
560
|
return false;
|
|
360
561
|
}
|
|
361
562
|
}
|
|
@@ -365,33 +566,47 @@ class VVVFS {
|
|
|
365
566
|
* @param query 查询字符串
|
|
366
567
|
*/
|
|
367
568
|
async search(basePath: string, query: string) {
|
|
368
|
-
if (!await this.isDir(basePath)) return null;
|
|
369
|
-
const that = this;
|
|
370
569
|
try {
|
|
570
|
+
if (!(await this.isDir(basePath))) {
|
|
571
|
+
console.warn("基础路径不是目录");
|
|
572
|
+
if (this.options.throwError) {
|
|
573
|
+
throw new VVVFSError("Search", "基础路径不是目录");
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
const that = this;
|
|
371
578
|
const dirs = await this.list(basePath);
|
|
372
579
|
return await search(basePath, dirs);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
580
|
+
async function search(parent: string, files: string[]) {
|
|
581
|
+
const result: string[] = [];
|
|
582
|
+
console.log(files);
|
|
583
|
+
for (const file of files) {
|
|
584
|
+
if (file == "") continue;
|
|
585
|
+
console.log(file);
|
|
586
|
+
if (await that.isDir(joinPath(parent, file))) {
|
|
587
|
+
if (file.includes(query)) {
|
|
588
|
+
result.push(joinPath(parent, file) + "/");
|
|
589
|
+
}
|
|
590
|
+
result.push(
|
|
591
|
+
...(await search(
|
|
592
|
+
joinPath(parent, file),
|
|
593
|
+
await that.list(joinPath(parent, file)),
|
|
594
|
+
)),
|
|
595
|
+
);
|
|
596
|
+
} else {
|
|
597
|
+
if (file.includes(query)) {
|
|
598
|
+
result.push(joinPath(parent, file));
|
|
599
|
+
}
|
|
391
600
|
}
|
|
392
601
|
}
|
|
602
|
+
return result;
|
|
393
603
|
}
|
|
394
|
-
|
|
604
|
+
} catch (e) {
|
|
605
|
+
console.error(e);
|
|
606
|
+
if (this.options.throwError) {
|
|
607
|
+
throw new VVVFSError("Search", "搜索文件失败" + e);
|
|
608
|
+
}
|
|
609
|
+
return null;
|
|
395
610
|
}
|
|
396
611
|
}
|
|
397
612
|
}
|
|
@@ -433,7 +648,7 @@ function joinPath(...paths: string[]) {
|
|
|
433
648
|
return result || (isAbsolute ? "/" : ".");
|
|
434
649
|
}
|
|
435
650
|
Object.defineProperty(VVVFS, "version", {
|
|
436
|
-
value:
|
|
651
|
+
value: version,
|
|
437
652
|
writable: false,
|
|
438
653
|
enumerable: true,
|
|
439
654
|
configurable: false,
|