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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -0
  3. package/dist/FSModule.d.ts +153 -0
  4. package/dist/FSModule.d.ts.map +1 -0
  5. package/dist/FSModule.js +555 -0
  6. package/dist/FSModule.js.map +1 -0
  7. package/dist/PathMapper.d.ts +30 -0
  8. package/dist/PathMapper.d.ts.map +1 -0
  9. package/dist/PathMapper.js +122 -0
  10. package/dist/PathMapper.js.map +1 -0
  11. package/dist/PathModule.d.ts +69 -0
  12. package/dist/PathModule.d.ts.map +1 -0
  13. package/dist/PathModule.js +159 -0
  14. package/dist/PathModule.js.map +1 -0
  15. package/dist/ResourceTracker.d.ts +74 -0
  16. package/dist/ResourceTracker.d.ts.map +1 -0
  17. package/dist/ResourceTracker.js +175 -0
  18. package/dist/ResourceTracker.js.map +1 -0
  19. package/dist/VirtualFileSystem.d.ts +145 -0
  20. package/dist/VirtualFileSystem.d.ts.map +1 -0
  21. package/dist/VirtualFileSystem.js +155 -0
  22. package/dist/VirtualFileSystem.js.map +1 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +13 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/operations/newer.d.ts +36 -0
  28. package/dist/operations/newer.d.ts.map +1 -0
  29. package/dist/operations/newer.js +239 -0
  30. package/dist/operations/newer.js.map +1 -0
  31. package/dist/operations/read.d.ts +24 -0
  32. package/dist/operations/read.d.ts.map +1 -0
  33. package/dist/operations/read.js +313 -0
  34. package/dist/operations/read.js.map +1 -0
  35. package/dist/operations/symlink.d.ts +8 -0
  36. package/dist/operations/symlink.d.ts.map +1 -0
  37. package/dist/operations/symlink.js +33 -0
  38. package/dist/operations/symlink.js.map +1 -0
  39. package/dist/operations/write.d.ts +29 -0
  40. package/dist/operations/write.d.ts.map +1 -0
  41. package/dist/operations/write.js +191 -0
  42. package/dist/operations/write.js.map +1 -0
  43. package/dist/utils/ErrorFilter.d.ts +6 -0
  44. package/dist/utils/ErrorFilter.d.ts.map +1 -0
  45. package/dist/utils/ErrorFilter.js +57 -0
  46. package/dist/utils/ErrorFilter.js.map +1 -0
  47. package/dist/utils/callbackify.d.ts +9 -0
  48. package/dist/utils/callbackify.d.ts.map +1 -0
  49. package/dist/utils/callbackify.js +48 -0
  50. package/dist/utils/callbackify.js.map +1 -0
  51. package/dist/wrappers/VirtualDir.d.ts +34 -0
  52. package/dist/wrappers/VirtualDir.d.ts.map +1 -0
  53. package/dist/wrappers/VirtualDir.js +72 -0
  54. package/dist/wrappers/VirtualDir.js.map +1 -0
  55. package/dist/wrappers/VirtualDirent.d.ts +21 -0
  56. package/dist/wrappers/VirtualDirent.d.ts.map +1 -0
  57. package/dist/wrappers/VirtualDirent.js +50 -0
  58. package/dist/wrappers/VirtualDirent.js.map +1 -0
  59. package/example.js +95 -0
  60. package/example.ts +32 -0
  61. package/package.json +29 -0
  62. package/src/FSModule.ts +546 -0
  63. package/src/PathMapper.ts +102 -0
  64. package/src/PathModule.ts +142 -0
  65. package/src/ResourceTracker.ts +162 -0
  66. package/src/VirtualFileSystem.ts +172 -0
  67. package/src/index.ts +9 -0
  68. package/src/operations/newer.ts +223 -0
  69. package/src/operations/read.ts +319 -0
  70. package/src/operations/symlink.ts +31 -0
  71. package/src/operations/write.ts +189 -0
  72. package/src/utils/ErrorFilter.ts +57 -0
  73. package/src/utils/callbackify.ts +54 -0
  74. package/src/wrappers/VirtualDir.ts +84 -0
  75. package/src/wrappers/VirtualDirent.ts +60 -0
  76. package/test-data/example.txt +1 -0
  77. package/test-data/subdir/nested.txt +1 -0
  78. package/tsconfig.example.json +8 -0
  79. 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
+ }