UNPKG

10.9 kBJavaScriptView Raw
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.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.SimpleMemoryHost = void 0;
11const rxjs_1 = require("rxjs");
12const exception_1 = require("../../exception");
13const path_1 = require("../path");
14class SimpleMemoryHost {
15 constructor() {
16 this._cache = new Map();
17 this._watchers = new Map();
18 this._cache.set((0, path_1.normalize)('/'), this._newDirStats());
19 }
20 _newDirStats() {
21 return {
22 inspect() {
23 return '<Directory>';
24 },
25 isFile() {
26 return false;
27 },
28 isDirectory() {
29 return true;
30 },
31 size: 0,
32 atime: new Date(),
33 ctime: new Date(),
34 mtime: new Date(),
35 birthtime: new Date(),
36 content: null,
37 };
38 }
39 _newFileStats(content, oldStats) {
40 return {
41 inspect() {
42 return `<File size(${content.byteLength})>`;
43 },
44 isFile() {
45 return true;
46 },
47 isDirectory() {
48 return false;
49 },
50 size: content.byteLength,
51 atime: oldStats ? oldStats.atime : new Date(),
52 ctime: new Date(),
53 mtime: new Date(),
54 birthtime: oldStats ? oldStats.birthtime : new Date(),
55 content,
56 };
57 }
58 _toAbsolute(path) {
59 return (0, path_1.isAbsolute)(path) ? path : (0, path_1.normalize)('/' + path);
60 }
61 _updateWatchers(path, type) {
62 const time = new Date();
63 let currentPath = path;
64 let parent = null;
65 if (this._watchers.size == 0) {
66 // Nothing to do if there's no watchers.
67 return;
68 }
69 const maybeWatcher = this._watchers.get(currentPath);
70 if (maybeWatcher) {
71 maybeWatcher.forEach((watcher) => {
72 const [options, subject] = watcher;
73 subject.next({ path, time, type });
74 if (!options.persistent && type == 2 /* Deleted */) {
75 subject.complete();
76 this._watchers.delete(currentPath);
77 }
78 });
79 }
80 do {
81 currentPath = parent !== null ? parent : currentPath;
82 parent = (0, path_1.dirname)(currentPath);
83 const maybeWatcher = this._watchers.get(currentPath);
84 if (maybeWatcher) {
85 maybeWatcher.forEach((watcher) => {
86 const [options, subject] = watcher;
87 if (!options.recursive) {
88 return;
89 }
90 subject.next({ path, time, type });
91 if (!options.persistent && type == 2 /* Deleted */) {
92 subject.complete();
93 this._watchers.delete(currentPath);
94 }
95 });
96 }
97 } while (parent != currentPath);
98 }
99 get capabilities() {
100 return { synchronous: true };
101 }
102 /**
103 * List of protected methods that give direct access outside the observables to the cache
104 * and internal states.
105 */
106 _write(path, content) {
107 path = this._toAbsolute(path);
108 const old = this._cache.get(path);
109 if (old && old.isDirectory()) {
110 throw new exception_1.PathIsDirectoryException(path);
111 }
112 // Update all directories. If we find a file we know it's an invalid write.
113 const fragments = (0, path_1.split)(path);
114 let curr = (0, path_1.normalize)('/');
115 for (const fr of fragments) {
116 curr = (0, path_1.join)(curr, fr);
117 const maybeStats = this._cache.get(fr);
118 if (maybeStats) {
119 if (maybeStats.isFile()) {
120 throw new exception_1.PathIsFileException(curr);
121 }
122 }
123 else {
124 this._cache.set(curr, this._newDirStats());
125 }
126 }
127 // Create the stats.
128 const stats = this._newFileStats(content, old);
129 this._cache.set(path, stats);
130 this._updateWatchers(path, old ? 0 /* Changed */ : 1 /* Created */);
131 }
132 _read(path) {
133 path = this._toAbsolute(path);
134 const maybeStats = this._cache.get(path);
135 if (!maybeStats) {
136 throw new exception_1.FileDoesNotExistException(path);
137 }
138 else if (maybeStats.isDirectory()) {
139 throw new exception_1.PathIsDirectoryException(path);
140 }
141 else if (!maybeStats.content) {
142 throw new exception_1.PathIsDirectoryException(path);
143 }
144 else {
145 return maybeStats.content;
146 }
147 }
148 _delete(path) {
149 path = this._toAbsolute(path);
150 if (this._isDirectory(path)) {
151 for (const [cachePath] of this._cache.entries()) {
152 if (cachePath.startsWith(path + path_1.NormalizedSep) || cachePath === path) {
153 this._cache.delete(cachePath);
154 }
155 }
156 }
157 else {
158 this._cache.delete(path);
159 }
160 this._updateWatchers(path, 2 /* Deleted */);
161 }
162 _rename(from, to) {
163 from = this._toAbsolute(from);
164 to = this._toAbsolute(to);
165 if (!this._cache.has(from)) {
166 throw new exception_1.FileDoesNotExistException(from);
167 }
168 else if (this._cache.has(to)) {
169 throw new exception_1.FileAlreadyExistException(to);
170 }
171 if (this._isDirectory(from)) {
172 for (const path of this._cache.keys()) {
173 if (path.startsWith(from + path_1.NormalizedSep)) {
174 const content = this._cache.get(path);
175 if (content) {
176 // We don't need to clone or extract the content, since we're moving files.
177 this._cache.set((0, path_1.join)(to, path_1.NormalizedSep, path.slice(from.length)), content);
178 }
179 }
180 }
181 }
182 else {
183 const content = this._cache.get(from);
184 if (content) {
185 const fragments = (0, path_1.split)(to);
186 const newDirectories = [];
187 let curr = (0, path_1.normalize)('/');
188 for (const fr of fragments) {
189 curr = (0, path_1.join)(curr, fr);
190 const maybeStats = this._cache.get(fr);
191 if (maybeStats) {
192 if (maybeStats.isFile()) {
193 throw new exception_1.PathIsFileException(curr);
194 }
195 }
196 else {
197 newDirectories.push(curr);
198 }
199 }
200 for (const newDirectory of newDirectories) {
201 this._cache.set(newDirectory, this._newDirStats());
202 }
203 this._cache.delete(from);
204 this._cache.set(to, content);
205 }
206 }
207 this._updateWatchers(from, 3 /* Renamed */);
208 }
209 _list(path) {
210 path = this._toAbsolute(path);
211 if (this._isFile(path)) {
212 throw new exception_1.PathIsFileException(path);
213 }
214 const fragments = (0, path_1.split)(path);
215 const result = new Set();
216 if (path !== path_1.NormalizedRoot) {
217 for (const p of this._cache.keys()) {
218 if (p.startsWith(path + path_1.NormalizedSep)) {
219 result.add((0, path_1.split)(p)[fragments.length]);
220 }
221 }
222 }
223 else {
224 for (const p of this._cache.keys()) {
225 if (p.startsWith(path_1.NormalizedSep) && p !== path_1.NormalizedRoot) {
226 result.add((0, path_1.split)(p)[1]);
227 }
228 }
229 }
230 return [...result];
231 }
232 _exists(path) {
233 return !!this._cache.get(this._toAbsolute(path));
234 }
235 _isDirectory(path) {
236 const maybeStats = this._cache.get(this._toAbsolute(path));
237 return maybeStats ? maybeStats.isDirectory() : false;
238 }
239 _isFile(path) {
240 const maybeStats = this._cache.get(this._toAbsolute(path));
241 return maybeStats ? maybeStats.isFile() : false;
242 }
243 _stat(path) {
244 const maybeStats = this._cache.get(this._toAbsolute(path));
245 if (!maybeStats) {
246 return null;
247 }
248 else {
249 return maybeStats;
250 }
251 }
252 _watch(path, options) {
253 path = this._toAbsolute(path);
254 const subject = new rxjs_1.Subject();
255 let maybeWatcherArray = this._watchers.get(path);
256 if (!maybeWatcherArray) {
257 maybeWatcherArray = [];
258 this._watchers.set(path, maybeWatcherArray);
259 }
260 maybeWatcherArray.push([options || {}, subject]);
261 return subject.asObservable();
262 }
263 write(path, content) {
264 return new rxjs_1.Observable((obs) => {
265 this._write(path, content);
266 obs.next();
267 obs.complete();
268 });
269 }
270 read(path) {
271 return new rxjs_1.Observable((obs) => {
272 const content = this._read(path);
273 obs.next(content);
274 obs.complete();
275 });
276 }
277 delete(path) {
278 return new rxjs_1.Observable((obs) => {
279 this._delete(path);
280 obs.next();
281 obs.complete();
282 });
283 }
284 rename(from, to) {
285 return new rxjs_1.Observable((obs) => {
286 this._rename(from, to);
287 obs.next();
288 obs.complete();
289 });
290 }
291 list(path) {
292 return new rxjs_1.Observable((obs) => {
293 obs.next(this._list(path));
294 obs.complete();
295 });
296 }
297 exists(path) {
298 return new rxjs_1.Observable((obs) => {
299 obs.next(this._exists(path));
300 obs.complete();
301 });
302 }
303 isDirectory(path) {
304 return new rxjs_1.Observable((obs) => {
305 obs.next(this._isDirectory(path));
306 obs.complete();
307 });
308 }
309 isFile(path) {
310 return new rxjs_1.Observable((obs) => {
311 obs.next(this._isFile(path));
312 obs.complete();
313 });
314 }
315 // Some hosts may not support stat.
316 stat(path) {
317 return new rxjs_1.Observable((obs) => {
318 obs.next(this._stat(path));
319 obs.complete();
320 });
321 }
322 watch(path, options) {
323 return this._watch(path, options);
324 }
325 reset() {
326 this._cache.clear();
327 this._watchers.clear();
328 }
329}
330exports.SimpleMemoryHost = SimpleMemoryHost;