@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.
- package/{license → LICENSE} +0 -0
- package/dist/jsenv_browser_system.js +18 -17
- package/dist/jsenv_browser_system.js.map +2 -2
- package/package.json +14 -14
- package/readme.md +1 -1
- package/src/buildProject.js +12 -13
- package/src/execute.js +92 -93
- package/src/executeTestPlan.js +15 -12
- package/src/internal/browser-launcher/executeHtmlFile.js +37 -25
- package/src/internal/building/buildUsingRollup.js +3 -4
- package/src/internal/building/build_logs.js +7 -6
- package/src/internal/building/createJsenvRollupPlugin.js +9 -14
- package/src/internal/building/url_trace.js +3 -4
- package/src/internal/compiling/createCompiledFileService.js +8 -5
- package/src/internal/compiling/startCompileServer.js +55 -46
- package/src/internal/executing/coverage/babel_plugin_instrument.js +1 -0
- package/src/internal/executing/coverage/reportToCoverage.js +147 -120
- package/src/internal/executing/{coverage → coverage_empty}/createEmptyCoverage.js +0 -0
- package/src/internal/executing/coverage_empty/list_files_not_covered.js +20 -0
- package/src/internal/executing/{coverage → coverage_empty}/relativeUrlToEmptyCoverage.js +3 -4
- package/src/internal/executing/{coverage/generateCoverageHtmlDirectory.js → coverage_reporter/coverage_reporter_html_directory.js} +11 -4
- package/src/internal/executing/coverage_reporter/coverage_reporter_json_file.js +22 -0
- package/src/internal/executing/{coverage/generateCoverageTextLog.js → coverage_reporter/coverage_reporter_text_log.js} +4 -2
- package/src/internal/executing/{coverage → coverage_reporter}/istanbulCoverageMapFromCoverage.js +0 -0
- package/src/internal/executing/{coverage/normalizeIstanbulCoverage.js → coverage_utils/file_by_file_coverage.js} +9 -7
- package/src/internal/executing/coverage_utils/istanbul_coverage_composition.js +28 -0
- package/src/internal/executing/coverage_utils/v8_and_istanbul.js +38 -0
- package/src/internal/executing/coverage_utils/v8_coverage_composition.js +23 -0
- package/src/internal/executing/coverage_utils/v8_coverage_from_directory.js +59 -0
- package/src/internal/executing/coverage_utils/v8_coverage_to_istanbul.js +90 -0
- package/src/internal/executing/createSummaryLog.js +20 -20
- package/src/internal/executing/executeConcurrently.js +92 -32
- package/src/internal/executing/executePlan.js +84 -81
- package/src/internal/executing/executionLogs.js +14 -18
- package/src/internal/executing/execution_colors.js +6 -12
- package/src/internal/executing/launchAndExecute.js +179 -176
- package/src/internal/node-launcher/createControllableNodeProcess.js +26 -23
- package/src/internal/runtime/s.js +25 -24
- package/src/launchBrowser.js +82 -75
- package/src/launchNode.js +11 -102
- package/src/startExploring.js +2 -17
- package/src/abort/abortable.js +0 -172
- package/src/abort/callback_list.js +0 -64
- package/src/abort/callback_race.js +0 -34
- package/src/abort/cleaner.js +0 -22
- package/src/abort/main.js +0 -32
- package/src/abort/process_teardown_events.js +0 -59
- package/src/internal/createCallbackList.js +0 -21
- package/src/internal/executing/coverage/composeIstanbulCoverages.js +0 -108
- package/src/internal/executing/coverage/composeV8Coverages.js +0 -20
- package/src/internal/executing/coverage/generateCoverageJsonFile.js +0 -5
- package/src/internal/executing/coverage/istanbulCoverageFromCoverages.js +0 -43
- package/src/internal/executing/coverage/istanbulCoverageFromV8Coverage.js +0 -79
- package/src/internal/executing/coverage/v8CoverageFromAllV8Coverages.js +0 -40
- package/src/internal/executing/coverage/v8CoverageFromNodeV8Directory.js +0 -67
- package/src/internal/executing/logUtils.js +0 -30
- package/src/internal/executing/writeLog.js +0 -106
- package/src/internal/executing/writeLog.test-manual.js +0 -62
- package/src/internal/logs/log_style.js +0 -40
- package/src/signal/signal.js +0 -65
package/src/abort/abortable.js
DELETED
|
@@ -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
|
-
}
|
package/src/abort/cleaner.js
DELETED
|
@@ -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,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
|
-
}
|