@jsenv/core 34.3.0 → 35.0.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 (73) hide show
  1. package/README.md +1 -1
  2. package/dist/{jsenv.js → jsenv_core.js} +1054 -3850
  3. package/package.json +6 -21
  4. package/src/build/build.js +2 -2
  5. package/src/dev/file_service.js +8 -8
  6. package/src/dev/start_dev_server.js +3 -3
  7. package/src/dev/user_agent.js +1 -1
  8. package/src/main.js +0 -23
  9. package/src/plugins/supervisor/jsenv_plugin_supervisor.js +1 -1
  10. package/src/plugins/transpilation/babel/require_babel_plugin.js +1 -1
  11. package/src/plugins/transpilation/js_module_fallback/convert_js_module_to_js_classic.js +1 -1
  12. package/dist/controllable_child_process.mjs +0 -129
  13. package/dist/controllable_worker_thread.mjs +0 -91
  14. package/dist/importmap_node_loader.mjs +0 -49
  15. package/dist/js/execute_using_dynamic_import.js +0 -850
  16. package/dist/js/resolveImport.js +0 -504
  17. package/dist/js/v8_coverage.js +0 -508
  18. package/dist/no_experimental_warnings.cjs +0 -8
  19. package/src/execute/execute.js +0 -111
  20. package/src/execute/run.js +0 -161
  21. package/src/execute/runtimes/browsers/chromium.js +0 -10
  22. package/src/execute/runtimes/browsers/firefox.js +0 -9
  23. package/src/execute/runtimes/browsers/from_playwright.js +0 -574
  24. package/src/execute/runtimes/browsers/middleware_istanbul.js +0 -65
  25. package/src/execute/runtimes/browsers/middleware_js_supervisor.js +0 -100
  26. package/src/execute/runtimes/browsers/webkit.js +0 -26
  27. package/src/execute/runtimes/node/child_exec_options.js +0 -166
  28. package/src/execute/runtimes/node/controllable_child_process.mjs +0 -135
  29. package/src/execute/runtimes/node/controllable_worker_thread.mjs +0 -103
  30. package/src/execute/runtimes/node/exec_options.js +0 -57
  31. package/src/execute/runtimes/node/execute_using_dynamic_import.js +0 -55
  32. package/src/execute/runtimes/node/exit_codes.js +0 -9
  33. package/src/execute/runtimes/node/importmap_node_loader.mjs +0 -51
  34. package/src/execute/runtimes/node/importmap_node_loader_file_url.js +0 -4
  35. package/src/execute/runtimes/node/kill_process_tree.js +0 -76
  36. package/src/execute/runtimes/node/no_experimental_warnings.cjs +0 -12
  37. package/src/execute/runtimes/node/no_experimental_warnings_file_url.js +0 -4
  38. package/src/execute/runtimes/node/node_child_process.js +0 -363
  39. package/src/execute/runtimes/node/node_execution_performance.js +0 -67
  40. package/src/execute/runtimes/node/node_worker_thread.js +0 -295
  41. package/src/execute/runtimes/node/profiler_v8_coverage.js +0 -56
  42. package/src/execute/runtimes/readme.md +0 -13
  43. package/src/execute/web_server_param.js +0 -74
  44. package/src/test/coverage/babel_plugin_instrument.js +0 -48
  45. package/src/test/coverage/coverage_reporter_html_directory.js +0 -32
  46. package/src/test/coverage/coverage_reporter_json_file.js +0 -17
  47. package/src/test/coverage/coverage_reporter_text_log.js +0 -19
  48. package/src/test/coverage/empty_coverage_factory.js +0 -52
  49. package/src/test/coverage/file_by_file_coverage.js +0 -25
  50. package/src/test/coverage/istanbul_coverage_composition.js +0 -28
  51. package/src/test/coverage/istanbul_coverage_map_from_coverage.js +0 -16
  52. package/src/test/coverage/list_files_not_covered.js +0 -15
  53. package/src/test/coverage/missing_coverage.js +0 -41
  54. package/src/test/coverage/report_to_coverage.js +0 -198
  55. package/src/test/coverage/v8_and_istanbul.js +0 -37
  56. package/src/test/coverage/v8_coverage.js +0 -26
  57. package/src/test/coverage/v8_coverage_composition.js +0 -24
  58. package/src/test/coverage/v8_coverage_node_directory.js +0 -85
  59. package/src/test/coverage/v8_coverage_to_istanbul.js +0 -99
  60. package/src/test/execute_steps.js +0 -425
  61. package/src/test/execute_test_plan.js +0 -372
  62. package/src/test/execution_colors.js +0 -10
  63. package/src/test/execution_steps.js +0 -65
  64. package/src/test/gc.js +0 -9
  65. package/src/test/logs_file_execution.js +0 -427
  66. package/src/test/logs_file_execution.test.mjs +0 -41
  67. package/src/test/readme.md +0 -3
  68. /package/src/{basic_fetch.js → helpers/basic_fetch.js} +0 -0
  69. /package/src/{lookup_package_directory.js → helpers/lookup_package_directory.js} +0 -0
  70. /package/src/{ping_server.js → helpers/ping_server.js} +0 -0
  71. /package/src/{require_from_jsenv.js → helpers/require_from_jsenv.js} +0 -0
  72. /package/src/{watch_source_files.js → helpers/watch_source_files.js} +0 -0
  73. /package/src/{web_url_converter.js → helpers/web_url_converter.js} +0 -0
