host.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright Google LLC All Rights Reserved.
  5. *
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://angular.dev/license
  8. */
  9. Object.defineProperty(exports, "__esModule", { value: true });
  10. exports.NodeJsSyncHost = exports.NodeJsAsyncHost = void 0;
  11. const node_fs_1 = require("node:fs");
  12. const node_path_1 = require("node:path");
  13. const rxjs_1 = require("rxjs");
  14. const src_1 = require("../src");
  15. async function exists(path) {
  16. try {
  17. await node_fs_1.promises.access(path, node_fs_1.constants.F_OK);
  18. return true;
  19. }
  20. catch {
  21. return false;
  22. }
  23. }
  24. // This will only be initialized if the watch() method is called.
  25. // Otherwise chokidar appears only in type positions, and shouldn't be referenced
  26. // in the JavaScript output.
  27. let FSWatcher;
  28. function loadFSWatcher() {
  29. if (!FSWatcher) {
  30. try {
  31. FSWatcher = require('chokidar').FSWatcher;
  32. }
  33. catch (e) {
  34. if (e.code !== 'MODULE_NOT_FOUND') {
  35. throw new Error('As of angular-devkit version 8.0, the "chokidar" package ' +
  36. 'must be installed in order to use watch() features.');
  37. }
  38. throw e;
  39. }
  40. }
  41. }
  42. /**
  43. * An implementation of the Virtual FS using Node as the background. There are two versions; one
  44. * synchronous and one asynchronous.
  45. */
  46. class NodeJsAsyncHost {
  47. get capabilities() {
  48. return { synchronous: false };
  49. }
  50. write(path, content) {
  51. return (0, rxjs_1.from)(node_fs_1.promises.mkdir((0, src_1.getSystemPath)((0, src_1.dirname)(path)), { recursive: true })).pipe((0, rxjs_1.mergeMap)(() => node_fs_1.promises.writeFile((0, src_1.getSystemPath)(path), new Uint8Array(content))));
  52. }
  53. read(path) {
  54. return (0, rxjs_1.from)(node_fs_1.promises.readFile((0, src_1.getSystemPath)(path))).pipe((0, rxjs_1.map)((buffer) => new Uint8Array(buffer).buffer));
  55. }
  56. delete(path) {
  57. return (0, rxjs_1.from)(node_fs_1.promises.rm((0, src_1.getSystemPath)(path), { force: true, recursive: true, maxRetries: 3 }));
  58. }
  59. rename(from, to) {
  60. return (0, rxjs_1.from)(node_fs_1.promises.rename((0, src_1.getSystemPath)(from), (0, src_1.getSystemPath)(to)));
  61. }
  62. list(path) {
  63. return (0, rxjs_1.from)(node_fs_1.promises.readdir((0, src_1.getSystemPath)(path))).pipe((0, rxjs_1.map)((names) => names.map((name) => (0, src_1.fragment)(name))));
  64. }
  65. exists(path) {
  66. return (0, rxjs_1.from)(exists((0, src_1.getSystemPath)(path)));
  67. }
  68. isDirectory(path) {
  69. return this.stat(path).pipe((0, rxjs_1.map)((stat) => stat.isDirectory()));
  70. }
  71. isFile(path) {
  72. return this.stat(path).pipe((0, rxjs_1.map)((stat) => stat.isFile()));
  73. }
  74. // Some hosts may not support stat.
  75. stat(path) {
  76. return (0, rxjs_1.from)(node_fs_1.promises.stat((0, src_1.getSystemPath)(path)));
  77. }
  78. // Some hosts may not support watching.
  79. watch(path, _options) {
  80. return new rxjs_1.Observable((obs) => {
  81. loadFSWatcher();
  82. const watcher = new FSWatcher({ persistent: true });
  83. watcher.add((0, src_1.getSystemPath)(path));
  84. watcher
  85. .on('change', (path) => {
  86. obs.next({
  87. path: (0, src_1.normalize)(path),
  88. time: new Date(),
  89. type: src_1.virtualFs.HostWatchEventType.Changed,
  90. });
  91. })
  92. .on('add', (path) => {
  93. obs.next({
  94. path: (0, src_1.normalize)(path),
  95. time: new Date(),
  96. type: src_1.virtualFs.HostWatchEventType.Created,
  97. });
  98. })
  99. .on('unlink', (path) => {
  100. obs.next({
  101. path: (0, src_1.normalize)(path),
  102. time: new Date(),
  103. type: src_1.virtualFs.HostWatchEventType.Deleted,
  104. });
  105. });
  106. return () => {
  107. void watcher.close();
  108. };
  109. }).pipe((0, rxjs_1.publish)(), (0, rxjs_1.refCount)());
  110. }
  111. }
  112. exports.NodeJsAsyncHost = NodeJsAsyncHost;
  113. /**
  114. * An implementation of the Virtual FS using Node as the backend, synchronously.
  115. */
  116. class NodeJsSyncHost {
  117. get capabilities() {
  118. return { synchronous: true };
  119. }
  120. write(path, content) {
  121. return new rxjs_1.Observable((obs) => {
  122. (0, node_fs_1.mkdirSync)((0, src_1.getSystemPath)((0, src_1.dirname)(path)), { recursive: true });
  123. (0, node_fs_1.writeFileSync)((0, src_1.getSystemPath)(path), new Uint8Array(content));
  124. obs.next();
  125. obs.complete();
  126. });
  127. }
  128. read(path) {
  129. return new rxjs_1.Observable((obs) => {
  130. const buffer = (0, node_fs_1.readFileSync)((0, src_1.getSystemPath)(path));
  131. obs.next(new Uint8Array(buffer).buffer);
  132. obs.complete();
  133. });
  134. }
  135. delete(path) {
  136. return new rxjs_1.Observable((obs) => {
  137. (0, node_fs_1.rmSync)((0, src_1.getSystemPath)(path), { force: true, recursive: true, maxRetries: 3 });
  138. obs.complete();
  139. });
  140. }
  141. rename(from, to) {
  142. return new rxjs_1.Observable((obs) => {
  143. const toSystemPath = (0, src_1.getSystemPath)(to);
  144. (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(toSystemPath), { recursive: true });
  145. (0, node_fs_1.renameSync)((0, src_1.getSystemPath)(from), toSystemPath);
  146. obs.next();
  147. obs.complete();
  148. });
  149. }
  150. list(path) {
  151. return new rxjs_1.Observable((obs) => {
  152. const names = (0, node_fs_1.readdirSync)((0, src_1.getSystemPath)(path));
  153. obs.next(names.map((name) => (0, src_1.fragment)(name)));
  154. obs.complete();
  155. });
  156. }
  157. exists(path) {
  158. return new rxjs_1.Observable((obs) => {
  159. obs.next((0, node_fs_1.existsSync)((0, src_1.getSystemPath)(path)));
  160. obs.complete();
  161. });
  162. }
  163. isDirectory(path) {
  164. return this.stat(path).pipe((0, rxjs_1.map)((stat) => stat.isDirectory()));
  165. }
  166. isFile(path) {
  167. return this.stat(path).pipe((0, rxjs_1.map)((stat) => stat.isFile()));
  168. }
  169. // Some hosts may not support stat.
  170. stat(path) {
  171. return new rxjs_1.Observable((obs) => {
  172. obs.next((0, node_fs_1.statSync)((0, src_1.getSystemPath)(path)));
  173. obs.complete();
  174. });
  175. }
  176. // Some hosts may not support watching.
  177. watch(path, _options) {
  178. return new rxjs_1.Observable((obs) => {
  179. loadFSWatcher();
  180. const watcher = new FSWatcher({ persistent: false });
  181. watcher.add((0, src_1.getSystemPath)(path));
  182. watcher
  183. .on('change', (path) => {
  184. obs.next({
  185. path: (0, src_1.normalize)(path),
  186. time: new Date(),
  187. type: src_1.virtualFs.HostWatchEventType.Changed,
  188. });
  189. })
  190. .on('add', (path) => {
  191. obs.next({
  192. path: (0, src_1.normalize)(path),
  193. time: new Date(),
  194. type: src_1.virtualFs.HostWatchEventType.Created,
  195. });
  196. })
  197. .on('unlink', (path) => {
  198. obs.next({
  199. path: (0, src_1.normalize)(path),
  200. time: new Date(),
  201. type: src_1.virtualFs.HostWatchEventType.Deleted,
  202. });
  203. });
  204. return () => {
  205. void watcher.close();
  206. };
  207. }).pipe((0, rxjs_1.publish)(), (0, rxjs_1.refCount)());
  208. }
  209. }
  210. exports.NodeJsSyncHost = NodeJsSyncHost;