@jsenv/core 27.0.0-alpha.5 → 27.0.0-alpha.50

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 (146) hide show
  1. package/dist/event_source_client.js +545 -0
  2. package/dist/event_source_client.js.map +187 -0
  3. package/dist/html_supervisor_installer.js +1236 -0
  4. package/dist/html_supervisor_installer.js.map +337 -0
  5. package/dist/html_supervisor_setup.js +95 -0
  6. package/dist/html_supervisor_setup.js.map +57 -0
  7. package/dist/import_meta_hot.js +86 -0
  8. package/dist/import_meta_hot.js.map +42 -0
  9. package/main.js +8 -1
  10. package/package.json +22 -21
  11. package/readme.md +4 -12
  12. package/src/build/build.js +749 -437
  13. package/src/build/build_urls_generator.js +56 -22
  14. package/src/build/graph_utils.js +31 -0
  15. package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +33 -15
  16. package/src/build/inject_service_worker_urls.js +79 -0
  17. package/src/build/resync_ressource_hints.js +68 -0
  18. package/src/build/start_build_server.js +255 -0
  19. package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
  20. package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
  21. package/src/dev/start_dev_server.js +136 -30
  22. package/src/execute/execute.js +31 -6
  23. package/src/execute/run.js +19 -56
  24. package/src/execute/runtimes/browsers/from_playwright.js +201 -147
  25. package/src/execute/runtimes/node/controllable_file.mjs +26 -10
  26. package/src/execute/runtimes/node/node_execution_performance.js +67 -0
  27. package/src/execute/runtimes/node/node_process.js +280 -39
  28. package/src/jsenv_root_directory_url.js +1 -0
  29. package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
  30. package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +66 -4
  31. package/src/omega/compat/runtime_compat.js +50 -0
  32. package/src/omega/errors.js +51 -58
  33. package/src/omega/fetched_content_compliance.js +24 -0
  34. package/src/omega/file_url_converter.js +8 -50
  35. package/src/omega/kitchen.js +482 -292
  36. package/src/omega/omega_server.js +2 -3
  37. package/src/omega/server/file_service.js +38 -25
  38. package/src/omega/server/user_agent.js +4 -2
  39. package/src/omega/url_graph/url_graph_load.js +14 -7
  40. package/src/omega/url_graph/url_graph_report.js +17 -15
  41. package/src/omega/url_graph/url_info_transformations.js +26 -9
  42. package/src/omega/url_graph.js +91 -16
  43. package/src/omega/web_workers.js +42 -0
  44. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
  45. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +2 -2
  46. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
  47. package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
  48. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +46 -0
  49. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +204 -0
  50. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +27 -0
  51. package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
  52. package/src/plugins/bundling/css/bundle_css.js +21 -0
  53. package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
  54. package/src/{build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js → plugins/bundling/js_module/bundle_js_module.js} +150 -79
  55. package/src/plugins/bundling/jsenv_plugin_bundling.js +54 -0
  56. package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +54 -41
  57. package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
  58. package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +8 -5
  59. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
  60. package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
  61. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +242 -0
  62. package/src/plugins/html_supervisor/client/html_supervisor_setup.js +79 -0
  63. package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
  64. package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
  65. package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +83 -58
  66. package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
  67. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +4 -5
  68. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +3 -1
  69. package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +2 -2
  70. package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +105 -0
  71. package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +33 -8
  72. package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
  73. package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
  74. package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +39 -33
  75. package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +67 -0
  76. package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
  77. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
  78. package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +65 -44
  79. package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
  80. package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
  81. package/src/plugins/inline/jsenv_plugin_js_inline_content.js +296 -0
  82. package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
  83. package/src/plugins/minification/css/minify_css.js +9 -0
  84. package/src/plugins/minification/html/minify_html.js +15 -0
  85. package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
  86. package/src/plugins/minification/jsenv_plugin_minification.js +78 -0
  87. package/src/plugins/minification/json/minify_json.js +8 -0
  88. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +146 -0
  89. package/src/{omega → plugins}/plugin_controller.js +42 -11
  90. package/src/plugins/plugins.js +91 -0
  91. package/src/plugins/transpilation/as_js_classic/client/s.js +808 -0
  92. package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
  93. package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
  94. package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
  95. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +183 -0
  96. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +256 -0
  97. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +55 -0
  98. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
  99. package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
  100. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
  101. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +4 -22
  102. package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
  103. package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +37 -21
  104. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +30 -6
  105. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
  106. package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
  107. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
  108. package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
  109. package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
  110. package/src/plugins/transpilation/fetch_original_url_info.js +30 -0
  111. package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +181 -0
  112. package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +70 -0
  113. package/src/plugins/transpilation/jsenv_plugin_transpilation.js +44 -0
  114. package/src/plugins/url_analysis/css/css_urls.js +42 -0
  115. package/src/plugins/url_analysis/html/html_urls.js +273 -0
  116. package/src/plugins/url_analysis/js/js_urls.js +67 -0
  117. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +18 -0
  118. package/src/plugins/url_analysis/webmanifest/webmanifest_urls.js +17 -0
  119. package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
  120. package/src/{omega/core_plugins → plugins}/url_version/jsenv_plugin_url_version.js +12 -15
  121. package/src/test/execute_plan.js +30 -18
  122. package/src/test/execute_test_plan.js +23 -8
  123. package/src/test/logs_file_execution.js +8 -7
  124. package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
  125. package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
  126. package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +0 -374
  127. package/src/dev/plugins/autoreload/sse_service.js +0 -149
  128. package/src/execute/runtimes/node/controlled_process.js +0 -316
  129. package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
  130. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_installer.js +0 -168
  131. package/src/omega/core_plugins/html_supervisor/client/html_supervisor_setup.js +0 -77
  132. package/src/omega/core_plugins/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -98
  133. package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
  134. package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
  135. package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
  136. package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
  137. package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -210
  138. package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
  139. package/src/omega/core_plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +0 -77
  140. package/src/omega/core_plugins.js +0 -39
  141. package/src/omega/runtime_support/runtime_support.js +0 -20
  142. package/src/omega/url_mentions/css_url_mentions.js +0 -63
  143. package/src/omega/url_mentions/html_url_mentions.js +0 -185
  144. package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
  145. package/src/omega/url_mentions/parse_url_mentions.js +0 -37
  146. package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
