@jsenv/core 34.3.0 → 35.0.1

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 (74) hide show
  1. package/README.md +2 -9
  2. package/dist/js/ws.js +1 -145
  3. package/dist/{jsenv.js → jsenv_core.js} +1056 -3850
  4. package/package.json +8 -23
  5. package/src/build/build.js +2 -2
  6. package/src/dev/file_service.js +8 -8
  7. package/src/dev/start_dev_server.js +3 -3
  8. package/src/dev/user_agent.js +1 -1
  9. package/src/main.js +0 -23
  10. package/src/plugins/supervisor/jsenv_plugin_supervisor.js +1 -1
  11. package/src/plugins/transpilation/babel/require_babel_plugin.js +1 -1
  12. package/src/plugins/transpilation/js_module_fallback/convert_js_module_to_js_classic.js +1 -1
  13. package/dist/controllable_child_process.mjs +0 -129
  14. package/dist/controllable_worker_thread.mjs +0 -91
  15. package/dist/importmap_node_loader.mjs +0 -49
  16. package/dist/js/execute_using_dynamic_import.js +0 -850
  17. package/dist/js/resolveImport.js +0 -504
  18. package/dist/js/v8_coverage.js +0 -508
  19. package/dist/no_experimental_warnings.cjs +0 -8
  20. package/src/execute/execute.js +0 -111
  21. package/src/execute/run.js +0 -161
  22. package/src/execute/runtimes/browsers/chromium.js +0 -10
  23. package/src/execute/runtimes/browsers/firefox.js +0 -9
  24. package/src/execute/runtimes/browsers/from_playwright.js +0 -574
  25. package/src/execute/runtimes/browsers/middleware_istanbul.js +0 -65
  26. package/src/execute/runtimes/browsers/middleware_js_supervisor.js +0 -100
  27. package/src/execute/runtimes/browsers/webkit.js +0 -26
  28. package/src/execute/runtimes/node/child_exec_options.js +0 -166
  29. package/src/execute/runtimes/node/controllable_child_process.mjs +0 -135
  30. package/src/execute/runtimes/node/controllable_worker_thread.mjs +0 -103
  31. package/src/execute/runtimes/node/exec_options.js +0 -57
  32. package/src/execute/runtimes/node/execute_using_dynamic_import.js +0 -55
  33. package/src/execute/runtimes/node/exit_codes.js +0 -9
  34. package/src/execute/runtimes/node/importmap_node_loader.mjs +0 -51
  35. package/src/execute/runtimes/node/importmap_node_loader_file_url.js +0 -4
  36. package/src/execute/runtimes/node/kill_process_tree.js +0 -76
  37. package/src/execute/runtimes/node/no_experimental_warnings.cjs +0 -12
  38. package/src/execute/runtimes/node/no_experimental_warnings_file_url.js +0 -4
  39. package/src/execute/runtimes/node/node_child_process.js +0 -363
  40. package/src/execute/runtimes/node/node_execution_performance.js +0 -67
  41. package/src/execute/runtimes/node/node_worker_thread.js +0 -295
  42. package/src/execute/runtimes/node/profiler_v8_coverage.js +0 -56
  43. package/src/execute/runtimes/readme.md +0 -13
  44. package/src/execute/web_server_param.js +0 -74
  45. package/src/test/coverage/babel_plugin_instrument.js +0 -48
  46. package/src/test/coverage/coverage_reporter_html_directory.js +0 -32
  47. package/src/test/coverage/coverage_reporter_json_file.js +0 -17
  48. package/src/test/coverage/coverage_reporter_text_log.js +0 -19
  49. package/src/test/coverage/empty_coverage_factory.js +0 -52
  50. package/src/test/coverage/file_by_file_coverage.js +0 -25
  51. package/src/test/coverage/istanbul_coverage_composition.js +0 -28
  52. package/src/test/coverage/istanbul_coverage_map_from_coverage.js +0 -16
  53. package/src/test/coverage/list_files_not_covered.js +0 -15
  54. package/src/test/coverage/missing_coverage.js +0 -41
  55. package/src/test/coverage/report_to_coverage.js +0 -198
  56. package/src/test/coverage/v8_and_istanbul.js +0 -37
  57. package/src/test/coverage/v8_coverage.js +0 -26
  58. package/src/test/coverage/v8_coverage_composition.js +0 -24
  59. package/src/test/coverage/v8_coverage_node_directory.js +0 -85
  60. package/src/test/coverage/v8_coverage_to_istanbul.js +0 -99
  61. package/src/test/execute_steps.js +0 -425
  62. package/src/test/execute_test_plan.js +0 -372
  63. package/src/test/execution_colors.js +0 -10
  64. package/src/test/execution_steps.js +0 -65
  65. package/src/test/gc.js +0 -9
  66. package/src/test/logs_file_execution.js +0 -427
  67. package/src/test/logs_file_execution.test.mjs +0 -41
  68. package/src/test/readme.md +0 -3
  69. /package/src/{basic_fetch.js → helpers/basic_fetch.js} +0 -0
  70. /package/src/{lookup_package_directory.js → helpers/lookup_package_directory.js} +0 -0
  71. /package/src/{ping_server.js → helpers/ping_server.js} +0 -0
  72. /package/src/{require_from_jsenv.js → helpers/require_from_jsenv.js} +0 -0
  73. /package/src/{watch_source_files.js → helpers/watch_source_files.js} +0 -0
  74. /package/src/{web_url_converter.js → helpers/web_url_converter.js} +0 -0
