forked from angular/angular
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild-ngsw-config.js
85 lines (71 loc) · 3.45 KB
/
build-ngsw-config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Imports
const {basename, dirname, resolve: resolvePath} = require('canonical-path');
const {mkdirSync, readFileSync, writeFileSync} = require('fs');
const {parse: parseJson} = require('json5');
// Constants
const FIREBASE_CONFIG_PATH = resolvePath(__dirname, '../firebase.json');
const NGSW_CONFIG_TEMPLATE_PATH = resolvePath(__dirname, '../ngsw-config.template.json');
const NGSW_CONFIG_OUTPUT_PATH = resolvePath(__dirname, '../src/generated/ngsw-config.json');
// Run
_main();
// Helpers
function _main() {
const firebaseConfig = readJson(FIREBASE_CONFIG_PATH);
const ngswConfig = readJson(NGSW_CONFIG_TEMPLATE_PATH);
const firebaseRedirects = firebaseConfig.hosting.redirects;
// Check that there are no regex-based redirects.
const regexBasedRedirects = firebaseRedirects.filter(({regex}) => regex !== undefined);
if (regexBasedRedirects.length > 0) {
throw new Error(
'The following redirects use `regex`, which is currently not supported by ' +
`${basename(__filename)}:` +
regexBasedRedirects.map(x => `\n - ${JSON.stringify(x)}`).join(''));
}
// Check that there are no unsupported glob characters/patterns.
const redirectsWithUnsupportedGlobs = firebaseRedirects
.filter(({source}) => !/^(?:[/\w\-.*]|:\w+|@\([\w\-.|]+\))+$/.test(source));
if (redirectsWithUnsupportedGlobs.length > 0) {
throw new Error(
'The following redirects use glob characters/patterns that are currently not supported by ' +
`${basename(__filename)}:` +
redirectsWithUnsupportedGlobs.map(x => `\n - ${JSON.stringify(x)}`).join(''));
}
// Compute additional ignore glob patterns to be added to `navigationUrls`.
const additionalNavigationUrls = firebaseRedirects
// Grab the redirect source glob.
.map(({source}) => source)
// Ignore redirects for files (since these are already ignored by the SW).
.filter(glob => /\/[^/.]*$/.test(glob))
// Convert each Firebase-specific glob to a SW-compatible glob.
.map(glob => `!${glob.replace(/:\w+/g, '*').replace(/@(\([\w\-.|]+\))/g, '$1')}`)
// Add optional trailing `/` for globs that don't end with `*`.
.map(glob => /\w$/.test(glob) ? `${glob}\/{0,1}` : glob)
// Remove more specific globs that are covered by more generic ones.
.filter((glob, _i, globs) => !isGlobRedundant(glob, globs))
// Sort the generated globs alphabetically.
.sort();
// Add the additional `navigationUrls` globs and save the config.
ngswConfig.navigationUrls.push(...additionalNavigationUrls);
mkdirSync(dirname(NGSW_CONFIG_OUTPUT_PATH), {recursive: true});
writeJson(NGSW_CONFIG_OUTPUT_PATH, ngswConfig);
}
function isGlobRedundant(glob, globs) {
// Find all globs that could cover other globs.
// For simplicity, we only consider globs ending with `/**`.
const genericGlobs = globs.filter(g => g.endsWith('/**'));
// A glob is redundant if it starts with the path of a potentially generic glob (excluding the
// trailing `**`) followed by a word character or a `*`.
// For example, `/foo/bar/baz` is covered (and thus made redundant) by `/foo/**`, but `/foo/{0,1}`
// is not.
return genericGlobs.some(g => {
const pathPrefix = g.slice(0, -2);
return (glob !== g) && glob.startsWith(pathPrefix) &&
/^[\w*]/.test(glob.slice(pathPrefix.length));
});
}
function readJson(filePath) {
return parseJson(readFileSync(filePath, 'utf8'));
}
function writeJson(filePath, obj) {
return writeFileSync(filePath, `${JSON.stringify(obj, null, 2)}\n`);
}