@pistonite/pure 0.0.12
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 +21 -0
- package/README.md +8 -0
- package/package.json +33 -0
- package/src/fs/FsError.ts +55 -0
- package/src/fs/FsFile.ts +67 -0
- package/src/fs/FsFileImpl.ts +225 -0
- package/src/fs/FsFileMgr.ts +29 -0
- package/src/fs/FsFileSystem.ts +71 -0
- package/src/fs/FsFileSystemInternal.ts +30 -0
- package/src/fs/FsImplEntryAPI.ts +188 -0
- package/src/fs/FsImplFileAPI.ts +126 -0
- package/src/fs/FsImplHandleAPI.ts +237 -0
- package/src/fs/FsOpen.ts +307 -0
- package/src/fs/FsPath.ts +137 -0
- package/src/fs/FsSave.ts +12 -0
- package/src/fs/FsSupportStatus.ts +91 -0
- package/src/fs/index.ts +129 -0
- package/src/log/index.ts +56 -0
- package/src/pref/dark.ts +184 -0
- package/src/pref/index.ts +12 -0
- package/src/pref/injectStyle.ts +22 -0
- package/src/pref/locale.ts +341 -0
- package/src/result/index.ts +215 -0
- package/src/sync/Debounce.ts +35 -0
- package/src/sync/Latest.ts +75 -0
- package/src/sync/RwLock.ts +95 -0
- package/src/sync/Serial.ts +170 -0
- package/src/sync/index.ts +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2025 Michael
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pistonite/pure",
|
|
3
|
+
"version": "0.0.12",
|
|
4
|
+
"description": "Pure TypeScript libraries for my projects",
|
|
5
|
+
"homepage": "https://github.com/Pistonite/pure",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/Pistonite/pure/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "Pistonight <pistonknight@outlook.com>",
|
|
11
|
+
"files": [
|
|
12
|
+
"src/**/*"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
"./fs": "./src/fs/index.ts",
|
|
16
|
+
"./log": "./src/log/index.ts",
|
|
17
|
+
"./result": "./src/result/index.ts",
|
|
18
|
+
"./sync": "./src/sync/index.ts",
|
|
19
|
+
"./pref": "./src/pref/index.ts"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Pistonite/pure.git",
|
|
24
|
+
"directory": "packages/pure"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"denque": "2.1.0",
|
|
28
|
+
"file-saver": "2.0.5"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/file-saver": "^2.0.7"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Result, Void } from "../result/index.ts";
|
|
2
|
+
|
|
3
|
+
/** Result type for file system operations */
|
|
4
|
+
export const FsErr = {
|
|
5
|
+
/** Generic error */
|
|
6
|
+
Fail: 1,
|
|
7
|
+
/** The operation does not apply to the root directory */
|
|
8
|
+
IsRoot: 2,
|
|
9
|
+
/** Invalid encoding */
|
|
10
|
+
InvalidEncoding: 3,
|
|
11
|
+
/** Not supported */
|
|
12
|
+
NotSupported: 4,
|
|
13
|
+
/** The operation does not apply to a file */
|
|
14
|
+
IsFile: 5,
|
|
15
|
+
/** The file was not modified since the last check */
|
|
16
|
+
NotModified: 6,
|
|
17
|
+
/** Permission error */
|
|
18
|
+
PermissionDenied: 7,
|
|
19
|
+
/** User abort */
|
|
20
|
+
UserAbort: 8,
|
|
21
|
+
/** Not found */
|
|
22
|
+
NotFound: 9,
|
|
23
|
+
/** Trying to do stuff to a closed file */
|
|
24
|
+
IsClosed: 10,
|
|
25
|
+
/** If the path is invalid, for example trying to get the parent of root */
|
|
26
|
+
InvalidPath: 11,
|
|
27
|
+
/** Trying to operate on a file that has been closed */
|
|
28
|
+
Closed: 12,
|
|
29
|
+
/** The operation does not apply to a directory */
|
|
30
|
+
IsDirectory: 5,
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
/** Result type for file system operations */
|
|
34
|
+
export type FsErr = (typeof FsErr)[keyof typeof FsErr];
|
|
35
|
+
|
|
36
|
+
/** Fs error type with a code and message */
|
|
37
|
+
export type FsError = {
|
|
38
|
+
readonly code: FsErr;
|
|
39
|
+
readonly message: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Helper to create a FsError */
|
|
43
|
+
export function fsErr(code: FsErr, message: string): FsError {
|
|
44
|
+
return { code, message };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Helper to create a FsError with the code Fail */
|
|
48
|
+
export function fsFail(message: string): FsError {
|
|
49
|
+
return fsErr(FsErr.Fail, message);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Helper result type for FsError */
|
|
53
|
+
export type FsResult<T> = Result<T, FsError>;
|
|
54
|
+
/** Helper result type for FsError with no value */
|
|
55
|
+
export type FsVoid = Void<FsError>;
|
package/src/fs/FsFile.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { FsResult, FsVoid } from "./FsError.ts";
|
|
2
|
+
|
|
3
|
+
/** Interface for operating on a file in the loaded file system */
|
|
4
|
+
export interface FsFile {
|
|
5
|
+
/** Path of the file relative to the root of the file system (the uploaded directory) */
|
|
6
|
+
readonly path: string;
|
|
7
|
+
|
|
8
|
+
/** Returns if the content of the file in memory is newer than the file on disk */
|
|
9
|
+
isDirty(): boolean;
|
|
10
|
+
|
|
11
|
+
/** Get the last modified time. May load it from file system if needed */
|
|
12
|
+
getLastModified(): Promise<FsResult<number>>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the text content of the file
|
|
16
|
+
*
|
|
17
|
+
* If the file is not loaded, it will load it.
|
|
18
|
+
*
|
|
19
|
+
* If the file is not a text file, it will return InvalidEncoding
|
|
20
|
+
*/
|
|
21
|
+
getText(): Promise<FsResult<string>>;
|
|
22
|
+
|
|
23
|
+
/** Get the content of the file */
|
|
24
|
+
getBytes(): Promise<FsResult<Uint8Array>>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Set the content in memory. Does not save to disk.
|
|
28
|
+
* Does nothing if file is closed
|
|
29
|
+
*/
|
|
30
|
+
setText(content: string): void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Set the content in memory. Does not save to disk.
|
|
34
|
+
* Does nothing if file is closed
|
|
35
|
+
*/
|
|
36
|
+
setBytes(content: Uint8Array): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Load the file's content if it's not newer than fs
|
|
40
|
+
*
|
|
41
|
+
* Returns Ok if the file is newer than fs
|
|
42
|
+
*/
|
|
43
|
+
loadIfNotDirty(): Promise<FsVoid>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Load the file's content from FS.
|
|
47
|
+
*
|
|
48
|
+
* Overwrites any unsaved changes in memory only if the file was modified
|
|
49
|
+
* at a later time than the last in memory modification.
|
|
50
|
+
*
|
|
51
|
+
* If it fails, the file's content in memory will not be changed
|
|
52
|
+
*/
|
|
53
|
+
load(): Promise<FsVoid>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Save the file's content to FS if it is dirty.
|
|
57
|
+
*
|
|
58
|
+
* If not dirty, returns Ok
|
|
59
|
+
*/
|
|
60
|
+
writeIfNewer(): Promise<FsVoid>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Close the file. In memory content will be lost.
|
|
64
|
+
* Further operations on the file will fail
|
|
65
|
+
*/
|
|
66
|
+
close(): void;
|
|
67
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { tryAsync, errstr } from "../result/index.ts";
|
|
2
|
+
|
|
3
|
+
import type { FsFile } from "./FsFile.ts";
|
|
4
|
+
import type { FsFileSystemInternal } from "./FsFileSystemInternal.ts";
|
|
5
|
+
import { FsErr, type FsResult, type FsVoid, fsErr, fsFail } from "./FsError.ts";
|
|
6
|
+
|
|
7
|
+
/** Allocate a new file object */
|
|
8
|
+
export function fsFile(fs: FsFileSystemInternal, path: string): FsFile {
|
|
9
|
+
return new FsFileImpl(fs, path);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function errclosed() {
|
|
13
|
+
return { err: fsErr(FsErr.Closed, "File is closed") } as const;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class FsFileImpl implements FsFile {
|
|
17
|
+
/** The path of the file */
|
|
18
|
+
public path: string;
|
|
19
|
+
|
|
20
|
+
private closed: boolean;
|
|
21
|
+
|
|
22
|
+
/** Reference to the file system so we can read/write */
|
|
23
|
+
private fs: FsFileSystemInternal;
|
|
24
|
+
/** If the file is text */
|
|
25
|
+
private isText: boolean;
|
|
26
|
+
/** Bytes of the file */
|
|
27
|
+
private buffer: Uint8Array | undefined;
|
|
28
|
+
/** If the content in the buffer is different from the content on FS */
|
|
29
|
+
private isBufferDirty: boolean;
|
|
30
|
+
/** The content string of the file */
|
|
31
|
+
private content: string | undefined;
|
|
32
|
+
/** If the content string is newer than the bytes */
|
|
33
|
+
private isContentNewer: boolean;
|
|
34
|
+
/** The last modified time of the file */
|
|
35
|
+
private lastModified: number | undefined;
|
|
36
|
+
|
|
37
|
+
constructor(fs: FsFileSystemInternal, path: string) {
|
|
38
|
+
this.closed = false;
|
|
39
|
+
this.fs = fs;
|
|
40
|
+
this.path = path;
|
|
41
|
+
this.isText = false;
|
|
42
|
+
this.buffer = undefined;
|
|
43
|
+
this.isBufferDirty = false;
|
|
44
|
+
this.content = undefined;
|
|
45
|
+
this.isContentNewer = false;
|
|
46
|
+
this.lastModified = undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public close(): void {
|
|
50
|
+
this.closed = true;
|
|
51
|
+
this.fs.closeFile(this.path);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public isDirty(): boolean {
|
|
55
|
+
return this.isBufferDirty || this.isContentNewer;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public async getLastModified(): Promise<FsResult<number>> {
|
|
59
|
+
if (this.closed) {
|
|
60
|
+
return errclosed();
|
|
61
|
+
}
|
|
62
|
+
if (this.lastModified === undefined) {
|
|
63
|
+
const r = await this.loadIfNotDirty();
|
|
64
|
+
if (r.err) {
|
|
65
|
+
return r;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { val: this.lastModified ?? 0 };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public async getText(): Promise<FsResult<string>> {
|
|
72
|
+
if (this.closed) {
|
|
73
|
+
return errclosed();
|
|
74
|
+
}
|
|
75
|
+
if (this.buffer === undefined) {
|
|
76
|
+
const r = await this.load();
|
|
77
|
+
if (r.err) {
|
|
78
|
+
return r;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!this.isText) {
|
|
82
|
+
const err = fsFail("File is not valid UTF-8");
|
|
83
|
+
return { err };
|
|
84
|
+
}
|
|
85
|
+
return { val: this.content ?? "" };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public async getBytes(): Promise<FsResult<Uint8Array>> {
|
|
89
|
+
if (this.closed) {
|
|
90
|
+
return errclosed();
|
|
91
|
+
}
|
|
92
|
+
this.updateBuffer();
|
|
93
|
+
if (this.buffer === undefined) {
|
|
94
|
+
const r = await this.load();
|
|
95
|
+
if (r.err) {
|
|
96
|
+
return r;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (this.buffer === undefined) {
|
|
100
|
+
const err = fsFail(
|
|
101
|
+
"Read was successful, but content was undefined",
|
|
102
|
+
);
|
|
103
|
+
return { err };
|
|
104
|
+
}
|
|
105
|
+
return { val: this.buffer };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public setText(content: string): void {
|
|
109
|
+
if (this.closed) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (this.content === content) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.content = content;
|
|
116
|
+
this.isContentNewer = true;
|
|
117
|
+
this.lastModified = new Date().getTime();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public setBytes(content: Uint8Array): void {
|
|
121
|
+
if (this.closed) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.buffer = content;
|
|
125
|
+
this.isBufferDirty = true;
|
|
126
|
+
this.decodeBuffer();
|
|
127
|
+
this.isContentNewer = true;
|
|
128
|
+
this.lastModified = new Date().getTime();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public async loadIfNotDirty(): Promise<FsVoid> {
|
|
132
|
+
if (this.closed) {
|
|
133
|
+
return errclosed();
|
|
134
|
+
}
|
|
135
|
+
if (this.isDirty()) {
|
|
136
|
+
return {};
|
|
137
|
+
}
|
|
138
|
+
return await this.load();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public async load(): Promise<FsVoid> {
|
|
142
|
+
if (this.closed) {
|
|
143
|
+
return errclosed();
|
|
144
|
+
}
|
|
145
|
+
const { val: file, err } = await this.fs.read(this.path);
|
|
146
|
+
if (err) {
|
|
147
|
+
return { err };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// check if the file has been modified since last loaded
|
|
151
|
+
if (this.lastModified !== undefined) {
|
|
152
|
+
if (file.lastModified <= this.lastModified) {
|
|
153
|
+
return {};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
this.lastModified = file.lastModified;
|
|
157
|
+
// load the buffer
|
|
158
|
+
const buffer = await tryAsync(
|
|
159
|
+
async () => new Uint8Array(await file.arrayBuffer()),
|
|
160
|
+
);
|
|
161
|
+
if ("err" in buffer) {
|
|
162
|
+
const err = fsFail(errstr(buffer.err));
|
|
163
|
+
return { err };
|
|
164
|
+
}
|
|
165
|
+
this.buffer = buffer.val;
|
|
166
|
+
this.isBufferDirty = false;
|
|
167
|
+
// Try decoding the buffer as text
|
|
168
|
+
this.decodeBuffer();
|
|
169
|
+
this.isContentNewer = false;
|
|
170
|
+
return {};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public async writeIfNewer(): Promise<FsVoid> {
|
|
174
|
+
if (this.closed) {
|
|
175
|
+
return errclosed();
|
|
176
|
+
}
|
|
177
|
+
if (!this.isDirty()) {
|
|
178
|
+
return {};
|
|
179
|
+
}
|
|
180
|
+
return await this.write();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Write the content without checking if it's dirty. Overwrites the file currently on FS
|
|
185
|
+
*
|
|
186
|
+
* This is private - outside code should only use writeIfDirty
|
|
187
|
+
*/
|
|
188
|
+
private async write(): Promise<FsVoid> {
|
|
189
|
+
this.updateBuffer();
|
|
190
|
+
const buffer = this.buffer;
|
|
191
|
+
if (this.content === undefined || buffer === undefined) {
|
|
192
|
+
// file was never read or modified
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
const result = await this.fs.write(this.path, buffer);
|
|
196
|
+
if (result.err) {
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
this.isBufferDirty = false;
|
|
200
|
+
return {};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private decodeBuffer() {
|
|
204
|
+
try {
|
|
205
|
+
this.content = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
206
|
+
this.buffer,
|
|
207
|
+
);
|
|
208
|
+
this.isText = true;
|
|
209
|
+
} catch (_) {
|
|
210
|
+
this.content = undefined;
|
|
211
|
+
this.isText = false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Encode the content to buffer if it is newer */
|
|
216
|
+
private updateBuffer() {
|
|
217
|
+
if (!this.isContentNewer || this.content === undefined) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const encoder = new TextEncoder();
|
|
221
|
+
this.buffer = encoder.encode(this.content);
|
|
222
|
+
this.isBufferDirty = true;
|
|
223
|
+
this.isContentNewer = false;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FsFile } from "./FsFile.ts";
|
|
2
|
+
import type { FsFileSystemInternal } from "./FsFileSystemInternal.ts";
|
|
3
|
+
import { fsFile } from "./FsFileImpl.ts";
|
|
4
|
+
|
|
5
|
+
/** Internal class to track opened files */
|
|
6
|
+
export class FsFileMgr {
|
|
7
|
+
private opened: { [path: string]: FsFile };
|
|
8
|
+
|
|
9
|
+
public constructor() {
|
|
10
|
+
this.opened = {};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public get(fs: FsFileSystemInternal, path: string): FsFile {
|
|
14
|
+
let file = this.opened[path];
|
|
15
|
+
if (!file) {
|
|
16
|
+
file = fsFile(fs, path);
|
|
17
|
+
this.opened[path] = file;
|
|
18
|
+
}
|
|
19
|
+
return file;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public close(path: string): void {
|
|
23
|
+
delete this.opened[path];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public getOpenedPaths(): string[] {
|
|
27
|
+
return Object.keys(this.opened);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
}
|