@jsenv/core 27.0.0-alpha.12 → 27.0.0-alpha.15

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