@jsenv/core 23.1.2 → 23.2.1

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 (85) 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 +185 -231
  12. package/dist/jsenv_toolbar_injector.js.map +30 -42
  13. package/{LICENSE → license} +0 -0
  14. package/package.json +9 -11
  15. package/src/abort/abortable.js +172 -0
  16. package/src/abort/callback_list.js +64 -0
  17. package/src/abort/callback_race.js +34 -0
  18. package/src/abort/cleaner.js +22 -0
  19. package/src/abort/main.js +32 -0
  20. package/src/abort/process_teardown_events.js +59 -0
  21. package/src/buildProject.js +132 -123
  22. package/src/execute.js +108 -107
  23. package/src/executeTestPlan.js +107 -125
  24. package/src/importUsingChildProcess.js +2 -1
  25. package/src/internal/browser-launcher/executeHtmlFile.js +33 -12
  26. package/src/internal/browser-utils/fetch-browser.js +4 -29
  27. package/src/internal/browser-utils/fetchUsingXHR.js +5 -7
  28. package/src/internal/building/buildUsingRollup.js +60 -24
  29. package/src/internal/building/createJsenvRollupPlugin.js +13 -31
  30. package/src/internal/building/ressource_builder.js +3 -6
  31. package/src/internal/building/sourcemap_loader.js +4 -5
  32. package/src/internal/building/url_fetcher.js +2 -5
  33. package/src/internal/building/url_loader.js +3 -6
  34. package/src/internal/compiling/compileFile.js +1 -2
  35. package/src/internal/compiling/createCompiledFileService.js +10 -10
  36. package/src/internal/compiling/jsenvCompilerForHtml.js +21 -7
  37. package/src/internal/compiling/jsenvCompilerForJavaScript.js +2 -0
  38. package/src/internal/compiling/startCompileServer.js +82 -134
  39. package/src/internal/executing/coverage/generateCoverageJsonFile.js +20 -3
  40. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +19 -30
  41. package/src/internal/executing/coverage/reportToCoverage.js +44 -24
  42. package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +2 -15
  43. package/src/internal/executing/createSummaryLog.js +50 -37
  44. package/src/internal/executing/executeConcurrently.js +89 -47
  45. package/src/internal/executing/executePlan.js +33 -7
  46. package/src/internal/executing/executionLogs.js +25 -28
  47. package/src/internal/executing/execution_colors.js +15 -0
  48. package/src/internal/executing/generateExecutionSteps.js +3 -2
  49. package/src/internal/executing/launchAndExecute.js +213 -257
  50. package/src/internal/exploring/fetchExploringJson.js +3 -4
  51. package/src/internal/fetchUrl.js +6 -2
  52. package/src/internal/logs/log_style.js +16 -28
  53. package/src/internal/logs/msAsDuration.js +1 -1
  54. package/src/internal/node-launcher/createChildProcessOptions.js +4 -5
  55. package/src/internal/node-launcher/createControllableNodeProcess.js +117 -229
  56. package/src/internal/node-launcher/kill_process_tree.js +76 -0
  57. package/src/internal/node-launcher/nodeControllableFile.mjs +16 -10
  58. package/src/internal/{promise_track_race.js → promise_race.js} +2 -2
  59. package/src/internal/runtime/s.js +25 -24
  60. package/src/internal/toolbar/toolbar.html +157 -61
  61. package/src/internal/toolbar/toolbar.injector.js +8 -0
  62. package/src/internal/toolbar/util/animation.js +3 -7
  63. package/src/internal/toolbar/util/fetching.js +1 -30
  64. package/src/jsenvServiceWorkerFinalizer.js +1 -2
  65. package/src/launchBrowser.js +131 -127
  66. package/src/launchNode.js +29 -17
  67. package/src/playwright_browser_versions.js +3 -3
  68. package/src/requireUsingChildProcess.js +2 -1
  69. package/src/signal/signal.js +65 -0
  70. package/src/startExploring.js +71 -71
  71. package/src/internal/executeJsenvAsyncFunction.js +0 -34
  72. package/src/internal/toolbar/animation/toolbar-movie-icon.svg +0 -15
  73. package/src/internal/toolbar/compilation/flask.svg +0 -7
  74. package/src/internal/toolbar/compilation/info.svg +0 -9
  75. package/src/internal/toolbar/compilation/loupe.svg +0 -11
  76. package/src/internal/toolbar/compilation/toolbar_compilation.svg +0 -11
  77. package/src/internal/toolbar/eventsource/toolbar-power-icon.svg +0 -10
  78. package/src/internal/toolbar/eventsource/toolbar-power-off-icon.svg +0 -10
  79. package/src/internal/toolbar/responsive/toolbar-dots-icon.svg +0 -10
  80. package/src/internal/toolbar/settings/toolbar-settings-icon.svg +0 -9
  81. package/src/internal/toolbar/theme/toolbar-palette-icon.svg +0 -10
  82. package/src/internal/toolbar/toolbar-cross-icon.svg +0 -10
  83. package/src/internal/toolbar/toolbar-loading-icon.svg +0 -102
  84. package/src/internal/toolbar/toolbar-notif-icon.svg +0 -9
  85. package/src/internal/trackRessources.js +0 -23
