@serwist/build 8.4.4 → 9.0.0-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/chunks/getManifest.js +6 -0
  2. package/dist/chunks/glob.js +60 -0
  3. package/dist/chunks/injectManifest.js +23 -0
  4. package/dist/chunks/serwist-config-error.js +57 -0
  5. package/dist/chunks/vite.js +7 -0
  6. package/dist/chunks/webpack.js +34 -0
  7. package/dist/get-manifest.d.ts +2 -1
  8. package/dist/get-manifest.d.ts.map +1 -0
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +53 -813
  12. package/dist/index.next.d.ts +3 -0
  13. package/dist/index.next.d.ts.map +1 -0
  14. package/dist/index.next.js +35 -0
  15. package/dist/inject-manifest.d.ts +2 -1
  16. package/dist/inject-manifest.d.ts.map +1 -0
  17. package/dist/lib/additional-precache-entries-transform.d.ts +6 -5
  18. package/dist/lib/additional-precache-entries-transform.d.ts.map +1 -0
  19. package/dist/lib/errors.d.ts +1 -2
  20. package/dist/lib/errors.d.ts.map +1 -0
  21. package/dist/lib/escape-regexp.d.ts +2 -1
  22. package/dist/lib/escape-regexp.d.ts.map +1 -0
  23. package/dist/lib/get-composite-details.d.ts +2 -1
  24. package/dist/lib/get-composite-details.d.ts.map +1 -0
  25. package/dist/lib/get-file-details.d.ts +2 -1
  26. package/dist/lib/get-file-details.d.ts.map +1 -0
  27. package/dist/lib/get-file-hash.d.ts +1 -0
  28. package/dist/lib/get-file-hash.d.ts.map +1 -0
  29. package/dist/lib/get-file-manifest-entries.d.ts +1 -0
  30. package/dist/lib/get-file-manifest-entries.d.ts.map +1 -0
  31. package/dist/lib/get-file-size.d.ts +1 -0
  32. package/dist/lib/get-file-size.d.ts.map +1 -0
  33. package/dist/lib/get-source-map-url.d.ts +1 -0
  34. package/dist/lib/get-source-map-url.d.ts.map +1 -0
  35. package/dist/lib/get-string-details.d.ts +1 -0
  36. package/dist/lib/get-string-details.d.ts.map +1 -0
  37. package/dist/lib/get-string-hash.d.ts +1 -0
  38. package/dist/lib/get-string-hash.d.ts.map +1 -0
  39. package/dist/lib/maximum-size-transform.d.ts +1 -0
  40. package/dist/lib/maximum-size-transform.d.ts.map +1 -0
  41. package/dist/lib/modify-url-prefix-transform.d.ts +1 -0
  42. package/dist/lib/modify-url-prefix-transform.d.ts.map +1 -0
  43. package/dist/lib/no-revision-for-urls-matching-transform.d.ts +1 -0
  44. package/dist/lib/no-revision-for-urls-matching-transform.d.ts.map +1 -0
  45. package/dist/lib/rebase-path.d.ts +1 -0
  46. package/dist/lib/rebase-path.d.ts.map +1 -0
  47. package/dist/lib/replace-and-update-source-map.d.ts +1 -0
  48. package/dist/lib/replace-and-update-source-map.d.ts.map +1 -0
  49. package/dist/lib/serwist-config-error.d.ts +7 -0
  50. package/dist/lib/serwist-config-error.d.ts.map +1 -0
  51. package/dist/lib/transform-manifest.d.ts +2 -1
  52. package/dist/lib/transform-manifest.d.ts.map +1 -0
  53. package/dist/lib/translate-url-to-sourcemap-paths.d.ts +1 -0
  54. package/dist/lib/translate-url-to-sourcemap-paths.d.ts.map +1 -0
  55. package/dist/lib/validate-next-options.d.ts +3 -0
  56. package/dist/lib/validate-next-options.d.ts.map +1 -0
  57. package/dist/lib/validate-options.d.ts +6 -8
  58. package/dist/lib/validate-options.d.ts.map +1 -0
  59. package/dist/schema/base.d.ts +169 -0
  60. package/dist/schema/base.d.ts.map +1 -0
  61. package/dist/schema/getManifest.d.ts +187 -0
  62. package/dist/schema/getManifest.d.ts.map +1 -0
  63. package/dist/schema/glob.d.ts +35 -0
  64. package/dist/schema/glob.d.ts.map +1 -0
  65. package/dist/schema/injectManifest.d.ts +206 -0
  66. package/dist/schema/injectManifest.d.ts.map +1 -0
  67. package/dist/schema/manifestEntry.d.ts +15 -0
  68. package/dist/schema/manifestEntry.d.ts.map +1 -0
  69. package/dist/schema/manifestTransform.d.ts +121 -0
  70. package/dist/schema/manifestTransform.d.ts.map +1 -0
  71. package/dist/schema/next.d.ts +243 -0
  72. package/dist/schema/next.d.ts.map +1 -0
  73. package/dist/schema/swDest.d.ts +16 -0
  74. package/dist/schema/swDest.d.ts.map +1 -0
  75. package/dist/schema/validationErrorMap.d.ts +3 -0
  76. package/dist/schema/validationErrorMap.d.ts.map +1 -0
  77. package/dist/schema/vite.d.ts +196 -0
  78. package/dist/schema/vite.d.ts.map +1 -0
  79. package/dist/schema/webpack.d.ts +231 -0
  80. package/dist/schema/webpack.d.ts.map +1 -0
  81. package/dist/types.d.ts +147 -175
  82. package/dist/types.d.ts.map +1 -0
  83. package/package.json +42 -28
  84. package/src/_types.js +112 -0
  85. package/src/get-manifest.ts +33 -0
  86. package/src/index.next.ts +3 -0
  87. package/{dist/index.d.cts → src/index.ts} +27 -2
  88. package/src/inject-manifest.ts +140 -0
  89. package/src/lib/additional-precache-entries-transform.ts +58 -0
  90. package/src/lib/errors.ts +99 -0
  91. package/src/lib/escape-regexp.ts +12 -0
  92. package/src/lib/get-composite-details.ts +31 -0
  93. package/src/lib/get-file-details.ts +68 -0
  94. package/src/lib/get-file-hash.ts +21 -0
  95. package/src/lib/get-file-manifest-entries.ts +126 -0
  96. package/src/lib/get-file-size.ts +23 -0
  97. package/src/lib/get-source-map-url.ts +17 -0
  98. package/src/lib/get-string-details.ts +18 -0
  99. package/src/lib/get-string-hash.ts +15 -0
  100. package/src/lib/maximum-size-transform.ts +29 -0
  101. package/src/lib/modify-url-prefix-transform.ts +55 -0
  102. package/src/lib/no-revision-for-urls-matching-transform.ts +32 -0
  103. package/src/lib/rebase-path.ts +22 -0
  104. package/src/lib/replace-and-update-source-map.ts +122 -0
  105. package/src/lib/serwist-config-error.ts +6 -0
  106. package/src/lib/transform-manifest.ts +158 -0
  107. package/src/lib/translate-url-to-sourcemap-paths.ts +38 -0
  108. package/src/lib/validate-next-options.ts +14 -0
  109. package/src/lib/validate-options.ts +47 -0
  110. package/src/schema/base.ts +16 -0
  111. package/src/schema/getManifest.ts +14 -0
  112. package/src/schema/glob.ts +41 -0
  113. package/src/schema/injectManifest.ts +23 -0
  114. package/src/schema/manifestEntry.ts +9 -0
  115. package/src/schema/manifestTransform.ts +15 -0
  116. package/src/schema/next.ts +35 -0
  117. package/src/schema/swDest.ts +14 -0
  118. package/src/schema/validationErrorMap.ts +36 -0
  119. package/src/schema/vite.ts +18 -0
  120. package/src/schema/webpack.ts +47 -0
  121. package/src/types.ts +407 -0
  122. package/dist/index.cjs +0 -1632
  123. package/dist/lib/cdn-utils.d.ts +0 -1
  124. package/dist/lib/copy-serwist-libraries.d.ts +0 -16
  125. package/dist/schema/index.d.ts +0 -605
