@jsenv/core 27.0.0-alpha.80 → 27.0.0-alpha.83

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 (36) hide show
  1. package/dist/babel_helpers/applyDecs/applyDecs.js +756 -0
  2. package/dist/babel_helpers/construct/construct.js +1 -1
  3. package/dist/babel_helpers/extends/extends.js +1 -1
  4. package/dist/babel_helpers/get/get.js +1 -1
  5. package/dist/babel_helpers/getPrototypeOf/getPrototypeOf.js +1 -1
  6. package/dist/babel_helpers/identity/identity.js +3 -0
  7. package/dist/babel_helpers/setPrototypeOf/setPrototypeOf.js +2 -2
  8. package/dist/js/event_source_client.js +205 -1
  9. package/dist/main.js +852 -63
  10. package/package.json +9 -10
  11. package/src/build/start_build_server.js +29 -26
  12. package/src/dev/start_dev_server.js +34 -30
  13. package/src/execute/runtimes/browsers/from_playwright.js +3 -2
  14. package/src/helpers/event_source/event_source.js +197 -0
  15. package/src/helpers/event_source/sse_service.js +53 -0
  16. package/src/helpers/worker_reload.js +56 -0
  17. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +1 -1
  18. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +1 -1
  19. package/src/test/coverage/babel_plugin_instrument.js +82 -0
  20. package/src/test/coverage/coverage_reporter_html_directory.js +36 -0
  21. package/src/test/coverage/coverage_reporter_json_file.js +22 -0
  22. package/src/test/coverage/coverage_reporter_text_log.js +19 -0
  23. package/src/test/coverage/empty_coverage_factory.js +52 -0
  24. package/src/test/coverage/file_by_file_coverage.js +26 -0
  25. package/src/test/coverage/istanbul_coverage_composition.js +28 -0
  26. package/src/test/coverage/istanbul_coverage_map_from_coverage.js +16 -0
  27. package/src/test/coverage/list_files_not_covered.js +15 -0
  28. package/src/test/coverage/missing_coverage.js +41 -0
  29. package/src/test/coverage/report_to_coverage.js +196 -0
  30. package/src/test/coverage/v8_and_istanbul.js +37 -0
  31. package/src/test/coverage/v8_coverage_composition.js +24 -0
  32. package/src/test/coverage/v8_coverage_from_directory.js +87 -0
  33. package/src/test/coverage/v8_coverage_to_istanbul.js +99 -0
  34. package/src/test/execute_plan.js +2 -2
  35. package/src/test/execute_test_plan.js +3 -3
  36. package/dist/babel_helpers/readme.md +0 -8
package/dist/main.js CHANGED
@@ -1,8 +1,10 @@
1
- import { parentPort } from "node:worker_threads";
2
- import { registerFileLifecycle, readFileSync as readFileSync$1, bufferToEtag, writeFileSync, ensureWindowsDriveLetter, collectFiles, assertAndNormalizeDirectoryUrl, registerDirectoryLifecycle, writeFile, ensureEmptyDirectory, writeDirectory } from "@jsenv/filesystem";
3
- import { createDetailedMessage, createLogger, createTaskLog, loggerToLevels, ANSI, msAsDuration, msAsEllapsedTime, byteAsMemoryUsage, UNICODE, createLog, startSpinner, distributePercentages, byteAsFileSize } from "@jsenv/log";
1
+ import { createSSERoom, timeStart, fetchFileSystem, composeTwoResponses, serveDirectory, startServer, pluginCORS, jsenvAccessControlAllowedHeaders, pluginServerTiming, pluginRequestWaitingCheck, composeServices, findFreePort } from "@jsenv/server";
2
+ import { registerFileLifecycle, readFileSync as readFileSync$1, bufferToEtag, writeFileSync, ensureWindowsDriveLetter, collectFiles, assertAndNormalizeDirectoryUrl, registerDirectoryLifecycle, writeFile, readFile, readDirectory, ensureEmptyDirectory, writeDirectory } from "@jsenv/filesystem";
3
+ import { createCallbackListNotifiedOnce, createCallbackList, Abort, raceProcessTeardownEvents, raceCallbacks } from "@jsenv/abort";
4
+ import { createDetailedMessage, createLogger, createTaskLog, loggerToLevels, byteAsFileSize, ANSI, msAsDuration, msAsEllapsedTime, byteAsMemoryUsage, UNICODE, createLog, startSpinner, distributePercentages } from "@jsenv/log";
4
5
  import { urlToRelativeUrl, generateInlineContentUrl, ensurePathnameTrailingSlash, urlIsInsideOf, urlToFilename, DATA_URL, injectQueryParams, injectQueryParamsIntoSpecifier, fileSystemPathToUrl, urlToFileSystemPath, isFileSystemPath, normalizeUrl, stringifyUrlSite, setUrlFilename, moveUrl, getCallerPosition, resolveUrl, resolveDirectoryUrl, asUrlWithoutSearch, asUrlUntilPathname, urlToBasename, urlToExtension } from "@jsenv/urls";
5
- import { initReloadableProcess } from "@jsenv/utils/process_reload/process_reload.js";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { workerData, Worker } from "node:worker_threads";
6
8
  import { URL_META } from "@jsenv/url-meta";
7
9
  import { parseHtmlString, stringifyHtmlAst, visitHtmlAst, getHtmlNodeAttributeByName, htmlNodePosition, findNode, getHtmlNodeTextNode, removeHtmlNode, setHtmlNodeGeneratedText, removeHtmlNodeAttributeByName, parseScriptNode, injectScriptAsEarlyAsPossible, createHtmlNode, removeHtmlNodeText, assignHtmlNodeAttributes, parseLinkNode } from "@jsenv/utils/html_ast/html_ast.js";
8
10
  import { htmlAttributeSrcSet } from "@jsenv/utils/html_ast/html_attribute_src_set.js";
@@ -13,7 +15,6 @@ import { parseJsUrls } from "@jsenv/utils/js_ast/parse_js_urls.js";
13
15
  import { resolveImport, normalizeImportMap, composeTwoImportMaps } from "@jsenv/importmap";
14
16
  import { applyNodeEsmResolution, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, applyFileSystemMagicResolution, getExtensionsToTry } from "@jsenv/node-esm-resolution";
15
17
  import { statSync, realpathSync, readdirSync, readFileSync, existsSync } from "node:fs";
