vvvfs 0.0.8 → 0.0.9
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 +6 -1
- package/index.html +2 -0
- package/index.ts +119 -65
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ const vvvfs = new VVVFS("vvvfs", {
|
|
|
44
44
|
await vvvfs.init("UserName"); // 初始化文件系统
|
|
45
45
|
await vvvfs.watch("/home/user/Desktop/test.txt", (type) => {
|
|
46
46
|
console.log(type); // 打印文件操作的类型
|
|
47
|
+
return true; // 返回true或false,表示是否取消该操作
|
|
47
48
|
});
|
|
48
49
|
await vvvfs.createDir("/home/user/Desktop"); // 创建目录,返回true和false
|
|
49
50
|
await vvvfs.writeText("/home/user/Desktop/test.txt", "Hello World!"); // 写入文本文件,写入文件还包括write(path: string, content: Blob)和writeJson(path: string, content: Record<string, any>)方法,返回true和false
|
|
@@ -81,9 +82,13 @@ const vvvfs = new VVVFS("vvvfs", {
|
|
|
81
82
|
|
|
82
83
|
## 更新日志
|
|
83
84
|
|
|
85
|
+
### 0.0.9
|
|
86
|
+
|
|
87
|
+
- 更新 `watch` 方法,监听时,返回 `true` 表示取消该操作
|
|
88
|
+
|
|
84
89
|
### 0.0.8
|
|
85
90
|
|
|
86
|
-
- 新增 `watch` 方法
|
|
91
|
+
- 新增 `watch` 方法 (该方法属于实验性功能,后期可能会改变)
|
|
87
92
|
|
|
88
93
|
### 0.0.7
|
|
89
94
|
|
package/index.html
CHANGED
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
(async () => {
|
|
14
14
|
try {
|
|
15
15
|
globalThis.vvvfs = new VVVFS();
|
|
16
|
+
vvvfs.options.throwError = true;
|
|
16
17
|
await vvvfs.reset();
|
|
17
18
|
await vvvfs.init("IFTC");
|
|
18
19
|
console.log(vvvfs);
|
|
19
20
|
await vvvfs.watch("/test.txt", (type) => {
|
|
20
21
|
console.log(type);
|
|
22
|
+
// return true;
|
|
21
23
|
});
|
|
22
24
|
console.log("创建文件", await vvvfs.createFile("/test.txt"));
|
|
23
25
|
console.log("写入文件", await vvvfs.writeText("/test.txt", "Hello World"));
|
package/index.ts
CHANGED
|
@@ -216,7 +216,7 @@ class VVVFSFile {
|
|
|
216
216
|
async search(query: string) {
|
|
217
217
|
return await this._vvvfs.search(this._path, query);
|
|
218
218
|
}
|
|
219
|
-
async watch(handler: (type: string) =>
|
|
219
|
+
async watch(handler: (type: string) => Promise<boolean>) {
|
|
220
220
|
return await this._vvvfs.watch(this._path, handler);
|
|
221
221
|
}
|
|
222
222
|
}
|
|
@@ -234,6 +234,10 @@ class VVVFS {
|
|
|
234
234
|
* 虚拟文件系统文件类
|
|
235
235
|
*/
|
|
236
236
|
static File = VVVFSFile;
|
|
237
|
+
/**
|
|
238
|
+
* 虚拟文件系统监听器
|
|
239
|
+
*/
|
|
240
|
+
watchers: Record<string, Array<(type: string) => Promise<boolean>>> = {};
|
|
237
241
|
/**
|
|
238
242
|
* 创建虚拟文件系统
|
|
239
243
|
* @param name 虚拟文件系统名称
|
|
@@ -413,11 +417,21 @@ class VVVFS {
|
|
|
413
417
|
*/
|
|
414
418
|
async createFile(path: string) {
|
|
415
419
|
const targetPath = joinPath(path);
|
|
416
|
-
if (await this.exists(targetPath)) {
|
|
417
|
-
console.warn("文件已存在");
|
|
418
|
-
return true;
|
|
419
|
-
}
|
|
420
420
|
try {
|
|
421
|
+
if (this.watchers[targetPath]) {
|
|
422
|
+
for (const handler of this.watchers[targetPath]) {
|
|
423
|
+
if (await handler("create")) {
|
|
424
|
+
if (this.options.throwError) {
|
|
425
|
+
throw new VVVFSError("CreateFile", "创建文件失败:监听器取消了操作");
|
|
426
|
+
}
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (await this.exists(targetPath)) {
|
|
432
|
+
console.warn("文件已存在");
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
421
435
|
const { name, parent } = parsePath(targetPath);
|
|
422
436
|
if (!(await this.exists(parent))) {
|
|
423
437
|
await this.createDir(parent);
|
|
@@ -445,11 +459,21 @@ class VVVFS {
|
|
|
445
459
|
*/
|
|
446
460
|
async createDir(path: string) {
|
|
447
461
|
const targetPath = joinPath(path);
|
|
448
|
-
if (await this.exists(targetPath)) {
|
|
449
|
-
console.warn("目录已存在");
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
462
|
try {
|
|
463
|
+
if (this.watchers[targetPath]) {
|
|
464
|
+
for (const handler of this.watchers[targetPath]) {
|
|
465
|
+
if (await handler("create")) {
|
|
466
|
+
if (this.options.throwError) {
|
|
467
|
+
throw new VVVFSError("CreateDir", "创建目录失败:监听器取消了操作");
|
|
468
|
+
}
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (await this.exists(targetPath)) {
|
|
474
|
+
console.warn("目录已存在");
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
453
477
|
const { name, parent } = parsePath(targetPath);
|
|
454
478
|
if (!(await this.exists(parent))) {
|
|
455
479
|
if (parent == "/") {
|
|
@@ -510,6 +534,16 @@ class VVVFS {
|
|
|
510
534
|
async write(path: string, content: Blob) {
|
|
511
535
|
try {
|
|
512
536
|
const targetPath = joinPath(path);
|
|
537
|
+
if (this.watchers[targetPath]) {
|
|
538
|
+
for (const handler of this.watchers[targetPath]) {
|
|
539
|
+
if (await handler("write")) {
|
|
540
|
+
if (this.options.throwError) {
|
|
541
|
+
throw new VVVFSError("Write", "写入文件失败:监听器取消了操作");
|
|
542
|
+
}
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
513
547
|
if (!(await this.exists(targetPath))) {
|
|
514
548
|
const success = await this.createFile(targetPath);
|
|
515
549
|
if (!success) {
|
|
@@ -597,6 +631,16 @@ class VVVFS {
|
|
|
597
631
|
async read(path: string) {
|
|
598
632
|
try {
|
|
599
633
|
const targetPath = joinPath(path);
|
|
634
|
+
if (this.watchers[targetPath]) {
|
|
635
|
+
for (const handler of this.watchers[targetPath]) {
|
|
636
|
+
if (await handler("read")) {
|
|
637
|
+
if (this.options.throwError) {
|
|
638
|
+
throw new VVVFSError("Read", "读取文件失败:监听器取消了操作");
|
|
639
|
+
}
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
600
644
|
if (!(await this.exists(targetPath))) {
|
|
601
645
|
console.warn("文件不存在");
|
|
602
646
|
if (this.options.throwError) {
|
|
@@ -707,6 +751,23 @@ class VVVFS {
|
|
|
707
751
|
async list(path: string) {
|
|
708
752
|
try {
|
|
709
753
|
const targetPath = joinPath(path);
|
|
754
|
+
if (this.watchers[targetPath]) {
|
|
755
|
+
for (const handler of this.watchers[targetPath]) {
|
|
756
|
+
if (await handler("list")) {
|
|
757
|
+
if (this.options.throwError) {
|
|
758
|
+
throw new VVVFSError("List", "列出目录下的文件失败:监听器取消了操作");
|
|
759
|
+
}
|
|
760
|
+
return [];
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (!(await this.exists(targetPath))) {
|
|
765
|
+
console.warn("路径不存在");
|
|
766
|
+
if (this.options.throwError) {
|
|
767
|
+
throw new VVVFSError("List", "路径不存在");
|
|
768
|
+
}
|
|
769
|
+
return [];
|
|
770
|
+
}
|
|
710
771
|
if (!(await this.isDir(targetPath))) {
|
|
711
772
|
console.warn("路径不是目录");
|
|
712
773
|
if (this.options.throwError) {
|
|
@@ -734,6 +795,16 @@ class VVVFS {
|
|
|
734
795
|
try {
|
|
735
796
|
const sourcePath = joinPath(path);
|
|
736
797
|
const { name, parent } = parsePath(sourcePath);
|
|
798
|
+
if (this.watchers[sourcePath]) {
|
|
799
|
+
for (const handler of this.watchers[sourcePath]) {
|
|
800
|
+
if (await handler("rename")) {
|
|
801
|
+
if (this.options.throwError) {
|
|
802
|
+
throw new VVVFSError("Rename", "重命名文件失败:监听器取消了操作");
|
|
803
|
+
}
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
737
808
|
if (!(await this.exists(sourcePath))) {
|
|
738
809
|
console.warn("文件不存在");
|
|
739
810
|
if (this.options.throwError) {
|
|
@@ -793,6 +864,16 @@ class VVVFS {
|
|
|
793
864
|
async delete(path: string) {
|
|
794
865
|
try {
|
|
795
866
|
const targetPath = joinPath(path);
|
|
867
|
+
if (this.watchers[targetPath]) {
|
|
868
|
+
for (const handler of this.watchers[targetPath]) {
|
|
869
|
+
if (await handler("delete")) {
|
|
870
|
+
if (this.options.throwError) {
|
|
871
|
+
throw new VVVFSError("Delete", "删除文件失败:监听器取消了操作");
|
|
872
|
+
}
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
796
877
|
if (!(await this.exists(targetPath))) {
|
|
797
878
|
console.warn("文件不存在");
|
|
798
879
|
if (this.options.throwError) {
|
|
@@ -839,6 +920,19 @@ class VVVFS {
|
|
|
839
920
|
try {
|
|
840
921
|
const sourcePath = joinPath(path);
|
|
841
922
|
const destinationPath = joinPath(newPath);
|
|
923
|
+
if (this.watchers[sourcePath]) {
|
|
924
|
+
for (const handler of this.watchers[sourcePath]) {
|
|
925
|
+
if (await handler("move")) {
|
|
926
|
+
if (this.options.throwError) {
|
|
927
|
+
throw new VVVFSError("Move", "移动文件失败:监听器取消了操作");
|
|
928
|
+
}
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
if (sourcePath === destinationPath) {
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
842
936
|
if (await this.exists(destinationPath)) {
|
|
843
937
|
console.warn("目标文件已存在");
|
|
844
938
|
if (this.options.throwError) {
|
|
@@ -903,6 +997,16 @@ class VVVFS {
|
|
|
903
997
|
try {
|
|
904
998
|
const sourcePath = joinPath(path);
|
|
905
999
|
const destinationPath = joinPath(newPath);
|
|
1000
|
+
if (this.watchers[sourcePath]) {
|
|
1001
|
+
for (const handler of this.watchers[sourcePath]) {
|
|
1002
|
+
if (await handler("copy")) {
|
|
1003
|
+
if (this.options.throwError) {
|
|
1004
|
+
throw new VVVFSError("Copy", "复制文件失败:监听器取消了操作");
|
|
1005
|
+
}
|
|
1006
|
+
return false;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
906
1010
|
if (await this.exists(destinationPath)) {
|
|
907
1011
|
console.warn("目标文件已存在");
|
|
908
1012
|
if (this.options.throwError) {
|
|
@@ -1006,62 +1110,12 @@ class VVVFS {
|
|
|
1006
1110
|
return null;
|
|
1007
1111
|
}
|
|
1008
1112
|
}
|
|
1009
|
-
async watch(path: string, handler: (type: string) =>
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
return { exists: false, signature: "" };
|
|
1016
|
-
}
|
|
1017
|
-
if (await this.isDir(targetPath)) {
|
|
1018
|
-
const records = await this.db.files
|
|
1019
|
-
.filter(
|
|
1020
|
-
(file) =>
|
|
1021
|
-
file.path === targetPath || file.path.startsWith(targetPath + "/"),
|
|
1022
|
-
)
|
|
1023
|
-
.toArray();
|
|
1024
|
-
const signature = records
|
|
1025
|
-
.map((file) => {
|
|
1026
|
-
const fullPath = joinPath(file.path, file.name);
|
|
1027
|
-
const fileInfo = file.file
|
|
1028
|
-
? `${file.file.type}:${file.file.size}:${file.file.lastModified}`
|
|
1029
|
-
: "null";
|
|
1030
|
-
return `${fullPath}:${file.type}:${fileInfo}`;
|
|
1031
|
-
})
|
|
1032
|
-
.sort()
|
|
1033
|
-
.join("|");
|
|
1034
|
-
return { exists: true, signature };
|
|
1035
|
-
}
|
|
1036
|
-
const { name, parent } = parsePath(targetPath);
|
|
1037
|
-
const record = await this.db.files.where({ name, path: parent, type: "file" }).first();
|
|
1038
|
-
const signature = record?.file
|
|
1039
|
-
? `${record.file.type}:${record.file.size}:${record.file.lastModified}`
|
|
1040
|
-
: "";
|
|
1041
|
-
return { exists: true, signature };
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
let previousState = await getState();
|
|
1045
|
-
setInterval(async () => {
|
|
1046
|
-
try {
|
|
1047
|
-
const currentState = await getState();
|
|
1048
|
-
if (
|
|
1049
|
-
previousState.exists !== currentState.exists ||
|
|
1050
|
-
previousState.signature !== currentState.signature
|
|
1051
|
-
) {
|
|
1052
|
-
if (!previousState.exists && currentState.exists) {
|
|
1053
|
-
handler("create");
|
|
1054
|
-
} else if (previousState.exists && !currentState.exists) {
|
|
1055
|
-
handler("unlink");
|
|
1056
|
-
} else {
|
|
1057
|
-
handler("change");
|
|
1058
|
-
}
|
|
1059
|
-
previousState = currentState;
|
|
1060
|
-
}
|
|
1061
|
-
} catch (error) {
|
|
1062
|
-
console.error("监听失败", error);
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1113
|
+
async watch(path: string, handler: (type: string) => Promise<boolean>) {
|
|
1114
|
+
path = joinPath(path);
|
|
1115
|
+
if (!this.watchers[path]) {
|
|
1116
|
+
this.watchers[path] = [];
|
|
1117
|
+
}
|
|
1118
|
+
this.watchers[path].push(handler);
|
|
1065
1119
|
}
|
|
1066
1120
|
}
|
|
1067
1121
|
function parsePath(path: string) {
|