VirtualFS.js 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.VirtualFS = void 0;
  4. const NodeFS_1 = require("./NodeFS");
  5. const ProxiedFS_1 = require("./ProxiedFS");
  6. const path_1 = require("./path");
  7. const NUMBER_REGEXP = /^[0-9]+$/;
  8. // $0: full path
  9. // $1: virtual folder
  10. // $2: virtual segment
  11. // $3: hash
  12. // $4: depth
  13. // $5: subpath
  14. const VIRTUAL_REGEXP = /^(\/(?:[^/]+\/)*?(?:\$\$virtual|__virtual__))((?:\/((?:[^/]+-)?[a-f0-9]+)(?:\/([^/]+))?)?((?:\/.*)?))$/;
  15. const VALID_COMPONENT = /^([^/]+-)?[a-f0-9]+$/;
  16. class VirtualFS extends ProxiedFS_1.ProxiedFS {
  17. static makeVirtualPath(base, component, to) {
  18. if (path_1.ppath.basename(base) !== `__virtual__`)
  19. throw new Error(`Assertion failed: Virtual folders must be named "__virtual__"`);
  20. if (!path_1.ppath.basename(component).match(VALID_COMPONENT))
  21. throw new Error(`Assertion failed: Virtual components must be ended by an hexadecimal hash`);
  22. // Obtains the relative distance between the virtual path and its actual target
  23. const target = path_1.ppath.relative(path_1.ppath.dirname(base), to);
  24. const segments = target.split(`/`);
  25. // Counts how many levels we need to go back to start applying the rest of the path
  26. let depth = 0;
  27. while (depth < segments.length && segments[depth] === `..`)
  28. depth += 1;
  29. const finalSegments = segments.slice(depth);
  30. const fullVirtualPath = path_1.ppath.join(base, component, String(depth), ...finalSegments);
  31. return fullVirtualPath;
  32. }
  33. static resolveVirtual(p) {
  34. const match = p.match(VIRTUAL_REGEXP);
  35. if (!match || (!match[3] && match[5]))
  36. return p;
  37. const target = path_1.ppath.dirname(match[1]);
  38. if (!match[3] || !match[4])
  39. return target;
  40. const isnum = NUMBER_REGEXP.test(match[4]);
  41. if (!isnum)
  42. return p;
  43. const depth = Number(match[4]);
  44. const backstep = `../`.repeat(depth);
  45. const subpath = (match[5] || `.`);
  46. return VirtualFS.resolveVirtual(path_1.ppath.join(target, backstep, subpath));
  47. }
  48. constructor({ baseFs = new NodeFS_1.NodeFS() } = {}) {
  49. super(path_1.ppath);
  50. this.baseFs = baseFs;
  51. }
  52. getExtractHint(hints) {
  53. return this.baseFs.getExtractHint(hints);
  54. }
  55. getRealPath() {
  56. return this.baseFs.getRealPath();
  57. }
  58. realpathSync(p) {
  59. const match = p.match(VIRTUAL_REGEXP);
  60. if (!match)
  61. return this.baseFs.realpathSync(p);
  62. if (!match[5])
  63. return p;
  64. const realpath = this.baseFs.realpathSync(this.mapToBase(p));
  65. return VirtualFS.makeVirtualPath(match[1], match[3], realpath);
  66. }
  67. async realpathPromise(p) {
  68. const match = p.match(VIRTUAL_REGEXP);
  69. if (!match)
  70. return await this.baseFs.realpathPromise(p);
  71. if (!match[5])
  72. return p;
  73. const realpath = await this.baseFs.realpathPromise(this.mapToBase(p));
  74. return VirtualFS.makeVirtualPath(match[1], match[3], realpath);
  75. }
  76. mapToBase(p) {
  77. if (p === ``)
  78. return p;
  79. if (this.pathUtils.isAbsolute(p))
  80. return VirtualFS.resolveVirtual(p);
  81. const resolvedRoot = VirtualFS.resolveVirtual(this.baseFs.resolve(path_1.PortablePath.dot));
  82. const resolvedP = VirtualFS.resolveVirtual(this.baseFs.resolve(p));
  83. return path_1.ppath.relative(resolvedRoot, resolvedP) || path_1.PortablePath.dot;
  84. }
  85. mapFromBase(p) {
  86. return p;
  87. }
  88. }
  89. exports.VirtualFS = VirtualFS;