@@ -4,47 +4,49 @@ import {
4
4
  isFileSystemPath,
5
5
  fileSystemPathToUrl,
6
6
  moveUrl,
7
- fileSystemRootUrl,
7
+ ensureWindowsDriveLetter,
8
8
  } from "@jsenv/filesystem"
9
+ import { createDetailedMessage } from "@jsenv/logger"
9
10
 
10
11
  import { stringifyUrlSite } from "@jsenv/utils/urls/url_trace.js"
12
+ import { CONTENT_TYPE } from "@jsenv/utils/content_type/content_type.js"
13
+ import { setUrlFilename } from "@jsenv/utils/urls/url_utils.js"
11
14
 
15
+ import { createPluginController } from "../plugins/plugin_controller.js"
12
16
  import { createUrlInfoTransformer } from "./url_graph/url_info_transformations.js"
13
- import { featuresCompatMap } from "./runtime_support/features_compatibility.js"
14
- import { isFeatureSupportedOnRuntimes } from "./runtime_support/runtime_support.js"
15
- import { fileUrlConverter } from "./file_url_converter.js"
16
- import { parseUrlMentions } from "./url_mentions/parse_url_mentions.js"
17
+ import { RUNTIME_COMPAT } from "./compat/runtime_compat.js"
18
+ import { defaultRuntimeCompat } from "./compat/default_runtime_compat.js"
17
19
  import {
18
- createResolveError,
19
- createLoadError,
20
- createParseError,
21
- createTransformError,
20
+ createResolveUrlError,
21
+ createFetchUrlContentError,
22
+ createTransformUrlContentError,
23
+ createFinalizeUrlContentError,
22
24
  } from "./errors.js"
23
- import { createPluginController } from "./plugin_controller.js"
25
+ import { assertFetchedContentCompliance } from "./fetched_content_compliance.js"
26
+ import { isWebWorkerEntryPointReference } from "./web_workers.js"
24
27
 
