@jsenv/core 23.2.0 → 23.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/{license → LICENSE} +0 -0
  2. package/dist/jsenv_browser_system.js +18 -17
  3. package/dist/jsenv_browser_system.js.map +2 -2
  4. package/package.json +14 -14
  5. package/readme.md +1 -1
  6. package/src/buildProject.js +12 -13
  7. package/src/execute.js +92 -93
  8. package/src/executeTestPlan.js +15 -12
  9. package/src/internal/browser-launcher/executeHtmlFile.js +37 -25
  10. package/src/internal/building/buildUsingRollup.js +3 -4
  11. package/src/internal/building/build_logs.js +7 -6
  12. package/src/internal/building/createJsenvRollupPlugin.js +9 -14
  13. package/src/internal/building/url_trace.js +3 -4
  14. package/src/internal/compiling/createCompiledFileService.js +8 -5
  15. package/src/internal/compiling/startCompileServer.js +55 -46
  16. package/src/internal/executing/coverage/babel_plugin_instrument.js +1 -0
  17. package/src/internal/executing/coverage/reportToCoverage.js +147 -120
  18. package/src/internal/executing/{coverage → coverage_empty}/createEmptyCoverage.js +0 -0
  19. package/src/internal/executing/coverage_empty/list_files_not_covered.js +20 -0
  20. package/src/internal/executing/{coverage → coverage_empty}/relativeUrlToEmptyCoverage.js +3 -4
  21. package/src/internal/executing/{coverage/generateCoverageHtmlDirectory.js → coverage_reporter/coverage_reporter_html_directory.js} +11 -4
  22. package/src/internal/executing/coverage_reporter/coverage_reporter_json_file.js +22 -0
  23. package/src/internal/executing/{coverage/generateCoverageTextLog.js → coverage_reporter/coverage_reporter_text_log.js} +4 -2
  24. package/src/internal/executing/{coverage → coverage_reporter}/istanbulCoverageMapFromCoverage.js +0 -0
  25. package/src/internal/executing/{coverage/normalizeIstanbulCoverage.js → coverage_utils/file_by_file_coverage.js} +9 -7
  26. package/src/internal/executing/coverage_utils/istanbul_coverage_composition.js +28 -0
  27. package/src/internal/executing/coverage_utils/v8_and_istanbul.js +38 -0
  28. package/src/internal/executing/coverage_utils/v8_coverage_composition.js +23 -0
  29. package/src/internal/executing/coverage_utils/v8_coverage_from_directory.js +59 -0
  30. package/src/internal/executing/coverage_utils/v8_coverage_to_istanbul.js +90 -0
  31. package/src/internal/executing/createSummaryLog.js +20 -20
  32. package/src/internal/executing/executeConcurrently.js +92 -32
  33. package/src/internal/executing/executePlan.js +84 -81
  34. package/src/internal/executing/executionLogs.js +14 -18
  35. package/src/internal/executing/execution_colors.js +6 -12
  36. package/src/internal/executing/launchAndExecute.js +179 -176
  37. package/src/internal/node-launcher/createControllableNodeProcess.js +26 -23
  38. package/src/internal/runtime/s.js +25 -24
  39. package/src/launchBrowser.js +82 -75
  40. package/src/launchNode.js +11 -102
  41. package/src/startExploring.js +2 -17
  42. package/src/abort/abortable.js +0 -172
  43. package/src/abort/callback_list.js +0 -64
  44. package/src/abort/callback_race.js +0 -34
  45. package/src/abort/cleaner.js +0 -22
  46. package/src/abort/main.js +0 -32
  47. package/src/abort/process_teardown_events.js +0 -59
  48. package/src/internal/createCallbackList.js +0 -21
  49. package/src/internal/executing/coverage/composeIstanbulCoverages.js +0 -108
  50. package/src/internal/executing/coverage/composeV8Coverages.js +0 -20
  51. package/src/internal/executing/coverage/generateCoverageJsonFile.js +0 -5
  52. package/src/internal/executing/coverage/istanbulCoverageFromCoverages.js +0 -43
  53. package/src/internal/executing/coverage/istanbulCoverageFromV8Coverage.js +0 -79
  54. package/src/internal/executing/coverage/v8CoverageFromAllV8Coverages.js +0 -40
  55. package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +0 -67
  56. package/src/internal/executing/logUtils.js +0 -30
  57. package/src/internal/executing/writeLog.js +0 -106
  58. package/src/internal/executing/writeLog.test-manual.js +0 -62
  59. package/src/internal/logs/log_style.js +0 -40
  60. package/src/signal/signal.js +0 -65
