@jsenv/core 27.3.2 → 27.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +16 -4
  2. package/dist/controllable_child_process.mjs +1 -0
  3. package/dist/controllable_worker_thread.mjs +1 -0
  4. package/dist/js/event_source_client.js +45 -24
  5. package/dist/js/execute_using_dynamic_import.js +5 -3
  6. package/dist/js/html_supervisor_installer.js +368 -139
  7. package/dist/main.js +668 -471
  8. package/package.json +5 -6
  9. package/src/build/build.js +6 -4
  10. package/src/build/graph_utils.js +14 -11
  11. package/src/execute/run.js +29 -28
  12. package/src/execute/runtimes/browsers/from_playwright.js +90 -92
  13. package/src/execute/runtimes/node/execute_using_dynamic_import.js +8 -2
  14. package/src/execute/runtimes/node/node_child_process.js +2 -0
  15. package/src/execute/runtimes/node/node_worker_thread.js +11 -6
  16. package/src/helpers/event_source/event_source.js +38 -17
  17. package/src/omega/errors.js +41 -9
  18. package/src/omega/kitchen.js +35 -19
  19. package/src/omega/omega_server.js +54 -1
  20. package/src/omega/server/file_service.js +30 -3
  21. package/src/omega/url_graph/url_graph_report.js +2 -4
  22. package/src/omega/url_graph.js +29 -16
  23. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +8 -8
  24. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +160 -172
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +0 -4
  26. package/src/plugins/bundling/js_module/bundle_js_module.js +0 -1
  27. package/src/plugins/html_supervisor/client/error_in_document.js +268 -121
  28. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +47 -5
  29. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +37 -12
  30. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +1 -2
  31. package/src/plugins/plugins.js +0 -2
  32. package/src/plugins/url_analysis/js/js_urls.js +0 -9
  33. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
  34. package/src/test/coverage/report_to_coverage.js +16 -11
  35. package/src/test/execute_plan.js +3 -2
  36. package/src/test/execute_test_plan.js +3 -1
  37. package/src/test/logs_file_execution.js +60 -27
  38. package/src/test/logs_file_execution.test.mjs +41 -0
