@jsenv/core 25.0.0 → 25.2.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 (60) hide show
  1. package/dist/browser_runtime/browser_runtime_91c5a3b8.js.map +2 -2
  2. package/dist/build_manifest.js +4 -4
  3. package/dist/compile_proxy/asset-manifest.json +2 -2
  4. package/dist/compile_proxy/{compile_proxy_e3b0c442_809f35f7.js.map → compile_proxy.html__inline__20_809f35f7.js.map} +0 -0
  5. package/dist/compile_proxy/{compile_proxy_7ad5faa6.html → compile_proxy_8dfaee51.html} +3 -4
  6. package/dist/redirector/asset-manifest.json +2 -2
  7. package/dist/redirector/{redirector_e3b0c442_e391410e.js.map → redirector.html__inline__15_e391410e.js.map} +0 -0
  8. package/dist/redirector/{redirector_eb92e8a7.html → redirector_3e9a97b9.html} +3 -4
  9. package/dist/toolbar/asset-manifest.json +1 -1
  10. package/dist/toolbar/{toolbar_f7b8a263.html → toolbar_361afb84.html} +2 -3
  11. package/dist/toolbar_injector/asset-manifest.json +2 -2
  12. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js → toolbar_injector_fac1e995.js} +2 -2
  13. package/dist/toolbar_injector/{toolbar_injector_49e4756e.js.map → toolbar_injector_fac1e995.js.map} +2 -2
  14. package/package.json +8 -8
  15. package/readme.md +61 -52
  16. package/src/buildProject.js +21 -13
  17. package/src/commonJsToJavaScriptModule.js +8 -7
  18. package/src/execute.js +2 -0
  19. package/src/executeTestPlan.js +14 -0
  20. package/src/internal/building/buildUsingRollup.js +4 -2
  21. package/src/internal/building/build_stats.js +3 -0
  22. package/src/internal/building/build_url_generator.js +153 -0
  23. package/src/internal/building/css/parseCssRessource.js +32 -26
  24. package/src/internal/building/html/parseHtmlRessource.js +109 -91
  25. package/src/internal/building/js/parseJsRessource.js +5 -13
  26. package/src/internal/building/parseRessource.js +3 -0
  27. package/src/internal/building/ressource_builder.js +72 -64
  28. package/src/internal/building/ressource_builder_util.js +17 -5
  29. package/src/internal/building/rollup_plugin_jsenv.js +262 -189
  30. package/src/internal/building/url_fetcher.js +16 -7
  31. package/src/internal/building/url_loader.js +1 -5
  32. package/src/internal/building/url_versioning.js +0 -173
  33. package/src/internal/compiling/babel_plugin_import_metadata.js +7 -11
  34. package/src/internal/compiling/babel_plugin_proxy_external_imports.js +31 -0
  35. package/src/internal/compiling/compile-directory/compile-asset.js +8 -4
  36. package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +43 -8
  37. package/src/internal/compiling/compile-directory/updateMeta.js +2 -8
  38. package/src/internal/compiling/compile-directory/validateCache.js +1 -2
  39. package/src/internal/compiling/compileFile.js +22 -10
  40. package/src/internal/compiling/compileHtml.js +15 -28
  41. package/src/internal/compiling/createCompiledFileService.js +22 -24
  42. package/src/internal/compiling/html_source_file_service.js +18 -19
  43. package/src/internal/compiling/js-compilation-service/jsenvTransform.js +14 -4
  44. package/src/internal/compiling/js-compilation-service/transformJs.js +9 -5
  45. package/src/internal/compiling/jsenvCompilerForHtml.js +534 -263
  46. package/src/internal/compiling/jsenvCompilerForJavaScript.js +15 -11
  47. package/src/internal/compiling/startCompileServer.js +83 -20
  48. package/src/internal/compiling/transformResultToCompilationResult.js +47 -25
  49. package/src/internal/executing/executePlan.js +2 -0
  50. package/src/internal/fetchUrl.js +3 -2
  51. package/src/internal/integrity/integrity_algorithms.js +26 -0
  52. package/src/internal/integrity/integrity_parsing.js +50 -0
  53. package/src/internal/integrity/integrity_update.js +23 -0
  54. package/src/internal/integrity/integrity_validation.js +49 -0
  55. package/src/internal/jsenvCoreDirectoryUrl.js +2 -0
  56. package/src/internal/jsenv_remote_directory.js +156 -0
  57. package/src/internal/origin_directory_converter.js +62 -0
  58. package/src/internal/response_validation.js +11 -24
  59. package/src/internal/sourceMappingURLUtils.js +10 -0
  60. 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 (url, { signal, urlTrace, contentTypeExpected }) => {
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
- asOriginalUrl(responseUrl) || asProjectUrl(responseUrl) || responseUrl,
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 (rollupUrl, { signal, logger }) => {
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
- cache[pattern] = []
69
- 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
- babel,
7
- // During the build we throw when for import call expression where
8
- // sepcifier or type is dynamic.
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
- specifierPath.node.value,
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
- generateCompiledFileAssetUrl(compileFileUrl, "meta.json")
16
+ generateCompilationAssetUrl(compileFileUrl, "meta.json")
17
17
 
18
- export const generateCompiledFileAssetUrl = (compiledFileUrl, assetName) => {
19
- return `${compiledFileUrl}__asset__${assetName}`
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,8 @@ 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
- sources.forEach((sourceFileUrl) => {
35
- const sourceFileExists = testFilePresence(sourceFileUrl)
36
- if (sourceFileExists) {
37
- return
38
- }
39
-
40
- sourcesToRemove.push(sourceFileUrl)
33
+ const sourcesToRemove = sources.filter((sourceFileUrl) => {
34
+ return !testFilePresence(sourceFileUrl)
41
35
  })
42
36
  const sourceNotFoundCount = sourcesToRemove.length
43
37
  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
- contentType,
83
- compiledEtag,
84
- compiledMtime,
85
- compiledSource,
86
- responseHeaders = {},
87
- } = compileResult
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 getUniqueNameForInlineHtmlNode = (node, nodes, pattern) => {
499
- return renderNamePattern(pattern, {
500
- id: () => {
501
- const idAttribute = getHtmlNodeAttributeByName(node, "id")
502
- if (idAttribute) {
503
- return idAttribute.value
504
- }
505
-
506
- const { line, column } = getHtmlNodeLocation(node) || {}
507
- const lineTaken = nodes.some((nodeCandidate) => {
508
- if (nodeCandidate === node) return false
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) => {