25
28
  export const createKitchen = ({
26
29
  signal,
27
30
  logger,
28
31
  rootDirectoryUrl,
29
32
  urlGraph,
33
+
30
34
  plugins,
31
35
  scenario,
32
-
33
36
  sourcemaps = {
34
37
  dev: "inline", // "programmatic" and "file" also allowed
35
38
  test: "inline",
36
39
  build: "none",
37
40
  }[scenario],
38
- // we don't need sources in sourcemap as long as the url in the
39
- // sourcemap uses file:/// (chrome will understand and read from filesystem)
40
- sourcemapsSources = false,
41
- loadInlineUrlInfos = (urlInfo) => {
42
- return {
43
- contentType: urlInfo.contentType,
44
- content: urlInfo.content,
45
- }
46
- },
47
-
41
+ sourcemapsSourcesContent = {
42
+ // during dev/test, chrome is able to find the sourcemap sources
43
+ // as long as they use file:// protocol in the sourcemap files
44
+ dev: false,
45
+ test: false,
46
+ build: true,
47
+ }[scenario],
48
+ sourcemapsRelativeSources,
49
+ runtimeCompat = defaultRuntimeCompat,
48
50
  writeOnFileSystem = true,
49
51
  }) => {
50
52
  const pluginController = createPluginController({
@@ -59,35 +61,89 @@ export const createKitchen = ({
59
61
  sourcemaps,
60
62
  urlGraph,
61
63
  scenario,
64
+ runtimeCompat,
65
+ isSupportedOnFutureClients: (feature) => {
66
+ return RUNTIME_COMPAT.isSupported(runtimeCompat, feature)
67
+ },
62
68
  }
63
69
  const createReference = ({
64
70
  data = {},
71
+ node,
65
72
  trace,
66
73
  parentUrl,
67
74
  type,
68
75
  subtype,
76
+ expectedContentType,
77
+ expectedType,
78
+ expectedSubtype,
79
+ filename,
80
+ integrity,
81
+ crossorigin,
69
82
  specifier,
83
+ specifierStart,
84
+ specifierEnd,
85
+ specifierLine,
86
+ specifierColumn,
87
+ baseUrl,
88
+ isOriginalPosition,
89
+ external = false,
70
90
  isInline = false,
91
+ injected = false,
92
+ isRessourceHint = false,
71
93
  content,
72
94
  contentType,
95
+ assert,
96
+ assertNode,
97
+ typePropertyNode,
73
98
  }) => {
99
+ if (typeof specifier !== "string") {
100
+ throw new TypeError(`"specifier" must be a string, got ${specifier}`)
101
+ }
74
102
  return {
103
+ original: null,
104
+ prev: null,
105
+ next: null,
75
106
  data,
107
+ node,
76
108
  trace,
77
109
  parentUrl,
78
110
  type,
79
111
  subtype,
112
+ expectedContentType,
113
+ expectedType,
114
+ expectedSubtype,
115
+ filename,
116
+ integrity,
117
+ crossorigin,
80
118
  specifier,
119
+ specifierStart,
120
+ specifierEnd,
121
+ specifierLine,
122
+ specifierColumn,
123
+ baseUrl,
124
+ isOriginalPosition,
125
+ external,
81
126
  isInline,
127
+ injected,
128
+ isRessourceHint,
82
129
  // for inline ressources the reference contains the content
83
130
  content,
84
131
  contentType,
132
+ timing: {},
133
+ assert,
134
+ assertNode,
135
+ typePropertyNode,
85
136
  }
86
137
  }
138
+ const mutateReference = (reference, newReference) => {
139
+ reference.next = newReference
140
+ newReference.prev = reference
141
+ newReference.original = reference.original || reference
142
+ }
87
143
  const resolveReference = (reference) => {
88
144
  try {
89
145
  const resolvedUrl = pluginController.callHooksUntil(
90
- "resolve",
146
+ "resolveUrl",
91
147
  reference,
92
148
  baseContext,
93
149
  )
@@ -95,15 +151,25 @@ export const createKitchen = ({
95
151
  throw new Error(`NO_RESOLVE`)
96
152
  }
97
153
  reference.url = resolvedUrl
154
+ if (reference.external) {
155
+ reference.generatedUrl = resolvedUrl
156
+ reference.generatedSpecifier = reference.specifier
157
+ return urlGraph.reuseOrCreateUrlInfo(reference.url)
158
+ }
98
159
  pluginController.callHooks(
99
- "normalize",
160
+ "normalizeUrl",
100
161
  reference,
101
162
  baseContext,
102
163
  (returnValue) => {
164
+ if (returnValue === reference.url) {
165
+ return
166
+ }
167
+ const previousReference = { ...reference }
103
168
  reference.url = returnValue
169
+ mutateReference(previousReference, reference)
104
170
  },
105
171
  )
106
- // force a last normalization regarding on url search params
172
+ // force a last normalization on url search params
107
173
  // some plugin use URLSearchParams to alter the url search params
108
174
  // which can result into "file:///file.css?css_module"
109
175
  // becoming "file:///file.css?css_module="
@@ -115,49 +181,59 @@ export const createKitchen = ({
115
181
  reference.url = reference.url.replace(/[=](?=&|$)/g, "")
116
182
  }
117
183
  const urlInfo = urlGraph.reuseOrCreateUrlInfo(reference.url)
118
- Object.assign(urlInfo.data, reference.data)
184
+ applyReferenceEffectsOnUrlInfo(reference, urlInfo, baseContext)
119
185
 
120
- // create a copy because .url will be mutated
121
- const referencedCopy = {
122
- ...reference,
123
- data: urlInfo.data,
124
- }
186
+ const referenceUrlObject = new URL(reference.url)
187
+ reference.searchParams = referenceUrlObject.searchParams
188
+ reference.generatedUrl = reference.url
189
+ // This hook must touch reference.generatedUrl, NOT reference.url
190
+ // And this is because this hook inject query params used to:
191
+ // - bypass browser cache (?v)
192
+ // - convey information (?hmr)
193
+ // But do not represent an other ressource, it is considered as
194
+ // the same ressource under the hood
125
195
  pluginController.callHooks(
126
- "transformReferencedUrl",
127
- referencedCopy,
196
+ "transformUrlSearchParams",
197
+ reference,
128
198
  baseContext,
129
199
  (returnValue) => {
130
- referencedCopy.url = returnValue
200
+ Object.keys(returnValue).forEach((key) => {
201
+ referenceUrlObject.searchParams.set(key, returnValue[key])
202
+ })
203
+ reference.generatedUrl = referenceUrlObject.href.replace(
204
+ /[=](?=&|$)/g,
205
+ "",
206
+ )
131
207
  },
132
208
  )
133
- reference.generatedUrl = referencedCopy.url
134
209
  const returnValue = pluginController.callHooksUntil(
135
- "formatReferencedUrl",
136
- referencedCopy,
210
+ "formatUrl",
211
+ reference,
137
212
  baseContext,
138
213
  )
139
214
  reference.generatedSpecifier = returnValue || reference.generatedUrl
140
- reference.generatedSpecifier = specifierFormat.encode(reference)
215
+ reference.generatedSpecifier = urlSpecifierFormat.encode(reference)
141
216
  return urlInfo
142
217
  } catch (error) {
143
- throw createResolveError({
218
+ throw createResolveUrlError({
144
219
  pluginController,
145
220
  reference,
146
221
  error,
147
222
  })
148
223
  }
149
224
  }
225
+ baseContext.resolveReference = resolveReference
150
226
  const urlInfoTransformer = createUrlInfoTransformer({
151
227
  logger,
152
228
  urlGraph,
153
229
  sourcemaps,
154
- sourcemapsSources,
230
+ sourcemapsSourcesContent,
231
+ sourcemapsRelativeSources,
155
232
  injectSourcemapPlaceholder: ({ urlInfo, specifier }) => {
156
233
  const sourcemapReference = createReference({
157
234
  trace: `sourcemap comment placeholder for ${urlInfo.url}`,
158
235
  type: "sourcemap_comment",
159
- subtype:
160
- urlInfo.contentType === "application/javascript" ? "js" : "css",
236
+ subtype: urlInfo.contentType === "text/javascript" ? "js" : "css",
161
237
  parentUrl: urlInfo.url,
162
238
  specifier,
163
239
  })
@@ -165,19 +241,27 @@ export const createKitchen = ({
165
241
  sourcemapUrlInfo.type = "sourcemap"
166
242
  return [sourcemapReference, sourcemapUrlInfo]
167
243
  },
168
- foundSourcemap: ({ urlInfo, line, column, type, specifier }) => {
244
+ foundSourcemap: ({
245
+ urlInfo,
246
+ type,
247
+ specifier,
248
+ specifierLine,
249
+ specifierColumn,
250
+ }) => {
169
251
  const sourcemapReference = createReference({
170
252
  trace: stringifyUrlSite(
171
253
  adjustUrlSite(urlInfo, {
172
254
  urlGraph,
173
255
  url: urlInfo.url,
174
- line,
175
- column,
256
+ line: specifierLine,
257
+ column: specifierColumn,
176
258
  }),
177
259
  ),
178
260
  type,
179
261
  parentUrl: urlInfo.url,
180
262
  specifier,
263
+ specifierLine,
264
+ specifierColumn,
181
265
  })
182
266
  const sourcemapUrlInfo = resolveReference(sourcemapReference)
183
267
  sourcemapUrlInfo.type = "sourcemap"
@@ -185,69 +269,77 @@ export const createKitchen = ({
185
269
  },
186
270
  })
187
271
 
188
- const isSupported = ({
189
- runtimeSupport,
190
- featureName,
191
- featureCompat = featuresCompatMap[featureName],
192
- }) => {
193
- return isFeatureSupportedOnRuntimes(runtimeSupport, featureCompat)
194
- }
195
-
196
- const load = async ({ reference, urlInfo, context }) => {
272
+ const fetchUrlContent = async ({ reference, urlInfo, context }) => {
273
+ if (reference.external) {
274
+ urlInfo.external = true
275
+ return
276
+ }
197
277
  try {
198
- const loadReturnValue = urlInfo.isInline
199
- ? loadInlineUrlInfos(urlInfo)
200
- : await pluginController.callAsyncHooksUntil("load", urlInfo, context)
201
- if (!loadReturnValue) {
202
- throw new Error("NO_LOAD")
278
+ const returnValue = await pluginController.callAsyncHooksUntil(
279
+ "fetchUrlContent",
280
+ urlInfo,
281
+ context,
282
+ )
283
+ if (!returnValue) {
284
+ logger.warn(
285
+ createDetailedMessage(
286
+ `no plugin has handled the url during "fetchUrlContent" hook -> consider url as external (ignore it)`,
287
+ {
288
+ "url": urlInfo.url,
289
+ "url reference trace": reference.trace,
290
+ },
291
+ ),
292
+ )
293
+ urlInfo.external = true
294
+ return
295
+ }
296
+ if (returnValue.external) {
297
+ urlInfo.external = true
298
+ return
203
299
  }
204
-
205
300
  const {
206
- contentType = "application/octet-stream",
207
- content, // can be a buffer (used for binary files) or a string
208
- sourcemap,
209
- // during build urls info are reused and load returns originalContent
210
- // that we want to keep
211
- originalContent = content,
212
301
  data,
213
- } = loadReturnValue
214
- Object.assign(urlInfo, {
215
- contentType,
302
+ type,
303
+ subtype,
304
+ contentType = "application/octet-stream",
216
305
  originalContent,
217
306
  content,
218
307
  sourcemap,
219
- })
308
+ filename,
309
+ } = returnValue
310
+ urlInfo.type =
311
+ type ||
312
+ reference.expectedType ||
313
+ inferUrlInfoType({
314
+ url: urlInfo.url,
315
+ contentType,
316
+ })
317
+ urlInfo.subtype =
318
+ subtype ||
319
+ reference.expectedSubtype ||
320
+ inferUrlInfoSubtype({
321
+ url: urlInfo.url,
322
+ type: urlInfo.type,
323
+ subtype: urlInfo.subtype,
324
+ })
325
+ urlInfo.contentType = contentType
326
+ // during build urls info are reused and load returns originalContent
327
+ urlInfo.originalContent =
328
+ originalContent === undefined ? content : originalContent
329
+ urlInfo.content = content
330
+ urlInfo.sourcemap = sourcemap
220
331
  if (data) {
221
332
  Object.assign(urlInfo.data, data)
222
333
  }
223
- if (!urlInfo.type) {
224
- const type = inferUrlInfoType(urlInfo)
225
- if (type === "js") {
226
- const urlObject = new URL(urlInfo.url)
227
- if (urlObject.searchParams.has("worker_type_classic")) {
228
- urlInfo.type = "js_classic"
229
- urlInfo.subtype = "worker"
230
- } else if (
231
- urlObject.searchParams.has("service_worker_type_classic")
232
- ) {
233
- urlInfo.type = "js_classic"
234
- urlInfo.subtype = "service_worker"
235
- } else if (urlObject.searchParams.has("js_classic")) {
236
- urlInfo.type = "js_classic"
237
- } else {
238
- urlInfo.type = "js_module"
239
- }
240
- if (urlObject.searchParams.has("worker")) {
241
- urlInfo.subtype = "worker"
242
- } else if (urlObject.searchParams.has("service_worker")) {
243
- urlInfo.subtype = "service_worker"
244
- }
245
- } else {
246
- urlInfo.type = type
247
- }
334
+ if (filename) {
335
+ urlInfo.filename = filename
248
336
  }
337
+ assertFetchedContentCompliance({
338
+ reference,
339
+ urlInfo,
340
+ })
249
341
  } catch (error) {
250
- throw createLoadError({
342
+ throw createFetchUrlContentError({
251
343
  pluginController,
252
344
  urlInfo,
253
345
  reference,
@@ -255,9 +347,8 @@ export const createKitchen = ({
255
347
  })
256
348
  }
257
349
  urlInfo.generatedUrl = determineFileUrlForOutDirectory({
258
- rootDirectoryUrl,
259
- outDirectoryUrl: context.outDirectoryUrl,
260
- url: urlInfo.url,
350
+ urlInfo,
351
+ context,
261
352
  })
262
353
  await urlInfoTransformer.initTransformations(urlInfo, context)
263
354
  }
@@ -266,34 +357,39 @@ export const createKitchen = ({
266
357
  reference,
267
358
  urlInfo,
268
359
  outDirectoryUrl,
269
- runtimeSupport,
360
+ // during dev/test clientRuntimeCompat is a single runtime
361
+ // during build clientRuntimeCompat is runtimeCompat
362
+ clientRuntimeCompat = runtimeCompat,
270
363
  cookDuringCook = cook,
271
364
  }) => {
365
+ baseContext.isSupportedOnCurrentClients = (feature) => {
366
+ return RUNTIME_COMPAT.isSupported(clientRuntimeCompat, feature)
367
+ }
272
368
  const context = {
273
369
  ...baseContext,
274
370
  reference,
275
371
  outDirectoryUrl,
276
- runtimeSupport,
277
- isSupportedOnRuntime: (featureName, featureCompat) => {
278
- return isSupported({ runtimeSupport, featureName, featureCompat })
279
- },
372
+ clientRuntimeCompat,
280
373
  cook: (params) => {
281
374
  return cookDuringCook({
282
375
  outDirectoryUrl,
283
- runtimeSupport,
376
+ clientRuntimeCompat,
284
377
  ...params,
285
378
  })
286
379
  },
287
- load: (params) => {
288
- return load({
380
+ fetchUrlContent: (params) => {
381
+ return fetchUrlContent({
289
382
  context,
290
383
  ...params,
291
384
  })
292
385
  },
293
386
  }
294
387
 
295
- // "load" hook
296
- await load({ reference, urlInfo, context })
388
+ // "fetchUrlContent" hook
389
+ await fetchUrlContent({ reference, urlInfo, context })
390
+ if (urlInfo.external) {
391
+ return
392
+ }
297
393
 
298
394
  // parsing
299
395
  const references = []
@@ -303,182 +399,155 @@ export const createKitchen = ({
303
399
  ...props,
304
400
  })
305
401
  references.push(reference)
306
- return [reference, resolveReference(reference)]
402
+ const referencedUrlInfo = resolveReference(reference)
403
+ return [reference, referencedUrlInfo]
307
404
  }
308
405
  const referenceUtils = {
309
- inject: ({ trace, ...rest }) => {
310
- if (trace === undefined) {
311
- const { prepareStackTrace } = Error
312
- Error.prepareStackTrace = (error, stack) => {
313
- Error.prepareStackTrace = prepareStackTrace
314
- return stack
315
- }
316
- const { stack } = new Error()
317
- const callerCallsite = stack[1]
318
- const fileName = callerCallsite.getFileName()
319
- trace = stringifyUrlSite({
320
- url:
321
- fileName && isFileSystemPath(fileName)
322
- ? fileSystemPathToUrl(fileName)
323
- : fileName,
324
- line: callerCallsite.getLineNumber(),
325
- column: callerCallsite.getColumnNumber(),
406
+ readGeneratedSpecifier: async (reference) => {
407
+ // "formatReferencedUrl" can be async BUT this is an exception
408
+ // for most cases it will be sync. We want to favor the sync signature to keep things simpler
409
+ // The only case where it needs to be async is when
410
+ // the specifier is a `data:*` url
411
+ // in this case we'll wait for the promise returned by
412
+ // "formatReferencedUrl"
413
+ if (reference.generatedSpecifier.then) {
414
+ return reference.generatedSpecifier.then((value) => {
415
+ reference.generatedSpecifier = value
416
+ return value
326
417
  })
327
418
  }
419
+ return reference.generatedSpecifier
420
+ },
421
+ found: ({ specifierLine, specifierColumn, ...rest }) => {
422
+ const trace = stringifyUrlSite(
423
+ adjustUrlSite(urlInfo, {
424
+ urlGraph,
425
+ url: urlInfo.url,
426
+ line: specifierLine,
427
+ column: specifierColumn,
428
+ }),
429
+ )
430
+ // console.log(trace)
328
431
  return addReference({
329
432
  trace,
433
+ specifierLine,
434
+ specifierColumn,
330
435
  ...rest,
331
436
  })
332
437
  },
333
- foundInline: ({
334
- type,
335
- isOriginal,
336
- line,
337
- column,
338
- specifier,
339
- contentType,
340
- content,
341
- }) => {
342
- const parentUrl = isOriginal ? urlInfo.url : urlInfo.generatedUrl
343
- const parentContent = isOriginal
438
+ foundInline: ({ isOriginalPosition, line, column, ...rest }) => {
439
+ const parentUrl = isOriginalPosition
440
+ ? urlInfo.url
441
+ : urlInfo.generatedUrl
442
+ const parentContent = isOriginalPosition
344
443
  ? urlInfo.originalContent
345
444
  : urlInfo.content
346
- const [inlineReference, inlineUrlInfo] = addReference({
445
+ return addReference({
347
446
  trace: stringifyUrlSite({
348
447
  url: parentUrl,
349
448
  content: parentContent,
350
449
  line,
351
450
  column,
352
451
  }),
353
- type,
354
- specifier,
355
- isInline: true,
356
- contentType,
357
- content,
358
- })
359
- inlineUrlInfo.isInline = true
360
- inlineUrlInfo.inlineUrlSite = {
361
- url: urlInfo.url,
362
- content: parentContent,
452
+ isOriginalPosition,
363
453
  line,
364
454
  column,
365
- }
366
- inlineUrlInfo.contentType = contentType
367
- inlineUrlInfo.originalContent = inlineUrlInfo.content = content
368
- return [inlineReference, inlineUrlInfo]
455
+ isInline: true,
456
+ ...rest,
457
+ })
369
458
  },
370
- updateSpecifier: (generatedSpecifier, newSpecifier, data) => {
371
- const index = references.findIndex(
372
- (ref) => ref.generatedSpecifier === generatedSpecifier,
373
- )
459
+ update: (currentReference, newReferenceParams) => {
460
+ const index = references.indexOf(currentReference)
374
461
  if (index === -1) {
375
- throw new Error(
376
- `Cannot find a reference for the following generatedSpecifier "${generatedSpecifier}"`,
377
- )
462
+ throw new Error(`reference do not exists`)
378
463
  }
379
- const referenceFound = references[index]
380
- const newReference = createReference({
381
- ...referenceFound,
382
- specifier: newSpecifier,
383
- data: {
384
- ...referenceFound.data,
385
- ...data,
386
- },
464
+ const previousReference = currentReference
465
+ const nextReference = createReference({
466
+ ...previousReference,
467
+ ...newReferenceParams,
387
468
  })
388
- references[index] = newReference
389
- newReference.data.originalReference = referenceFound
390
- const newUrlInfo = resolveReference(newReference)
391
- return [newReference, newUrlInfo]
469
+ references[index] = nextReference
470
+ mutateReference(previousReference, nextReference)
471
+ const newUrlInfo = resolveReference(nextReference)
472
+ const currentUrlInfo = context.urlGraph.getUrlInfo(currentReference.url)
473
+ if (
474
+ currentUrlInfo &&
475
+ currentUrlInfo !== newUrlInfo &&
476
+ currentUrlInfo.dependents.size === 0
477
+ ) {
478
+ context.urlGraph.deleteUrlInfo(currentReference.url)
479
+ }
480
+ return [nextReference, newUrlInfo]
392
481
  },
393
482
  becomesInline: (
394
483
  reference,
395
- { isOriginal, line, column, specifier, contentType, content },
484
+ {
485
+ isOriginalPosition,
486
+ specifier,
487
+ specifierLine,
488
+ specifierColumn,
489
+ contentType,
490
+ content,
491
+ },
396
492
  ) => {
397
- const parentUrl = isOriginal ? urlInfo.url : urlInfo.generatedUrl
398
- const parentContent = isOriginal
493
+ const parentUrl = isOriginalPosition
494
+ ? urlInfo.url
495
+ : urlInfo.generatedUrl
496
+ const parentContent = isOriginalPosition
399
497
  ? urlInfo.originalContent
400
498
  : urlInfo.content
401
- reference.trace = stringifyUrlSite({
402
- url: parentUrl,
403
- content: parentContent,
404
- line,
405
- column,
499
+ return referenceUtils.update(reference, {
500
+ trace: stringifyUrlSite({
501
+ url: parentUrl,
502
+ content: parentContent,
503
+ line: specifierLine,
504
+ column: specifierColumn,
505
+ }),
506
+ isOriginalPosition,
507
+ isInline: true,
508
+ specifier,
509
+ specifierLine,
510
+ specifierColumn,
511
+ contentType,
512
+ content,
406
513
  })
407
- reference.isInline = true
408
- reference.specifier = specifier
409
- reference.contentType = contentType
410
- reference.content = content
411
- const inlineUrlInfo = resolveReference(reference)
412
- inlineUrlInfo.isInline = true
413
- inlineUrlInfo.inlineUrlSite = {
414
- url: urlInfo.url,
415
- content: parentContent,
416
- line,
417
- column,
418
- }
419
- inlineUrlInfo.contentType = contentType
420
- inlineUrlInfo.content = content
421
- return reference
422
514
  },
423
- }
424
-
425
- let parseResult
426
- try {
427
- parseResult = await parseUrlMentions({
428
- type: urlInfo.type,
429
- url: urlInfo.data.sourceUrl || urlInfo.url,
430
- generatedUrl: urlInfo.generatedUrl,
431
- content: urlInfo.content,
432
- })
433
- } catch (error) {
434
- throw createParseError({
435
- reference,
436
- urlInfo,
437
- error,
438
- })
439
- }
440
- if (parseResult) {
441
- Object.assign(urlInfo.data, parseResult.data)
442
- const { urlMentions, replaceUrls } = parseResult
443
- for (const urlMention of urlMentions) {
444
- const [reference] = addReference({
445
- trace: stringifyUrlSite(
446
- adjustUrlSite(urlInfo, {
447
- urlGraph,
448
- url: urlInfo.url,
449
- line: urlMention.line,
450
- column: urlMention.column,
451
- }),
452
- ),
453
- type: urlMention.type,
454
- subtype: urlMention.subtype,
455
- specifier: urlMention.specifier,
456
- })
457
- urlMention.reference = reference
458
- }
459
- if (references.length) {
460
- // "formatReferencedUrl" can be async BUT this is an exception
461
- // for most cases it will be sync. We want to favor the sync signature to keep things simpler
462
- // The only case where it needs to be async is when
463
- // the specifier is a `data:*` url
464
- // in this case we'll wait for the promise returned by
465
- // "formatReferencedUrl"
466
- await Promise.all(
467
- references.map(async (reference) => {
468
- if (reference.generatedSpecifier.then) {
469
- const value = await reference.generatedSpecifier
470
- reference.generatedSpecifier = value
471
- }
472
- }),
473
- )
474
- const replaceReturnValue = await replaceUrls((urlMention) => {
475
- return urlMention.reference.generatedSpecifier
515
+ inject: ({ trace, ...rest }) => {
516
+ if (trace === undefined) {
517
+ const { prepareStackTrace } = Error
518
+ Error.prepareStackTrace = (error, stack) => {
519
+ Error.prepareStackTrace = prepareStackTrace
520
+ return stack
521
+ }
522
+ const { stack } = new Error()
523
+ const callerCallsite = stack[1]
524
+ const fileName = callerCallsite.getFileName()
525
+ trace = stringifyUrlSite({
526
+ url:
527
+ fileName && isFileSystemPath(fileName)
528
+ ? fileSystemPathToUrl(fileName)
529
+ : fileName,
530
+ line: callerCallsite.getLineNumber(),
531
+ column: callerCallsite.getColumnNumber(),
532
+ })
533
+ }
534
+ return addReference({
535
+ trace,
536
+ injected: true,
537
+ ...rest,
476
538
  })
477
- await urlInfoTransformer.applyIntermediateTransformations(
478
- urlInfo,
479
- replaceReturnValue,
539
+ },
540
+ findByGeneratedSpecifier: (generatedSpecifier) => {
541
+ const reference = references.find(
542
+ (ref) => ref.generatedSpecifier === generatedSpecifier,
480
543
  )
481
- }
544
+ if (!reference) {
545
+ throw new Error(
546
+ `No reference found using the following generatedSpecifier: "${generatedSpecifier}"`,
547
+ )
548
+ }
549
+ return reference
550
+ },
482
551
  }
483
552
 
484
553
  // "transform" hook
@@ -486,7 +555,7 @@ export const createKitchen = ({
486
555
  context.referenceUtils = referenceUtils
487
556
  try {
488
557
  await pluginController.callAsyncHooks(
489
- "transform",
558
+ "transformUrlContent",
490
559
  urlInfo,
491
560
  context,
492
561
  async (transformReturnValue) => {
@@ -497,7 +566,7 @@ export const createKitchen = ({
497
566
  },
498
567
  )
499
568
  } catch (error) {
500
- throw createTransformError({
569
+ throw createTransformUrlContentError({
501
570
  pluginController,
502
571
  reference,
503
572
  urlInfo,
@@ -509,15 +578,24 @@ export const createKitchen = ({
509
578
  urlGraph.updateReferences(urlInfo, references)
510
579
 
511
580
  // "finalize" hook
512
- const finalizeReturnValue = await pluginController.callHooksUntil(
513
- "finalize",
514
- urlInfo,
515
- context,
516
- )
517
- await urlInfoTransformer.applyFinalTransformations(
518
- urlInfo,
519
- finalizeReturnValue,
520
- )
581
+ try {
582
+ const finalizeReturnValue = await pluginController.callAsyncHooksUntil(
583
+ "finalizeUrlContent",
584
+ urlInfo,
585
+ context,
586
+ )
587
+ await urlInfoTransformer.applyFinalTransformations(
588
+ urlInfo,
589
+ finalizeReturnValue,
590
+ )
591
+ } catch (error) {
592
+ throw createFinalizeUrlContentError({
593
+ pluginController,
594
+ reference,
595
+ urlInfo,
596
+ error,
597
+ })
598
+ }
521
599
 
522
600
  // "cooked" hook
523
601
  pluginController.callHooks(
@@ -541,7 +619,7 @@ export const createKitchen = ({
541
619
  },
542
620
  )
543
621
  }
544
- const cook = async ({ urlInfo, outDirectoryUrl, ...rest }) => {
622
+ const cook = memoizeCook(async ({ urlInfo, outDirectoryUrl, ...rest }) => {
545
623
  outDirectoryUrl = outDirectoryUrl ? String(outDirectoryUrl) : undefined
546
624
 
547
625
  const writeFiles = ({ gotError }) => {
@@ -576,19 +654,98 @@ export const createKitchen = ({
576
654
  writeFiles({ gotError: true })
577
655
  throw e
578
656
  }
579
- }
657
+ })
580
658
 
581
659
  baseContext.cook = cook
582
660
 
661
+ const prepareEntryPoint = (params) => {
662
+ const entryReference = createReference(params)
663
+ const entryUrlInfo = resolveReference(entryReference)
664
+ // I should likely delete urlInfo.sourcemap
665
+ // otherwise it is reused when page is reloaded
666
+ return [entryReference, entryUrlInfo]
667
+ }
668
+
669
+ const injectReference = (params) => {
670
+ const ref = createReference(params)
671
+ const urlInfo = resolveReference(ref)
672
+ return [ref, urlInfo]
673
+ }
674
+
583
675
  return {
584
676
  pluginController,
585
677
  urlInfoTransformer,
586
678
  rootDirectoryUrl,
587
679
  jsenvDirectoryUrl,
588
- isSupported,
589
- createReference,
590
- resolveReference,
680
+ baseContext,
591
681
  cook,
682
+ prepareEntryPoint,
683
+ injectReference,
684
+ }
685
+ }
686
+
687
+ const memoizeCook = (cook) => {
688
+ const pendingDishes = new Map()
689
+ return async (params) => {
690
+ const { urlInfo } = params
691
+ const { url, modifiedTimestamp } = urlInfo
692
+ const pendingDish = pendingDishes.get(url)
693
+ if (pendingDish) {
694
+ if (!modifiedTimestamp) {
695
+ await pendingDish.promise
696
+ return
697
+ }
698
+ if (pendingDish.timestamp > modifiedTimestamp) {
699
+ await pendingDish.promise
700
+ return
701
+ }
702
+ pendingDishes.delete(url)
703
+ }
704
+ const timestamp = Date.now()
705
+ const promise = cook(params)
706
+ pendingDishes.set(url, {
707
+ timestamp,
708
+ promise,
709
+ })
710
+ try {
711
+ await promise
712
+ } finally {
713
+ pendingDishes.delete(url)
714
+ }
715
+ }
716
+ }
717
+
718
+ const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
719
+ Object.assign(urlInfo.data, reference.data)
720
+ Object.assign(urlInfo.timing, reference.timing)
721
+ if (reference.injected) {
722
+ urlInfo.data.injected = true
723
+ }
724
+ if (reference.filename) {
725
+ urlInfo.filename = reference.filename
726
+ }
727
+ if (reference.isInline) {
728
+ urlInfo.isInline = true
729
+ const parentUrlInfo = context.urlGraph.getUrlInfo(reference.parentUrl)
730
+ urlInfo.inlineUrlSite = {
731
+ url: parentUrlInfo.url,
732
+ content: reference.isOriginalPosition
733
+ ? parentUrlInfo.originalContent
734
+ : parentUrlInfo.content,
735
+ line: reference.specifierLine,
736
+ column: reference.specifierColumn,
737
+ }
738
+ urlInfo.contentType = reference.contentType
739
+ urlInfo.originalContent =
740
+ context === "build"
741
+ ? urlInfo.originalContent === undefined
742
+ ? reference.content
743
+ : urlInfo.originalContent
744
+ : reference.content
745
+ urlInfo.content = reference.content
746
+ }
747
+ if (isWebWorkerEntryPointReference(reference)) {
748
+ urlInfo.data.isWebWorkerEntryPoint = true
592
749
  }
593
750
  }
594
751
 
@@ -626,54 +783,86 @@ const adjustUrlSite = (urlInfo, { urlGraph, url, line, column }) => {
626
783
  )
627
784
  }
628
785
 
629
- const inferUrlInfoType = ({ contentType }) => {
786
+ const inferUrlInfoType = ({ url, contentType }) => {
630
787
  if (contentType === "text/html") {
631
788
  return "html"
632
789
  }
633
790
  if (contentType === "text/css") {
634
791
  return "css"
635
792
  }
636
- if (contentType === "application/javascript") {
637
- return "js"
638
- }
639
- if (contentType === "application/json") {
640
- return "json"
793
+ if (contentType === "text/javascript") {
794
+ const urlObject = new URL(url)
795
+ if (urlObject.searchParams.has("js_classic")) {
796
+ return "js_classic"
797
+ }
798
+ return "js_module"
641
799
  }
642
800
  if (contentType === "application/importmap+json") {
643
801
  return "importmap"
644
802
  }
803
+ if (contentType === "application/manifest+json") {
804
+ return "webmanifest"
805
+ }
806
+ if (contentType === "image/svg+xml") {
807
+ return "svg"
808
+ }
809
+ if (CONTENT_TYPE.isJson(contentType)) {
810
+ return "json"
811
+ }
812
+ if (CONTENT_TYPE.isTextual(contentType)) {
813
+ return "text"
814
+ }
645
815
  return "other"
646
816
  }
647
817
 
648
- const determineFileUrlForOutDirectory = ({
649
- rootDirectoryUrl,
650
- outDirectoryUrl,
651
- url,
652
- }) => {
653
- if (!outDirectoryUrl) {
654
- return url
818
+ const inferUrlInfoSubtype = ({ type, subtype, url }) => {
819
+ if (type === "js_classic" || type === "js_module") {
820
+ const urlObject = new URL(url)
821
+ if (urlObject.searchParams.has("worker")) {
822
+ return "worker"
823
+ }
824
+ if (urlObject.searchParams.has("service_worker")) {
825
+ return "service_worker"
826
+ }
827
+ if (urlObject.searchParams.has("shared_worker")) {
828
+ return "shared_worker"
829
+ }
830
+ // if we are currently inside a worker, all deps are consider inside worker too
831
+ return subtype
832
+ }
833
+ return ""
834
+ }
835
+
836
+ const determineFileUrlForOutDirectory = ({ urlInfo, context }) => {
837
+ if (!context.outDirectoryUrl) {
838
+ return urlInfo.url
839
+ }
840
+ if (!urlInfo.url.startsWith("file:")) {
841
+ return urlInfo.url
655
842
  }
656
- if (!url.startsWith("file:")) {
657
- return url
843
+ let url = urlInfo.url
844
+ if (!urlIsInsideOf(urlInfo.url, context.rootDirectoryUrl)) {
845
+ const fsRootUrl = ensureWindowsDriveLetter("file:///", urlInfo.url)
846
+ url = `${context.rootDirectoryUrl}@fs/${url.slice(fsRootUrl.length)}`
658
847
  }
659
- if (!urlIsInsideOf(url, rootDirectoryUrl)) {
660
- url = `${rootDirectoryUrl}@fs/${url.slice(fileSystemRootUrl.length)}`
848
+ if (urlInfo.filename) {
849
+ url = setUrlFilename(url, urlInfo.filename)
661
850
  }
662
851
  return moveUrl({
663
- url: fileUrlConverter.asUrlWithoutSpecialParams(url),
664
- from: rootDirectoryUrl,
665
- to: outDirectoryUrl,
852
+ url,
853
+ from: context.rootDirectoryUrl,
854
+ to: context.outDirectoryUrl,
666
855
  preferAbsolute: true,
667
856
  })
668
857
  }
669
858
 
670
- const specifierFormat = {
859
+ const urlSpecifierFormat = {
671
860
  encode: (reference) => {
672
861
  const { generatedSpecifier } = reference
673
862
  if (generatedSpecifier.then) {
674
863
  return generatedSpecifier.then((value) => {
675
864
  reference.generatedSpecifier = value
676
- return specifierFormat.encode(reference)
865
+ return urlSpecifierFormat.encode(reference)
677
866
  })
678
867
  }
679
868
  // allow plugin to return a function to bypas default formatting
@@ -698,10 +887,11 @@ const specifierFormat = {
698
887
  },
699
888
  }
700
889
  const formatters = {
701
- js_import_export: { encode: JSON.stringify, decode: JSON.parse },
702
- js_import_meta_url_pattern: { encode: JSON.stringify, decode: JSON.parse },
890
+ "js_import_export": { encode: JSON.stringify, decode: JSON.parse },
891
+ "js_url_specifier": { encode: JSON.stringify, decode: JSON.parse },
892
+ "css_@import": { encode: JSON.stringify, code: JSON.stringify },
703
893
  // https://github.com/webpack-contrib/css-loader/pull/627/files
704
- css_url: {
894
+ "css_url": {
705
895
  encode: (url) => {
706
896
  // If url is already wrapped in quotes, remove them
707
897
  url = formatters.css_url.decode(url)