@ricsam/quickjs-fs 0.2.0 → 0.2.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/dist/cjs/directory-handle.cjs +166 -0
- package/dist/cjs/directory-handle.cjs.map +10 -0
- package/dist/cjs/file-handle.cjs +125 -0
- package/dist/cjs/file-handle.cjs.map +10 -0
- package/dist/cjs/index.cjs +4 -4
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/cjs/memory-adapter.cjs +269 -0
- package/dist/cjs/memory-adapter.cjs.map +10 -0
- package/dist/cjs/node-adapter.cjs +221 -0
- package/dist/cjs/node-adapter.cjs.map +10 -0
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/setup.cjs +140 -0
- package/dist/cjs/setup.cjs.map +10 -0
- package/dist/cjs/types.cjs +26 -0
- package/dist/cjs/types.cjs.map +9 -0
- package/dist/cjs/writable-stream.cjs +119 -0
- package/dist/cjs/writable-stream.cjs.map +10 -0
- package/dist/mjs/directory-handle.mjs +135 -0
- package/dist/mjs/directory-handle.mjs.map +10 -0
- package/dist/mjs/file-handle.mjs +94 -0
- package/dist/mjs/file-handle.mjs.map +10 -0
- package/dist/mjs/index.mjs +4 -4
- package/dist/mjs/index.mjs.map +2 -2
- package/dist/mjs/memory-adapter.mjs +237 -0
- package/dist/mjs/memory-adapter.mjs.map +10 -0
- package/dist/mjs/node-adapter.mjs +189 -0
- package/dist/mjs/node-adapter.mjs.map +10 -0
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/setup.mjs +112 -0
- package/dist/mjs/setup.mjs.map +10 -0
- package/dist/mjs/types.mjs +3 -0
- package/dist/mjs/types.mjs.map +9 -0
- package/dist/mjs/writable-stream.mjs +88 -0
- package/dist/mjs/writable-stream.mjs.map +10 -0
- package/package.json +2 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/fs/src/handles/directory-handle.ts
|
|
31
|
+
var exports_directory_handle = {};
|
|
32
|
+
__export(exports_directory_handle, {
|
|
33
|
+
registerHostDirectoryHandle: () => registerHostDirectoryHandle,
|
|
34
|
+
pendingHostHandles: () => pendingHostHandles,
|
|
35
|
+
createFileSystemDirectoryHandleClass: () => createFileSystemDirectoryHandleClass
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(exports_directory_handle);
|
|
38
|
+
var import_quickjs_core = require("@ricsam/quickjs-core");
|
|
39
|
+
var import_file_handle = require("./file-handle.cjs");
|
|
40
|
+
var nextHostHandleId = 0;
|
|
41
|
+
var pendingHostHandles = new Map;
|
|
42
|
+
function registerHostDirectoryHandle(handle) {
|
|
43
|
+
const id = nextHostHandleId++;
|
|
44
|
+
pendingHostHandles.set(id, { handle, name: handle.name });
|
|
45
|
+
return id;
|
|
46
|
+
}
|
|
47
|
+
function createFileSystemDirectoryHandleClass(context, stateMap) {
|
|
48
|
+
return import_quickjs_core.defineClass(context, stateMap, {
|
|
49
|
+
name: "FileSystemDirectoryHandle",
|
|
50
|
+
construct: (args) => {
|
|
51
|
+
const hostHandleId = args[0];
|
|
52
|
+
const pending = pendingHostHandles.get(hostHandleId);
|
|
53
|
+
if (!pending) {
|
|
54
|
+
throw new Error(`No pending host handle with ID ${hostHandleId}`);
|
|
55
|
+
}
|
|
56
|
+
pendingHostHandles.delete(hostHandleId);
|
|
57
|
+
return {
|
|
58
|
+
kind: "directory",
|
|
59
|
+
name: pending.name,
|
|
60
|
+
hostHandle: pending.handle
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
properties: {
|
|
64
|
+
kind: {
|
|
65
|
+
get() {
|
|
66
|
+
return "directory";
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
name: {
|
|
70
|
+
get() {
|
|
71
|
+
return this.name;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
methods: {
|
|
76
|
+
async _getFileHandleInternal(name, options) {
|
|
77
|
+
const opts = options;
|
|
78
|
+
const hostFile = await this.hostHandle.getFileHandle(String(name), {
|
|
79
|
+
create: opts?.create
|
|
80
|
+
});
|
|
81
|
+
return { __fileHandleId: import_file_handle.registerHostFileHandle(hostFile) };
|
|
82
|
+
},
|
|
83
|
+
async _getDirectoryHandleInternal(name, options) {
|
|
84
|
+
const opts = options;
|
|
85
|
+
const hostDir = await this.hostHandle.getDirectoryHandle(String(name), {
|
|
86
|
+
create: opts?.create
|
|
87
|
+
});
|
|
88
|
+
return { __directoryHandleId: registerHostDirectoryHandle(hostDir) };
|
|
89
|
+
},
|
|
90
|
+
async removeEntry(name, options) {
|
|
91
|
+
const opts = options;
|
|
92
|
+
await this.hostHandle.removeEntry(String(name), {
|
|
93
|
+
recursive: opts?.recursive
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
async resolve(possibleDescendant) {
|
|
97
|
+
if (!possibleDescendant || typeof possibleDescendant !== "object") {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const descendant = possibleDescendant;
|
|
101
|
+
return this.hostHandle.resolve(descendant.hostHandle);
|
|
102
|
+
},
|
|
103
|
+
async entries() {
|
|
104
|
+
const result = [];
|
|
105
|
+
for await (const [name, handle] of this.hostHandle.entries()) {
|
|
106
|
+
if (handle.kind === "file") {
|
|
107
|
+
result.push([
|
|
108
|
+
name,
|
|
109
|
+
{
|
|
110
|
+
kind: "file",
|
|
111
|
+
name: handle.name,
|
|
112
|
+
hostHandle: handle
|
|
113
|
+
}
|
|
114
|
+
]);
|
|
115
|
+
} else {
|
|
116
|
+
result.push([
|
|
117
|
+
name,
|
|
118
|
+
{
|
|
119
|
+
kind: "directory",
|
|
120
|
+
name: handle.name,
|
|
121
|
+
hostHandle: handle
|
|
122
|
+
}
|
|
123
|
+
]);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return result;
|
|
127
|
+
},
|
|
128
|
+
async keys() {
|
|
129
|
+
const result = [];
|
|
130
|
+
for await (const name of this.hostHandle.keys()) {
|
|
131
|
+
result.push(name);
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
},
|
|
135
|
+
async values() {
|
|
136
|
+
const result = [];
|
|
137
|
+
for await (const handle of this.hostHandle.values()) {
|
|
138
|
+
if (handle.kind === "file") {
|
|
139
|
+
result.push({
|
|
140
|
+
kind: "file",
|
|
141
|
+
name: handle.name,
|
|
142
|
+
hostHandle: handle
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
result.push({
|
|
146
|
+
kind: "directory",
|
|
147
|
+
name: handle.name,
|
|
148
|
+
hostHandle: handle
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
},
|
|
154
|
+
async isSameEntry(other) {
|
|
155
|
+
if (!other || typeof other !== "object") {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const otherHandle = other;
|
|
159
|
+
return this.hostHandle === otherHandle.hostHandle;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
//# debugId=BB1AC823E8D90E4864756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/handles/directory-handle.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass } from \"@ricsam/quickjs-core\";\nimport type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type {\n FileSystemDirectoryHandleState,\n FileSystemFileHandleState,\n HostDirectoryHandle,\n} from \"../types.cjs\";\nimport { registerHostFileHandle } from \"./file-handle.cjs\";\n\n// Registry for pending host handles that will be picked up by constructor\nlet nextHostHandleId = 0;\nexport const pendingHostHandles = new Map<\n number,\n { handle: HostDirectoryHandle; name: string }\n>();\n\nexport function registerHostDirectoryHandle(\n handle: HostDirectoryHandle\n): number {\n const id = nextHostHandleId++;\n pendingHostHandles.set(id, { handle, name: handle.name });\n return id;\n}\n\n/**\n * Create the FileSystemDirectoryHandle class for QuickJS\n */\nexport function createFileSystemDirectoryHandleClass(\n context: QuickJSContext,\n stateMap: StateMap\n): QuickJSHandle {\n return defineClass<FileSystemDirectoryHandleState>(context, stateMap, {\n name: \"FileSystemDirectoryHandle\",\n construct: (args) => {\n // First argument is the host handle ID\n const hostHandleId = args[0] as number;\n const pending = pendingHostHandles.get(hostHandleId);\n if (!pending) {\n throw new Error(`No pending host handle with ID ${hostHandleId}`);\n }\n pendingHostHandles.delete(hostHandleId);\n return {\n kind: \"directory\" as const,\n name: pending.name,\n hostHandle: pending.handle,\n };\n },\n properties: {\n kind: {\n get(this: FileSystemDirectoryHandleState) {\n return \"directory\";\n },\n },\n name: {\n get(this: FileSystemDirectoryHandleState) {\n return this.name;\n },\n },\n },\n methods: {\n async _getFileHandleInternal(\n this: FileSystemDirectoryHandleState,\n name: unknown,\n options?: unknown\n ): Promise<{ __fileHandleId: number }> {\n const opts = options as { create?: boolean } | undefined;\n const hostFile = await this.hostHandle.getFileHandle(String(name), {\n create: opts?.create,\n });\n\n return { __fileHandleId: registerHostFileHandle(hostFile) };\n },\n async _getDirectoryHandleInternal(\n this: FileSystemDirectoryHandleState,\n name: unknown,\n options?: unknown\n ): Promise<{ __directoryHandleId: number }> {\n const opts = options as { create?: boolean } | undefined;\n const hostDir = await this.hostHandle.getDirectoryHandle(String(name), {\n create: opts?.create,\n });\n\n return { __directoryHandleId: registerHostDirectoryHandle(hostDir) };\n },\n async removeEntry(\n this: FileSystemDirectoryHandleState,\n name: unknown,\n options?: unknown\n ): Promise<void> {\n const opts = options as { recursive?: boolean } | undefined;\n await this.hostHandle.removeEntry(String(name), {\n recursive: opts?.recursive,\n });\n },\n async resolve(\n this: FileSystemDirectoryHandleState,\n possibleDescendant: unknown\n ): Promise<string[] | null> {\n if (!possibleDescendant || typeof possibleDescendant !== \"object\") {\n return null;\n }\n\n const descendant = possibleDescendant as\n | FileSystemFileHandleState\n | FileSystemDirectoryHandleState;\n return this.hostHandle.resolve(descendant.hostHandle);\n },\n async entries(\n this: FileSystemDirectoryHandleState\n ): Promise<\n Array<\n [string, FileSystemFileHandleState | FileSystemDirectoryHandleState]\n >\n > {\n const result: Array<\n [string, FileSystemFileHandleState | FileSystemDirectoryHandleState]\n > = [];\n\n for await (const [name, handle] of this.hostHandle.entries()) {\n if (handle.kind === \"file\") {\n result.push([\n name,\n {\n kind: \"file\",\n name: handle.name,\n hostHandle: handle,\n },\n ]);\n } else {\n result.push([\n name,\n {\n kind: \"directory\",\n name: handle.name,\n hostHandle: handle,\n },\n ]);\n }\n }\n\n return result;\n },\n async keys(this: FileSystemDirectoryHandleState): Promise<string[]> {\n const result: string[] = [];\n for await (const name of this.hostHandle.keys()) {\n result.push(name);\n }\n return result;\n },\n async values(\n this: FileSystemDirectoryHandleState\n ): Promise<\n Array<FileSystemFileHandleState | FileSystemDirectoryHandleState>\n > {\n const result: Array<\n FileSystemFileHandleState | FileSystemDirectoryHandleState\n > = [];\n\n for await (const handle of this.hostHandle.values()) {\n if (handle.kind === \"file\") {\n result.push({\n kind: \"file\",\n name: handle.name,\n hostHandle: handle,\n });\n } else {\n result.push({\n kind: \"directory\",\n name: handle.name,\n hostHandle: handle,\n });\n }\n }\n\n return result;\n },\n async isSameEntry(\n this: FileSystemDirectoryHandleState,\n other: unknown\n ): Promise<boolean> {\n if (!other || typeof other !== \"object\") {\n return false;\n }\n const otherHandle = other as FileSystemDirectoryHandleState;\n return this.hostHandle === otherHandle.hostHandle;\n },\n },\n });\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAC4B,IAA5B;AAOuC,IAAvC;AAGA,IAAI,mBAAmB;AAChB,IAAM,qBAAqB,IAAI;AAK/B,SAAS,2BAA2B,CACzC,QACQ;AAAA,EACR,MAAM,KAAK;AAAA,EACX,mBAAmB,IAAI,IAAI,EAAE,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,EACxD,OAAO;AAAA;AAMF,SAAS,oCAAoC,CAClD,SACA,UACe;AAAA,EACf,OAAO,gCAA4C,SAAS,UAAU;AAAA,IACpE,MAAM;AAAA,IACN,WAAW,CAAC,SAAS;AAAA,MAEnB,MAAM,eAAe,KAAK;AAAA,MAC1B,MAAM,UAAU,mBAAmB,IAAI,YAAY;AAAA,MACnD,IAAI,CAAC,SAAS;AAAA,QACZ,MAAM,IAAI,MAAM,kCAAkC,cAAc;AAAA,MAClE;AAAA,MACA,mBAAmB,OAAO,YAAY;AAAA,MACtC,OAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,QAAQ;AAAA,QACd,YAAY,QAAQ;AAAA,MACtB;AAAA;AAAA,IAEF,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,GAAG,GAAuC;AAAA,UACxC,OAAO;AAAA;AAAA,MAEX;AAAA,MACA,MAAM;AAAA,QACJ,GAAG,GAAuC;AAAA,UACxC,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,IACF;AAAA,IACA,SAAS;AAAA,WACD,uBAAsB,CAE1B,MACA,SACqC;AAAA,QACrC,MAAM,OAAO;AAAA,QACb,MAAM,WAAW,MAAM,KAAK,WAAW,cAAc,OAAO,IAAI,GAAG;AAAA,UACjE,QAAQ,MAAM;AAAA,QAChB,CAAC;AAAA,QAED,OAAO,EAAE,gBAAgB,0CAAuB,QAAQ,EAAE;AAAA;AAAA,WAEtD,4BAA2B,CAE/B,MACA,SAC0C;AAAA,QAC1C,MAAM,OAAO;AAAA,QACb,MAAM,UAAU,MAAM,KAAK,WAAW,mBAAmB,OAAO,IAAI,GAAG;AAAA,UACrE,QAAQ,MAAM;AAAA,QAChB,CAAC;AAAA,QAED,OAAO,EAAE,qBAAqB,4BAA4B,OAAO,EAAE;AAAA;AAAA,WAE/D,YAAW,CAEf,MACA,SACe;AAAA,QACf,MAAM,OAAO;AAAA,QACb,MAAM,KAAK,WAAW,YAAY,OAAO,IAAI,GAAG;AAAA,UAC9C,WAAW,MAAM;AAAA,QACnB,CAAC;AAAA;AAAA,WAEG,QAAO,CAEX,oBAC0B;AAAA,QAC1B,IAAI,CAAC,sBAAsB,OAAO,uBAAuB,UAAU;AAAA,UACjE,OAAO;AAAA,QACT;AAAA,QAEA,MAAM,aAAa;AAAA,QAGnB,OAAO,KAAK,WAAW,QAAQ,WAAW,UAAU;AAAA;AAAA,WAEhD,QAAO,GAMX;AAAA,QACA,MAAM,SAEF,CAAC;AAAA,QAEL,kBAAkB,MAAM,WAAW,KAAK,WAAW,QAAQ,GAAG;AAAA,UAC5D,IAAI,OAAO,SAAS,QAAQ;AAAA,YAC1B,OAAO,KAAK;AAAA,cACV;AAAA,cACA;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM,OAAO;AAAA,gBACb,YAAY;AAAA,cACd;AAAA,YACF,CAAC;AAAA,UACH,EAAO;AAAA,YACL,OAAO,KAAK;AAAA,cACV;AAAA,cACA;AAAA,gBACE,MAAM;AAAA,gBACN,MAAM,OAAO;AAAA,gBACb,YAAY;AAAA,cACd;AAAA,YACF,CAAC;AAAA;AAAA,QAEL;AAAA,QAEA,OAAO;AAAA;AAAA,WAEH,KAAI,GAA0D;AAAA,QAClE,MAAM,SAAmB,CAAC;AAAA,QAC1B,iBAAiB,QAAQ,KAAK,WAAW,KAAK,GAAG;AAAA,UAC/C,OAAO,KAAK,IAAI;AAAA,QAClB;AAAA,QACA,OAAO;AAAA;AAAA,WAEH,OAAM,GAIV;AAAA,QACA,MAAM,SAEF,CAAC;AAAA,QAEL,iBAAiB,UAAU,KAAK,WAAW,OAAO,GAAG;AAAA,UACnD,IAAI,OAAO,SAAS,QAAQ;AAAA,YAC1B,OAAO,KAAK;AAAA,cACV,MAAM;AAAA,cACN,MAAM,OAAO;AAAA,cACb,YAAY;AAAA,YACd,CAAC;AAAA,UACH,EAAO;AAAA,YACL,OAAO,KAAK;AAAA,cACV,MAAM;AAAA,cACN,MAAM,OAAO;AAAA,cACb,YAAY;AAAA,YACd,CAAC;AAAA;AAAA,QAEL;AAAA,QAEA,OAAO;AAAA;AAAA,WAEH,YAAW,CAEf,OACkB;AAAA,QAClB,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AAAA,UACvC,OAAO;AAAA,QACT;AAAA,QACA,MAAM,cAAc;AAAA,QACpB,OAAO,KAAK,eAAe,YAAY;AAAA;AAAA,IAE3C;AAAA,EACF,CAAC;AAAA;",
|
|
8
|
+
"debugId": "BB1AC823E8D90E4864756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/fs/src/handles/file-handle.ts
|
|
31
|
+
var exports_file_handle = {};
|
|
32
|
+
__export(exports_file_handle, {
|
|
33
|
+
registerHostWritableStream: () => registerHostWritableStream,
|
|
34
|
+
registerHostFileHandle: () => registerHostFileHandle,
|
|
35
|
+
pendingWritableStreams: () => pendingWritableStreams,
|
|
36
|
+
pendingFileHandles: () => pendingFileHandles,
|
|
37
|
+
createFileSystemFileHandleClass: () => createFileSystemFileHandleClass
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(exports_file_handle);
|
|
40
|
+
var import_quickjs_core = require("@ricsam/quickjs-core");
|
|
41
|
+
var nextFileHandleId = 0;
|
|
42
|
+
var pendingFileHandles = new Map;
|
|
43
|
+
var nextWritableStreamId = 0;
|
|
44
|
+
var pendingWritableStreams = new Map;
|
|
45
|
+
function registerHostFileHandle(handle) {
|
|
46
|
+
const id = nextFileHandleId++;
|
|
47
|
+
pendingFileHandles.set(id, { handle, name: handle.name });
|
|
48
|
+
return id;
|
|
49
|
+
}
|
|
50
|
+
function registerHostWritableStream(stream) {
|
|
51
|
+
const id = nextWritableStreamId++;
|
|
52
|
+
pendingWritableStreams.set(id, stream);
|
|
53
|
+
return id;
|
|
54
|
+
}
|
|
55
|
+
function createFileSystemFileHandleClass(context, stateMap) {
|
|
56
|
+
return import_quickjs_core.defineClass(context, stateMap, {
|
|
57
|
+
name: "FileSystemFileHandle",
|
|
58
|
+
construct: (args) => {
|
|
59
|
+
const hostHandleId = args[0];
|
|
60
|
+
const pending = pendingFileHandles.get(hostHandleId);
|
|
61
|
+
if (!pending) {
|
|
62
|
+
throw new Error(`No pending file handle with ID ${hostHandleId}`);
|
|
63
|
+
}
|
|
64
|
+
pendingFileHandles.delete(hostHandleId);
|
|
65
|
+
return {
|
|
66
|
+
kind: "file",
|
|
67
|
+
name: pending.name,
|
|
68
|
+
hostHandle: pending.handle
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
properties: {
|
|
72
|
+
kind: {
|
|
73
|
+
get() {
|
|
74
|
+
return "file";
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
name: {
|
|
78
|
+
get() {
|
|
79
|
+
return this.name;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
methods: {
|
|
84
|
+
async getFile() {
|
|
85
|
+
const file = await this.hostHandle.getFile();
|
|
86
|
+
const buffer = await file.arrayBuffer();
|
|
87
|
+
const data = new Uint8Array(buffer);
|
|
88
|
+
return {
|
|
89
|
+
parts: [data],
|
|
90
|
+
type: file.type,
|
|
91
|
+
size: file.size,
|
|
92
|
+
name: file.name,
|
|
93
|
+
lastModified: file.lastModified,
|
|
94
|
+
webkitRelativePath: "",
|
|
95
|
+
async text() {
|
|
96
|
+
return new TextDecoder().decode(data);
|
|
97
|
+
},
|
|
98
|
+
async arrayBuffer() {
|
|
99
|
+
return buffer;
|
|
100
|
+
},
|
|
101
|
+
async bytes() {
|
|
102
|
+
return data;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
async _createWritableInternal(options) {
|
|
107
|
+
const opts = options;
|
|
108
|
+
const hostStream = await this.hostHandle.createWritable({
|
|
109
|
+
keepExistingData: opts?.keepExistingData
|
|
110
|
+
});
|
|
111
|
+
return { __writableStreamId: registerHostWritableStream(hostStream) };
|
|
112
|
+
},
|
|
113
|
+
async isSameEntry(other) {
|
|
114
|
+
if (!other || typeof other !== "object") {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
const otherHandle = other;
|
|
118
|
+
return this.hostHandle === otherHandle.hostHandle;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
//# debugId=03934374EFF6363C64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/handles/file-handle.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { StateMap } from \"@ricsam/quickjs-core\";\nimport { defineClass } from \"@ricsam/quickjs-core\";\nimport type { FileSystemFileHandleState, HostFileHandle, HostWritableFileStream } from \"../types.cjs\";\n\n// Registry for pending host handles that will be picked up by constructor\nlet nextFileHandleId = 0;\nexport const pendingFileHandles = new Map<number, { handle: HostFileHandle; name: string }>();\nlet nextWritableStreamId = 0;\nexport const pendingWritableStreams = new Map<number, HostWritableFileStream>();\n\nexport function registerHostFileHandle(handle: HostFileHandle): number {\n const id = nextFileHandleId++;\n pendingFileHandles.set(id, { handle, name: handle.name });\n return id;\n}\n\nexport function registerHostWritableStream(stream: HostWritableFileStream): number {\n const id = nextWritableStreamId++;\n pendingWritableStreams.set(id, stream);\n return id;\n}\n\n/**\n * Create the FileSystemFileHandle class for QuickJS\n */\nexport function createFileSystemFileHandleClass(\n context: QuickJSContext,\n stateMap: StateMap\n): QuickJSHandle {\n return defineClass<FileSystemFileHandleState>(context, stateMap, {\n name: \"FileSystemFileHandle\",\n construct: (args) => {\n const hostHandleId = args[0] as number;\n const pending = pendingFileHandles.get(hostHandleId);\n if (!pending) {\n throw new Error(`No pending file handle with ID ${hostHandleId}`);\n }\n pendingFileHandles.delete(hostHandleId);\n return {\n kind: \"file\" as const,\n name: pending.name,\n hostHandle: pending.handle,\n };\n },\n properties: {\n kind: {\n get(this: FileSystemFileHandleState) {\n return \"file\";\n },\n },\n name: {\n get(this: FileSystemFileHandleState) {\n return this.name;\n },\n },\n },\n methods: {\n async getFile(this: FileSystemFileHandleState): Promise<object> {\n const file = await this.hostHandle.getFile();\n\n // Convert native File to our internal File representation\n const buffer = await file.arrayBuffer();\n const data = new Uint8Array(buffer);\n\n return {\n parts: [data],\n type: file.type,\n size: file.size,\n name: file.name,\n lastModified: file.lastModified,\n webkitRelativePath: \"\",\n // Include methods that will be recognized\n async text() {\n return new TextDecoder().decode(data);\n },\n async arrayBuffer() {\n return buffer;\n },\n async bytes() {\n return data;\n },\n };\n },\n async _createWritableInternal(\n this: FileSystemFileHandleState,\n options?: unknown\n ): Promise<{ __writableStreamId: number }> {\n const opts = options as { keepExistingData?: boolean } | undefined;\n const hostStream = await this.hostHandle.createWritable({\n keepExistingData: opts?.keepExistingData,\n });\n\n return { __writableStreamId: registerHostWritableStream(hostStream) };\n },\n async isSameEntry(\n this: FileSystemFileHandleState,\n other: unknown\n ): Promise<boolean> {\n if (!other || typeof other !== \"object\") {\n return false;\n }\n const otherHandle = other as FileSystemFileHandleState;\n return this.hostHandle === otherHandle.hostHandle;\n },\n },\n });\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE4B,IAA5B;AAIA,IAAI,mBAAmB;AAChB,IAAM,qBAAqB,IAAI;AACtC,IAAI,uBAAuB;AACpB,IAAM,yBAAyB,IAAI;AAEnC,SAAS,sBAAsB,CAAC,QAAgC;AAAA,EACrE,MAAM,KAAK;AAAA,EACX,mBAAmB,IAAI,IAAI,EAAE,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,EACxD,OAAO;AAAA;AAGF,SAAS,0BAA0B,CAAC,QAAwC;AAAA,EACjF,MAAM,KAAK;AAAA,EACX,uBAAuB,IAAI,IAAI,MAAM;AAAA,EACrC,OAAO;AAAA;AAMF,SAAS,+BAA+B,CAC7C,SACA,UACe;AAAA,EACf,OAAO,gCAAuC,SAAS,UAAU;AAAA,IAC/D,MAAM;AAAA,IACN,WAAW,CAAC,SAAS;AAAA,MACnB,MAAM,eAAe,KAAK;AAAA,MAC1B,MAAM,UAAU,mBAAmB,IAAI,YAAY;AAAA,MACnD,IAAI,CAAC,SAAS;AAAA,QACZ,MAAM,IAAI,MAAM,kCAAkC,cAAc;AAAA,MAClE;AAAA,MACA,mBAAmB,OAAO,YAAY;AAAA,MACtC,OAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,QAAQ;AAAA,QACd,YAAY,QAAQ;AAAA,MACtB;AAAA;AAAA,IAEF,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,GAAG,GAAkC;AAAA,UACnC,OAAO;AAAA;AAAA,MAEX;AAAA,MACA,MAAM;AAAA,QACJ,GAAG,GAAkC;AAAA,UACnC,OAAO,KAAK;AAAA;AAAA,MAEhB;AAAA,IACF;AAAA,IACA,SAAS;AAAA,WACD,QAAO,GAAmD;AAAA,QAC9D,MAAM,OAAO,MAAM,KAAK,WAAW,QAAQ;AAAA,QAG3C,MAAM,SAAS,MAAM,KAAK,YAAY;AAAA,QACtC,MAAM,OAAO,IAAI,WAAW,MAAM;AAAA,QAElC,OAAO;AAAA,UACL,OAAO,CAAC,IAAI;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,MAAM,KAAK;AAAA,UACX,MAAM,KAAK;AAAA,UACX,cAAc,KAAK;AAAA,UACnB,oBAAoB;AAAA,eAEd,KAAI,GAAG;AAAA,YACX,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AAAA;AAAA,eAEhC,YAAW,GAAG;AAAA,YAClB,OAAO;AAAA;AAAA,eAEH,MAAK,GAAG;AAAA,YACZ,OAAO;AAAA;AAAA,QAEX;AAAA;AAAA,WAEI,wBAAuB,CAE3B,SACyC;AAAA,QACzC,MAAM,OAAO;AAAA,QACb,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe;AAAA,UACtD,kBAAkB,MAAM;AAAA,QAC1B,CAAC;AAAA,QAED,OAAO,EAAE,oBAAoB,2BAA2B,UAAU,EAAE;AAAA;AAAA,WAEhE,YAAW,CAEf,OACkB;AAAA,QAClB,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AAAA,UACvC,OAAO;AAAA,QACT;AAAA,QACA,MAAM,cAAc;AAAA,QACpB,OAAO,KAAK,eAAe,YAAY;AAAA;AAAA,IAE3C;AAAA,EACF,CAAC;AAAA;",
|
|
8
|
+
"debugId": "03934374EFF6363C64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -35,9 +35,9 @@ __export(exports_src, {
|
|
|
35
35
|
createMemoryDirectoryHandle: () => import_memory_adapter.createMemoryDirectoryHandle
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(exports_src);
|
|
38
|
-
var import_setup = require("./setup.
|
|
39
|
-
var import_node_adapter = require("./node-adapter.
|
|
40
|
-
var import_memory_adapter = require("./memory-adapter.
|
|
38
|
+
var import_setup = require("./setup.cjs");
|
|
39
|
+
var import_node_adapter = require("./node-adapter.cjs");
|
|
40
|
+
var import_memory_adapter = require("./memory-adapter.cjs");
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
-
//# debugId=
|
|
43
|
+
//# debugId=17BC35DC931775ED64756E2164756E21
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"export { setupFs } from \"./setup.
|
|
5
|
+
"export { setupFs } from \"./setup.cjs\";\nexport { createNodeDirectoryHandle } from \"./node-adapter.cjs\";\nexport { createMemoryDirectoryHandle } from \"./memory-adapter.cjs\";\n\nexport type {\n SetupFsOptions,\n FsHandle,\n HostDirectoryHandle,\n HostFileHandle,\n HostWritableFileStream,\n WriteParams,\n} from \"./types.cjs\";\n"
|
|
6
6
|
],
|
|
7
7
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAwB,IAAxB;AAC0C,IAA1C;AAC4C,IAA5C;",
|
|
8
|
-
"debugId": "
|
|
8
|
+
"debugId": "17BC35DC931775ED64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/fs/src/memory-adapter.ts
|
|
31
|
+
var exports_memory_adapter = {};
|
|
32
|
+
__export(exports_memory_adapter, {
|
|
33
|
+
createMemoryDirectoryHandle: () => createMemoryDirectoryHandle
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(exports_memory_adapter);
|
|
36
|
+
|
|
37
|
+
class MemoryFileHandle {
|
|
38
|
+
name;
|
|
39
|
+
entry;
|
|
40
|
+
kind = "file";
|
|
41
|
+
constructor(name, entry) {
|
|
42
|
+
this.name = name;
|
|
43
|
+
this.entry = entry;
|
|
44
|
+
}
|
|
45
|
+
async getFile() {
|
|
46
|
+
const content = this.entry.content ?? new Uint8Array;
|
|
47
|
+
return new File([content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength)], this.name, {
|
|
48
|
+
type: this.entry.type || "application/octet-stream",
|
|
49
|
+
lastModified: this.entry.lastModified
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async createWritable(options) {
|
|
53
|
+
return new MemoryWritableFileStream(this.entry, options?.keepExistingData ?? false);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class MemoryWritableFileStream {
|
|
58
|
+
entry;
|
|
59
|
+
buffer;
|
|
60
|
+
position = 0;
|
|
61
|
+
constructor(entry, keepExistingData) {
|
|
62
|
+
this.entry = entry;
|
|
63
|
+
if (keepExistingData && this.entry.content) {
|
|
64
|
+
this.buffer = new Uint8Array(this.entry.content);
|
|
65
|
+
} else {
|
|
66
|
+
this.buffer = new Uint8Array(0);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async write(data) {
|
|
70
|
+
let bytes;
|
|
71
|
+
if (typeof data === "string") {
|
|
72
|
+
bytes = new TextEncoder().encode(data);
|
|
73
|
+
} else if (data instanceof ArrayBuffer) {
|
|
74
|
+
bytes = new Uint8Array(data);
|
|
75
|
+
} else if (data instanceof Uint8Array) {
|
|
76
|
+
bytes = data;
|
|
77
|
+
} else if (data instanceof Blob) {
|
|
78
|
+
bytes = new Uint8Array(await data.arrayBuffer());
|
|
79
|
+
} else {
|
|
80
|
+
if (data.type === "seek") {
|
|
81
|
+
this.position = data.position ?? 0;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (data.type === "truncate") {
|
|
85
|
+
this.buffer = this.buffer.slice(0, data.size ?? 0);
|
|
86
|
+
if (this.position > this.buffer.length) {
|
|
87
|
+
this.position = this.buffer.length;
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (data.data === undefined)
|
|
92
|
+
return;
|
|
93
|
+
return this.write(data.data);
|
|
94
|
+
}
|
|
95
|
+
const neededSize = this.position + bytes.length;
|
|
96
|
+
if (neededSize > this.buffer.length) {
|
|
97
|
+
const newBuffer = new Uint8Array(neededSize);
|
|
98
|
+
newBuffer.set(this.buffer);
|
|
99
|
+
this.buffer = newBuffer;
|
|
100
|
+
}
|
|
101
|
+
this.buffer.set(bytes, this.position);
|
|
102
|
+
this.position += bytes.length;
|
|
103
|
+
}
|
|
104
|
+
async seek(position) {
|
|
105
|
+
this.position = position;
|
|
106
|
+
}
|
|
107
|
+
async truncate(size) {
|
|
108
|
+
if (size < this.buffer.length) {
|
|
109
|
+
this.buffer = this.buffer.slice(0, size);
|
|
110
|
+
} else if (size > this.buffer.length) {
|
|
111
|
+
const newBuffer = new Uint8Array(size);
|
|
112
|
+
newBuffer.set(this.buffer);
|
|
113
|
+
this.buffer = newBuffer;
|
|
114
|
+
}
|
|
115
|
+
if (this.position > size) {
|
|
116
|
+
this.position = size;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async close() {
|
|
120
|
+
this.entry.content = this.buffer;
|
|
121
|
+
this.entry.lastModified = Date.now();
|
|
122
|
+
}
|
|
123
|
+
async abort(_reason) {}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class MemoryDirectoryHandle {
|
|
127
|
+
name;
|
|
128
|
+
entry;
|
|
129
|
+
kind = "directory";
|
|
130
|
+
constructor(name, entry) {
|
|
131
|
+
this.name = name;
|
|
132
|
+
this.entry = entry;
|
|
133
|
+
}
|
|
134
|
+
async getFileHandle(name, options) {
|
|
135
|
+
if (!this.entry.children) {
|
|
136
|
+
this.entry.children = new Map;
|
|
137
|
+
}
|
|
138
|
+
let child = this.entry.children.get(name);
|
|
139
|
+
if (!child) {
|
|
140
|
+
if (!options?.create) {
|
|
141
|
+
throw new DOMException(`File not found: ${name}`, "NotFoundError");
|
|
142
|
+
}
|
|
143
|
+
child = {
|
|
144
|
+
kind: "file",
|
|
145
|
+
name,
|
|
146
|
+
content: new Uint8Array(0),
|
|
147
|
+
lastModified: Date.now()
|
|
148
|
+
};
|
|
149
|
+
this.entry.children.set(name, child);
|
|
150
|
+
}
|
|
151
|
+
if (child.kind !== "file") {
|
|
152
|
+
throw new DOMException(`${name} is not a file`, "TypeMismatchError");
|
|
153
|
+
}
|
|
154
|
+
return new MemoryFileHandle(name, child);
|
|
155
|
+
}
|
|
156
|
+
async getDirectoryHandle(name, options) {
|
|
157
|
+
if (!this.entry.children) {
|
|
158
|
+
this.entry.children = new Map;
|
|
159
|
+
}
|
|
160
|
+
let child = this.entry.children.get(name);
|
|
161
|
+
if (!child) {
|
|
162
|
+
if (!options?.create) {
|
|
163
|
+
throw new DOMException(`Directory not found: ${name}`, "NotFoundError");
|
|
164
|
+
}
|
|
165
|
+
child = {
|
|
166
|
+
kind: "directory",
|
|
167
|
+
name,
|
|
168
|
+
children: new Map,
|
|
169
|
+
lastModified: Date.now()
|
|
170
|
+
};
|
|
171
|
+
this.entry.children.set(name, child);
|
|
172
|
+
}
|
|
173
|
+
if (child.kind !== "directory") {
|
|
174
|
+
throw new DOMException(`${name} is not a directory`, "TypeMismatchError");
|
|
175
|
+
}
|
|
176
|
+
return new MemoryDirectoryHandle(name, child);
|
|
177
|
+
}
|
|
178
|
+
async removeEntry(name, options) {
|
|
179
|
+
if (!this.entry.children) {
|
|
180
|
+
throw new DOMException(`Entry not found: ${name}`, "NotFoundError");
|
|
181
|
+
}
|
|
182
|
+
const child = this.entry.children.get(name);
|
|
183
|
+
if (!child) {
|
|
184
|
+
throw new DOMException(`Entry not found: ${name}`, "NotFoundError");
|
|
185
|
+
}
|
|
186
|
+
if (child.kind === "directory" && child.children?.size && !options?.recursive) {
|
|
187
|
+
throw new DOMException(`Directory is not empty: ${name}`, "InvalidModificationError");
|
|
188
|
+
}
|
|
189
|
+
this.entry.children.delete(name);
|
|
190
|
+
}
|
|
191
|
+
async resolve(possibleDescendant) {
|
|
192
|
+
const descendantName = possibleDescendant.name;
|
|
193
|
+
if (this.entry.children?.has(descendantName)) {
|
|
194
|
+
return [descendantName];
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
async* entries() {
|
|
199
|
+
if (!this.entry.children) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
for (const [name, child] of this.entry.children) {
|
|
203
|
+
if (child.kind === "file") {
|
|
204
|
+
yield [name, new MemoryFileHandle(name, child)];
|
|
205
|
+
} else {
|
|
206
|
+
yield [name, new MemoryDirectoryHandle(name, child)];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async* keys() {
|
|
211
|
+
if (!this.entry.children) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
for (const name of this.entry.children.keys()) {
|
|
215
|
+
yield name;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async* values() {
|
|
219
|
+
for await (const [, handle] of this.entries()) {
|
|
220
|
+
yield handle;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function createMemoryDirectoryHandle(initialFiles) {
|
|
225
|
+
const root = {
|
|
226
|
+
kind: "directory",
|
|
227
|
+
name: "",
|
|
228
|
+
children: new Map,
|
|
229
|
+
lastModified: Date.now()
|
|
230
|
+
};
|
|
231
|
+
if (initialFiles) {
|
|
232
|
+
for (const [path, content] of Object.entries(initialFiles)) {
|
|
233
|
+
const segments = path.split("/").filter(Boolean);
|
|
234
|
+
let current = root;
|
|
235
|
+
for (let i = 0;i < segments.length - 1; i++) {
|
|
236
|
+
const segment = segments[i];
|
|
237
|
+
if (!current.children) {
|
|
238
|
+
current.children = new Map;
|
|
239
|
+
}
|
|
240
|
+
let child = current.children.get(segment);
|
|
241
|
+
if (!child) {
|
|
242
|
+
child = {
|
|
243
|
+
kind: "directory",
|
|
244
|
+
name: segment,
|
|
245
|
+
children: new Map,
|
|
246
|
+
lastModified: Date.now()
|
|
247
|
+
};
|
|
248
|
+
current.children.set(segment, child);
|
|
249
|
+
}
|
|
250
|
+
current = child;
|
|
251
|
+
}
|
|
252
|
+
const fileName = segments[segments.length - 1];
|
|
253
|
+
if (!current.children) {
|
|
254
|
+
current.children = new Map;
|
|
255
|
+
}
|
|
256
|
+
const fileContent = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
257
|
+
current.children.set(fileName, {
|
|
258
|
+
kind: "file",
|
|
259
|
+
name: fileName,
|
|
260
|
+
content: fileContent,
|
|
261
|
+
lastModified: Date.now()
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return new MemoryDirectoryHandle("", root);
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
//# debugId=EE454A6223A555BF64756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/memory-adapter.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import type {\n HostDirectoryHandle,\n HostFileHandle,\n HostWritableFileStream,\n WriteParams,\n} from \"./types.cjs\";\n\ninterface MemoryEntry {\n kind: \"file\" | \"directory\";\n name: string;\n content?: Uint8Array;\n children?: Map<string, MemoryEntry>;\n lastModified: number;\n type?: string;\n}\n\n/**\n * In-memory file handle implementation\n */\nclass MemoryFileHandle implements HostFileHandle {\n readonly kind = \"file\" as const;\n\n constructor(\n public readonly name: string,\n private entry: MemoryEntry\n ) {}\n\n async getFile(): Promise<File> {\n const content = this.entry.content ?? new Uint8Array();\n return new File([content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength) as ArrayBuffer], this.name, {\n type: this.entry.type || \"application/octet-stream\",\n lastModified: this.entry.lastModified,\n });\n }\n\n async createWritable(\n options?: { keepExistingData?: boolean }\n ): Promise<HostWritableFileStream> {\n return new MemoryWritableFileStream(\n this.entry,\n options?.keepExistingData ?? false\n );\n }\n}\n\n/**\n * In-memory writable file stream implementation\n */\nclass MemoryWritableFileStream implements HostWritableFileStream {\n private buffer: Uint8Array;\n private position = 0;\n\n constructor(\n private entry: MemoryEntry,\n keepExistingData: boolean\n ) {\n if (keepExistingData && this.entry.content) {\n this.buffer = new Uint8Array(this.entry.content);\n } else {\n this.buffer = new Uint8Array(0);\n }\n }\n\n async write(\n data: string | ArrayBuffer | Uint8Array | Blob | WriteParams\n ): Promise<void> {\n let bytes: Uint8Array;\n\n if (typeof data === \"string\") {\n bytes = new TextEncoder().encode(data);\n } else if (data instanceof ArrayBuffer) {\n bytes = new Uint8Array(data);\n } else if (data instanceof Uint8Array) {\n bytes = data;\n } else if (data instanceof Blob) {\n bytes = new Uint8Array(await data.arrayBuffer());\n } else {\n // WriteParams\n if (data.type === \"seek\") {\n this.position = data.position ?? 0;\n return;\n }\n if (data.type === \"truncate\") {\n this.buffer = this.buffer.slice(0, data.size ?? 0);\n if (this.position > this.buffer.length) {\n this.position = this.buffer.length;\n }\n return;\n }\n // type === \"write\"\n if (data.data === undefined) return;\n return this.write(data.data);\n }\n\n // Expand buffer if needed\n const neededSize = this.position + bytes.length;\n if (neededSize > this.buffer.length) {\n const newBuffer = new Uint8Array(neededSize);\n newBuffer.set(this.buffer);\n this.buffer = newBuffer;\n }\n\n this.buffer.set(bytes, this.position);\n this.position += bytes.length;\n }\n\n async seek(position: number): Promise<void> {\n this.position = position;\n }\n\n async truncate(size: number): Promise<void> {\n if (size < this.buffer.length) {\n this.buffer = this.buffer.slice(0, size);\n } else if (size > this.buffer.length) {\n const newBuffer = new Uint8Array(size);\n newBuffer.set(this.buffer);\n this.buffer = newBuffer;\n }\n if (this.position > size) {\n this.position = size;\n }\n }\n\n async close(): Promise<void> {\n this.entry.content = this.buffer;\n this.entry.lastModified = Date.now();\n }\n\n async abort(_reason?: unknown): Promise<void> {\n // Don't save, just discard\n }\n}\n\n/**\n * In-memory directory handle implementation\n */\nclass MemoryDirectoryHandle implements HostDirectoryHandle {\n readonly kind = \"directory\" as const;\n\n constructor(\n public readonly name: string,\n private entry: MemoryEntry\n ) {}\n\n async getFileHandle(\n name: string,\n options?: { create?: boolean }\n ): Promise<HostFileHandle> {\n if (!this.entry.children) {\n this.entry.children = new Map();\n }\n\n let child = this.entry.children.get(name);\n\n if (!child) {\n if (!options?.create) {\n throw new DOMException(`File not found: ${name}`, \"NotFoundError\");\n }\n child = {\n kind: \"file\",\n name,\n content: new Uint8Array(0),\n lastModified: Date.now(),\n };\n this.entry.children.set(name, child);\n }\n\n if (child.kind !== \"file\") {\n throw new DOMException(\n `${name} is not a file`,\n \"TypeMismatchError\"\n );\n }\n\n return new MemoryFileHandle(name, child);\n }\n\n async getDirectoryHandle(\n name: string,\n options?: { create?: boolean }\n ): Promise<HostDirectoryHandle> {\n if (!this.entry.children) {\n this.entry.children = new Map();\n }\n\n let child = this.entry.children.get(name);\n\n if (!child) {\n if (!options?.create) {\n throw new DOMException(\n `Directory not found: ${name}`,\n \"NotFoundError\"\n );\n }\n child = {\n kind: \"directory\",\n name,\n children: new Map(),\n lastModified: Date.now(),\n };\n this.entry.children.set(name, child);\n }\n\n if (child.kind !== \"directory\") {\n throw new DOMException(\n `${name} is not a directory`,\n \"TypeMismatchError\"\n );\n }\n\n return new MemoryDirectoryHandle(name, child);\n }\n\n async removeEntry(\n name: string,\n options?: { recursive?: boolean }\n ): Promise<void> {\n if (!this.entry.children) {\n throw new DOMException(`Entry not found: ${name}`, \"NotFoundError\");\n }\n\n const child = this.entry.children.get(name);\n if (!child) {\n throw new DOMException(`Entry not found: ${name}`, \"NotFoundError\");\n }\n\n if (child.kind === \"directory\" && child.children?.size && !options?.recursive) {\n throw new DOMException(\n `Directory is not empty: ${name}`,\n \"InvalidModificationError\"\n );\n }\n\n this.entry.children.delete(name);\n }\n\n async resolve(\n possibleDescendant: HostFileHandle | HostDirectoryHandle\n ): Promise<string[] | null> {\n // Simplified implementation - just check if it's a direct child\n const descendantName = possibleDescendant.name;\n if (this.entry.children?.has(descendantName)) {\n return [descendantName];\n }\n return null;\n }\n\n async *entries(): AsyncIterable<\n [string, HostFileHandle | HostDirectoryHandle]\n > {\n if (!this.entry.children) {\n return;\n }\n\n for (const [name, child] of this.entry.children) {\n if (child.kind === \"file\") {\n yield [name, new MemoryFileHandle(name, child)];\n } else {\n yield [name, new MemoryDirectoryHandle(name, child)];\n }\n }\n }\n\n async *keys(): AsyncIterable<string> {\n if (!this.entry.children) {\n return;\n }\n for (const name of this.entry.children.keys()) {\n yield name;\n }\n }\n\n async *values(): AsyncIterable<HostFileHandle | HostDirectoryHandle> {\n for await (const [, handle] of this.entries()) {\n yield handle;\n }\n }\n}\n\n/**\n * Create an in-memory directory handle\n * Useful for testing or fully sandboxed environments\n *\n * @example\n * import { createMemoryDirectoryHandle } from \"@ricsam/quickjs-fs\";\n *\n * const memFs = createMemoryDirectoryHandle({\n * \"config.json\": JSON.stringify({ debug: true }),\n * \"data/users.json\": JSON.stringify([]),\n * });\n *\n * const handle = setupFs(context, {\n * getDirectory: async (path) => memFs\n * });\n */\nexport function createMemoryDirectoryHandle(\n initialFiles?: Record<string, string | Uint8Array>\n): HostDirectoryHandle {\n const root: MemoryEntry = {\n kind: \"directory\",\n name: \"\",\n children: new Map(),\n lastModified: Date.now(),\n };\n\n if (initialFiles) {\n for (const [path, content] of Object.entries(initialFiles)) {\n const segments = path.split(\"/\").filter(Boolean);\n let current = root;\n\n // Create directories as needed\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n if (!current.children) {\n current.children = new Map();\n }\n\n let child = current.children.get(segment);\n if (!child) {\n child = {\n kind: \"directory\",\n name: segment,\n children: new Map(),\n lastModified: Date.now(),\n };\n current.children.set(segment, child);\n }\n current = child;\n }\n\n // Create the file\n const fileName = segments[segments.length - 1]!;\n if (!current.children) {\n current.children = new Map();\n }\n\n const fileContent =\n typeof content === \"string\"\n ? new TextEncoder().encode(content)\n : content;\n\n current.children.set(fileName, {\n kind: \"file\",\n name: fileName,\n content: fileContent,\n lastModified: Date.now(),\n });\n }\n }\n\n return new MemoryDirectoryHandle(\"\", root);\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "EE454A6223A555BF64756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|