source: trip-planner-front/node_modules/@angular-devkit/schematics/src/tree/host-tree.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 14.9 KB
Line 
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.FilterHostTree = exports.HostCreateTree = exports.HostTree = exports.HostDirEntry = void 0;
11const core_1 = require("@angular-devkit/core");
12const rxjs_1 = require("rxjs");
13const operators_1 = require("rxjs/operators");
14const exception_1 = require("../exception/exception");
15const delegate_1 = require("./delegate");
16const entry_1 = require("./entry");
17const interface_1 = require("./interface");
18const recorder_1 = require("./recorder");
19const scoped_1 = require("./scoped");
20let _uniqueId = 0;
21class HostDirEntry {
22 constructor(parent, path, _host, _tree) {
23 this.parent = parent;
24 this.path = path;
25 this._host = _host;
26 this._tree = _tree;
27 }
28 get subdirs() {
29 return this._host
30 .list(this.path)
31 .filter((fragment) => this._host.isDirectory(core_1.join(this.path, fragment)));
32 }
33 get subfiles() {
34 return this._host
35 .list(this.path)
36 .filter((fragment) => this._host.isFile(core_1.join(this.path, fragment)));
37 }
38 dir(name) {
39 return this._tree.getDir(core_1.join(this.path, name));
40 }
41 file(name) {
42 return this._tree.get(core_1.join(this.path, name));
43 }
44 visit(visitor) {
45 try {
46 this.getSubfilesRecursively().forEach((file) => visitor(file.path, file));
47 }
48 catch (e) {
49 if (e !== interface_1.FileVisitorCancelToken) {
50 throw e;
51 }
52 }
53 }
54 getSubfilesRecursively() {
55 function _recurse(entry) {
56 return entry.subdirs.reduce((files, subdir) => [...files, ..._recurse(entry.dir(subdir))], entry.subfiles.map((subfile) => entry.file(subfile)));
57 }
58 return _recurse(this);
59 }
60}
61exports.HostDirEntry = HostDirEntry;
62class HostTree {
63 constructor(_backend = new core_1.virtualFs.Empty()) {
64 this._backend = _backend;
65 this._id = --_uniqueId;
66 this._ancestry = new Set();
67 this._dirCache = new Map();
68 this._record = new core_1.virtualFs.CordHost(new core_1.virtualFs.SafeReadonlyHost(_backend));
69 this._recordSync = new core_1.virtualFs.SyncDelegateHost(this._record);
70 }
71 [interface_1.TreeSymbol]() {
72 return this;
73 }
74 static isHostTree(tree) {
75 if (tree instanceof HostTree) {
76 return true;
77 }
78 if (typeof tree === 'object' && typeof tree._ancestry === 'object') {
79 return true;
80 }
81 return false;
82 }
83 _normalizePath(path) {
84 return core_1.normalize('/' + path);
85 }
86 _willCreate(path) {
87 return this._record.willCreate(path);
88 }
89 _willOverwrite(path) {
90 return this._record.willOverwrite(path);
91 }
92 _willDelete(path) {
93 return this._record.willDelete(path);
94 }
95 _willRename(path) {
96 return this._record.willRename(path);
97 }
98 branch() {
99 const branchedTree = new HostTree(this._backend);
100 branchedTree._record = this._record.clone();
101 branchedTree._recordSync = new core_1.virtualFs.SyncDelegateHost(branchedTree._record);
102 branchedTree._ancestry = new Set(this._ancestry).add(this._id);
103 return branchedTree;
104 }
105 isAncestorOf(tree) {
106 if (tree instanceof HostTree) {
107 return tree._ancestry.has(this._id);
108 }
109 if (tree instanceof delegate_1.DelegateTree) {
110 return this.isAncestorOf(tree._other);
111 }
112 if (tree instanceof scoped_1.ScopedTree) {
113 return this.isAncestorOf(tree._base);
114 }
115 return false;
116 }
117 merge(other, strategy = interface_1.MergeStrategy.Default) {
118 if (other === this) {
119 // Merging with yourself? Tsk tsk. Nothing to do at least.
120 return;
121 }
122 if (this.isAncestorOf(other)) {
123 // Workaround for merging a branch back into one of its ancestors
124 // More complete branch point tracking is required to avoid
125 strategy |= interface_1.MergeStrategy.Overwrite;
126 }
127 const creationConflictAllowed = (strategy & interface_1.MergeStrategy.AllowCreationConflict) == interface_1.MergeStrategy.AllowCreationConflict;
128 const overwriteConflictAllowed = (strategy & interface_1.MergeStrategy.AllowOverwriteConflict) == interface_1.MergeStrategy.AllowOverwriteConflict;
129 const deleteConflictAllowed = (strategy & interface_1.MergeStrategy.AllowDeleteConflict) == interface_1.MergeStrategy.AllowDeleteConflict;
130 other.actions.forEach((action) => {
131 switch (action.kind) {
132 case 'c': {
133 const { path, content } = action;
134 if (this._willCreate(path) || this._willOverwrite(path) || this.exists(path)) {
135 const existingContent = this.read(path);
136 if (existingContent && content.equals(existingContent)) {
137 // Identical outcome; no action required
138 return;
139 }
140 if (!creationConflictAllowed) {
141 throw new exception_1.MergeConflictException(path);
142 }
143 this._record.overwrite(path, content).subscribe();
144 }
145 else {
146 this._record.create(path, content).subscribe();
147 }
148 return;
149 }
150 case 'o': {
151 const { path, content } = action;
152 if (this._willDelete(path) && !overwriteConflictAllowed) {
153 throw new exception_1.MergeConflictException(path);
154 }
155 // Ignore if content is the same (considered the same change).
156 if (this._willOverwrite(path)) {
157 const existingContent = this.read(path);
158 if (existingContent && content.equals(existingContent)) {
159 // Identical outcome; no action required
160 return;
161 }
162 if (!overwriteConflictAllowed) {
163 throw new exception_1.MergeConflictException(path);
164 }
165 }
166 // We use write here as merge validation has already been done, and we want to let
167 // the CordHost do its job.
168 this._record.write(path, content).subscribe();
169 return;
170 }
171 case 'r': {
172 const { path, to } = action;
173 if (this._willDelete(path)) {
174 throw new exception_1.MergeConflictException(path);
175 }
176 if (this._willRename(path)) {
177 if (this._record.willRenameTo(path, to)) {
178 // Identical outcome; no action required
179 return;
180 }
181 // No override possible for renaming.
182 throw new exception_1.MergeConflictException(path);
183 }
184 this.rename(path, to);
185 return;
186 }
187 case 'd': {
188 const { path } = action;
189 if (this._willDelete(path)) {
190 // TODO: This should technically check the content (e.g., hash on delete)
191 // Identical outcome; no action required
192 return;
193 }
194 if (!this.exists(path) && !deleteConflictAllowed) {
195 throw new exception_1.MergeConflictException(path);
196 }
197 this._recordSync.delete(path);
198 return;
199 }
200 }
201 });
202 }
203 get root() {
204 return this.getDir('/');
205 }
206 // Readonly.
207 read(path) {
208 const entry = this.get(path);
209 return entry ? entry.content : null;
210 }
211 exists(path) {
212 return this._recordSync.isFile(this._normalizePath(path));
213 }
214 get(path) {
215 const p = this._normalizePath(path);
216 if (this._recordSync.isDirectory(p)) {
217 throw new core_1.PathIsDirectoryException(p);
218 }
219 if (!this._recordSync.exists(p)) {
220 return null;
221 }
222 return new entry_1.LazyFileEntry(p, () => Buffer.from(this._recordSync.read(p)));
223 }
224 getDir(path) {
225 const p = this._normalizePath(path);
226 if (this._recordSync.isFile(p)) {
227 throw new core_1.PathIsFileException(p);
228 }
229 let maybeCache = this._dirCache.get(p);
230 if (!maybeCache) {
231 let parent = core_1.dirname(p);
232 if (p === parent) {
233 parent = null;
234 }
235 maybeCache = new HostDirEntry(parent && this.getDir(parent), p, this._recordSync, this);
236 this._dirCache.set(p, maybeCache);
237 }
238 return maybeCache;
239 }
240 visit(visitor) {
241 this.root.visit((path, entry) => {
242 visitor(path, entry);
243 });
244 }
245 // Change content of host files.
246 overwrite(path, content) {
247 const p = this._normalizePath(path);
248 if (!this._recordSync.exists(p)) {
249 throw new exception_1.FileDoesNotExistException(p);
250 }
251 const c = typeof content == 'string' ? Buffer.from(content) : content;
252 this._record.overwrite(p, c).subscribe();
253 }
254 beginUpdate(path) {
255 const entry = this.get(path);
256 if (!entry) {
257 throw new exception_1.FileDoesNotExistException(path);
258 }
259 return recorder_1.UpdateRecorderBase.createFromFileEntry(entry);
260 }
261 commitUpdate(record) {
262 if (record instanceof recorder_1.UpdateRecorderBase) {
263 const path = record.path;
264 const entry = this.get(path);
265 if (!entry) {
266 throw new exception_1.ContentHasMutatedException(path);
267 }
268 else {
269 const newContent = record.apply(entry.content);
270 if (!newContent.equals(entry.content)) {
271 this.overwrite(path, newContent);
272 }
273 }
274 }
275 else {
276 throw new exception_1.InvalidUpdateRecordException();
277 }
278 }
279 // Structural methods.
280 create(path, content) {
281 const p = this._normalizePath(path);
282 if (this._recordSync.exists(p)) {
283 throw new exception_1.FileAlreadyExistException(p);
284 }
285 const c = typeof content == 'string' ? Buffer.from(content) : content;
286 this._record.create(p, c).subscribe();
287 }
288 delete(path) {
289 this._recordSync.delete(this._normalizePath(path));
290 }
291 rename(from, to) {
292 this._recordSync.rename(this._normalizePath(from), this._normalizePath(to));
293 }
294 apply(action, strategy) {
295 throw new exception_1.SchematicsException('Apply not implemented on host trees.');
296 }
297 *generateActions() {
298 for (const record of this._record.records()) {
299 switch (record.kind) {
300 case 'create':
301 yield {
302 id: this._id,
303 parent: 0,
304 kind: 'c',
305 path: record.path,
306 content: Buffer.from(record.content),
307 };
308 break;
309 case 'overwrite':
310 yield {
311 id: this._id,
312 parent: 0,
313 kind: 'o',
314 path: record.path,
315 content: Buffer.from(record.content),
316 };
317 break;
318 case 'rename':
319 yield {
320 id: this._id,
321 parent: 0,
322 kind: 'r',
323 path: record.from,
324 to: record.to,
325 };
326 break;
327 case 'delete':
328 yield {
329 id: this._id,
330 parent: 0,
331 kind: 'd',
332 path: record.path,
333 };
334 break;
335 }
336 }
337 }
338 get actions() {
339 // Create a list of all records until we hit our original backend. This is to support branches
340 // that diverge from each others.
341 return Array.from(this.generateActions());
342 }
343}
344exports.HostTree = HostTree;
345class HostCreateTree extends HostTree {
346 constructor(host) {
347 super();
348 const tempHost = new HostTree(host);
349 tempHost.visit((path) => {
350 const content = tempHost.read(path);
351 if (content) {
352 this.create(path, content);
353 }
354 });
355 }
356}
357exports.HostCreateTree = HostCreateTree;
358class FilterHostTree extends HostTree {
359 constructor(tree, filter = () => true) {
360 const newBackend = new core_1.virtualFs.SimpleMemoryHost();
361 // cast to allow access
362 const originalBackend = tree._backend;
363 const recurse = (base) => {
364 return originalBackend.list(base).pipe(operators_1.mergeMap((x) => x), operators_1.map((path) => core_1.join(base, path)), operators_1.concatMap((path) => {
365 let isDirectory = false;
366 originalBackend.isDirectory(path).subscribe((val) => (isDirectory = val));
367 if (isDirectory) {
368 return recurse(path);
369 }
370 let isFile = false;
371 originalBackend.isFile(path).subscribe((val) => (isFile = val));
372 if (!isFile || !filter(path)) {
373 return rxjs_1.EMPTY;
374 }
375 let content = null;
376 originalBackend.read(path).subscribe((val) => (content = val));
377 if (!content) {
378 return rxjs_1.EMPTY;
379 }
380 return newBackend.write(path, content);
381 }));
382 };
383 recurse(core_1.normalize('/')).subscribe();
384 super(newBackend);
385 for (const action of tree.actions) {
386 if (!filter(action.path)) {
387 continue;
388 }
389 switch (action.kind) {
390 case 'c':
391 this.create(action.path, action.content);
392 break;
393 case 'd':
394 this.delete(action.path);
395 break;
396 case 'o':
397 this.overwrite(action.path, action.content);
398 break;
399 case 'r':
400 this.rename(action.path, action.to);
401 break;
402 }
403 }
404 }
405}
406exports.FilterHostTree = FilterHostTree;
Note: See TracBrowser for help on using the repository browser.