UNPKG

9.08 kBJavaScriptView Raw
1/**
2 * @license Angular v10.2.3
3 * (c) 2010-2020 Google LLC. https://angular.io/
4 * License: MIT
5 */
6
7import { __awaiter } from 'tslib';
8
9/**
10 * @license
11 * Copyright Google LLC All Rights Reserved.
12 *
13 * Use of this source code is governed by an MIT-style license that can be
14 * found in the LICENSE file at https://angular.io/license
15 */
16const PARSE_TO_PAIRS = /([0-9]+[^0-9]+)/g;
17const PAIR_SPLIT = /^([0-9]+)([dhmsu]+)$/;
18function parseDurationToMs(duration) {
19 const matches = [];
20 let array;
21 while ((array = PARSE_TO_PAIRS.exec(duration)) !== null) {
22 matches.push(array[0]);
23 }
24 return matches
25 .map(match => {
26 const res = PAIR_SPLIT.exec(match);
27 if (res === null) {
28 throw new Error(`Not a valid duration: ${match}`);
29 }
30 let factor = 0;
31 switch (res[2]) {
32 case 'd':
33 factor = 86400000;
34 break;
35 case 'h':
36 factor = 3600000;
37 break;
38 case 'm':
39 factor = 60000;
40 break;
41 case 's':
42 factor = 1000;
43 break;
44 case 'u':
45 factor = 1;
46 break;
47 default:
48 throw new Error(`Not a valid duration unit: ${res[2]}`);
49 }
50 return parseInt(res[1]) * factor;
51 })
52 .reduce((total, value) => total + value, 0);
53}
54
55/**
56 * @license
57 * Copyright Google LLC All Rights Reserved.
58 *
59 * Use of this source code is governed by an MIT-style license that can be
60 * found in the LICENSE file at https://angular.io/license
61 */
62const QUESTION_MARK = '[^/]';
63const WILD_SINGLE = '[^/]*';
64const WILD_OPEN = '(?:.+\\/)?';
65const TO_ESCAPE_BASE = [
66 { replace: /\./g, with: '\\.' },
67 { replace: /\+/g, with: '\\+' },
68 { replace: /\*/g, with: WILD_SINGLE },
69];
70const TO_ESCAPE_WILDCARD_QM = [
71 ...TO_ESCAPE_BASE,
72 { replace: /\?/g, with: QUESTION_MARK },
73];
74const TO_ESCAPE_LITERAL_QM = [
75 ...TO_ESCAPE_BASE,
76 { replace: /\?/g, with: '\\?' },
77];
78function globToRegex(glob, literalQuestionMark = false) {
79 const toEscape = literalQuestionMark ? TO_ESCAPE_LITERAL_QM : TO_ESCAPE_WILDCARD_QM;
80 const segments = glob.split('/').reverse();
81 let regex = '';
82 while (segments.length > 0) {
83 const segment = segments.pop();
84 if (segment === '**') {
85 if (segments.length > 0) {
86 regex += WILD_OPEN;
87 }
88 else {
89 regex += '.*';
90 }
91 }
92 else {
93 const processed = toEscape.reduce((segment, escape) => segment.replace(escape.replace, escape.with), segment);
94 regex += processed;
95 if (segments.length > 0) {
96 regex += '\\/';
97 }
98 }
99 }
100 return regex;
101}
102
103/**
104 * @license
105 * Copyright Google LLC All Rights Reserved.
106 *
107 * Use of this source code is governed by an MIT-style license that can be
108 * found in the LICENSE file at https://angular.io/license
109 */
110const DEFAULT_NAVIGATION_URLS = [
111 '/**',
112 '!/**/*.*',
113 '!/**/*__*',
114 '!/**/*__*/**',
115];
116/**
117 * Consumes service worker configuration files and processes them into control files.
118 *
119 * @publicApi
120 */
121class Generator {
122 constructor(fs, baseHref) {
123 this.fs = fs;
124 this.baseHref = baseHref;
125 }
126 process(config) {
127 return __awaiter(this, void 0, void 0, function* () {
128 const unorderedHashTable = {};
129 const assetGroups = yield this.processAssetGroups(config, unorderedHashTable);
130 return {
131 configVersion: 1,
132 timestamp: Date.now(),
133 appData: config.appData,
134 index: joinUrls(this.baseHref, config.index),
135 assetGroups,
136 dataGroups: this.processDataGroups(config),
137 hashTable: withOrderedKeys(unorderedHashTable),
138 navigationUrls: processNavigationUrls(this.baseHref, config.navigationUrls),
139 };
140 });
141 }
142 processAssetGroups(config, hashTable) {
143 return __awaiter(this, void 0, void 0, function* () {
144 const seenMap = new Set();
145 return Promise.all((config.assetGroups || []).map((group) => __awaiter(this, void 0, void 0, function* () {
146 if (group.resources.versionedFiles) {
147 throw new Error(`Asset-group '${group.name}' in 'ngsw-config.json' uses the 'versionedFiles' option, ` +
148 'which is no longer supported. Use \'files\' instead.');
149 }
150 const fileMatcher = globListToMatcher(group.resources.files || []);
151 const allFiles = yield this.fs.list('/');
152 const matchedFiles = allFiles.filter(fileMatcher).filter(file => !seenMap.has(file)).sort();
153 matchedFiles.forEach(file => seenMap.add(file));
154 // Add the hashes.
155 yield matchedFiles.reduce((previous, file) => __awaiter(this, void 0, void 0, function* () {
156 yield previous;
157 const hash = yield this.fs.hash(file);
158 hashTable[joinUrls(this.baseHref, file)] = hash;
159 }), Promise.resolve());
160 return {
161 name: group.name,
162 installMode: group.installMode || 'prefetch',
163 updateMode: group.updateMode || group.installMode || 'prefetch',
164 cacheQueryOptions: buildCacheQueryOptions(group.cacheQueryOptions),
165 urls: matchedFiles.map(url => joinUrls(this.baseHref, url)),
166 patterns: (group.resources.urls || []).map(url => urlToRegex(url, this.baseHref, true)),
167 };
168 })));
169 });
170 }
171 processDataGroups(config) {
172 return (config.dataGroups || []).map(group => {
173 return {
174 name: group.name,
175 patterns: group.urls.map(url => urlToRegex(url, this.baseHref, true)),
176 strategy: group.cacheConfig.strategy || 'performance',
177 maxSize: group.cacheConfig.maxSize,
178 maxAge: parseDurationToMs(group.cacheConfig.maxAge),
179 timeoutMs: group.cacheConfig.timeout && parseDurationToMs(group.cacheConfig.timeout),
180 cacheQueryOptions: buildCacheQueryOptions(group.cacheQueryOptions),
181 version: group.version !== undefined ? group.version : 1,
182 };
183 });
184 }
185}
186function processNavigationUrls(baseHref, urls = DEFAULT_NAVIGATION_URLS) {
187 return urls.map(url => {
188 const positive = !url.startsWith('!');
189 url = positive ? url : url.substr(1);
190 return { positive, regex: `^${urlToRegex(url, baseHref)}$` };
191 });
192}
193function globListToMatcher(globs) {
194 const patterns = globs.map(pattern => {
195 if (pattern.startsWith('!')) {
196 return {
197 positive: false,
198 regex: new RegExp('^' + globToRegex(pattern.substr(1)) + '$'),
199 };
200 }
201 else {
202 return {
203 positive: true,
204 regex: new RegExp('^' + globToRegex(pattern) + '$'),
205 };
206 }
207 });
208 return (file) => matches(file, patterns);
209}
210function matches(file, patterns) {
211 const res = patterns.reduce((isMatch, pattern) => {
212 if (pattern.positive) {
213 return isMatch || pattern.regex.test(file);
214 }
215 else {
216 return isMatch && !pattern.regex.test(file);
217 }
218 }, false);
219 return res;
220}
221function urlToRegex(url, baseHref, literalQuestionMark) {
222 if (!url.startsWith('/') && url.indexOf('://') === -1) {
223 // Prefix relative URLs with `baseHref`.
224 // Strip a leading `.` from a relative `baseHref` (e.g. `./foo/`), since it would result in an
225 // incorrect regex (matching a literal `.`).
226 url = joinUrls(baseHref.replace(/^\.(?=\/)/, ''), url);
227 }
228 return globToRegex(url, literalQuestionMark);
229}
230function joinUrls(a, b) {
231 if (a.endsWith('/') && b.startsWith('/')) {
232 return a + b.substr(1);
233 }
234 else if (!a.endsWith('/') && !b.startsWith('/')) {
235 return a + '/' + b;
236 }
237 return a + b;
238}
239function withOrderedKeys(unorderedObj) {
240 const orderedObj = {};
241 Object.keys(unorderedObj).sort().forEach(key => orderedObj[key] = unorderedObj[key]);
242 return orderedObj;
243}
244function buildCacheQueryOptions(inOptions) {
245 return Object.assign({ ignoreVary: true }, inOptions);
246}
247
248/**
249 * @license
250 * Copyright Google LLC All Rights Reserved.
251 *
252 * Use of this source code is governed by an MIT-style license that can be
253 * found in the LICENSE file at https://angular.io/license
254 */
255
256/**
257 * @license
258 * Copyright Google LLC All Rights Reserved.
259 *
260 * Use of this source code is governed by an MIT-style license that can be
261 * found in the LICENSE file at https://angular.io/license
262 */
263
264/**
265 * Generated bundle index. Do not edit.
266 */
267
268export { Generator };
269//# sourceMappingURL=config.js.map