@@ -1,295 +0,0 @@
1
- // https://github.com/avajs/ava/blob/576f534b345259055c95fa0c2b33bef10847a2af/lib/fork.js#L23
2
- // https://nodejs.org/api/worker_threads.html
3
- // https://github.com/avajs/ava/blob/576f534b345259055c95fa0c2b33bef10847a2af/lib/worker/base.js
4
- import { Worker } from "node:worker_threads"
5
- import { fileURLToPath } from "node:url"
6
- import {
7
- Abort,
8
- createCallbackListNotifiedOnce,
9
- raceCallbacks,
10
- } from "@jsenv/abort"
11
- import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
12
-
13
- import { createChildExecOptions } from "./child_exec_options.js"
14
- import { ExecOptions } from "./exec_options.js"
15
- import { EXIT_CODES } from "./exit_codes.js"
16
- import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js"
17
- import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js"
18
-
19
- const CONTROLLABLE_WORKER_THREAD_URL = new URL(
20
- "./controllable_worker_thread.mjs?entry_point",
21
- import.meta.url,
22
- ).href
23
-
24
- export const nodeWorkerThread = {
25
- type: "node",
26
- name: "node_worker_thread",
27
- version: process.version.slice(1),
28
- }
29
-
30
- nodeWorkerThread.run = async ({
31
- signal = new AbortController().signal,
32
- // logger,
33
- rootDirectoryUrl,
34
- fileRelativeUrl,
35
- importMap,
36
-
37
- keepRunning,
38
- stopSignal,
39
- onConsole,
40
-
41
- collectConsole = false,
42
- collectPerformance,
43
- coverageEnabled = false,
44
- coverageConfig,
45
- coverageMethodForNodeJs,
46
- coverageFileUrl,
47
-
48
- env,
49
- debugPort,
50
- debugMode,
51
- debugModeInheritBreak,
52
- inheritProcessEnv = true,
53
- commandLineOptions = [],
54
- }) => {
55
- if (env !== undefined && typeof env !== "object") {
56
- throw new TypeError(`env must be an object, got ${env}`)
57
- }
58
- env = {
59
- ...env,
60
- JSENV: true,
61
- }
62
- if (coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
63
- env.NODE_V8_COVERAGE = ""
64
- }
65
- if (importMap) {
66
- env.IMPORT_MAP = JSON.stringify(importMap)
67
- env.IMPORT_MAP_BASE_URL = rootDirectoryUrl
68
- commandLineOptions.push(
69
- `--experimental-loader=${fileURLToPath(IMPORTMAP_NODE_LOADER_FILE_URL)}`,
70
- )
71
- commandLineOptions.push(
72
- `--require=${fileURLToPath(NO_EXPERIMENTAL_WARNING_FILE_URL)}`,
73
- )
74
- }
75
-
76
- const workerThreadExecOptions = await createChildExecOptions({
77
- signal,
78
- debugPort,
79
- debugMode,
80
- debugModeInheritBreak,
81
- })
82
- const execArgvForWorkerThread = ExecOptions.toExecArgv({
83
- ...workerThreadExecOptions,
84
- ...ExecOptions.fromExecArgv(commandLineOptions),
85
- })
86
- const envForWorkerThread = {
87
- ...(inheritProcessEnv ? process.env : {}),
88
- ...env,
89
- }
90
-
91
- const cleanupCallbackList = createCallbackListNotifiedOnce()
92
- const cleanup = async (reason) => {
93
- await cleanupCallbackList.notify({ reason })
94
- }
95
- const actionOperation = Abort.startOperation()
96
- actionOperation.addAbortSignal(signal)
97
- // https://nodejs.org/api/worker_threads.html#new-workerfilename-options
98
- const workerThread = new Worker(
99
- fileURLToPath(CONTROLLABLE_WORKER_THREAD_URL),
100
- {
101
- env: envForWorkerThread,
102
- execArgv: execArgvForWorkerThread,
103
- // workerData: { options },
104
- stdin: true,
105
- stdout: true,
106
- stderr: true,
107
- },
108
- )
109
- const removeOutputListener = installWorkerThreadOutputListener(
110
- workerThread,
111
- ({ type, text }) => {
112
- onConsole({ type, text })
113
- },
114
- )
115
- const workerThreadReadyPromise = new Promise((resolve) => {
116
- onceWorkerThreadMessage(workerThread, "ready", resolve)
117
- })
118
-
119
- const stop = memoize(async () => {
120
- // read all stdout before terminating
121
- // (no need for stderr because it's sync)
122
- if (collectConsole) {
123
- while (workerThread.stdout.read() !== null) {}
124
- await new Promise((resolve) => {
125
- setTimeout(resolve, 50)
126
- })
127
- }
128
- await workerThread.terminate()
129
- })
130
-
131
- const winnerPromise = new Promise((resolve) => {
132
- raceCallbacks(
133
- {
134
- aborted: (cb) => {
135
- return actionOperation.addAbortCallback(cb)
136
- },
137
- error: (cb) => {
138
- return onceWorkerThreadEvent(workerThread, "error", cb)
139
- },
140
- exit: (cb) => {
141
- return onceWorkerThreadEvent(workerThread, "exit", (code, signal) => {
142
- cb({ code, signal })
143
- })
144
- },
145
- response: (cb) => {
146
- return onceWorkerThreadMessage(workerThread, "action-result", cb)
147
- },
148
- },
149
- resolve,
150
- )
151
- })
152
-
153
- const result = {
154
- status: "executing",
155
- errors: [],
156
- namespace: null,
157
- }
158
-
159
- const writeResult = async () => {
160
- actionOperation.throwIfAborted()
161
- await workerThreadReadyPromise
162
- actionOperation.throwIfAborted()
163
- await sendToWorkerThread(workerThread, {
164
- type: "action",
165
- data: {
166
- actionType: "execute-using-dynamic-import",
167
- actionParams: {
168
- rootDirectoryUrl,
169
- fileUrl: new URL(fileRelativeUrl, rootDirectoryUrl).href,
170
- collectPerformance,
171
- coverageEnabled,
172
- coverageConfig,
173
- coverageMethodForNodeJs,
174
- coverageFileUrl,
175
- exitAfterAction: true,
176
- },
177
- },
178
- })
179
- const winner = await winnerPromise
180
- if (winner.name === "aborted") {
181
- result.status = "aborted"
182
- return
183
- }
184
- if (winner.name === "error") {
185
- const error = winner.data
186
- removeOutputListener()
187
- result.status = "failed"
188
- result.errors.push(error)
189
- return
190
- }
191
- if (winner.name === "exit") {
192
- const { code } = winner.data
193
- await cleanup("process exit")
194
- if (code === 12) {
195
- result.status = "failed"
196
- result.errors.push(
197
- new Error(
198
- `node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
199
- ),
200
- )
201
- return
202
- }
203
- if (
204
- code === null ||
205
- code === 0 ||
206
- code === EXIT_CODES.SIGINT ||
207
- code === EXIT_CODES.SIGTERM ||
208
- code === EXIT_CODES.SIGABORT
209
- ) {
210
- result.status = "failed"
211
- result.errors.push(
212
- new Error(`node worker thread exited during execution`),
213
- )
214
- return
215
- }
216
- // process.exit(1) in child process or process.exitCode = 1 + process.exit()
217
- // means there was an error even if we don't know exactly what.
218
- result.status = "failed"
219
- result.errors.push(
220
- new Error(
221
- `node worker thread exited with code ${code} during execution`,
222
- ),
223
- )
224
- }
225
- const { status, value } = winner.data
226
- if (status === "action-failed") {
227
- result.status = "failed"
228
- result.errors.push(value)
229
- return
230
- }
231
- const { namespace, performance, coverage } = value
232
- result.status = "completed"
233
- result.namespace = namespace
234
- result.performance = performance
235
- result.coverage = coverage
236
- }
237
-
238
- try {
239
- await writeResult()
240
- } catch (e) {
241
- result.status = "failed"
242
- result.errors.push(e)
243
- }
244
-
245
- if (keepRunning) {
246
- stopSignal.notify = stop
247
- } else {
248
- await stop()
249
- }
250
- await actionOperation.end()
251
- return result
252
- }
253
-
254
- const installWorkerThreadOutputListener = (workerThread, callback) => {
255
- // beware that we may receive ansi output here, should not be a problem but keep that in mind
256
- const stdoutDataCallback = (chunk) => {
257
- const text = String(chunk)
258
- callback({ type: "log", text })
259
- }
260
- workerThread.stdout.on("data", stdoutDataCallback)
261
- const stdErrorDataCallback = (chunk) => {
262
- const text = String(chunk)
263
- callback({ type: "error", text })
264
- }
265
- workerThread.stderr.on("data", stdErrorDataCallback)
266
- return () => {
267
- workerThread.stdout.removeListener("data", stdoutDataCallback)
268
- workerThread.stderr.removeListener("data", stdErrorDataCallback)
269
- }
270
- }
271
-
272
- const sendToWorkerThread = (worker, { type, data }) => {
273
- worker.postMessage({ jsenv: true, type, data })
274
- }
275
-
276
- const onceWorkerThreadMessage = (workerThread, type, callback) => {
277
- const onmessage = (message) => {
278
- if (message && message.jsenv && message.type === type) {
279
- workerThread.removeListener("message", onmessage)
280
- // eslint-disable-next-line no-eval
281
- callback(message.data ? eval(`(${message.data})`) : undefined)
282
- }
283
- }
284
- workerThread.on("message", onmessage)
285
- return () => {
286
- workerThread.removeListener("message", onmessage)
287
- }
288
- }
289
-
290
- const onceWorkerThreadEvent = (worker, type, callback) => {
291
- worker.once(type, callback)
292
- return () => {
293
- worker.removeListener(type, callback)
294
- }
295
- }
@@ -1,56 +0,0 @@
1
- /*
2
- * Calling Profiler.startPreciseCoverage DO NOT propagate to
3
- * subprocesses (new Worker or child_process.fork())
4
- * So the best solution remains NODE_V8_COVERAGE
5
- * This profiler strategy remains useful when:
6
- * - As fallback when NODE_V8_COVERAGE is not configured
7
- * - If explicitely enabled with coverageMethodForNodeJs: 'Profiler'
8
- * - Used by jsenv during automated tests about coverage
9
- * - Anyone prefering this approach over NODE_V8_COVERAGE and assuming
10
- * it will not fork subprocess or don't care if coverage is missed for this code
11
- * - https://v8.dev/blog/javascript-code-coverage#for-embedders
12
- * - https://github.com/nodejs/node/issues/28283
13
- * - https://vanilla.aslushnikov.com/?Profiler.startPreciseCoverage
14
- */
15
-
16
- import { Session } from "node:inspector"
17
-
18
- export const startJsCoverage = async ({
19
- callCount = true,
20
- detailed = true,
21
- } = {}) => {
22
- const session = new Session()
23
- session.connect()
24
- const postSession = (action, options) => {
25
- const promise = new Promise((resolve, reject) => {
26
- session.post(action, options, (error, data) => {
27
- if (error) {
28
- reject(error)
29
- } else {
30
- resolve(data)
31
- }
32
- })
33
- })
34
- return promise
35
- }
36
-
37
- await postSession("Profiler.enable")
38
- await postSession("Profiler.startPreciseCoverage", { callCount, detailed })
39
-
40
- const takeJsCoverage = async () => {
41
- const coverage = await postSession("Profiler.takePreciseCoverage")
42
- return coverage
43
- }
44
-
45
- const stopJsCoverage = async () => {
46
- const coverage = await takeJsCoverage()
47
- await postSession("Profiler.stopPreciseCoverage")
48
- await postSession("Profiler.disable")
49
- return coverage
50
- }
51
-
52
- return {
53
- takeJsCoverage,
54
- stopJsCoverage,
55
- }
56
- }
@@ -1,13 +0,0 @@
1
- # runtimes/
2
-
3
- Code implementing runtimes can be found here.
4
-
5
- # Description
6
-
7
- A runtime is an object with a "run" method.
8
- The run method is roughly doing the following:
9
-
10
- 1. spawn a runtime (browser,Node.js)
11
- 2. set various listeners to monitor file execution
12
- 3. execute the file
13
- 4. return info about file execution (logs and errors for instance)
@@ -1,74 +0,0 @@
1
- import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
2
-
3
- import { pingServer } from "../ping_server.js"
4
- import { basicFetch } from "../basic_fetch.js"
5
-
6
- export const assertAndNormalizeWebServer = async (webServer) => {
7
- if (!webServer) {
8
- throw new TypeError(
9
- `webServer is required when running tests on browser(s)`,
10
- )
11
- }
12
- const unexpectedParamNames = Object.keys(webServer).filter((key) => {
13
- return !["origin", "moduleUrl", "rootDirectoryUrl"].includes(key)
14
- })
15
- if (unexpectedParamNames.length > 0) {
16
- throw new TypeError(
17
- `${unexpectedParamNames.join(",")}: there is no such param to webServer`,
18
- )
19
- }
20
-
21
- let aServerIsListening = await pingServer(webServer.origin)
22
- if (!aServerIsListening) {
23
- if (!webServer.moduleUrl) {
24
- throw new TypeError(
25
- `webServer.moduleUrl is required as there is no server listening "${webServer.origin}"`,
26
- )
27
- }
28
- try {
29
- process.env.IMPORTED_BY_TEST_PLAN = "1"
30
- await import(webServer.moduleUrl)
31
- delete process.env.IMPORTED_BY_TEST_PLAN
32
- } catch (e) {
33
- if (e.code === "ERR_MODULE_NOT_FOUND") {
34
- throw new Error(
35
- `webServer.moduleUrl does not lead to a file at "${webServer.moduleUrl}"`,
36
- )
37
- }
38
- throw e
39
- }
40
- aServerIsListening = await pingServer(webServer.origin)
41
- if (!aServerIsListening) {
42
- throw new Error(
43
- `webServer.moduleUrl did not start a server listening at "${webServer.origin}", check file at "${webServer.moduleUrl}"`,
44
- )
45
- }
46
- }
47
- const { headers } = await basicFetch(webServer.origin, {
48
- method: "GET",
49
- rejectUnauthorized: false,
50
- headers: {
51
- "x-server-inspect": "1",
52
- },
53
- })
54
- if (String(headers["server"]).includes("jsenv_dev_server")) {
55
- webServer.isJsenvDevServer = true
56
- const { json } = await basicFetch(`${webServer.origin}/__params__.json`, {
57
- rejectUnauthorized: false,
58
- })
59
- if (webServer.rootDirectoryUrl === undefined) {
60
- const jsenvDevServerParams = await json()
61
- webServer.rootDirectoryUrl = jsenvDevServerParams.sourceDirectoryUrl
62
- } else {
63
- webServer.rootDirectoryUrl = assertAndNormalizeDirectoryUrl(
64
- webServer.rootDirectoryUrl,
65
- "webServer.rootDirectoryUrl",
66
- )
67
- }
68
- } else {
69
- webServer.rootDirectoryUrl = assertAndNormalizeDirectoryUrl(
70
- webServer.rootDirectoryUrl,
71
- "webServer.rootDirectoryUrl",
72
- )
73
- }
74
- }
@@ -1,48 +0,0 @@
1
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
2
-
3
- // https://github.com/istanbuljs/babel-plugin-istanbul/blob/321740f7b25d803f881466ea819d870f7ed6a254/src/index.js
4
-
5
- export const babelPluginInstrument = (api, { useInlineSourceMaps = false }) => {
6
- const { programVisitor } = requireFromJsenv("istanbul-lib-instrument")
7
- const { types } = api
8
-
9
- return {
10
- name: "transform-instrument",
11
- visitor: {
12
- Program: {
13
- enter(path) {
14
- const { file } = this
15
- const { opts } = file
16
- let inputSourceMap
17
- if (useInlineSourceMaps) {
18
- // https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
19
- inputSourceMap =
20
- opts.inputSourceMap || file.inputMap
21
- ? file.inputMap.sourcemap
22
- : null
23
- } else {
24
- inputSourceMap = opts.inputSourceMap
25
- }
26
- this.__dv__ = programVisitor(
27
- types,
28
- opts.filenameRelative || opts.filename,
29
- {
30
- coverageVariable: "__coverage__",
31
- inputSourceMap,
32
- },
33
- )
34
- this.__dv__.enter(path)
35
- },
36
-
37
- exit(path) {
38
- if (!this.__dv__) {
39
- return
40
- }
41
- const object = this.__dv__.exit(path)
42
- // object got two properties: fileCoverage and sourceMappingURL
43
- this.file.metadata.coverage = object.fileCoverage
44
- },
45
- },
46
- },
47
- }
48
- }
@@ -1,32 +0,0 @@
1
- import { fileURLToPath } from "node:url"
2
- import { readFileSync } from "node:fs"
3
-
4
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
5
- import { istanbulCoverageMapFromCoverage } from "./istanbul_coverage_map_from_coverage.js"
6
-
7
- export const generateCoverageHtmlDirectory = async (
8
- coverage,
9
- {
10
- rootDirectoryUrl,
11
- coverageHtmlDirectoryRelativeUrl,
12
- coverageReportSkipEmpty,
13
- coverageReportSkipFull,
14
- },
15
- ) => {
16
- const libReport = requireFromJsenv("istanbul-lib-report")
17
- const reports = requireFromJsenv("istanbul-reports")
18
-
19
- const context = libReport.createContext({
20
- dir: fileURLToPath(rootDirectoryUrl),
21
- coverageMap: istanbulCoverageMapFromCoverage(coverage),
22
- sourceFinder: (path) =>
23
- readFileSync(new URL(path, rootDirectoryUrl), "utf8"),
24
- })
25
-
26
- const report = reports.create("html", {
27
- skipEmpty: coverageReportSkipEmpty,
28
- skipFull: coverageReportSkipFull,
29
- subdir: coverageHtmlDirectoryRelativeUrl,
30
- })
31
- report.execute(context)
32
- }
@@ -1,17 +0,0 @@
1
- import { writeFile } from "@jsenv/filesystem"
2
- import { urlToFileSystemPath } from "@jsenv/urls"
3
- import { byteAsFileSize } from "@jsenv/log"
4
-
5
- export const generateCoverageJsonFile = async ({
6
- coverage,
7
- coverageJsonFileUrl,
8
- logger,
9
- }) => {
10
- const coverageAsText = JSON.stringify(coverage, null, " ")
11
- logger.info(
12
- `-> ${urlToFileSystemPath(coverageJsonFileUrl)} (${byteAsFileSize(
13
- Buffer.byteLength(coverageAsText),
14
- )})`,
15
- )
16
- await writeFile(coverageJsonFileUrl, coverageAsText)
17
- }
@@ -1,19 +0,0 @@
1
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
2
- import { istanbulCoverageMapFromCoverage } from "./istanbul_coverage_map_from_coverage.js"
3
-
4
- export const generateCoverageTextLog = (
5
- coverage,
6
- { coverageReportSkipEmpty, coverageReportSkipFull },
7
- ) => {
8
- const libReport = requireFromJsenv("istanbul-lib-report")
9
- const reports = requireFromJsenv("istanbul-reports")
10
-
11
- const context = libReport.createContext({
12
- coverageMap: istanbulCoverageMapFromCoverage(coverage),
13
- })
14
- const report = reports.create("text", {
15
- skipEmpty: coverageReportSkipEmpty,
16
- skipFull: coverageReportSkipFull,
17
- })
18
- report.execute(context)
19
- }
@@ -1,52 +0,0 @@
1
- import { readFile } from "@jsenv/filesystem"
2
- import { resolveUrl } from "@jsenv/urls"
3
- import { Abort } from "@jsenv/abort"
4
- import { applyBabelPlugins } from "@jsenv/ast"
5
-
6
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
7
- import { babelPluginInstrument } from "./babel_plugin_instrument.js"
8
-
9
- export const relativeUrlToEmptyCoverage = async (
10
- relativeUrl,
11
- { signal, rootDirectoryUrl },
12
- ) => {
13
- const operation = Abort.startOperation()
14
- operation.addAbortSignal(signal)
15
-
16
- try {
17
- const fileUrl = resolveUrl(relativeUrl, rootDirectoryUrl)
18
- const content = await readFile(fileUrl, { as: "string" })
19
-
20
- operation.throwIfAborted()
21
- const { metadata } = await applyBabelPlugins({
22
- babelPlugins: [babelPluginInstrument],
23
- urlInfo: {
24
- originalUrl: fileUrl,
25
- content,
26
- },
27
- })
28
- const { coverage } = metadata
29
- if (!coverage) {
30
- throw new Error(`missing coverage for file`)
31
- }
32
- // https://github.com/gotwarlost/istanbul/blob/bc84c315271a5dd4d39bcefc5925cfb61a3d174a/lib/command/common/run-with-cover.js#L229
33
- Object.keys(coverage.s).forEach(function (key) {
34
- coverage.s[key] = 0
35
- })
36
- return coverage
37
- } catch (e) {
38
- if (e && e.code === "PARSE_ERROR") {
39
- // return an empty coverage for that file when
40
- // it contains a syntax error
41
- return createEmptyCoverage(relativeUrl)
42
- }
43
- throw e
44
- } finally {
45
- await operation.end()
46
- }
47
- }
48
-
49
- const createEmptyCoverage = (relativeUrl) => {
50
- const { createFileCoverage } = requireFromJsenv("istanbul-lib-coverage")
51
- return createFileCoverage(relativeUrl).toJSON()
52
- }
@@ -1,25 +0,0 @@
1
- import {
2
- urlToRelativeUrl,
3
- fileSystemPathToUrl,
4
- isFileSystemPath,
5
- } from "@jsenv/urls"
6
-
7
- export const normalizeFileByFileCoveragePaths = (
8
- fileByFileCoverage,
9
- rootDirectoryUrl,
10
- ) => {
11
- const fileByFileNormalized = {}
12
- Object.keys(fileByFileCoverage).forEach((key) => {
13
- const fileCoverage = fileByFileCoverage[key]
14
- const { path } = fileCoverage
15
- const url = isFileSystemPath(path)
16
- ? fileSystemPathToUrl(path)
17
- : new URL(path, rootDirectoryUrl).href
18
- const relativeUrl = urlToRelativeUrl(url, rootDirectoryUrl)
19
- fileByFileNormalized[`./${relativeUrl}`] = {
20
- ...fileCoverage,
21
- path: `./${relativeUrl}`,
22
- }
23
- })
24
- return fileByFileNormalized
25
- }
@@ -1,28 +0,0 @@
1
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
2
-
3
- export const composeTwoFileByFileIstanbulCoverages = (
4
- firstFileByFileIstanbulCoverage,
5
- secondFileByFileIstanbulCoverage,
6
- ) => {
7
- const fileByFileIstanbulCoverage = {}
8
- Object.keys(firstFileByFileIstanbulCoverage).forEach((key) => {
9
- fileByFileIstanbulCoverage[key] = firstFileByFileIstanbulCoverage[key]
10
- })
11
- Object.keys(secondFileByFileIstanbulCoverage).forEach((key) => {
12
- const firstCoverage = firstFileByFileIstanbulCoverage[key]
13
- const secondCoverage = secondFileByFileIstanbulCoverage[key]
14
- fileByFileIstanbulCoverage[key] = firstCoverage
15
- ? merge(firstCoverage, secondCoverage)
16
- : secondCoverage
17
- })
18
-
19
- return fileByFileIstanbulCoverage
20
- }
21
-
22
- const merge = (firstIstanbulCoverage, secondIstanbulCoverage) => {
23
- const { createFileCoverage } = requireFromJsenv("istanbul-lib-coverage")
24
- const istanbulFileCoverageObject = createFileCoverage(firstIstanbulCoverage)
25
- istanbulFileCoverageObject.merge(secondIstanbulCoverage)
26
- const istanbulCoverage = istanbulFileCoverageObject.toJSON()
27
- return istanbulCoverage
28
- }
@@ -1,16 +0,0 @@
1
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
2
-
3
- export const istanbulCoverageMapFromCoverage = (coverage) => {
4
- const { createCoverageMap } = requireFromJsenv("istanbul-lib-coverage")
5
-
6
- const coverageAdjusted = {}
7
- Object.keys(coverage).forEach((key) => {
8
- coverageAdjusted[key.slice(2)] = {
9
- ...coverage[key],
10
- path: key.slice(2),
11
- }
12
- })
13
-
14
- const coverageMap = createCoverageMap(coverageAdjusted)
15
- return coverageMap
16
- }