16
- import { pathToFileURL } from "node:url";
17
18
  import { CONTENT_TYPE } from "@jsenv/utils/content_type/content_type.js";
18
19
  import { JS_QUOTES } from "@jsenv/utils/string/js_quotes.js";
19
20
  import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js";
@@ -26,32 +27,75 @@ import { injectImport } from "@jsenv/utils/js_ast/babel_utils.js";
26
27
  import { sortByDependencies } from "@jsenv/utils/graph/sort_by_dependencies.js";
27
28
  import { applyRollupPlugins } from "@jsenv/utils/js_ast/apply_rollup_plugins.js";
28
29
  import { sourcemapConverter } from "@jsenv/utils/sourcemap/sourcemap_converter.js";
29
- import { createCallbackList, createCallbackListNotifiedOnce, Abort, raceCallbacks, raceProcessTeardownEvents } from "@jsenv/abort";
30
- import { createSSEService } from "@jsenv/utils/event_source/sse_service.js";
31
- import { timeStart, fetchFileSystem, composeTwoResponses, serveDirectory, startServer, pluginCORS, jsenvAccessControlAllowedHeaders, pluginServerTiming, pluginRequestWaitingCheck, composeServices, findFreePort } from "@jsenv/server";
32
30
  import { SOURCEMAP, generateSourcemapUrl, sourcemapToBase64Url } from "@jsenv/utils/sourcemap/sourcemap_utils.js";
33
31
  import { validateResponseIntegrity } from "@jsenv/integrity";
34
32
  import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
35
33
  import { memoizeByFirstArgument } from "@jsenv/utils/memoize/memoize_by_first_argument.js";
36
- import { generateCoverageJsonFile } from "@jsenv/utils/coverage/coverage_reporter_json_file.js";
37
- import { generateCoverageHtmlDirectory } from "@jsenv/utils/coverage/coverage_reporter_html_directory.js";
38
- import { generateCoverageTextLog } from "@jsenv/utils/coverage/coverage_reporter_text_log.js";
39
34
  import { memoryUsage } from "node:process";
40
35
  import wrapAnsi from "wrap-ansi";
41
36
  import stripAnsi from "strip-ansi";
42
37
  import cuid from "cuid";
43
- import { babelPluginInstrument } from "@jsenv/utils/coverage/babel_plugin_instrument.js";
44
- import { reportToCoverage } from "@jsenv/utils/coverage/report_to_coverage.js";
45
38
  import v8 from "node:v8";
46
39
  import { runInNewContext, Script } from "node:vm";
47
40
  import { memoize } from "@jsenv/utils/memoize/memoize.js";
48
- import { filterV8Coverage } from "@jsenv/utils/coverage/v8_coverage_from_directory.js";
49
- import { composeTwoFileByFileIstanbulCoverages } from "@jsenv/utils/coverage/istanbul_coverage_composition.js";
50
41
  import { escapeRegexpSpecialChars } from "@jsenv/utils/string/escape_regexp_special_chars.js";
51
42
  import { fork } from "node:child_process";
52
43
  import { uneval } from "@jsenv/uneval";
53
44
  import { createVersionGenerator } from "@jsenv/utils/versioning/version_generator.js";
54
45
 
46
+ const createReloadableWorker = (workerFileUrl, options = {}) => {
47
+ const workerFilePath = fileURLToPath(workerFileUrl);
48
+ const isPrimary = !workerData || workerData.workerFilePath !== workerFilePath;
49
+ let worker;
50
+
51
+ const terminate = async () => {
52
+ if (worker) {
53
+ let _worker = worker;
54
+ worker = null;
55
+ const exitPromise = new Promise(resolve => {
56
+ _worker.once("exit", resolve);
57
+ });
58
+
59
+ _worker.terminate();
60
+
61
+ await exitPromise;
62
+ }
63
+ };
64
+
65
+ const load = async () => {
66
+ if (!isPrimary) {
67
+ throw new Error(`worker can be loaded from primary file only`);
68
+ }
69
+
70
+ worker = new Worker(workerFilePath, { ...options,
71
+ workerData: { ...options.workerData,
72
+ workerFilePath
73
+ }
74
+ });
75
+ worker.once("error", error => {
76
+ console.error(error);
77
+ });
78
+ worker.once("exit", () => {
79
+ worker = null;
80
+ });
81
+ await new Promise(resolve => {
82
+ worker.once("online", resolve);
83
+ });
84
+ };
85
+
86
+ const reload = async () => {
87
+ await terminate();
88
+ await load();
89
+ };
90
+
91
+ return {
92
+ isPrimary,
93
+ load,
94
+ reload,
95
+ terminate
96
+ };
97
+ };
98
+
55
99
  const parseAndTransformHtmlUrls = async (urlInfo, context) => {
56
100
  const url = urlInfo.originalUrl;
57
101
  const content = urlInfo.content;
@@ -3386,9 +3430,13 @@ const getFeatureCompat = feature => {
3386
3430
  return feature;
3387
3431
  };
3388
3432
 
3389
- // https://github.com/babel/babel/blob/99f4f6c3b03c7f3f67cf1b9f1a21b80cfd5b0224/packages/babel-core/src/tools/build-external-helpers.js
3390
- // the list of possible helpers:
3391
- // https://github.com/babel/babel/blob/99f4f6c3b03c7f3f67cf1b9f1a21b80cfd5b0224/packages/babel-helpers/src/helpers.js#L13
3433
+ /*
3434
+ * Generated helpers
3435
+ * - https://github.com/babel/babel/commits/main/packages/babel-helpers/src/helpers.ts
3436
+ * File helpers
3437
+ * - https://github.com/babel/babel/tree/main/packages/babel-helpers/src/helpers
3438
+ *
3439
+ */
3392
3440
  const babelHelperClientDirectoryUrl = new URL("./babel_helpers/", import.meta.url).href; // we cannot use "@jsenv/core/src/*" because babel helper might be injected
3393
3441
  // into node_modules not depending on "@jsenv/core"
3394
3442
 
@@ -5633,6 +5681,60 @@ const jsenvPluginDevSSEClient = () => {
5633
5681
  };
5634
5682
  };
5635
5683
 