@@ -1,172 +0,0 @@
1
- /*
2
- * https://github.com/whatwg/dom/issues/920
3
- */
4
-
5
- import { createCleaner } from "./cleaner.js"
6
- import { raceCallbacks } from "./callback_race.js"
7
- import { createCallbackList } from "./callback_list.js"
8
-
9
- export const Abortable = {
10
- throwIfAborted: (operation) => {
11
- if (operation.signal.aborted) {
12
- const error = new Error(`The operation was aborted`)
13
- error.name = "AbortError"
14
- error.type = "aborted"
15
- throw error
16
- }
17
- },
18
-
19
- isAbortError: (error) => {
20
- return error.name === "AbortError"
21
- },
22
-
23
- start: () => {
24
- const abortController = new AbortController()
25
- const abort = (value) => abortController.abort(value)
26
- const signal = abortController.signal
27
- const cleaner = createCleaner()
28
-
29
- // abortCallbackList is used to ignore the max listeners warning from Node.js
30
- // this warning is useful but becomes problematic when it's expected
31
- // (a function doing 20 http call in parallel)
32
- // To be 100% sure we don't have memory leak, only Abortable.asyncCallback
33
- // uses abortCallbackList to know when something is aborted
34
- const abortCallbackList = createCallbackList()
35
- signal.onabort = () => {
36
- const callbacks = abortCallbackList.copy()
37
- abortCallbackList.clear()
38
- callbacks.forEach((callback) => {
39
- callback()
40
- })
41
- }
42
- cleaner.addCallback(() => {
43
- abortCallbackList.clear()
44
- })
45
-
46
- const operation = {
47
- abort,
48
- signal,
49
- abortCallbackList,
50
- cleaner,
51
- }
52
-
53
- return operation
54
- },
55
-
56
- fromSignal: (signal) => {
57
- const operation = Abortable.start()
58
- Abortable.followSignal(operation, signal)
59
- return operation
60
- },
61
-
62
- followSignal: (operation, signal, cleanup = cleanupNoop) => {
63
- if (operation.signal.aborted) {
64
- return () => {}
65
- }
66
-
67
- if (signal.aborted) {
68
- operation.abort()
69
- return () => {}
70
- }
71
-
72
- return raceCallbacks(
73
- {
74
- parent_abort: (cb) => {
75
- return operation.abortCallbackList.add(cb)
76
- },
77
- child_abort: (cb) => {
78
- return addEventListener(signal, "abort", cb)
79
- },
80
- cleaned: (cb) => {
81
- return operation.cleaner.addCallback(cb)
82
- },
83
- },
84
- (winner) => {
85
- const raceEffects = {
86
- parent_abort: () => {
87
- // Nothing to do, exists to remove
88
- // - "abort" event listener on parent
89
- // - "abort" event listener on child
90
- cleanup()
91
- },
92
- child_abort: () => {
93
- operation.abort()
94
- },
95
- cleaned: () => {
96
- // Nothing to do, exists to remove
97
- // - "abort" event listener on parent
98
- // - "abort" event listener on child
99
- cleanup()
100
- },
101
- }
102
- raceEffects[winner.name](winner.value)
103
- },
104
- )
105
- },
106
-
107
- effect: (operation, effect) => {
108
- const abortController = new AbortController()
109
- const returnValue = effect((value) => abortController.abort(value))
110
- const cleanup =
111
- typeof returnValue === "function" ? returnValue : cleanupNoop
112
- const signal = abortController.signal
113
-
114
- Abortable.followSignal(operation, signal, cleanup)
115
- return {
116
- signal,
117
- cleanup,
118
- }
119
- },
120
-
121
- timeout: (operation, ms) => {
122
- return Abortable.effect(operation, (abort) => {
123
- const timeoutId = setTimeout(abort, ms)
124
- return () => {
125
- clearTimeout(timeoutId)
126
- }
127
- })
128
- },
129
-
130
- cleanOnAbort: (operation) => {
131
- const removeAbortEventListener = addEventListener(
132
- operation.signal,
133
- "abort",
134
- () => {
135
- removeAbortEventListener()
136
- operation.cleaner.clean("operation aborted")
137
- },
138
- )
139
- return removeAbortEventListener
140
- },
141
-
142
- // Provide a signal to the callback
143
- // this signal won't inherit the current signal max listeners
144
- asyncCallback: async (operation, asyncFunction) => {
145
- Abortable.throwIfAborted(operation)
146
-
147
- const abortController = new AbortController()
148
- const signal = abortController.signal
149
-
150
- const removeOperationAbortCallback = operation.abortCallbackList.add(() => {
151
- abortController.abort()
152
- })
153
-
154
- try {
155
- const value = await asyncFunction(signal)
156
- removeOperationAbortCallback()
157
- return value
158
- } catch (e) {
159
- removeOperationAbortCallback()
160
- throw e
161
- }
162
- },
163
- }
164
-
165
- const cleanupNoop = () => {}
166
-
167
- const addEventListener = (target, eventName, cb) => {
168
- target.addEventListener(eventName, cb)
169
- return () => {
170
- target.removeEventListener(eventName, cb)
171
- }
172
- }
@@ -1,64 +0,0 @@
1
- export const createCallbackList = () => {
2
- let callbacks = []
3
-
4
- const add = (callback) => {
5
- if (typeof callback !== "function") {
6
- throw new Error(`callback must be a function, got ${callback}`)
7
- }
8
-
9
- // don't register twice
10
- const existingCallback = callbacks.find((callbackCandidate) => {
11
- return callbackCandidate === callback
12
- })
13
- if (existingCallback) {
14
- if (typeof process.emitWarning === "object") {
15
- process.emitWarning(`Trying to register same callback twice`, {
16
- CODE: "CALLBACK_DUPLICATION",
17
- detail: `It's often the sign that code is executd more than once`,
18
- })
19
- } else {
20
- console.warn(`Trying to add same callback twice`)
21
- }
22
- } else {
23
- callbacks = [...callbacks, callback]
24
- }
25
-
26
- return () => {
27
- remove(callback)
28
- }
29
- }
30
-
31
- const remove = (callback) => {
32
- callbacks = arrayWithout(callbacks, callback)
33
- }
34
-
35
- const clear = () => {
36
- callbacks = []
37
- }
38
-
39
- const copy = () => {
40
- return callbacks.slice()
41
- }
42
-
43
- return {
44
- add,
45
- remove,
46
- clear,
47
- copy,
48
- }
49
- }
50
-
51
- const arrayWithout = (array, item) => {
52
- if (array.length === 0) return array
53
- const arrayWithoutItem = []
54
- let i = 0
55
- while (i < array.length) {
56
- const value = array[i]
57
- i++
58
- if (value === item) {
59
- continue
60
- }
61
- arrayWithoutItem.push(value)
62
- }
63
- return arrayWithoutItem
64
- }
@@ -1,34 +0,0 @@
1
- /*
2
- * See callback_race.md
3
- */
4
-
5
- export const raceCallbacks = (raceDescription, winnerCallback) => {
6
- const cleanCallbacks = []
7
- let done = false
8
-
9
- const cleanup = () => {
10
- const cleanCallbacksCopy = cleanCallbacks.slice()
11
- cleanCallbacks.length = 0
12
- cleanCallbacksCopy.forEach((clean) => {
13
- clean()
14
- })
15
- }
16
-
17
- Object.keys(raceDescription).forEach((candidateName) => {
18
- const register = raceDescription[candidateName]
19
- const returnValue = register((data) => {
20
- if (done) return
21
- done = true
22
- cleanup()
23
- winnerCallback({
24
- name: candidateName,
25
- data,
26
- })
27
- })
28
- if (typeof returnValue === "function") {
29
- cleanCallbacks.push(returnValue)
30
- }
31
- })
32
-
33
- return cleanup
34
- }
@@ -1,22 +0,0 @@
1
- import { createCallbackList } from "./callback_list.js"
2
-
3
- export const createCleaner = () => {
4
- const callbackList = createCallbackList()
5
-
6
- const addCallback = (callback) => {
7
- return callbackList.add(callback)
8
- }
9
-
10
- const clean = async (reason) => {
11
- const callbacks = callbackList.copy()
12
- callbackList.clear()
13
-
14
- await Promise.all(
15
- callbacks.map(async (callback) => {
16
- await callback(reason)
17
- }),
18
- )
19
- }
20
-
21
- return { addCallback, clean }
22
- }
package/src/abort/main.js DELETED
@@ -1,32 +0,0 @@
1
- /*
2
- * When starting an http server there is two distinct things
3
- * that code may want to do:
4
- * 1. Abort the server while it's starting
5
- * 2. Stop server onces its started
6
- *
7
- * This can be achieved with the following code where
8
- * server is aborted if it takes more than 1s to start
9
- * and immediatly stopped once started
10
- *
11
- * const abortController = new AbortController()
12
- * setTimeout(() => { abortController.abort() }, 1000)
13
- * const server = await startServer({
14
- * abortSignal: abortController.signal
15
- * })
16
- * await server.stop()
17
- *
18
- * In order to implement this kind of API two helpers are exported
19
- * here:
20
- * 1. "Abort" which can be used to throw an abort error
21
- * while server is starting
22
- * 2. "Cleanup" which can be used to track how to cleanup all the things
23
- * done to start the server
24
- *
25
- * Same concepts could be reused when spwaning a child process, a worker, etc..
26
- *
27
- */
28
-
29
- export { Abortable } from "./abortable.js"
30
-
31
- // when will be a package this should be a Node.js export only
32
- export { raceProcessTeardownEvents } from "./process_teardown_events.js"
@@ -1,59 +0,0 @@
1
- import { raceCallbacks } from "./callback_race.js"
2
-
3
- export const raceProcessTeardownEvents = (processTeardownEvents, callback) => {
4
- return raceCallbacks(
5
- {
6
- ...(processTeardownEvents.SIGHUP ? SIGHUP_CALLBACK : {}),
7
- ...(processTeardownEvents.SIGTERM ? SIGTERM_CALLBACK : {}),
8
- ...(processTeardownEvents.SIGINT ? SIGINT_CALLBACK : {}),
9
- ...(processTeardownEvents.beforeExit ? BEFORE_EXIT_CALLBACK : {}),
10
- ...(processTeardownEvents.exit ? EXIT_CALLBACK : {}),
11
- },
12
- callback,
13
- )
14
- }
15
-
16
- const SIGHUP_CALLBACK = {
17
- SIGHUP: (cb) => {
18
- process.on("SIGHUP", cb)
19
- return () => {
20
- process.removeListener("SIGHUP", cb)
21
- }
22
- },
23
- }
24
-
25
- const SIGTERM_CALLBACK = {
26
- SIGTERM: (cb) => {
27
- process.on("SIGTERM", cb)
28
- return () => {
29
- process.removeListener("SIGTERM", cb)
30
- }
31
- },
32
- }
33
-
34
- const BEFORE_EXIT_CALLBACK = {
35
- beforeExit: (cb) => {
36
- process.on("beforeExit", cb)
37
- return () => {
38
- process.removeListener("beforeExit", cb)
39
- }
40
- },
41
- }
42
-
43
- const EXIT_CALLBACK = {
44
- exit: (cb) => {
45
- process.on("exit", cb)
46
- return () => {
47
- process.removeListener("exit", cb)
48
- }
49
- },
50
- }
51
-
52
- const SIGINT_CALLBACK = {
53
- SIGINT: (cb) => {
54
- process.on("SIGINT", cb)
55
- return () => {
56
- process.removeListener("SIGINT", cb)
57
- }
58
- },
59
- }
@@ -1,21 +0,0 @@
1
- export const createCallbackList = () => {
2
- const callbackSet = new Set()
3
-
4
- const register = (callback) => {
5
- callbackSet.add(callback)
6
- return () => {
7
- callbackSet.delete(callback)
8
- }
9
- }
10
-
11
- const notify = (...args) => {
12
- callbackSet.forEach((callback) => {
13
- callback(...args)
14
- })
15
- }
16
-
17
- return {
18
- register,
19
- notify,
20
- }
21
- }
@@ -1,108 +0,0 @@
1
- import { require } from "../../require.js"
2
-
3
- // https://github.com/istanbuljs/istanbuljs/blob/5405550c3868712b14fd8bfe0cbd6f2e7ac42279/packages/istanbul-lib-coverage/lib/coverage-map.js#L43
4
- export const composeIstanbulCoverages = (
5
- istanbulCoverages,
6
- { coverageV8MergeConflictIsExpected = false } = {},
7
- ) => {
8
- const coverageComposed = {}
9
-
10
- // we can't merge coverage coming from code instrumented by istanbul
11
- // with coverage coming from v8 and converted to istanbul, so we want to:
12
- // 1. Have istanbul and v8 as long as they don't cover the same file
13
- // 2. Choose istanbul or v8 depending which one cover the most
14
- // To do that we first merge all v8 together and istanbul together
15
- // To be able to know which one covers the most in case of merge conflict
16
- const coverageFromV8Conversion = {}
17
- const coverageFromIstanbul = {}
18
- istanbulCoverages.forEach((istanbulCoverage) => {
19
- Object.keys(istanbulCoverage).forEach((key) => {
20
- const istanbulFileCoverage = istanbulCoverage[key]
21
- if (istanbulFileCoverage.fromV8) {
22
- const existingCoverageForFile = coverageFromV8Conversion[key]
23
- if (existingCoverageForFile) {
24
- coverageFromV8Conversion[key] = merge(existingCoverageForFile, istanbulFileCoverage)
25
- } else {
26
- coverageFromV8Conversion[key] = istanbulFileCoverage
27
- }
28
- } else {
29
- const existingCoverageForFile = coverageFromIstanbul[key]
30
- if (existingCoverageForFile) {
31
- coverageFromIstanbul[key] = merge(existingCoverageForFile, istanbulFileCoverage)
32
- } else {
33
- coverageFromIstanbul[key] = istanbulFileCoverage
34
- }
35
- }
36
- })
37
- })
38
-
39
- Object.keys(coverageFromV8Conversion).forEach((key) => {
40
- const fileCoverageFromV8 = coverageFromV8Conversion[key]
41
- const fileCoverageFromIstanbul = coverageFromIstanbul[key]
42
- if (fileCoverageFromIstanbul) {
43
- const v8HitCount = hitCountFromFileCoverage(fileCoverageFromV8)
44
- const istanbulHitCount = hitCountFromFileCoverage(fileCoverageFromIstanbul)
45
- const coverageWithMostHit =
46
- v8HitCount >= istanbulHitCount ? fileCoverageFromV8 : fileCoverageFromIstanbul
47
-
48
- if (!coverageV8MergeConflictIsExpected) {
49
- // ideally when coverageV8MergeConflictIsExpected it would be a console.debug
50
- console.warn(
51
- formatMergeConflictBetweenV8AndIstanbulWarning({
52
- fileRelativeUrl: key,
53
- coverageKept: coverageWithMostHit,
54
- }),
55
- )
56
- }
57
- coverageComposed[key] = coverageWithMostHit
58
- } else {
59
- coverageComposed[key] = fileCoverageFromV8
60
- }
61
- })
62
-
63
- Object.keys(coverageFromIstanbul).forEach((key) => {
64
- const fileCoverageFromIstanbul = coverageFromIstanbul[key]
65
- const fileCoverageFromV8 = coverageFromV8Conversion[key]
66
- if (fileCoverageFromV8) {
67
- // already handled
68
- } else {
69
- coverageComposed[key] = fileCoverageFromIstanbul
70
- }
71
- })
72
-
73
- return coverageComposed
74
- }
75
-
76
- const hitCountFromFileCoverage = ({ b, s }) => {
77
- const statementHitCount = Object.keys(s).reduce((previous, key) => {
78
- return previous + s[key]
79
- }, 0)
80
-
81
- const branchHitCount = Object.keys(b).reduce((previous, key) => {
82
- const branchCount = b[key].reduce((previous, count) => {
83
- return previous + count
84
- }, 0)
85
- return previous + branchCount
86
- }, 0)
87
-
88
- return statementHitCount + branchHitCount
89
- }
90
-
91
- const merge = (istanbulFileCoverageA, istanbulFileCoverageB) => {
92
- const { createFileCoverage } = require("istanbul-lib-coverage")
93
- const istanbulFileCoverageObject = createFileCoverage(istanbulFileCoverageA)
94
- istanbulFileCoverageObject.merge(istanbulFileCoverageB)
95
- return istanbulFileCoverageObject.toJSON()
96
- }
97
-
98
- const formatMergeConflictBetweenV8AndIstanbulWarning = ({ fileRelativeUrl, coverageKept }) => {
99
- return `Cannot merge file coverage coming from v8 and istanbul.
100
- The one with most branch coverage will be kept and the other ignored.
101
- --- coverage kept ---
102
- ${coverageKept.fromV8 ? "v8" : "istanbul"}
103
- --- file ---
104
- ${fileRelativeUrl}
105
- --- suggestion ---
106
- If this is expected use coverageV8MergeConflictIsExpected to disable this warning
107
- `
108
- }
@@ -1,20 +0,0 @@
1
- import { require } from "@jsenv/core/src/internal/require.js"
2
-
3
- export const composeV8Coverages = (v8Coverages) => {
4
- const { mergeProcessCovs } = require("@c88/v8-coverage")
5
-
6
- // mergeCoverageReports do not preserves source-map-cache during the merge
7
- // so we store sourcemap cache now
8
- const sourceMapCache = {}
9
- v8Coverages.forEach((coverageReport) => {
10
- coverageReport.result.forEach((fileReport) => {
11
- if (fileReport["source-map-cache"]) {
12
- Object.assign(sourceMapCache, fileReport["source-map-cache"])
13
- }
14
- })
15
- })
16
-
17
- const v8Coverage = mergeProcessCovs(v8Coverages)
18
- v8Coverage["source-map-cache"] = sourceMapCache
19
- return v8Coverage
20
- }
@@ -1,5 +0,0 @@
1
- import { writeFile } from "@jsenv/filesystem"
2
-
3
- export const generateCoverageJsonFile = async (coverage, coverageJsonFileUrl) => {
4
- await writeFile(coverageJsonFileUrl, JSON.stringify(coverage, null, " "))
5
- }
@@ -1,43 +0,0 @@
1
- /**
2
- *
3
- * The goal is to get an istanbul coverage from a list of coverage that are either
4
- * v8Coverage or istanbul coverage
5
- *
6
- */
7
-
8
- import { composeV8Coverages } from "./composeV8Coverages.js"
9
- import { composeIstanbulCoverages } from "./composeIstanbulCoverages.js"
10
- import { istanbulCoverageFromV8Coverage } from "./istanbulCoverageFromV8Coverage.js"
11
- import { normalizeIstanbulCoverage } from "./normalizeIstanbulCoverage.js"
12
-
13
- export const istanbulCoverageFromCoverages = async (
14
- coverages,
15
- { projectDirectoryUrl, coverageV8MergeConflictIsExpected },
16
- ) => {
17
- const v8Coverages = []
18
- const istanbulCoverages = []
19
-
20
- coverages.forEach((coverage) => {
21
- if (coverage.result) {
22
- v8Coverages.push(coverage)
23
- } else {
24
- istanbulCoverages.push(normalizeIstanbulCoverage(coverage, projectDirectoryUrl))
25
- }
26
- })
27
-
28
- const v8CoverageComposed = composeV8Coverages(v8Coverages)
29
- const istanbulCoverageComposed = composeIstanbulCoverages(istanbulCoverages)
30
- const istanbulCoverageFromV8CoverageComposed = await istanbulCoverageFromV8Coverage(
31
- v8CoverageComposed,
32
- )
33
- const istanbulCoverage = composeIstanbulCoverages(
34
- [
35
- istanbulCoverageComposed,
36
- normalizeIstanbulCoverage(istanbulCoverageFromV8CoverageComposed, projectDirectoryUrl),
37
- ],
38
- {
39
- coverageV8MergeConflictIsExpected,
40
- },
41
- )
42
- return istanbulCoverage
43
- }
@@ -1,79 +0,0 @@
1
- import { urlToFileSystemPath } from "@jsenv/filesystem"
2
-
3
- import { require } from "@jsenv/core/src/internal/require.js"
4
-
5
- import { composeIstanbulCoverages } from "./composeIstanbulCoverages.js"
6
-
7
- export const istanbulCoverageFromV8Coverage = async (v8Coverage) => {
8
- const v8ToIstanbul = require("v8-to-istanbul")
9
- const sourcemapCache = v8Coverage["source-map-cache"]
10
- const istanbulCoverages = await Promise.all(
11
- v8Coverage.result.map(async (fileV8Coverage) => {
12
- const { source } = fileV8Coverage
13
- let sources
14
- // when v8 coverage comes from playwright (chromium) v8Coverage.source is set
15
- if (typeof source === "string") {
16
- sources = { source }
17
- }
18
- // when v8 coverage comes from Node.js, the source can be read from sourcemapCache
19
- else if (sourcemapCache) {
20
- sources = sourcesFromSourceMapCache(fileV8Coverage.url, sourcemapCache)
21
- }
22
- const path = urlToFileSystemPath(fileV8Coverage.url)
23
-
24
- const converter = v8ToIstanbul(
25
- path,
26
- // wrapperLength is undefined we don't need it
27
- // https://github.com/istanbuljs/v8-to-istanbul/blob/2b54bc97c5edf8a37b39a171ec29134ba9bfd532/lib/v8-to-istanbul.js#L27
28
- undefined,
29
- sources,
30
- )
31
- await converter.load()
32
-
33
- converter.applyCoverage(fileV8Coverage.functions)
34
- const istanbulCoverage = converter.toIstanbul()
35
- return istanbulCoverage
36
- }),
37
- )
38
-
39
- const istanbulCoverageComposed = composeIstanbulCoverages(istanbulCoverages)
40
- return markCoverageAsConverted(istanbulCoverageComposed)
41
- }
42
-
43
- const markCoverageAsConverted = (istanbulCoverage) => {
44
- const istanbulCoverageMarked = {}
45
- Object.keys(istanbulCoverage).forEach((key) => {
46
- istanbulCoverageMarked[key] = {
47
- ...istanbulCoverage[key],
48
- fromV8: true,
49
- }
50
- })
51
- return istanbulCoverageMarked
52
- }
53
-
54
- const sourcesFromSourceMapCache = (url, sourceMapCache) => {
55
- const sourceMapAndLineLengths = sourceMapCache[url]
56
- if (!sourceMapAndLineLengths) {
57
- return {}
58
- }
59
-
60
- const { data, lineLengths } = sourceMapAndLineLengths
61
- // See: https://github.com/nodejs/node/pull/34305
62
- if (!data) {
63
- return undefined
64
- }
65
-
66
- const sources = {
67
- sourcemap: data,
68
- ...(lineLengths ? { source: sourcesFromLineLengths(lineLengths) } : {}),
69
- }
70
- return sources
71
- }
72
-
73
- const sourcesFromLineLengths = (lineLengths) => {
74
- let source = ""
75
- lineLengths.forEach((length) => {
76
- source += `${"".padEnd(length, ".")}\n`
77
- })
78
- return source
79
- }