@@ -6,7 +6,10 @@ import {
6
6
  jsenvToolbarInjectorFileInfo,
7
7
  } from "@jsenv/core/src/internal/jsenvInternalFiles.js"
8
8
  import { getDefaultImportMap } from "@jsenv/core/src/internal/import-resolution/importmap-default.js"
9
- import { setJavaScriptSourceMappingUrl } from "../sourceMappingURLUtils.js"
9
+ import {
10
+ setJavaScriptSourceMappingUrl,
11
+ sourcemapToBase64Url,
12
+ } from "../sourceMappingURLUtils.js"
10
13
  import { transformJs } from "./js-compilation-service/transformJs.js"
11
14
  import {
12
15
  parseHtmlString,
@@ -41,6 +44,7 @@ export const compileHtml = async ({
41
44
  babelPluginMap,
42
45
 
43
46
  jsenvToolbarInjection,
47
+ sourcemapMethod,
44
48
  }) => {
45
49
  const jsenvBrowserBuildUrlRelativeToProject = urlToRelativeUrl(
46
50
  jsenvBrowserSystemFileInfo.jsenvBuildUrl,
@@ -203,12 +207,22 @@ export const compileHtml = async ({
203
207
  sourcemapFileUrl,
204
208
  compiledUrl,
205
209
  )
206
- code = setJavaScriptSourceMappingUrl(
207
- code,
208
- sourcemapFileRelativePathForModule,
209
- )
210
- assets = [...assets, scriptAssetUrl, sourcemapFileUrl]
211
- assetsContent = [...assetsContent, code, JSON.stringify(map, null, " ")]
210
+
211
+ if (sourcemapMethod === "inline") {
212
+ code = setJavaScriptSourceMappingUrl(code, sourcemapToBase64Url(map))
213
+ } else {
214
+ // TODO: respect "sourcemapMethod" parameter
215
+ code = setJavaScriptSourceMappingUrl(
216
+ code,
217
+ sourcemapFileRelativePathForModule,
218
+ )
219
+ assets = [...assets, scriptAssetUrl, sourcemapFileUrl]
220
+ assetsContent = [
221
+ ...assetsContent,
222
+ code,
223
+ JSON.stringify(map, null, " "),
224
+ ]
225
+ }
212
226
  }),
213
227
  )
214
228
 
@@ -14,6 +14,7 @@ export const compileJavascript = async ({
14
14
  importMetaFormat,
15
15
 
16
16
  sourcemapExcludeSources,
17
+ sourcemapMethod,
17
18
  }) => {
18
19
  const transformResult = await transformJs({
19
20
  code,
@@ -42,6 +43,7 @@ export const compileJavascript = async ({
42
43
  compiledFileUrl: compiledUrl,
43
44
  sourcemapFileUrl: `${compiledUrl}.map`,
44
45
  sourcemapExcludeSources,
46
+ sourcemapMethod,
45
47
  },
46
48
  )
47
49
  }
@@ -1,10 +1,4 @@
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,
@@ -12,6 +6,9 @@ import {
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,12 +19,12 @@ 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"
30
26
 
27
+ import { Abortable } from "@jsenv/core/src/abort/main.js"
31
28
  import { isBrowserPartOfSupportedRuntimes } from "@jsenv/core/src/internal/generateGroupMap/runtime_support.js"
32
29
  import { loadBabelPluginMapFromFile } from "./load_babel_plugin_map_from_file.js"
33
30
  import { extractSyntaxBabelPluginMap } from "./babel_plugins.js"
@@ -48,7 +45,7 @@ import { urlIsCompilationAsset } from "./compile-directory/compile-asset.js"
48
45
  import { createTransformHtmlSourceFileService } from "./html_source_file_service.js"
49
46
 
50
47
  export const startCompileServer = async ({
51
- cancellationToken = createCancellationToken(),
48
+ signal = new AbortController().signal,
52
49
  compileServerLogLevel,
53
50
 
54
51
  projectDirectoryUrl,
@@ -59,6 +56,7 @@ export const startCompileServer = async ({
59
56
  jsenvDirectoryClean = false,
60
57
  outDirectoryName = "out",
61
58
 
59
+ sourcemapMethod = "comment", // "inline" is also possible
62
60
  sourcemapExcludeSources = false, // this should increase perf (no need to download source for browser)
63
61
  compileServerCanReadFromFilesystem = true,
64
62
  compileServerCanWriteOnFilesystem = true,
@@ -88,7 +86,7 @@ export const startCompileServer = async ({
88
86
  compileServerIp = "0.0.0.0",
89
87
  compileServerPort = 0,
90
88
  keepProcessAlive = false,
91
- stopOnPackageVersionChange = false,
89
+ onStop = () => {},
92
90
 
93
91
  // remaining options
94
92
  runtimeSupport,
@@ -217,15 +215,12 @@ export const startCompileServer = async ({
217
215
  ...babelPluginMap,
218
216
  }
219
217
 
220
- const serverStopCancellationSource = createCancellationSource()
218
+ const compileServerOperation = Abortable.fromSignal(signal)
221
219
 
222
220
  let projectFileRequestedCallback = () => {}
223
221
  if (livereloadSSE) {
224
222
  const sseSetup = setupServerSentEventsForLivereload({
225
- cancellationToken: composeCancellationToken(
226
- cancellationToken,
227
- serverStopCancellationSource.token,
228
- ),
223
+ compileServerOperation,
229
224
  projectDirectoryUrl,
230
225
  jsenvDirectoryRelativeUrl,
231
226
  outDirectoryRelativeUrl,
@@ -235,7 +230,7 @@ export const startCompileServer = async ({
235
230
 
236
231
  projectFileRequestedCallback = sseSetup.projectFileRequestedCallback
237
232
  const serveSSEForLivereload = createSSEForLivereloadService({
238
- cancellationToken,
233
+ compileServerOperation,
239
234
  outDirectoryRelativeUrl,
240
235
  trackMainAndDependencies: sseSetup.trackMainAndDependencies,
241
236
  })
@@ -269,6 +264,8 @@ export const startCompileServer = async ({
269
264
  babelPluginMap,
270
265
  customCompilers,
271
266
  jsenvToolbarInjection,
267
+ sourcemapMethod,
268
+ sourcemapExcludeSources,
272
269
  })
273
270
  if (compileServerCanWriteOnFilesystem) {
274
271
  await setupOutDirectory({
@@ -280,31 +277,6 @@ export const startCompileServer = async ({
280
277
  })
281
278
  }
282
279
 
283
- const sourceFileService = composeServicesWithTiming({
284
- ...(transformHtmlSourceFiles
285
- ? {
286
- "service:transform html source file":
287
- createTransformHtmlSourceFileService({
288
- logger,
289
- projectDirectoryUrl,
290
- inlineImportMapIntoHTML,
291
- jsenvScriptInjection,
292
- jsenvToolbarInjection,
293
- }),
294
- }
295
- : {}),
296
- "service:source file": createSourceFileService({
297
- logger,
298
- projectDirectoryUrl,
299
- projectFileRequestedCallback,
300
- projectFileEtagEnabled,
301
- transformHtmlSourceFiles,
302
- inlineImportMapIntoHTML,
303
- jsenvScriptInjection,
304
- jsenvToolbarInjection,
305
- }),
306
- })
307
-
308
280
  const jsenvServices = {
309
281
  "service:compilation asset": createCompilationAssetFileService({
310
282
  projectDirectoryUrl,
@@ -324,8 +296,7 @@ export const startCompileServer = async ({
324
296
  projectDirectoryUrl,
325
297
  }),
326
298
  "service:compiled file": createCompiledFileService({
327
- sourceFileService,
328
- cancellationToken,
299
+ compileServerOperation,
329
300
  logger,
330
301
 
331
302
  projectDirectoryUrl,
@@ -345,13 +316,42 @@ export const startCompileServer = async ({
345
316
  projectFileRequestedCallback,
346
317
  useFilesystemAsCache: compileServerCanReadFromFilesystem,
347
318
  writeOnFilesystem: compileServerCanWriteOnFilesystem,
319
+ sourcemapMethod,
348
320
  sourcemapExcludeSources,
349
321
  compileCacheStrategy,
350
322
  }),
323
+ ...(transformHtmlSourceFiles
324
+ ? {
325
+ "service:transform html source file":
326
+ createTransformHtmlSourceFileService({
327
+ logger,
328
+ projectDirectoryUrl,
329
+ inlineImportMapIntoHTML,
330
+ jsenvScriptInjection,
331
+ jsenvToolbarInjection,
332
+ }),
333
+ }
334
+ : {}),
335
+ "service:source file": createSourceFileService({
336
+ logger,
337
+ projectDirectoryUrl,
338
+ projectFileRequestedCallback,
339
+ projectFileEtagEnabled,
340
+ transformHtmlSourceFiles,
341
+ inlineImportMapIntoHTML,
342
+ jsenvScriptInjection,
343
+ jsenvToolbarInjection,
344
+ }),
351
345
  }
352
346
 
353
347
  const compileServer = await startServer({
354
- cancellationToken,
348
+ signal: compileServerOperation.signal,
349
+ stopOnExit: false,
350
+ stopOnSIGINT: false,
351
+ stopOnInternalError: false,
352
+ sendServerInternalErrorDetails: true,
353
+ keepProcessAlive,
354
+
355
355
  logLevel: compileServerLogLevel,
356
356
 
357
357
  protocol: compileServerProtocol,
@@ -360,43 +360,32 @@ export const startCompileServer = async ({
360
360
  serverCertificatePrivateKey: compileServerPrivateKey,
361
361
  ip: compileServerIp,
362
362
  port: compileServerPort,
363
- sendServerTiming: true,
364
- nagle: false,
365
- sendServerInternalErrorDetails: true,
363
+ plugins: {
364
+ ...pluginCORS({
365
+ accessControlAllowRequestOrigin: true,
366
+ accessControlAllowRequestMethod: true,
367
+ accessControlAllowRequestHeaders: true,
368
+ accessControlAllowedRequestHeaders: [
369
+ ...jsenvAccessControlAllowedHeaders,
370
+ "x-jsenv-execution-id",
371
+ ],
372
+ accessControlAllowCredentials: true,
373
+ }),
374
+ ...pluginServerTiming,
375
+ ...pluginRequestWaitingCheck({
376
+ requestWaitingMs: 60 * 1000,
377
+ }),
378
+ },
366
379
  requestToResponse: composeServicesWithTiming({
367
380
  ...customServices,
368
381
  ...jsenvServices,
369
382
  }),
370
- accessControlAllowRequestOrigin: true,
371
- accessControlAllowRequestMethod: true,
372
- accessControlAllowRequestHeaders: true,
373
- accessControlAllowedRequestHeaders: [
374
- ...jsenvAccessControlAllowedHeaders,
375
- "x-jsenv-execution-id",
376
- ],
377
- accessControlAllowCredentials: true,
378
- keepProcessAlive,
383
+ onStop: () => {
384
+ onStop()
385
+ compileServerOperation.cleaner.clean()
386
+ },
379
387
  })
380
388
 
381
- compileServer.stoppedPromise.then(serverStopCancellationSource.cancel)
382
-
383
- if (stopOnPackageVersionChange) {
384
- const stopListeningJsenvPackageVersionChange =
385
- listenJsenvPackageVersionChange({
386
- projectDirectoryUrl,
387
- jsenvDirectoryRelativeUrl,
388
- onJsenvPackageVersionChange: () => {
389
- compileServer.stop(STOP_REASON_PACKAGE_VERSION_CHANGED)
390
- },
391
- })
392
- compileServer.stoppedPromise.then(
393
- () => {
394
- stopListeningJsenvPackageVersionChange()
395
- },
396
- () => {},
397
- )
398
- }
399
-
400
389
  return {
401
390
  jsenvDirectoryRelativeUrl,
402
391
  outDirectoryRelativeUrl,
@@ -570,7 +559,7 @@ const compareValueJson = (left, right) => {
570
559
  *
571
560
  */
572
561
  const setupServerSentEventsForLivereload = ({
573
- cancellationToken,
562
+ compileServerOperation,
574
563
  projectDirectoryUrl,
575
564
  jsenvDirectoryRelativeUrl,
576
565
  outDirectoryRelativeUrl,
@@ -616,7 +605,7 @@ const setupServerSentEventsForLivereload = ({
616
605
  recursive: true,
617
606
  },
618
607
  )
619
- cancellationToken.register(unregisterDirectoryLifecyle)
608
+ compileServerOperation.cleaner.addCallback(unregisterDirectoryLifecyle)
620
609
 
621
610
  const getDependencySet = (mainRelativeUrl) => {
622
611
  if (trackerMap.has(mainRelativeUrl)) {
@@ -772,11 +761,14 @@ const setupServerSentEventsForLivereload = ({
772
761
  }
773
762
  }
774
763
 
775
- return { projectFileRequestedCallback, trackMainAndDependencies }
764
+ return {
765
+ projectFileRequestedCallback,
766
+ trackMainAndDependencies,
767
+ }
776
768
  }
777
769
 
778
770
  const createSSEForLivereloadService = ({
779
- cancellationToken,
771
+ compileServerOperation,
780
772
  outDirectoryRelativeUrl,
781
773
  trackMainAndDependencies,
782
774
  }) => {
@@ -810,17 +802,18 @@ const createSSEForLivereloadService = ({
810
802
  },
811
803
  })
812
804
 
813
- const cancelRegistration = cancellationToken.register(() => {
814
- cancelRegistration.unregister()
815
-
816
- sseRoom.close()
817
- stopTracking()
818
- })
805
+ const removeSSECleanupCallback = compileServerOperation.cleaner.addCallback(
806
+ () => {
807
+ removeSSECleanupCallback()
808
+ sseRoom.close()
809
+ stopTracking()
810
+ },
811
+ )
819
812
  cache.push({
820
813
  mainFileRelativeUrl,
821
814
  sseRoom,
822
815
  cleanup: () => {
823
- cancelRegistration.unregister()
816
+ removeSSECleanupCallback()
824
817
  sseRoom.close()
825
818
  stopTracking()
826
819
  },
@@ -945,6 +938,8 @@ const createOutJSONFiles = ({
945
938
  inlineImportMapIntoHTML,
946
939
  customCompilers,
947
940
  jsenvToolbarInjection,
941
+ sourcemapMethod,
942
+ sourcemapExcludeSources,
948
943
  }) => {
949
944
  const outJSONFiles = {}
950
945
  const outDirectoryUrl = resolveUrl(
@@ -968,6 +963,8 @@ const createOutJSONFiles = ({
968
963
  processEnvNodeEnv,
969
964
  customCompilerPatterns,
970
965
  jsenvToolbarInjection,
966
+ sourcemapMethod,
967
+ sourcemapExcludeSources,
971
968
  }
972
969
  outJSONFiles.meta = {
973
970
  url: metaOutFileUrl,
@@ -1113,51 +1110,6 @@ const createCompileProxyService = ({ projectDirectoryUrl }) => {
1113
1110
  }
1114
1111
  }
1115
1112
 
1116
- const listenJsenvPackageVersionChange = ({
1117
- projectDirectoryUrl,
1118
- jsenvDirectoryRelativeUrl,
1119
- onJsenvPackageVersionChange = () => {},
1120
- }) => {
1121
- const jsenvCoreDirectoryUrl = resolveUrl(
1122
- jsenvDirectoryRelativeUrl,
1123
- projectDirectoryUrl,
1124
- )
1125
- const packageFileUrl = resolveUrl("./package.json", jsenvCoreDirectoryUrl)
1126
- const packageFilePath = urlToFileSystemPath(packageFileUrl)
1127
- let packageVersion
1128
-
1129
- try {
1130
- packageVersion = readPackage(packageFilePath).version
1131
- } catch (e) {
1132
- if (e.code === "ENOENT") return () => {}
1133
- }
1134
-
1135
- const checkPackageVersion = () => {
1136
- let packageObject
1137
- try {
1138
- packageObject = readPackage(packageFilePath)
1139
- } catch (e) {
1140
- // package json deleted ? not a problem
1141
- // let's wait for it to show back
1142
- if (e.code === "ENOENT") return
1143
- // package.json malformed ? not a problem
1144
- // let's wait for use to fix it or filesystem to finish writing the file
1145
- if (e.name === "SyntaxError") return
1146
- throw e
1147
- }
1148
-
1149
- if (packageVersion !== packageObject.version) {
1150
- onJsenvPackageVersionChange()
1151
- }
1152
- }
1153
-
1154
- return registerFileLifecycle(packageFilePath, {
1155
- added: checkPackageVersion,
1156
- updated: checkPackageVersion,
1157
- keepProcessAlive: false,
1158
- })
1159
- }
1160
-
1161
1113
  const readPackage = (packagePath) => {
1162
1114
  const buffer = readFileSync(packagePath)
1163
1115
  const string = String(buffer)
@@ -1165,10 +1117,6 @@ const readPackage = (packagePath) => {
1165
1117
  return packageObject
1166
1118
  }
1167
1119
 
1168
- export const STOP_REASON_PACKAGE_VERSION_CHANGED = {
1169
- toString: () => `package version changed`,
1170
- }
1171
-
1172
1120
  const __filenameReplacement = `import.meta.url.slice('file:///'.length)`
1173
1121
 
1174
1122
  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,41 @@
1
- import { createOperation } from "@jsenv/cancellation"
2
1
  import { resolveUrl, urlToFileSystemPath, readFile } from "@jsenv/filesystem"
3
2
 
3
+ import { Abortable } from "@jsenv/core/src/abort/main.js"
4
4
  import {
5
5
  babelPluginsFromBabelPluginMap,
6
6
  getMinimalBabelPluginMap,
7
7
  } from "@jsenv/core/src/internal/compiling/babel_plugins.js"
8
-
9
8
  import { babelPluginInstrument } from "./babel_plugin_instrument.js"
10
9
  import { createEmptyCoverage } from "./createEmptyCoverage.js"
11
10
 
12
11
  export const relativeUrlToEmptyCoverage = async (
13
12
  relativeUrl,
14
- { cancellationToken, projectDirectoryUrl, babelPluginMap },
13
+ { multipleExecutionsOperation, projectDirectoryUrl, babelPluginMap },
15
14
  ) => {
16
15
  const { transformAsync } = await import("@babel/core")
17
16
 
18
17
  const fileUrl = resolveUrl(relativeUrl, projectDirectoryUrl)
19
- const source = await createOperation({
20
- cancellationToken,
21
- start: () => readFile(fileUrl),
22
- })
18
+ Abortable.throwIfAborted(multipleExecutionsOperation)
19
+ const source = await readFile(fileUrl)
23
20
 
24
21
  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
- }
22
+ babelPluginMap = {
23
+ ...getMinimalBabelPluginMap(),
24
+ ...babelPluginMap,
25
+ "transform-instrument": [babelPluginInstrument, { projectDirectoryUrl }],
26
+ }
36
27
 
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 }
28
+ Abortable.throwIfAborted(multipleExecutionsOperation)
29
+ const { metadata } = await transformAsync(source, {
30
+ filename: urlToFileSystemPath(fileUrl),
31
+ filenameRelative: relativeUrl,
32
+ configFile: false,
33
+ babelrc: false,
34
+ ast: true,
35
+ parserOpts: {
36
+ allowAwaitOutsideFunction: true,
49
37
  },
38
+ plugins: babelPluginsFromBabelPluginMap(babelPluginMap),
50
39
  })
51
40
 
52
41
  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
  }