@jsenv/core 23.1.4 → 23.3.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 (66) hide show
  1. package/dist/jsenv_browser_system.js +36 -99
  2. package/dist/jsenv_browser_system.js.map +12 -21
  3. package/dist/jsenv_compile_proxy.js +18 -82
  4. package/dist/jsenv_compile_proxy.js.map +11 -21
  5. package/dist/jsenv_exploring_index.js +127 -274
  6. package/dist/jsenv_exploring_index.js.map +76 -90
  7. package/dist/jsenv_exploring_redirector.js +21 -89
  8. package/dist/jsenv_exploring_redirector.js.map +13 -25
  9. package/dist/jsenv_toolbar.js +81 -149
  10. package/dist/jsenv_toolbar.js.map +50 -61
  11. package/dist/jsenv_toolbar_injector.js +56 -124
  12. package/dist/jsenv_toolbar_injector.js.map +27 -41
  13. package/package.json +15 -19
  14. package/src/buildProject.js +130 -122
  15. package/src/execute.js +47 -47
  16. package/src/executeTestPlan.js +107 -125
  17. package/src/importUsingChildProcess.js +2 -1
  18. package/src/internal/browser-launcher/executeHtmlFile.js +32 -12
  19. package/src/internal/browser-utils/fetch-browser.js +4 -29
  20. package/src/internal/browser-utils/fetchUsingXHR.js +5 -7
  21. package/src/internal/building/buildUsingRollup.js +59 -24
  22. package/src/internal/building/build_logs.js +7 -6
  23. package/src/internal/building/createJsenvRollupPlugin.js +10 -33
  24. package/src/internal/building/ressource_builder.js +3 -6
  25. package/src/internal/building/sourcemap_loader.js +4 -5
  26. package/src/internal/building/url_fetcher.js +2 -5
  27. package/src/internal/building/url_loader.js +3 -6
  28. package/src/internal/building/url_trace.js +3 -4
  29. package/src/internal/compiling/compileFile.js +1 -2
  30. package/src/internal/compiling/createCompiledFileService.js +12 -9
  31. package/src/internal/compiling/startCompileServer.js +85 -133
  32. package/src/internal/executing/coverage/generateCoverageJsonFile.js +20 -3
  33. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +18 -30
  34. package/src/internal/executing/coverage/reportToCoverage.js +44 -24
  35. package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +2 -15
  36. package/src/internal/executing/createSummaryLog.js +48 -37
  37. package/src/internal/executing/executeConcurrently.js +96 -52
  38. package/src/internal/executing/executePlan.js +93 -67
  39. package/src/internal/executing/executionLogs.js +31 -38
  40. package/src/internal/executing/execution_colors.js +9 -0
  41. package/src/internal/executing/generateExecutionSteps.js +3 -2
  42. package/src/internal/executing/launchAndExecute.js +207 -271
  43. package/src/internal/exploring/fetchExploringJson.js +3 -4
  44. package/src/internal/fetchUrl.js +6 -2
  45. package/src/internal/logs/msAsDuration.js +1 -1
  46. package/src/internal/node-launcher/createChildProcessOptions.js +4 -5
  47. package/src/internal/node-launcher/createControllableNodeProcess.js +120 -229
  48. package/src/internal/node-launcher/kill_process_tree.js +76 -0
  49. package/src/internal/node-launcher/nodeControllableFile.mjs +16 -10
  50. package/src/internal/{promise_track_race.js → promise_race.js} +2 -2
  51. package/src/internal/runtime/s.js +25 -24
  52. package/src/internal/toolbar/util/animation.js +3 -7
  53. package/src/internal/toolbar/util/fetching.js +1 -30
  54. package/src/jsenvServiceWorkerFinalizer.js +1 -2
  55. package/src/launchBrowser.js +146 -139
  56. package/src/launchNode.js +29 -17
  57. package/src/playwright_browser_versions.js +3 -3
  58. package/src/requireUsingChildProcess.js +2 -1
  59. package/src/startExploring.js +55 -74
  60. package/src/internal/createCallbackList.js +0 -21
  61. package/src/internal/executeJsenvAsyncFunction.js +0 -34
  62. package/src/internal/executing/logUtils.js +0 -30
  63. package/src/internal/executing/writeLog.js +0 -106
  64. package/src/internal/executing/writeLog.test-manual.js +0 -62
  65. package/src/internal/logs/log_style.js +0 -52
  66. package/src/internal/trackRessources.js +0 -23