@@ -1,4 +0,0 @@
1
- export const IMPORTMAP_NODE_LOADER_FILE_URL = new URL(
2
- "./importmap_node_loader.mjs?entry_point",
3
- import.meta.url,
4
- ).href
@@ -1,76 +0,0 @@
1
- import { requireFromJsenv } from "@jsenv/core/src/require_from_jsenv.js"
2
-
3
- // see also https://github.com/sindresorhus/execa/issues/96
4
- export const killProcessTree = async (
5
- processId,
6
- { signal, timeout = 2000 },
7
- ) => {
8
- const pidtree = requireFromJsenv("pidtree")
9
-
10
- let descendantProcessIds
11
- try {
12
- descendantProcessIds = await pidtree(processId)
13
- } catch (e) {
14
- if (e.message === "No matching pid found") {
15
- descendantProcessIds = []
16
- } else {
17
- throw e
18
- }
19
- }
20
- descendantProcessIds.forEach((descendantProcessId) => {
21
- try {
22
- process.kill(descendantProcessId, signal)
23
- } catch (error) {
24
- // ignore
25
- }
26
- })
27
-
28
- try {
29
- process.kill(processId, signal)
30
- } catch (e) {
31
- if (e.code !== "ESRCH") {
32
- throw e
33
- }
34
- }
35
-
36
- let remainingIds = [...descendantProcessIds, processId]
37
-
38
- const updateRemainingIds = () => {
39
- remainingIds = remainingIds.filter((remainingId) => {
40
- try {
41
- process.kill(remainingId, 0)
42
- return true
43
- } catch (e) {
44
- return false
45
- }
46
- })
47
- }
48
-
49
- let timeSpentWaiting = 0
50
-
51
- const check = async () => {
52
- updateRemainingIds()
53
- if (remainingIds.length === 0) {
54
- return
55
- }
56
-
57
- if (timeSpentWaiting > timeout) {
58
- const timeoutError = new Error(
59
- `timed out waiting for ${
60
- remainingIds.length
61
- } process to exit (${remainingIds.join(" ")})`,
62
- )
63
- timeoutError.code = "TIMEOUT"
64
- throw timeoutError
65
- }
66
-
67
- await new Promise((resolve) => setTimeout(resolve, 400))
68
- timeSpentWaiting += 400
69
- await check()
70
- }
71
-
72
- await new Promise((resolve) => {
73
- setTimeout(resolve, 0)
74
- })
75
- await check()
76
- }
@@ -1,12 +0,0 @@
1
- // see https://github.com/nodejs/node/issues/47478
2
- const originalEmit = process.emit
3
- process.emit = (event, error) => {
4
- if (
5
- event === "warning" &&
6
- error.name === "ExperimentalWarning" &&
7
- error.message.includes("--experimental-loader")
8
- ) {
9
- return false
10
- }
11
- return originalEmit.call(process, event, error)
12
- }
@@ -1,4 +0,0 @@
1
- export const NO_EXPERIMENTAL_WARNING_FILE_URL = new URL(
2
- "./no_experimental_warnings.cjs?entry_point",
3
- import.meta.url,
4
- ).href
@@ -1,363 +0,0 @@
1
- import { fork } from "node:child_process"
2
- import { fileURLToPath } from "node:url"
3
- import {
4
- Abort,
5
- raceCallbacks,
6
- createCallbackListNotifiedOnce,
7
- } from "@jsenv/abort"
8
- import { createDetailedMessage } from "@jsenv/log"
9
- import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
10
-
11
- import { createChildExecOptions } from "./child_exec_options.js"
12
- import { ExecOptions } from "./exec_options.js"
13
- import { killProcessTree } from "./kill_process_tree.js"
14
- import { EXIT_CODES } from "./exit_codes.js"
15
- import { IMPORTMAP_NODE_LOADER_FILE_URL } from "./importmap_node_loader_file_url.js"
16
- import { NO_EXPERIMENTAL_WARNING_FILE_URL } from "./no_experimental_warnings_file_url.js"
17
-
18
- const CONTROLLABLE_CHILD_PROCESS_URL = new URL(
19
- "./controllable_child_process.mjs?entry_point",
20
- import.meta.url,
21
- ).href
22
-
23
- export const nodeChildProcess = {
24
- type: "node",
25
- name: "node_child_process",
26
- version: process.version.slice(1),
27
- }
28
-
29
- nodeChildProcess.run = async ({
30
- signal = new AbortController().signal,
31
- logger,
32
- logProcessCommand = false,
33
- rootDirectoryUrl,
34
- fileRelativeUrl,
35
- importMap,
36
-
37
- keepRunning,
38
- gracefulStopAllocatedMs = 4000,
39
- stopSignal,
40
- onConsole,
41
-
42
- coverageEnabled = false,
43
- coverageConfig,
44
- coverageMethodForNodeJs,
45
- coverageFileUrl,
46
- collectPerformance,
47
-
48
- env,
49
- debugPort,
50
- debugMode,
51
- debugModeInheritBreak,
52
- inheritProcessEnv = true,
53
- commandLineOptions = [],
54
- stdin = "pipe",
55
- stdout = "pipe",
56
- stderr = "pipe",
57
- }) => {
58
- if (env !== undefined && typeof env !== "object") {
59
- throw new TypeError(`env must be an object, got ${env}`)
60
- }
61
- env = {
62
- ...env,
63
- JSENV: true,
64
- }
65
- if (coverageMethodForNodeJs !== "NODE_V8_COVERAGE") {
66
- env.NODE_V8_COVERAGE = ""
67
- }
68
- commandLineOptions = [
69
- "--experimental-import-meta-resolve",
70
- ...commandLineOptions,
71
- ]
72
-
73
- if (importMap) {
74
- env.IMPORT_MAP = JSON.stringify(importMap)
75
- env.IMPORT_MAP_BASE_URL = rootDirectoryUrl
76
- commandLineOptions.push(
77
- `--experimental-loader=${fileURLToPath(IMPORTMAP_NODE_LOADER_FILE_URL)}`,
78
- )
79
- commandLineOptions.push(
80
- `--require=${fileURLToPath(NO_EXPERIMENTAL_WARNING_FILE_URL)}`,
81
- )
82
- }
83
-
84
- const cleanupCallbackList = createCallbackListNotifiedOnce()
85
- const cleanup = async (reason) => {
86
- await cleanupCallbackList.notify({ reason })
87
- }
88
-
89
- const childExecOptions = await createChildExecOptions({
90
- signal,
91
- debugPort,
92
- debugMode,
93
- debugModeInheritBreak,
94
- })
95
- const execArgv = ExecOptions.toExecArgv({
96
- ...childExecOptions,
97
- ...ExecOptions.fromExecArgv(commandLineOptions),
98
- })
99
- const envForChildProcess = {
100
- ...(inheritProcessEnv ? process.env : {}),
101
- ...env,
102
- }
103
- logger[logProcessCommand ? "info" : "debug"](
104
- `${process.argv[0]} ${execArgv.join(" ")} ${fileURLToPath(
105
- CONTROLLABLE_CHILD_PROCESS_URL,
106
- )}`,
107
- )
108
- const childProcess = fork(fileURLToPath(CONTROLLABLE_CHILD_PROCESS_URL), {
109
- execArgv,
110
- // silent: true
111
- stdio: ["pipe", "pipe", "pipe", "ipc"],
112
- env: envForChildProcess,
113
- cwd: new URL(rootDirectoryUrl),
114
- })
115
- logger.debug(
116
- createDetailedMessage(`child process forked (pid ${childProcess.pid})`, {
117
- "custom env": JSON.stringify(env, null, " "),
118
- }),
119
- )
120
- // if we pass stream, pipe them https://github.com/sindresorhus/execa/issues/81
121
- if (typeof stdin === "object") {
122
- stdin.pipe(childProcess.stdin)
123
- }
124
- if (typeof stdout === "object") {
125
- childProcess.stdout.pipe(stdout)
126
- }
127
- if (typeof stderr === "object") {
128
- childProcess.stderr.pipe(stderr)
129
- }
130
- const childProcessReadyPromise = new Promise((resolve) => {
131
- onceChildProcessMessage(childProcess, "ready", resolve)
132
- })
133
- const removeOutputListener = installChildProcessOutputListener(
134
- childProcess,
135
- ({ type, text }) => {
136
- onConsole({ type, text })
137
- },
138
- )
139
- const stop = memoize(async ({ gracefulStopAllocatedMs } = {}) => {
140
- // all libraries are facing problem on windows when trying
141
- // to kill a process spawning other processes.
142
- // "killProcessTree" is theorically correct but sometimes keep process handing forever.
143
- // Inside GitHub workflow the whole Virtual machine gets unresponsive and ends up being killed
144
- // There is no satisfying solution to this problem so we stick to the basic
145
- // childProcess.kill()
146
- if (process.platform === "win32") {
147
- childProcess.kill()
148
- return
149
- }
150
- if (gracefulStopAllocatedMs) {
151
- try {
152
- await killProcessTree(childProcess.pid, {
153
- signal: GRACEFUL_STOP_SIGNAL,
154
- timeout: gracefulStopAllocatedMs,
155
- })
156
- return
157
- } catch (e) {
158
- if (e.code === "TIMEOUT") {
159
- logger.debug(
160
- `kill with SIGTERM because gracefulStop still pending after ${gracefulStopAllocatedMs}ms`,
161
- )
162
- await killProcessTree(childProcess.pid, {
163
- signal: GRACEFUL_STOP_FAILED_SIGNAL,
164
- })
165
- return
166
- }
167
- throw e
168
- }
169
- }
170
- await killProcessTree(childProcess.pid, { signal: STOP_SIGNAL })
171
- return
172
- })
173
-
174
- const actionOperation = Abort.startOperation()
175
- actionOperation.addAbortSignal(signal)
176
- const winnerPromise = new Promise((resolve) => {
177
- raceCallbacks(
178
- {
179
- aborted: (cb) => {
180
- return actionOperation.addAbortCallback(cb)
181
- },
182
- // https://nodejs.org/api/child_process.html#child_process_event_disconnect
183
- // disconnect: (cb) => {
184
- // return onceProcessEvent(childProcess, "disconnect", cb)
185
- // },
186
- // https://nodejs.org/api/child_process.html#child_process_event_error
187
- error: (cb) => {
188
- return onceChildProcessEvent(childProcess, "error", cb)
189
- },
190
- exit: (cb) => {
191
- return onceChildProcessEvent(childProcess, "exit", (code, signal) => {
192
- cb({ code, signal })
193
- })
194
- },
195
- response: (cb) => {
196
- return onceChildProcessMessage(childProcess, "action-result", cb)
197
- },
198
- },
199
- resolve,
200
- )
201
- })
202
- const result = {
203
- status: "executing",
204
- errors: [],
205
- namespace: null,
206
- }
207
-
208
- const writeResult = async () => {
209
- actionOperation.throwIfAborted()
210
- await childProcessReadyPromise
211
- actionOperation.throwIfAborted()
212
- await sendToChildProcess(childProcess, {
213
- type: "action",
214
- data: {
215
- actionType: "execute-using-dynamic-import",
216
- actionParams: {
217
- rootDirectoryUrl,
218
- fileUrl: new URL(fileRelativeUrl, rootDirectoryUrl).href,
219
- collectPerformance,
220
- coverageEnabled,
221
- coverageConfig,
222
- coverageMethodForNodeJs,
223
- coverageFileUrl,
224
- exitAfterAction: true,
225
- },
226
- },
227
- })
228
- const winner = await winnerPromise
229
- if (winner.name === "aborted") {
230
- result.status = "aborted"
231
- return
232
- }
233
- if (winner.name === "error") {
234
- const error = winner.data
235
- removeOutputListener()
236
- result.status = "failed"
237
- result.errors.push(error)
238
- return
239
- }
240
- if (winner.name === "exit") {
241
- const { code } = winner.data
242
- await cleanup("process exit")
243
- if (code === 12) {
244
- result.status = "failed"
245
- result.errors.push(
246
- new Error(
247
- `node process exited with 12 (the forked child process wanted to use a non-available port for debug)`,
248
- ),
249
- )
250
- return
251
- }
252
- if (
253
- code === null ||
254
- code === 0 ||
255
- code === EXIT_CODES.SIGINT ||
256
- code === EXIT_CODES.SIGTERM ||
257
- code === EXIT_CODES.SIGABORT
258
- ) {
259
- result.status = "failed"
260
- result.errors.push(new Error(`node process exited during execution`))
261
- return
262
- }
263
- // process.exit(1) in child process or process.exitCode = 1 + process.exit()
264
- // means there was an error even if we don't know exactly what.
265
- result.status = "failed"
266
- result.errors.push(
267
- new Error(`node process exited with code ${code} during execution`),
268
- )
269
- return
270
- }
271
- const { status, value } = winner.data
272
- if (status === "action-failed") {
273
- result.status = "failed"
274
- result.errors.push(value)
275
- return
276
- }
277
- const { namespace, performance, coverage } = value
278
- result.status = "completed"
279
- result.namespace = namespace
280
- result.performance = performance
281
- result.coverage = coverage
282
- }
283
-
284
- try {
285
- await writeResult()
286
- } catch (e) {
287
- result.status = "failed"
288
- result.errors.push(e)
289
- }
290
- if (keepRunning) {
291
- stopSignal.notify = stop
292
- } else {
293
- await stop({
294
- gracefulStopAllocatedMs,
295
- })
296
- }
297
- await actionOperation.end()
298
- return result
299
- }
300
-
301
- // http://man7.org/linux/man-pages/man7/signal.7.html
302
- // https:// github.com/nodejs/node/blob/1d9511127c419ec116b3ddf5fc7a59e8f0f1c1e4/lib/internal/child_process.js#L472
303
- const GRACEFUL_STOP_SIGNAL = "SIGTERM"
304
- const STOP_SIGNAL = "SIGKILL"
305
- // it would be more correct if GRACEFUL_STOP_FAILED_SIGNAL was SIGHUP instead of SIGKILL.
306
- // but I'm not sure and it changes nothing so just use SIGKILL
307
- const GRACEFUL_STOP_FAILED_SIGNAL = "SIGKILL"
308
-
309
- const sendToChildProcess = async (childProcess, { type, data }) => {
310
- return new Promise((resolve, reject) => {
311
- childProcess.send(
312
- {
313
- jsenv: true,
314
- type,
315
- data,
316
- },
317
- (error) => {
318
- if (error) {
319
- reject(error)
320
- } else {
321
- resolve()
322
- }
323
- },
324
- )
325
- })
326
- }
327
-
328
- const installChildProcessOutputListener = (childProcess, callback) => {
329
- // beware that we may receive ansi output here, should not be a problem but keep that in mind
330
- const stdoutDataCallback = (chunk) => {
331
- callback({ type: "log", text: String(chunk) })
332
- }
333
- childProcess.stdout.on("data", stdoutDataCallback)
334
- const stdErrorDataCallback = (chunk) => {
335
- callback({ type: "error", text: String(chunk) })
336
- }
337
- childProcess.stderr.on("data", stdErrorDataCallback)
338
- return () => {
339
- childProcess.stdout.removeListener("data", stdoutDataCallback)
340
- childProcess.stderr.removeListener("data", stdoutDataCallback)
341
- }
342
- }
343
-
344
- const onceChildProcessMessage = (childProcess, type, callback) => {
345
- const onmessage = (message) => {
346
- if (message && message.jsenv && message.type === type) {
347
- childProcess.removeListener("message", onmessage)
348
- // eslint-disable-next-line no-eval
349
- callback(message.data ? eval(`(${message.data})`) : "")
350
- }
351
- }
352
- childProcess.on("message", onmessage)
353
- return () => {
354
- childProcess.removeListener("message", onmessage)
355
- }
356
- }
357
-
358
- const onceChildProcessEvent = (childProcess, type, callback) => {
359
- childProcess.once(type, callback)
360
- return () => {
361
- childProcess.removeListener(type, callback)
362
- }
363
- }
@@ -1,67 +0,0 @@
1
- import { PerformanceObserver, performance } from "node:perf_hooks"
2
-
3
- export const startObservingPerformances = () => {
4
- const measureEntries = []
5
- // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html
6
- const perfObserver = new PerformanceObserver(
7
- (
8
- // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceobserverentrylist
9
- list,
10
- ) => {
11
- const perfMeasureEntries = list.getEntriesByType("measure")
12
- measureEntries.push(...perfMeasureEntries)
13
- },
14
- )
15
- perfObserver.observe({
16
- entryTypes: ["measure"],
17
- })
18
- return async () => {
19
- // wait for node to call the performance observer
20
- await new Promise((resolve) => {
21
- setTimeout(resolve)
22
- })
23
- performance.clearMarks()
24
- perfObserver.disconnect()
25
- return {
26
- ...readNodePerformance(),
27
- measures: measuresFromMeasureEntries(measureEntries),
28
- }
29
- }
30
- }
31
-
32
- const readNodePerformance = () => {
33
- const nodePerformance = {
34
- nodeTiming: asPlainObject(performance.nodeTiming),
35
- timeOrigin: performance.timeOrigin,
36
- eventLoopUtilization: performance.eventLoopUtilization(),
37
- }
38
- return nodePerformance
39
- }
40
-
41
- // remove getters that cannot be stringified
42
- const asPlainObject = (objectWithGetters) => {
43
- const objectWithoutGetters = {}
44
- Object.keys(objectWithGetters).forEach((key) => {
45
- objectWithoutGetters[key] = objectWithGetters[key]
46
- })
47
- return objectWithoutGetters
48
- }
49
-
50
- const measuresFromMeasureEntries = (measureEntries) => {
51
- const measures = {}
52
- // Sort to ensure measures order is predictable
53
- // It seems to be already predictable on Node 16+ but
54
- // it's not the case on Node 14.
55
- measureEntries.sort((a, b) => {
56
- return a.startTime - b.startTime
57
- })
58
- measureEntries.forEach(
59
- (
60
- // https://nodejs.org/dist/latest-v16.x/docs/api/perf_hooks.html#perf_hooks_class_performanceentry
61
- perfMeasureEntry,
62
- ) => {
63
- measures[perfMeasureEntry.name] = perfMeasureEntry.duration
64
- },
65
- )
66
- return measures
67
- }