typescript-virtual-container 1.2.9 → 1.3.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/.vscode/settings.json +0 -1
- package/README.md +141 -50
- package/biome.json +7 -0
- package/dist/SSHMimic/exec.d.ts.map +1 -1
- package/dist/SSHMimic/executor.d.ts.map +1 -1
- package/dist/SSHMimic/executor.js +32 -16
- package/dist/SSHMimic/index.d.ts.map +1 -1
- package/dist/SSHMimic/index.js +20 -6
- package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -1
- package/dist/VirtualFileSystem/binaryPack.js +29 -6
- package/dist/VirtualFileSystem/index.d.ts.map +1 -1
- package/dist/VirtualFileSystem/index.js +36 -13
- package/dist/VirtualPackageManager/index.d.ts.map +1 -1
- package/dist/VirtualPackageManager/index.js +192 -43
- package/dist/VirtualShell/index.d.ts +10 -4
- package/dist/VirtualShell/index.d.ts.map +1 -1
- package/dist/VirtualShell/index.js +18 -7
- package/dist/VirtualShell/shell.d.ts.map +1 -1
- package/dist/VirtualShell/shell.js +3 -1
- package/dist/VirtualShell/shellParser.d.ts.map +1 -1
- package/dist/VirtualUserManager/index.d.ts.map +1 -1
- package/dist/commands/adduser.d.ts +6 -0
- package/dist/commands/adduser.d.ts.map +1 -1
- package/dist/commands/adduser.js +6 -0
- package/dist/commands/alias.d.ts +5 -0
- package/dist/commands/alias.d.ts.map +1 -1
- package/dist/commands/alias.js +5 -0
- package/dist/commands/apt.d.ts +5 -0
- package/dist/commands/apt.d.ts.map +1 -1
- package/dist/commands/apt.js +32 -9
- package/dist/commands/awk.d.ts +11 -0
- package/dist/commands/awk.d.ts.map +1 -1
- package/dist/commands/awk.js +15 -2
- package/dist/commands/base64.d.ts +5 -0
- package/dist/commands/base64.d.ts.map +1 -1
- package/dist/commands/base64.js +9 -1
- package/dist/commands/cat.d.ts +5 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +10 -2
- package/dist/commands/cd.d.ts +5 -0
- package/dist/commands/cd.d.ts.map +1 -1
- package/dist/commands/cd.js +5 -0
- package/dist/commands/chmod.d.ts +5 -0
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +5 -0
- package/dist/commands/cp.d.ts +5 -0
- package/dist/commands/cp.d.ts.map +1 -1
- package/dist/commands/cp.js +5 -0
- package/dist/commands/curl.d.ts +5 -0
- package/dist/commands/curl.d.ts.map +1 -1
- package/dist/commands/curl.js +34 -6
- package/dist/commands/cut.d.ts +5 -0
- package/dist/commands/cut.d.ts.map +1 -1
- package/dist/commands/cut.js +8 -1
- package/dist/commands/date.d.ts +5 -0
- package/dist/commands/date.d.ts.map +1 -1
- package/dist/commands/date.js +7 -1
- package/dist/commands/declare.d.ts +3 -0
- package/dist/commands/declare.d.ts.map +1 -0
- package/dist/commands/declare.js +39 -0
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +5 -0
- package/dist/commands/dpkg.d.ts +5 -0
- package/dist/commands/dpkg.d.ts.map +1 -1
- package/dist/commands/dpkg.js +24 -7
- package/dist/commands/du.d.ts.map +1 -1
- package/dist/commands/du.js +8 -2
- package/dist/commands/echo.d.ts +5 -0
- package/dist/commands/echo.d.ts.map +1 -1
- package/dist/commands/echo.js +13 -4
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +11 -1
- package/dist/commands/exit.d.ts +5 -0
- package/dist/commands/exit.d.ts.map +1 -1
- package/dist/commands/exit.js +12 -2
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +3 -1
- package/dist/commands/find.d.ts +5 -0
- package/dist/commands/find.d.ts.map +1 -1
- package/dist/commands/find.js +5 -0
- package/dist/commands/free.d.ts +5 -0
- package/dist/commands/free.d.ts.map +1 -1
- package/dist/commands/free.js +5 -0
- package/dist/commands/grep.d.ts +5 -0
- package/dist/commands/grep.d.ts.map +1 -1
- package/dist/commands/grep.js +12 -2
- package/dist/commands/gzip.d.ts +5 -0
- package/dist/commands/gzip.d.ts.map +1 -1
- package/dist/commands/gzip.js +18 -2
- package/dist/commands/head.d.ts +5 -0
- package/dist/commands/head.d.ts.map +1 -1
- package/dist/commands/head.js +5 -0
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +98 -45
- package/dist/commands/history.d.ts +5 -0
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +5 -0
- package/dist/commands/hostname.d.ts +5 -0
- package/dist/commands/hostname.d.ts.map +1 -1
- package/dist/commands/hostname.js +5 -0
- package/dist/commands/id.d.ts.map +1 -1
- package/dist/commands/id.js +4 -1
- package/dist/commands/index.d.ts +2 -17
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -340
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +3 -1
- package/dist/commands/lsb-release.d.ts.map +1 -1
- package/dist/commands/lsb-release.js +8 -2
- package/dist/commands/nano.js +1 -1
- package/dist/commands/neofetch.js +1 -1
- package/dist/commands/node.d.ts +9 -0
- package/dist/commands/node.d.ts.map +1 -0
- package/dist/commands/node.js +316 -0
- package/dist/commands/npm.d.ts +19 -0
- package/dist/commands/npm.d.ts.map +1 -0
- package/dist/commands/npm.js +109 -0
- package/dist/commands/ping.d.ts.map +1 -1
- package/dist/commands/ping.js +3 -1
- package/dist/commands/printf.d.ts +3 -0
- package/dist/commands/printf.d.ts.map +1 -0
- package/dist/commands/printf.js +113 -0
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +4 -1
- package/dist/commands/python.d.ts +30 -0
- package/dist/commands/python.d.ts.map +1 -0
- package/dist/commands/python.js +2058 -0
- package/dist/commands/read.d.ts +3 -0
- package/dist/commands/read.d.ts.map +1 -0
- package/dist/commands/read.js +34 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +229 -0
- package/dist/commands/runtime.d.ts +6 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +280 -0
- package/dist/commands/sed.d.ts.map +1 -1
- package/dist/commands/sed.js +11 -3
- package/dist/commands/set.d.ts.map +1 -1
- package/dist/commands/set.js +9 -3
- package/dist/commands/sh.d.ts.map +1 -1
- package/dist/commands/sh.js +57 -36
- package/dist/commands/shift.d.ts +5 -0
- package/dist/commands/shift.d.ts.map +1 -0
- package/dist/commands/shift.js +52 -0
- package/dist/commands/sleep.d.ts.map +1 -1
- package/dist/commands/sort.d.ts.map +1 -1
- package/dist/commands/sort.js +4 -2
- package/dist/commands/source.d.ts.map +1 -1
- package/dist/commands/source.js +5 -2
- package/dist/commands/sudo.js +1 -1
- package/dist/commands/tar.d.ts.map +1 -1
- package/dist/commands/tar.js +11 -3
- package/dist/commands/tee.d.ts.map +1 -1
- package/dist/commands/tee.js +8 -6
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +46 -24
- package/dist/commands/tr.d.ts.map +1 -1
- package/dist/commands/tr.js +3 -1
- package/dist/commands/true.d.ts +4 -0
- package/dist/commands/true.d.ts.map +1 -0
- package/dist/commands/true.js +14 -0
- package/dist/commands/type.d.ts.map +1 -1
- package/dist/commands/type.js +1 -1
- package/dist/commands/uname.d.ts.map +1 -1
- package/dist/commands/uname.js +4 -1
- package/dist/commands/uniq.d.ts.map +1 -1
- package/dist/commands/uptime.d.ts.map +1 -1
- package/dist/commands/uptime.js +4 -1
- package/dist/commands/wget.d.ts.map +1 -1
- package/dist/commands/wget.js +32 -7
- package/dist/commands/which.d.ts.map +1 -1
- package/dist/commands/xargs.d.ts.map +1 -1
- package/dist/commands/xargs.js +1 -1
- package/dist/index.d.ts +15 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/modules/linuxRootfs.d.ts +18 -1
- package/dist/modules/linuxRootfs.d.ts.map +1 -1
- package/dist/modules/linuxRootfs.js +160 -17
- package/dist/standalone-wo-sftp.d.ts +2 -0
- package/dist/standalone-wo-sftp.d.ts.map +1 -0
- package/dist/standalone-wo-sftp.js +30 -0
- package/dist/utils/expand.d.ts +50 -0
- package/dist/utils/expand.d.ts.map +1 -0
- package/dist/utils/expand.js +183 -0
- package/dist/utils/vfsDiff.d.ts +90 -0
- package/dist/utils/vfsDiff.d.ts.map +1 -0
- package/dist/utils/vfsDiff.js +177 -0
- package/package.json +2 -1
- package/src/SSHMimic/exec.ts +10 -1
- package/src/SSHMimic/executor.ts +104 -18
- package/src/SSHMimic/index.ts +49 -15
- package/src/VirtualFileSystem/binaryPack.ts +35 -8
- package/src/VirtualFileSystem/index.ts +78 -28
- package/src/VirtualPackageManager/index.ts +208 -49
- package/src/VirtualShell/index.ts +35 -7
- package/src/VirtualShell/shell.ts +23 -3
- package/src/VirtualShell/shellParser.ts +134 -36
- package/src/VirtualUserManager/index.ts +7 -2
- package/src/commands/adduser.ts +6 -0
- package/src/commands/alias.ts +5 -1
- package/src/commands/apt.ts +47 -17
- package/src/commands/awk.ts +20 -6
- package/src/commands/base64.ts +13 -2
- package/src/commands/cat.ts +13 -5
- package/src/commands/cd.ts +5 -0
- package/src/commands/chmod.ts +5 -0
- package/src/commands/cp.ts +5 -0
- package/src/commands/curl.ts +56 -12
- package/src/commands/cut.ts +8 -1
- package/src/commands/date.ts +7 -1
- package/src/commands/declare.ts +44 -0
- package/src/commands/diff.ts +17 -3
- package/src/commands/dpkg.ts +33 -11
- package/src/commands/du.ts +17 -5
- package/src/commands/echo.ts +22 -9
- package/src/commands/env.ts +11 -1
- package/src/commands/exit.ts +12 -2
- package/src/commands/export.ts +3 -1
- package/src/commands/find.ts +5 -0
- package/src/commands/free.ts +9 -2
- package/src/commands/grep.ts +12 -2
- package/src/commands/gzip.ts +28 -4
- package/src/commands/head.ts +5 -0
- package/src/commands/help.ts +121 -47
- package/src/commands/history.ts +7 -2
- package/src/commands/hostname.ts +5 -0
- package/src/commands/id.ts +4 -1
- package/src/commands/index.ts +9 -360
- package/src/commands/ls.ts +5 -3
- package/src/commands/lsb-release.ts +8 -2
- package/src/commands/nano.ts +1 -1
- package/src/commands/neofetch.ts +1 -1
- package/src/commands/node.ts +341 -0
- package/src/commands/npm.ts +132 -0
- package/src/commands/ping.ts +6 -2
- package/src/commands/printf.ts +112 -0
- package/src/commands/ps.ts +21 -9
- package/src/commands/python.ts +2229 -0
- package/src/commands/read.ts +41 -0
- package/src/commands/registry.ts +244 -0
- package/src/commands/runtime.ts +353 -0
- package/src/commands/sed.ts +27 -9
- package/src/commands/set.ts +9 -3
- package/src/commands/sh.ts +159 -55
- package/src/commands/shift.ts +53 -0
- package/src/commands/sleep.ts +2 -1
- package/src/commands/sort.ts +10 -6
- package/src/commands/source.ts +15 -3
- package/src/commands/sudo.ts +1 -1
- package/src/commands/tar.ts +28 -7
- package/src/commands/tee.ts +7 -1
- package/src/commands/test.ts +61 -26
- package/src/commands/tr.ts +3 -1
- package/src/commands/true.ts +17 -0
- package/src/commands/type.ts +6 -3
- package/src/commands/uname.ts +5 -1
- package/src/commands/uniq.ts +8 -2
- package/src/commands/uptime.ts +4 -1
- package/src/commands/wget.ts +51 -12
- package/src/commands/which.ts +5 -2
- package/src/commands/xargs.ts +11 -2
- package/src/index.ts +23 -24
- package/src/modules/linuxRootfs.ts +233 -30
- package/src/standalone-wo-sftp.ts +38 -0
- package/src/utils/expand.ts +238 -0
- package/src/utils/vfsDiff.ts +275 -0
- package/standalone-wo-sftp.js +507 -0
- package/standalone-wo-sftp.js.map +7 -0
- package/standalone.js +253 -191
- package/standalone.js.map +4 -4
- package/tests/bun-test-shim.ts +9 -1
- package/tests/command-helpers.test.ts +1 -5
- package/tests/new-features.test.ts +415 -5
- package/tests/parser-executor.test.ts +27 -27
- package/tests/sftp.test.ts +122 -42
- package/tests/users.test.ts +23 -5
- package/CHANGELOG.md +0 -150
|
@@ -31,19 +31,25 @@
|
|
|
31
31
|
* Binary pack : ~1.00 MB + ~40 bytes/node header → ~27% smaller, no string parsing
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import type {
|
|
34
|
+
import type {
|
|
35
|
+
InternalDirectoryNode,
|
|
36
|
+
InternalFileNode,
|
|
37
|
+
InternalNode,
|
|
38
|
+
} from "./internalTypes";
|
|
35
39
|
|
|
36
40
|
const MAGIC = Buffer.from([0x56, 0x46, 0x53, 0x21]); // "VFS!"
|
|
37
41
|
const VERSION = 0x01;
|
|
38
42
|
const TYPE_FILE = 0x01;
|
|
39
|
-
const TYPE_DIR
|
|
43
|
+
const TYPE_DIR = 0x02;
|
|
40
44
|
|
|
41
45
|
// ── Encoder ───────────────────────────────────────────────────────────────────
|
|
42
46
|
|
|
43
47
|
class Encoder {
|
|
44
48
|
private chunks: Buffer[] = [];
|
|
45
49
|
|
|
46
|
-
write(buf: Buffer): void {
|
|
50
|
+
write(buf: Buffer): void {
|
|
51
|
+
this.chunks.push(buf);
|
|
52
|
+
}
|
|
47
53
|
|
|
48
54
|
writeUint8(n: number): void {
|
|
49
55
|
const b = Buffer.allocUnsafe(1);
|
|
@@ -80,7 +86,9 @@ class Encoder {
|
|
|
80
86
|
this.chunks.push(bytes);
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
toBuffer(): Buffer {
|
|
89
|
+
toBuffer(): Buffer {
|
|
90
|
+
return Buffer.concat(this.chunks);
|
|
91
|
+
}
|
|
84
92
|
}
|
|
85
93
|
|
|
86
94
|
function encodeNode(enc: Encoder, node: InternalNode): void {
|
|
@@ -124,7 +132,9 @@ class Decoder {
|
|
|
124
132
|
private pos = 0;
|
|
125
133
|
constructor(private readonly buf: Buffer) {}
|
|
126
134
|
|
|
127
|
-
readUint8(): number {
|
|
135
|
+
readUint8(): number {
|
|
136
|
+
return this.buf.readUInt8(this.pos++);
|
|
137
|
+
}
|
|
128
138
|
|
|
129
139
|
readUint16(): number {
|
|
130
140
|
const v = this.buf.readUInt16LE(this.pos);
|
|
@@ -158,7 +168,9 @@ class Decoder {
|
|
|
158
168
|
return b;
|
|
159
169
|
}
|
|
160
170
|
|
|
161
|
-
remaining(): number {
|
|
171
|
+
remaining(): number {
|
|
172
|
+
return this.buf.length - this.pos;
|
|
173
|
+
}
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
function decodeNode(dec: Decoder): InternalNode {
|
|
@@ -171,7 +183,15 @@ function decodeNode(dec: Decoder): InternalNode {
|
|
|
171
183
|
if (type === TYPE_FILE) {
|
|
172
184
|
const compressed = dec.readUint8() === 0x01;
|
|
173
185
|
const content = dec.readBytes();
|
|
174
|
-
return {
|
|
186
|
+
return {
|
|
187
|
+
type: "file",
|
|
188
|
+
name,
|
|
189
|
+
mode,
|
|
190
|
+
createdAt,
|
|
191
|
+
updatedAt,
|
|
192
|
+
compressed,
|
|
193
|
+
content,
|
|
194
|
+
} satisfies InternalFileNode;
|
|
175
195
|
}
|
|
176
196
|
|
|
177
197
|
if (type === TYPE_DIR) {
|
|
@@ -181,7 +201,14 @@ function decodeNode(dec: Decoder): InternalNode {
|
|
|
181
201
|
const child = decodeNode(dec);
|
|
182
202
|
children.set(child.name, child);
|
|
183
203
|
}
|
|
184
|
-
return {
|
|
204
|
+
return {
|
|
205
|
+
type: "directory",
|
|
206
|
+
name,
|
|
207
|
+
mode,
|
|
208
|
+
createdAt,
|
|
209
|
+
updatedAt,
|
|
210
|
+
children,
|
|
211
|
+
} satisfies InternalDirectoryNode;
|
|
185
212
|
}
|
|
186
213
|
|
|
187
214
|
throw new Error(`[VFS binary] Unknown node type: 0x${type.toString(16)}`);
|
|
@@ -172,7 +172,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
172
172
|
// Legacy JSON fallback — auto-migrates on next flushMirror()
|
|
173
173
|
const snapshot: VfsSnapshot = JSON.parse(raw.toString("utf8"));
|
|
174
174
|
this.root = this.deserializeDir(snapshot.root, "");
|
|
175
|
-
console.info(
|
|
175
|
+
console.info(
|
|
176
|
+
"[VirtualFileSystem] Migrating legacy JSON snapshot to binary format.",
|
|
177
|
+
);
|
|
176
178
|
}
|
|
177
179
|
this.emit("snapshot:restore", { path: this.snapshotFile });
|
|
178
180
|
} catch (err) {
|
|
@@ -220,7 +222,11 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
220
222
|
public mkdir(targetPath: string, mode: number = 0o755): void {
|
|
221
223
|
const normalized = normalizePath(targetPath);
|
|
222
224
|
const existing = (() => {
|
|
223
|
-
try {
|
|
225
|
+
try {
|
|
226
|
+
return getNode(this.root, normalized);
|
|
227
|
+
} catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
224
230
|
})();
|
|
225
231
|
if (existing && existing.type !== "directory") {
|
|
226
232
|
throw new Error(
|
|
@@ -311,7 +317,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
311
317
|
try {
|
|
312
318
|
getNode(this.root, normalizePath(targetPath));
|
|
313
319
|
return true;
|
|
314
|
-
} catch {
|
|
320
|
+
} catch {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
315
323
|
}
|
|
316
324
|
|
|
317
325
|
/** Updates mode bits on a node. */
|
|
@@ -327,15 +335,24 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
327
335
|
if (node.type === "file") {
|
|
328
336
|
const f = node as InternalFileNode;
|
|
329
337
|
return {
|
|
330
|
-
type: "file",
|
|
331
|
-
|
|
332
|
-
|
|
338
|
+
type: "file",
|
|
339
|
+
name,
|
|
340
|
+
path: normalized,
|
|
341
|
+
mode: f.mode,
|
|
342
|
+
createdAt: f.createdAt,
|
|
343
|
+
updatedAt: f.updatedAt,
|
|
344
|
+
compressed: f.compressed,
|
|
345
|
+
size: f.content.length,
|
|
333
346
|
};
|
|
334
347
|
}
|
|
335
348
|
const d = node as InternalDirectoryNode;
|
|
336
349
|
return {
|
|
337
|
-
type: "directory",
|
|
338
|
-
|
|
350
|
+
type: "directory",
|
|
351
|
+
name,
|
|
352
|
+
path: normalized,
|
|
353
|
+
mode: d.mode,
|
|
354
|
+
createdAt: d.createdAt,
|
|
355
|
+
updatedAt: d.updatedAt,
|
|
339
356
|
childrenCount: d.children.size,
|
|
340
357
|
};
|
|
341
358
|
}
|
|
@@ -355,9 +372,7 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
355
372
|
const normalized = normalizePath(dirPath);
|
|
356
373
|
const node = getNode(this.root, normalized);
|
|
357
374
|
if (node.type !== "directory") {
|
|
358
|
-
throw new Error(
|
|
359
|
-
`Cannot render tree for '${dirPath}': not a directory.`,
|
|
360
|
-
);
|
|
375
|
+
throw new Error(`Cannot render tree for '${dirPath}': not a directory.`);
|
|
361
376
|
}
|
|
362
377
|
const label = dirPath === "/" ? "/" : path.posix.basename(normalized);
|
|
363
378
|
return this.renderTreeLines(node as InternalDirectoryNode, label);
|
|
@@ -375,7 +390,8 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
375
390
|
lines.push(`${connector}${name}`);
|
|
376
391
|
if (child.type === "directory") {
|
|
377
392
|
const sub = this.renderTreeLines(child as InternalDirectoryNode, "")
|
|
378
|
-
.split("\n")
|
|
393
|
+
.split("\n")
|
|
394
|
+
.slice(1)
|
|
379
395
|
.map((l) => `${nextPrefix}${l}`);
|
|
380
396
|
lines.push(...sub);
|
|
381
397
|
}
|
|
@@ -400,7 +416,8 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
400
416
|
/** Compresses a file's content with gzip in place. */
|
|
401
417
|
public compressFile(targetPath: string): void {
|
|
402
418
|
const node = getNode(this.root, normalizePath(targetPath));
|
|
403
|
-
if (node.type !== "file")
|
|
419
|
+
if (node.type !== "file")
|
|
420
|
+
throw new Error(`Cannot compress '${targetPath}': not a file.`);
|
|
404
421
|
const f = node as InternalFileNode;
|
|
405
422
|
if (!f.compressed) {
|
|
406
423
|
f.content = gzipSync(f.content);
|
|
@@ -412,7 +429,8 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
412
429
|
/** Decompresses a gzip-compressed file in place. */
|
|
413
430
|
public decompressFile(targetPath: string): void {
|
|
414
431
|
const node = getNode(this.root, normalizePath(targetPath));
|
|
415
|
-
if (node.type !== "file")
|
|
432
|
+
if (node.type !== "file")
|
|
433
|
+
throw new Error(`Cannot decompress '${targetPath}': not a file.`);
|
|
416
434
|
const f = node as InternalFileNode;
|
|
417
435
|
if (f.compressed) {
|
|
418
436
|
f.content = gunzipSync(f.content);
|
|
@@ -431,18 +449,25 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
431
449
|
? normalizePath(targetPath)
|
|
432
450
|
: targetPath;
|
|
433
451
|
const { parent, name } = getParentDirectory(
|
|
434
|
-
this.root,
|
|
452
|
+
this.root,
|
|
453
|
+
normalizedLink,
|
|
454
|
+
true,
|
|
435
455
|
(p) => this.mkdirRecursive(p, 0o755),
|
|
436
456
|
);
|
|
437
457
|
const symNode: InternalFileNode = {
|
|
438
|
-
type: "file",
|
|
458
|
+
type: "file",
|
|
459
|
+
name,
|
|
439
460
|
content: Buffer.from(normalizedTarget, "utf8"),
|
|
440
461
|
mode: 0o120777,
|
|
441
462
|
compressed: false,
|
|
442
|
-
createdAt: new Date(),
|
|
463
|
+
createdAt: new Date(),
|
|
464
|
+
updatedAt: new Date(),
|
|
443
465
|
};
|
|
444
466
|
parent.children.set(name, symNode);
|
|
445
|
-
this.emit("symlink:create", {
|
|
467
|
+
this.emit("symlink:create", {
|
|
468
|
+
link: normalizedLink,
|
|
469
|
+
target: normalizedTarget,
|
|
470
|
+
});
|
|
446
471
|
}
|
|
447
472
|
|
|
448
473
|
/** Returns true when the path is a symbolic link node. */
|
|
@@ -450,7 +475,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
450
475
|
try {
|
|
451
476
|
const node = getNode(this.root, normalizePath(targetPath));
|
|
452
477
|
return node.type === "file" && node.mode === 0o120777;
|
|
453
|
-
} catch {
|
|
478
|
+
} catch {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
454
481
|
}
|
|
455
482
|
|
|
456
483
|
/**
|
|
@@ -466,10 +493,14 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
466
493
|
const target = (node as InternalFileNode).content.toString("utf8");
|
|
467
494
|
current = target.startsWith("/")
|
|
468
495
|
? target
|
|
469
|
-
: normalizePath(
|
|
496
|
+
: normalizePath(
|
|
497
|
+
path.posix.join(path.posix.dirname(current), target),
|
|
498
|
+
);
|
|
470
499
|
continue;
|
|
471
500
|
}
|
|
472
|
-
} catch {
|
|
501
|
+
} catch {
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
473
504
|
return current;
|
|
474
505
|
}
|
|
475
506
|
throw new Error(`Too many levels of symbolic links: ${linkPath}`);
|
|
@@ -488,7 +519,12 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
488
519
|
);
|
|
489
520
|
}
|
|
490
521
|
}
|
|
491
|
-
const { parent, name } = getParentDirectory(
|
|
522
|
+
const { parent, name } = getParentDirectory(
|
|
523
|
+
this.root,
|
|
524
|
+
normalized,
|
|
525
|
+
false,
|
|
526
|
+
() => {},
|
|
527
|
+
);
|
|
492
528
|
parent.children.delete(name);
|
|
493
529
|
this.emit("node:remove", { path: normalized });
|
|
494
530
|
}
|
|
@@ -506,10 +542,16 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
506
542
|
}
|
|
507
543
|
this.mkdirRecursive(path.posix.dirname(toNormalized), 0o755);
|
|
508
544
|
const { parent: destParent, name: destName } = getParentDirectory(
|
|
509
|
-
this.root,
|
|
545
|
+
this.root,
|
|
546
|
+
toNormalized,
|
|
547
|
+
false,
|
|
548
|
+
() => {},
|
|
510
549
|
);
|
|
511
550
|
const { parent: srcParent, name: srcName } = getParentDirectory(
|
|
512
|
-
this.root,
|
|
551
|
+
this.root,
|
|
552
|
+
fromNormalized,
|
|
553
|
+
false,
|
|
554
|
+
() => {},
|
|
513
555
|
);
|
|
514
556
|
srcParent.children.delete(srcName);
|
|
515
557
|
node.name = destName;
|
|
@@ -538,7 +580,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
538
580
|
);
|
|
539
581
|
}
|
|
540
582
|
return {
|
|
541
|
-
type: "directory",
|
|
583
|
+
type: "directory",
|
|
584
|
+
name: dir.name,
|
|
585
|
+
mode: dir.mode,
|
|
542
586
|
createdAt: dir.createdAt.toISOString(),
|
|
543
587
|
updatedAt: dir.updatedAt.toISOString(),
|
|
544
588
|
children,
|
|
@@ -547,7 +591,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
547
591
|
|
|
548
592
|
private serializeFile(file: InternalFileNode): VfsSnapshotFileNode {
|
|
549
593
|
return {
|
|
550
|
-
type: "file",
|
|
594
|
+
type: "file",
|
|
595
|
+
name: file.name,
|
|
596
|
+
mode: file.mode,
|
|
551
597
|
createdAt: file.createdAt.toISOString(),
|
|
552
598
|
updatedAt: file.updatedAt.toISOString(),
|
|
553
599
|
compressed: file.compressed,
|
|
@@ -588,7 +634,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
588
634
|
name: string,
|
|
589
635
|
): InternalDirectoryNode {
|
|
590
636
|
const dir: InternalDirectoryNode = {
|
|
591
|
-
type: "directory",
|
|
637
|
+
type: "directory",
|
|
638
|
+
name,
|
|
639
|
+
mode: snap.mode,
|
|
592
640
|
createdAt: new Date(snap.createdAt),
|
|
593
641
|
updatedAt: new Date(snap.updatedAt),
|
|
594
642
|
children: new Map(),
|
|
@@ -597,7 +645,9 @@ class VirtualFileSystem extends EventEmitter {
|
|
|
597
645
|
if (child.type === "file") {
|
|
598
646
|
const f = child as VfsSnapshotFileNode;
|
|
599
647
|
dir.children.set(f.name, {
|
|
600
|
-
type: "file",
|
|
648
|
+
type: "file",
|
|
649
|
+
name: f.name,
|
|
650
|
+
mode: f.mode,
|
|
601
651
|
createdAt: new Date(f.createdAt),
|
|
602
652
|
updatedAt: new Date(f.updatedAt),
|
|
603
653
|
compressed: f.compressed,
|