@@ -1,17 +1,14 @@
1
- /* eslint-disable import/max-dependencies */
2
1
  import { readFileSync } from "node:fs"
3
- import {
4
- createCancellationToken,
5
- createCancellationSource,
6
- composeCancellationToken,
7
- } from "@jsenv/cancellation"
8
2
  import {
9
3
  jsenvAccessControlAllowedHeaders,
10
4
  startServer,
11
- serveFile,
5
+ fetchFileSystem,
12
6
  createSSERoom,
13
7
  composeServicesWithTiming,
14
8
  urlToContentType,
9
+ pluginServerTiming,
10
+ pluginRequestWaitingCheck,
11
+ pluginCORS,
15
12
  } from "@jsenv/server"
16
13
  import { createLogger, createDetailedMessage } from "@jsenv/logger"
17
14
  import {
@@ -22,17 +19,19 @@ import {
22
19
  readFile,
23
20
  writeFile,
24
21
  ensureEmptyDirectory,
25
- registerFileLifecycle,
26
22
  registerDirectoryLifecycle,
27
23
  urlIsInsideOf,
28
24
  urlToBasename,
29
25
  } from "@jsenv/filesystem"
26
+ import {
27
+ createCallbackList,
28
+ createCallbackListNotifiedOnce,
29
+ } from "@jsenv/abort"
30
30
 
31
31
  import { isBrowserPartOfSupportedRuntimes } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
32
32
  import { loadBabelPluginMapFromFile } from "./load_babel_plugin_map_from_file.js"
33
33
  import { extractSyntaxBabelPluginMap } from "./babel_plugins.js"
34
34
  import { generateGroupMap } from "../generateGroupMap/generateGroupMap.js"
35
- import { createCallbackList } from "../createCallbackList.js"
36
35
  import {
37
36
  jsenvCompileProxyFileInfo,
38
37
  sourcemapMainFileInfo,
@@ -48,7 +47,8 @@ import { urlIsCompilationAsset } from "./compile-directory/compile-asset.js"
48
47
  import { createTransformHtmlSourceFileService } from "./html_source_file_service.js"
49
48
 
50
49
  export const startCompileServer = async ({
51
- cancellationToken = createCancellationToken(),
50
+ signal = new AbortController().signal,
51
+ handleSIGINT,
52
52
  compileServerLogLevel,
53
53
 
54
54
  projectDirectoryUrl,
@@ -89,7 +89,7 @@ export const startCompileServer = async ({
89
89
  compileServerIp = "0.0.0.0",
90
90
  compileServerPort = 0,
91
91
  keepProcessAlive = false,
92
- stopOnPackageVersionChange = false,
92
+ onStop = () => {},
93
93
 
94
94
  // remaining options
95
95
  runtimeSupport,
@@ -218,15 +218,12 @@ export const startCompileServer = async ({
218
218
  ...babelPluginMap,
219
219
  }
220
220
 
221
- const serverStopCancellationSource = createCancellationSource()
221
+ const serverStopCallbackList = createCallbackListNotifiedOnce()
222
222
 
223
223
  let projectFileRequestedCallback = () => {}
224
224
  if (livereloadSSE) {
225
225
  const sseSetup = setupServerSentEventsForLivereload({
226
- cancellationToken: composeCancellationToken(
227
- cancellationToken,
228
- serverStopCancellationSource.token,
229
- ),
226
+ serverStopCallbackList,
230
227
  projectDirectoryUrl,
231
228
  jsenvDirectoryRelativeUrl,
232
229
  outDirectoryRelativeUrl,
@@ -236,7 +233,7 @@ export const startCompileServer = async ({
236
233
 
237
234
  projectFileRequestedCallback = sseSetup.projectFileRequestedCallback
238
235
  const serveSSEForLivereload = createSSEForLivereloadService({
239
- cancellationToken,
236
+ serverStopCallbackList,
240
237
  outDirectoryRelativeUrl,
241
238
  trackMainAndDependencies: sseSetup.trackMainAndDependencies,
242
239
  })
@@ -302,7 +299,6 @@ export const startCompileServer = async ({
302
299
  projectDirectoryUrl,
303
300
  }),
304
301
  "service:compiled file": createCompiledFileService({
305
- cancellationToken,
306
302
  logger,
307
303
 
308
304
  projectDirectoryUrl,
@@ -351,7 +347,13 @@ export const startCompileServer = async ({
351
347
  }
352
348
 
353
349
  const compileServer = await startServer({
354
- cancellationToken,
350
+ signal,
351
+ stopOnExit: false,
352
+ stopOnSIGINT: handleSIGINT,
353
+ stopOnInternalError: false,
354
+ sendServerInternalErrorDetails: true,
355
+ keepProcessAlive,
356
+
355
357
  logLevel: compileServerLogLevel,
356
358
 
357
359
  protocol: compileServerProtocol,
@@ -360,44 +362,32 @@ export const startCompileServer = async ({
360
362
  serverCertificatePrivateKey: compileServerPrivateKey,
361
363
  ip: compileServerIp,
362
364
  port: compileServerPort,
363
- sendServerTiming: true,
364
- // nagle: false,
365
- requestWaitingMs: 60 * 1000,
366
- sendServerInternalErrorDetails: true,
365
+ plugins: {
366
+ ...pluginCORS({
367
+ accessControlAllowRequestOrigin: true,
368
+ accessControlAllowRequestMethod: true,
369
+ accessControlAllowRequestHeaders: true,
370
+ accessControlAllowedRequestHeaders: [
371
+ ...jsenvAccessControlAllowedHeaders,
372
+ "x-jsenv-execution-id",
373
+ ],
374
+ accessControlAllowCredentials: true,
375
+ }),
376
+ ...pluginServerTiming,
377
+ ...pluginRequestWaitingCheck({
378
+ requestWaitingMs: 60 * 1000,
379
+ }),
380
+ },
367
381
  requestToResponse: composeServicesWithTiming({
368
382
  ...customServices,
369
383
  ...jsenvServices,
370
384
  }),
371
- accessControlAllowRequestOrigin: true,
372
- accessControlAllowRequestMethod: true,
373
- accessControlAllowRequestHeaders: true,
374
- accessControlAllowedRequestHeaders: [
375
- ...jsenvAccessControlAllowedHeaders,
376
- "x-jsenv-execution-id",
377
- ],
378
- accessControlAllowCredentials: true,
379
- keepProcessAlive,
385
+ onStop: (reason) => {
386
+ onStop()
387
+ serverStopCallbackList.notify(reason)
388
+ },
380
389
  })
381
390
 
382
- compileServer.stoppedPromise.then(serverStopCancellationSource.cancel)
383
-
384
- if (stopOnPackageVersionChange) {
385
- const stopListeningJsenvPackageVersionChange =
386
- listenJsenvPackageVersionChange({
387
- projectDirectoryUrl,
388
- jsenvDirectoryRelativeUrl,
389
- onJsenvPackageVersionChange: () => {
390
- compileServer.stop(STOP_REASON_PACKAGE_VERSION_CHANGED)
391
- },
392
- })
393
- compileServer.stoppedPromise.then(
394
- () => {
395
- stopListeningJsenvPackageVersionChange()
396
- },
397
- () => {},
398
- )
399
- }
400
-
401
391
  return {
402
392
  jsenvDirectoryRelativeUrl,
403
393
  outDirectoryRelativeUrl,
@@ -571,7 +561,7 @@ const compareValueJson = (left, right) => {
571
561
  *
572
562
  */
573
563
  const setupServerSentEventsForLivereload = ({
574
- cancellationToken,
564
+ serverStopCallbackList,
575
565
  projectDirectoryUrl,
576
566
  jsenvDirectoryRelativeUrl,
577
567
  outDirectoryRelativeUrl,
@@ -594,7 +584,7 @@ const setupServerSentEventsForLivereload = ({
594
584
  return
595
585
  }
596
586
 
597
- projectFileRequested.notify(relativeUrl, request)
587
+ projectFileRequested.notify({ relativeUrl, request })
598
588
  }
599
589
  const watchDescription = {
600
590
  ...livereloadWatchConfig,
@@ -617,7 +607,7 @@ const setupServerSentEventsForLivereload = ({
617
607
  recursive: true,
618
608
  },
619
609
  )
620
- cancellationToken.register(unregisterDirectoryLifecyle)
610
+ serverStopCallbackList.add(unregisterDirectoryLifecyle)
621
611
 
622
612
  const getDependencySet = (mainRelativeUrl) => {
623
613
  if (trackerMap.has(mainRelativeUrl)) {
@@ -630,7 +620,7 @@ const setupServerSentEventsForLivereload = ({
630
620
  }
631
621
 
632
622
  // each time a file is requested for the first time its dependencySet is computed
633
- projectFileRequested.register((mainRelativeUrl) => {
623
+ projectFileRequested.add(({ relativeUrl: mainRelativeUrl }) => {
634
624
  // for now no use case of livereloading on node.js
635
625
  // and for browsers only html file can be main files
636
626
  // this avoid collecting dependencies of non html files that will never be used
@@ -644,8 +634,8 @@ const setupServerSentEventsForLivereload = ({
644
634
  dependencySet.add(mainRelativeUrl)
645
635
  trackerMap.set(mainRelativeUrl, dependencySet)
646
636
 
647
- const unregisterDependencyRequested = projectFileRequested.register(
648
- (relativeUrl, request) => {
637
+ const removeDependencyRequestedCallback = projectFileRequested.add(
638
+ ({ relativeUrl, request }) => {
649
639
  if (dependencySet.has(relativeUrl)) {
650
640
  return
651
641
  }
@@ -668,10 +658,10 @@ const setupServerSentEventsForLivereload = ({
668
658
  dependencySet.add(relativeUrl)
669
659
  },
670
660
  )
671
- const unregisterMainRemoved = projectFileRemoved.register((relativeUrl) => {
661
+ const removeMainRemovedCallback = projectFileRemoved.add((relativeUrl) => {
672
662
  if (relativeUrl === mainRelativeUrl) {
673
- unregisterDependencyRequested()
674
- unregisterMainRemoved()
663
+ removeDependencyRequestedCallback()
664
+ removeMainRemovedCallback()
675
665
  trackerMap.delete(mainRelativeUrl)
676
666
  }
677
667
  })
@@ -683,19 +673,19 @@ const setupServerSentEventsForLivereload = ({
683
673
  ) => {
684
674
  livereloadLogger.debug(`track ${mainRelativeUrl} and its dependencies`)
685
675
 
686
- const unregisterModified = projectFileModified.register((relativeUrl) => {
676
+ const removeModifiedCallback = projectFileModified.add((relativeUrl) => {
687
677
  const dependencySet = getDependencySet(mainRelativeUrl)
688
678
  if (dependencySet.has(relativeUrl)) {
689
679
  modified(relativeUrl)
690
680
  }
691
681
  })
692
- const unregisterRemoved = projectFileRemoved.register((relativeUrl) => {
682
+ const removeRemovedCallback = projectFileRemoved.add((relativeUrl) => {
693
683
  const dependencySet = getDependencySet(mainRelativeUrl)
694
684
  if (dependencySet.has(relativeUrl)) {
695
685
  removed(relativeUrl)
696
686
  }
697
687
  })
698
- const unregisterAdded = projectFileAdded.register((relativeUrl) => {
688
+ const removeAddedCallback = projectFileAdded.add((relativeUrl) => {
699
689
  const dependencySet = getDependencySet(mainRelativeUrl)
700
690
  if (dependencySet.has(relativeUrl)) {
701
691
  added(relativeUrl)
@@ -706,9 +696,9 @@ const setupServerSentEventsForLivereload = ({
706
696
  livereloadLogger.debug(
707
697
  `stop tracking ${mainRelativeUrl} and its dependencies.`,
708
698
  )
709
- unregisterModified()
710
- unregisterRemoved()
711
- unregisterAdded()
699
+ removeModifiedCallback()
700
+ removeRemovedCallback()
701
+ removeAddedCallback()
712
702
  }
713
703
  }
714
704
 
@@ -773,11 +763,14 @@ const setupServerSentEventsForLivereload = ({
773
763
  }
774
764
  }
775
765
 
776
- return { projectFileRequestedCallback, trackMainAndDependencies }
766
+ return {
767
+ projectFileRequestedCallback,
768
+ trackMainAndDependencies,
769
+ }
777
770
  }
778
771
 
779
772
  const createSSEForLivereloadService = ({
780
- cancellationToken,
773
+ serverStopCallbackList,
781
774
  outDirectoryRelativeUrl,
782
775
  trackMainAndDependencies,
783
776
  }) => {
@@ -811,9 +804,8 @@ const createSSEForLivereloadService = ({
811
804
  },
812
805
  })
813
806
 
814
- const cancelRegistration = cancellationToken.register(() => {
815
- cancelRegistration.unregister()
816
-
807
+ const removeSSECleanupCallback = serverStopCallbackList.add(() => {
808
+ removeSSECleanupCallback()
817
809
  sseRoom.close()
818
810
  stopTracking()
819
811
  })
@@ -821,7 +813,7 @@ const createSSEForLivereloadService = ({
821
813
  mainFileRelativeUrl,
822
814
  sseRoom,
823
815
  cleanup: () => {
824
- cancelRegistration.unregister()
816
+ removeSSECleanupCallback()
825
817
  sseRoom.close()
826
818
  stopTracking()
827
819
  },
@@ -865,10 +857,13 @@ const createCompilationAssetFileService = ({ projectDirectoryUrl }) => {
865
857
  const { origin, ressource } = request
866
858
  const requestUrl = `${origin}${ressource}`
867
859
  if (urlIsCompilationAsset(requestUrl)) {
868
- return serveFile(request, {
869
- rootDirectoryUrl: projectDirectoryUrl,
870
- etagEnabled: true,
871
- })
860
+ return fetchFileSystem(
861
+ new URL(request.ressource.slice(1), projectDirectoryUrl),
862
+ {
863
+ headers: request.headers,
864
+ etagEnabled: true,
865
+ },
866
+ )
872
867
  }
873
868
  return null
874
869
  }
@@ -924,10 +919,13 @@ const createSourceFileService = ({
924
919
  const relativeUrl = ressource.slice(1)
925
920
  projectFileRequestedCallback(relativeUrl, request)
926
921
 
927
- const responsePromise = serveFile(request, {
928
- rootDirectoryUrl: projectDirectoryUrl,
929
- etagEnabled: projectFileEtagEnabled,
930
- })
922
+ const responsePromise = fetchFileSystem(
923
+ new URL(request.ressource.slice(1), projectDirectoryUrl),
924
+ {
925
+ headers: request.headers,
926
+ etagEnabled: projectFileEtagEnabled,
927
+ },
928
+ )
931
929
 
932
930
  return responsePromise
933
931
  }
@@ -1059,10 +1057,13 @@ const createOutFilesService = async ({
1059
1057
  if (!isOutRootFile(requestUrl)) {
1060
1058
  return null
1061
1059
  }
1062
- return serveFile(request, {
1063
- rootDirectoryUrl: projectDirectoryUrl,
1064
- etagEnabled: true,
1065
- })
1060
+ return fetchFileSystem(
1061
+ new URL(request.ressource.slice(1), projectDirectoryUrl),
1062
+ {
1063
+ headers: request.headers,
1064
+ etagEnabled: true,
1065
+ },
1066
+ )
1066
1067
  }
1067
1068
  }
1068
1069
  // serve from memory
@@ -1118,51 +1119,6 @@ const createCompileProxyService = ({ projectDirectoryUrl }) => {
1118
1119
  }
1119
1120
  }
1120
1121
 
1121
- const listenJsenvPackageVersionChange = ({
1122
- projectDirectoryUrl,
1123
- jsenvDirectoryRelativeUrl,
1124
- onJsenvPackageVersionChange = () => {},
1125
- }) => {
1126
- const jsenvCoreDirectoryUrl = resolveUrl(
1127
- jsenvDirectoryRelativeUrl,
1128
- projectDirectoryUrl,
1129
- )
1130
- const packageFileUrl = resolveUrl("./package.json", jsenvCoreDirectoryUrl)
1131
- const packageFilePath = urlToFileSystemPath(packageFileUrl)
1132
- let packageVersion
1133
-
1134
- try {
1135
- packageVersion = readPackage(packageFilePath).version
1136
- } catch (e) {
1137
- if (e.code === "ENOENT") return () => {}
1138
- }
1139
-
1140
- const checkPackageVersion = () => {
1141
- let packageObject
1142
- try {
1143
- packageObject = readPackage(packageFilePath)
1144
- } catch (e) {
1145
- // package json deleted ? not a problem
1146
- // let's wait for it to show back
1147
- if (e.code === "ENOENT") return
1148
- // package.json malformed ? not a problem
1149
- // let's wait for use to fix it or filesystem to finish writing the file
1150
- if (e.name === "SyntaxError") return
1151
- throw e
1152
- }
1153
-
1154
- if (packageVersion !== packageObject.version) {
1155
- onJsenvPackageVersionChange()
1156
- }
1157
- }
1158
-
1159
- return registerFileLifecycle(packageFilePath, {
1160
- added: checkPackageVersion,
1161
- updated: checkPackageVersion,
1162
- keepProcessAlive: false,
1163
- })
1164
- }
1165
-
1166
1122
  const readPackage = (packagePath) => {
1167
1123
  const buffer = readFileSync(packagePath)
1168
1124
  const string = String(buffer)
@@ -1170,10 +1126,6 @@ const readPackage = (packagePath) => {
1170
1126
  return packageObject
1171
1127
  }
1172
1128
 
1173
- export const STOP_REASON_PACKAGE_VERSION_CHANGED = {
1174
- toString: () => `package version changed`,
1175
- }
1176
-
1177
1129
  const __filenameReplacement = `import.meta.url.slice('file:///'.length)`
1178
1130
 
1179
1131
  const __dirnameReplacement = `import.meta.url.slice('file:///'.length).replace(/[\\\/\\\\][^\\\/\\\\]*$/, '')`
@@ -1,5 +1,22 @@
1
- import { writeFile } from "@jsenv/filesystem"
1
+ import { writeFile, urlToFileSystemPath } from "@jsenv/filesystem"
2
2
 
3
- export const generateCoverageJsonFile = async (coverage, coverageJsonFileUrl) => {
4
- await writeFile(coverageJsonFileUrl, JSON.stringify(coverage, null, " "))
3
+ import { byteAsFileSize } from "@jsenv/core/src/internal/logs/byteAsFileSize.js"
4
+
5
+ export const generateCoverageJsonFile = async ({
6
+ coverage,
7
+ coverageJsonFileUrl,
8
+ coverageJsonFileLog,
9
+ logger,
10
+ }) => {
11
+ const coverageAsText = JSON.stringify(coverage, null, " ")
12
+
13
+ if (coverageJsonFileLog) {
14
+ logger.info(
15
+ `-> ${urlToFileSystemPath(coverageJsonFileUrl)} (${byteAsFileSize(
16
+ Buffer.byteLength(coverageAsText),
17
+ )})`,
18
+ )
19
+ }
20
+
21
+ await writeFile(coverageJsonFileUrl, coverageAsText)
5
22
  }
@@ -1,52 +1,40 @@
1
- import { createOperation } from "@jsenv/cancellation"
2
1
  import { resolveUrl, urlToFileSystemPath, readFile } from "@jsenv/filesystem"
3
2
 
4
3
  import {
5
4
  babelPluginsFromBabelPluginMap,
6
5
  getMinimalBabelPluginMap,
7
6
  } from "@jsenv/core/src/internal/compiling/babel_plugins.js"
8
-
9
7
  import { babelPluginInstrument } from "./babel_plugin_instrument.js"
10
8
  import { createEmptyCoverage } from "./createEmptyCoverage.js"
11
9
 
12
10
  export const relativeUrlToEmptyCoverage = async (
13
11
  relativeUrl,
14
- { cancellationToken, projectDirectoryUrl, babelPluginMap },
12
+ { multipleExecutionsOperation, projectDirectoryUrl, babelPluginMap },
15
13
  ) => {
16
14
  const { transformAsync } = await import("@babel/core")
17
15
 
18
16
  const fileUrl = resolveUrl(relativeUrl, projectDirectoryUrl)
19
- const source = await createOperation({
20
- cancellationToken,
21
- start: () => readFile(fileUrl),
22
- })
17
+ multipleExecutionsOperation.throwIfAborted()
18
+ const source = await readFile(fileUrl)
23
19
 
24
20
  try {
25
- const { metadata } = await createOperation({
26
- cancellationToken,
27
- start: async () => {
28
- babelPluginMap = {
29
- ...getMinimalBabelPluginMap(),
30
- ...babelPluginMap,
31
- "transform-instrument": [
32
- babelPluginInstrument,
33
- { projectDirectoryUrl },
34
- ],
35
- }
21
+ babelPluginMap = {
22
+ ...getMinimalBabelPluginMap(),
23
+ ...babelPluginMap,
24
+ "transform-instrument": [babelPluginInstrument, { projectDirectoryUrl }],
25
+ }
36
26
 
37
- const { metadata } = await transformAsync(source, {
38
- filename: urlToFileSystemPath(fileUrl),
39
- filenameRelative: relativeUrl,
40
- configFile: false,
41
- babelrc: false,
42
- ast: true,
43
- parserOpts: {
44
- allowAwaitOutsideFunction: true,
45
- },
46
- plugins: babelPluginsFromBabelPluginMap(babelPluginMap),
47
- })
48
- return { metadata }
27
+ multipleExecutionsOperation.throwIfAborted()
28
+ const { metadata } = await transformAsync(source, {
29
+ filename: urlToFileSystemPath(fileUrl),
30
+ filenameRelative: relativeUrl,
31
+ configFile: false,
32
+ babelrc: false,
33
+ ast: true,
34
+ parserOpts: {
35
+ allowAwaitOutsideFunction: true,
49
36
  },
37
+ plugins: babelPluginsFromBabelPluginMap(babelPluginMap),
50
38
  })
51
39
 
52
40
  const { coverage } = metadata
@@ -1,4 +1,5 @@
1
1
  import { collectFiles } from "@jsenv/filesystem"
2
+
2
3
  import { relativeUrlToEmptyCoverage } from "./relativeUrlToEmptyCoverage.js"
3
4
  import { istanbulCoverageFromCoverages } from "./istanbulCoverageFromCoverages.js"
4
5
  import { normalizeIstanbulCoverage } from "./normalizeIstanbulCoverage.js"
@@ -6,8 +7,8 @@ import { normalizeIstanbulCoverage } from "./normalizeIstanbulCoverage.js"
6
7
  export const reportToCoverage = async (
7
8
  report,
8
9
  {
10
+ multipleExecutionsOperation,
9
11
  logger,
10
- cancellationToken,
11
12
  projectDirectoryUrl,
12
13
  babelPluginMap,
13
14
  coverageConfig,
@@ -15,50 +16,66 @@ export const reportToCoverage = async (
15
16
  coverageV8MergeConflictIsExpected,
16
17
  },
17
18
  ) => {
18
- const istanbulCoverageFromExecution = await executionReportToCoverage(report, {
19
- logger,
20
- projectDirectoryUrl,
21
- coverageV8MergeConflictIsExpected,
22
- })
19
+ // here we should forward multipleExecutionsOperation.signal
20
+ // to allow aborting this too
21
+ const istanbulCoverageFromExecution = await executionReportToCoverage(
22
+ report,
23
+ {
24
+ logger,
25
+ projectDirectoryUrl,
26
+ coverageV8MergeConflictIsExpected,
27
+ },
28
+ )
23
29
 
24
30
  if (!coverageIncludeMissing) {
25
31
  return istanbulCoverageFromExecution
26
32
  }
27
33
 
28
34
  const relativeFileUrlToCoverArray = await listRelativeFileUrlToCover({
29
- cancellationToken,
35
+ multipleExecutionsOperation,
30
36
  projectDirectoryUrl,
31
37
  coverageConfig,
32
38
  })
33
39
 
34
- const relativeFileUrlMissingCoverageArray = relativeFileUrlToCoverArray.filter(
35
- (relativeFileUrlToCover) =>
40
+ const relativeFileUrlMissingCoverageArray =
41
+ relativeFileUrlToCoverArray.filter((relativeFileUrlToCover) =>
36
42
  Object.keys(istanbulCoverageFromExecution).every((key) => {
37
43
  return key !== `./${relativeFileUrlToCover}`
38
44
  }),
39
- )
45
+ )
40
46
 
41
47
  const istanbulCoverageFromMissedFiles = {}
48
+ // maybe we should prefer reduce over Promise.all here
49
+ // because it creates a LOT of things to do
42
50
  await Promise.all(
43
- relativeFileUrlMissingCoverageArray.map(async (relativeFileUrlMissingCoverage) => {
44
- const emptyCoverage = await relativeUrlToEmptyCoverage(relativeFileUrlMissingCoverage, {
45
- cancellationToken,
46
- projectDirectoryUrl,
47
- babelPluginMap,
48
- })
49
- istanbulCoverageFromMissedFiles[relativeFileUrlMissingCoverage] = emptyCoverage
50
- return emptyCoverage
51
- }),
51
+ relativeFileUrlMissingCoverageArray.map(
52
+ async (relativeFileUrlMissingCoverage) => {
53
+ const emptyCoverage = await relativeUrlToEmptyCoverage(
54
+ relativeFileUrlMissingCoverage,
55
+ {
56
+ multipleExecutionsOperation,
57
+ projectDirectoryUrl,
58
+ babelPluginMap,
59
+ },
60
+ )
61
+ istanbulCoverageFromMissedFiles[relativeFileUrlMissingCoverage] =
62
+ emptyCoverage
63
+ return emptyCoverage
64
+ },
65
+ ),
52
66
  )
53
67
 
54
68
  return {
55
69
  ...istanbulCoverageFromExecution, // already normalized
56
- ...normalizeIstanbulCoverage(istanbulCoverageFromMissedFiles, projectDirectoryUrl),
70
+ ...normalizeIstanbulCoverage(
71
+ istanbulCoverageFromMissedFiles,
72
+ projectDirectoryUrl,
73
+ ),
57
74
  }
58
75
  }
59
76
 
60
77
  const listRelativeFileUrlToCover = async ({
61
- cancellationToken,
78
+ multipleExecutionsOperation,
62
79
  projectDirectoryUrl,
63
80
  coverageConfig,
64
81
  }) => {
@@ -67,7 +84,7 @@ const listRelativeFileUrlToCover = async ({
67
84
  }
68
85
 
69
86
  const matchingFileResultArray = await collectFiles({
70
- cancellationToken,
87
+ signal: multipleExecutionsOperation.signal,
71
88
  directoryUrl: projectDirectoryUrl,
72
89
  structuredMetaMap: structuredMetaMapForCoverage,
73
90
  predicate: ({ cover }) => cover,
@@ -85,7 +102,8 @@ const executionReportToCoverage = async (
85
102
  Object.keys(report).forEach((file) => {
86
103
  const executionResultForFile = report[file]
87
104
  Object.keys(executionResultForFile).forEach((executionName) => {
88
- const executionResultForFileOnRuntime = executionResultForFile[executionName]
105
+ const executionResultForFileOnRuntime =
106
+ executionResultForFile[executionName]
89
107
 
90
108
  const { status, coverage } = executionResultForFileOnRuntime
91
109
  if (!coverage) {
@@ -108,7 +126,9 @@ const executionReportToCoverage = async (
108
126
  // that were suppose to be coverage but were not.
109
127
 
110
128
  if (status === "completed") {
111
- logger.warn(`No execution.coverage from execution named "${executionName}" of ${file}`)
129
+ logger.warn(
130
+ `No execution.coverage from execution named "${executionName}" of ${file}`,
131
+ )
112
132
  }
113
133
  return
114
134
  }
@@ -26,15 +26,11 @@ export const v8CoverageFromNodeV8Directory = async ({
26
26
  }
27
27
 
28
28
  const readV8CoverageReportsFromDirectory = async (coverageDirectory) => {
29
- const tryReadDirectory = async (timeSpentTrying = 0) => {
29
+ const tryReadDirectory = async () => {
30
30
  const dirContent = await readDirectory(coverageDirectory)
31
31
  if (dirContent.length > 0) {
32
32
  return dirContent
33
33
  }
34
- if (timeSpentTrying < 800) {
35
- await new Promise((resolve) => setTimeout(resolve, 100))
36
- return tryReadDirectory(timeSpentTrying + 100)
37
- }
38
34
  console.warn(`v8 coverage directory is empty at ${coverageDirectory}`)
39
35
  return dirContent
40
36
  }
@@ -45,20 +41,11 @@ const readV8CoverageReportsFromDirectory = async (coverageDirectory) => {
45
41
  await Promise.all(
46
42
  dirContent.map(async (dirEntry) => {
47
43
  const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl)
48
- const tryReadJsonFile = async (timeSpentTrying = 0) => {
44
+ const tryReadJsonFile = async () => {
49
45
  try {
50
46
  const fileContent = await readFile(dirEntryUrl, { as: "json" })
51
47
  return fileContent
52
48
  } catch (e) {
53
- if (e.name === "SyntaxError") {
54
- // If there is a syntax error it's likely because Node.js
55
- // is not done writing the json file content
56
- // -> let's retry to read file after 100ms
57
- if (timeSpentTrying < 100) {
58
- await new Promise((resolve) => setTimeout(resolve, 100))
59
- return tryReadJsonFile(timeSpentTrying + 100)
60
- }
61
- }
62
49
  console.warn(
63
50
  createDetailedMessage(`Error while reading coverage file`, {
64
51
  "error stack": e.stack,