@jsenv/core 27.0.0-alpha.10 → 27.0.0-alpha.13

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