package/dist/main.js CHANGED
@@ -5928,19 +5928,6 @@ const generateInlineContentUrl = ({
5928
5928
  return inlineContentUrl;
5929
5929
  };
5930
5930
 
5931
- const urlToFileSystemPath = url => {
5932
- let urlString = String(url);
5933
-
5934
- if (urlString[urlString.length - 1] === "/") {
5935
- // remove trailing / so that nodejs path becomes predictable otherwise it logs
5936
- // the trailing slash on linux but does not on windows
5937
- urlString = urlString.slice(0, -1);
5938
- }
5939
-
5940
- const fileSystemPath = fileURLToPath(urlString);
5941
- return fileSystemPath;
5942
- };
5943
-
5944
5931
  // consider switching to https://babeljs.io/docs/en/babel-code-frame
5945
5932
  const stringifyUrlSite = ({
5946
5933
  url,
@@ -5953,7 +5940,7 @@ const stringifyUrlSite = ({
5953
5940
  lineMaxLength,
5954
5941
  color
5955
5942
  } = {}) => {
5956
- let string = `${humanizeUrl(url)}`;
5943
+ let string = url;
5957
5944
 
5958
5945
  if (typeof line === "number") {
5959
5946
  string += `:${line}`;
@@ -5978,15 +5965,6 @@ const stringifyUrlSite = ({
5978
5965
  return `${string}
5979
5966
  ${sourceLoc}`;
5980
5967
  };
5981
- const humanizeUrl = url => {
5982
- if (url.startsWith("file://")) {
5983
- // we prefer file system path because vscode reliably make them clickable
5984
- // and sometimes it won't for file:// urls
5985
- return urlToFileSystemPath(url);
5986
- }
5987
-
5988
- return url;
5989
- };
5990
5968
  const showSourceLocation = ({
5991
5969
  content,
5992
5970
  line,
@@ -6489,6 +6467,19 @@ const urlToBasename = url => {
6489
6467
  return basename;
6490
6468
  };
6491
6469
 
6470
+ const urlToFileSystemPath = url => {
6471
+ let urlString = String(url);
6472
+
6473
+ if (urlString[urlString.length - 1] === "/") {
6474
+ // remove trailing / so that nodejs path becomes predictable otherwise it logs
6475
+ // the trailing slash on linux but does not on windows
6476
+ urlString = urlString.slice(0, -1);
6477
+ }
6478
+
6479
+ const fileSystemPath = fileURLToPath(urlString);
6480
+ return fileSystemPath;
6481
+ };
6482
+
6492
6483
  const assertAndNormalizeDirectoryUrl = value => {
6493
6484
  let urlString;
6494
6485
 
@@ -8470,22 +8461,11 @@ const parseAndTransformJsUrls = async (urlInfo, context) => {
8470
8461
  } = context;
8471
8462
  const actions = [];
8472
8463
  const magicSource = createMagicSource(urlInfo.content);
8473
- urlInfo.data.usesImport = false;
8474
- urlInfo.data.usesExport = false;
8475
- urlInfo.data.usesImportAssertion = false;
8476
8464
  jsMentions.forEach(jsMention => {
8477
- if (jsMention.assert) {
8478
- urlInfo.data.usesImportAssertion = true;
8479
- }
8480
-
8481
8465
  if (jsMention.subtype === "import_static" || jsMention.subtype === "import_dynamic") {
8482
8466
  urlInfo.data.usesImport = true;
8483
8467
  }
8484
8468
 
8485
- if (jsMention.subtype === "export") {
8486
- urlInfo.data.usesExport = true;
8487
- }
8488
-
8489
8469
  const [reference] = referenceUtils.found({
8490
8470
  type: jsMention.type,
8491
8471
  subtype: jsMention.subtype,
@@ -8633,7 +8613,9 @@ const jsenvPluginUrlAnalysis = ({
8633
8613
  type: "filesystem",
8634
8614
  subtype: "directory_entry",
8635
8615
  specifier: directoryEntryName,
8636
- trace: `"${directoryRelativeUrl}${directoryEntryName}" entry in directory referenced by ${originalDirectoryReference.trace}`
8616
+ trace: {
8617
+ message: `"${directoryRelativeUrl}${directoryEntryName}" entry in directory referenced by ${originalDirectoryReference.trace.message}`
8618
+ }
8637
8619
  });
8638
8620
  });
8639
8621
  }
@@ -10927,9 +10909,7 @@ const jsenvPluginNodeEsmResolution = ({
10927
10909
  const onFileChange = () => {
10928
10910
  packageScopesCache.clear();
10929
10911
  packageJsonsCache.clear();
10930
- Object.keys(urlGraph.urlInfos).forEach(url => {
10931
- const urlInfo = urlGraph.getUrlInfo(url);
10932
-
10912
+ urlGraph.urlInfoMap.forEach(urlInfo => {
10933
10913
  if (urlInfo.dependsOnPackageJson) {
10934
10914
  urlGraph.considerModified(urlInfo);
10935
10915
  }
@@ -12050,6 +12030,8 @@ const jsenvPluginInlineUrls = () => {
12050
12030
  };
12051
12031
  };
12052
12032
 
12033
+ const requireFromJsenv = createRequire(import.meta.url);
12034
+
12053
12035
  /*
12054
12036
  * Things happening here
12055
12037
  * - html supervisor module injection
@@ -12067,13 +12049,32 @@ const jsenvPluginHtmlSupervisor = ({
12067
12049
  dev: true,
12068
12050
  test: true
12069
12051
  },
12052
+ serve: request => {
12053
+ if (!request.ressource.startsWith("/__open_in_editor__/")) {
12054
+ return null;
12055
+ }
12056
+
12057
+ const file = request.ressource.slice("/__open_in_editor__/".length);
12058
+
12059
+ if (!file) {
12060
+ return {
12061
+ status: 400,
12062
+ body: 'Missing "file" in url search params'
12063
+ };
12064
+ }
12065
+
12066
+ const launch = requireFromJsenv("launch-editor");
12067
+ launch(fileURLToPath(file), () => {// ignore error for now
12068
+ });
12069
+ return {
12070
+ status: 200
12071
+ };
12072
+ },
12070
12073
  transformUrlContent: {
12071
12074
  html: ({
12072
12075
  url,
12073
12076
  content
12074
- }, {
12075
- referenceUtils
12076
- }) => {
12077
+ }, context) => {
12077
12078
  const htmlAst = parseHtmlString(content);
12078
12079
  const scriptsToSupervise = [];
12079
12080
 
@@ -12096,7 +12097,7 @@ const jsenvPluginHtmlSupervisor = ({
12096
12097
  lineEnd,
12097
12098
  columnEnd
12098
12099
  });
12099
- const [inlineScriptReference] = referenceUtils.foundInline({
12100
+ const [inlineScriptReference] = context.referenceUtils.foundInline({
12100
12101
  type: "script_src",
12101
12102
  expectedType: {
12102
12103
  classic: "js_classic",
@@ -12173,7 +12174,7 @@ const jsenvPluginHtmlSupervisor = ({
12173
12174
  }
12174
12175
  }
12175
12176
  });
12176
- const [htmlSupervisorInstallerFileReference] = referenceUtils.inject({
12177
+ const [htmlSupervisorInstallerFileReference] = context.referenceUtils.inject({
12177
12178
  type: "js_import_export",
12178
12179
  expectedType: "js_module",
12179
12180
  specifier: htmlSupervisorInstallerFileUrl
@@ -12185,11 +12186,12 @@ const jsenvPluginHtmlSupervisor = ({
12185
12186
  import { installHtmlSupervisor } from ${htmlSupervisorInstallerFileReference.generatedSpecifier}
12186
12187
  installHtmlSupervisor(${JSON.stringify({
12187
12188
  logs,
12188
- measurePerf
12189
+ measurePerf,
12190
+ rootDirectoryUrl: context.rootDirectoryUrl
12189
12191
  }, null, " ")})`,
12190
12192
  "injected-by": "jsenv:html_supervisor"
12191
12193
  }));
12192
- const [htmlSupervisorSetupFileReference] = referenceUtils.inject({
12194
+ const [htmlSupervisorSetupFileReference] = context.referenceUtils.inject({
12193
12195
  type: "script_src",
12194
12196
  expectedType: "js_classic",
12195
12197
  specifier: htmlSupervisorSetupFileUrl
@@ -12776,8 +12778,6 @@ export default inlineContent.text`,
12776
12778
  return [asJsonModule, asCssModule, asTextModule];
12777
12779
  };
12778
12780
 
12779
- const requireFromJsenv = createRequire(import.meta.url);
12780
-
12781
12781
  const babelPluginPackagePath = requireFromJsenv.resolve("@jsenv/babel-plugins");
12782
12782
  const babelPluginPackageUrl = pathToFileURL(babelPluginPackagePath);
12783
12783
  const requireBabelPlugin = createRequire(babelPluginPackageUrl);
@@ -19338,8 +19338,7 @@ const rollupPluginJsenv = ({
19338
19338
  data: {
19339
19339
  generatedBy: "rollup",
19340
19340
  bundleRelativeUrl: rollupFileInfo.fileName,
19341
- usesImport: rollupFileInfo.imports.length > 0 || rollupFileInfo.dynamicImports.length > 0,
19342
- usesExport: rollupFileInfo.exports.length > 0
19341
+ usesImport: rollupFileInfo.imports.length > 0 || rollupFileInfo.dynamicImports.length > 0
19343
19342
  },
19344
19343
  contentType: "text/javascript",
19345
19344
  content: rollupFileInfo.code,
@@ -20240,269 +20239,216 @@ const jsenvPluginDevSSEClient = () => {
20240
20239
  };
20241
20240
  };
20242
20241
 
20243
- const createSSEService = ({
20244
- serverEventCallbackList
20245
- }) => {
20246
- const destroyCallbackList = createCallbackListNotifiedOnce();
20247
- const cache = [];
20248
- const sseRoomLimit = 100;
20249
-
20250
- const getOrCreateSSERoom = request => {
20251
- const htmlFileRelativeUrl = request.ressource.slice(1);
20252
- const cacheEntry = cache.find(cacheEntryCandidate => cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl);
20253
-
20254
- if (cacheEntry) {
20255
- return cacheEntry.sseRoom;
20256
- }
20257
-
20258
- const sseRoom = createSSERoom({
20259
- retryDuration: 2000,
20260
- historyLength: 100,
20261
- welcomeEventEnabled: true,
20262
- effect: () => {
20263
- return serverEventCallbackList.add(event => {
20264
- sseRoom.sendEvent(event);
20265
- });
20266
- }
20267
- });
20268
- const removeSSECleanupCallback = destroyCallbackList.add(() => {
20269
- removeSSECleanupCallback();
20270
- sseRoom.close();
20271
- });
20272
- cache.push({
20273
- htmlFileRelativeUrl,
20274
- sseRoom,
20275
- cleanup: () => {
20276
- removeSSECleanupCallback();
20277
- sseRoom.close();
20278
- }
20279
- });
20280
-
20281
- if (cache.length >= sseRoomLimit) {
20282
- const firstCacheEntry = cache.shift();
20283
- firstCacheEntry.cleanup();
20284
- }
20285
-
20286
- return sseRoom;
20287
- };
20288
-
20289
- return {
20290
- getOrCreateSSERoom,
20291
- destroy: () => {
20292
- destroyCallbackList.notify();
20293
- }
20294
- };
20295
- };
20296
-
20297
20242
  const jsenvPluginDevSSEServer = ({
20298
- rootDirectoryUrl,
20299
- urlGraph,
20300
20243
  clientFileChangeCallbackList,
20301
20244
  clientFilesPruneCallbackList
20302
20245
  }) => {
20303
- const serverEventCallbackList = createCallbackList();
20304
- const sseService = createSSEService({
20305
- serverEventCallbackList
20306
- });
20307
-
20308
- const notifyDeclined = ({
20309
- cause,
20310
- reason,
20311
- declinedBy
20312
- }) => {
20313
- serverEventCallbackList.notify({
20314
- type: "reload",
20315
- data: JSON.stringify({
20246
+ return {
20247
+ name: "jsenv:sse_server",
20248
+ appliesDuring: {
20249
+ dev: true
20250
+ },
20251
+ registerServerEvents: ({
20252
+ sendServerEvent
20253
+ }, {
20254
+ rootDirectoryUrl,
20255
+ urlGraph
20256
+ }) => {
20257
+ const notifyDeclined = ({
20316
20258
  cause,
20317
- type: "full",
20318
- typeReason: reason,
20259
+ reason,
20319
20260
  declinedBy
20320
- })
20321
- });
20322
- };
20261
+ }) => {
20262
+ sendServerEvent({
20263
+ type: "reload",
20264
+ data: {
20265
+ cause,
20266
+ type: "full",
20267
+ typeReason: reason,
20268
+ declinedBy
20269
+ }
20270
+ });
20271
+ };
20323
20272
 
20324
- const notifyAccepted = ({
20325
- cause,
20326
- reason,
20327
- instructions
20328
- }) => {
20329
- serverEventCallbackList.notify({
20330
- type: "reload",
20331
- data: JSON.stringify({
20273
+ const notifyAccepted = ({
20332
20274
  cause,
20333
- type: "hot",
20334
- typeReason: reason,
20335
- hotInstructions: instructions
20336
- })
20337
- });
20338
- };
20339
-
20340
- const propagateUpdate = firstUrlInfo => {
20341
- const urlInfos = urlGraph.urlInfos;
20275
+ reason,
20276
+ instructions
20277
+ }) => {
20278
+ sendServerEvent({
20279
+ type: "reload",
20280
+ data: {
20281
+ cause,
20282
+ type: "hot",
20283
+ typeReason: reason,
20284
+ hotInstructions: instructions
20285
+ }
20286
+ });
20287
+ };
20342
20288
 
20343
- const iterate = (urlInfo, trace) => {
20344
- if (urlInfo.data.hotAcceptSelf) {
20345
- return {
20346
- accepted: true,
20347
- reason: urlInfo === firstUrlInfo ? `file accepts hot reload` : `a dependent file accepts hot reload`,
20348
- instructions: [{
20349
- type: urlInfo.type,
20350
- boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
20351
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl)
20352
- }]
20353
- };
20354
- }
20289
+ const propagateUpdate = firstUrlInfo => {
20290
+ const iterate = (urlInfo, seen) => {
20291
+ if (urlInfo.data.hotAcceptSelf) {
20292
+ return {
20293
+ accepted: true,
20294
+ reason: urlInfo === firstUrlInfo ? `file accepts hot reload` : `a dependent file accepts hot reload`,
20295
+ instructions: [{
20296
+ type: urlInfo.type,
20297
+ boundary: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl),
20298
+ acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl)
20299
+ }]
20300
+ };
20301
+ }
20355
20302
 
20356
- const {
20357
- dependents
20358
- } = urlInfo;
20359
- const instructions = [];
20303
+ const {
20304
+ dependents
20305
+ } = urlInfo;
20306
+ const instructions = [];
20360
20307
 
20361
- for (const dependentUrl of dependents) {
20362
- const dependentUrlInfo = urlInfos[dependentUrl];
20308
+ for (const dependentUrl of dependents) {
20309
+ const dependentUrlInfo = urlGraph.getUrlInfo(dependentUrl);
20363
20310
 
20364
- if (dependentUrlInfo.data.hotDecline) {
20365
- return {
20366
- declined: true,
20367
- reason: `a dependent file declines hot reload`,
20368
- declinedBy: dependentUrl
20369
- };
20370
- }
20311
+ if (dependentUrlInfo.data.hotDecline) {
20312
+ return {
20313
+ declined: true,
20314
+ reason: `a dependent file declines hot reload`,
20315
+ declinedBy: dependentUrl
20316
+ };
20317
+ }
20371
20318
 
20372
- const {
20373
- hotAcceptDependencies = []
20374
- } = dependentUrlInfo.data;
20319
+ const {
20320
+ hotAcceptDependencies = []
20321
+ } = dependentUrlInfo.data;
20322
+
20323
+ if (hotAcceptDependencies.includes(urlInfo.url)) {
20324
+ instructions.push({
20325
+ type: dependentUrlInfo.type,
20326
+ boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
20327
+ acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl)
20328
+ });
20329
+ continue;
20330
+ }
20375
20331
 
20376
- if (hotAcceptDependencies.includes(urlInfo.url)) {
20377
- instructions.push({
20378
- type: dependentUrlInfo.type,
20379
- boundary: urlToRelativeUrl(dependentUrl, rootDirectoryUrl),
20380
- acceptedBy: urlToRelativeUrl(urlInfo.url, rootDirectoryUrl)
20381
- });
20382
- continue;
20383
- }
20332
+ if (seen.includes(dependentUrl)) {
20333
+ return {
20334
+ declined: true,
20335
+ reason: "circular dependency",
20336
+ declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl)
20337
+ };
20338
+ }
20384
20339
 
20385
- if (trace.includes(dependentUrl)) {
20386
- return {
20387
- declined: true,
20388
- reason: "circular dependency",
20389
- declinedBy: urlToRelativeUrl(dependentUrl, rootDirectoryUrl)
20390
- };
20391
- }
20340
+ const dependentPropagationResult = iterate(dependentUrlInfo, [...seen, dependentUrl]);
20392
20341
 
20393
- const dependentPropagationResult = iterate(dependentUrlInfo, [...trace, dependentUrl]);
20342
+ if (dependentPropagationResult.accepted) {
20343
+ instructions.push(...dependentPropagationResult.instructions);
20344
+ continue;
20345
+ }
20394
20346
 
20395
- if (dependentPropagationResult.accepted) {
20396
- instructions.push(...dependentPropagationResult.instructions);
20397
- continue;
20398
- }
20347
+ if ( // declined explicitely by an other file, it must decline the whole update
20348
+ dependentPropagationResult.declinedBy) {
20349
+ return dependentPropagationResult;
20350
+ } // declined by absence of boundary, we can keep searching
20399
20351
 
20400
- if ( // declined explicitely by an other file, it must decline the whole update
20401
- dependentPropagationResult.declinedBy) {
20402
- return dependentPropagationResult;
20403
- } // declined by absence of boundary, we can keep searching
20404
20352
 
20353
+ continue;
20354
+ }
20405
20355
 
20406
- continue;
20407
- }
20356
+ if (instructions.length === 0) {
20357
+ return {
20358
+ declined: true,
20359
+ reason: `there is no file accepting hot reload while propagating update`
20360
+ };
20361
+ }
20408
20362
 
20409
- if (instructions.length === 0) {
20410
- return {
20411
- declined: true,
20412
- reason: `there is no file accepting hot reload while propagating update`
20363
+ return {
20364
+ accepted: true,
20365
+ reason: `${instructions.length} dependent file(s) accepts hot reload`,
20366
+ instructions
20367
+ };
20413
20368
  };
20414
- }
20415
20369
 
20416
- return {
20417
- accepted: true,
20418
- reason: `${instructions.length} dependent file(s) accepts hot reload`,
20419
- instructions
20370
+ const seen = [];
20371
+ return iterate(firstUrlInfo, seen);
20420
20372
  };
20421
- };
20422
20373
 
20423
- const trace = [];
20424
- return iterate(firstUrlInfo, trace);
20425
- };
20426
-
20427
- clientFileChangeCallbackList.push(({
20428
- url,
20429
- event
20430
- }) => {
20431
- const urlInfo = urlGraph.getUrlInfo(url); // file not part of dependency graph
20374
+ clientFileChangeCallbackList.push(({
20375
+ url,
20376
+ event
20377
+ }) => {
20378
+ const urlInfo = urlGraph.getUrlInfo(url); // file not part of dependency graph
20432
20379
 
20433
- if (!urlInfo) {
20434
- return;
20435
- }
20380
+ if (!urlInfo) {
20381
+ return;
20382
+ }
20436
20383
 
20437
- const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl);
20438
- const hotUpdate = propagateUpdate(urlInfo);
20384
+ const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl);
20385
+ const hotUpdate = propagateUpdate(urlInfo);
20439
20386
 
20440
- if (hotUpdate.declined) {
20441
- notifyDeclined({
20442
- cause: `${relativeUrl} ${event}`,
20443
- reason: hotUpdate.reason,
20444
- declinedBy: hotUpdate.declinedBy
20445
- });
20446
- } else {
20447
- notifyAccepted({
20448
- cause: `${relativeUrl} ${event}`,
20449
- reason: hotUpdate.reason,
20450
- instructions: hotUpdate.instructions
20387
+ if (hotUpdate.declined) {
20388
+ notifyDeclined({
20389
+ cause: `${relativeUrl} ${event}`,
20390
+ reason: hotUpdate.reason,
20391
+ declinedBy: hotUpdate.declinedBy
20392
+ });
20393
+ } else {
20394
+ notifyAccepted({
20395
+ cause: `${relativeUrl} ${event}`,
20396
+ reason: hotUpdate.reason,
20397
+ instructions: hotUpdate.instructions
20398
+ });
20399
+ }
20451
20400
  });
20452
- }
20453
- });
20454
- clientFilesPruneCallbackList.push(({
20455
- prunedUrlInfos,
20456
- firstUrlInfo
20457
- }) => {
20458
- const mainHotUpdate = propagateUpdate(firstUrlInfo);
20459
- const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl))}`; // now check if we can hot update the main ressource
20460
- // then if we can hot update all dependencies
20401
+ clientFilesPruneCallbackList.push(({
20402
+ prunedUrlInfos,
20403
+ firstUrlInfo
20404
+ }) => {
20405
+ const mainHotUpdate = propagateUpdate(firstUrlInfo);
20406
+ const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl))}`; // now check if we can hot update the main ressource
20407
+ // then if we can hot update all dependencies
20408
+
20409
+ if (mainHotUpdate.declined) {
20410
+ notifyDeclined({
20411
+ cause,
20412
+ reason: mainHotUpdate.reason,
20413
+ declinedBy: mainHotUpdate.declinedBy
20414
+ });
20415
+ return;
20416
+ } // main can hot update
20461
20417
 
20462
- if (mainHotUpdate.declined) {
20463
- notifyDeclined({
20464
- cause,
20465
- reason: mainHotUpdate.reason,
20466
- declinedBy: mainHotUpdate.declinedBy
20467
- });
20468
- return;
20469
- } // main can hot update
20470
20418
 
20419
+ let i = 0;
20420
+ const instructions = [];
20471
20421
 
20472
- let i = 0;
20473
- const instructions = [];
20422
+ while (i < prunedUrlInfos.length) {
20423
+ const prunedUrlInfo = prunedUrlInfos[i++];
20424
+
20425
+ if (prunedUrlInfo.data.hotDecline) {
20426
+ notifyDeclined({
20427
+ cause,
20428
+ reason: `a pruned file declines hot reload`,
20429
+ declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl)
20430
+ });
20431
+ return;
20432
+ }
20474
20433
 
20475
- while (i < prunedUrlInfos.length) {
20476
- const prunedUrlInfo = prunedUrlInfos[i++];
20434
+ instructions.push({
20435
+ type: "prune",
20436
+ boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
20437
+ acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl)
20438
+ });
20439
+ }
20477
20440
 
20478
- if (prunedUrlInfo.data.hotDecline) {
20479
- notifyDeclined({
20441
+ notifyAccepted({
20480
20442
  cause,
20481
- reason: `a pruned file declines hot reload`,
20482
- declinedBy: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl)
20443
+ reason: mainHotUpdate.reason,
20444
+ instructions
20483
20445
  });
20484
- return;
20485
- }
20486
-
20487
- instructions.push({
20488
- type: "prune",
20489
- boundary: urlToRelativeUrl(prunedUrlInfo.url, rootDirectoryUrl),
20490
- acceptedBy: urlToRelativeUrl(firstUrlInfo.url, rootDirectoryUrl)
20491
20446
  });
20492
- }
20493
-
20494
- notifyAccepted({
20495
- cause,
20496
- reason: mainHotUpdate.reason,
20497
- instructions
20498
- });
20499
- });
20500
- return {
20501
- name: "jsenv:sse_server",
20502
- appliesDuring: {
20503
- dev: true
20504
20447
  },
20505
- serve: request => {
20448
+ serve: (request, {
20449
+ rootDirectoryUrl,
20450
+ urlGraph
20451
+ }) => {
20506
20452
  if (request.ressource === "/__graph__") {
20507
20453
  const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl));
20508
20454
  return {
@@ -20515,26 +20461,12 @@ const jsenvPluginDevSSEServer = ({
20515
20461
  };
20516
20462
  }
20517
20463
 
20518
- const {
20519
- accept
20520
- } = request.headers;
20521
-
20522
- if (accept && accept.includes("text/event-stream")) {
20523
- const room = sseService.getOrCreateSSERoom(request);
20524
- return room.join(request);
20525
- }
20526
-
20527
- return null;
20528
- },
20529
- destroy: () => {
20530
- sseService.destroy();
20531
- }
20532
- };
20533
- };
20464
+ return null;
20465
+ }
20466
+ };
20467
+ };
20534
20468
 
20535
20469
  const jsenvPluginAutoreload = ({
20536
- rootDirectoryUrl,
20537
- urlGraph,
20538
20470
  scenario,
20539
20471
  clientFileChangeCallbackList,
20540
20472
  clientFilesPruneCallbackList
@@ -20544,8 +20476,6 @@ const jsenvPluginAutoreload = ({
20544
20476
  }
20545
20477
 
20546
20478
  return [jsenvPluginHmr(), jsenvPluginDevSSEClient(), jsenvPluginDevSSEServer({
20547
- rootDirectoryUrl,
20548
- urlGraph,
20549
20479
  clientFileChangeCallbackList,
20550
20480
  clientFilesPruneCallbackList
20551
20481
  })];
@@ -20634,8 +20564,6 @@ const getCorePlugins = ({
20634
20564
  }), jsenvPluginUrlResolution(), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
20635
20565
  runtimeCompat
20636
20566
  }), jsenvPluginBundling(bundling), jsenvPluginMinification(minification), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({ ...clientAutoreload,
20637
- rootDirectoryUrl,
20638
- urlGraph,
20639
20567
  scenario,
20640
20568
  clientFileChangeCallbackList,
20641
20569
  clientFilesPruneCallbackList
@@ -20722,15 +20650,15 @@ const createUrlGraph = ({
20722
20650
  clientFileChangeCallbackList,
20723
20651
  clientFilesPruneCallbackList
20724
20652
  } = {}) => {
20725
- const urlInfos = {};
20653
+ const urlInfoMap = new Map();
20726
20654
 
20727
- const getUrlInfo = url => urlInfos[url];
20655
+ const getUrlInfo = url => urlInfoMap.get(url);
20728
20656
 
20729
20657
  const deleteUrlInfo = url => {
20730
- const urlInfo = urlInfos[url];
20658
+ const urlInfo = urlInfoMap.get(url);
20731
20659
 
20732
20660
  if (urlInfo) {
20733
- delete urlInfos[url];
20661
+ urlInfoMap.delete(url);
20734
20662
 
20735
20663
  if (urlInfo.sourcemapReference) {
20736
20664
  deleteUrlInfo(urlInfo.sourcemapReference.url);
@@ -20739,15 +20667,15 @@ const createUrlGraph = ({
20739
20667
  };
20740
20668
 
20741
20669
  const reuseOrCreateUrlInfo = url => {
20742
- const existingUrlInfo = urlInfos[url];
20670
+ const existingUrlInfo = getUrlInfo(url);
20743
20671
  if (existingUrlInfo) return existingUrlInfo;
20744
20672
  const urlInfo = createUrlInfo(url);
20745
- urlInfos[url] = urlInfo;
20673
+ urlInfoMap.set(url, urlInfo);
20746
20674
  return urlInfo;
20747
20675
  };
20748
20676
 
20749
20677
  const inferReference = (specifier, parentUrl) => {
20750
- const parentUrlInfo = urlInfos[parentUrl];
20678
+ const parentUrlInfo = getUrlInfo(parentUrl);
20751
20679
 
20752
20680
  if (!parentUrlInfo) {
20753
20681
  return null;
@@ -20760,7 +20688,7 @@ const createUrlGraph = ({
20760
20688
  };
20761
20689
 
20762
20690
  const findDependent = (url, predicate) => {
20763
- const urlInfo = urlInfos[url];
20691
+ const urlInfo = getUrlInfo(url);
20764
20692
 
20765
20693
  if (!urlInfo) {
20766
20694
  return null;
@@ -20768,7 +20696,7 @@ const createUrlGraph = ({
20768
20696
 
20769
20697
  const visitDependents = urlInfo => {
20770
20698
  for (const dependentUrl of urlInfo.dependents) {
20771
- const dependent = urlInfos[dependentUrl];
20699
+ const dependent = getUrlInfo(dependentUrl);
20772
20700
 
20773
20701
  if (predicate(dependent)) {
20774
20702
  return dependent;
@@ -20818,7 +20746,7 @@ const createUrlGraph = ({
20818
20746
  const removeDependencies = (urlInfo, urlsToPrune) => {
20819
20747
  urlsToPrune.forEach(urlToPrune => {
20820
20748
  urlInfo.dependencies.delete(urlToPrune);
20821
- const dependency = urlInfos[urlToPrune];
20749
+ const dependency = getUrlInfo(urlToPrune);
20822
20750
 
20823
20751
  if (!dependency) {
20824
20752
  return;
@@ -20858,7 +20786,7 @@ const createUrlGraph = ({
20858
20786
  clientFileChangeCallbackList.push(({
20859
20787
  url
20860
20788
  }) => {
20861
- const urlInfo = urlInfos[url];
20789
+ const urlInfo = getUrlInfo(url);
20862
20790
 
20863
20791
  if (urlInfo) {
20864
20792
  considerModified(urlInfo, Date.now());
@@ -20878,7 +20806,7 @@ const createUrlGraph = ({
20878
20806
  urlInfo.modifiedTimestamp = modifiedTimestamp;
20879
20807
  urlInfo.contentEtag = undefined;
20880
20808
  urlInfo.dependents.forEach(dependentUrl => {
20881
- const dependentUrlInfo = urlInfos[dependentUrl];
20809
+ const dependentUrlInfo = getUrlInfo(dependentUrl);
20882
20810
  const {
20883
20811
  hotAcceptDependencies = []
20884
20812
  } = dependentUrlInfo.data;
@@ -20887,6 +20815,13 @@ const createUrlGraph = ({
20887
20815
  iterate(dependentUrlInfo);
20888
20816
  }
20889
20817
  });
20818
+ urlInfo.dependencies.forEach(dependencyUrl => {
20819
+ const dependencyUrlInfo = getUrlInfo(dependencyUrl);
20820
+
20821
+ if (dependencyUrlInfo.isInline) {
20822
+ iterate(dependencyUrlInfo);
20823
+ }
20824
+ });
20890
20825
  };
20891
20826
 
20892
20827
  iterate(urlInfo);
@@ -20908,7 +20843,7 @@ const createUrlGraph = ({
20908
20843
  };
20909
20844
 
20910
20845
  return {
20911
- urlInfos,
20846
+ urlInfoMap,
20912
20847
  reuseOrCreateUrlInfo,
20913
20848
  getUrlInfo,
20914
20849
  deleteUrlInfo,
@@ -20917,13 +20852,20 @@ const createUrlGraph = ({
20917
20852
  updateReferences,
20918
20853
  considerModified,
20919
20854
  getRelatedUrlInfos,
20855
+ toObject: () => {
20856
+ const data = {};
20857
+ urlInfoMap.forEach(urlInfo => {
20858
+ data[urlInfo.url] = urlInfo;
20859
+ });
20860
+ return data;
20861
+ },
20920
20862
  toJSON: rootDirectoryUrl => {
20921
20863
  const data = {};
20922
- Object.keys(urlInfos).forEach(url => {
20923
- const dependencyUrls = Array.from(urlInfos[url].dependencies);
20864
+ urlInfoMap.forEach(urlInfo => {
20865
+ const dependencyUrls = Array.from(urlInfo.dependencies);
20924
20866
 
20925
20867
  if (dependencyUrls.length) {
20926
- const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl);
20868
+ const relativeUrl = urlToRelativeUrl(urlInfo.url, rootDirectoryUrl);
20927
20869
  data[relativeUrl] = dependencyUrls.map(dependencyUrl => urlToRelativeUrl(dependencyUrl, rootDirectoryUrl));
20928
20870
  }
20929
20871
  });
@@ -21508,7 +21450,7 @@ const createResolveUrlError = ({
21508
21450
  reason,
21509
21451
  ...details,
21510
21452
  "specifier": `"${reference.specifier}"`,
21511
- "specifier trace": reference.trace,
21453
+ "specifier trace": reference.trace.message,
21512
21454
  ...detailsFromPluginController(pluginController)
21513
21455
  }));
21514
21456
  resolveError.name = "RESOLVE_URL_ERROR";
@@ -21539,17 +21481,21 @@ const createFetchUrlContentError = ({
21539
21481
  reason,
21540
21482
  ...details
21541
21483
  }) => {
21542
- const fetchContentError = new Error(createDetailedMessage$1(`Failed to fetch url content`, {
21484
+ const fetchError = new Error(createDetailedMessage$1(`Failed to fetch url content`, {
21543
21485
  reason,
21544
21486
  ...details,
21545
21487
  "url": urlInfo.url,
21546
- "url reference trace": reference.trace,
21488
+ "url reference trace": reference.trace.message,
21547
21489
  ...detailsFromPluginController(pluginController)
21548
21490
  }));
21549
- fetchContentError.name = "FETCH_URL_CONTENT_ERROR";
21550
- fetchContentError.code = code;
21551
- fetchContentError.reason = reason;
21552
- return fetchContentError;
21491
+ fetchError.name = "FETCH_URL_CONTENT_ERROR";
21492
+ fetchError.code = code;
21493
+ fetchError.reason = reason;
21494
+ fetchError.url = reference.trace.url;
21495
+ fetchError.line = reference.trace.line;
21496
+ fetchError.column = reference.trace.column;
21497
+ fetchError.contentFrame = reference.trace.message;
21498
+ return fetchError;
21553
21499
  };
21554
21500
 
21555
21501
  if (error.code === "EPERM") {
@@ -21593,12 +21539,42 @@ const createTransformUrlContentError = ({
21593
21539
  reason,
21594
21540
  ...details,
21595
21541
  "url": urlInfo.url,
21596
- "url reference trace": reference.trace,
21542
+ "url reference trace": reference.trace.message,
21597
21543
  ...detailsFromPluginController(pluginController)
21598
21544
  }));
21599
21545
  transformError.name = "TRANSFORM_URL_CONTENT_ERROR";
21600
21546
  transformError.code = code;
21601
21547
  transformError.reason = reason;
21548
+ transformError.url = reference.trace.url;
21549
+ transformError.line = reference.trace.line;
21550
+ transformError.column = reference.trace.column;
21551
+ transformError.stack = error.stack;
21552
+ transformError.contentFrame = reference.trace.message;
21553
+
21554
+ if (code === "PARSE_ERROR") {
21555
+ transformError.reason = error.message;
21556
+
21557
+ if (urlInfo.isInline) {
21558
+ transformError.line = reference.trace.line + error.line - 1;
21559
+ transformError.column = reference.trace.column + error.column;
21560
+ transformError.contentFrame = stringifyUrlSite({
21561
+ url: urlInfo.inlineUrlSite.url,
21562
+ line: transformError.line,
21563
+ column: transformError.column,
21564
+ content: urlInfo.inlineUrlSite.content
21565
+ });
21566
+ } else {
21567
+ transformError.line = error.line;
21568
+ transformError.column = error.column;
21569
+ transformError.contentFrame = stringifyUrlSite({
21570
+ url: urlInfo.url,
21571
+ line: transformError.line,
21572
+ column: transformError.column,
21573
+ content: urlInfo.content
21574
+ });
21575
+ }
21576
+ }
21577
+
21602
21578
  return transformError;
21603
21579
  };
21604
21580
 
@@ -21617,7 +21593,7 @@ const createFinalizeUrlContentError = ({
21617
21593
  "reason": `An error occured during "finalizeUrlContent"`,
21618
21594
  ...detailsFromValueThrown(error),
21619
21595
  "url": urlInfo.url,
21620
- "url reference trace": reference.trace,
21596
+ "url reference trace": reference.trace.message,
21621
21597
  ...detailsFromPluginController(pluginController)
21622
21598
  }));
21623
21599
  finalizeError.name = "FINALIZE_URL_CONTENT_ERROR";
@@ -22012,7 +21988,10 @@ const createKitchen = ({
22012
21988
  specifier
22013
21989
  }) => {
22014
21990
  const sourcemapReference = createReference({
22015
- trace: `sourcemap comment placeholder for ${urlInfo.url}`,
21991
+ trace: {
21992
+ message: `sourcemap comment placeholder`,
21993
+ url: urlInfo.url
21994
+ },
22016
21995
  type: "sourcemap_comment",
22017
21996
  subtype: urlInfo.contentType === "text/javascript" ? "js" : "css",
22018
21997
  parentUrl: urlInfo.url,
@@ -22029,13 +22008,14 @@ const createKitchen = ({
22029
22008
  specifierLine,
22030
22009
  specifierColumn
22031
22010
  }) => {
22011
+ const sourcemapUrlSite = adjustUrlSite(urlInfo, {
22012
+ urlGraph,
22013
+ url: urlInfo.url,
22014
+ line: specifierLine,
22015
+ column: specifierColumn
22016
+ });
22032
22017
  const sourcemapReference = createReference({
22033
- trace: stringifyUrlSite(adjustUrlSite(urlInfo, {
22034
- urlGraph,
22035
- url: urlInfo.url,
22036
- line: specifierLine,
22037
- column: specifierColumn
22038
- })),
22018
+ trace: traceFromUrlSite(sourcemapUrlSite),
22039
22019
  type,
22040
22020
  parentUrl: urlInfo.url,
22041
22021
  specifier,
@@ -22058,7 +22038,7 @@ const createKitchen = ({
22058
22038
  if (!fetchUrlContentReturnValue) {
22059
22039
  logger.warn(createDetailedMessage$1(`no plugin has handled url during "fetchUrlContent" hook -> url will be ignored`, {
22060
22040
  "url": urlInfo.url,
22061
- "url reference trace": reference.trace
22041
+ "url reference trace": reference.trace.message
22062
22042
  }));
22063
22043
  return;
22064
22044
  }
@@ -22215,7 +22195,7 @@ const createKitchen = ({
22215
22195
  ...rest
22216
22196
  }) => {
22217
22197
  if (trace === undefined) {
22218
- trace = stringifyUrlSite(adjustUrlSite(urlInfo, {
22198
+ trace = traceFromUrlSite(adjustUrlSite(urlInfo, {
22219
22199
  urlGraph,
22220
22200
  url: urlInfo.url,
22221
22201
  line: rest.specifierLine,
@@ -22231,22 +22211,22 @@ const createKitchen = ({
22231
22211
  },
22232
22212
  foundInline: ({
22233
22213
  isOriginalPosition,
22234
- line,
22235
- column,
22214
+ specifierLine,
22215
+ specifierColumn,
22236
22216
  ...rest
22237
22217
  }) => {
22238
22218
  const parentUrl = isOriginalPosition ? urlInfo.url : urlInfo.generatedUrl;
22239
22219
  const parentContent = isOriginalPosition ? urlInfo.originalContent : urlInfo.content;
22240
22220
  return addReference({
22241
- trace: stringifyUrlSite({
22221
+ trace: traceFromUrlSite({
22242
22222
  url: parentUrl,
22243
22223
  content: parentContent,
22244
- line,
22245
- column
22224
+ line: specifierLine,
22225
+ column: specifierColumn
22246
22226
  }),
22247
22227
  isOriginalPosition,
22248
- line,
22249
- column,
22228
+ specifierLine,
22229
+ specifierColumn,
22250
22230
  isInline: true,
22251
22231
  ...rest
22252
22232
  });
@@ -22284,7 +22264,7 @@ const createKitchen = ({
22284
22264
  const parentUrl = isOriginalPosition ? urlInfo.url : urlInfo.generatedUrl;
22285
22265
  const parentContent = isOriginalPosition ? urlInfo.originalContent : urlInfo.content;
22286
22266
  return referenceUtils.update(reference, {
22287
- trace: stringifyUrlSite({
22267
+ trace: traceFromUrlSite({
22288
22268
  url: parentUrl,
22289
22269
  content: parentContent,
22290
22270
  line: specifierLine,
@@ -22309,7 +22289,7 @@ const createKitchen = ({
22309
22289
  line,
22310
22290
  column
22311
22291
  } = getCallerPosition();
22312
- trace = stringifyUrlSite({
22292
+ trace = traceFromUrlSite({
22313
22293
  url,
22314
22294
  line,
22315
22295
  column
@@ -22518,6 +22498,15 @@ const memoizeCook = cook => {
22518
22498
  };
22519
22499
  };
22520
22500
 
22501
+ const traceFromUrlSite = urlSite => {
22502
+ return {
22503
+ message: stringifyUrlSite(urlSite),
22504
+ url: urlSite.url,
22505
+ line: urlSite.line,
22506
+ column: urlSite.column
22507
+ };
22508
+ };
22509
+
22521
22510
  const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
22522
22511
  if (reference.shouldHandle) {
22523
22512
  urlInfo.shouldHandle = true;
@@ -22746,6 +22735,60 @@ const determineFileUrlForOutDirectory = ({
22746
22735
  // }
22747
22736
  // }
22748
22737
 
22738
+ const createSSEService = ({
22739
+ serverEventCallbackList
22740
+ }) => {
22741
+ const destroyCallbackList = createCallbackListNotifiedOnce();
22742
+ const cache = [];
22743
+ const sseRoomLimit = 100;
22744
+
22745
+ const getOrCreateSSERoom = request => {
22746
+ const htmlFileRelativeUrl = request.ressource.slice(1);
22747
+ const cacheEntry = cache.find(cacheEntryCandidate => cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl);
22748
+
22749
+ if (cacheEntry) {
22750
+ return cacheEntry.sseRoom;
22751
+ }
22752
+
22753
+ const sseRoom = createSSERoom({
22754
+ retryDuration: 2000,
22755
+ historyLength: 100,
22756
+ welcomeEventEnabled: true,
22757
+ effect: () => {
22758
+ return serverEventCallbackList.add(event => {
22759
+ sseRoom.sendEvent(event);
22760
+ });
22761
+ }
22762
+ });
22763
+ const removeSSECleanupCallback = destroyCallbackList.add(() => {
22764
+ removeSSECleanupCallback();
22765
+ sseRoom.close();
22766
+ });
22767
+ cache.push({
22768
+ htmlFileRelativeUrl,
22769
+ sseRoom,
22770
+ cleanup: () => {
22771
+ removeSSECleanupCallback();
22772
+ sseRoom.close();
22773
+ }
22774
+ });
22775
+
22776
+ if (cache.length >= sseRoomLimit) {
22777
+ const firstCacheEntry = cache.shift();
22778
+ firstCacheEntry.cleanup();
22779
+ }
22780
+
22781
+ return sseRoom;
22782
+ };
22783
+
22784
+ return {
22785
+ getOrCreateSSERoom,
22786
+ destroy: () => {
22787
+ destroyCallbackList.notify();
22788
+ }
22789
+ };
22790
+ };
22791
+
22749
22792
  const memoizeByFirstArgument = compute => {
22750
22793
  const urlCache = new Map();
22751
22794
 
@@ -22798,7 +22841,10 @@ const createFileService = ({
22798
22841
  rootDirectoryUrl,
22799
22842
  urlGraph,
22800
22843
  kitchen,
22801
- scenario
22844
+ scenario,
22845
+ onParseError,
22846
+ onFileNotFound,
22847
+ onUnexpectedError
22802
22848
  }) => {
22803
22849
  kitchen.pluginController.addHook("serve");
22804
22850
  kitchen.pluginController.addHook("augmentResponse");
@@ -22838,7 +22884,9 @@ const createFileService = ({
22838
22884
 
22839
22885
  if (!reference) {
22840
22886
  const entryPoint = kitchen.injectReference({
22841
- trace: parentUrl || rootDirectoryUrl,
22887
+ trace: {
22888
+ message: parentUrl || rootDirectoryUrl
22889
+ },
22842
22890
  parentUrl: parentUrl || rootDirectoryUrl,
22843
22891
  type: "http_request",
22844
22892
  specifier: request.ressource
@@ -22918,10 +22966,18 @@ const createFileService = ({
22918
22966
  const code = e.code;
22919
22967
 
22920
22968
  if (code === "PARSE_ERROR") {
22921
- // let the browser re-throw the syntax error
22969
+ onParseError({
22970
+ reason: e.reason,
22971
+ message: e.message,
22972
+ url: e.url,
22973
+ line: e.line,
22974
+ column: e.column,
22975
+ contentFrame: e.contentFrame
22976
+ });
22922
22977
  return {
22923
22978
  url: reference.url,
22924
22979
  status: 200,
22980
+ // let the browser re-throw the syntax error
22925
22981
  statusText: e.reason,
22926
22982
  statusMessage: e.message,
22927
22983
  headers: {
@@ -22952,6 +23008,14 @@ const createFileService = ({
22952
23008
  }
22953
23009
 
22954
23010
  if (code === "NOT_FOUND") {
23011
+ onFileNotFound({
23012
+ reason: e.reason,
23013
+ message: e.message,
23014
+ url: e.url,
23015
+ line: e.line,
23016
+ column: e.column,
23017
+ contentFrame: e.contentFrame
23018
+ });
22955
23019
  return {
22956
23020
  url: reference.url,
22957
23021
  status: 404,
@@ -22960,6 +23024,15 @@ const createFileService = ({
22960
23024
  };
22961
23025
  }
22962
23026
 
23027
+ onUnexpectedError({
23028
+ reason: e.reason,
23029
+ message: e.message,
23030
+ stack: e.stack,
23031
+ url: e.url,
23032
+ line: e.line,
23033
+ column: e.column,
23034
+ contentFrame: e.contentFrame
23035
+ });
22963
23036
  return {
22964
23037
  url: reference.url,
22965
23038
  status: 500,
@@ -23026,12 +23099,75 @@ const startOmegaServer = async ({
23026
23099
  kitchen
23027
23100
  }) => {
23028
23101
  const serverStopCallbackList = createCallbackListNotifiedOnce();
23102
+ const serverEventCallbackList = createCallbackList();
23103
+ const sseService = createSSEService({
23104
+ serverEventCallbackList
23105
+ });
23106
+
23107
+ const sendServerEvent = ({
23108
+ type,
23109
+ data
23110
+ }) => {
23111
+ serverEventCallbackList.notify({
23112
+ type,
23113
+ data: JSON.stringify(data)
23114
+ });
23115
+ };
23116
+
23117
+ kitchen.pluginController.addHook("registerServerEvents");
23118
+ kitchen.pluginController.callHooks("registerServerEvents", {
23119
+ sendServerEvent
23120
+ }, {
23121
+ rootDirectoryUrl,
23122
+ urlGraph,
23123
+ scenario
23124
+ }, () => {});
23125
+
23126
+ const sendServerErrorEvent = event => {
23127
+ // setTimeout display first the error
23128
+ // dispatched on window by browser
23129
+ // then display the jsenv error
23130
+ setTimeout(() => {
23131
+ sendServerEvent(event);
23132
+ }, 10);
23133
+ };
23134
+
23029
23135
  const coreServices = {
23136
+ "service:server_events": request => {
23137
+ const {
23138
+ accept
23139
+ } = request.headers;
23140
+
23141
+ if (accept && accept.includes("text/event-stream")) {
23142
+ const room = sseService.getOrCreateSSERoom(request);
23143
+ return room.join(request);
23144
+ }
23145
+
23146
+ return null;
23147
+ },
23030
23148
  "service:file": createFileService({
23031
23149
  rootDirectoryUrl,
23032
23150
  urlGraph,
23033
23151
  kitchen,
23034
- scenario
23152
+ scenario,
23153
+ onFileNotFound: data => {
23154
+ sendServerErrorEvent({
23155
+ type: "file_not_found",
23156
+ data
23157
+ });
23158
+ },
23159
+ onParseError: data => {
23160
+ sendServerErrorEvent({
23161
+ type: "parse_error",
23162
+ data
23163
+ });
23164
+ },
23165
+ onUnexpectedError: data => {
23166
+ sendServerErrorEvent({
23167
+ type: "unexpected_error",
23168
+ data
23169
+ });
23170
+ }
23035
23171
  })
23036
23172
  };
23037
23173
  const server = await startServer({
@@ -23112,6 +23248,7 @@ const startOmegaServer = async ({
23112
23248
  }),
23113
23249
  onStop: reason => {
23114
23250
  onStop();
23251
+ sseService.destroy();
23115
23252
  serverStopCallbackList.notify(reason);
23116
23253
  }
23117
23254
  });
@@ -24003,7 +24140,7 @@ const reportToCoverage = async (report, {
24003
24140
  // coverDescription will generate empty coverage for files
24004
24141
  // that were suppose to be coverage but were not.
24005
24142
  if (executionResult.status === "completed" && executionResult.type === "node" && coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
24006
- logger.warn(`No "coverageFileUrl" from execution named "${executionName}" of ${file}`);
24143
+ logger.warn(`"${executionName}" execution of ${file} did not properly write coverage into ${executionResult.coverageFileUrl}`);
24007
24144
  }
24008
24145
  }
24009
24146
  });
@@ -24084,17 +24221,22 @@ const getCoverageFromReport = async ({
24084
24221
  const {
24085
24222
  coverageFileUrl
24086
24223
  } = executionResultForFileOnRuntime;
24224
+ let executionCoverage;
24087
24225
 
24088
- if (!coverageFileUrl) {
24089
- onMissing({
24090
- executionName,
24091
- file,
24092
- executionResult: executionResultForFileOnRuntime
24093
- });
24094
- return;
24095
- }
24226
+ try {
24227
+ executionCoverage = JSON.parse(String(readFileSync$1(new URL(coverageFileUrl))));
24228
+ } catch (e) {
24229
+ if (e.code === "ENOENT" || e.name === "SyntaxError") {
24230
+ onMissing({
24231
+ executionName,
24232
+ file,
24233
+ executionResult: executionResultForFileOnRuntime
24234
+ });
24235
+ return;
24236
+ }
24096
24237
 
24097
- const executionCoverage = JSON.parse(String(readFileSync$1(new URL(coverageFileUrl))));
24238
+ throw e;
24239
+ }
24098
24240
 
24099
24241
  if (isV8Coverage(executionCoverage)) {
24100
24242
  v8Coverage = v8Coverage ? composeTwoV8Coverages(v8Coverage, executionCoverage) : executionCoverage;
@@ -24127,7 +24269,7 @@ const run = async ({
24127
24269
  runtime,
24128
24270
  runtimeParams
24129
24271
  }) => {
24130
- let result = {};
24272
+ const result = {};
24131
24273
  const callbacks = [];
24132
24274
  const onConsoleRef = {
24133
24275
  current: () => {}
@@ -24145,18 +24287,16 @@ const run = async ({
24145
24287
  const timeoutAbortSource = runOperation.timeout(allocatedMs);
24146
24288
  callbacks.push(() => {
24147
24289
  if (result.status === "errored" && Abort.isAbortError(result.error) && timeoutAbortSource.signal.aborted) {
24148
- result = {
24149
- status: "timedout"
24150
- };
24290
+ result.status = "timedout";
24291
+ delete result.error;
24151
24292
  }
24152
24293
  });
24153
24294
  }
24154
24295
 
24155
24296
  callbacks.push(() => {
24156
24297
  if (result.status === "errored" && Abort.isAbortError(result.error)) {
24157
- result = {
24158
- status: "aborted"
24159
- };
24298
+ result.status = "aborted";
24299
+ delete result.error;
24160
24300
  }
24161
24301
  });
24162
24302
  const consoleCalls = [];
@@ -24185,6 +24325,22 @@ const run = async ({
24185
24325
  callbacks.push(() => {
24186
24326
  result.consoleCalls = consoleCalls;
24187
24327
  });
24328
+ } // we do not keep coverage in memory, it can grow very big
24329
+ // instead we store it on the filesystem
24330
+ // and they can be read later at "coverageFileUrl"
24331
+
24332
+
24333
+ let coverageFileUrl;
24334
+
24335
+ if (coverageEnabled) {
24336
+ coverageFileUrl = new URL(`./${runtime.name}/${cuid()}.json`, coverageTempDirectoryUrl).href;
24337
+ await ensureParentDirectories(coverageFileUrl);
24338
+
24339
+ if (coverageEnabled) {
24340
+ result.coverageFileUrl = coverageFileUrl; // written within the child_process/worker_thread or during runtime.run()
24341
+ // for browsers
24342
+ // (because it takes time to serialize and transfer the coverage object)
24343
+ }
24188
24344
  }
24189
24345
 
24190
24346
  const startMs = Date.now();
@@ -24209,7 +24365,9 @@ const run = async ({
24209
24365
  signal: runOperation.signal,
24210
24366
  logger,
24211
24367
  ...runtimeParams,
24368
+ collectConsole,
24212
24369
  collectPerformance,
24370
+ coverageFileUrl,
24213
24371
  keepRunning,
24214
24372
  stopSignal,
24215
24373
  onConsole: log => onConsoleRef.current(log)
@@ -24234,8 +24392,7 @@ const run = async ({
24234
24392
  status,
24235
24393
  namespace,
24236
24394
  error,
24237
- performance,
24238
- coverage
24395
+ performance
24239
24396
  } = winner.data;
24240
24397
  result.status = status;
24241
24398
 
@@ -24249,27 +24406,13 @@ const run = async ({
24249
24406
  result.performance = performance;
24250
24407
  }
24251
24408
 
24252
- if (coverageEnabled) {
24253
- if (coverage) {
24254
- // we do not keep coverage in memory, it can grow very big
24255
- // instead we store it on the filesystem
24256
- // and they can be read later at "coverageFileUrl"
24257
- const coverageFileUrl = new URL(`./${runtime.name}/${cuid()}.json`, coverageTempDirectoryUrl);
24258
- writeFileSync(coverageFileUrl, JSON.stringify(coverage, null, " "));
24259
- result.coverageFileUrl = coverageFileUrl.href;
24260
- } else {// will eventually log a warning in report_to_coverage.js
24261
- }
24262
- }
24263
-
24264
24409
  callbacks.forEach(callback => {
24265
24410
  callback();
24266
24411
  });
24267
24412
  return result;
24268
24413
  } catch (e) {
24269
- result = {
24270
- status: "errored",
24271
- error: e
24272
- };
24414
+ result.status = "errored";
24415
+ result.error = e;
24273
24416
  callbacks.forEach(callback => {
24274
24417
  callback();
24275
24418
  });
@@ -24567,20 +24710,78 @@ const formatConsoleCalls = consoleCalls => {
24567
24710
  error: 0,
24568
24711
  log: 0
24569
24712
  };
24570
- let consoleOutput = ``;
24571
24713
  consoleCalls.forEach(consoleCall => {
24572
24714
  repartition[consoleCall.type]++;
24573
- const text = consoleCall.text;
24715
+ });
24716
+ const consoleOutput = formatConsoleOutput(consoleCalls);
24717
+ return `${ANSI.color(`-------- ${formatConsoleSummary(repartition)} --------`, ANSI.GREY)}
24718
+ ${consoleOutput}
24719
+ ${ANSI.color(`-------------------------`, ANSI.GREY)}`;
24720
+ };
24721
+
24722
+ const formatConsoleOutput = consoleCalls => {
24723
+ // inside Node.js you can do process.stdout.write()
24724
+ // and in that case the consoleCall is not suffixed with "\n"
24725
+ // we want to keep these calls together in the output
24726
+ const regroupedCalls = [];
24727
+ consoleCalls.forEach((consoleCall, index) => {
24728
+ if (index === 0) {
24729
+ regroupedCalls.push(consoleCall);
24730
+ return;
24731
+ }
24732
+
24733
+ const previousCall = consoleCalls[index - 1];
24734
+
24735
+ if (previousCall.type !== consoleCall.type) {
24736
+ regroupedCalls.push(consoleCall);
24737
+ return;
24738
+ }
24739
+
24740
+ if (previousCall.text.endsWith("\n")) {
24741
+ regroupedCalls.push(consoleCall);
24742
+ return;
24743
+ }
24744
+
24745
+ if (previousCall.text.endsWith("\r")) {
24746
+ regroupedCalls.push(consoleCall);
24747
+ return;
24748
+ }
24749
+
24750
+ const previousRegroupedCallIndex = regroupedCalls.length - 1;
24751
+ const previousRegroupedCall = regroupedCalls[previousRegroupedCallIndex];
24752
+ previousRegroupedCall.text = `${previousRegroupedCall.text}${consoleCall.text}`;
24753
+ });
24754
+ let consoleOutput = ``;
24755
+ regroupedCalls.forEach((regroupedCall, index) => {
24756
+ const text = regroupedCall.text;
24574
24757
  const textFormatted = prefixFirstAndIndentRemainingLines({
24575
- prefix: CONSOLE_ICONS[consoleCall.type],
24758
+ prefix: CONSOLE_ICONS[regroupedCall.type],
24576
24759
  text,
24577
- trimLastLine: consoleCall === consoleCalls[consoleCalls.length - 1]
24760
+ trimLastLine: index === regroupedCalls.length - 1
24578
24761
  });
24579
24762
  consoleOutput += textFormatted;
24580
24763
  });
24581
- return `${ANSI.color(`-------- ${formatConsoleSummary(repartition)} --------`, ANSI.GREY)}
24582
- ${consoleOutput}
24583
- ${ANSI.color(`-------------------------`, ANSI.GREY)}`;
24764
+ return consoleOutput;
24765
+ };
24766
+
24767
+ const prefixFirstAndIndentRemainingLines = ({
24768
+ prefix,
24769
+ text,
24770
+ trimLastLine
24771
+ }) => {
24772
+ const lines = text.split(/\r?\n/);
24773
+ const firstLine = lines.shift();
24774
+ let result = `${prefix} ${firstLine}`;
24775
+ let i = 0;
24776
+ const indentation = ` `;
24777
+
24778
+ while (i < lines.length) {
24779
+ const line = lines[i].trim();
24780
+ i++;
24781
+ result += line.length ? `\n${indentation}${line}` : trimLastLine && i === lines.length ? "" : `\n`;
24782
+ }
24783
+
24784
+ return result;
24584
24785
  };
24585
24786
 
24586
24787
  const CONSOLE_ICONS = {
@@ -24623,26 +24824,6 @@ const formatConsoleSummary = repartition => {
24623
24824
  return `console (${parts.join(" ")})`;
24624
24825
  };
24625
24826
 
24626
- const prefixFirstAndIndentRemainingLines = ({
24627
- prefix,
24628
- text,
24629
- trimLastLine
24630
- }) => {
24631
- const lines = text.split(/\r?\n/);
24632
- const firstLine = lines.shift();
24633
- let result = `${prefix} ${firstLine}`;
24634
- let i = 0;
24635
- const indentation = ` `;
24636
-
24637
- while (i < lines.length) {
24638
- const line = lines[i].trim();
24639
- i++;
24640
- result += line.length ? `\n${indentation}${line}` : trimLastLine && i === lines.length ? "" : `\n`;
24641
- }
24642
-
24643
- return result;
24644
- };
24645
-
24646
24827
  const formatExecution = ({
24647
24828
  label,
24648
24829
  details = {},
@@ -24767,7 +24948,7 @@ const executePlan = async (plan, {
24767
24948
  } else {
24768
24949
  coverageMethodForNodeJs = "Profiler";
24769
24950
  logger.warn(createDetailedMessage$1(`process.env.NODE_V8_COVERAGE is required to generate coverage for Node.js subprocesses`, {
24770
- "suggestion": `Preprend NODE_V8_COVERAGE=.coverage/node to the command executing this process`,
24951
+ "suggestion": `set process.env.NODE_V8_COVERAGE`,
24771
24952
  "suggestion 2": `use coverageMethodForNodeJs: "Profiler". But it means coverage for child_process and worker_thread cannot be collected`
24772
24953
  }));
24773
24954
  }
@@ -24845,7 +25026,7 @@ const executePlan = async (plan, {
24845
25026
  getCustomBabelPlugins: ({
24846
25027
  clientRuntimeCompat
24847
25028
  }) => {
24848
- if (coverageEnabled && Object.keys(clientRuntimeCompat)[0] !== "chrome") {
25029
+ if (coverageEnabled && (coverageMethodForBrowsers !== "playwright_api" || Object.keys(clientRuntimeCompat)[0] !== "chrome")) {
24849
25030
  return {
24850
25031
  "transform-instrument": [babelPluginInstrument, {
24851
25032
  rootDirectoryUrl,
@@ -25269,8 +25450,7 @@ const executeTestPlan = async ({
25269
25450
  },
25270
25451
  coverageIncludeMissing = true,
25271
25452
  coverageAndExecutionAllowed = false,
25272
- coverageMethodForNodeJs = "NODE_V8_COVERAGE",
25273
- // "Profiler" also accepted
25453
+ coverageMethodForNodeJs = process.env.NODE_V8_COVERAGE ? "NODE_V8_COVERAGE" : "Profiler",
25274
25454
  coverageMethodForBrowsers = "playwright_api",
25275
25455
  // "istanbul" also accepted
25276
25456
  coverageV8ConflictWarning = true,
@@ -25508,6 +25688,7 @@ const createRuntimeFromPlaywright = ({
25508
25688
  coverageEnabled = false,
25509
25689
  coverageConfig,
25510
25690
  coverageMethodForBrowsers,
25691
+ coverageFileUrl,
25511
25692
  stopAfterAllSignal,
25512
25693
  stopSignal,
25513
25694
  keepRunning,
@@ -25590,13 +25771,14 @@ const createRuntimeFromPlaywright = ({
25590
25771
  }
25591
25772
  };
25592
25773
 
25593
- let resultTransformer = result => result;
25774
+ const result = {};
25775
+ const callbacks = [];
25594
25776
 
25595
25777
  if (coverageEnabled) {
25596
25778
  if (coveragePlaywrightAPIAvailable && coverageMethodForBrowsers === "playwright_api") {
25597
25779
  await page.coverage.startJSCoverage({// reportAnonymousScripts: true,
25598
25780
  });
25599
- resultTransformer = composeTransformer(resultTransformer, async result => {
25781
+ callbacks.push(async () => {
25600
25782
  const v8CoveragesWithWebUrls = await page.coverage.stopJSCoverage(); // we convert urls starting with http:// to file:// because we later
25601
25783
  // convert the url to filesystem path in istanbulCoverageFromV8Coverage function
25602
25784
 
@@ -25617,23 +25799,20 @@ const createRuntimeFromPlaywright = ({
25617
25799
  rootDirectoryUrl,
25618
25800
  coverageConfig
25619
25801
  });
25620
- return { ...result,
25621
- coverage
25622
- };
25802
+ writeFileSync$1(new URL(coverageFileUrl), JSON.stringify(coverage, null, " "));
25623
25803
  });
25624
25804
  } else {
25625
- resultTransformer = composeTransformer(resultTransformer, async result => {
25805
+ callbacks.push(() => {
25626
25806
  const scriptExecutionResults = result.namespace;
25627
25807
 
25628
25808
  if (scriptExecutionResults) {
25629
- result.coverage = generateCoverageForPage(scriptExecutionResults);
25809
+ const coverage = generateCoverageForPage(scriptExecutionResults) || {};
25810
+ writeFileSync$1(new URL(coverageFileUrl), JSON.stringify(coverage, null, " "));
25630
25811
  }
25631
-
25632
- return result;
25633
25812
  });
25634
25813
  }
25635
25814
  } else {
25636
- resultTransformer = composeTransformer(resultTransformer, result => {
25815
+ callbacks.push(() => {
25637
25816
  const scriptExecutionResults = result.namespace;
25638
25817
 
25639
25818
  if (scriptExecutionResults) {
@@ -25641,13 +25820,11 @@ const createRuntimeFromPlaywright = ({
25641
25820
  delete scriptExecutionResults[fileRelativeUrl].coverage;
25642
25821
  });
25643
25822
  }
25644
-
25645
- return result;
25646
25823
  });
25647
25824
  }
25648
25825
 
25649
25826
  if (collectPerformance) {
25650
- resultTransformer = composeTransformer(resultTransformer, async result => {
25827
+ callbacks.push(async () => {
25651
25828
  const performance = await page.evaluate(
25652
25829
  /* eslint-disable no-undef */
25653
25830
 
@@ -25676,7 +25853,6 @@ const createRuntimeFromPlaywright = ({
25676
25853
  /* eslint-enable no-undef */
25677
25854
  );
25678
25855
  result.performance = performance;
25679
- return result;
25680
25856
  });
25681
25857
  }
25682
25858
 
@@ -25770,7 +25946,7 @@ const createRuntimeFromPlaywright = ({
25770
25946
  await page.goto(fileClientUrl, {
25771
25947
  timeout: 0
25772
25948
  });
25773
- const result = await page.evaluate(
25949
+ const returnValue = await page.evaluate(
25774
25950
  /* eslint-disable no-undef */
25775
25951
 
25776
25952
  /* istanbul ignore next */
@@ -25786,12 +25962,12 @@ const createRuntimeFromPlaywright = ({
25786
25962
  const {
25787
25963
  status,
25788
25964
  scriptExecutionResults
25789
- } = result;
25965
+ } = returnValue;
25790
25966
 
25791
25967
  if (status === "errored") {
25792
25968
  const {
25793
25969
  exceptionSource
25794
- } = result;
25970
+ } = returnValue;
25795
25971
  const error = evalException(exceptionSource, {
25796
25972
  rootDirectoryUrl,
25797
25973
  server,
@@ -25842,16 +26018,32 @@ const createRuntimeFromPlaywright = ({
25842
26018
  return winner.data;
25843
26019
  };
25844
26020
 
25845
- let result;
25846
-
25847
26021
  try {
25848
- result = await getResult();
25849
- result = await resultTransformer(result);
26022
+ const {
26023
+ status,
26024
+ error,
26025
+ namespace,
26026
+ performance
26027
+ } = await getResult();
26028
+ result.status = status;
26029
+
26030
+ if (status === "errored") {
26031
+ result.error = error;
26032
+ } else {
26033
+ result.namespace = namespace;
26034
+ }
26035
+
26036
+ if (collectPerformance) {
26037
+ result.performance = performance;
26038
+ }
26039
+
26040
+ await callbacks.reduce(async (previous, callback) => {
26041
+ await previous;
26042
+ await callback();
26043
+ }, Promise.resolve());
25850
26044
  } catch (e) {
25851
- result = {
25852
- status: "errored",
25853
- error: e
25854
- };
26045
+ result.status = "errored";
26046
+ result.error = e;
25855
26047
  }
25856
26048
 
25857
26049
  if (keepRunning) {
@@ -25969,13 +26161,6 @@ const isTargetClosedError = error => {
25969
26161
  return false;
25970
26162
  };
25971
26163
 
25972
- const composeTransformer = (previousTransformer, transformer) => {
25973
- return async value => {
25974
- const transformedValue = await previousTransformer(value);
25975
- return transformer(transformedValue);
25976
- };
25977
- };
25978
-
25979
26164
  const extractTextFromConsoleMessage = consoleMessage => {
25980
26165
  return consoleMessage.text(); // ensure we use a string so that istanbul won't try
25981
26166
  // to put any coverage statement inside it
@@ -26385,6 +26570,7 @@ nodeChildProcess.run = async ({
26385
26570
  coverageEnabled = false,
26386
26571
  coverageConfig,
26387
26572
  coverageMethodForNodeJs,
26573
+ coverageFileUrl,
26388
26574
  collectPerformance,
26389
26575
  env,
26390
26576
  debugPort,
@@ -26548,6 +26734,7 @@ nodeChildProcess.run = async ({
26548
26734
  coverageEnabled,
26549
26735
  coverageConfig,
26550
26736
  coverageMethodForNodeJs,
26737
+ coverageFileUrl,
26551
26738
  exitAfterAction: true
26552
26739
  }
26553
26740
  }
@@ -26728,10 +26915,12 @@ nodeWorkerThread.run = async ({
26728
26915
  keepRunning,
26729
26916
  stopSignal,
26730
26917
  onConsole,
26918
+ collectConsole = false,
26919
+ collectPerformance,
26920
+ coverageEnabled = false,
26731
26921
  coverageConfig,
26732
26922
  coverageMethodForNodeJs,
26733
- coverageEnabled = false,
26734
- collectPerformance,
26923
+ coverageFileUrl,
26735
26924
  env,
26736
26925
  debugPort,
26737
26926
  debugMode,
@@ -26797,11 +26986,14 @@ nodeWorkerThread.run = async ({
26797
26986
  const stop = memoize(async () => {
26798
26987
  // read all stdout before terminating
26799
26988
  // (no need for stderr because it's sync)
26800
- while (workerThread.stdout.read() !== null) {}
26989
+ if (collectConsole) {
26990
+ while (workerThread.stdout.read() !== null) {}
26991
+
26992
+ await new Promise(resolve => {
26993
+ setTimeout(resolve, 50);
26994
+ });
26995
+ }
26801
26996
 
26802
- await new Promise(resolve => {
26803
- setTimeout(resolve);
26804
- });
26805
26997
  await workerThread.terminate();
26806
26998
  });
26807
26999
  const winnerPromise = new Promise(resolve => {
@@ -26841,6 +27033,7 @@ nodeWorkerThread.run = async ({
26841
27033
  coverageEnabled,
26842
27034
  coverageConfig,
26843
27035
  coverageMethodForNodeJs,
27036
+ coverageFileUrl,
26844
27037
  exitAfterAction: true
26845
27038
  }
26846
27039
  }
@@ -27098,9 +27291,6 @@ ${createRepartitionMessage(graphReport)}
27098
27291
  };
27099
27292
 
27100
27293
  const createUrlGraphReport = urlGraph => {
27101
- const {
27102
- urlInfos
27103
- } = urlGraph;
27104
27294
  const countGroups = {
27105
27295
  sourcemaps: 0,
27106
27296
  html: 0,
@@ -27119,15 +27309,14 @@ const createUrlGraphReport = urlGraph => {
27119
27309
  other: 0,
27120
27310
  total: 0
27121
27311
  };
27122
- Object.keys(urlInfos).forEach(url => {
27123
- if (url.startsWith("data:")) {
27312
+ urlGraph.urlInfoMap.forEach(urlInfo => {
27313
+ if (urlInfo.url.startsWith("data:")) {
27124
27314
  return;
27125
- }
27126
-
27127
- const urlInfo = urlInfos[url]; // ignore:
27315
+ } // ignore:
27128
27316
  // - inline files: they are already taken into account in the file where they appear
27129
27317
  // - ignored files: we don't know their content
27130
27318
 
27319
+
27131
27320
  if (urlInfo.isInline || !urlInfo.shouldHandle) {
27132
27321
  return;
27133
27322
  } // file loaded via import assertion are already inside the graph
@@ -27305,20 +27494,18 @@ const createRepartitionMessage = ({
27305
27494
 
27306
27495
  const GRAPH = {
27307
27496
  map: (graph, callback) => {
27308
- return Object.keys(graph.urlInfos).map(url => {
27309
- return callback(graph.urlInfos[url]);
27497
+ const array = [];
27498
+ graph.urlInfoMap.forEach(urlInfo => {
27499
+ array.push(callback(urlInfo));
27310
27500
  });
27501
+ return array;
27311
27502
  },
27312
27503
  forEach: (graph, callback) => {
27313
- Object.keys(graph.urlInfos).forEach(url => {
27314
- callback(graph.urlInfos[url], url);
27315
- });
27504
+ graph.urlInfoMap.forEach(callback);
27316
27505
  },
27317
27506
  filter: (graph, callback) => {
27318
27507
  const urlInfos = [];
27319
- Object.keys(graph.urlInfos).forEach(url => {
27320
- const urlInfo = graph.urlInfos[url];
27321
-
27508
+ graph.urlInfoMap.forEach(urlInfo => {
27322
27509
  if (callback(urlInfo)) {
27323
27510
  urlInfos.push(urlInfo);
27324
27511
  }
@@ -27326,10 +27513,16 @@ const GRAPH = {
27326
27513
  return urlInfos;
27327
27514
  },
27328
27515
  find: (graph, callback) => {
27329
- const urlFound = Object.keys(graph.urlInfos).find(url => {
27330
- return callback(graph.urlInfos[url]);
27331
- });
27332
- return graph.urlInfos[urlFound];
27516
+ let found = null;
27517
+
27518
+ for (const urlInfo of graph.urlInfoMap.values()) {
27519
+ if (callback(urlInfo)) {
27520
+ found = urlInfo;
27521
+ break;
27522
+ }
27523
+ }
27524
+
27525
+ return found;
27333
27526
  }
27334
27527
  };
27335
27528
 
@@ -27964,7 +28157,9 @@ build ${entryPointKeys.length} entry points`);
27964
28157
  startLoading: cookEntryFile => {
27965
28158
  Object.keys(entryPoints).forEach(key => {
27966
28159
  const [, entryUrlInfo] = cookEntryFile({
27967
- trace: `"${key}" in entryPoints parameter`,
28160
+ trace: {
28161
+ message: `"${key}" in entryPoints parameter`
28162
+ },
27968
28163
  type: "entry_point",
27969
28164
  specifier: key
27970
28165
  });
@@ -28460,7 +28655,9 @@ build ${entryPointKeys.length} entry points`);
28460
28655
  startLoading: cookEntryFile => {
28461
28656
  entryUrls.forEach(entryUrl => {
28462
28657
  const [, postBuildEntryUrlInfo] = cookEntryFile({
28463
- trace: `entryPoint`,
28658
+ trace: {
28659
+ message: `entryPoint`
28660
+ },
28464
28661
  type: "entry_point",
28465
28662
  specifier: entryUrl
28466
28663
  });
@@ -28475,7 +28672,7 @@ build ${entryPointKeys.length} entry points`);
28475
28672
 
28476
28673
  buildTask.done();
28477
28674
  logger.debug(`graph urls pre-versioning:
28478
- ${Object.keys(finalGraph.urlInfos).join("\n")}`);
28675
+ ${Array.from(finalGraph.urlInfoMap.keys()).join("\n")}`);
28479
28676
 
28480
28677
  if (versioning) {
28481
28678
  await applyUrlVersioning({
@@ -28731,7 +28928,7 @@ const applyUrlVersioning = async ({
28731
28928
  });
28732
28929
 
28733
28930
  try {
28734
- const urlsSorted = sortByDependencies(finalGraph.urlInfos);
28931
+ const urlsSorted = sortByDependencies(finalGraph.toObject());
28735
28932
  urlsSorted.forEach(url => {
28736
28933
  if (url.startsWith("data:")) {
28737
28934
  return;