@pistonite/pure 0.27.1 → 0.29.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/LICENSE +1 -1
- package/README.md +23 -4
- package/dist/log/index.js +57 -0
- package/dist/log/index.js.map +1 -0
- package/dist/memory/index.js +92 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/result/index.js +29 -0
- package/dist/result/index.js.map +1 -0
- package/dist/sync/index.js +252 -0
- package/dist/sync/index.js.map +1 -0
- package/package.json +22 -13
- package/src/env.d.ts +1 -0
- package/src/log/index.ts +36 -11
- package/src/log/logger.ts +93 -115
- package/src/memory/cell.ts +21 -11
- package/src/memory/emp.ts +34 -23
- package/src/memory/idgen.test.ts +1 -1
- package/src/memory/index.ts +1 -4
- package/src/memory/persist.ts +9 -12
- package/src/result/index.ts +12 -4
- package/src/sync/batch.test.ts +1 -1
- package/src/sync/batch.ts +12 -17
- package/src/sync/capture.ts +2 -0
- package/src/sync/debounce.test.ts +1 -1
- package/src/sync/debounce.ts +12 -15
- package/src/sync/index.ts +2 -3
- package/src/sync/latest.test.ts +1 -1
- package/src/sync/latest.ts +19 -16
- package/src/sync/once.test.ts +1 -1
- package/src/sync/once.ts +13 -8
- package/src/sync/serial.test.ts +1 -1
- package/src/sync/serial.ts +14 -12
- package/src/sync/util.ts +2 -2
- package/src/fs/FsError.ts +0 -55
- package/src/fs/FsFile.ts +0 -67
- package/src/fs/FsFileImpl.ts +0 -219
- package/src/fs/FsFileMgr.ts +0 -29
- package/src/fs/FsFileStandalone.ts +0 -21
- package/src/fs/FsFileStandaloneImplFileAPI.ts +0 -54
- package/src/fs/FsFileStandaloneImplHandleAPI.ts +0 -147
- package/src/fs/FsFileSystem.ts +0 -71
- package/src/fs/FsFileSystemInternal.ts +0 -30
- package/src/fs/FsImplEntryAPI.ts +0 -149
- package/src/fs/FsImplFileAPI.ts +0 -116
- package/src/fs/FsImplHandleAPI.ts +0 -199
- package/src/fs/FsOpen.ts +0 -271
- package/src/fs/FsOpenFile.ts +0 -256
- package/src/fs/FsPath.ts +0 -137
- package/src/fs/FsSave.ts +0 -216
- package/src/fs/FsSupportStatus.ts +0 -87
- package/src/fs/index.ts +0 -123
- package/src/log/internal.ts +0 -14
- package/src/memory/async_erc.ts +0 -186
- package/src/memory/erc.test.ts +0 -258
- package/src/memory/erc.ts +0 -320
- package/src/pref/dark.ts +0 -151
- package/src/pref/device.ts +0 -118
- package/src/pref/index.ts +0 -13
- package/src/pref/inject_style.ts +0 -22
- package/src/pref/locale.ts +0 -296
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { ilog } from "../log/internal.ts";
|
|
2
|
-
import { errstr } from "../result";
|
|
3
|
-
|
|
4
|
-
import { fsErr, FsErr, fsFail, type FsVoid, type FsResult } from "./FsError.ts";
|
|
5
|
-
import type { FsFileStandalone } from "./FsFileStandalone.ts";
|
|
6
|
-
|
|
7
|
-
export class FsFileStandaloneImplFileAPI implements FsFileStandalone {
|
|
8
|
-
public name: string;
|
|
9
|
-
private size: number;
|
|
10
|
-
private lastModified: number;
|
|
11
|
-
private file: File;
|
|
12
|
-
|
|
13
|
-
constructor(file: File) {
|
|
14
|
-
this.name = file.name;
|
|
15
|
-
this.size = file.size;
|
|
16
|
-
this.lastModified = file.lastModified;
|
|
17
|
-
this.file = file;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
public async isWritable(): Promise<boolean> {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public async getSize(): Promise<FsResult<number>> {
|
|
25
|
-
return { val: this.size };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public async getBytes(): Promise<FsResult<Uint8Array>> {
|
|
29
|
-
try {
|
|
30
|
-
const data = await this.file.arrayBuffer();
|
|
31
|
-
return { val: new Uint8Array(data) };
|
|
32
|
-
} catch (e) {
|
|
33
|
-
ilog.error(e);
|
|
34
|
-
return { err: fsFail(errstr(e)) };
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
public async getLastModified(): Promise<FsResult<number>> {
|
|
38
|
-
return { val: this.lastModified };
|
|
39
|
-
}
|
|
40
|
-
public async getText(): Promise<FsResult<string>> {
|
|
41
|
-
try {
|
|
42
|
-
const data = await this.file.text();
|
|
43
|
-
return { val: data };
|
|
44
|
-
} catch (e) {
|
|
45
|
-
ilog.error(e);
|
|
46
|
-
return { err: fsFail(errstr(e)) };
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
public async write(): Promise<FsVoid> {
|
|
50
|
-
return {
|
|
51
|
-
err: fsErr(FsErr.NotSupported, "Write not supported in File API"),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { ilog } from "../log/internal.ts";
|
|
2
|
-
import { errstr } from "../result";
|
|
3
|
-
|
|
4
|
-
import { fsErr, FsErr, fsFail, type FsVoid, type FsResult } from "./FsError.ts";
|
|
5
|
-
import type { FsFileStandalone } from "./FsFileStandalone.ts";
|
|
6
|
-
|
|
7
|
-
export class FsFileStandaloneImplHandleAPI implements FsFileStandalone {
|
|
8
|
-
name: string;
|
|
9
|
-
private handle: FileSystemFileHandle;
|
|
10
|
-
constructor(handle: FileSystemFileHandle) {
|
|
11
|
-
this.name = handle.name;
|
|
12
|
-
this.handle = handle;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public async isWritable(): Promise<boolean> {
|
|
16
|
-
if (
|
|
17
|
-
!("queryPermission" in this.handle) ||
|
|
18
|
-
!(typeof this.handle.queryPermission === "function")
|
|
19
|
-
) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
const permission = await this.handle.queryPermission({
|
|
24
|
-
mode: "readwrite",
|
|
25
|
-
});
|
|
26
|
-
if (permission === "granted") {
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
if (permission === "denied") {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
if (
|
|
33
|
-
!("requestPermission" in this.handle) ||
|
|
34
|
-
!(typeof this.handle.requestPermission === "function")
|
|
35
|
-
) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
const requestedPermission = await this.handle.requestPermission({
|
|
39
|
-
mode: "readwrite",
|
|
40
|
-
});
|
|
41
|
-
return requestedPermission === "granted";
|
|
42
|
-
} catch (e) {
|
|
43
|
-
ilog.error(e);
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private async getFile(): Promise<FsResult<File>> {
|
|
49
|
-
try {
|
|
50
|
-
return { val: await this.handle.getFile() };
|
|
51
|
-
} catch (e) {
|
|
52
|
-
if (e && typeof e === "object" && "name" in e) {
|
|
53
|
-
if (e.name === "NotAllowedError") {
|
|
54
|
-
return {
|
|
55
|
-
err: fsErr(FsErr.PermissionDenied, "Permission denied"),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
if (e.name === "NotFoundError") {
|
|
59
|
-
return { err: fsErr(FsErr.NotFound, "File not found") };
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
ilog.error(e);
|
|
63
|
-
return { err: fsFail(errstr(e)) };
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public async getSize(): Promise<FsResult<number>> {
|
|
68
|
-
const file = await this.getFile();
|
|
69
|
-
if (file.err) {
|
|
70
|
-
return file;
|
|
71
|
-
}
|
|
72
|
-
return { val: file.val.size };
|
|
73
|
-
}
|
|
74
|
-
public async getBytes(): Promise<FsResult<Uint8Array>> {
|
|
75
|
-
const file = await this.getFile();
|
|
76
|
-
if (file.err) {
|
|
77
|
-
return file;
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
const data = await file.val.arrayBuffer();
|
|
81
|
-
return { val: new Uint8Array(data) };
|
|
82
|
-
} catch (e) {
|
|
83
|
-
ilog.error(e);
|
|
84
|
-
return { err: fsFail(errstr(e)) };
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
public async getLastModified(): Promise<FsResult<number>> {
|
|
88
|
-
const file = await this.getFile();
|
|
89
|
-
if (file.err) {
|
|
90
|
-
return file;
|
|
91
|
-
}
|
|
92
|
-
return { val: file.val.lastModified };
|
|
93
|
-
}
|
|
94
|
-
public async getText(): Promise<FsResult<string>> {
|
|
95
|
-
const file = await this.getFile();
|
|
96
|
-
if (file.err) {
|
|
97
|
-
return file;
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
const data = await file.val.text();
|
|
101
|
-
return { val: data };
|
|
102
|
-
} catch (e) {
|
|
103
|
-
ilog.error(e);
|
|
104
|
-
return { err: fsFail(errstr(e)) };
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
public async write(content: Uint8Array | string): Promise<FsVoid> {
|
|
108
|
-
const writable = await this.isWritable();
|
|
109
|
-
if (!writable) {
|
|
110
|
-
return {
|
|
111
|
-
err: fsErr(FsErr.NotSupported, "Permission was not granted or API not supported"),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
try {
|
|
115
|
-
const stream = await this.handle.createWritable();
|
|
116
|
-
await stream.write(content);
|
|
117
|
-
await stream.close();
|
|
118
|
-
return {};
|
|
119
|
-
} catch (e) {
|
|
120
|
-
if (e && typeof e === "object" && "name" in e) {
|
|
121
|
-
if (e.name === "NotAllowedError") {
|
|
122
|
-
return {
|
|
123
|
-
err: fsErr(FsErr.PermissionDenied, "Permission denied"),
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
if (e.name === "NotFoundError") {
|
|
127
|
-
return { err: fsErr(FsErr.NotFound, "File not found") };
|
|
128
|
-
}
|
|
129
|
-
if (e.name === "NoMidificationAllowedError") {
|
|
130
|
-
return {
|
|
131
|
-
err: fsErr(FsErr.PermissionDenied, "Failed to acquire write lock"),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
if (e.name === "AbortError") {
|
|
135
|
-
return { err: fsErr(FsErr.UserAbort, "User abort") };
|
|
136
|
-
}
|
|
137
|
-
if (e.name === "QuotaExceededError") {
|
|
138
|
-
return {
|
|
139
|
-
err: fsErr(FsErr.PermissionDenied, "Quota exceeded"),
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
ilog.error(e);
|
|
144
|
-
return { err: fsFail(errstr(e)) };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
package/src/fs/FsFileSystem.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { FsFile } from "./FsFile.ts";
|
|
2
|
-
import type { FsResult } from "./FsError.ts";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* File system before it is initialized
|
|
6
|
-
*
|
|
7
|
-
* This is an internal type used inside fsOpen functions
|
|
8
|
-
*/
|
|
9
|
-
export interface FsFileSystemUninit {
|
|
10
|
-
/// Initialize the file system
|
|
11
|
-
init(): Promise<FsResult<FsFileSystem>>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** Initialized file system */
|
|
15
|
-
export interface FsFileSystem {
|
|
16
|
-
/**
|
|
17
|
-
* Get the root path of the file system for display
|
|
18
|
-
*
|
|
19
|
-
* The returned string has no significance in the file system itself.
|
|
20
|
-
* It should only be used as an indicator to the user.
|
|
21
|
-
*/
|
|
22
|
-
readonly root: string;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Capabilities of this file system implementation
|
|
26
|
-
* See README.md for more information
|
|
27
|
-
*/
|
|
28
|
-
readonly capabilities: FsCapabilities;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* List files in a directory
|
|
32
|
-
*
|
|
33
|
-
* The input path should be relative to the root (of the uploaded directory).
|
|
34
|
-
*
|
|
35
|
-
* Returns a list of file names in the directory (not full paths).
|
|
36
|
-
* Directory names end with a slash.
|
|
37
|
-
*
|
|
38
|
-
* Returns Fail if the underlying file system operation fails.
|
|
39
|
-
*/
|
|
40
|
-
listDir: (path: string) => Promise<FsResult<string[]>>;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Get a file object for operations
|
|
44
|
-
*
|
|
45
|
-
* The returned object can store temporary state for the file, such
|
|
46
|
-
* as newer content. Calling openFile with the same path will
|
|
47
|
-
* return the same object.
|
|
48
|
-
*
|
|
49
|
-
* Note that opening a file doesn't actually block the file
|
|
50
|
-
* from being modified by programs other than the browser.
|
|
51
|
-
*
|
|
52
|
-
* You can make the FsFileSystem forget about the file by
|
|
53
|
-
* calling `close` on the file object.
|
|
54
|
-
*/
|
|
55
|
-
getFile: (path: string) => FsFile;
|
|
56
|
-
|
|
57
|
-
/** Get all paths that `getFile` has been called with but not `close`d */
|
|
58
|
-
getOpenedPaths: () => string[];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Capabilities of the file system implementation */
|
|
62
|
-
export type FsCapabilities = {
|
|
63
|
-
/** Can the browser directly write to the file system */
|
|
64
|
-
write: boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Can the browser detect live updates:
|
|
67
|
-
* - Change of modified time
|
|
68
|
-
* - Change of directory structure (new, renamed, deleted files)
|
|
69
|
-
*/
|
|
70
|
-
live: boolean;
|
|
71
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { FsResult, FsVoid } from "./FsError.ts";
|
|
2
|
-
|
|
3
|
-
/** Internal APIs for FsFileSystem */
|
|
4
|
-
export interface FsFileSystemInternal {
|
|
5
|
-
/**
|
|
6
|
-
* Read the file as a File object
|
|
7
|
-
*
|
|
8
|
-
* Returns Fail if the underlying file system operation fails.
|
|
9
|
-
*/
|
|
10
|
-
read: (path: string) => Promise<FsResult<File>>;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Write content to a file on disk
|
|
14
|
-
*
|
|
15
|
-
* Writes the content to the path specified.
|
|
16
|
-
* If the content is a string, UTF-8 encoding is used.
|
|
17
|
-
*
|
|
18
|
-
* Will overwrite existing file.
|
|
19
|
-
*
|
|
20
|
-
* Returns Fail if the underlying file system operation fails.
|
|
21
|
-
* Returns NotSupported if the browser does not support this
|
|
22
|
-
* Returns PermissionDenied if the operation is supported, but permission is not given
|
|
23
|
-
*/
|
|
24
|
-
write: (path: string, content: Uint8Array) => Promise<FsVoid>;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Forget about a file
|
|
28
|
-
*/
|
|
29
|
-
closeFile: (path: string) => void;
|
|
30
|
-
}
|
package/src/fs/FsImplEntryAPI.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { type Ok, tryAsync, errstr } from "../result/index.ts";
|
|
2
|
-
|
|
3
|
-
import { FsErr, type FsResult, type FsVoid, fsErr, fsFail } from "./FsError.ts";
|
|
4
|
-
import type { FsFileSystem, FsFileSystemUninit, FsCapabilities } from "./FsFileSystem.ts";
|
|
5
|
-
import type { FsFile } from "./FsFile.ts";
|
|
6
|
-
import { fsIsRoot, fsNormalize } from "./FsPath.ts";
|
|
7
|
-
import { FsFileMgr } from "./FsFileMgr.ts";
|
|
8
|
-
import type { FsFileSystemInternal } from "./FsFileSystemInternal.ts";
|
|
9
|
-
|
|
10
|
-
/** FsFileSystem implementation that uses FileEntry API */
|
|
11
|
-
export class FsImplEntryAPI implements FsFileSystemUninit, FsFileSystem, FsFileSystemInternal {
|
|
12
|
-
public root: string;
|
|
13
|
-
public capabilities: FsCapabilities;
|
|
14
|
-
|
|
15
|
-
private rootEntry: FileSystemDirectoryEntry;
|
|
16
|
-
|
|
17
|
-
private mgr: FsFileMgr;
|
|
18
|
-
|
|
19
|
-
constructor(root: string, rootEntry: FileSystemDirectoryEntry) {
|
|
20
|
-
this.root = root;
|
|
21
|
-
this.rootEntry = rootEntry;
|
|
22
|
-
this.capabilities = { write: false, live: true };
|
|
23
|
-
this.mgr = new FsFileMgr();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public init(): Promise<FsResult<FsFileSystem>> {
|
|
27
|
-
// no init needed
|
|
28
|
-
return Promise.resolve({ val: this });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public async listDir(path: string): Promise<FsResult<string[]>> {
|
|
32
|
-
const normalized = fsNormalize(path);
|
|
33
|
-
if (normalized.err) {
|
|
34
|
-
return normalized;
|
|
35
|
-
}
|
|
36
|
-
path = normalized.val;
|
|
37
|
-
|
|
38
|
-
const entry = await this.resolveDir(path);
|
|
39
|
-
if (entry.err) {
|
|
40
|
-
return entry;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const entries = await tryAsync(
|
|
44
|
-
() =>
|
|
45
|
-
new Promise<FileSystemEntry[]>((resolve, reject) => {
|
|
46
|
-
entry.val.createReader().readEntries(resolve, reject);
|
|
47
|
-
}),
|
|
48
|
-
);
|
|
49
|
-
if ("err" in entries) {
|
|
50
|
-
const err = fsFail("Failed to list directory `" + path + "`: " + errstr(entries.err));
|
|
51
|
-
return { err };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const names = entries.val.map(({ isDirectory, name }) => {
|
|
55
|
-
if (isDirectory) {
|
|
56
|
-
return name + "/";
|
|
57
|
-
}
|
|
58
|
-
return name;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return { val: names };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public async read(path: string): Promise<FsResult<File>> {
|
|
65
|
-
const normalized = fsNormalize(path);
|
|
66
|
-
if (normalized.err) {
|
|
67
|
-
return normalized;
|
|
68
|
-
}
|
|
69
|
-
path = normalized.val;
|
|
70
|
-
|
|
71
|
-
const entry = await this.resolveFile(path);
|
|
72
|
-
if (entry.err) {
|
|
73
|
-
return entry;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const file = await tryAsync(
|
|
77
|
-
() =>
|
|
78
|
-
new Promise<File>((resolve, reject) => {
|
|
79
|
-
entry.val.file(resolve, reject);
|
|
80
|
-
}),
|
|
81
|
-
);
|
|
82
|
-
if ("err" in file) {
|
|
83
|
-
const err = fsFail("Failed to read file `" + path + "`: " + errstr(file.err));
|
|
84
|
-
return { err };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return file;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
public write(): Promise<FsVoid> {
|
|
91
|
-
const err = fsErr(FsErr.NotSupported, "Write not supported in FileEntry API");
|
|
92
|
-
return Promise.resolve({ err });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public getFile(path: string): FsFile {
|
|
96
|
-
return this.mgr.get(this, path);
|
|
97
|
-
}
|
|
98
|
-
public getOpenedPaths(): string[] {
|
|
99
|
-
return this.mgr.getOpenedPaths();
|
|
100
|
-
}
|
|
101
|
-
public closeFile(path: string): void {
|
|
102
|
-
this.mgr.close(path);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** Resolve a directory entry. Path must be normalized */
|
|
106
|
-
private async resolveDir(path: string): Promise<FsResult<FileSystemDirectoryEntry>> {
|
|
107
|
-
if (fsIsRoot(path)) {
|
|
108
|
-
return { val: this.rootEntry };
|
|
109
|
-
}
|
|
110
|
-
const entry = await tryAsync(
|
|
111
|
-
() =>
|
|
112
|
-
new Promise<FileSystemEntry>((resolve, reject) => {
|
|
113
|
-
this.rootEntry.getDirectory(path, {}, resolve, reject);
|
|
114
|
-
}),
|
|
115
|
-
);
|
|
116
|
-
if ("err" in entry) {
|
|
117
|
-
const err = fsFail("Failed to resolve directory `" + path + "`: " + errstr(entry.err));
|
|
118
|
-
return { err };
|
|
119
|
-
}
|
|
120
|
-
if (!entry.val.isDirectory) {
|
|
121
|
-
const err = fsErr(FsErr.IsFile, "Path `" + path + "` is not a directory");
|
|
122
|
-
return { err };
|
|
123
|
-
}
|
|
124
|
-
return entry as Ok<FileSystemDirectoryEntry>;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Resolve a file entry. Path must be normalized */
|
|
128
|
-
private async resolveFile(path: string): Promise<FsResult<FileSystemFileEntry>> {
|
|
129
|
-
if (fsIsRoot(path)) {
|
|
130
|
-
const err = fsErr(FsErr.IsDirectory, "Path `" + path + "` is not a file");
|
|
131
|
-
return { err };
|
|
132
|
-
}
|
|
133
|
-
const entry = await tryAsync(
|
|
134
|
-
() =>
|
|
135
|
-
new Promise<FileSystemEntry>((resolve, reject) => {
|
|
136
|
-
this.rootEntry.getFile(path, {}, resolve, reject);
|
|
137
|
-
}),
|
|
138
|
-
);
|
|
139
|
-
if ("err" in entry) {
|
|
140
|
-
const err = fsFail("Failed to resolve file `" + path + "`: " + errstr(entry.err));
|
|
141
|
-
return { err };
|
|
142
|
-
}
|
|
143
|
-
if (!entry.val.isFile) {
|
|
144
|
-
const err = fsErr(FsErr.IsDirectory, "Path `" + path + "` is not a file");
|
|
145
|
-
return { err };
|
|
146
|
-
}
|
|
147
|
-
return entry as Ok<FileSystemFileEntry>;
|
|
148
|
-
}
|
|
149
|
-
}
|
package/src/fs/FsImplFileAPI.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { ilog } from "../log/internal.ts";
|
|
2
|
-
|
|
3
|
-
import type { FsFile } from "./FsFile.ts";
|
|
4
|
-
import type { FsFileSystem, FsFileSystemUninit, FsCapabilities } from "./FsFileSystem.ts";
|
|
5
|
-
import { FsErr, type FsResult, type FsVoid, fsErr } from "./FsError.ts";
|
|
6
|
-
import { fsIsRoot, fsNormalize } from "./FsPath.ts";
|
|
7
|
-
import { FsFileMgr } from "./FsFileMgr.ts";
|
|
8
|
-
import type { FsFileSystemInternal } from "./FsFileSystemInternal.ts";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* FileSystem implementation that uses a list of Files
|
|
12
|
-
* This is supported in all browsers, but it is stale.
|
|
13
|
-
* It's used for Firefox when the File Entries API is not available
|
|
14
|
-
* i.e. opened from <input type="file">
|
|
15
|
-
*/
|
|
16
|
-
export class FsImplFileAPI implements FsFileSystemUninit, FsFileSystem, FsFileSystemInternal {
|
|
17
|
-
public root: string;
|
|
18
|
-
public capabilities: FsCapabilities;
|
|
19
|
-
|
|
20
|
-
private files: Record<string, File>;
|
|
21
|
-
private directories: Record<string, string[]>;
|
|
22
|
-
private mgr: FsFileMgr;
|
|
23
|
-
|
|
24
|
-
constructor(files: FileList) {
|
|
25
|
-
// this seems to also work for windows
|
|
26
|
-
this.root = files[0].webkitRelativePath.split("/", 1)[0];
|
|
27
|
-
this.capabilities = { write: false, live: false };
|
|
28
|
-
this.files = {};
|
|
29
|
-
this.directories = {};
|
|
30
|
-
this.mgr = new FsFileMgr();
|
|
31
|
-
|
|
32
|
-
for (let i = 0; i < files.length; i++) {
|
|
33
|
-
const file = files[i];
|
|
34
|
-
// remove "<root>/"
|
|
35
|
-
const path = file.webkitRelativePath.slice(this.root.length + 1);
|
|
36
|
-
const normalized = fsNormalize(path);
|
|
37
|
-
if (normalized.err) {
|
|
38
|
-
// shouldn't happen since the path is from the File API
|
|
39
|
-
ilog.error("invalid path: " + path);
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
this.files[normalized.val] = file;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public init(): Promise<FsResult<FsFileSystem>> {
|
|
47
|
-
// no init needed
|
|
48
|
-
return Promise.resolve({ val: this });
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public listDir(path: string): Promise<FsResult<string[]>> {
|
|
52
|
-
const normalized = fsNormalize(path);
|
|
53
|
-
if (normalized.err) {
|
|
54
|
-
return Promise.resolve(normalized);
|
|
55
|
-
}
|
|
56
|
-
path = normalized.val;
|
|
57
|
-
|
|
58
|
-
if (path in this.directories) {
|
|
59
|
-
return Promise.resolve({ val: this.directories[path] });
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const set = new Set<string>();
|
|
63
|
-
const prefix = fsIsRoot(path) ? "" : path + "/";
|
|
64
|
-
|
|
65
|
-
Object.keys(this.files).forEach((path) => {
|
|
66
|
-
if (!path.startsWith(prefix)) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
const relPath = path.slice(prefix.length);
|
|
70
|
-
const slashIndex = relPath.indexOf("/");
|
|
71
|
-
if (slashIndex < 0) {
|
|
72
|
-
// file
|
|
73
|
-
set.add(relPath);
|
|
74
|
-
} else {
|
|
75
|
-
// directory
|
|
76
|
-
const dir = relPath.slice(0, slashIndex + 1);
|
|
77
|
-
set.add(dir);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const paths = Array.from(set);
|
|
82
|
-
this.directories[path] = paths;
|
|
83
|
-
|
|
84
|
-
return Promise.resolve({ val: paths });
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public read(path: string): Promise<FsResult<File>> {
|
|
88
|
-
const normalized = fsNormalize(path);
|
|
89
|
-
if (normalized.err) {
|
|
90
|
-
return Promise.resolve(normalized);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const file = this.files[normalized.val];
|
|
94
|
-
if (!file) {
|
|
95
|
-
const err = fsErr(FsErr.NotFound, "File not found: " + path);
|
|
96
|
-
return Promise.resolve({ err });
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return Promise.resolve({ val: file });
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
public write(): Promise<FsVoid> {
|
|
103
|
-
const err = fsErr(FsErr.NotSupported, "Write not supported in File API");
|
|
104
|
-
return Promise.resolve({ err });
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public getFile(path: string): FsFile {
|
|
108
|
-
return this.mgr.get(this, path);
|
|
109
|
-
}
|
|
110
|
-
public getOpenedPaths(): string[] {
|
|
111
|
-
return this.mgr.getOpenedPaths();
|
|
112
|
-
}
|
|
113
|
-
public closeFile(path: string): void {
|
|
114
|
-
this.mgr.close(path);
|
|
115
|
-
}
|
|
116
|
-
}
|