@jsenv/core 25.0.1 → 25.2.1
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.
- package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +2 -2
- package/dist/build_manifest.js +4 -4
- package/dist/compile_proxy/asset-manifest.json +2 -2
- package/dist/compile_proxy/{compile_proxy_e3b0c442_809f35f7.js.map → compile_proxy.html__inline__20_809f35f7.js.map} +0 -0
- package/dist/compile_proxy/{compile_proxy_7ad5faa6.html → compile_proxy_8dfaee51.html} +3 -4
- package/dist/redirector/asset-manifest.json +2 -2
- package/dist/redirector/{redirector_e3b0c442_e391410e.js.map → redirector.html__inline__15_e391410e.js.map} +0 -0
- package/dist/redirector/{redirector_eb92e8a7.html → redirector_3e9a97b9.html} +3 -4
- package/dist/toolbar/asset-manifest.json +1 -1
- package/dist/toolbar/{toolbar_f7b8a263.html → toolbar_361afb84.html} +2 -3
- package/dist/toolbar_injector/asset-manifest.json +2 -2
- package/dist/toolbar_injector/{toolbar_injector_49e4756e.js → toolbar_injector_fac1e995.js} +2 -2
- package/dist/toolbar_injector/{toolbar_injector_49e4756e.js.map → toolbar_injector_fac1e995.js.map} +2 -2
- package/package.json +9 -10
- package/readme.md +60 -51
- package/src/buildProject.js +21 -13
- package/src/commonJsToJavaScriptModule.js +8 -7
- package/src/dev_server.js +2 -0
- package/src/execute.js +2 -0
- package/src/executeTestPlan.js +14 -0
- package/src/internal/building/buildUsingRollup.js +4 -2
- package/src/internal/building/build_stats.js +3 -0
- package/src/internal/building/build_url_generator.js +153 -0
- package/src/internal/building/css/parseCssRessource.js +32 -26
- package/src/internal/building/html/parseHtmlRessource.js +109 -91
- package/src/internal/building/js/parseJsRessource.js +5 -13
- package/src/internal/building/parseRessource.js +3 -0
- package/src/internal/building/ressource_builder.js +72 -64
- package/src/internal/building/ressource_builder_util.js +17 -5
- package/src/internal/building/rollup_plugin_jsenv.js +262 -189
- package/src/internal/building/url_fetcher.js +16 -7
- package/src/internal/building/url_loader.js +1 -5
- package/src/internal/building/url_versioning.js +0 -173
- package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
- package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
- package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
- package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
- package/src/internal/compiling/compile-directory/updateMeta.js +4 -8
- package/src/internal/compiling/compile-directory/validateCache.js +1 -2
- package/src/internal/compiling/compileFile.js +22 -10
- package/src/internal/compiling/compileHtml.js +15 -28
- package/src/internal/compiling/createCompiledFileService.js +22 -24
- package/src/internal/compiling/html_source_file_service.js +18 -19
- package/src/internal/compiling/js-compilation-service/babelHelper.js +10 -13
- package/src/internal/compiling/js-compilation-service/babel_plugin_babel_helpers_as_jsenv_imports.js +4 -2
- package/src/internal/compiling/js-compilation-service/jsenvTransform.js +16 -7
- package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
- package/src/internal/compiling/jsenvCompilerForHtml.js +536 -262
- package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
- package/src/internal/compiling/startCompileServer.js +83 -20
- package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
- package/src/internal/executing/executePlan.js +2 -0
- package/src/internal/fetchUrl.js +3 -2
- package/src/internal/integrity/integrity_algorithms.js +26 -0
- package/src/internal/integrity/integrity_parsing.js +50 -0
- package/src/internal/integrity/integrity_update.js +23 -0
- package/src/internal/integrity/integrity_validation.js +49 -0
- package/src/internal/jsenvCoreDirectoryUrl.js +2 -0
- package/src/internal/jsenv_remote_directory.js +156 -0
- package/src/internal/origin_directory_converter.js +62 -0
- package/src/internal/response_validation.js +11 -24
- package/src/internal/sourceMappingURLUtils.js +10 -0
- package/src/internal/url_conversion.js +1 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { generateSourcemapUrl } from "@jsenv/core/src/internal/sourceMappingURLUtils.js"
|
|
2
|
+
|
|
1
3
|
import { transformJs } from "./js-compilation-service/transformJs.js"
|
|
2
4
|
import { transformResultToCompilationResult } from "./transformResultToCompilationResult.js"
|
|
3
5
|
|
|
4
6
|
export const compileJavascript = async ({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
projectDirectoryUrl,
|
|
8
|
+
jsenvRemoteDirectory,
|
|
7
9
|
url,
|
|
8
10
|
compiledUrl,
|
|
9
|
-
projectDirectoryUrl,
|
|
10
11
|
|
|
11
12
|
babelPluginMap,
|
|
12
13
|
workerUrls,
|
|
@@ -16,6 +17,8 @@ export const compileJavascript = async ({
|
|
|
16
17
|
topLevelAwait,
|
|
17
18
|
prependSystemJs,
|
|
18
19
|
|
|
20
|
+
code,
|
|
21
|
+
map,
|
|
19
22
|
sourcemapExcludeSources,
|
|
20
23
|
sourcemapMethod,
|
|
21
24
|
}) => {
|
|
@@ -23,38 +26,39 @@ export const compileJavascript = async ({
|
|
|
23
26
|
prependSystemJs =
|
|
24
27
|
workerUrls.includes(url) || serviceWorkerUrls.includes(url)
|
|
25
28
|
}
|
|
26
|
-
|
|
27
29
|
const transformResult = await transformJs({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
projectDirectoryUrl,
|
|
31
|
+
jsenvRemoteDirectory,
|
|
30
32
|
url,
|
|
31
33
|
compiledUrl,
|
|
32
|
-
projectDirectoryUrl,
|
|
33
34
|
|
|
34
35
|
babelPluginMap,
|
|
35
36
|
moduleOutFormat,
|
|
36
37
|
importMetaFormat,
|
|
37
38
|
topLevelAwait,
|
|
38
39
|
prependSystemJs,
|
|
39
|
-
})
|
|
40
40
|
|
|
41
|
+
code,
|
|
42
|
+
map,
|
|
43
|
+
})
|
|
41
44
|
return transformResultToCompilationResult(
|
|
42
45
|
{
|
|
43
46
|
contentType: "application/javascript",
|
|
47
|
+
metadata: transformResult.metadata,
|
|
44
48
|
code: transformResult.code,
|
|
45
49
|
map: transformResult.map,
|
|
46
|
-
metadata: transformResult.metadata,
|
|
47
50
|
},
|
|
48
51
|
{
|
|
49
52
|
projectDirectoryUrl,
|
|
50
|
-
|
|
53
|
+
jsenvRemoteDirectory,
|
|
51
54
|
originalFileUrl: url,
|
|
52
55
|
compiledFileUrl: compiledUrl,
|
|
53
56
|
// sourcemap are not inside the asset folder because
|
|
54
57
|
// of https://github.com/microsoft/vscode-chrome-debug-core/issues/544
|
|
55
|
-
sourcemapFileUrl:
|
|
58
|
+
sourcemapFileUrl: generateSourcemapUrl(compiledUrl),
|
|
56
59
|
sourcemapExcludeSources,
|
|
57
60
|
sourcemapMethod,
|
|
61
|
+
originalFileContent: code,
|
|
58
62
|
},
|
|
59
63
|
)
|
|
60
64
|
}
|
|
@@ -36,14 +36,19 @@ import {
|
|
|
36
36
|
} from "@jsenv/core/dist/build_manifest.js"
|
|
37
37
|
import { generateGroupMap } from "@jsenv/core/src/internal/generateGroupMap/generateGroupMap.js"
|
|
38
38
|
import { isBrowserPartOfSupportedRuntimes } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
|
|
39
|
-
|
|
40
|
-
import {
|
|
39
|
+
|
|
40
|
+
import { createJsenvRemoteDirectory } from "../jsenv_remote_directory.js"
|
|
41
41
|
import {
|
|
42
42
|
sourcemapMainFileInfo,
|
|
43
43
|
sourcemapMappingFileInfo,
|
|
44
44
|
} from "../jsenvInternalFiles.js"
|
|
45
|
-
import { jsenvCoreDirectoryUrl } from "../jsenvCoreDirectoryUrl.js"
|
|
46
45
|
import { babelPluginReplaceExpressions } from "../babel_plugin_replace_expressions.js"
|
|
46
|
+
import {
|
|
47
|
+
jsenvCoreDirectoryUrl,
|
|
48
|
+
jsenvDistDirectoryUrl,
|
|
49
|
+
} from "../jsenvCoreDirectoryUrl.js"
|
|
50
|
+
import { loadBabelPluginMapFromFile } from "./load_babel_plugin_map_from_file.js"
|
|
51
|
+
import { extractSyntaxBabelPluginMap } from "./babel_plugins.js"
|
|
47
52
|
import { babelPluginGlobalThisAsJsenvImport } from "./babel_plugin_global_this_as_jsenv_import.js"
|
|
48
53
|
import { babelPluginNewStylesheetAsJsenvImport } from "./babel_plugin_new_stylesheet_as_jsenv_import.js"
|
|
49
54
|
import { babelPluginImportAssertions } from "./babel_plugin_import_assertions.js"
|
|
@@ -95,6 +100,7 @@ export const startCompileServer = async ({
|
|
|
95
100
|
babelPluginMap,
|
|
96
101
|
babelConfigFileUrl,
|
|
97
102
|
customCompilers = {},
|
|
103
|
+
preservedUrls,
|
|
98
104
|
workers = [],
|
|
99
105
|
serviceWorkers = [],
|
|
100
106
|
importMapInWebWorkers = false,
|
|
@@ -143,6 +149,30 @@ export const startCompileServer = async ({
|
|
|
143
149
|
)
|
|
144
150
|
const logger = createLogger({ logLevel })
|
|
145
151
|
|
|
152
|
+
preservedUrls = {
|
|
153
|
+
// Authorize jsenv to modify any file url
|
|
154
|
+
// because the goal is to build the files into chunks
|
|
155
|
+
"file://": false,
|
|
156
|
+
// Preserves http and https urls
|
|
157
|
+
// because if code specifiy a CDN url it's usually because code wants
|
|
158
|
+
// to keep the url intact and keep HTTP request to CDN (both in dev and prod)
|
|
159
|
+
"http://": true,
|
|
160
|
+
"https://": true,
|
|
161
|
+
/*
|
|
162
|
+
* It's possible to selectively overrides the behaviour above:
|
|
163
|
+
* 1. The CDN file needs to be transformed to be executable in dev, build or both
|
|
164
|
+
* preservedUrls: {"https://cdn.skypack.dev/preact@10.6.4": false}
|
|
165
|
+
* 2. No strong need to preserve the CDN dependency
|
|
166
|
+
* 3. Prevent concatenation of a file during build
|
|
167
|
+
* preservedUrls: {"./file.js": false}
|
|
168
|
+
*/
|
|
169
|
+
...preservedUrls,
|
|
170
|
+
}
|
|
171
|
+
const jsenvRemoteDirectory = createJsenvRemoteDirectory({
|
|
172
|
+
projectDirectoryUrl,
|
|
173
|
+
jsenvDirectoryRelativeUrl,
|
|
174
|
+
preservedUrls,
|
|
175
|
+
})
|
|
146
176
|
const workerUrls = workers.map((worker) =>
|
|
147
177
|
resolveUrl(worker, projectDirectoryUrl),
|
|
148
178
|
)
|
|
@@ -287,11 +317,18 @@ export const startCompileServer = async ({
|
|
|
287
317
|
projectDirectoryUrl,
|
|
288
318
|
jsenvDirectoryRelativeUrl,
|
|
289
319
|
outDirectoryRelativeUrl,
|
|
320
|
+
jsenvRemoteDirectory,
|
|
290
321
|
importDefaultExtension,
|
|
322
|
+
|
|
323
|
+
preservedUrls,
|
|
324
|
+
workers,
|
|
325
|
+
serviceWorkers,
|
|
291
326
|
compileServerGroupMap,
|
|
327
|
+
babelPluginMap,
|
|
328
|
+
replaceProcessEnvNodeEnv,
|
|
329
|
+
processEnvNodeEnv,
|
|
292
330
|
env,
|
|
293
331
|
inlineImportMapIntoHTML,
|
|
294
|
-
babelPluginMap,
|
|
295
332
|
customCompilers,
|
|
296
333
|
jsenvToolbarInjection,
|
|
297
334
|
sourcemapMethod,
|
|
@@ -325,7 +362,9 @@ export const startCompileServer = async ({
|
|
|
325
362
|
logger,
|
|
326
363
|
|
|
327
364
|
projectDirectoryUrl,
|
|
365
|
+
jsenvDirectoryRelativeUrl,
|
|
328
366
|
outDirectoryRelativeUrl,
|
|
367
|
+
jsenvRemoteDirectory,
|
|
329
368
|
|
|
330
369
|
importDefaultExtension,
|
|
331
370
|
|
|
@@ -366,6 +405,7 @@ export const startCompileServer = async ({
|
|
|
366
405
|
: {}),
|
|
367
406
|
"service:source file": createSourceFileService({
|
|
368
407
|
projectDirectoryUrl,
|
|
408
|
+
jsenvRemoteDirectory,
|
|
369
409
|
projectFileRequestedCallback,
|
|
370
410
|
projectFileCacheStrategy,
|
|
371
411
|
}),
|
|
@@ -421,6 +461,7 @@ export const startCompileServer = async ({
|
|
|
421
461
|
...compileServer,
|
|
422
462
|
compileServerGroupMap,
|
|
423
463
|
babelPluginMap,
|
|
464
|
+
preservedUrls,
|
|
424
465
|
projectFileRequestedCallback,
|
|
425
466
|
}
|
|
426
467
|
}
|
|
@@ -936,30 +977,45 @@ const createSourceFileService = ({
|
|
|
936
977
|
projectDirectoryUrl,
|
|
937
978
|
projectFileRequestedCallback,
|
|
938
979
|
projectFileCacheStrategy,
|
|
980
|
+
jsenvRemoteDirectory,
|
|
939
981
|
}) => {
|
|
940
982
|
return async (request) => {
|
|
941
983
|
const relativeUrl = request.pathname.slice(1)
|
|
942
984
|
projectFileRequestedCallback(relativeUrl, request)
|
|
943
|
-
|
|
944
985
|
const fileUrl = new URL(request.ressource.slice(1), projectDirectoryUrl)
|
|
945
986
|
.href
|
|
946
987
|
const fileIsInsideJsenvDistDirectory = urlIsInsideOf(
|
|
947
988
|
fileUrl,
|
|
948
|
-
|
|
989
|
+
jsenvDistDirectoryUrl,
|
|
949
990
|
)
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
991
|
+
const fromFileSystem = () =>
|
|
992
|
+
fetchFileSystem(fileUrl, {
|
|
993
|
+
headers: request.headers,
|
|
994
|
+
etagEnabled: projectFileCacheStrategy === "etag",
|
|
995
|
+
mtimeEnabled: projectFileCacheStrategy === "mtime",
|
|
996
|
+
...(fileIsInsideJsenvDistDirectory
|
|
997
|
+
? {
|
|
998
|
+
cacheControl: `private,max-age=${60 * 60 * 24 * 30},immutable`,
|
|
999
|
+
}
|
|
1000
|
+
: {}),
|
|
1001
|
+
})
|
|
1002
|
+
const filesystemResponse = await fromFileSystem()
|
|
1003
|
+
if (
|
|
1004
|
+
filesystemResponse.status === 404 &&
|
|
1005
|
+
jsenvRemoteDirectory.isFileUrlForRemoteUrl(fileUrl)
|
|
1006
|
+
) {
|
|
1007
|
+
try {
|
|
1008
|
+
await jsenvRemoteDirectory.loadFileUrlFromRemote(fileUrl, request)
|
|
1009
|
+
// re-fetch filesystem instead to ensure response headers are correct
|
|
1010
|
+
return fromFileSystem()
|
|
1011
|
+
} catch (e) {
|
|
1012
|
+
if (e && e.asResponse) {
|
|
1013
|
+
return e.asResponse()
|
|
1014
|
+
}
|
|
1015
|
+
throw e
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return filesystemResponse
|
|
963
1019
|
}
|
|
964
1020
|
}
|
|
965
1021
|
|
|
@@ -968,6 +1024,10 @@ const createCompileServerMetaFileInfo = ({
|
|
|
968
1024
|
jsenvDirectoryRelativeUrl,
|
|
969
1025
|
outDirectoryRelativeUrl,
|
|
970
1026
|
importDefaultExtension,
|
|
1027
|
+
|
|
1028
|
+
preservedUrls,
|
|
1029
|
+
workers,
|
|
1030
|
+
serviceWorkers,
|
|
971
1031
|
compileServerGroupMap,
|
|
972
1032
|
babelPluginMap,
|
|
973
1033
|
replaceProcessEnvNodeEnv,
|
|
@@ -1013,6 +1073,9 @@ const createCompileServerMetaFileInfo = ({
|
|
|
1013
1073
|
outDirectoryRelativeUrl,
|
|
1014
1074
|
importDefaultExtension,
|
|
1015
1075
|
|
|
1076
|
+
preservedUrls,
|
|
1077
|
+
workers,
|
|
1078
|
+
serviceWorkers,
|
|
1016
1079
|
babelPluginMap: babelPluginMapAsData(babelPluginMap),
|
|
1017
1080
|
compileServerGroupMap,
|
|
1018
1081
|
customCompilerPatterns,
|
|
@@ -1026,7 +1089,7 @@ const createCompileServerMetaFileInfo = ({
|
|
|
1026
1089
|
sourcemapMappingFileRelativeUrl,
|
|
1027
1090
|
errorStackRemapping: true,
|
|
1028
1091
|
|
|
1029
|
-
// used to consider
|
|
1092
|
+
// used to consider logic generating files may have changed
|
|
1030
1093
|
jsenvCorePackageVersion,
|
|
1031
1094
|
|
|
1032
1095
|
// impact only HTML files
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
urlToRelativeUrl,
|
|
4
4
|
readFile,
|
|
5
5
|
ensureWindowsDriveLetter,
|
|
6
|
+
urlIsInsideOf,
|
|
6
7
|
} from "@jsenv/filesystem"
|
|
7
8
|
|
|
8
9
|
import {
|
|
@@ -15,16 +16,16 @@ import {
|
|
|
15
16
|
setCssSourceMappingUrl,
|
|
16
17
|
sourcemapToBase64Url,
|
|
17
18
|
} from "../sourceMappingURLUtils.js"
|
|
18
|
-
import {
|
|
19
|
+
import { generateCompilationAssetUrl } from "./compile-directory/compile-asset.js"
|
|
19
20
|
import { testFilePresence } from "./compile-directory/fs-optimized-for-cache.js"
|
|
20
21
|
|
|
21
22
|
const isWindows = process.platform === "win32"
|
|
22
23
|
|
|
23
24
|
export const transformResultToCompilationResult = async (
|
|
24
|
-
{ contentType,
|
|
25
|
+
{ contentType, metadata = {}, code, map },
|
|
25
26
|
{
|
|
26
27
|
projectDirectoryUrl,
|
|
27
|
-
|
|
28
|
+
jsenvRemoteDirectory,
|
|
28
29
|
originalFileUrl,
|
|
29
30
|
compiledFileUrl,
|
|
30
31
|
sourcemapFileUrl,
|
|
@@ -33,9 +34,13 @@ export const transformResultToCompilationResult = async (
|
|
|
33
34
|
// it also means client have to fetch source from server (additional http request)
|
|
34
35
|
// some client ignore sourcesContent property such as vscode-chrome-debugger
|
|
35
36
|
// Because it's the most complex scenario and we want to ensure client is always able
|
|
36
|
-
// to find source from the sourcemap,
|
|
37
|
-
|
|
37
|
+
// to find source from the sourcemap, it's a good idea
|
|
38
|
+
// to exclude sourcesContent from sourcemap.
|
|
39
|
+
// However some ressource are abstract and it means additional http request for the browser.
|
|
40
|
+
// For these reasons it's simpler to keep source content in sourcemap.
|
|
41
|
+
sourcemapExcludeSources = false,
|
|
38
42
|
sourcemapMethod = "comment", // "comment", "inline"
|
|
43
|
+
originalFileContent,
|
|
39
44
|
},
|
|
40
45
|
) => {
|
|
41
46
|
if (typeof contentType !== "string") {
|
|
@@ -71,6 +76,14 @@ export const transformResultToCompilationResult = async (
|
|
|
71
76
|
const sourcesContent = []
|
|
72
77
|
const assets = []
|
|
73
78
|
const assetsContent = []
|
|
79
|
+
const addSource = ({ url, content }) => {
|
|
80
|
+
sources.push(url)
|
|
81
|
+
sourcesContent.push(content)
|
|
82
|
+
}
|
|
83
|
+
const addAsset = ({ url, content }) => {
|
|
84
|
+
assets.push(url)
|
|
85
|
+
assetsContent.push(content)
|
|
86
|
+
}
|
|
74
87
|
|
|
75
88
|
let output = code
|
|
76
89
|
if (sourcemapEnabled && map) {
|
|
@@ -78,8 +91,10 @@ export const transformResultToCompilationResult = async (
|
|
|
78
91
|
// may happen in some cases where babel returns a wrong sourcemap
|
|
79
92
|
// there is at least one case where it happens
|
|
80
93
|
// a file with only import './whatever.js' inside
|
|
81
|
-
|
|
82
|
-
|
|
94
|
+
addSource({
|
|
95
|
+
url: originalFileUrl,
|
|
96
|
+
content: originalFileContent,
|
|
97
|
+
})
|
|
83
98
|
} else {
|
|
84
99
|
map.sources.forEach((source, index) => {
|
|
85
100
|
const sourceFileUrl = resolveSourceFile({
|
|
@@ -90,19 +105,25 @@ export const transformResultToCompilationResult = async (
|
|
|
90
105
|
projectDirectoryUrl,
|
|
91
106
|
})
|
|
92
107
|
if (sourceFileUrl) {
|
|
93
|
-
|
|
108
|
+
// In case the file comes from a remote url
|
|
109
|
+
// we prefer to consider remote url as the real source for this code
|
|
110
|
+
map.sources[index] =
|
|
111
|
+
jsenvRemoteDirectory &&
|
|
112
|
+
jsenvRemoteDirectory.isFileUrlForRemoteUrl(sourceFileUrl)
|
|
113
|
+
? jsenvRemoteDirectory.remoteUrlFromFileUrl(sourceFileUrl)
|
|
114
|
+
: urlToRelativeUrl(sourceFileUrl, sourcemapFileUrl)
|
|
94
115
|
sources[index] = sourceFileUrl
|
|
95
116
|
}
|
|
96
117
|
})
|
|
97
|
-
|
|
98
118
|
if (sources.length === 0) {
|
|
99
119
|
// happens when sourcemap is generated by webpack and looks like
|
|
100
120
|
// webpack://Package./src/file.js
|
|
101
121
|
// in that case we'll don't know how to find the source file
|
|
102
|
-
|
|
103
|
-
|
|
122
|
+
addSource({
|
|
123
|
+
url: originalFileUrl,
|
|
124
|
+
content: originalFileContent,
|
|
125
|
+
})
|
|
104
126
|
}
|
|
105
|
-
|
|
106
127
|
await Promise.all(
|
|
107
128
|
sources.map(async (sourceUrl, index) => {
|
|
108
129
|
const contentFromSourcemap = map.sourcesContent
|
|
@@ -121,7 +142,6 @@ export const transformResultToCompilationResult = async (
|
|
|
121
142
|
if (sourcemapExcludeSources) {
|
|
122
143
|
delete map.sourcesContent
|
|
123
144
|
}
|
|
124
|
-
|
|
125
145
|
// we don't need sourceRoot because our path are relative or absolute to the current location
|
|
126
146
|
// we could comment this line because it is not set by babel because not passed during transform
|
|
127
147
|
delete map.sourceRoot
|
|
@@ -139,22 +159,28 @@ export const transformResultToCompilationResult = async (
|
|
|
139
159
|
compiledFileUrl,
|
|
140
160
|
)
|
|
141
161
|
output = setSourceMappingUrl(output, sourcemapFileRelativePathForModule)
|
|
142
|
-
|
|
143
|
-
|
|
162
|
+
addAsset({
|
|
163
|
+
url: sourcemapFileUrl,
|
|
164
|
+
content: stringifyMap(map),
|
|
165
|
+
})
|
|
144
166
|
}
|
|
145
167
|
} else {
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
addSource({
|
|
169
|
+
url: originalFileUrl,
|
|
170
|
+
content: originalFileContent,
|
|
171
|
+
})
|
|
148
172
|
}
|
|
149
173
|
|
|
150
174
|
const { coverage } = metadata
|
|
151
175
|
if (coverage) {
|
|
152
|
-
const coverageAssetFileUrl =
|
|
176
|
+
const coverageAssetFileUrl = generateCompilationAssetUrl(
|
|
153
177
|
compiledFileUrl,
|
|
154
178
|
"coverage.json",
|
|
155
179
|
)
|
|
156
|
-
|
|
157
|
-
|
|
180
|
+
addAsset({
|
|
181
|
+
url: coverageAssetFileUrl,
|
|
182
|
+
content: stringifyCoverage(coverage),
|
|
183
|
+
})
|
|
158
184
|
}
|
|
159
185
|
|
|
160
186
|
const { dependencies = [] } = metadata
|
|
@@ -179,18 +205,15 @@ const resolveSourceFile = ({
|
|
|
179
205
|
projectDirectoryUrl,
|
|
180
206
|
}) => {
|
|
181
207
|
const sourceFileUrl = resolveSourceUrl({ source, sourcemapFileUrl })
|
|
182
|
-
|
|
183
|
-
if (!sourceFileUrl.startsWith(projectDirectoryUrl)) {
|
|
208
|
+
if (!urlIsInsideOf(sourceFileUrl, projectDirectoryUrl)) {
|
|
184
209
|
// do not track dependency outside project
|
|
185
210
|
// it means cache stays valid for those external sources
|
|
186
211
|
return null
|
|
187
212
|
}
|
|
188
|
-
|
|
189
213
|
const fileFound = testFilePresence(sourceFileUrl)
|
|
190
214
|
if (fileFound) {
|
|
191
215
|
return sourceFileUrl
|
|
192
216
|
}
|
|
193
|
-
|
|
194
217
|
// prefer original source file
|
|
195
218
|
const relativeUrl = urlToRelativeUrl(sourceFileUrl, compiledFileUrl)
|
|
196
219
|
const originalSourceUrl = resolveUrl(relativeUrl, originalFileUrl)
|
|
@@ -211,7 +234,6 @@ const resolveSourceUrl = ({ source, sourcemapFileUrl }) => {
|
|
|
211
234
|
)
|
|
212
235
|
return ensureWindowsDriveLetter(url, sourcemapFileUrl)
|
|
213
236
|
}
|
|
214
|
-
|
|
215
237
|
return resolveUrl(source, sourcemapFileUrl)
|
|
216
238
|
}
|
|
217
239
|
|
|
@@ -51,6 +51,7 @@ export const executePlan = async (
|
|
|
51
51
|
compileServerCanWriteOnFilesystem,
|
|
52
52
|
babelPluginMap,
|
|
53
53
|
babelConfigFileUrl,
|
|
54
|
+
preservedUrls,
|
|
54
55
|
workers,
|
|
55
56
|
serviceWorkers,
|
|
56
57
|
importMapInWebWorkers,
|
|
@@ -126,6 +127,7 @@ export const executePlan = async (
|
|
|
126
127
|
keepProcessAlive: true, // to be sure it stays alive
|
|
127
128
|
babelPluginMap,
|
|
128
129
|
babelConfigFileUrl,
|
|
130
|
+
preservedUrls,
|
|
129
131
|
workers,
|
|
130
132
|
serviceWorkers,
|
|
131
133
|
importMapInWebWorkers,
|
package/src/internal/fetchUrl.js
CHANGED
|
@@ -13,9 +13,9 @@ export const fetchUrl = async (
|
|
|
13
13
|
ignoreHttpsError,
|
|
14
14
|
...rest,
|
|
15
15
|
})
|
|
16
|
-
|
|
17
|
-
return {
|
|
16
|
+
const responseObject = {
|
|
18
17
|
url: response.url,
|
|
18
|
+
type: "default",
|
|
19
19
|
status: response.status,
|
|
20
20
|
statusText: response.statusText,
|
|
21
21
|
headers: headersToObject(response.headers),
|
|
@@ -24,4 +24,5 @@ export const fetchUrl = async (
|
|
|
24
24
|
blob: response.blob.bind(response),
|
|
25
25
|
arrayBuffer: response.arrayBuffer.bind(response),
|
|
26
26
|
}
|
|
27
|
+
return responseObject
|
|
27
28
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import crypto from "node:crypto"
|
|
2
|
+
|
|
3
|
+
export const isSupportedAlgorithm = (algo) => {
|
|
4
|
+
return SUPPORTED_ALGORITHMS.includes(algo)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// https://www.w3.org/TR/SRI/#priority
|
|
8
|
+
export const getPrioritizedHashFunction = (firstAlgo, secondAlgo) => {
|
|
9
|
+
const firstIndex = SUPPORTED_ALGORITHMS.indexOf(firstAlgo)
|
|
10
|
+
const secondIndex = SUPPORTED_ALGORITHMS.indexOf(secondAlgo)
|
|
11
|
+
if (firstIndex === secondIndex) {
|
|
12
|
+
return ""
|
|
13
|
+
}
|
|
14
|
+
if (firstIndex < secondIndex) {
|
|
15
|
+
return secondAlgo
|
|
16
|
+
}
|
|
17
|
+
return firstAlgo
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const applyAlgoToRepresentationData = (algo, data) => {
|
|
21
|
+
const base64Value = crypto.createHash(algo).update(data).digest("base64")
|
|
22
|
+
return base64Value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// keep this ordered by collision resistance as it is also used by "getPrioritizedHashFunction"
|
|
26
|
+
const SUPPORTED_ALGORITHMS = ["sha256", "sha384", "sha512"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isSupportedAlgorithm } from "./integrity_algorithms.js"
|
|
2
|
+
|
|
3
|
+
// see https://w3c.github.io/webappsec-subresource-integrity/#parse-metadata
|
|
4
|
+
export const parseIntegrity = (string) => {
|
|
5
|
+
const integrityMetadata = {}
|
|
6
|
+
string
|
|
7
|
+
.trim()
|
|
8
|
+
.split(/\s+/)
|
|
9
|
+
.forEach((token) => {
|
|
10
|
+
const { isValid, algo, base64Value, optionExpression } =
|
|
11
|
+
parseAsHashWithOptions(token)
|
|
12
|
+
if (!isValid) {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
if (!isSupportedAlgorithm(algo)) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
const metadataList = integrityMetadata[algo]
|
|
19
|
+
const metadata = { base64Value, optionExpression }
|
|
20
|
+
integrityMetadata[algo] = metadataList
|
|
21
|
+
? [...metadataList, metadata]
|
|
22
|
+
: [metadata]
|
|
23
|
+
})
|
|
24
|
+
return integrityMetadata
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// see https://w3c.github.io/webappsec-subresource-integrity/#the-integrity-attribute
|
|
28
|
+
const parseAsHashWithOptions = (token) => {
|
|
29
|
+
const dashIndex = token.indexOf("-")
|
|
30
|
+
if (dashIndex === -1) {
|
|
31
|
+
return { isValid: false }
|
|
32
|
+
}
|
|
33
|
+
const beforeDash = token.slice(0, dashIndex)
|
|
34
|
+
const afterDash = token.slice(dashIndex + 1)
|
|
35
|
+
const questionIndex = afterDash.indexOf("?")
|
|
36
|
+
const algo = beforeDash
|
|
37
|
+
if (questionIndex === -1) {
|
|
38
|
+
const base64Value = afterDash
|
|
39
|
+
const isValid = BASE64_REGEX.test(afterDash)
|
|
40
|
+
return { isValid, algo, base64Value }
|
|
41
|
+
}
|
|
42
|
+
const base64Value = afterDash.slice(0, questionIndex)
|
|
43
|
+
const optionExpression = afterDash.slice(questionIndex + 1)
|
|
44
|
+
const isValid =
|
|
45
|
+
BASE64_REGEX.test(afterDash) && VCHAR_REGEX.test(optionExpression)
|
|
46
|
+
return { isValid, algo, base64Value, optionExpression }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const BASE64_REGEX = /^[A-Za-z0-9+\/=+]+$/
|
|
50
|
+
const VCHAR_REGEX = /^[\x21-\x7E]+$/
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { parseIntegrity } from "./integrity_parsing.js"
|
|
2
|
+
import {
|
|
3
|
+
getPrioritizedHashFunction,
|
|
4
|
+
applyAlgoToRepresentationData,
|
|
5
|
+
} from "./integrity_algorithms.js"
|
|
6
|
+
|
|
7
|
+
export const updateIntegrity = (integrity, representationData) => {
|
|
8
|
+
const integrityMetadata = parseIntegrity(integrity)
|
|
9
|
+
const algos = Object.keys(integrityMetadata)
|
|
10
|
+
if (algos.length === 0) {
|
|
11
|
+
return ""
|
|
12
|
+
}
|
|
13
|
+
let strongestAlgo = algos[0]
|
|
14
|
+
algos.slice(1).forEach((algoCandidate) => {
|
|
15
|
+
strongestAlgo =
|
|
16
|
+
getPrioritizedHashFunction(strongestAlgo, algoCandidate) || strongestAlgo
|
|
17
|
+
})
|
|
18
|
+
const base64Value = applyAlgoToRepresentationData(
|
|
19
|
+
strongestAlgo,
|
|
20
|
+
representationData,
|
|
21
|
+
)
|
|
22
|
+
return `${strongestAlgo}-${base64Value}`
|
|
23
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parseIntegrity } from "./integrity_parsing.js"
|
|
2
|
+
import {
|
|
3
|
+
getPrioritizedHashFunction,
|
|
4
|
+
applyAlgoToRepresentationData,
|
|
5
|
+
} from "./integrity_algorithms.js"
|
|
6
|
+
|
|
7
|
+
// https://www.w3.org/TR/SRI/#does-response-match-metadatalist
|
|
8
|
+
export const validateResponseIntegrity = (
|
|
9
|
+
{ url, type, dataRepresentation },
|
|
10
|
+
integrity,
|
|
11
|
+
) => {
|
|
12
|
+
if (!isResponseEligibleForIntegrityValidation({ type })) {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
const integrityMetadata = parseIntegrity(integrity)
|
|
16
|
+
const algos = Object.keys(integrityMetadata)
|
|
17
|
+
if (algos.length === 0) {
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
let strongestAlgo = algos[0]
|
|
21
|
+
algos.slice(1).forEach((algoCandidate) => {
|
|
22
|
+
strongestAlgo =
|
|
23
|
+
getPrioritizedHashFunction(strongestAlgo, algoCandidate) || strongestAlgo
|
|
24
|
+
})
|
|
25
|
+
const metadataList = integrityMetadata[strongestAlgo]
|
|
26
|
+
const actualBase64Value = applyAlgoToRepresentationData(
|
|
27
|
+
strongestAlgo,
|
|
28
|
+
dataRepresentation,
|
|
29
|
+
)
|
|
30
|
+
const acceptedBase64Values = metadataList.map(
|
|
31
|
+
(metadata) => metadata.base64Value,
|
|
32
|
+
)
|
|
33
|
+
const someIsMatching = acceptedBase64Values.includes(actualBase64Value)
|
|
34
|
+
if (someIsMatching) {
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
const error = new Error(
|
|
38
|
+
`Integrity validation failed for ressource "${url}". The integrity found for this ressource is "${strongestAlgo}-${actualBase64Value}"`,
|
|
39
|
+
)
|
|
40
|
+
error.code = "EINTEGRITY"
|
|
41
|
+
error.algorithm = strongestAlgo
|
|
42
|
+
error.found = actualBase64Value
|
|
43
|
+
throw error
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// https://www.w3.org/TR/SRI/#is-response-eligible-for-integrity-validation
|
|
47
|
+
const isResponseEligibleForIntegrityValidation = (response) => {
|
|
48
|
+
return ["basic", "cors", "default"].includes(response.type)
|
|
49
|
+
}
|