Passed
Push — develop ( 8f1cdd...81d653 )
by Endre
03:42
created

src/ServiceWorkerManager.ts   A

Complexity

Total Complexity 10
Complexity/F 1.67

Size

Lines of Code 111
Function Count 6

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 96.77%

Importance

Changes 0
Metric Value
eloc 84
dl 0
loc 111
ccs 30
cts 31
cp 0.9677
rs 10
c 0
b 0
f 0
wmc 10
mnd 4
bc 4
fnc 6
bpm 0.6666
cpm 1.6666
noi 0

6 Functions

Rating   Name   Duplication   Size   Complexity  
A ServiceWorkerManager.clearOldCaches 0 9 2
A ServiceWorkerManager.installCache 0 4 1
A ServiceWorkerManager.cacheFiles 0 4 1
A ServiceWorkerManager.activateCache 0 3 1
A ServiceWorkerManager.fetch 0 23 3
A ServiceWorkerManager.fetchRequest 0 3 1
1
export interface ServiceWorkerEventMap {
2
  'activate': ExtendableEvent;
3
  'fetch': FetchEvent;
4
  'install': InstallEvent;
5
}
6
7
export interface ServiceWorkerGlobalScope {
8
  readonly caches: CacheStorage;
9
  addEventListener<K extends keyof ServiceWorkerEventMap>(
10
    type: K,
11
    listener: (event: ServiceWorkerEventMap[K]) => any,
12
    useCapture?: boolean
13
  ): void;
14
  skipWaiting(): void;
15
}
16
17
export interface InstallEvent extends ExtendableEvent {
18
  readonly activeWorker: ServiceWorker;
19
}
20
21
export interface ExtendableEvent extends Event {
22
  waitUntil(promise: Promise<any>): void;
23
}
24
25
export interface FetchEvent extends Event {
26
  readonly isReload: boolean;
27
  readonly request: Request;
28
  readonly clientId: string;
29
  respondWith(all: any): Response;
30
}
31
32
// https://developers.google.com/web/fundamentals/primers/service-workers
33
export class ServiceWorkerManager {
34
  worker: ServiceWorkerGlobalScope;
35
  caches: CacheStorage;
36
  version: string;
37
  fileList: string[];
38
39
  constructor(worker: any, caches: CacheStorage, version: string, fileList: string[]) {
40 8
    this.worker = worker;
41 8
    this.caches = caches;
42 8
    this.version = version;
43 8
    this.fileList = fileList;
44
45 8
    this.worker.addEventListener('install', this.installCache.bind(this));
46 8
    this.worker.addEventListener('activate', this.activateCache.bind(this));
47 8
    this.worker.addEventListener('fetch', this.fetchRequest.bind(this));
48
  }
49
50
  installCache(event: InstallEvent) {
51 1
    this.worker.skipWaiting(); // Not content immediately active (even partially)
52 1
    event.waitUntil(this.cacheFiles());
53
  }
54
55
  activateCache(event: ExtendableEvent) {
56 1
    event.waitUntil(this.clearOldCaches());
57
  }
58
59
  fetchRequest(event: FetchEvent) {
60 5
    event.respondWith(this.fetch(event.request));
61
  }
62
63
  async cacheFiles() {
64 1
    const cache: Cache = await this.caches.open(this.version);
65 1
    return cache.addAll(this.fileList);
66
  }
67
68
  async clearOldCaches() {
69 1
    const cacheNames = await this.caches.keys();
70
71 1
    return Promise.all(
72
      cacheNames.map(
73
        (cacheName: string) => {
74 2
          if (cacheName != this.version) {
75 1
            return this.caches.delete(cacheName);
76
          }
77
        }
78
      )
79
    );
80
  }
81
82
  async fetch(request: Request) {
83 5
    const response: Response | undefined = await this.caches.match(request);
84
85 5
    if (response) {
86 1
      return response;
87
    }
88
89 4
    const fetchResponse: Response = await fetch(request);
90 5
    if (!fetchResponse || fetchResponse.status !== 200 || fetchResponse.type !== 'basic') {
91 3
      return fetchResponse;
92
    }
93
94
    // IMPORTANT: Clone the response. A response is a stream
95
    // and because we want the browser to consume the response
96
    // as well as the cache consuming the response, we need
97
    // to clone it so we have two streams.
98 1
    const responseToCache: Response = fetchResponse.clone();
99
100 1
    const cache: Cache = await this.caches.open(this.version);
101 1
    await cache.put(request, responseToCache);
102
103 1
    return fetchResponse;
104
  }
105
}
106
107 1
const version: string = 'VERSION'; // Will be generated by script
108 1
const fileList: string[] = []; // Will be generated by script
109 2
if (this) {
110
  new ServiceWorkerManager(this, caches, version, fileList);
111
}