source: trip-planner-front/node_modules/@angular-devkit/core/src/virtual-fs/host/record.js@ 6a80231

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

initial commit

  • Property mode set to 100644
File size: 12.1 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.CordHost = void 0;
11const rxjs_1 = require("rxjs");
12const operators_1 = require("rxjs/operators");
13const exception_1 = require("../../exception");
14const memory_1 = require("./memory");
15/**
16 * A Host that records changes to the underlying Host, while keeping a record of Create, Overwrite,
17 * Rename and Delete of files.
18 *
19 * This is fully compatible with Host, but will keep a staging of every changes asked. That staging
20 * follows the principle of the Tree (e.g. can create a file that already exists).
21 *
22 * Using `create()` and `overwrite()` will force those operations, but using `write` will add
23 * the create/overwrite records IIF the files does/doesn't already exist.
24 */
25class CordHost extends memory_1.SimpleMemoryHost {
26 constructor(_back) {
27 super();
28 this._back = _back;
29 this._filesToCreate = new Set();
30 this._filesToRename = new Map();
31 this._filesToRenameRevert = new Map();
32 this._filesToDelete = new Set();
33 this._filesToOverwrite = new Set();
34 }
35 get backend() {
36 return this._back;
37 }
38 get capabilities() {
39 // Our own host is always Synchronous, but the backend might not be.
40 return {
41 synchronous: this._back.capabilities.synchronous,
42 };
43 }
44 /**
45 * Create a copy of this host, including all actions made.
46 * @returns {CordHost} The carbon copy.
47 */
48 clone() {
49 const dolly = new CordHost(this._back);
50 dolly._cache = new Map(this._cache);
51 dolly._filesToCreate = new Set(this._filesToCreate);
52 dolly._filesToRename = new Map(this._filesToRename);
53 dolly._filesToRenameRevert = new Map(this._filesToRenameRevert);
54 dolly._filesToDelete = new Set(this._filesToDelete);
55 dolly._filesToOverwrite = new Set(this._filesToOverwrite);
56 return dolly;
57 }
58 /**
59 * Commit the changes recorded to a Host. It is assumed that the host does have the same structure
60 * as the host that was used for backend (could be the same host).
61 * @param host The host to create/delete/rename/overwrite files to.
62 * @param force Whether to skip existence checks when creating/overwriting. This is
63 * faster but might lead to incorrect states. Because Hosts natively don't support creation
64 * versus overwriting (it's only writing), we check for existence before completing a request.
65 * @returns An observable that completes when done, or error if an error occured.
66 */
67 commit(host, force = false) {
68 // Really commit everything to the actual host.
69 return rxjs_1.from(this.records()).pipe(operators_1.concatMap((record) => {
70 switch (record.kind) {
71 case 'delete':
72 return host.delete(record.path);
73 case 'rename':
74 return host.rename(record.from, record.to);
75 case 'create':
76 return host.exists(record.path).pipe(operators_1.switchMap((exists) => {
77 if (exists && !force) {
78 return rxjs_1.throwError(new exception_1.FileAlreadyExistException(record.path));
79 }
80 else {
81 return host.write(record.path, record.content);
82 }
83 }));
84 case 'overwrite':
85 return host.exists(record.path).pipe(operators_1.switchMap((exists) => {
86 if (!exists && !force) {
87 return rxjs_1.throwError(new exception_1.FileDoesNotExistException(record.path));
88 }
89 else {
90 return host.write(record.path, record.content);
91 }
92 }));
93 }
94 }), operators_1.reduce(() => { }));
95 }
96 records() {
97 return [
98 ...[...this._filesToDelete.values()].map((path) => ({
99 kind: 'delete',
100 path,
101 })),
102 ...[...this._filesToRename.entries()].map(([from, to]) => ({
103 kind: 'rename',
104 from,
105 to,
106 })),
107 ...[...this._filesToCreate.values()].map((path) => ({
108 kind: 'create',
109 path,
110 content: this._read(path),
111 })),
112 ...[...this._filesToOverwrite.values()].map((path) => ({
113 kind: 'overwrite',
114 path,
115 content: this._read(path),
116 })),
117 ];
118 }
119 /**
120 * Specialized version of {@link CordHost#write} which forces the creation of a file whether it
121 * exists or not.
122 * @param {} path
123 * @param {FileBuffer} content
124 * @returns {Observable<void>}
125 */
126 create(path, content) {
127 if (super._exists(path)) {
128 throw new exception_1.FileAlreadyExistException(path);
129 }
130 if (this._filesToDelete.has(path)) {
131 this._filesToDelete.delete(path);
132 this._filesToOverwrite.add(path);
133 }
134 else {
135 this._filesToCreate.add(path);
136 }
137 return super.write(path, content);
138 }
139 overwrite(path, content) {
140 return this.isDirectory(path).pipe(operators_1.switchMap((isDir) => {
141 if (isDir) {
142 return rxjs_1.throwError(new exception_1.PathIsDirectoryException(path));
143 }
144 return this.exists(path);
145 }), operators_1.switchMap((exists) => {
146 if (!exists) {
147 return rxjs_1.throwError(new exception_1.FileDoesNotExistException(path));
148 }
149 if (!this._filesToCreate.has(path)) {
150 this._filesToOverwrite.add(path);
151 }
152 return super.write(path, content);
153 }));
154 }
155 write(path, content) {
156 return this.exists(path).pipe(operators_1.switchMap((exists) => {
157 if (exists) {
158 // It exists, but might be being renamed or deleted. In that case we want to create it.
159 if (this.willRename(path) || this.willDelete(path)) {
160 return this.create(path, content);
161 }
162 else {
163 return this.overwrite(path, content);
164 }
165 }
166 else {
167 return this.create(path, content);
168 }
169 }));
170 }
171 read(path) {
172 if (this._exists(path)) {
173 return super.read(path);
174 }
175 return this._back.read(path);
176 }
177 delete(path) {
178 if (this._exists(path)) {
179 if (this._filesToCreate.has(path)) {
180 this._filesToCreate.delete(path);
181 }
182 else if (this._filesToOverwrite.has(path)) {
183 this._filesToOverwrite.delete(path);
184 this._filesToDelete.add(path);
185 }
186 else {
187 const maybeOrigin = this._filesToRenameRevert.get(path);
188 if (maybeOrigin) {
189 this._filesToRenameRevert.delete(path);
190 this._filesToRename.delete(maybeOrigin);
191 this._filesToDelete.add(maybeOrigin);
192 }
193 else {
194 return rxjs_1.throwError(new exception_1.UnknownException(`This should never happen. Path: ${JSON.stringify(path)}.`));
195 }
196 }
197 return super.delete(path);
198 }
199 else {
200 return this._back.exists(path).pipe(operators_1.switchMap((exists) => {
201 if (exists) {
202 this._filesToDelete.add(path);
203 return rxjs_1.of();
204 }
205 else {
206 return rxjs_1.throwError(new exception_1.FileDoesNotExistException(path));
207 }
208 }));
209 }
210 }
211 rename(from, to) {
212 return rxjs_1.concat(this.exists(to), this.exists(from)).pipe(operators_1.toArray(), operators_1.switchMap(([existTo, existFrom]) => {
213 if (!existFrom) {
214 return rxjs_1.throwError(new exception_1.FileDoesNotExistException(from));
215 }
216 if (from === to) {
217 return rxjs_1.EMPTY;
218 }
219 if (existTo) {
220 return rxjs_1.throwError(new exception_1.FileAlreadyExistException(to));
221 }
222 // If we're renaming a file that's been created, shortcircuit to creating the `to` path.
223 if (this._filesToCreate.has(from)) {
224 this._filesToCreate.delete(from);
225 this._filesToCreate.add(to);
226 return super.rename(from, to);
227 }
228 if (this._filesToOverwrite.has(from)) {
229 this._filesToOverwrite.delete(from);
230 // Recursively call this function. This is so we don't repeat the bottom logic. This
231 // if will be by-passed because we just deleted the `from` path from files to overwrite.
232 return rxjs_1.concat(this.rename(from, to), new rxjs_1.Observable((x) => {
233 this._filesToOverwrite.add(to);
234 x.complete();
235 }));
236 }
237 if (this._filesToDelete.has(to)) {
238 this._filesToDelete.delete(to);
239 this._filesToDelete.add(from);
240 this._filesToOverwrite.add(to);
241 // We need to delete the original and write the new one.
242 return this.read(from).pipe(operators_1.map((content) => this._write(to, content)));
243 }
244 const maybeTo1 = this._filesToRenameRevert.get(from);
245 if (maybeTo1) {
246 // We already renamed to this file (A => from), let's rename the former to the new
247 // path (A => to).
248 this._filesToRename.delete(maybeTo1);
249 this._filesToRenameRevert.delete(from);
250 from = maybeTo1;
251 }
252 this._filesToRename.set(from, to);
253 this._filesToRenameRevert.set(to, from);
254 // If the file is part of our data, just rename it internally.
255 if (this._exists(from)) {
256 return super.rename(from, to);
257 }
258 else {
259 // Create a file with the same content.
260 return this._back.read(from).pipe(operators_1.switchMap((content) => super.write(to, content)));
261 }
262 }));
263 }
264 list(path) {
265 return rxjs_1.concat(super.list(path), this._back.list(path)).pipe(operators_1.reduce((list, curr) => {
266 curr.forEach((elem) => list.add(elem));
267 return list;
268 }, new Set()), operators_1.map((set) => [...set]));
269 }
270 exists(path) {
271 return this._exists(path)
272 ? rxjs_1.of(true)
273 : this.willDelete(path) || this.willRename(path)
274 ? rxjs_1.of(false)
275 : this._back.exists(path);
276 }
277 isDirectory(path) {
278 return this._exists(path) ? super.isDirectory(path) : this._back.isDirectory(path);
279 }
280 isFile(path) {
281 return this._exists(path)
282 ? super.isFile(path)
283 : this.willDelete(path) || this.willRename(path)
284 ? rxjs_1.of(false)
285 : this._back.isFile(path);
286 }
287 stat(path) {
288 return this._exists(path)
289 ? super.stat(path)
290 : this.willDelete(path) || this.willRename(path)
291 ? rxjs_1.of(null)
292 : this._back.stat(path);
293 }
294 watch(path, options) {
295 // Watching not supported.
296 return null;
297 }
298 willCreate(path) {
299 return this._filesToCreate.has(path);
300 }
301 willOverwrite(path) {
302 return this._filesToOverwrite.has(path);
303 }
304 willDelete(path) {
305 return this._filesToDelete.has(path);
306 }
307 willRename(path) {
308 return this._filesToRename.has(path);
309 }
310 willRenameTo(path, to) {
311 return this._filesToRename.get(path) === to;
312 }
313}
314exports.CordHost = CordHost;
Note: See TracBrowser for help on using the repository browser.