@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
|
@@ -5,6 +5,7 @@ import { fetchUrl as jsenvFetchUrl } from "@jsenv/core/src/internal/fetchUrl.js"
|
|
|
5
5
|
import { validateResponse } from "@jsenv/core/src/internal/response_validation.js"
|
|
6
6
|
|
|
7
7
|
export const createUrlFetcher = ({
|
|
8
|
+
jsenvRemoteDirectory,
|
|
8
9
|
asOriginalUrl,
|
|
9
10
|
asProjectUrl,
|
|
10
11
|
applyUrlMappings,
|
|
@@ -13,18 +14,28 @@ export const createUrlFetcher = ({
|
|
|
13
14
|
}) => {
|
|
14
15
|
const urlRedirectionMap = {}
|
|
15
16
|
|
|
16
|
-
const fetchUrl = async (
|
|
17
|
+
const fetchUrl = async (
|
|
18
|
+
url,
|
|
19
|
+
{ signal, urlTrace, contentTypeExpected, crossorigin },
|
|
20
|
+
) => {
|
|
17
21
|
const urlToFetch = applyUrlMappings(url)
|
|
18
|
-
|
|
19
22
|
const response = await jsenvFetchUrl(urlToFetch, {
|
|
20
23
|
signal,
|
|
21
24
|
ignoreHttpsError: true,
|
|
25
|
+
credentials:
|
|
26
|
+
crossorigin === "anonymous" || crossorigin === ""
|
|
27
|
+
? "same-origin"
|
|
28
|
+
: crossorigin === "use-credentials"
|
|
29
|
+
? "include"
|
|
30
|
+
: undefined,
|
|
22
31
|
})
|
|
23
32
|
const responseUrl = response.url
|
|
24
|
-
|
|
33
|
+
const originalUrl =
|
|
34
|
+
asOriginalUrl(responseUrl) || asProjectUrl(responseUrl) || responseUrl
|
|
25
35
|
const responseValidity = await validateResponse(response, {
|
|
26
|
-
originalUrl:
|
|
27
|
-
|
|
36
|
+
originalUrl: jsenvRemoteDirectory.isFileUrlForRemoteUrl(originalUrl)
|
|
37
|
+
? jsenvRemoteDirectory.remoteUrlFromFileUrl(originalUrl)
|
|
38
|
+
: originalUrl,
|
|
28
39
|
urlTrace,
|
|
29
40
|
contentTypeExpected,
|
|
30
41
|
})
|
|
@@ -56,11 +67,9 @@ export const createUrlFetcher = ({
|
|
|
56
67
|
beforeThrowingResponseValidationError(responseValidationError)
|
|
57
68
|
throw responseValidationError
|
|
58
69
|
}
|
|
59
|
-
|
|
60
70
|
if (url !== responseUrl) {
|
|
61
71
|
urlRedirectionMap[url] = responseUrl
|
|
62
72
|
}
|
|
63
|
-
|
|
64
73
|
return response
|
|
65
74
|
}
|
|
66
75
|
|
|
@@ -8,7 +8,6 @@ export const createUrlLoader = ({
|
|
|
8
8
|
allowJson,
|
|
9
9
|
urlImporterMap,
|
|
10
10
|
|
|
11
|
-
asServerUrl,
|
|
12
11
|
asProjectUrl,
|
|
13
12
|
asOriginalUrl,
|
|
14
13
|
|
|
@@ -16,15 +15,12 @@ export const createUrlLoader = ({
|
|
|
16
15
|
}) => {
|
|
17
16
|
const urlResponseBodyMap = {}
|
|
18
17
|
|
|
19
|
-
const loadUrl = async (
|
|
20
|
-
let url = asServerUrl(rollupUrl)
|
|
21
|
-
|
|
18
|
+
const loadUrl = async (url, { signal, logger }) => {
|
|
22
19
|
const customLoader = urlCustomLoaders[url]
|
|
23
20
|
if (customLoader) {
|
|
24
21
|
const result = await customLoader()
|
|
25
22
|
return result
|
|
26
23
|
}
|
|
27
|
-
|
|
28
24
|
const response = await urlFetcher.fetchUrl(url, {
|
|
29
25
|
signal,
|
|
30
26
|
contentTypeExpected: [
|
|
@@ -1,177 +1,4 @@
|
|
|
1
1
|
import { createHash } from "crypto"
|
|
2
|
-
import {
|
|
3
|
-
urlToParentUrl,
|
|
4
|
-
urlToBasename,
|
|
5
|
-
urlToExtension,
|
|
6
|
-
} from "@jsenv/filesystem"
|
|
7
|
-
|
|
8
|
-
export const createUrlVersioner = ({
|
|
9
|
-
entryPointUrls,
|
|
10
|
-
asOriginalUrl,
|
|
11
|
-
lineBreakNormalization,
|
|
12
|
-
}) => {
|
|
13
|
-
const availableNameGenerator = createAvailableNameGenerator()
|
|
14
|
-
|
|
15
|
-
const computeBuildRelativeUrl = (ressource, precomputation) => {
|
|
16
|
-
const pattern = getFilenamePattern({
|
|
17
|
-
ressource,
|
|
18
|
-
entryPointUrls,
|
|
19
|
-
asOriginalUrl,
|
|
20
|
-
precomputeBuildRelativeUrl,
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
const buildRelativeUrl = generateBuildRelativeUrl(
|
|
24
|
-
ressource.url,
|
|
25
|
-
ressource.bufferAfterBuild,
|
|
26
|
-
{
|
|
27
|
-
pattern,
|
|
28
|
-
getName: precomputation
|
|
29
|
-
? () => urlToBasename(ressource.url)
|
|
30
|
-
: () =>
|
|
31
|
-
availableNameGenerator.getAvailableNameForPattern(
|
|
32
|
-
urlToBasename(ressource.url),
|
|
33
|
-
pattern,
|
|
34
|
-
),
|
|
35
|
-
contentType: ressource.contentType,
|
|
36
|
-
lineBreakNormalization,
|
|
37
|
-
},
|
|
38
|
-
)
|
|
39
|
-
return buildRelativeUrl
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const precomputeBuildRelativeUrl = (ressource, bufferAfterBuild = "") => {
|
|
43
|
-
if (ressource.buildRelativeUrl) {
|
|
44
|
-
return ressource.buildRelativeUrl
|
|
45
|
-
}
|
|
46
|
-
if (ressource.precomputedBuildRelativeUrl) {
|
|
47
|
-
return ressource.precomputedBuildRelativeUrl
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
ressource.bufferAfterBuild = bufferAfterBuild
|
|
51
|
-
const precomputedBuildRelativeUrl = computeBuildRelativeUrl(ressource, true)
|
|
52
|
-
ressource.bufferAfterBuild = undefined
|
|
53
|
-
ressource.precomputedBuildRelativeUrl = precomputedBuildRelativeUrl
|
|
54
|
-
return precomputedBuildRelativeUrl
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
computeBuildRelativeUrl,
|
|
59
|
-
precomputeBuildRelativeUrl,
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const createAvailableNameGenerator = () => {
|
|
64
|
-
const cache = {}
|
|
65
|
-
const getAvailableNameForPattern = (name, pattern) => {
|
|
66
|
-
let names = cache[pattern]
|
|
67
|
-
if (!names) {
|
|
68
|
-
names = []
|
|
69
|
-
cache[pattern] = names
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let nameCandidate = name
|
|
73
|
-
let integer = 1
|
|
74
|
-
// eslint-disable-next-line no-constant-condition
|
|
75
|
-
while (true) {
|
|
76
|
-
if (!names.includes(nameCandidate)) {
|
|
77
|
-
names.push(nameCandidate)
|
|
78
|
-
return nameCandidate
|
|
79
|
-
}
|
|
80
|
-
integer++
|
|
81
|
-
nameCandidate = `${name}${integer}`
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
getAvailableNameForPattern,
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const getFilenamePattern = ({
|
|
91
|
-
ressource,
|
|
92
|
-
entryPointUrls,
|
|
93
|
-
asOriginalUrl,
|
|
94
|
-
precomputeBuildRelativeUrl,
|
|
95
|
-
}) => {
|
|
96
|
-
if (ressource.isEntryPoint) {
|
|
97
|
-
const originalUrl = asOriginalUrl(ressource.url)
|
|
98
|
-
const entryPointBuildRelativeUrl = entryPointUrls[originalUrl]
|
|
99
|
-
return entryPointBuildRelativeUrl
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// inline ressource inherits location
|
|
103
|
-
if (ressource.isInline) {
|
|
104
|
-
// inherit parent directory location because it's an inline file
|
|
105
|
-
const importerBuildRelativeUrl = precomputeBuildRelativeUrl(
|
|
106
|
-
ressource.importer,
|
|
107
|
-
)
|
|
108
|
-
const name = urlToBasename(`file://${importerBuildRelativeUrl}`)
|
|
109
|
-
return `${name}_[hash][extname]`
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// importmap.
|
|
113
|
-
// we want to force the fileName for the importmap
|
|
114
|
-
// so that we don't have to rewrite its content
|
|
115
|
-
// the goal is to put the importmap at the same relative path
|
|
116
|
-
// than in the project
|
|
117
|
-
if (ressource.contentType === "application/importmap+json") {
|
|
118
|
-
const importmapRessourceUrl = ressource.url
|
|
119
|
-
const name = urlToBasename(importmapRessourceUrl)
|
|
120
|
-
return `${name}_[hash][extname]`
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// service worker:
|
|
124
|
-
// - MUST be at the root (same level than the HTML file)
|
|
125
|
-
// otherwise it might be registered for the scope "/assets/" instead of "/"
|
|
126
|
-
// - MUST not be versioned
|
|
127
|
-
if (ressource.isServiceWorker) {
|
|
128
|
-
return "[name][extname]"
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (ressource.isWorker) {
|
|
132
|
-
return "[name]_[hash][extname]"
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (ressource.isJsModule) {
|
|
136
|
-
return "[name]_[hash].js"
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return ressource.urlVersioningDisabled
|
|
140
|
-
? "assets/[name][extname]"
|
|
141
|
-
: "assets/[name]_[hash][extname]"
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const generateBuildRelativeUrl = (
|
|
145
|
-
fileUrl,
|
|
146
|
-
fileContent,
|
|
147
|
-
{
|
|
148
|
-
getName,
|
|
149
|
-
pattern,
|
|
150
|
-
contentType = "application/octet-stream",
|
|
151
|
-
lineBreakNormalization = false,
|
|
152
|
-
} = {},
|
|
153
|
-
) => {
|
|
154
|
-
pattern = typeof pattern === "function" ? pattern() : pattern
|
|
155
|
-
if (pattern.startsWith("./")) pattern = pattern.slice(2)
|
|
156
|
-
const buildRelativeUrl = renderFileNamePattern(pattern, {
|
|
157
|
-
dirname: () => urlToParentUrl(fileUrl),
|
|
158
|
-
name: getName,
|
|
159
|
-
hash: () =>
|
|
160
|
-
generateContentHash(fileContent, {
|
|
161
|
-
contentType,
|
|
162
|
-
lineBreakNormalization,
|
|
163
|
-
}),
|
|
164
|
-
extname: () => urlToExtension(fileUrl),
|
|
165
|
-
})
|
|
166
|
-
return buildRelativeUrl
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const renderFileNamePattern = (pattern, replacements) => {
|
|
170
|
-
return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
|
|
171
|
-
const replacement = replacements[type]()
|
|
172
|
-
return replacement
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
2
|
|
|
176
3
|
// https://github.com/rollup/rollup/blob/19e50af3099c2f627451a45a84e2fa90d20246d5/src/utils/FileEmitter.ts#L47
|
|
177
4
|
export const generateContentHash = (
|
|
@@ -2,21 +2,17 @@ import { babelPluginImportVisitor } from "./babel_plugin_import_visitor.js"
|
|
|
2
2
|
|
|
3
3
|
export const babelPluginImportMetadata = (babel) => {
|
|
4
4
|
return {
|
|
5
|
-
...babelPluginImportVisitor(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Here there is no strong need to throw because keeping the source code intact
|
|
10
|
-
// will throw an error when browser will execute the code
|
|
11
|
-
({ state, specifierPath }) => {
|
|
5
|
+
...babelPluginImportVisitor(babel, ({ state, specifierPath }) => {
|
|
6
|
+
const specifierNode = specifierPath.node
|
|
7
|
+
if (specifierNode.type === "StringLiteral") {
|
|
8
|
+
const specifier = specifierNode.value
|
|
12
9
|
const { metadata } = state.file
|
|
13
|
-
|
|
14
10
|
metadata.dependencies = [
|
|
15
11
|
...(metadata.dependencies ? metadata.dependencies : []),
|
|
16
|
-
|
|
12
|
+
specifier,
|
|
17
13
|
]
|
|
18
|
-
}
|
|
19
|
-
),
|
|
14
|
+
}
|
|
15
|
+
}),
|
|
20
16
|
name: "import-metadata",
|
|
21
17
|
}
|
|
22
18
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { urlToRelativeUrl, fileSystemPathToUrl } from "@jsenv/filesystem"
|
|
2
|
+
|
|
3
|
+
import { babelPluginImportVisitor } from "./babel_plugin_import_visitor.js"
|
|
4
|
+
|
|
5
|
+
export const babelPluginProxyExternalImports = (
|
|
6
|
+
babel,
|
|
7
|
+
{ jsenvRemoteDirectory },
|
|
8
|
+
) => {
|
|
9
|
+
return {
|
|
10
|
+
...babelPluginImportVisitor(babel, ({ specifierPath, state }) => {
|
|
11
|
+
const specifierNode = specifierPath.node
|
|
12
|
+
if (specifierNode.type === "StringLiteral") {
|
|
13
|
+
const specifier = specifierNode.value
|
|
14
|
+
if (
|
|
15
|
+
jsenvRemoteDirectory.isRemoteUrl(specifier) &&
|
|
16
|
+
!jsenvRemoteDirectory.isPreservedUrl(specifier)
|
|
17
|
+
) {
|
|
18
|
+
const fileUrl = jsenvRemoteDirectory.fileUrlFromRemoteUrl(specifier)
|
|
19
|
+
const importerFileUrl = fileSystemPathToUrl(state.filename)
|
|
20
|
+
const urlRelativeToProject = urlToRelativeUrl(
|
|
21
|
+
fileUrl,
|
|
22
|
+
importerFileUrl,
|
|
23
|
+
)
|
|
24
|
+
const specifierProxy = `./${urlRelativeToProject}`
|
|
25
|
+
specifierPath.replaceWith(babel.types.stringLiteral(specifierProxy))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}),
|
|
29
|
+
name: "proxy-external-imports",
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { urlToFilename } from "@jsenv/filesystem"
|
|
1
|
+
import { urlToFilename, urlToOrigin, urlToPathname } from "@jsenv/filesystem"
|
|
2
2
|
|
|
3
3
|
export const urlIsCompilationAsset = (url) => {
|
|
4
4
|
const filename = urlToFilename(url)
|
|
@@ -13,8 +13,12 @@ export const urlIsCompilationAsset = (url) => {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export const getMetaJsonFileUrl = (compileFileUrl) =>
|
|
16
|
-
|
|
16
|
+
generateCompilationAssetUrl(compileFileUrl, "meta.json")
|
|
17
17
|
|
|
18
|
-
export const
|
|
19
|
-
|
|
18
|
+
export const generateCompilationAssetUrl = (compiledFileUrl, assetName) => {
|
|
19
|
+
// we want to remove eventual search params from url
|
|
20
|
+
const origin = urlToOrigin(compiledFileUrl)
|
|
21
|
+
const pathname = urlToPathname(compiledFileUrl)
|
|
22
|
+
const compilationAssetUrl = `${origin}${pathname}__asset__${assetName}`
|
|
23
|
+
return compilationAssetUrl
|
|
20
24
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { timeStart, timeFunction } from "@jsenv/server"
|
|
1
2
|
import { urlToFileSystemPath, readFile } from "@jsenv/filesystem"
|
|
2
3
|
import { createDetailedMessage } from "@jsenv/logger"
|
|
3
|
-
import { timeStart, timeFunction } from "@jsenv/server"
|
|
4
4
|
|
|
5
5
|
import { validateCache } from "./validateCache.js"
|
|
6
6
|
import { getMetaJsonFileUrl } from "./compile-asset.js"
|
|
@@ -14,6 +14,8 @@ export const getOrGenerateCompiledFile = async ({
|
|
|
14
14
|
projectDirectoryUrl,
|
|
15
15
|
originalFileUrl,
|
|
16
16
|
compiledFileUrl = originalFileUrl,
|
|
17
|
+
jsenvRemoteDirectory,
|
|
18
|
+
|
|
17
19
|
compileCacheStrategy,
|
|
18
20
|
compileCacheSourcesValidation,
|
|
19
21
|
compileCacheAssetsValidation,
|
|
@@ -61,8 +63,11 @@ export const getOrGenerateCompiledFile = async ({
|
|
|
61
63
|
const lockTiming = lockTimeEnd()
|
|
62
64
|
const { meta, compileResult, compileResultStatus, timing } =
|
|
63
65
|
await computeCompileReport({
|
|
66
|
+
projectDirectoryUrl,
|
|
64
67
|
originalFileUrl,
|
|
65
68
|
compiledFileUrl,
|
|
69
|
+
jsenvRemoteDirectory,
|
|
70
|
+
|
|
66
71
|
compile,
|
|
67
72
|
compileCacheStrategy,
|
|
68
73
|
compileCacheSourcesValidation,
|
|
@@ -89,14 +94,17 @@ export const getOrGenerateCompiledFile = async ({
|
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
const computeCompileReport = async ({
|
|
97
|
+
// projectDirectoryUrl,
|
|
98
|
+
logger,
|
|
92
99
|
originalFileUrl,
|
|
93
100
|
compiledFileUrl,
|
|
101
|
+
jsenvRemoteDirectory,
|
|
102
|
+
|
|
94
103
|
compile,
|
|
95
104
|
compileCacheStrategy,
|
|
96
105
|
compileCacheSourcesValidation,
|
|
97
106
|
compileCacheAssetsValidation,
|
|
98
107
|
request,
|
|
99
|
-
logger,
|
|
100
108
|
}) => {
|
|
101
109
|
const [readCacheTiming, cacheValidity] = await timeFunction(
|
|
102
110
|
"read cache",
|
|
@@ -128,10 +136,41 @@ const computeCompileReport = async ({
|
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
const metaIsValid = cacheValidity.meta ? cacheValidity.meta.isValid : false
|
|
139
|
+
|
|
140
|
+
const fetchOriginalFile = async () => {
|
|
141
|
+
// The original file might be behind an http url.
|
|
142
|
+
// In that case jsenv try first to read file from filesystem
|
|
143
|
+
// in ".jsenv/.http/" directory. If not found, the url
|
|
144
|
+
// is fetched and file is written in that ".jsenv/.http/" directory.
|
|
145
|
+
// After that the only way to re-fetch this ressource is
|
|
146
|
+
// to delete the content of ".jsenv/.http/"
|
|
147
|
+
try {
|
|
148
|
+
const code = await readFile(originalFileUrl)
|
|
149
|
+
return { code }
|
|
150
|
+
} catch (e) {
|
|
151
|
+
// when file is not found and the file is referenced with an http url
|
|
152
|
+
if (
|
|
153
|
+
e &&
|
|
154
|
+
e.code === "ENOENT" &&
|
|
155
|
+
jsenvRemoteDirectory.isFileUrlForRemoteUrl(originalFileUrl)
|
|
156
|
+
) {
|
|
157
|
+
const responseBodyAsBuffer =
|
|
158
|
+
await jsenvRemoteDirectory.loadFileUrlFromRemote(
|
|
159
|
+
originalFileUrl,
|
|
160
|
+
request,
|
|
161
|
+
)
|
|
162
|
+
const code = String(responseBodyAsBuffer)
|
|
163
|
+
return { code }
|
|
164
|
+
}
|
|
165
|
+
throw e
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const { code } = await fetchOriginalFile()
|
|
131
169
|
const [compileTiming, compileResult] = await timeFunction("compile", () =>
|
|
132
170
|
callCompile({
|
|
133
171
|
logger,
|
|
134
172
|
originalFileUrl,
|
|
173
|
+
code,
|
|
135
174
|
compile,
|
|
136
175
|
}),
|
|
137
176
|
)
|
|
@@ -169,12 +208,9 @@ const computeCompileReport = async ({
|
|
|
169
208
|
}
|
|
170
209
|
}
|
|
171
210
|
|
|
172
|
-
const callCompile = async ({ logger, originalFileUrl, compile }) => {
|
|
211
|
+
const callCompile = async ({ logger, code, originalFileUrl, compile }) => {
|
|
173
212
|
logger.debug(`compile ${originalFileUrl}`)
|
|
174
|
-
|
|
175
|
-
const compileReturnValue = await compile({
|
|
176
|
-
code: await readFile(originalFileUrl),
|
|
177
|
-
})
|
|
213
|
+
const compileReturnValue = await compile({ code })
|
|
178
214
|
if (typeof compileReturnValue !== "object" || compileReturnValue === null) {
|
|
179
215
|
throw new TypeError(
|
|
180
216
|
`compile must return an object, got ${compileReturnValue}`,
|
|
@@ -200,7 +236,6 @@ const callCompile = async ({ logger, originalFileUrl, compile }) => {
|
|
|
200
236
|
`compile must return a compiledSource string, got ${compiledSource}`,
|
|
201
237
|
)
|
|
202
238
|
}
|
|
203
|
-
|
|
204
239
|
return {
|
|
205
240
|
contentType,
|
|
206
241
|
compiledSource,
|
|
@@ -30,14 +30,10 @@ export const updateMeta = async ({
|
|
|
30
30
|
const promises = []
|
|
31
31
|
if (isNew || isUpdated) {
|
|
32
32
|
// ensure source that does not leads to concrete files are not capable to invalidate the cache
|
|
33
|
-
const sourcesToRemove =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
sourcesToRemove.push(sourceFileUrl)
|
|
33
|
+
const sourcesToRemove = sources.filter((sourceFileUrl) => {
|
|
34
|
+
return (
|
|
35
|
+
sourceFileUrl.startsWith("file://") && !testFilePresence(sourceFileUrl)
|
|
36
|
+
)
|
|
41
37
|
})
|
|
42
38
|
const sourceNotFoundCount = sourcesToRemove.length
|
|
43
39
|
if (sourceNotFoundCount > 0) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
|
|
2
|
-
|
|
3
1
|
import { fileURLToPath } from "node:url"
|
|
4
2
|
import { readFileSync, statSync } from "node:fs"
|
|
3
|
+
import { resolveUrl, bufferToEtag } from "@jsenv/filesystem"
|
|
5
4
|
|
|
6
5
|
export const validateCache = async ({
|
|
7
6
|
compiledFileUrl,
|
|
@@ -14,10 +14,13 @@ export const compileFile = async ({
|
|
|
14
14
|
logger,
|
|
15
15
|
|
|
16
16
|
projectDirectoryUrl,
|
|
17
|
+
jsenvRemoteDirectory,
|
|
17
18
|
originalFileUrl,
|
|
18
19
|
compiledFileUrl,
|
|
20
|
+
|
|
19
21
|
projectFileRequestedCallback = () => {},
|
|
20
22
|
request,
|
|
23
|
+
responseHeaders = {},
|
|
21
24
|
pushResponse,
|
|
22
25
|
importmapInfos,
|
|
23
26
|
compile,
|
|
@@ -35,6 +38,11 @@ export const compileFile = async ({
|
|
|
35
38
|
)
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
projectFileRequestedCallback(
|
|
42
|
+
urlToRelativeUrl(originalFileUrl, projectDirectoryUrl),
|
|
43
|
+
request,
|
|
44
|
+
)
|
|
45
|
+
|
|
38
46
|
const clientCacheDisabled = request.headers["cache-control"] === "no-cache"
|
|
39
47
|
|
|
40
48
|
try {
|
|
@@ -44,6 +52,8 @@ export const compileFile = async ({
|
|
|
44
52
|
projectDirectoryUrl,
|
|
45
53
|
originalFileUrl,
|
|
46
54
|
compiledFileUrl,
|
|
55
|
+
jsenvRemoteDirectory,
|
|
56
|
+
|
|
47
57
|
request,
|
|
48
58
|
compileCacheStrategy,
|
|
49
59
|
compileCacheSourcesValidation,
|
|
@@ -78,13 +88,15 @@ export const compileFile = async ({
|
|
|
78
88
|
compileResult.compiledMtime = Date.now()
|
|
79
89
|
}
|
|
80
90
|
|
|
81
|
-
const {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const { contentType, compiledEtag, compiledMtime, compiledSource } =
|
|
92
|
+
compileResult
|
|
93
|
+
|
|
94
|
+
if (compileResult.responseHeaders) {
|
|
95
|
+
responseHeaders = {
|
|
96
|
+
...responseHeaders,
|
|
97
|
+
...compileResult.responseHeaders,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
88
100
|
|
|
89
101
|
if (compileResultStatus !== "cached" && compileCacheStrategy !== "none") {
|
|
90
102
|
// we MUST await updateMeta otherwise we might get 404
|
|
@@ -207,7 +219,6 @@ export const compileFile = async ({
|
|
|
207
219
|
}
|
|
208
220
|
// on the correspondig file
|
|
209
221
|
const json = JSON.stringify(data)
|
|
210
|
-
|
|
211
222
|
return {
|
|
212
223
|
status: 500,
|
|
213
224
|
statusText: "parse error",
|
|
@@ -219,13 +230,14 @@ export const compileFile = async ({
|
|
|
219
230
|
body: json,
|
|
220
231
|
}
|
|
221
232
|
}
|
|
222
|
-
|
|
233
|
+
if (error && error.asResponse) {
|
|
234
|
+
return error.asResponse()
|
|
235
|
+
}
|
|
223
236
|
if (error && error.statusText === "Unexpected directory operation") {
|
|
224
237
|
return {
|
|
225
238
|
status: 403,
|
|
226
239
|
}
|
|
227
240
|
}
|
|
228
|
-
|
|
229
241
|
return convertFileSystemErrorToResponseProperties(error)
|
|
230
242
|
}
|
|
231
243
|
}
|
|
@@ -495,35 +495,22 @@ export const createInlineScriptHash = (script) => {
|
|
|
495
495
|
return hash.digest("hex").slice(0, 8)
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
-
export const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const htmlNodeLocation = getHtmlNodeLocation(nodeCandidate)
|
|
510
|
-
if (!htmlNodeLocation) return false
|
|
511
|
-
return htmlNodeLocation.line === line
|
|
512
|
-
})
|
|
513
|
-
if (lineTaken) {
|
|
514
|
-
return `${line}.${column}`
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
return line
|
|
518
|
-
},
|
|
519
|
-
})
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
const renderNamePattern = (pattern, replacements) => {
|
|
523
|
-
return pattern.replace(/\[(\w+)\]/g, (_match, type) => {
|
|
524
|
-
const replacement = replacements[type]()
|
|
525
|
-
return replacement
|
|
498
|
+
export const getIdForInlineHtmlNode = (node, nodes) => {
|
|
499
|
+
const idAttribute = getHtmlNodeAttributeByName(node, "id")
|
|
500
|
+
if (idAttribute) {
|
|
501
|
+
return idAttribute.value
|
|
502
|
+
}
|
|
503
|
+
const { line, column } = getHtmlNodeLocation(node) || {}
|
|
504
|
+
const lineTaken = nodes.some((nodeCandidate) => {
|
|
505
|
+
if (nodeCandidate === node) return false
|
|
506
|
+
const htmlNodeLocation = getHtmlNodeLocation(nodeCandidate)
|
|
507
|
+
if (!htmlNodeLocation) return false
|
|
508
|
+
return htmlNodeLocation.line === line
|
|
526
509
|
})
|
|
510
|
+
if (lineTaken) {
|
|
511
|
+
return `${line}.${column}`
|
|
512
|
+
}
|
|
513
|
+
return line
|
|
527
514
|
}
|
|
528
515
|
|
|
529
516
|
const parseHtmlAsSingleElement = (html) => {
|