@@ -0,0 +1,126 @@
1
+ /*
2
+ Copyright 2021 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import assert from "assert";
10
+
11
+ import type { FileDetails, GetManifestOptions, GetManifestResult } from "../types.js";
12
+ import { errors } from "./errors.js";
13
+ import { getCompositeDetails } from "./get-composite-details.js";
14
+ import { getFileDetails } from "./get-file-details.js";
15
+ import { getStringDetails } from "./get-string-details.js";
16
+ import { transformManifest } from "./transform-manifest.js";
17
+
18
+ export async function getFileManifestEntries({
19
+ additionalPrecacheEntries,
20
+ dontCacheBustURLsMatching,
21
+ globDirectory,
22
+ globFollow,
23
+ globIgnores,
24
+ globPatterns = [],
25
+ globStrict,
26
+ manifestTransforms,
27
+ maximumFileSizeToCacheInBytes,
28
+ modifyURLPrefix,
29
+ templatedURLs,
30
+ disablePrecacheManifest,
31
+ }: GetManifestOptions): Promise<GetManifestResult> {
32
+ if (disablePrecacheManifest) {
33
+ return {
34
+ count: 0,
35
+ size: 0,
36
+ manifestEntries: undefined,
37
+ warnings: [],
38
+ };
39
+ }
40
+
41
+ const warnings: string[] = [];
42
+ const allFileDetails = new Map<string, FileDetails>();
43
+
44
+ try {
45
+ for (const globPattern of globPatterns) {
46
+ const { globbedFileDetails, warning } = getFileDetails({
47
+ globDirectory,
48
+ globFollow,
49
+ globIgnores,
50
+ globPattern,
51
+ globStrict,
52
+ });
53
+
54
+ if (warning) {
55
+ warnings.push(warning);
56
+ }
57
+
58
+ for (const details of globbedFileDetails) {
59
+ if (details && !allFileDetails.has(details.file)) {
60
+ allFileDetails.set(details.file, details);
61
+ }
62
+ }
63
+ }
64
+ } catch (error) {
65
+ // If there's an exception thrown while globbing, then report
66
+ // it back as a warning, and don't consider it fatal.
67
+ if (error instanceof Error && error.message) {
68
+ warnings.push(error.message);
69
+ }
70
+ }
71
+
72
+ if (templatedURLs) {
73
+ for (const url of Object.keys(templatedURLs)) {
74
+ assert(!allFileDetails.has(url), errors["templated-url-matches-glob"]);
75
+
76
+ const dependencies = templatedURLs[url];
77
+ if (Array.isArray(dependencies)) {
78
+ const details = dependencies.reduce<FileDetails[]>((previous, globPattern) => {
79
+ try {
80
+ const { globbedFileDetails, warning } = getFileDetails({
81
+ globDirectory,
82
+ globFollow,
83
+ globIgnores,
84
+ globPattern,
85
+ globStrict,
86
+ });
87
+
88
+ if (warning) {
89
+ warnings.push(warning);
90
+ }
91
+
92
+ return previous.concat(globbedFileDetails);
93
+ } catch (error) {
94
+ const debugObj: { [key: string]: string[] } = {};
95
+ debugObj[url] = dependencies;
96
+ throw new Error(
97
+ `${errors["bad-template-urls-asset"]} ` +
98
+ `'${globPattern}' from '${JSON.stringify(debugObj)}':\n` +
99
+ `${error instanceof Error ? error.toString() : ""}`,
100
+ );
101
+ }
102
+ }, []);
103
+ if (details.length === 0) {
104
+ throw new Error(`${errors["bad-template-urls-asset"]} The glob ` + `pattern '${dependencies.toString()}' did not match anything.`);
105
+ }
106
+ allFileDetails.set(url, getCompositeDetails(url, details));
107
+ } else if (typeof dependencies === "string") {
108
+ allFileDetails.set(url, getStringDetails(url, dependencies));
109
+ }
110
+ }
111
+ }
112
+
113
+ const transformedManifest = await transformManifest({
114
+ additionalPrecacheEntries,
115
+ dontCacheBustURLsMatching,
116
+ manifestTransforms,
117
+ maximumFileSizeToCacheInBytes,
118
+ modifyURLPrefix,
119
+ fileDetails: Array.from(allFileDetails.values()),
120
+ disablePrecacheManifest,
121
+ });
122
+
123
+ transformedManifest.warnings.push(...warnings);
124
+
125
+ return transformedManifest;
126
+ }
@@ -0,0 +1,23 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import fse from "fs-extra";
10
+
11
+ import { errors } from "./errors.js";
12
+
13
+ export function getFileSize(file: string): number | null {
14
+ try {
15
+ const stat = fse.statSync(file);
16
+ if (!stat.isFile()) {
17
+ return null;
18
+ }
19
+ return stat.size;
20
+ } catch (err) {
21
+ throw new Error(`${errors["unable-to-get-file-size"]} '${err instanceof Error && err.message ? err.message : ""}'`);
22
+ }
23
+ }
@@ -0,0 +1,17 @@
1
+ /*
2
+ Copyright 2022 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ // Adapted from https://github.com/lydell/source-map-url/blob/master/source-map-url.js
10
+ // See https://github.com/GoogleChrome/workbox/issues/3019
11
+ const innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/;
12
+ const regex = RegExp(`(?:/\\*(?:\\s*\r?\n(?://)?)?(?:${innerRegex.source})\\s*\\*/|//(?:${innerRegex.source}))\\s*`);
13
+
14
+ export function getSourceMapURL(srcContents: string): string | null {
15
+ const match = srcContents.match(regex);
16
+ return match ? match[1] || match[2] || "" : null;
17
+ }
@@ -0,0 +1,18 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { FileDetails } from "../types.js";
10
+ import { getStringHash } from "./get-string-hash.js";
11
+
12
+ export function getStringDetails(url: string, str: string): FileDetails {
13
+ return {
14
+ file: url,
15
+ hash: getStringHash(str),
16
+ size: str.length,
17
+ };
18
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import crypto from "crypto";
10
+
11
+ export function getStringHash(input: crypto.BinaryLike): string {
12
+ const md5 = crypto.createHash("md5");
13
+ md5.update(input);
14
+ return md5.digest("hex");
15
+ }
@@ -0,0 +1,29 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import prettyBytes from "pretty-bytes";
10
+
11
+ import type { ManifestTransform } from "../types.js";
12
+
13
+ export function maximumSizeTransform(maximumFileSizeToCacheInBytes: number): ManifestTransform {
14
+ return (originalManifest) => {
15
+ const warnings: string[] = [];
16
+ const manifest = originalManifest.filter((entry) => {
17
+ if (entry.size <= maximumFileSizeToCacheInBytes) {
18
+ return true;
19
+ }
20
+
21
+ warnings.push(
22
+ `${entry.url} is ${prettyBytes(entry.size)}, and won't be precached. Configure maximumFileSizeToCacheInBytes to change this limit.`,
23
+ );
24
+ return false;
25
+ });
26
+
27
+ return { manifest, warnings };
28
+ };
29
+ }
@@ -0,0 +1,55 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { ManifestTransform } from "../types.js";
10
+ import { errors } from "./errors.js";
11
+ import { escapeRegExp } from "./escape-regexp.js";
12
+
13
+ export function modifyURLPrefixTransform(modifyURLPrefix: { [key: string]: string }): ManifestTransform {
14
+ if (!modifyURLPrefix || typeof modifyURLPrefix !== "object" || Array.isArray(modifyURLPrefix)) {
15
+ throw new Error(errors["modify-url-prefix-bad-prefixes"]);
16
+ }
17
+
18
+ // If there are no entries in modifyURLPrefix, just return an identity
19
+ // function as a shortcut.
20
+ if (Object.keys(modifyURLPrefix).length === 0) {
21
+ return (manifest) => {
22
+ return { manifest };
23
+ };
24
+ }
25
+
26
+ for (const key of Object.keys(modifyURLPrefix)) {
27
+ if (typeof modifyURLPrefix[key] !== "string") {
28
+ throw new Error(errors["modify-url-prefix-bad-prefixes"]);
29
+ }
30
+ }
31
+
32
+ // Escape the user input so it's safe to use in a regex.
33
+ const safeModifyURLPrefixes = Object.keys(modifyURLPrefix).map(escapeRegExp);
34
+ // Join all the `modifyURLPrefix` keys so a single regex can be used.
35
+ const prefixMatchesStrings = safeModifyURLPrefixes.join("|");
36
+ // Add `^` to the front the prefix matches so it only matches the start of
37
+ // a string.
38
+ const modifyRegex = new RegExp(`^(${prefixMatchesStrings})`);
39
+
40
+ return (originalManifest) => {
41
+ const manifest = originalManifest.map((entry) => {
42
+ if (typeof entry.url !== "string") {
43
+ throw new Error(errors["manifest-entry-bad-url"]);
44
+ }
45
+
46
+ entry.url = entry.url.replace(modifyRegex, (match) => {
47
+ return modifyURLPrefix[match];
48
+ });
49
+
50
+ return entry;
51
+ });
52
+
53
+ return { manifest };
54
+ };
55
+ }
@@ -0,0 +1,32 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { ManifestTransform } from "../types.js";
10
+ import { errors } from "./errors.js";
11
+
12
+ export function noRevisionForURLsMatchingTransform(regexp: RegExp): ManifestTransform {
13
+ if (!(regexp instanceof RegExp)) {
14
+ throw new Error(errors["invalid-dont-cache-bust"]);
15
+ }
16
+
17
+ return (originalManifest) => {
18
+ const manifest = originalManifest.map((entry) => {
19
+ if (typeof entry.url !== "string") {
20
+ throw new Error(errors["manifest-entry-bad-url"]);
21
+ }
22
+
23
+ if (entry.url.match(regexp)) {
24
+ entry.revision = null;
25
+ }
26
+
27
+ return entry;
28
+ });
29
+
30
+ return { manifest };
31
+ };
32
+ }
@@ -0,0 +1,22 @@
1
+ /*
2
+ Copyright 2019 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import upath from "upath";
10
+
11
+ export function rebasePath({ baseDirectory, file }: { baseDirectory: string; file: string }): string {
12
+ // The initial path is relative to the current directory, so make it absolute.
13
+ const absolutePath = upath.resolve(file);
14
+
15
+ // Convert the absolute path so that it's relative to the baseDirectory.
16
+ const relativePath = upath.relative(baseDirectory, absolutePath);
17
+
18
+ // Remove any leading ./ as it won't work in a glob pattern.
19
+ const normalizedPath = upath.normalize(relativePath);
20
+
21
+ return normalizedPath;
22
+ }
@@ -0,0 +1,122 @@
1
+ /*
2
+ Copyright 2019 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { RawSourceMap } from "source-map";
10
+ import { SourceMapConsumer, SourceMapGenerator } from "source-map";
11
+
12
+ interface ReplaceAndUpdateSourceMapOptions {
13
+ /**
14
+ * The name for the file whose contents
15
+ * correspond to originalSource.
16
+ */
17
+ jsFilename: string;
18
+ /**
19
+ * The sourcemap for originalSource,
20
+ * prior to any replacements.
21
+ */
22
+ originalMap: RawSourceMap;
23
+ /**
24
+ * The source code, prior to any
25
+ * replacements.
26
+ */
27
+ originalSource: string;
28
+ /**
29
+ * A string to swap in for searchString.
30
+ */
31
+ replaceString: string;
32
+ /**
33
+ * A string in originalSource to replace.
34
+ * Only the first occurrence will be replaced.
35
+ */
36
+ searchString: string;
37
+ }
38
+
39
+ /**
40
+ * Adapted from https://github.com/nsams/sourcemap-aware-replace, with modern
41
+ * JavaScript updates, along with additional properties copied from originalMap.
42
+ *
43
+ * @param options
44
+ * @returns An object containing both
45
+ * originalSource with the replacement applied, and the modified originalMap.
46
+ * @private
47
+ */
48
+ export async function replaceAndUpdateSourceMap({
49
+ jsFilename,
50
+ originalMap,
51
+ originalSource,
52
+ replaceString,
53
+ searchString,
54
+ }: ReplaceAndUpdateSourceMapOptions): Promise<{ map: string; source: string }> {
55
+ const generator = new SourceMapGenerator({
56
+ file: jsFilename,
57
+ });
58
+
59
+ const consumer = await new SourceMapConsumer(originalMap);
60
+
61
+ let pos: number;
62
+ let src = originalSource;
63
+ const replacements: { line: number; column: number }[] = [];
64
+ let lineNum = 0;
65
+ let filePos = 0;
66
+
67
+ const lines = src.split("\n");
68
+ for (let line of lines) {
69
+ lineNum++;
70
+ let searchPos = 0;
71
+ while ((pos = line.indexOf(searchString, searchPos)) !== -1) {
72
+ src = src.substring(0, filePos + pos) + replaceString + src.substring(filePos + pos + searchString.length);
73
+ line = line.substring(0, pos) + replaceString + line.substring(pos + searchString.length);
74
+ replacements.push({ line: lineNum, column: pos });
75
+ searchPos = pos + replaceString.length;
76
+ }
77
+ filePos += line.length + 1;
78
+ }
79
+
80
+ replacements.reverse();
81
+
82
+ consumer.eachMapping((mapping) => {
83
+ for (const replacement of replacements) {
84
+ if (replacement.line === mapping.generatedLine && mapping.generatedColumn > replacement.column) {
85
+ const offset = searchString.length - replaceString.length;
86
+ mapping.generatedColumn -= offset;
87
+ }
88
+ }
89
+
90
+ if (mapping.source) {
91
+ const newMapping = {
92
+ generated: {
93
+ line: mapping.generatedLine,
94
+ column: mapping.generatedColumn,
95
+ },
96
+ original: {
97
+ line: mapping.originalLine,
98
+ column: mapping.originalColumn,
99
+ },
100
+ source: mapping.source,
101
+ };
102
+ return generator.addMapping(newMapping);
103
+ }
104
+
105
+ return mapping;
106
+ });
107
+
108
+ consumer.destroy();
109
+ // JSON.parse returns any.
110
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
111
+ const updatedSourceMap: RawSourceMap = Object.assign(JSON.parse(generator.toString()), {
112
+ names: originalMap.names,
113
+ sourceRoot: originalMap.sourceRoot,
114
+ sources: originalMap.sources,
115
+ sourcesContent: originalMap.sourcesContent,
116
+ });
117
+
118
+ return {
119
+ map: JSON.stringify(updatedSourceMap),
120
+ source: src,
121
+ };
122
+ }
@@ -0,0 +1,6 @@
1
+ export class SerwistConfigError extends Error {
2
+ constructor({ moduleName, message }: { moduleName?: string; message?: string }) {
3
+ super(`Received an invalid ${moduleName ?? "Serwist"} configuration: ${message}`);
4
+ Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }
@@ -0,0 +1,158 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { BasePartial, FileDetails, ManifestEntry, ManifestTransform } from "../types.js";
10
+ import { additionalPrecacheEntriesTransform } from "./additional-precache-entries-transform.js";
11
+ import { errors } from "./errors.js";
12
+ import { maximumSizeTransform } from "./maximum-size-transform.js";
13
+ import { modifyURLPrefixTransform } from "./modify-url-prefix-transform.js";
14
+ import { noRevisionForURLsMatchingTransform } from "./no-revision-for-urls-matching-transform.js";
15
+
16
+ /**
17
+ * A `ManifestTransform` function can be used to modify the modify the `url` or
18
+ * `revision` properties of some or all of the
19
+ * `@serwist/build.ManifestEntry` in the manifest.
20
+ *
21
+ * Deleting the `revision` property of an entry will cause
22
+ * the corresponding `url` to be precached without cache-busting parameters
23
+ * applied, which is to say, it implies that the URL itself contains
24
+ * proper versioning info. If the `revision` property is present, it must be
25
+ * set to a string.
26
+ *
27
+ * @example A transformation that prepended the origin of a CDN for any
28
+ * URL starting with '/assets/' could be implemented as:
29
+ *
30
+ * const cdnTransform = async (manifestEntries) => {
31
+ * const manifest = manifestEntries.map(entry => {
32
+ * const cdnOrigin = 'https://example.com';
33
+ * if (entry.url.startsWith('/assets/')) {
34
+ * entry.url = cdnOrigin + entry.url;
35
+ * }
36
+ * return entry;
37
+ * });
38
+ * return {manifest, warnings: []};
39
+ * };
40
+ *
41
+ * @example A transformation that nulls the revision field when the
42
+ * URL contains an 8-character hash surrounded by '.', indicating that it
43
+ * already contains revision information:
44
+ *
45
+ * const removeRevisionTransform = async (manifestEntries) => {
46
+ * const manifest = manifestEntries.map(entry => {
47
+ * const hashRegExp = /\.\w{8}\./;
48
+ * if (entry.url.match(hashRegExp)) {
49
+ * entry.revision = null;
50
+ * }
51
+ * return entry;
52
+ * });
53
+ * return {manifest, warnings: []};
54
+ * };
55
+ *
56
+ * @callback ManifestTransform
57
+ * @param manifestEntries The full
58
+ * array of entries, prior to the current transformation.
59
+ * @param compilation When used in the webpack plugins, this param
60
+ * will be set to the current `compilation`.
61
+ * @returns The array of entries with the transformation applied,
62
+ * and optionally, any warnings that should be reported back to the build tool.
63
+ */
64
+
65
+ interface ManifestTransformResultWithWarnings {
66
+ count: number;
67
+ size: number;
68
+ manifestEntries: ManifestEntry[] | undefined;
69
+ warnings: string[];
70
+ }
71
+ export async function transformManifest({
72
+ additionalPrecacheEntries,
73
+ dontCacheBustURLsMatching,
74
+ fileDetails,
75
+ manifestTransforms,
76
+ maximumFileSizeToCacheInBytes,
77
+ modifyURLPrefix,
78
+ transformParam,
79
+ disablePrecacheManifest,
80
+ }: BasePartial & {
81
+ fileDetails: FileDetails[];
82
+ // When this is called by the webpack plugin, transformParam will be the
83
+ // current webpack compilation.
84
+ transformParam?: unknown;
85
+ }): Promise<ManifestTransformResultWithWarnings> {
86
+ if (disablePrecacheManifest) {
87
+ return {
88
+ count: 0,
89
+ size: 0,
90
+ manifestEntries: undefined,
91
+ warnings: [],
92
+ };
93
+ }
94
+
95
+ const allWarnings: string[] = [];
96
+
97
+ // Take the array of fileDetail objects and convert it into an array of
98
+ // {url, revision, size} objects, with \ replaced with /.
99
+ const normalizedManifest = fileDetails.map((fileDetails) => {
100
+ return {
101
+ url: fileDetails.file.replace(/\\/g, "/"),
102
+ revision: fileDetails.hash,
103
+ size: fileDetails.size,
104
+ };
105
+ });
106
+
107
+ const transformsToApply: ManifestTransform[] = [];
108
+
109
+ if (maximumFileSizeToCacheInBytes) {
110
+ transformsToApply.push(maximumSizeTransform(maximumFileSizeToCacheInBytes));
111
+ }
112
+
113
+ if (modifyURLPrefix) {
114
+ transformsToApply.push(modifyURLPrefixTransform(modifyURLPrefix));
115
+ }
116
+
117
+ if (dontCacheBustURLsMatching) {
118
+ transformsToApply.push(noRevisionForURLsMatchingTransform(dontCacheBustURLsMatching));
119
+ }
120
+
121
+ // Run any manifestTransforms functions second-to-last.
122
+ if (manifestTransforms) {
123
+ transformsToApply.push(...manifestTransforms);
124
+ }
125
+
126
+ // Run additionalPrecacheEntriesTransform last.
127
+ if (additionalPrecacheEntries) {
128
+ transformsToApply.push(additionalPrecacheEntriesTransform(additionalPrecacheEntries));
129
+ }
130
+
131
+ let transformedManifest: (ManifestEntry & { size: number })[] = normalizedManifest;
132
+ for (const transform of transformsToApply) {
133
+ const result = await transform(transformedManifest, transformParam);
134
+ if (!("manifest" in result)) {
135
+ throw new Error(errors["bad-manifest-transforms-return-value"]);
136
+ }
137
+
138
+ transformedManifest = result.manifest;
139
+ allWarnings.push(...(result.warnings || []));
140
+ }
141
+
142
+ // Generate some metadata about the manifest before we clear out the size
143
+ // properties from each entry.
144
+ const count = transformedManifest.length;
145
+ let size = 0;
146
+ for (const manifestEntry of transformedManifest as (ManifestEntry & { size?: number })[]) {
147
+ size += manifestEntry.size || 0;
148
+ // biome-ignore lint/performance/noDelete: I don't understand this part yet.
149
+ delete manifestEntry.size;
150
+ }
151
+
152
+ return {
153
+ count,
154
+ size,
155
+ manifestEntries: transformedManifest as ManifestEntry[],
156
+ warnings: allWarnings,
157
+ };
158
+ }
@@ -0,0 +1,38 @@
1
+ /*
2
+ Copyright 2021 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import fse from "fs-extra";
10
+ import upath from "upath";
11
+
12
+ import { errors } from "./errors.js";
13
+
14
+ export function translateURLToSourcemapPaths(
15
+ url: string | null,
16
+ swSrc: string,
17
+ swDest: string,
18
+ ): {
19
+ destPath: string | undefined;
20
+ srcPath: string | undefined;
21
+ warning: string | undefined;
22
+ } {
23
+ let destPath: string | undefined = undefined;
24
+ let srcPath: string | undefined = undefined;
25
+ let warning: string | undefined = undefined;
26
+
27
+ if (url && !url.startsWith("data:")) {
28
+ const possibleSrcPath = upath.resolve(upath.dirname(swSrc), url);
29
+ if (fse.existsSync(possibleSrcPath)) {
30
+ srcPath = possibleSrcPath;
31
+ destPath = upath.resolve(upath.dirname(swDest), url);
32
+ } else {
33
+ warning = `${errors["cant-find-sourcemap"]} ${possibleSrcPath}`;
34
+ }
35
+ }
36
+
37
+ return { destPath, srcPath, warning };
38
+ }
@@ -0,0 +1,14 @@
1
+ import { nextInjectManifestOptions } from "../schema/next.js";
2
+ import { validationErrorMap } from "../schema/validationErrorMap.js";
3
+ import type { NextInjectManifestOptionsComplete } from "../types.js";
4
+ import { SerwistConfigError } from "./serwist-config-error.js";
5
+
6
+ export const validateNextInjectManifestOptions = (input: unknown): NextInjectManifestOptionsComplete => {
7
+ const result = nextInjectManifestOptions.safeParse(input, {
8
+ errorMap: validationErrorMap,
9
+ });
10
+ if (!result.success) {
11
+ throw new SerwistConfigError({ moduleName: "@serwist/next", message: JSON.stringify(result.error.format(), null, 2) });
12
+ }
13
+ return result.data;
14
+ };