UNPKG

@angular/service-worker

Version:

Angular - service worker tooling!

351 lines (342 loc) • 10.4 kB
/** * @license Angular v7.0.2 * (c) 2010-2018 Google, Inc. https://angular.io/ * License: MIT */ import { __awaiter } from 'tslib'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @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 */ /** @type {?} */ const PARSE_TO_PAIRS = /([0-9]+[^0-9]+)/g; /** @type {?} */ const PAIR_SPLIT = /^([0-9]+)([dhmsu]+)$/; /** * @param {?} duration * @return {?} */ function parseDurationToMs(duration) { /** @type {?} */ const matches = []; /** @type {?} */ let array; while ((array = PARSE_TO_PAIRS.exec(duration)) !== null) { matches.push(array[0]); } return matches .map(match => { /** @type {?} */ const res = PAIR_SPLIT.exec(match); if (res === null) { throw new Error(`Not a valid duration: ${match}`); } /** @type {?} */ let factor = 0; switch (res[2]) { case 'd': factor = 86400000; break; case 'h': factor = 3600000; break; case 'm': factor = 60000; break; case 's': factor = 1000; break; case 'u': factor = 1; break; default: throw new Error(`Not a valid duration unit: ${res[2]}`); } return parseInt(res[1]) * factor; }) .reduce((total, value) => total + value, 0); } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @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 */ /** @type {?} */ const QUESTION_MARK = '[^/]'; /** @type {?} */ const WILD_SINGLE = '[^/]*'; /** @type {?} */ const WILD_OPEN = '(?:.+\\/)?'; /** @type {?} */ const TO_ESCAPE_BASE = [ { replace: /\./g, with: '\\.' }, { replace: /\+/g, with: '\\+' }, { replace: /\*/g, with: WILD_SINGLE }, ]; /** @type {?} */ const TO_ESCAPE_WILDCARD_QM = [ ...TO_ESCAPE_BASE, { replace: /\?/g, with: QUESTION_MARK }, ]; /** @type {?} */ const TO_ESCAPE_LITERAL_QM = [ ...TO_ESCAPE_BASE, { replace: /\?/g, with: '\\?' }, ]; /** * @param {?} glob * @param {?=} literalQuestionMark * @return {?} */ function globToRegex(glob, literalQuestionMark = false) { /** @type {?} */ const toEscape = literalQuestionMark ? TO_ESCAPE_LITERAL_QM : TO_ESCAPE_WILDCARD_QM; /** @type {?} */ const segments = glob.split('/').reverse(); /** @type {?} */ let regex = ''; while (segments.length > 0) { /** @type {?} */ const segment = /** @type {?} */ ((segments.pop())); if (segment === '**') { if (segments.length > 0) { regex += WILD_OPEN; } else { regex += '.*'; } } else { /** @type {?} */ const processed = toEscape.reduce((segment, escape) => segment.replace(escape.replace, escape.with), segment); regex += processed; if (segments.length > 0) { regex += '\\/'; } } } return regex; } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** @type {?} */ const DEFAULT_NAVIGATION_URLS = [ '/**', '!/**/*.*', '!/**/*__*', '!/**/*__*/**', ]; /** * Consumes service worker configuration files and processes them into control files. * * \@publicApi */ class Generator { /** * @param {?} fs * @param {?} baseHref */ constructor(fs, baseHref) { this.fs = fs; this.baseHref = baseHref; } /** * @param {?} config * @return {?} */ process(config) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const unorderedHashTable = {}; /** @type {?} */ const assetGroups = yield this.processAssetGroups(config, unorderedHashTable); return { configVersion: 1, appData: config.appData, index: joinUrls(this.baseHref, config.index), assetGroups, dataGroups: this.processDataGroups(config), hashTable: withOrderedKeys(unorderedHashTable), navigationUrls: processNavigationUrls(this.baseHref, config.navigationUrls), }; }); } /** * @param {?} config * @param {?} hashTable * @return {?} */ processAssetGroups(config, hashTable) { return __awaiter(this, void 0, void 0, function* () { /** @type {?} */ const seenMap = new Set(); return Promise.all((config.assetGroups || []).map((group) => __awaiter(this, void 0, void 0, function* () { if (group.resources.versionedFiles) { console.warn(`Asset-group '${group.name}' in 'ngsw-config.json' uses the 'versionedFiles' option.\n` + 'As of v6 \'versionedFiles\' and \'files\' options have the same behavior. ' + 'Use \'files\' instead.'); } /** @type {?} */ const fileMatcher = globListToMatcher(group.resources.files || []); /** @type {?} */ const versionedMatcher = globListToMatcher(group.resources.versionedFiles || []); /** @type {?} */ const allFiles = yield this.fs.list('/'); /** @type {?} */ const plainFiles = allFiles.filter(fileMatcher).filter(file => !seenMap.has(file)); plainFiles.forEach(file => seenMap.add(file)); /** @type {?} */ const versionedFiles = allFiles.filter(versionedMatcher).filter(file => !seenMap.has(file)); versionedFiles.forEach(file => seenMap.add(file)); /** @type {?} */ const matchedFiles = [...plainFiles, ...versionedFiles].sort(); yield matchedFiles.reduce((previous, file) => __awaiter(this, void 0, void 0, function* () { yield previous; /** @type {?} */ const hash = yield this.fs.hash(file); hashTable[joinUrls(this.baseHref, file)] = hash; }), Promise.resolve()); return { name: group.name, installMode: group.installMode || 'prefetch', updateMode: group.updateMode || group.installMode || 'prefetch', urls: matchedFiles.map(url => joinUrls(this.baseHref, url)), patterns: (group.resources.urls || []).map(url => urlToRegex(url, this.baseHref, true)), }; }))); }); } /** * @param {?} config * @return {?} */ processDataGroups(config) { return (config.dataGroups || []).map(group => { return { name: group.name, patterns: group.urls.map(url => urlToRegex(url, this.baseHref, true)), strategy: group.cacheConfig.strategy || 'performance', maxSize: group.cacheConfig.maxSize, maxAge: parseDurationToMs(group.cacheConfig.maxAge), timeoutMs: group.cacheConfig.timeout && parseDurationToMs(group.cacheConfig.timeout), version: group.version !== undefined ? group.version : 1, }; }); } } /** * @param {?} baseHref * @param {?=} urls * @return {?} */ function processNavigationUrls(baseHref, urls = DEFAULT_NAVIGATION_URLS) { return urls.map(url => { /** @type {?} */ const positive = !url.startsWith('!'); url = positive ? url : url.substr(1); return { positive, regex: `^${urlToRegex(url, baseHref)}$` }; }); } /** * @param {?} globs * @return {?} */ function globListToMatcher(globs) { /** @type {?} */ const patterns = globs.map(pattern => { if (pattern.startsWith('!')) { return { positive: false, regex: new RegExp('^' + globToRegex(pattern.substr(1)) + '$'), }; } else { return { positive: true, regex: new RegExp('^' + globToRegex(pattern) + '$'), }; } }); return (file) => matches(file, patterns); } /** * @param {?} file * @param {?} patterns * @return {?} */ function matches(file, patterns) { /** @type {?} */ const res = patterns.reduce((isMatch, pattern) => { if (pattern.positive) { return isMatch || pattern.regex.test(file); } else { return isMatch && !pattern.regex.test(file); } }, false); return res; } /** * @param {?} url * @param {?} baseHref * @param {?=} literalQuestionMark * @return {?} */ function urlToRegex(url, baseHref, literalQuestionMark) { if (!url.startsWith('/') && url.indexOf('://') === -1) { url = joinUrls(baseHref, url); } return globToRegex(url, literalQuestionMark); } /** * @param {?} a * @param {?} b * @return {?} */ function joinUrls(a, b) { if (a.endsWith('/') && b.startsWith('/')) { return a + b.substr(1); } else if (!a.endsWith('/') && !b.startsWith('/')) { return a + '/' + b; } return a + b; } /** * @template T * @param {?} unorderedObj * @return {?} */ function withOrderedKeys(unorderedObj) { /** @type {?} */ const orderedObj = /** @type {?} */ ({}); Object.keys(unorderedObj).sort().forEach(key => orderedObj[key] = unorderedObj[key]); return orderedObj; } /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * Generated bundle index. Do not edit. */ export { Generator }; //# sourceMappingURL=config.js.map