5684
+ const createSSEService = ({
5685
+ serverEventCallbackList
5686
+ }) => {
5687
+ const destroyCallbackList = createCallbackListNotifiedOnce();
5688
+ const cache = [];
5689
+ const sseRoomLimit = 100;
5690
+
5691
+ const getOrCreateSSERoom = request => {
5692
+ const htmlFileRelativeUrl = request.ressource.slice(1);
5693
+ const cacheEntry = cache.find(cacheEntryCandidate => cacheEntryCandidate.htmlFileRelativeUrl === htmlFileRelativeUrl);
5694
+
5695
+ if (cacheEntry) {
5696
+ return cacheEntry.sseRoom;
5697
+ }
5698
+
5699
+ const sseRoom = createSSERoom({
5700
+ retryDuration: 2000,
5701
+ historyLength: 100,
5702
+ welcomeEventEnabled: true,
5703
+ effect: () => {
5704
+ return serverEventCallbackList.add(event => {
5705
+ sseRoom.sendEvent(event);
5706
+ });
5707
+ }
5708
+ });
5709
+ const removeSSECleanupCallback = destroyCallbackList.add(() => {
5710
+ removeSSECleanupCallback();
5711
+ sseRoom.close();
5712
+ });
5713
+ cache.push({
5714
+ htmlFileRelativeUrl,
5715
+ sseRoom,
5716
+ cleanup: () => {
5717
+ removeSSECleanupCallback();
5718
+ sseRoom.close();
5719
+ }
5720
+ });
5721
+
5722
+ if (cache.length >= sseRoomLimit) {
5723
+ const firstCacheEntry = cache.shift();
5724
+ firstCacheEntry.cleanup();
5725
+ }
5726
+
5727
+ return sseRoom;
5728
+ };
5729
+
5730
+ return {
5731
+ getOrCreateSSERoom,
5732
+ destroy: () => {
5733
+ destroyCallbackList.notify();
5734
+ }
5735
+ };
5736
+ };
5737
+
5636
5738
  const jsenvPluginDevSSEServer = ({
5637
5739
  rootDirectoryUrl,
5638
5740
  urlGraph,
@@ -8291,7 +8393,7 @@ const jsenvPluginExplorer = ({
8291
8393
 
8292
8394
  const startDevServer = async ({
8293
8395
  signal = new AbortController().signal,
8294
- handleSIGINT,
8396
+ handleSIGINT = true,
8295
8397
  logLevel = "info",
8296
8398
  omegaServerLogLevel = "warn",
8297
8399
  port = 3456,
@@ -8311,9 +8413,9 @@ const startDevServer = async ({
8311
8413
  devServerMainFile = getCallerPosition().url,
8312
8414
  // force disable server autoreload when this code is executed:
8313
8415
  // - inside a forked child process
8314
- // - inside a worker thread
8315
- // (because node cluster won't work)
8316
- devServerAutoreload = typeof process.send !== "function" && !parentPort && !process.env.VSCODE_INSPECTOR_OPTIONS,
8416
+ // - debugged by vscode
8417
+ // otherwise we get net:ERR_CONNECTION_REFUSED
8418
+ devServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
8317
8419
  clientFiles = {
8318
8420
  "./src/": true,
8319
8421
  "./test/": true
@@ -8353,32 +8455,36 @@ const startDevServer = async ({
8353
8455
  logLevel
8354
8456
  });
8355
8457
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
8356
- const reloadableProcess = await initReloadableProcess({
8357
- signal,
8358
- handleSIGINT,
8359
- ...(devServerAutoreload ? {
8360
- enabled: true,
8361
- logLevel: "warn",
8362
- fileToRestart: devServerMainFile
8363
- } : {
8364
- enabled: false
8365
- })
8366
- });
8458
+ const operation = Abort.startOperation();
8459
+ operation.addAbortSignal(signal);
8460
+
8461
+ if (handleSIGINT) {
8462
+ operation.addAbortSource(abort => {
8463
+ return raceProcessTeardownEvents({
8464
+ SIGINT: true
8465
+ }, abort);
8466
+ });
8467
+ }
8468
+
8469
+ if (port === 0) {
8470
+ port = await findFreePort(port, {
8471
+ signal: operation.signal
8472
+ });
8473
+ }
8367
8474
 
8368
- if (reloadableProcess.isPrimary) {
8475
+ const reloadableWorker = createReloadableWorker(devServerMainFile);
8476
+
8477
+ if (devServerAutoreload && reloadableWorker.isPrimary) {
8369
8478
  const devServerFileChangeCallback = ({
8370
8479
  relativeUrl,
8371
8480
  event
8372
8481
  }) => {
8373
8482
  const url = new URL(relativeUrl, rootDirectoryUrl).href;
8374
-
8375
- if (devServerAutoreload) {
8376
- logger.info(`file ${event} ${url} -> restarting server...`);
8377
- reloadableProcess.reload();
8378
- }
8483
+ logger.info(`file ${event} ${url} -> restarting server...`);
8484
+ reloadableWorker.reload();
8379
8485
  };
8380
8486
 
8381
- const unregisterDevServerFilesWatcher = registerDirectoryLifecycle(rootDirectoryUrl, {
8487
+ const stopWatchingDevServerFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
8382
8488
  watchPatterns: {
8383
8489
  [devServerMainFile]: true,
8384
8490
  ...devServerFiles
@@ -8411,14 +8517,16 @@ const startDevServer = async ({
8411
8517
  });
8412
8518
  }
8413
8519
  });
8414
- signal.addEventListener("abort", () => {
8415
- unregisterDevServerFilesWatcher();
8520
+ operation.addAbortCallback(() => {
8521
+ stopWatchingDevServerFiles();
8522
+ reloadableWorker.terminate();
8416
8523
  });
8524
+ await reloadableWorker.load();
8417
8525
  return {
8418
8526
  origin: `${protocol}://127.0.0.1:${port}`,
8419
8527
  stop: () => {
8420
- unregisterDevServerFilesWatcher();
8421
- reloadableProcess.stop();
8528
+ stopWatchingDevServerFiles();
8529
+ reloadableWorker.terminate();
8422
8530
  }
8423
8531
  };
8424
8532
  }
@@ -8537,6 +8645,679 @@ const startDevServer = async ({
8537
8645
  };
8538
8646
  };
8539
8647
 
8648
+ const generateCoverageJsonFile = async ({
8649
+ coverage,
8650
+ coverageJsonFileUrl,
8651
+ coverageJsonFileLog,
8652
+ logger
8653
+ }) => {
8654
+ const coverageAsText = JSON.stringify(coverage, null, " ");
8655
+
8656
+ if (coverageJsonFileLog) {
8657
+ logger.info(`-> ${urlToFileSystemPath(coverageJsonFileUrl)} (${byteAsFileSize(Buffer.byteLength(coverageAsText))})`);
8658
+ }
8659
+
8660
+ await writeFile(coverageJsonFileUrl, coverageAsText);
8661
+ };
8662
+
8663
+ const istanbulCoverageMapFromCoverage = coverage => {
8664
+ const {
8665
+ createCoverageMap
8666
+ } = requireFromJsenv("istanbul-lib-coverage");
8667
+ const coverageAdjusted = {};
8668
+ Object.keys(coverage).forEach(key => {
8669
+ coverageAdjusted[key.slice(2)] = { ...coverage[key],
8670
+ path: key.slice(2)
8671
+ };
8672
+ });
8673
+ const coverageMap = createCoverageMap(coverageAdjusted);
8674
+ return coverageMap;
8675
+ };
8676
+
8677
+ const generateCoverageHtmlDirectory = async (coverage, {
8678
+ rootDirectoryUrl,
8679
+ coverageHtmlDirectoryRelativeUrl,
8680
+ coverageSkipEmpty,
8681
+ coverageSkipFull
8682
+ }) => {
8683
+ const libReport = requireFromJsenv("istanbul-lib-report");
8684
+ const reports = requireFromJsenv("istanbul-reports");
8685
+ const context = libReport.createContext({
8686
+ dir: urlToFileSystemPath(rootDirectoryUrl),
8687
+ coverageMap: istanbulCoverageMapFromCoverage(coverage),
8688
+ sourceFinder: path => {
8689
+ return readFileSync(urlToFileSystemPath(resolveUrl(path, rootDirectoryUrl)), "utf8");
8690
+ }
8691
+ });
8692
+ const report = reports.create("html", {
8693
+ skipEmpty: coverageSkipEmpty,
8694
+ skipFull: coverageSkipFull,
8695
+ subdir: coverageHtmlDirectoryRelativeUrl
8696
+ });
8697
+ report.execute(context);
8698
+ };
8699
+
8700
+ const generateCoverageTextLog = (coverage, {
8701
+ coverageSkipEmpty,
8702
+ coverageSkipFull
8703
+ }) => {
8704
+ const libReport = requireFromJsenv("istanbul-lib-report");
8705
+ const reports = requireFromJsenv("istanbul-reports");
8706
+ const context = libReport.createContext({
8707
+ coverageMap: istanbulCoverageMapFromCoverage(coverage)
8708
+ });
8709
+ const report = reports.create("text", {
8710
+ skipEmpty: coverageSkipEmpty,
8711
+ skipFull: coverageSkipFull
8712
+ });
8713
+ report.execute(context);
8714
+ };
8715
+
8716
+ const babelPluginInstrument = (api, {
8717
+ rootDirectoryUrl,
8718
+ useInlineSourceMaps = false,
8719
+ coverageConfig = {
8720
+ "./**/*": true
8721
+ }
8722
+ }) => {
8723
+ const {
8724
+ programVisitor
8725
+ } = requireFromJsenv("istanbul-lib-instrument");
8726
+ const {
8727
+ types
8728
+ } = api;
8729
+ const associations = URL_META.resolveAssociations({
8730
+ cover: coverageConfig
8731
+ }, rootDirectoryUrl);
8732
+
8733
+ const shouldInstrument = url => {
8734
+ return URL_META.applyAssociations({
8735
+ url,
8736
+ associations
8737
+ }).cover;
8738
+ };
8739
+
8740
+ return {
8741
+ name: "transform-instrument",
8742
+ visitor: {
8743
+ Program: {
8744
+ enter(path) {
8745
+ const {
8746
+ file
8747
+ } = this;
8748
+ const {
8749
+ opts
8750
+ } = file;
8751
+
8752
+ if (!opts.sourceFileName) {
8753
+ console.warn(`cannot instrument file when "sourceFileName" option is not set`);
8754
+ return;
8755
+ }
8756
+
8757
+ const fileUrl = fileSystemPathToUrl(opts.sourceFileName);
8758
+
8759
+ if (!shouldInstrument(fileUrl)) {
8760
+ return;
8761
+ }
8762
+
8763
+ this.__dv__ = null;
8764
+ let inputSourceMap;
8765
+
8766
+ if (useInlineSourceMaps) {
8767
+ // https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
8768
+ inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
8769
+ } else {
8770
+ inputSourceMap = opts.inputSourceMap;
8771
+ }
8772
+
8773
+ this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
8774
+ coverageVariable: "__coverage__",
8775
+ inputSourceMap
8776
+ });
8777
+
8778
+ this.__dv__.enter(path);
8779
+ },
8780
+
8781
+ exit(path) {
8782
+ if (!this.__dv__) {
8783
+ return;
8784
+ }
8785
+
8786
+ const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
8787
+
8788
+
8789
+ this.file.metadata.coverage = object.fileCoverage;
8790
+ }
8791
+
8792
+ }
8793
+ }
8794
+ };
8795
+ };
8796
+
8797
+ const visitNodeV8Directory = async ({
8798
+ logger,
8799
+ signal,
8800
+ NODE_V8_COVERAGE,
8801
+ onV8Coverage,
8802
+ maxMsWaitingForNodeToWriteCoverageFile = 2000
8803
+ }) => {
8804
+ const operation = Abort.startOperation();
8805
+ operation.addAbortSignal(signal);
8806
+
8807
+ const tryReadDirectory = async () => {
8808
+ const dirContent = await readDirectory(NODE_V8_COVERAGE);
8809
+
8810
+ if (dirContent.length > 0) {
8811
+ return dirContent;
8812
+ }
8813
+
8814
+ logger.warn(`v8 coverage directory is empty at ${NODE_V8_COVERAGE}`);
8815
+ return dirContent;
8816
+ };
8817
+
8818
+ try {
8819
+ operation.throwIfAborted();
8820
+ const dirContent = await tryReadDirectory();
8821
+ const coverageDirectoryUrl = assertAndNormalizeDirectoryUrl(NODE_V8_COVERAGE);
8822
+ await dirContent.reduce(async (previous, dirEntry) => {
8823
+ operation.throwIfAborted();
8824
+ await previous;
8825
+ const dirEntryUrl = resolveUrl(dirEntry, coverageDirectoryUrl);
8826
+
8827
+ const tryReadJsonFile = async (timeSpentTrying = 0) => {
8828
+ const fileContent = await readFile(dirEntryUrl, {
8829
+ as: "string"
8830
+ });
8831
+
8832
+ if (fileContent === "") {
8833
+ if (timeSpentTrying < 400) {
8834
+ await new Promise(resolve => setTimeout(resolve, 200));
8835
+ return tryReadJsonFile(timeSpentTrying + 200);
8836
+ }
8837
+
8838
+ console.warn(`Coverage JSON file is empty at ${dirEntryUrl}`);
8839
+ return null;
8840
+ }
8841
+
8842
+ try {
8843
+ const fileAsJson = JSON.parse(fileContent);
8844
+ return fileAsJson;
8845
+ } catch (e) {
8846
+ if (timeSpentTrying < maxMsWaitingForNodeToWriteCoverageFile) {
8847
+ await new Promise(resolve => setTimeout(resolve, 200));
8848
+ return tryReadJsonFile(timeSpentTrying + 200);
8849
+ }
8850
+
8851
+ console.warn(createDetailedMessage(`Error while reading coverage file`, {
8852
+ "error stack": e.stack,
8853
+ "file": dirEntryUrl
8854
+ }));
8855
+ return null;
8856
+ }
8857
+ };
8858
+
8859
+ const fileContent = await tryReadJsonFile();
8860
+
8861
+ if (fileContent) {
8862
+ onV8Coverage(fileContent);
8863
+ }
8864
+ }, Promise.resolve());
8865
+ } finally {
8866
+ await operation.end();
8867
+ }
8868
+ };
8869
+ const filterV8Coverage = (v8Coverage, {
8870
+ urlShouldBeCovered
8871
+ }) => {
8872
+ const v8CoverageFiltered = { ...v8Coverage,
8873
+ result: v8Coverage.result.filter(fileReport => urlShouldBeCovered(fileReport.url))
8874
+ };
8875
+ return v8CoverageFiltered;
8876
+ };
8877
+
8878
+ const composeTwoV8Coverages = (firstV8Coverage, secondV8Coverage) => {
8879
+ if (secondV8Coverage.result.length === 0) {
8880
+ return firstV8Coverage;
8881
+ } // eslint-disable-next-line import/no-unresolved
8882
+
8883
+
8884
+ const {
8885
+ mergeProcessCovs
8886
+ } = requireFromJsenv("@c88/v8-coverage"); // "mergeProcessCovs" do not preserves source-map-cache during the merge
8887
+ // so we store sourcemap cache now
8888
+
8889
+ const sourceMapCache = {};
8890
+
8891
+ const visit = coverageReport => {
8892
+ if (coverageReport["source-map-cache"]) {
8893
+ Object.assign(sourceMapCache, coverageReport["source-map-cache"]);
8894
+ }
8895
+ };
8896
+
8897
+ visit(firstV8Coverage);
8898
+ visit(secondV8Coverage);
8899
+ const v8Coverage = mergeProcessCovs([firstV8Coverage, secondV8Coverage]);
8900
+ v8Coverage["source-map-cache"] = sourceMapCache;
8901
+ return v8Coverage;
8902
+ };
8903
+
8904
+ const composeTwoFileByFileIstanbulCoverages = (firstFileByFileIstanbulCoverage, secondFileByFileIstanbulCoverage) => {
8905
+ const fileByFileIstanbulCoverage = {};
8906
+ Object.keys(firstFileByFileIstanbulCoverage).forEach(key => {
8907
+ fileByFileIstanbulCoverage[key] = firstFileByFileIstanbulCoverage[key];
8908
+ });
8909
+ Object.keys(secondFileByFileIstanbulCoverage).forEach(key => {
8910
+ const firstCoverage = firstFileByFileIstanbulCoverage[key];
8911
+ const secondCoverage = secondFileByFileIstanbulCoverage[key];
8912
+ fileByFileIstanbulCoverage[key] = firstCoverage ? merge(firstCoverage, secondCoverage) : secondCoverage;
8913
+ });
8914
+ return fileByFileIstanbulCoverage;
8915
+ };
8916
+
8917
+ const merge = (firstIstanbulCoverage, secondIstanbulCoverage) => {
8918
+ const {
8919
+ createFileCoverage
8920
+ } = requireFromJsenv("istanbul-lib-coverage");
8921
+ const istanbulFileCoverageObject = createFileCoverage(firstIstanbulCoverage);
8922
+ istanbulFileCoverageObject.merge(secondIstanbulCoverage);
8923
+ const istanbulCoverage = istanbulFileCoverageObject.toJSON();
8924
+ return istanbulCoverage;
8925
+ };
8926
+
8927
+ const v8CoverageToIstanbul = async (v8Coverage, {
8928
+ signal
8929
+ }) => {
8930
+ const operation = Abort.startOperation();
8931
+ operation.addAbortSignal(signal);
8932
+
8933
+ try {
8934
+ const v8ToIstanbul = requireFromJsenv("v8-to-istanbul");
8935
+ const sourcemapCache = v8Coverage["source-map-cache"];
8936
+ let istanbulCoverageComposed = null;
8937
+ await v8Coverage.result.reduce(async (previous, fileV8Coverage) => {
8938
+ operation.throwIfAborted();
8939
+ await previous;
8940
+ const {
8941
+ source
8942
+ } = fileV8Coverage;
8943
+ let sources; // when v8 coverage comes from playwright (chromium) v8Coverage.source is set
8944
+
8945
+ if (typeof source === "string") {
8946
+ sources = {
8947
+ source
8948
+ };
8949
+ } // when v8 coverage comes from Node.js, the source can be read from sourcemapCache
8950
+ else if (sourcemapCache) {
8951
+ sources = sourcesFromSourceMapCache(fileV8Coverage.url, sourcemapCache);
8952
+ }
8953
+
8954
+ const path = urlToFileSystemPath(fileV8Coverage.url);
8955
+ const converter = v8ToIstanbul(path, // wrapperLength is undefined we don't need it
8956
+ // https://github.com/istanbuljs/v8-to-istanbul/blob/2b54bc97c5edf8a37b39a171ec29134ba9bfd532/lib/v8-to-istanbul.js#L27
8957
+ undefined, sources);
8958
+ await converter.load();
8959
+ converter.applyCoverage(fileV8Coverage.functions);
8960
+ const istanbulCoverage = converter.toIstanbul();
8961
+ istanbulCoverageComposed = istanbulCoverageComposed ? composeTwoFileByFileIstanbulCoverages(istanbulCoverageComposed, istanbulCoverage) : istanbulCoverage;
8962
+ }, Promise.resolve());
8963
+
8964
+ if (!istanbulCoverageComposed) {
8965
+ return {};
8966
+ }
8967
+
8968
+ istanbulCoverageComposed = markAsConvertedFromV8(istanbulCoverageComposed);
8969
+ return istanbulCoverageComposed;
8970
+ } finally {
8971
+ await operation.end();
8972
+ }
8973
+ };
8974
+
8975
+ const markAsConvertedFromV8 = fileByFileCoverage => {
8976
+ const fileByFileMarked = {};
8977
+ Object.keys(fileByFileCoverage).forEach(key => {
8978
+ const fileCoverage = fileByFileCoverage[key];
8979
+ fileByFileMarked[key] = { ...fileCoverage,
8980
+ fromV8: true
8981
+ };
8982
+ });
8983
+ return fileByFileMarked;
8984
+ };
8985
+
8986
+ const sourcesFromSourceMapCache = (url, sourceMapCache) => {
8987
+ const sourceMapAndLineLengths = sourceMapCache[url];
8988
+
8989
+ if (!sourceMapAndLineLengths) {
8990
+ return {};
8991
+ }
8992
+
8993
+ const {
8994
+ data,
8995
+ lineLengths
8996
+ } = sourceMapAndLineLengths; // See: https://github.com/nodejs/node/pull/34305
8997
+
8998
+ if (!data) {
8999
+ return undefined;
9000
+ }
9001
+
9002
+ const sources = {
9003
+ sourcemap: data,
9004
+ ...(lineLengths ? {
9005
+ source: sourcesFromLineLengths(lineLengths)
9006
+ } : {})
9007
+ };
9008
+ return sources;
9009
+ };
9010
+
9011
+ const sourcesFromLineLengths = lineLengths => {
9012
+ let source = "";
9013
+ lineLengths.forEach(length => {
9014
+ source += `${"".padEnd(length, ".")}\n`;
9015
+ });
9016
+ return source;
9017
+ };
9018
+
9019
+ const composeV8AndIstanbul = (v8FileByFileCoverage, istanbulFileByFileCoverage, {
9020
+ coverageV8ConflictWarning
9021
+ }) => {
9022
+ const fileByFileCoverage = {};
9023
+ const v8Files = Object.keys(v8FileByFileCoverage);
9024
+ const istanbulFiles = Object.keys(istanbulFileByFileCoverage);
9025
+ v8Files.forEach(key => {
9026
+ fileByFileCoverage[key] = v8FileByFileCoverage[key];
9027
+ });
9028
+ istanbulFiles.forEach(key => {
9029
+ const v8Coverage = v8FileByFileCoverage[key];
9030
+
9031
+ if (v8Coverage) {
9032
+ if (coverageV8ConflictWarning) {
9033
+ console.warn(createDetailedMessage(`Coverage conflict on "${key}", found two coverage that cannot be merged together: v8 and istanbul. The istanbul coverage will be ignored.`, {
9034
+ details: `This happens when a file is executed on a runtime using v8 coverage (node or chromium) and on runtime using istanbul coverage (firefox or webkit)`,
9035
+ suggestion: "You can disable this warning with coverageV8ConflictWarning: false"
9036
+ }));
9037
+ }
9038
+
9039
+ fileByFileCoverage[key] = v8Coverage;
9040
+ } else {
9041
+ fileByFileCoverage[key] = istanbulFileByFileCoverage[key];
9042
+ }
9043
+ });
9044
+ return fileByFileCoverage;
9045
+ };
9046
+
9047
+ const normalizeFileByFileCoveragePaths = (fileByFileCoverage, rootDirectoryUrl) => {
9048
+ const fileByFileNormalized = {};
9049
+ Object.keys(fileByFileCoverage).forEach(key => {
9050
+ const fileCoverage = fileByFileCoverage[key];
9051
+ const {
9052
+ path
9053
+ } = fileCoverage;
9054
+ const url = isFileSystemPath(path) ? fileSystemPathToUrl(path) : resolveUrl(path, rootDirectoryUrl);
9055
+ const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl);
9056
+ fileByFileNormalized[`./${relativeUrl}`] = { ...fileCoverage,
9057
+ path: `./${relativeUrl}`
9058
+ };
9059
+ });
9060
+ return fileByFileNormalized;
9061
+ };
9062
+
9063
+ const listRelativeFileUrlToCover = async ({
9064
+ signal,
9065
+ rootDirectoryUrl,
9066
+ coverageConfig
9067
+ }) => {
9068
+ const matchingFileResultArray = await collectFiles({
9069
+ signal,
9070
+ directoryUrl: rootDirectoryUrl,
9071
+ associations: {
9072
+ cover: coverageConfig
9073
+ },
9074
+ predicate: ({
9075
+ cover
9076
+ }) => cover
9077
+ });
9078
+ return matchingFileResultArray.map(({
9079
+ relativeUrl
9080
+ }) => relativeUrl);
9081
+ };
9082
+
9083
+ const relativeUrlToEmptyCoverage = async (relativeUrl, {
9084
+ signal,
9085
+ rootDirectoryUrl
9086
+ }) => {
9087
+ const operation = Abort.startOperation();
9088
+ operation.addAbortSignal(signal);
9089
+
9090
+ try {
9091
+ const fileUrl = resolveUrl(relativeUrl, rootDirectoryUrl);
9092
+ const content = await readFile(fileUrl, {
9093
+ as: "string"
9094
+ });
9095
+ operation.throwIfAborted();
9096
+ const {
9097
+ metadata
9098
+ } = await applyBabelPlugins({
9099
+ babelPlugins: [[babelPluginInstrument, {
9100
+ rootDirectoryUrl
9101
+ }]],
9102
+ urlInfo: {
9103
+ originalUrl: fileUrl,
9104
+ content
9105
+ }
9106
+ });
9107
+ const {
9108
+ coverage
9109
+ } = metadata;
9110
+
9111
+ if (!coverage) {
9112
+ throw new Error(`missing coverage for file`);
9113
+ } // https://github.com/gotwarlost/istanbul/blob/bc84c315271a5dd4d39bcefc5925cfb61a3d174a/lib/command/common/run-with-cover.js#L229
9114
+
9115
+
9116
+ Object.keys(coverage.s).forEach(function (key) {
9117
+ coverage.s[key] = 0;
9118
+ });
9119
+ return coverage;
9120
+ } catch (e) {
9121
+ if (e && e.code === "PARSE_ERROR") {
9122
+ // return an empty coverage for that file when
9123
+ // it contains a syntax error
9124
+ return createEmptyCoverage(relativeUrl);
9125
+ }
9126
+
9127
+ throw e;
9128
+ } finally {
9129
+ await operation.end();
9130
+ }
9131
+ };
9132
+
9133
+ const createEmptyCoverage = relativeUrl => {
9134
+ const {
9135
+ createFileCoverage
9136
+ } = requireFromJsenv("istanbul-lib-coverage");
9137
+ return createFileCoverage(relativeUrl).toJSON();
9138
+ };
9139
+
9140
+ const getMissingFileByFileCoverage = async ({
9141
+ signal,
9142
+ rootDirectoryUrl,
9143
+ coverageConfig,
9144
+ fileByFileCoverage
9145
+ }) => {
9146
+ const relativeUrlsToCover = await listRelativeFileUrlToCover({
9147
+ signal,
9148
+ rootDirectoryUrl,
9149
+ coverageConfig
9150
+ });
9151
+ const relativeUrlsMissing = relativeUrlsToCover.filter(relativeUrlToCover => Object.keys(fileByFileCoverage).every(key => {
9152
+ return key !== `./${relativeUrlToCover}`;
9153
+ }));
9154
+ const operation = Abort.startOperation();
9155
+ operation.addAbortSignal(signal);
9156
+ const missingFileByFileCoverage = {};
9157
+ await relativeUrlsMissing.reduce(async (previous, relativeUrlMissing) => {
9158
+ operation.throwIfAborted();
9159
+ await previous;
9160
+ await operation.withSignal(async signal => {
9161
+ const emptyCoverage = await relativeUrlToEmptyCoverage(relativeUrlMissing, {
9162
+ signal,
9163
+ rootDirectoryUrl
9164
+ });
9165
+ missingFileByFileCoverage[`./${relativeUrlMissing}`] = emptyCoverage;
9166
+ });
9167
+ }, Promise.resolve());
9168
+ return missingFileByFileCoverage;
9169
+ };
9170
+
9171
+ const reportToCoverage = async (report, {
9172
+ signal,
9173
+ logger,
9174
+ rootDirectoryUrl,
9175
+ coverageConfig,
9176
+ coverageIncludeMissing,
9177
+ urlShouldBeCovered,
9178
+ coverageForceIstanbul,
9179
+ coverageV8ConflictWarning
9180
+ }) => {
9181
+ // collect v8 and istanbul coverage from executions
9182
+ let {
9183
+ v8Coverage,
9184
+ fileByFileIstanbulCoverage
9185
+ } = await getCoverageFromReport({
9186
+ signal,
9187
+ report,
9188
+ onMissing: ({
9189
+ file,
9190
+ executionResult,
9191
+ executionName
9192
+ }) => {
9193
+ // several reasons not to have coverage here:
9194
+ // 1. the file we executed did not import an instrumented file.
9195
+ // - a test file without import
9196
+ // - a test file importing only file excluded from coverage
9197
+ // - a coverDescription badly configured so that we don't realize
9198
+ // a file should be covered
9199
+ // 2. the file we wanted to executed timedout
9200
+ // - infinite loop
9201
+ // - too extensive operation
9202
+ // - a badly configured or too low allocatedMs for that execution.
9203
+ // 3. the file we wanted to execute contains syntax-error
9204
+ // in any scenario we are fine because
9205
+ // coverDescription will generate empty coverage for files
9206
+ // that were suppose to be coverage but were not.
9207
+ if (executionResult.status === "completed" && executionResult.runtimeName !== "node" && !process.env.NODE_V8_COVERAGE) {
9208
+ logger.warn(`No execution.coverageFileUrl from execution named "${executionName}" of ${file}`);
9209
+ }
9210
+ }
9211
+ });
9212
+
9213
+ if (!coverageForceIstanbul && process.env.NODE_V8_COVERAGE) {
9214
+ await visitNodeV8Directory({
9215
+ logger,
9216
+ signal,
9217
+ NODE_V8_COVERAGE: process.env.NODE_V8_COVERAGE,
9218
+ onV8Coverage: nodeV8Coverage => {
9219
+ const nodeV8CoverageLight = filterV8Coverage(nodeV8Coverage, {
9220
+ urlShouldBeCovered
9221
+ });
9222
+ v8Coverage = v8Coverage ? composeTwoV8Coverages(v8Coverage, nodeV8CoverageLight) : nodeV8CoverageLight;
9223
+ }
9224
+ });
9225
+ } // try to merge v8 with istanbul, if any
9226
+
9227
+
9228
+ let fileByFileCoverage;
9229
+
9230
+ if (v8Coverage) {
9231
+ let v8FileByFileCoverage = await v8CoverageToIstanbul(v8Coverage, {
9232
+ signal
9233
+ });
9234
+ v8FileByFileCoverage = normalizeFileByFileCoveragePaths(v8FileByFileCoverage, rootDirectoryUrl);
9235
+
9236
+ if (fileByFileIstanbulCoverage) {
9237
+ fileByFileIstanbulCoverage = normalizeFileByFileCoveragePaths(fileByFileIstanbulCoverage, rootDirectoryUrl);
9238
+ fileByFileCoverage = composeV8AndIstanbul(v8FileByFileCoverage, fileByFileIstanbulCoverage, {
9239
+ coverageV8ConflictWarning
9240
+ });
9241
+ } else {
9242
+ fileByFileCoverage = v8FileByFileCoverage;
9243
+ }
9244
+ } // get istanbul only
9245
+ else if (fileByFileIstanbulCoverage) {
9246
+ fileByFileCoverage = normalizeFileByFileCoveragePaths(fileByFileIstanbulCoverage, rootDirectoryUrl);
9247
+ } // no coverage found in execution (or zero file where executed)
9248
+ else {
9249
+ fileByFileCoverage = {};
9250
+ } // now add coverage for file not covered
9251
+
9252
+
9253
+ if (coverageIncludeMissing) {
9254
+ const missingFileByFileCoverage = await getMissingFileByFileCoverage({
9255
+ signal,
9256
+ rootDirectoryUrl,
9257
+ coverageConfig,
9258
+ fileByFileCoverage
9259
+ });
9260
+ Object.assign(fileByFileCoverage, normalizeFileByFileCoveragePaths(missingFileByFileCoverage, rootDirectoryUrl));
9261
+ }
9262
+
9263
+ return fileByFileCoverage;
9264
+ };
9265
+
9266
+ const getCoverageFromReport = async ({
9267
+ signal,
9268
+ report,
9269
+ onMissing
9270
+ }) => {
9271
+ const operation = Abort.startOperation();
9272
+ operation.addAbortSignal(signal);
9273
+
9274
+ try {
9275
+ let v8Coverage;
9276
+ let fileByFileIstanbulCoverage; // collect v8 and istanbul coverage from executions
9277
+
9278
+ await Object.keys(report).reduce(async (previous, file) => {
9279
+ operation.throwIfAborted();
9280
+ await previous;
9281
+ const executionResultForFile = report[file];
9282
+ await Object.keys(executionResultForFile).reduce(async (previous, executionName) => {
9283
+ operation.throwIfAborted();
9284
+ await previous;
9285
+ const executionResultForFileOnRuntime = executionResultForFile[executionName];
9286
+ const {
9287
+ coverageFileUrl
9288
+ } = executionResultForFileOnRuntime;
9289
+
9290
+ if (!coverageFileUrl) {
9291
+ onMissing({
9292
+ executionName,
9293
+ file,
9294
+ executionResult: executionResultForFileOnRuntime
9295
+ });
9296
+ return;
9297
+ }
9298
+
9299
+ const executionCoverage = await readFile(coverageFileUrl, {
9300
+ as: "json"
9301
+ });
9302
+
9303
+ if (isV8Coverage(executionCoverage)) {
9304
+ v8Coverage = v8Coverage ? composeTwoV8Coverages(v8Coverage, executionCoverage) : executionCoverage;
9305
+ } else {
9306
+ fileByFileIstanbulCoverage = fileByFileIstanbulCoverage ? composeTwoFileByFileIstanbulCoverages(fileByFileIstanbulCoverage, executionCoverage) : executionCoverage;
9307
+ }
9308
+ }, Promise.resolve());
9309
+ }, Promise.resolve());
9310
+ return {
9311
+ v8Coverage,
9312
+ fileByFileIstanbulCoverage
9313
+ };
9314
+ } finally {
9315
+ await operation.end();
9316
+ }
9317
+ };
9318
+
9319
+ const isV8Coverage = coverage => Boolean(coverage.result);
9320
+
8540
9321
  const run = async ({
8541
9322
  signal = new AbortController().signal,
8542
9323
  logger,
@@ -13032,9 +13813,9 @@ const startBuildServer = async ({
13032
13813
  buildServerMainFile = getCallerPosition().url,
13033
13814
  // force disable server autoreload when this code is executed:
13034
13815
  // - inside a forked child process
13035
- // - inside a worker thread
13036
- // (because node cluster won't work)
13037
- buildServerAutoreload = typeof process.send !== "function" && !parentPort && !process.env.VSCODE_INSPECTOR_OPTIONS,
13816
+ // - debugged by vscode
13817
+ // otherwise we get net:ERR_CONNECTION_REFUSED
13818
+ buildServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
13038
13819
  cooldownBetweenFileEvents
13039
13820
  }) => {
13040
13821
  const logger = createLogger({
@@ -13042,19 +13823,26 @@ const startBuildServer = async ({
13042
13823
  });
13043
13824
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
13044
13825
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl);
13045
- const reloadableProcess = await initReloadableProcess({
13046
- signal,
13047
- handleSIGINT,
13048
- ...(buildServerAutoreload ? {
13049
- enabled: true,
13050
- logLevel: "info",
13051
- fileToRestart: buildServerMainFile
13052
- } : {
13053
- enabled: false
13054
- })
13055
- });
13826
+ const operation = Abort.startOperation();
13827
+ operation.addAbortSignal(signal);
13828
+
13829
+ if (handleSIGINT) {
13830
+ operation.addAbortSource(abort => {
13831
+ return raceProcessTeardownEvents({
13832
+ SIGINT: true
13833
+ }, abort);
13834
+ });
13835
+ }
13836
+
13837
+ if (port === 0) {
13838
+ port = await findFreePort(port, {
13839
+ signal: operation.signal
13840
+ });
13841
+ }
13842
+
13843
+ const reloadableWorker = createReloadableWorker(buildServerMainFile);
13056
13844
 
13057
- if (reloadableProcess.isPrimary) {
13845
+ if (buildServerAutoreload && reloadableWorker.isPrimary) {
13058
13846
  const buildServerFileChangeCallback = ({
13059
13847
  relativeUrl,
13060
13848
  event
@@ -13063,7 +13851,7 @@ const startBuildServer = async ({
13063
13851
 
13064
13852
  if (buildServerAutoreload) {
13065
13853
  logger.info(`file ${event} ${url} -> restarting server...`);
13066
- reloadableProcess.reload();
13854
+ reloadableWorker.reload();
13067
13855
  }
13068
13856
  };
13069
13857
 
@@ -13100,19 +13888,20 @@ const startBuildServer = async ({
13100
13888
  });
13101
13889
  }
13102
13890
  });
13103
- signal.addEventListener("abort", () => {
13891
+ operation.addAbortCallback(() => {
13104
13892
  stopWatchingBuildServerFiles();
13893
+ reloadableWorker.terminate();
13105
13894
  });
13895
+ await reloadableWorker.load();
13106
13896
  return {
13107
13897
  origin: `${protocol}://127.0.0.1:${port}`,
13108
13898
  stop: () => {
13109
13899
  stopWatchingBuildServerFiles();
13110
- reloadableProcess.stop();
13900
+ reloadableWorker.terminate();
13111
13901
  }
13112
13902
  };
13113
13903
  }
13114
13904
 
13115
- signal = reloadableProcess.signal;
13116
13905
  const startBuildServerTask = createTaskLog("start build server", {
13117
13906
  disabled: !loggerToLevels(logger).info
13118
13907
  });