sandbox-fs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +418 -0
- package/dist/FSModule.d.ts +153 -0
- package/dist/FSModule.d.ts.map +1 -0
- package/dist/FSModule.js +555 -0
- package/dist/FSModule.js.map +1 -0
- package/dist/PathMapper.d.ts +30 -0
- package/dist/PathMapper.d.ts.map +1 -0
- package/dist/PathMapper.js +122 -0
- package/dist/PathMapper.js.map +1 -0
- package/dist/PathModule.d.ts +69 -0
- package/dist/PathModule.d.ts.map +1 -0
- package/dist/PathModule.js +159 -0
- package/dist/PathModule.js.map +1 -0
- package/dist/ResourceTracker.d.ts +74 -0
- package/dist/ResourceTracker.d.ts.map +1 -0
- package/dist/ResourceTracker.js +175 -0
- package/dist/ResourceTracker.js.map +1 -0
- package/dist/VirtualFileSystem.d.ts +145 -0
- package/dist/VirtualFileSystem.d.ts.map +1 -0
- package/dist/VirtualFileSystem.js +155 -0
- package/dist/VirtualFileSystem.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/newer.d.ts +36 -0
- package/dist/operations/newer.d.ts.map +1 -0
- package/dist/operations/newer.js +239 -0
- package/dist/operations/newer.js.map +1 -0
- package/dist/operations/read.d.ts +24 -0
- package/dist/operations/read.d.ts.map +1 -0
- package/dist/operations/read.js +313 -0
- package/dist/operations/read.js.map +1 -0
- package/dist/operations/symlink.d.ts +8 -0
- package/dist/operations/symlink.d.ts.map +1 -0
- package/dist/operations/symlink.js +33 -0
- package/dist/operations/symlink.js.map +1 -0
- package/dist/operations/write.d.ts +29 -0
- package/dist/operations/write.d.ts.map +1 -0
- package/dist/operations/write.js +191 -0
- package/dist/operations/write.js.map +1 -0
- package/dist/utils/ErrorFilter.d.ts +6 -0
- package/dist/utils/ErrorFilter.d.ts.map +1 -0
- package/dist/utils/ErrorFilter.js +57 -0
- package/dist/utils/ErrorFilter.js.map +1 -0
- package/dist/utils/callbackify.d.ts +9 -0
- package/dist/utils/callbackify.d.ts.map +1 -0
- package/dist/utils/callbackify.js +48 -0
- package/dist/utils/callbackify.js.map +1 -0
- package/dist/wrappers/VirtualDir.d.ts +34 -0
- package/dist/wrappers/VirtualDir.d.ts.map +1 -0
- package/dist/wrappers/VirtualDir.js +72 -0
- package/dist/wrappers/VirtualDir.js.map +1 -0
- package/dist/wrappers/VirtualDirent.d.ts +21 -0
- package/dist/wrappers/VirtualDirent.d.ts.map +1 -0
- package/dist/wrappers/VirtualDirent.js +50 -0
- package/dist/wrappers/VirtualDirent.js.map +1 -0
- package/example.js +95 -0
- package/example.ts +32 -0
- package/package.json +29 -0
- package/src/FSModule.ts +546 -0
- package/src/PathMapper.ts +102 -0
- package/src/PathModule.ts +142 -0
- package/src/ResourceTracker.ts +162 -0
- package/src/VirtualFileSystem.ts +172 -0
- package/src/index.ts +9 -0
- package/src/operations/newer.ts +223 -0
- package/src/operations/read.ts +319 -0
- package/src/operations/symlink.ts +31 -0
- package/src/operations/write.ts +189 -0
- package/src/utils/ErrorFilter.ts +57 -0
- package/src/utils/callbackify.ts +54 -0
- package/src/wrappers/VirtualDir.ts +84 -0
- package/src/wrappers/VirtualDirent.ts +60 -0
- package/test-data/example.txt +1 -0
- package/test-data/subdir/nested.txt +1 -0
- package/tsconfig.example.json +8 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterError = filterError;
|
|
4
|
+
/**
|
|
5
|
+
* Filter error messages to replace real paths with virtual paths
|
|
6
|
+
*/
|
|
7
|
+
function filterError(error, pathMapper) {
|
|
8
|
+
const realRoot = pathMapper.getRoot();
|
|
9
|
+
// Create a regex to match the real root path
|
|
10
|
+
// Escape special regex characters and handle both forward and back slashes
|
|
11
|
+
const escapedRoot = realRoot.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
+
const rootPattern = new RegExp(escapedRoot.replace(/\\/g, "\\\\"), "g");
|
|
13
|
+
// Filter the error message
|
|
14
|
+
if (error.message) {
|
|
15
|
+
error.message = error.message.replace(rootPattern, "");
|
|
16
|
+
}
|
|
17
|
+
// Filter the stack trace
|
|
18
|
+
if (error.stack) {
|
|
19
|
+
error.stack = error.stack.replace(rootPattern, "");
|
|
20
|
+
}
|
|
21
|
+
// Filter the path property if it exists
|
|
22
|
+
const errWithPath = error;
|
|
23
|
+
if (errWithPath.path && typeof errWithPath.path === "string") {
|
|
24
|
+
try {
|
|
25
|
+
// Try to convert real path to virtual path
|
|
26
|
+
if (pathMapper.isWithinRoot(errWithPath.path)) {
|
|
27
|
+
errWithPath.path = pathMapper.toVirtualPath(errWithPath.path);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// If outside root, just strip the root prefix
|
|
31
|
+
errWithPath.path = errWithPath.path.replace(rootPattern, "");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// If conversion fails, just strip the root prefix
|
|
36
|
+
errWithPath.path = errWithPath.path.replace(rootPattern, "");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Filter the dest property if it exists (for copy operations)
|
|
40
|
+
if ("dest" in errWithPath && typeof errWithPath.dest === "string") {
|
|
41
|
+
try {
|
|
42
|
+
const destStr = errWithPath.dest;
|
|
43
|
+
if (pathMapper.isWithinRoot(destStr)) {
|
|
44
|
+
errWithPath.dest = pathMapper.toVirtualPath(destStr);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
errWithPath.dest = destStr.replace(rootPattern, "");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
const destStr = errWithPath.dest;
|
|
52
|
+
errWithPath.dest = destStr.replace(rootPattern, "");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return error;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=ErrorFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorFilter.js","sourceRoot":"","sources":["../../src/utils/ErrorFilter.ts"],"names":[],"mappings":";;AAKA,kCAmDC;AAtDD;;GAEG;AACH,SAAgB,WAAW,CAAC,KAAY,EAAE,UAAsB;IAC9D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;IAEtC,6CAA6C;IAC7C,2EAA2E;IAC3E,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAExE,2BAA2B;IAC3B,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,yBAAyB;IACzB,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,wCAAwC;IACxC,MAAM,WAAW,GAAG,KAA8B,CAAC;IACnD,IAAI,WAAW,CAAC,IAAI,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7D,IAAI,CAAC;YACH,2CAA2C;YAC3C,IAAI,UAAU,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9C,WAAW,CAAC,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,8CAA8C;gBAC9C,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;YAClD,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,8DAA8D;IAC9D,IAAI,MAAM,IAAI,WAAW,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,IAAc,CAAC;YAC3C,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpC,WAAmB,CAAC,IAAI,GAAG,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACL,WAAmB,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,OAAO,GAAG,WAAW,CAAC,IAAc,CAAC;YAC1C,WAAmB,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a promise-based function to a callback-based function
|
|
3
|
+
*/
|
|
4
|
+
export declare function callbackify<T extends any[], R>(fn: (...args: T) => Promise<R>): (...args: [...T, (err: Error | null, result?: R) => void]) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Callbackify for void-returning promises
|
|
7
|
+
*/
|
|
8
|
+
export declare function callbackifyVoid<T extends any[]>(fn: (...args: T) => Promise<void>): (...args: [...T, (err: Error | null) => void]) => void;
|
|
9
|
+
//# sourceMappingURL=callbackify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callbackify.d.ts","sourceRoot":"","sources":["../../src/utils/callbackify.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,GAAG,EAAE,EAAE,CAAC,EAC5C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7B,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAuBpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,GAAG,EAAE,EAC7C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAChC,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,CAkBxD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.callbackify = callbackify;
|
|
4
|
+
exports.callbackifyVoid = callbackifyVoid;
|
|
5
|
+
/**
|
|
6
|
+
* Convert a promise-based function to a callback-based function
|
|
7
|
+
*/
|
|
8
|
+
function callbackify(fn) {
|
|
9
|
+
return function (...args) {
|
|
10
|
+
// Extract callback from arguments
|
|
11
|
+
const callback = args[args.length - 1];
|
|
12
|
+
if (typeof callback !== 'function') {
|
|
13
|
+
throw new TypeError('The last argument must be a callback function');
|
|
14
|
+
}
|
|
15
|
+
// Get the actual arguments (without callback)
|
|
16
|
+
const actualArgs = args.slice(0, -1);
|
|
17
|
+
// Call the promise function
|
|
18
|
+
fn.apply(this, actualArgs)
|
|
19
|
+
.then((result) => {
|
|
20
|
+
// Call callback with no error
|
|
21
|
+
callback(null, result);
|
|
22
|
+
})
|
|
23
|
+
.catch((err) => {
|
|
24
|
+
// Call callback with error
|
|
25
|
+
callback(err);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Callbackify for void-returning promises
|
|
31
|
+
*/
|
|
32
|
+
function callbackifyVoid(fn) {
|
|
33
|
+
return function (...args) {
|
|
34
|
+
const callback = args[args.length - 1];
|
|
35
|
+
if (typeof callback !== 'function') {
|
|
36
|
+
throw new TypeError('The last argument must be a callback function');
|
|
37
|
+
}
|
|
38
|
+
const actualArgs = args.slice(0, -1);
|
|
39
|
+
fn.apply(this, actualArgs)
|
|
40
|
+
.then(() => {
|
|
41
|
+
callback(null);
|
|
42
|
+
})
|
|
43
|
+
.catch((err) => {
|
|
44
|
+
callback(err);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=callbackify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callbackify.js","sourceRoot":"","sources":["../../src/utils/callbackify.ts"],"names":[],"mappings":";;AAGA,kCAyBC;AAKD,0CAoBC;AArDD;;GAEG;AACH,SAAgB,WAAW,CACzB,EAA8B;IAE9B,OAAO,UAAqB,GAAG,IAAW;QACxC,kCAAkC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEvC,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;QACvE,CAAC;QAED,8CAA8C;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAM,CAAC;QAE1C,4BAA4B;QAC5B,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC;aACvB,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,8BAA8B;YAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,2BAA2B;YAC3B,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,eAAe,CAC7B,EAAiC;IAEjC,OAAO,UAAqB,GAAG,IAAW;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEvC,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAM,CAAC;QAE1C,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC;aACvB,IAAI,CAAC,GAAG,EAAE;YACT,QAAQ,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,QAAQ,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { VirtualDirent } from './VirtualDirent';
|
|
3
|
+
import type { PathMapper } from '../PathMapper';
|
|
4
|
+
/**
|
|
5
|
+
* Virtual Dir that wraps a real fs.Dir and returns VirtualDirent instances
|
|
6
|
+
*/
|
|
7
|
+
export declare class VirtualDir implements AsyncIterable<VirtualDirent> {
|
|
8
|
+
private realDir;
|
|
9
|
+
private _virtualPath;
|
|
10
|
+
private pathMapper;
|
|
11
|
+
constructor(realDir: fs.Dir, virtualPath: string, pathMapper: PathMapper);
|
|
12
|
+
get path(): string;
|
|
13
|
+
/**
|
|
14
|
+
* Read the next directory entry
|
|
15
|
+
*/
|
|
16
|
+
read(): Promise<VirtualDirent | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Synchronously read the next directory entry
|
|
19
|
+
*/
|
|
20
|
+
readSync(): VirtualDirent | null;
|
|
21
|
+
/**
|
|
22
|
+
* Close the directory
|
|
23
|
+
*/
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Synchronously close the directory
|
|
27
|
+
*/
|
|
28
|
+
closeSync(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Async iterator support
|
|
31
|
+
*/
|
|
32
|
+
[Symbol.asyncIterator](): AsyncIterator<VirtualDirent>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=VirtualDir.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualDir.d.ts","sourceRoot":"","sources":["../../src/wrappers/VirtualDir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,qBAAa,UAAW,YAAW,aAAa,CAAC,aAAa,CAAC;IAC7D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAa;gBAEnB,OAAO,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;IAMxE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAc3C;;OAEG;IACH,QAAQ,IAAI,aAAa,GAAG,IAAI;IAahC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,aAAa,CAAC;CAWvD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VirtualDir = void 0;
|
|
4
|
+
const VirtualDirent_1 = require("./VirtualDirent");
|
|
5
|
+
/**
|
|
6
|
+
* Virtual Dir that wraps a real fs.Dir and returns VirtualDirent instances
|
|
7
|
+
*/
|
|
8
|
+
class VirtualDir {
|
|
9
|
+
constructor(realDir, virtualPath, pathMapper) {
|
|
10
|
+
this.realDir = realDir;
|
|
11
|
+
this._virtualPath = virtualPath;
|
|
12
|
+
this.pathMapper = pathMapper;
|
|
13
|
+
}
|
|
14
|
+
get path() {
|
|
15
|
+
return this._virtualPath;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Read the next directory entry
|
|
19
|
+
*/
|
|
20
|
+
async read() {
|
|
21
|
+
const realDirent = await this.realDir.read();
|
|
22
|
+
if (realDirent === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
// Construct virtual path for this entry
|
|
26
|
+
const virtualEntryPath = this._virtualPath === '/'
|
|
27
|
+
? `/${realDirent.name}`
|
|
28
|
+
: `${this._virtualPath}/${realDirent.name}`;
|
|
29
|
+
return new VirtualDirent_1.VirtualDirent(realDirent, virtualEntryPath, realDirent.name);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Synchronously read the next directory entry
|
|
33
|
+
*/
|
|
34
|
+
readSync() {
|
|
35
|
+
const realDirent = this.realDir.readSync();
|
|
36
|
+
if (realDirent === null) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const virtualEntryPath = this._virtualPath === '/'
|
|
40
|
+
? `/${realDirent.name}`
|
|
41
|
+
: `${this._virtualPath}/${realDirent.name}`;
|
|
42
|
+
return new VirtualDirent_1.VirtualDirent(realDirent, virtualEntryPath, realDirent.name);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Close the directory
|
|
46
|
+
*/
|
|
47
|
+
async close() {
|
|
48
|
+
await this.realDir.close();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Synchronously close the directory
|
|
52
|
+
*/
|
|
53
|
+
closeSync() {
|
|
54
|
+
this.realDir.closeSync();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Async iterator support
|
|
58
|
+
*/
|
|
59
|
+
[Symbol.asyncIterator]() {
|
|
60
|
+
return {
|
|
61
|
+
next: async () => {
|
|
62
|
+
const dirent = await this.read();
|
|
63
|
+
if (dirent === null) {
|
|
64
|
+
return { done: true, value: undefined };
|
|
65
|
+
}
|
|
66
|
+
return { done: false, value: dirent };
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.VirtualDir = VirtualDir;
|
|
72
|
+
//# sourceMappingURL=VirtualDir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualDir.js","sourceRoot":"","sources":["../../src/wrappers/VirtualDir.ts"],"names":[],"mappings":";;;AACA,mDAAgD;AAGhD;;GAEG;AACH,MAAa,UAAU;IAKrB,YAAY,OAAe,EAAE,WAAmB,EAAE,UAAsB;QACtE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,wCAAwC;QACxC,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,KAAK,GAAG;YAChD,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE;YACvB,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QAE9C,OAAO,IAAI,6BAAa,CAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC3C,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,KAAK,GAAG;YAChD,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE;YACvB,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;QAE9C,OAAO,IAAI,6BAAa,CAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,KAAK,IAA4C,EAAE;gBACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACjC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;oBACpB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;gBAC1C,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YACxC,CAAC;SACF,CAAC;IACJ,CAAC;CACF;AA5ED,gCA4EC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
/**
|
|
3
|
+
* Virtual Dirent that wraps a real fs.Dirent and exposes virtual paths
|
|
4
|
+
*/
|
|
5
|
+
export declare class VirtualDirent implements fs.Dirent {
|
|
6
|
+
private realDirent;
|
|
7
|
+
private _virtualPath;
|
|
8
|
+
private _name;
|
|
9
|
+
constructor(realDirent: fs.Dirent, virtualPath: string, name?: string);
|
|
10
|
+
get name(): string;
|
|
11
|
+
get path(): string;
|
|
12
|
+
get parentPath(): string;
|
|
13
|
+
isFile(): boolean;
|
|
14
|
+
isDirectory(): boolean;
|
|
15
|
+
isBlockDevice(): boolean;
|
|
16
|
+
isCharacterDevice(): boolean;
|
|
17
|
+
isSymbolicLink(): boolean;
|
|
18
|
+
isFIFO(): boolean;
|
|
19
|
+
isSocket(): boolean;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=VirtualDirent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualDirent.d.ts","sourceRoot":"","sources":["../../src/wrappers/VirtualDirent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;GAEG;AACH,qBAAa,aAAc,YAAW,EAAE,CAAC,MAAM;IAC7C,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,KAAK,CAAS;gBAEV,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAMrE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,UAAU,IAAI,MAAM,CAMvB;IAED,MAAM,IAAI,OAAO;IAIjB,WAAW,IAAI,OAAO;IAItB,aAAa,IAAI,OAAO;IAIxB,iBAAiB,IAAI,OAAO;IAI5B,cAAc,IAAI,OAAO;IAIzB,MAAM,IAAI,OAAO;IAIjB,QAAQ,IAAI,OAAO;CAGpB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VirtualDirent = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Virtual Dirent that wraps a real fs.Dirent and exposes virtual paths
|
|
6
|
+
*/
|
|
7
|
+
class VirtualDirent {
|
|
8
|
+
constructor(realDirent, virtualPath, name) {
|
|
9
|
+
this.realDirent = realDirent;
|
|
10
|
+
this._virtualPath = virtualPath;
|
|
11
|
+
this._name = name || realDirent.name;
|
|
12
|
+
}
|
|
13
|
+
get name() {
|
|
14
|
+
return this._name;
|
|
15
|
+
}
|
|
16
|
+
get path() {
|
|
17
|
+
return this._virtualPath;
|
|
18
|
+
}
|
|
19
|
+
get parentPath() {
|
|
20
|
+
// Return the parent directory path
|
|
21
|
+
const parts = this._virtualPath.split('/').filter(Boolean);
|
|
22
|
+
if (parts.length === 0)
|
|
23
|
+
return '/';
|
|
24
|
+
parts.pop();
|
|
25
|
+
return '/' + parts.join('/');
|
|
26
|
+
}
|
|
27
|
+
isFile() {
|
|
28
|
+
return this.realDirent.isFile();
|
|
29
|
+
}
|
|
30
|
+
isDirectory() {
|
|
31
|
+
return this.realDirent.isDirectory();
|
|
32
|
+
}
|
|
33
|
+
isBlockDevice() {
|
|
34
|
+
return this.realDirent.isBlockDevice();
|
|
35
|
+
}
|
|
36
|
+
isCharacterDevice() {
|
|
37
|
+
return this.realDirent.isCharacterDevice();
|
|
38
|
+
}
|
|
39
|
+
isSymbolicLink() {
|
|
40
|
+
return this.realDirent.isSymbolicLink();
|
|
41
|
+
}
|
|
42
|
+
isFIFO() {
|
|
43
|
+
return this.realDirent.isFIFO();
|
|
44
|
+
}
|
|
45
|
+
isSocket() {
|
|
46
|
+
return this.realDirent.isSocket();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.VirtualDirent = VirtualDirent;
|
|
50
|
+
//# sourceMappingURL=VirtualDirent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualDirent.js","sourceRoot":"","sources":["../../src/wrappers/VirtualDirent.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,MAAa,aAAa;IAKxB,YAAY,UAAqB,EAAE,WAAmB,EAAE,IAAa;QACnE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC;IACvC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,UAAU;QACZ,mCAAmC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,GAAG,CAAC;QACnC,KAAK,CAAC,GAAG,EAAE,CAAC;QACZ,OAAO,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;IACzC,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC;IAC7C,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;CACF;AAtDD,sCAsDC"}
|
package/example.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const { VirtualFileSystem } = require("./dist/index.js");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
|
|
5
|
+
// Create a test directory
|
|
6
|
+
const testDir = path.join(__dirname, "test-data");
|
|
7
|
+
if (!fs.existsSync(testDir)) {
|
|
8
|
+
fs.mkdirSync(testDir);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Create a test file
|
|
12
|
+
fs.writeFileSync(path.join(testDir, "example.txt"), "Hello from VFS!");
|
|
13
|
+
fs.mkdirSync(path.join(testDir, "subdir"), { recursive: true });
|
|
14
|
+
fs.writeFileSync(
|
|
15
|
+
path.join(testDir, "subdir", "nested.txt"),
|
|
16
|
+
"Nested file content",
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
console.log("Test directory created at:", testDir);
|
|
20
|
+
console.log("");
|
|
21
|
+
|
|
22
|
+
// Create VFS instance
|
|
23
|
+
const vfs = new VirtualFileSystem({ root: testDir });
|
|
24
|
+
const vfsFs = vfs.createNodeFSModule();
|
|
25
|
+
const vfsPath = vfs.createNodePathModule();
|
|
26
|
+
|
|
27
|
+
console.log("=== VirtualFileSystem Test ===\n");
|
|
28
|
+
|
|
29
|
+
// Test path conversion
|
|
30
|
+
console.log("1. Path Conversion:");
|
|
31
|
+
console.log(" Virtual -> Real:", vfs.toRealPath("/example.txt"));
|
|
32
|
+
console.log(
|
|
33
|
+
" Real -> Virtual:",
|
|
34
|
+
vfs.toVirtualPath(path.join(testDir, "example.txt")),
|
|
35
|
+
);
|
|
36
|
+
console.log("");
|
|
37
|
+
|
|
38
|
+
// Test read operations
|
|
39
|
+
console.log("2. Read Operations:");
|
|
40
|
+
console.log(" readFileSync:", vfsFs.readFileSync("/example.txt", "utf8"));
|
|
41
|
+
console.log(" readdirSync:", vfsFs.readdirSync("/"));
|
|
42
|
+
console.log(
|
|
43
|
+
" statSync:",
|
|
44
|
+
vfsFs.statSync("/example.txt").isFile() ? "is a file" : "not a file",
|
|
45
|
+
);
|
|
46
|
+
console.log("");
|
|
47
|
+
|
|
48
|
+
// Test promise API
|
|
49
|
+
console.log("3. Promise API:");
|
|
50
|
+
vfsFs.promises
|
|
51
|
+
.readFile("/subdir/nested.txt", "utf8")
|
|
52
|
+
.then((content) => console.log(" promises.readFile:", content))
|
|
53
|
+
.catch((err) => console.error(" Error:", err.message));
|
|
54
|
+
|
|
55
|
+
// Test write operation (should fail)
|
|
56
|
+
console.log("");
|
|
57
|
+
console.log("4. Write Operation (should fail):");
|
|
58
|
+
try {
|
|
59
|
+
vfsFs.writeFileSync("/test.txt", "data");
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.log(" ✓ Write blocked with code:", err.code);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Test path module
|
|
65
|
+
console.log("");
|
|
66
|
+
console.log("5. Path Module:");
|
|
67
|
+
console.log(' resolve("."):', vfsPath.resolve("."));
|
|
68
|
+
console.log(' resolve("foo/bar.txt"):', vfsPath.resolve("foo/bar.txt"));
|
|
69
|
+
console.log(' join("/foo", "bar"):', vfsPath.join("/foo", "bar"));
|
|
70
|
+
console.log(" sep:", vfsPath.sep);
|
|
71
|
+
console.log(' dirname("/foo/bar.txt"):', vfsPath.dirname("/foo/bar.txt"));
|
|
72
|
+
console.log("");
|
|
73
|
+
|
|
74
|
+
// Test error filtering
|
|
75
|
+
console.log("6. Error Filtering:");
|
|
76
|
+
try {
|
|
77
|
+
vfsFs.readFileSync("/nonexistent.txt");
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.log(" Error message:", err.message);
|
|
80
|
+
console.log(" ✓ Real path filtered (no absolute path visible)");
|
|
81
|
+
}
|
|
82
|
+
console.log("");
|
|
83
|
+
|
|
84
|
+
// Test close
|
|
85
|
+
console.log("7. Close VFS:");
|
|
86
|
+
vfs.close();
|
|
87
|
+
console.log(" VFS closed:", vfs.closed);
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
vfsFs.readFileSync("/example.txt");
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.log(" ✓ Operations after close blocked with code:", err.code);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log("\n=== All Tests Passed! ===");
|
package/example.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { VirtualFileSystem, VFSOptions } from './dist/index';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
|
|
5
|
+
// Create test directory
|
|
6
|
+
const testDir = path.join(__dirname, 'test-data');
|
|
7
|
+
|
|
8
|
+
// Create VFS with TypeScript
|
|
9
|
+
const options: VFSOptions = { root: testDir };
|
|
10
|
+
const vfs: VirtualFileSystem = new VirtualFileSystem(options);
|
|
11
|
+
|
|
12
|
+
// Get typed fs and path modules
|
|
13
|
+
const vfsFs = vfs.createNodeFSModule();
|
|
14
|
+
const vfsPath = vfs.createNodePathModule();
|
|
15
|
+
|
|
16
|
+
// TypeScript knows the types!
|
|
17
|
+
const content: string = vfsFs.readFileSync('/example.txt', 'utf8');
|
|
18
|
+
const files: string[] = vfsFs.readdirSync('/') as string[];
|
|
19
|
+
const resolved: string = vfsPath.resolve('foo', 'bar');
|
|
20
|
+
|
|
21
|
+
console.log('TypeScript example works!');
|
|
22
|
+
console.log('Content:', content);
|
|
23
|
+
console.log('Files:', files);
|
|
24
|
+
console.log('Resolved:', resolved);
|
|
25
|
+
|
|
26
|
+
// Test promise API with async/await
|
|
27
|
+
(async () => {
|
|
28
|
+
const asyncContent: string = await vfsFs.promises.readFile('/example.txt', 'utf8');
|
|
29
|
+
console.log('Async content:', asyncContent);
|
|
30
|
+
})();
|
|
31
|
+
|
|
32
|
+
vfs.close();
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sandbox-fs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A read-only virtual file system that maps Unix-style virtual paths to a real directory root",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"filesystem",
|
|
14
|
+
"vfs",
|
|
15
|
+
"virtual",
|
|
16
|
+
"sandbox",
|
|
17
|
+
"readonly",
|
|
18
|
+
"fs"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^18.0.0",
|
|
27
|
+
"typescript": "^5.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|