@zenfs/dom 1.0.6 → 1.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/dist/IndexedDB.d.ts +4 -4
- package/dist/access.d.ts +3 -4
- package/dist/access.js +9 -6
- package/dist/devices/dsp.js +3 -2
- package/dist/devices/framebuffer.d.ts +9 -1
- package/dist/devices/framebuffer.js +33 -27
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/{Storage.d.ts → storage.d.ts} +1 -2
- package/dist/{Storage.js → storage.js} +2 -6
- package/dist/xml.d.ts +54 -0
- package/dist/xml.js +177 -0
- package/package.json +4 -4
- package/readme.md +41 -6
package/dist/IndexedDB.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SharedConfig, Store } from '@zenfs/core';
|
|
2
|
-
import {
|
|
1
|
+
import type { AsyncMixin, SharedConfig, Store } from '@zenfs/core';
|
|
2
|
+
import { AsyncTransaction, StoreFS } from '@zenfs/core';
|
|
3
3
|
/**
|
|
4
4
|
* @hidden
|
|
5
5
|
*/
|
|
@@ -53,10 +53,10 @@ declare const _IndexedDB: {
|
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
readonly isAvailable: (idbFactory?: IDBFactory) => Promise<boolean>;
|
|
56
|
-
readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<
|
|
56
|
+
readonly create: (options: IndexedDBOptions & Partial<SharedConfig>) => Promise<AsyncMixin & StoreFS<IndexedDBStore>>;
|
|
57
57
|
};
|
|
58
58
|
type _IndexedDB = typeof _IndexedDB;
|
|
59
|
-
interface IndexedDB extends _IndexedDB {
|
|
59
|
+
export interface IndexedDB extends _IndexedDB {
|
|
60
60
|
}
|
|
61
61
|
export declare const IndexedDB: IndexedDB;
|
|
62
62
|
export {};
|
package/dist/access.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { FileSystemMetadata } from '@zenfs/core';
|
|
2
|
-
import {
|
|
2
|
+
import { FileSystem, PreloadFile, Stats } from '@zenfs/core';
|
|
3
3
|
export interface WebAccessOptions {
|
|
4
4
|
handle: FileSystemDirectoryHandle;
|
|
5
5
|
}
|
|
6
|
-
declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof FileSystem,
|
|
6
|
+
declare const WebAccessFS_base: import("@zenfs/core").Mixin<typeof FileSystem, import("@zenfs/core").AsyncMixin>;
|
|
7
7
|
export declare class WebAccessFS extends WebAccessFS_base {
|
|
8
8
|
private _handles;
|
|
9
9
|
/**
|
|
@@ -31,14 +31,13 @@ declare const _WebAccess: {
|
|
|
31
31
|
readonly handle: {
|
|
32
32
|
readonly type: "object";
|
|
33
33
|
readonly required: true;
|
|
34
|
-
readonly description: "The directory handle to use for the root";
|
|
35
34
|
};
|
|
36
35
|
};
|
|
37
36
|
readonly isAvailable: () => boolean;
|
|
38
37
|
readonly create: (options: WebAccessOptions) => WebAccessFS;
|
|
39
38
|
};
|
|
40
39
|
type _WebAccess = typeof _WebAccess;
|
|
41
|
-
interface WebAccess extends _WebAccess {
|
|
40
|
+
export interface WebAccess extends _WebAccess {
|
|
42
41
|
}
|
|
43
42
|
export declare const WebAccess: WebAccess;
|
|
44
43
|
export {};
|
package/dist/access.js
CHANGED
|
@@ -2,6 +2,13 @@ import { Async, Errno, ErrnoError, FileSystem, InMemory, PreloadFile, Stats } fr
|
|
|
2
2
|
import { S_IFDIR, S_IFREG } from '@zenfs/core/emulation/constants.js';
|
|
3
3
|
import { basename, dirname, join } from '@zenfs/core/emulation/path.js';
|
|
4
4
|
import { convertException } from './utils.js';
|
|
5
|
+
function isResizable(buffer) {
|
|
6
|
+
if (buffer instanceof ArrayBuffer)
|
|
7
|
+
return buffer.resizable;
|
|
8
|
+
if (buffer instanceof SharedArrayBuffer)
|
|
9
|
+
return buffer.growable;
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
5
12
|
export class WebAccessFS extends Async(FileSystem) {
|
|
6
13
|
constructor(handle) {
|
|
7
14
|
super();
|
|
@@ -55,7 +62,7 @@ export class WebAccessFS extends Async(FileSystem) {
|
|
|
55
62
|
await this.unlink(oldPath);
|
|
56
63
|
}
|
|
57
64
|
async writeFile(path, data) {
|
|
58
|
-
if (data.buffer
|
|
65
|
+
if (isResizable(data.buffer)) {
|
|
59
66
|
throw new ErrnoError(Errno.EINVAL, 'Resizable buffers can not be written', path, 'write');
|
|
60
67
|
}
|
|
61
68
|
const handle = await this.getHandle(dirname(path));
|
|
@@ -171,11 +178,7 @@ export class WebAccessFS extends Async(FileSystem) {
|
|
|
171
178
|
const _WebAccess = {
|
|
172
179
|
name: 'WebAccess',
|
|
173
180
|
options: {
|
|
174
|
-
handle: {
|
|
175
|
-
type: 'object',
|
|
176
|
-
required: true,
|
|
177
|
-
description: 'The directory handle to use for the root',
|
|
178
|
-
},
|
|
181
|
+
handle: { type: 'object', required: true },
|
|
179
182
|
},
|
|
180
183
|
isAvailable() {
|
|
181
184
|
return typeof FileSystemHandle == 'function';
|
package/dist/devices/dsp.js
CHANGED
|
@@ -40,14 +40,15 @@ export async function dsp(options = {}) {
|
|
|
40
40
|
});
|
|
41
41
|
return {
|
|
42
42
|
name: 'dsp',
|
|
43
|
-
|
|
43
|
+
singleton: true,
|
|
44
|
+
init(ino, options) {
|
|
44
45
|
return { data: dsp, major: 14, minor: 3 };
|
|
45
46
|
},
|
|
46
47
|
read() {
|
|
47
48
|
return 0;
|
|
48
49
|
},
|
|
49
50
|
write(file, data) {
|
|
50
|
-
|
|
51
|
+
file.device.data.port.postMessage(data.buffer);
|
|
51
52
|
return data.byteLength;
|
|
52
53
|
},
|
|
53
54
|
};
|
|
@@ -2,4 +2,12 @@ import type { DeviceDriver } from '@zenfs/core';
|
|
|
2
2
|
export interface FramebufferOptions {
|
|
3
3
|
canvas?: HTMLCanvasElement | null;
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* A frame buffer
|
|
7
|
+
*
|
|
8
|
+
* Setup:
|
|
9
|
+
* ```
|
|
10
|
+
* addDevice(framebuffer, { canvas: document.querySelector('#your-canvas') })
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare const framebuffer: DeviceDriver<CanvasRenderingContext2D>;
|
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
/* Credit: David Konsumer */
|
|
2
1
|
import { Errno, ErrnoError } from '@zenfs/core';
|
|
3
2
|
let framebufferN = 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
/**
|
|
4
|
+
* A frame buffer
|
|
5
|
+
*
|
|
6
|
+
* Setup:
|
|
7
|
+
* ```
|
|
8
|
+
* addDevice(framebuffer, { canvas: document.querySelector('#your-canvas') })
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export const framebuffer = {
|
|
12
|
+
name: 'framebuffer',
|
|
13
|
+
init(ino, { canvas } = {}) {
|
|
14
|
+
if (!canvas) {
|
|
15
|
+
canvas = document.createElement('canvas');
|
|
16
|
+
document.body.appendChild(canvas);
|
|
17
|
+
}
|
|
18
|
+
const ctx = canvas.getContext('2d');
|
|
19
|
+
if (!ctx) {
|
|
20
|
+
throw new ErrnoError(Errno.EIO, 'Could not get context from canvas whilst initializing frame buffer.');
|
|
21
|
+
}
|
|
22
|
+
return { data: ctx, major: 29, minor: framebufferN++, name: 'fb' };
|
|
23
|
+
},
|
|
24
|
+
read() {
|
|
25
|
+
return 0;
|
|
26
|
+
},
|
|
27
|
+
write(file, data) {
|
|
28
|
+
const { width, height } = file.device.data.canvas;
|
|
29
|
+
if (data.byteLength < 4 * width * height) {
|
|
19
30
|
return 0;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
ctx.putImageData(imageData, 0, 0);
|
|
27
|
-
return data.byteLength;
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
+
}
|
|
32
|
+
const imageData = new ImageData(new Uint8ClampedArray(data), width, height);
|
|
33
|
+
file.device.data.putImageData(imageData, 0, 0);
|
|
34
|
+
return data.byteLength;
|
|
35
|
+
},
|
|
36
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -34,7 +34,6 @@ declare const _WebStorage: {
|
|
|
34
34
|
readonly storage: {
|
|
35
35
|
readonly type: "object";
|
|
36
36
|
readonly required: false;
|
|
37
|
-
readonly description: "The Storage to use. Defaults to globalThis.localStorage.";
|
|
38
37
|
};
|
|
39
38
|
};
|
|
40
39
|
/**
|
|
@@ -44,7 +43,7 @@ declare const _WebStorage: {
|
|
|
44
43
|
readonly create: ({ storage }: WebStorageOptions) => StoreFS<WebStorageStore>;
|
|
45
44
|
};
|
|
46
45
|
type _WebStorage = typeof _WebStorage;
|
|
47
|
-
interface WebStorage extends _WebStorage {
|
|
46
|
+
export interface WebStorage extends _WebStorage {
|
|
48
47
|
}
|
|
49
48
|
export declare const WebStorage: WebStorage;
|
|
50
49
|
export {};
|
|
@@ -9,6 +9,7 @@ export class WebStorageStore {
|
|
|
9
9
|
constructor(storage) {
|
|
10
10
|
this.storage = storage;
|
|
11
11
|
}
|
|
12
|
+
/* node:coverage ignore next 10 */
|
|
12
13
|
clear() {
|
|
13
14
|
this.storage.clear();
|
|
14
15
|
}
|
|
@@ -17,7 +18,6 @@ export class WebStorageStore {
|
|
|
17
18
|
}
|
|
18
19
|
async sync() { }
|
|
19
20
|
transaction() {
|
|
20
|
-
// No need to differentiate.
|
|
21
21
|
return new SimpleTransaction(this);
|
|
22
22
|
}
|
|
23
23
|
keys() {
|
|
@@ -53,11 +53,7 @@ export class WebStorageStore {
|
|
|
53
53
|
const _WebStorage = {
|
|
54
54
|
name: 'WebStorage',
|
|
55
55
|
options: {
|
|
56
|
-
storage: {
|
|
57
|
-
type: 'object',
|
|
58
|
-
required: false,
|
|
59
|
-
description: 'The Storage to use. Defaults to globalThis.localStorage.',
|
|
60
|
-
},
|
|
56
|
+
storage: { type: 'object', required: false },
|
|
61
57
|
},
|
|
62
58
|
/**
|
|
63
59
|
* @todo Consider replacing `instanceof` with a duck-typing check?
|
package/dist/xml.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { File, StatsLike } from '@zenfs/core';
|
|
2
|
+
import { FileSystem, Stats } from '@zenfs/core';
|
|
3
|
+
export interface XMLOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The root `fs` element
|
|
6
|
+
*/
|
|
7
|
+
root?: Element;
|
|
8
|
+
}
|
|
9
|
+
declare const XMLFS_base: import("@zenfs/core").Mixin<typeof FileSystem, import("utilium").ExtractProperties<FileSystem, (...args: any[]) => Promise<unknown>>>;
|
|
10
|
+
export declare class XMLFS extends XMLFS_base {
|
|
11
|
+
/**
|
|
12
|
+
* @inheritdoc XMLOptions.root
|
|
13
|
+
*/
|
|
14
|
+
readonly root: Element;
|
|
15
|
+
constructor(
|
|
16
|
+
/**
|
|
17
|
+
* @inheritdoc XMLOptions.root
|
|
18
|
+
*/
|
|
19
|
+
root?: Element);
|
|
20
|
+
renameSync(oldPath: string, newPath: string): void;
|
|
21
|
+
statSync(path: string): Stats;
|
|
22
|
+
openFileSync(path: string, flag: string): File;
|
|
23
|
+
createFileSync(path: string, flag: string, mode: number): File;
|
|
24
|
+
unlinkSync(path: string): void;
|
|
25
|
+
rmdirSync(path: string): void;
|
|
26
|
+
mkdirSync(path: string, mode: number): void;
|
|
27
|
+
readdirSync(path: string): string[];
|
|
28
|
+
linkSync(target: string, link: string): void;
|
|
29
|
+
syncSync(path: string, data: Uint8Array, stats: Readonly<Stats>): void;
|
|
30
|
+
toString(): string;
|
|
31
|
+
protected get(syscall: string, path: string): Element;
|
|
32
|
+
protected create(syscall: string, path: string, stats?: Partial<StatsLike<number>>): Element;
|
|
33
|
+
protected add(syscall: string, node: Element, path: string, contents?: boolean): void;
|
|
34
|
+
protected remove(syscall: string, node: Element, path: string, contents?: boolean): void;
|
|
35
|
+
}
|
|
36
|
+
declare const _XML: {
|
|
37
|
+
name: string;
|
|
38
|
+
options: {
|
|
39
|
+
root: {
|
|
40
|
+
type: "object";
|
|
41
|
+
required: false;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
isAvailable(): boolean;
|
|
45
|
+
create(options: XMLOptions): XMLFS;
|
|
46
|
+
};
|
|
47
|
+
type _XML = typeof _XML;
|
|
48
|
+
export interface XML extends _XML {
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @experimental
|
|
52
|
+
*/
|
|
53
|
+
export declare const XML: XML;
|
|
54
|
+
export {};
|
package/dist/xml.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { decodeRaw, encodeRaw, Errno, ErrnoError, FileSystem, PreloadFile, Stats, Sync } from '@zenfs/core';
|
|
2
|
+
import { S_IFDIR, S_IFREG } from '@zenfs/core/emulation/constants.js';
|
|
3
|
+
import { basename, dirname } from '@zenfs/core/path';
|
|
4
|
+
const statsLikeKeys = ['size', 'mode', 'atimeMs', 'mtimeMs', 'ctimeMs', 'birthtimeMs', 'uid', 'gid', 'ino', 'nlink'];
|
|
5
|
+
function get_stats(node) {
|
|
6
|
+
const stats = {};
|
|
7
|
+
for (const key of statsLikeKeys) {
|
|
8
|
+
const value = node.getAttribute(key);
|
|
9
|
+
stats[key] = value != null ? parseInt(value, 16) : undefined;
|
|
10
|
+
}
|
|
11
|
+
return new Stats(stats);
|
|
12
|
+
}
|
|
13
|
+
function set_stats(node, stats) {
|
|
14
|
+
for (const key of statsLikeKeys) {
|
|
15
|
+
if (stats[key] != undefined) {
|
|
16
|
+
node.setAttribute(key, stats[key].toString(16));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function get_paths(node, contents = false) {
|
|
21
|
+
let paths;
|
|
22
|
+
try {
|
|
23
|
+
const raw = contents ? node.textContent : node.getAttribute('paths');
|
|
24
|
+
paths = JSON.parse(raw || '[]');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
paths = [];
|
|
28
|
+
}
|
|
29
|
+
return paths;
|
|
30
|
+
}
|
|
31
|
+
export class XMLFS extends Sync(FileSystem) {
|
|
32
|
+
constructor(
|
|
33
|
+
/**
|
|
34
|
+
* @inheritdoc XMLOptions.root
|
|
35
|
+
*/
|
|
36
|
+
root = new DOMParser().parseFromString('<fs></fs>', 'application/xml').documentElement) {
|
|
37
|
+
super();
|
|
38
|
+
this.root = root;
|
|
39
|
+
try {
|
|
40
|
+
this.mkdirSync('/', 0o777);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
const error = e;
|
|
44
|
+
if (error.code != 'EEXIST')
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
renameSync(oldPath, newPath) {
|
|
49
|
+
const node = this.get('rename', oldPath);
|
|
50
|
+
this.remove('rename', node, oldPath);
|
|
51
|
+
this.add('rename', node, newPath);
|
|
52
|
+
}
|
|
53
|
+
statSync(path) {
|
|
54
|
+
return get_stats(this.get('stat', path));
|
|
55
|
+
}
|
|
56
|
+
openFileSync(path, flag) {
|
|
57
|
+
const node = this.get('openFile', path);
|
|
58
|
+
return new PreloadFile(this, path, flag, get_stats(node), encodeRaw(node.textContent));
|
|
59
|
+
}
|
|
60
|
+
createFileSync(path, flag, mode) {
|
|
61
|
+
const stats = new Stats({ mode: mode | S_IFREG });
|
|
62
|
+
this.create('createFile', path, stats);
|
|
63
|
+
return new PreloadFile(this, path, flag, stats);
|
|
64
|
+
}
|
|
65
|
+
unlinkSync(path) {
|
|
66
|
+
const node = this.get('unlink', path);
|
|
67
|
+
if (get_stats(node).isDirectory())
|
|
68
|
+
throw ErrnoError.With('EISDIR', path, 'unlink');
|
|
69
|
+
this.remove('unlink', node, path);
|
|
70
|
+
}
|
|
71
|
+
rmdirSync(path) {
|
|
72
|
+
const node = this.get('rmdir', path);
|
|
73
|
+
if (node.textContent?.length)
|
|
74
|
+
throw ErrnoError.With('ENOTEMPTY', path, 'rmdir');
|
|
75
|
+
if (!get_stats(node).isDirectory())
|
|
76
|
+
throw ErrnoError.With('ENOTDIR', path, 'rmdir');
|
|
77
|
+
this.remove('rmdir', node, path);
|
|
78
|
+
}
|
|
79
|
+
mkdirSync(path, mode) {
|
|
80
|
+
const node = this.create('mkdir', path, { mode: mode | S_IFDIR });
|
|
81
|
+
node.textContent = '[]';
|
|
82
|
+
}
|
|
83
|
+
readdirSync(path) {
|
|
84
|
+
const node = this.get('readdir', path);
|
|
85
|
+
if (!get_stats(node).isDirectory())
|
|
86
|
+
throw ErrnoError.With('ENOTDIR', path, 'rmdir');
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(node.textContent);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
throw new ErrnoError(Errno.EIO, 'Invalid directory listing: ' + e, path, 'readdir');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
linkSync(target, link) {
|
|
95
|
+
const node = this.get('link', target);
|
|
96
|
+
this.add('link', node, link);
|
|
97
|
+
}
|
|
98
|
+
syncSync(path, data, stats) {
|
|
99
|
+
const node = this.get('sync', path);
|
|
100
|
+
node.textContent = decodeRaw(data);
|
|
101
|
+
set_stats(node, stats);
|
|
102
|
+
}
|
|
103
|
+
toString() {
|
|
104
|
+
return new XMLSerializer().serializeToString(this.root);
|
|
105
|
+
}
|
|
106
|
+
get(syscall, path) {
|
|
107
|
+
const nodes = this.root.children;
|
|
108
|
+
if (!nodes)
|
|
109
|
+
throw ErrnoError.With('EIO', path, syscall);
|
|
110
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
111
|
+
if (get_paths(nodes[i]).includes(path))
|
|
112
|
+
return nodes[i];
|
|
113
|
+
}
|
|
114
|
+
throw ErrnoError.With('ENOENT', path, syscall);
|
|
115
|
+
}
|
|
116
|
+
create(syscall, path, stats = {}) {
|
|
117
|
+
if (this.existsSync(path))
|
|
118
|
+
throw ErrnoError.With('EEXIST', path, syscall);
|
|
119
|
+
const node = document.createElement('file');
|
|
120
|
+
this.add(syscall, node, path);
|
|
121
|
+
set_stats(node, new Stats(stats));
|
|
122
|
+
this.root.append(node);
|
|
123
|
+
return node;
|
|
124
|
+
}
|
|
125
|
+
add(syscall, node, path, contents = false) {
|
|
126
|
+
const paths = get_paths(node, contents);
|
|
127
|
+
paths.push(path);
|
|
128
|
+
if (contents) {
|
|
129
|
+
node.textContent = JSON.stringify(paths);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
node.setAttribute('paths', JSON.stringify(paths));
|
|
133
|
+
node.setAttribute('nlink', paths.length.toString(16));
|
|
134
|
+
if (path != '/') {
|
|
135
|
+
const parent = this.get(syscall, dirname(path));
|
|
136
|
+
this.add(syscall, parent, basename(path), true);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
remove(syscall, node, path, contents = false) {
|
|
140
|
+
const paths = get_paths(node, contents);
|
|
141
|
+
const i = paths.indexOf(path);
|
|
142
|
+
if (i == -1)
|
|
143
|
+
return;
|
|
144
|
+
paths.splice(i, 1);
|
|
145
|
+
if (contents) {
|
|
146
|
+
node.textContent = JSON.stringify(paths);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!paths.length) {
|
|
150
|
+
node.remove();
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
node.setAttribute('paths', JSON.stringify(paths));
|
|
154
|
+
node.setAttribute('nlink', paths.length.toString(16));
|
|
155
|
+
}
|
|
156
|
+
if (path != '/') {
|
|
157
|
+
const parent = this.get(syscall, dirname(path));
|
|
158
|
+
this.remove(syscall, parent, basename(path), true);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const _XML = {
|
|
163
|
+
name: 'XML',
|
|
164
|
+
options: {
|
|
165
|
+
root: { type: 'object', required: false },
|
|
166
|
+
},
|
|
167
|
+
isAvailable() {
|
|
168
|
+
return true;
|
|
169
|
+
},
|
|
170
|
+
create(options) {
|
|
171
|
+
return new XMLFS(options.root);
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* @experimental
|
|
176
|
+
*/
|
|
177
|
+
export const XML = _XML;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenfs/dom",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "DOM backends for ZenFS",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"globals": "^15.10.0",
|
|
51
51
|
"prettier": "^3.2.5",
|
|
52
52
|
"tsx": "^4.19.2",
|
|
53
|
-
"typedoc": "^0.
|
|
54
|
-
"typescript": "^5.
|
|
53
|
+
"typedoc": "^0.27.2",
|
|
54
|
+
"typescript": "^5.7.2",
|
|
55
55
|
"typescript-eslint": "^8.8.1"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@zenfs/core": "^1.
|
|
58
|
+
"@zenfs/core": "^1.6.4"
|
|
59
59
|
},
|
|
60
60
|
"optionalDependencies": {
|
|
61
61
|
"fake-indexeddb": "^6.0.0",
|
package/readme.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[ZenFS](https://github.com/zen-fs/core) backends for DOM APIs. DOM APIs are _only_ available natively in browsers.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
> Please read the ZenFS core documentation!
|
|
5
|
+
Please read the ZenFS core documentation!
|
|
7
6
|
|
|
8
7
|
## Backends
|
|
9
8
|
|
|
@@ -15,10 +14,7 @@ For more information, see the [API documentation](https://zen-fs.github.io/dom).
|
|
|
15
14
|
|
|
16
15
|
## Usage
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
> The examples are written in ESM.
|
|
20
|
-
> For CJS, you can `require` the package.
|
|
21
|
-
> If using a browser environment, you can use a `<script>` with `type=module` (you may need to use import maps)
|
|
17
|
+
You can use the backends from `@zenfs/dom` just like the backends from `@zenfs/core`:
|
|
22
18
|
|
|
23
19
|
```js
|
|
24
20
|
import { configure, fs } from '@zenfs/core';
|
|
@@ -33,3 +29,42 @@ if (!fs.existsSync('/test.txt')) {
|
|
|
33
29
|
const contents = fs.readFileSync('/test.txt', 'utf-8');
|
|
34
30
|
console.log(contents);
|
|
35
31
|
```
|
|
32
|
+
|
|
33
|
+
#### `XML`
|
|
34
|
+
|
|
35
|
+
The `XML` backend can be used to create a file system which lives in the DOM:
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<!-- ... -->
|
|
39
|
+
<fs />
|
|
40
|
+
<!-- ... -->
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { configure, fs } from '@zenfs/core';
|
|
45
|
+
import { XML } from '@zenfs/dom';
|
|
46
|
+
|
|
47
|
+
await configureSingle({
|
|
48
|
+
backend: XML,
|
|
49
|
+
root: document.querySelector('fs'), // root is optional
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
fs.writeFileSync('/test.txt', 'This is in the DOM!');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you choose to add the root element to the DOM by appending it, you will likely want to hide its contents (`display:none` works well).
|
|
56
|
+
|
|
57
|
+
The `root` option is not required. If you choose not to pass in a `root`, you can always append it to the DOM later:
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import { configure, fs, mounts } from '@zenfs/core';
|
|
61
|
+
import { XML } from '@zenfs/dom';
|
|
62
|
+
|
|
63
|
+
await configureSingle({ backend: XML });
|
|
64
|
+
|
|
65
|
+
const { root } = mounts.get('/');
|
|
66
|
+
|
|
67
|
+
document.body.append(root);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This may disrupt use cases that involve saving the HTML file locally and loading it later, since a new element is created when configuring. In contrast, when using an existing element and passing in a `root`, the existing element's contents will be preserved.
|