| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  | import {MockRequest, MockResponse} from './fetch'; | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export interface DehydratedResponse { | 
					
						
							|  |  |  |   body: string|null; | 
					
						
							|  |  |  |   status: number; | 
					
						
							|  |  |  |   statusText: string; | 
					
						
							|  |  |  |   headers: {[name: string]: string}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type DehydratedCache = { | 
					
						
							|  |  |  |   [url: string]: DehydratedResponse | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | export type DehydratedCacheStorage = { | 
					
						
							|  |  |  |   [name: string]: DehydratedCache | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockCacheStorage implements CacheStorage { | 
					
						
							|  |  |  |   private caches = new Map<string, MockCache>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |   constructor(private origin: string, hydrateFrom?: string) { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     if (hydrateFrom !== undefined) { | 
					
						
							|  |  |  |       const hydrated = JSON.parse(hydrateFrom) as DehydratedCacheStorage; | 
					
						
							|  |  |  |       Object.keys(hydrated).forEach( | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |           name => { this.caches.set(name, new MockCache(this.origin, hydrated[name])); }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async has(name: string): Promise<boolean> { return this.caches.has(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async keys(): Promise<string[]> { return Array.from(this.caches.keys()); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async open(name: string): Promise<Cache> { | 
					
						
							|  |  |  |     if (!this.caches.has(name)) { | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |       this.caches.set(name, new MockCache(this.origin)); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |     return this.caches.get(name) as any; | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async match(req: Request): Promise<Response|undefined> { | 
					
						
							|  |  |  |     return await Array.from(this.caches.values()) | 
					
						
							|  |  |  |         .reduce<Promise<Response|undefined>>(async(answer, cache): Promise<Response|undefined> => { | 
					
						
							|  |  |  |           const curr = await answer; | 
					
						
							|  |  |  |           if (curr !== undefined) { | 
					
						
							|  |  |  |             return curr; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return cache.match(req); | 
					
						
							|  |  |  |         }, Promise.resolve<Response|undefined>(undefined)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async 'delete'(name: string): Promise<boolean> { | 
					
						
							|  |  |  |     if (this.caches.has(name)) { | 
					
						
							|  |  |  |       this.caches.delete(name); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dehydrate(): string { | 
					
						
							|  |  |  |     const dehydrated: DehydratedCacheStorage = {}; | 
					
						
							|  |  |  |     Array.from(this.caches.keys()).forEach(name => { | 
					
						
							|  |  |  |       const cache = this.caches.get(name) !; | 
					
						
							|  |  |  |       dehydrated[name] = cache.dehydrate(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return JSON.stringify(dehydrated); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  | export class MockCache { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |   private cache = new Map<string, Response>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |   constructor(private origin: string, hydrated?: DehydratedCache) { | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     if (hydrated !== undefined) { | 
					
						
							|  |  |  |       Object.keys(hydrated).forEach(url => { | 
					
						
							|  |  |  |         const resp = hydrated[url]; | 
					
						
							|  |  |  |         this.cache.set( | 
					
						
							|  |  |  |             url, new MockResponse( | 
					
						
							|  |  |  |                      resp.body, | 
					
						
							|  |  |  |                      {status: resp.status, statusText: resp.statusText, headers: resp.headers})); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async add(request: RequestInfo): Promise<void> { throw 'Not implemented'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async addAll(requests: RequestInfo[]): Promise<void> { throw 'Not implemented'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async 'delete'(request: RequestInfo): Promise<boolean> { | 
					
						
							|  |  |  |     const url = (typeof request === 'string' ? request : request.url); | 
					
						
							|  |  |  |     if (this.cache.has(url)) { | 
					
						
							|  |  |  |       this.cache.delete(url); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async keys(match?: Request|string): Promise<string[]> { | 
					
						
							|  |  |  |     if (match !== undefined) { | 
					
						
							|  |  |  |       throw 'Not implemented'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Array.from(this.cache.keys()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async match(request: RequestInfo, options?: CacheQueryOptions): Promise<Response> { | 
					
						
							| 
									
										
										
										
											2017-10-02 15:59:57 -07:00
										 |  |  |     let url = (typeof request === 'string' ? request : request.url); | 
					
						
							|  |  |  |     if (url.startsWith(this.origin)) { | 
					
						
							|  |  |  |       url = '/' + url.substr(this.origin.length); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     // TODO: cleanup typings. Typescript doesn't know this can resolve to undefined.
 | 
					
						
							|  |  |  |     let res = this.cache.get(url); | 
					
						
							|  |  |  |     if (res !== undefined) { | 
					
						
							|  |  |  |       res = res.clone(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res !; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async matchAll(request?: Request|string, options?: CacheQueryOptions): Promise<Response[]> { | 
					
						
							|  |  |  |     if (request === undefined) { | 
					
						
							|  |  |  |       return Array.from(this.cache.values()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const url = (typeof request === 'string' ? request : request.url); | 
					
						
							|  |  |  |     if (this.cache.has(url)) { | 
					
						
							|  |  |  |       return [this.cache.get(url) !]; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async put(request: RequestInfo, response: Response): Promise<void> { | 
					
						
							|  |  |  |     const url = (typeof request === 'string' ? request : request.url); | 
					
						
							|  |  |  |     this.cache.set(url, response.clone()); | 
					
						
							| 
									
										
										
										
											2017-10-10 12:54:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Even though the body above is cloned, consume it here because the
 | 
					
						
							|  |  |  |     // real cache consumes the body.
 | 
					
						
							|  |  |  |     await response.text(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dehydrate(): DehydratedCache { | 
					
						
							|  |  |  |     const dehydrated: DehydratedCache = {}; | 
					
						
							|  |  |  |     Array.from(this.cache.keys()).forEach(url => { | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |       const resp = this.cache.get(url) as MockResponse; | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  |       const dehydratedResp = { | 
					
						
							|  |  |  |         body: resp._body, | 
					
						
							|  |  |  |         status: resp.status, | 
					
						
							|  |  |  |         statusText: resp.statusText, | 
					
						
							|  |  |  |         headers: {}, | 
					
						
							|  |  |  |       } as DehydratedResponse; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-08 13:37:54 -07:00
										 |  |  |       resp.headers.forEach( | 
					
						
							|  |  |  |           (value: string, name: string) => { dehydratedResp.headers[name] = value; }); | 
					
						
							| 
									
										
										
										
											2017-09-28 16:18:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       dehydrated[url] = dehydratedResp; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return dehydrated; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  | } |