@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,425 +0,0 @@
1
- import { existsSync } from "node:fs"
2
- import { memoryUsage } from "node:process"
3
- import { takeCoverage } from "node:v8"
4
- import stripAnsi from "strip-ansi"
5
-
6
- import { urlToFileSystemPath } from "@jsenv/urls"
7
- import { createLog, startSpinner } from "@jsenv/log"
8
- import { Abort, raceProcessTeardownEvents } from "@jsenv/abort"
9
- import { ensureEmptyDirectory, writeFileSync } from "@jsenv/filesystem"
10
-
11
- import { reportToCoverage } from "./coverage/report_to_coverage.js"
12
- import { run } from "@jsenv/core/src/execute/run.js"
13
-
14
- import { ensureGlobalGc } from "./gc.js"
15
- import { createExecutionLog, createSummaryLog } from "./logs_file_execution.js"
16
-
17
- export const executeSteps = async (
18
- executionSteps,
19
- {
20
- signal,
21
- handleSIGINT,
22
- logger,
23
- logRefresh,
24
- logRuntime,
25
- logEachDuration,
26
- logSummary,
27
- logTimeUsage,
28
- logMemoryHeapUsage,
29
- logFileRelativeUrl,
30
- completedExecutionLogMerging,
31
- completedExecutionLogAbbreviation,
32
- rootDirectoryUrl,
33
- webServer,
34
-
35
- keepRunning,
36
- defaultMsAllocatedPerExecution,
37
- maxExecutionsInParallel,
38
- failFast,
39
- gcBetweenExecutions,
40
- cooldownBetweenExecutions,
41
-
42
- coverageEnabled,
43
- coverageConfig,
44
- coverageIncludeMissing,
45
- coverageMethodForBrowsers,
46
- coverageMethodForNodeJs,
47
- coverageV8ConflictWarning,
48
- coverageTempDirectoryUrl,
49
-
50
- beforeExecutionCallback = () => {},
51
- afterExecutionCallback = () => {},
52
- } = {},
53
- ) => {
54
- const executePlanReturnValue = {}
55
- const report = {}
56
- const callbacks = []
57
- const stopAfterAllSignal = { notify: () => {} }
58
-
59
- const multipleExecutionsOperation = Abort.startOperation()
60
- multipleExecutionsOperation.addAbortSignal(signal)
61
- if (handleSIGINT) {
62
- multipleExecutionsOperation.addAbortSource((abort) => {
63
- return raceProcessTeardownEvents(
64
- {
65
- SIGINT: true,
66
- },
67
- () => {
68
- logger.debug(`SIGINT abort`)
69
- abort()
70
- },
71
- )
72
- })
73
- }
74
- const failFastAbortController = new AbortController()
75
- if (failFast) {
76
- multipleExecutionsOperation.addAbortSignal(failFastAbortController.signal)
77
- }
78
-
79
- try {
80
- if (gcBetweenExecutions) {
81
- ensureGlobalGc()
82
- }
83
-
84
- if (coverageEnabled) {
85
- // when runned multiple times, we don't want to keep previous files in this directory
86
- await ensureEmptyDirectory(coverageTempDirectoryUrl)
87
- callbacks.push(async () => {
88
- if (multipleExecutionsOperation.signal.aborted) {
89
- // don't try to do the coverage stuff
90
- return
91
- }
92
- try {
93
- if (coverageMethodForNodeJs === "NODE_V8_COVERAGE") {
94
- takeCoverage()
95
- // conceptually we don't need coverage anymore so it would be
96
- // good to call v8.stopCoverage()
97
- // but it logs a strange message about "result is not an object"
98
- }
99
- const planCoverage = await reportToCoverage(report, {
100
- signal: multipleExecutionsOperation.signal,
101
- logger,
102
- rootDirectoryUrl,
103
- coverageConfig,
104
- coverageIncludeMissing,
105
- coverageMethodForBrowsers,
106
- coverageV8ConflictWarning,
107
- })
108
- executePlanReturnValue.planCoverage = planCoverage
109
- } catch (e) {
110
- if (Abort.isAbortError(e)) {
111
- return
112
- }
113
- throw e
114
- }
115
- })
116
- }
117
-
118
- let runtimeParams = {
119
- rootDirectoryUrl,
120
- webServer,
121
-
122
- coverageEnabled,
123
- coverageConfig,
124
- coverageMethodForBrowsers,
125
- coverageMethodForNodeJs,
126
- stopAfterAllSignal,
127
- }
128
-
129
- if (completedExecutionLogMerging && !process.stdout.isTTY) {
130
- completedExecutionLogMerging = false
131
- logger.debug(
132
- `Force completedExecutionLogMerging to false because process.stdout.isTTY is false`,
133
- )
134
- }
135
- const debugLogsEnabled = logger.levels.debug
136
- const executionLogsEnabled = logger.levels.info
137
- const executionSpinner =
138
- logRefresh &&
139
- !debugLogsEnabled &&
140
- executionLogsEnabled &&
141
- process.stdout.isTTY &&
142
- // if there is an error during execution npm will mess up the output
143
- // (happens when npm runs several command in a workspace)
144
- // so we enable spinner only when !process.exitCode (no error so far)
145
- process.exitCode !== 1
146
-
147
- const startMs = Date.now()
148
- let rawOutput = ""
149
- let executionLog = createLog({ newLine: "" })
150
- const counters = {
151
- total: executionSteps.length,
152
- aborted: 0,
153
- timedout: 0,
154
- failed: 0,
155
- completed: 0,
156
- done: 0,
157
- }
158
- await executeInParallel({
159
- multipleExecutionsOperation,
160
- maxExecutionsInParallel,
161
- cooldownBetweenExecutions,
162
- executionSteps,
163
- start: async (paramsFromStep) => {
164
- const executionIndex = executionSteps.indexOf(paramsFromStep)
165
- const { executionName, fileRelativeUrl, runtime } = paramsFromStep
166
- const runtimeType = runtime.type
167
- const runtimeName = runtime.name
168
- const runtimeVersion = runtime.version
169
- const executionParams = {
170
- measurePerformance: false,
171
- collectPerformance: false,
172
- collectConsole: true,
173
- allocatedMs: defaultMsAllocatedPerExecution,
174
- ...paramsFromStep,
175
- runtimeParams: {
176
- fileRelativeUrl,
177
- ...paramsFromStep.runtimeParams,
178
- },
179
- }
180
- const beforeExecutionInfo = {
181
- fileRelativeUrl,
182
- runtimeType,
183
- runtimeName,
184
- runtimeVersion,
185
- executionIndex,
186
- executionParams,
187
- startMs: Date.now(),
188
- executionResult: {
189
- status: "executing",
190
- },
191
- }
192
- let spinner
193
- if (executionSpinner) {
194
- spinner = startSpinner({
195
- log: executionLog,
196
- render: () => {
197
- return createExecutionLog(beforeExecutionInfo, {
198
- counters,
199
- logRuntime,
200
- logEachDuration,
201
- ...(logTimeUsage
202
- ? {
203
- timeEllapsed: Date.now() - startMs,
204
- }
205
- : {}),
206
- ...(logMemoryHeapUsage
207
- ? { memoryHeap: memoryUsage().heapUsed }
208
- : {}),
209
- })
210
- },
211
- })
212
- }
213
- beforeExecutionCallback(beforeExecutionInfo)
214
-
215
- const fileUrl = `${rootDirectoryUrl}${fileRelativeUrl}`
216
- let executionResult
217
- if (existsSync(new URL(fileUrl))) {
218
- executionResult = await run({
219
- signal: multipleExecutionsOperation.signal,
220
- logger,
221
- allocatedMs:
222
- typeof executionParams.allocatedMs === "function"
223
- ? executionParams.allocatedMs(beforeExecutionInfo)
224
- : executionParams.allocatedMs,
225
- keepRunning,
226
- mirrorConsole: false, // file are executed in parallel, log would be a mess to read
227
- collectConsole: executionParams.collectConsole,
228
- coverageEnabled,
229
- coverageTempDirectoryUrl,
230
- runtime: executionParams.runtime,
231
- runtimeParams: {
232
- ...runtimeParams,
233
- ...executionParams.runtimeParams,
234
- },
235
- })
236
- } else {
237
- executionResult = {
238
- status: "failed",
239
- errors: [
240
- new Error(
241
- `No file at ${fileRelativeUrl} for execution "${executionName}"`,
242
- ),
243
- ],
244
- }
245
- }
246
- counters.done++
247
- const fileReport = report[fileRelativeUrl]
248
- if (fileReport) {
249
- fileReport[executionName] = executionResult
250
- } else {
251
- report[fileRelativeUrl] = {
252
- [executionName]: executionResult,
253
- }
254
- }
255
-
256
- const afterExecutionInfo = {
257
- ...beforeExecutionInfo,
258
- runtimeVersion: runtime.version,
259
- endMs: Date.now(),
260
- executionResult,
261
- }
262
- afterExecutionCallback(afterExecutionInfo)
263
-
264
- if (executionResult.status === "aborted") {
265
- counters.aborted++
266
- } else if (executionResult.status === "timedout") {
267
- counters.timedout++
268
- } else if (executionResult.status === "failed") {
269
- counters.failed++
270
- } else if (executionResult.status === "completed") {
271
- counters.completed++
272
- }
273
- if (gcBetweenExecutions) {
274
- global.gc()
275
- }
276
- if (executionLogsEnabled) {
277
- const log = createExecutionLog(afterExecutionInfo, {
278
- completedExecutionLogAbbreviation,
279
- counters,
280
- logRuntime,
281
- logEachDuration,
282
- ...(logTimeUsage
283
- ? {
284
- timeEllapsed: Date.now() - startMs,
285
- }
286
- : {}),
287
- ...(logMemoryHeapUsage
288
- ? { memoryHeap: memoryUsage().heapUsed }
289
- : {}),
290
- })
291
- // replace spinner with this execution result
292
- if (spinner) spinner.stop()
293
- executionLog.write(log)
294
- rawOutput += stripAnsi(log)
295
-
296
- const canOverwriteLog = canOverwriteLogGetter({
297
- completedExecutionLogMerging,
298
- executionResult,
299
- })
300
- if (canOverwriteLog) {
301
- // nothing to do, we reuse the current executionLog object
302
- } else {
303
- executionLog.destroy()
304
- executionLog = createLog({ newLine: "" })
305
- }
306
- }
307
- const isLastExecutionLog = executionIndex === executionSteps.length - 1
308
- const cancelRemaining =
309
- failFast &&
310
- executionResult.status !== "completed" &&
311
- counters.done < counters.total
312
- if (isLastExecutionLog && logger.levels.info) {
313
- executionLog.write("\n")
314
- }
315
-
316
- if (cancelRemaining) {
317
- logger.info(`"failFast" enabled -> cancel remaining executions`)
318
- failFastAbortController.abort()
319
- }
320
- },
321
- })
322
- if (!keepRunning) {
323
- logger.debug("stopAfterAllSignal.notify()")
324
- await stopAfterAllSignal.notify()
325
- }
326
-
327
- counters.cancelled = counters.total - counters.done
328
- const summary = {
329
- counters,
330
- // when execution is aborted, the remaining executions are "cancelled"
331
- duration: Date.now() - startMs,
332
- }
333
- if (logSummary) {
334
- const summaryLog = createSummaryLog(summary)
335
- rawOutput += stripAnsi(summaryLog)
336
- logger.info(summaryLog)
337
- }
338
- if (summary.counters.total !== summary.counters.completed) {
339
- const logFileUrl = new URL(logFileRelativeUrl, rootDirectoryUrl).href
340
- writeFileSync(logFileUrl, rawOutput)
341
- logger.info(`-> ${urlToFileSystemPath(logFileUrl)}`)
342
- }
343
- executePlanReturnValue.aborted = multipleExecutionsOperation.signal.aborted
344
- executePlanReturnValue.planSummary = summary
345
- executePlanReturnValue.planReport = report
346
- await callbacks.reduce(async (previous, callback) => {
347
- await previous
348
- await callback()
349
- }, Promise.resolve())
350
- return executePlanReturnValue
351
- } finally {
352
- await multipleExecutionsOperation.end()
353
- }
354
- }
355
-
356
- const canOverwriteLogGetter = ({
357
- completedExecutionLogMerging,
358
- executionResult,
359
- }) => {
360
- if (!completedExecutionLogMerging) {
361
- return false
362
- }
363
- if (executionResult.status === "aborted") {
364
- return true
365
- }
366
- if (executionResult.status !== "completed") {
367
- return false
368
- }
369
- const { consoleCalls = [] } = executionResult
370
- if (consoleCalls.length > 0) {
371
- return false
372
- }
373
- return true
374
- }
375
-
376
- const executeInParallel = async ({
377
- multipleExecutionsOperation,
378
- maxExecutionsInParallel,
379
- cooldownBetweenExecutions,
380
- executionSteps,
381
- start,
382
- }) => {
383
- const executionResults = []
384
- let progressionIndex = 0
385
- let remainingExecutionCount = executionSteps.length
386
-
387
- const nextChunk = async () => {
388
- if (multipleExecutionsOperation.signal.aborted) {
389
- return
390
- }
391
- const outputPromiseArray = []
392
- while (
393
- remainingExecutionCount > 0 &&
394
- outputPromiseArray.length < maxExecutionsInParallel
395
- ) {
396
- remainingExecutionCount--
397
- const outputPromise = executeOne(progressionIndex)
398
- progressionIndex++
399
- outputPromiseArray.push(outputPromise)
400
- }
401
- if (outputPromiseArray.length) {
402
- await Promise.all(outputPromiseArray)
403
- if (remainingExecutionCount > 0) {
404
- await nextChunk()
405
- }
406
- }
407
- }
408
-
409
- const executeOne = async (index) => {
410
- const input = executionSteps[index]
411
- const output = await start(input)
412
- if (!multipleExecutionsOperation.signal.aborted) {
413
- executionResults[index] = output
414
- }
415
- if (cooldownBetweenExecutions) {
416
- await new Promise((resolve) =>
417
- setTimeout(resolve, cooldownBetweenExecutions),
418
- )
419
- }
420
- }
421
-
422
- await nextChunk()
423
-
424
- return executionResults
425
- }