@jsenv/core 23.2.2 → 23.3.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 (34) hide show
  1. package/{license → LICENSE} +0 -0
  2. package/package.json +13 -14
  3. package/src/buildProject.js +12 -13
  4. package/src/execute.js +92 -93
  5. package/src/internal/browser-launcher/executeHtmlFile.js +6 -7
  6. package/src/internal/building/buildUsingRollup.js +3 -4
  7. package/src/internal/building/build_logs.js +7 -6
  8. package/src/internal/building/createJsenvRollupPlugin.js +9 -14
  9. package/src/internal/building/url_trace.js +3 -4
  10. package/src/internal/compiling/createCompiledFileService.js +8 -5
  11. package/src/internal/compiling/startCompileServer.js +55 -46
  12. package/src/internal/executing/coverage/relativeUrlToEmptyCoverage.js +2 -3
  13. package/src/internal/executing/createSummaryLog.js +12 -14
  14. package/src/internal/executing/executeConcurrently.js +7 -5
  15. package/src/internal/executing/executePlan.js +80 -80
  16. package/src/internal/executing/executionLogs.js +14 -18
  17. package/src/internal/executing/execution_colors.js +6 -12
  18. package/src/internal/executing/launchAndExecute.js +125 -145
  19. package/src/internal/node-launcher/createControllableNodeProcess.js +26 -23
  20. package/src/launchBrowser.js +64 -61
  21. package/src/launchNode.js +6 -6
  22. package/src/startExploring.js +2 -17
  23. package/src/abort/abortable.js +0 -172
  24. package/src/abort/callback_list.js +0 -64
  25. package/src/abort/callback_race.js +0 -34
  26. package/src/abort/cleaner.js +0 -22
  27. package/src/abort/main.js +0 -32
  28. package/src/abort/process_teardown_events.js +0 -59
  29. package/src/internal/createCallbackList.js +0 -21
  30. package/src/internal/executing/logUtils.js +0 -30
  31. package/src/internal/executing/writeLog.js +0 -106
  32. package/src/internal/executing/writeLog.test-manual.js +0 -62
  33. package/src/internal/logs/log_style.js +0 -40
  34. package/src/signal/signal.js +0 -65
@@ -1,13 +1,8 @@
1
1
  import { createLogger, createDetailedMessage } from "@jsenv/logger"
2
+ import { Abort, raceCallbacks } from "@jsenv/abort"
2
3
 
3
- import { Abortable } from "@jsenv/core/src/abort/main.js"
4
- import { raceCallbacks } from "../../abort/callback_race.js"
5
4
  import { composeIstanbulCoverages } from "./coverage/composeIstanbulCoverages.js"
6
5
 
7
- const TIMING_BEFORE_EXECUTION = "before-execution"
8
- const TIMING_DURING_EXECUTION = "during-execution"
9
- const TIMING_AFTER_EXECUTION = "after-execution"
10
-
11
6
  export const launchAndExecute = async ({
12
7
  signal = new AbortController().signal,
13
8
  launchAndExecuteLogLevel,
@@ -32,7 +27,7 @@ export const launchAndExecute = async ({
32
27
  // however unit test will pass true because they want to move on
33
28
  stopAfterExecute = false,
34
29
  stopAfterExecuteReason = "stop after execute",
35
- // when launch returns { stoppedSignal, gracefulStop, stop }
30
+ // when launch returns { stoppedCallbackList, gracefulStop, stop }
36
31
  // the launched runtime have that amount of ms for disconnected to resolve
37
32
  // before we call stop
38
33
  gracefulStopAllocatedMs = 4000,
@@ -60,27 +55,20 @@ export const launchAndExecute = async ({
60
55
 
61
56
  let executionResultTransformer = (executionResult) => executionResult
62
57
 
63
- const launchAndExecuteOperation = Abortable.fromSignal(signal)
58
+ const launchAndExecuteOperation = Abort.startOperation()
59
+ launchAndExecuteOperation.addAbortSignal(signal)
64
60
 
65
61
  const hasAllocatedMs =
66
62
  typeof allocatedMs === "number" && allocatedMs !== Infinity
67
- let timeoutAbortEffect
63
+ let timeoutAbortSource
68
64
 
69
65
  if (hasAllocatedMs) {
70
- timeoutAbortEffect = Abortable.timeout(
71
- launchAndExecuteOperation,
66
+ timeoutAbortSource = launchAndExecuteOperation.timeout(
72
67
  // FIXME: if allocatedMs is veryyyyyy big
73
68
  // setTimeout may be called immediatly
74
69
  // in that case we should just throw that the number is too big
75
70
  allocatedMs,
76
71
  )
77
- executionResultTransformer = composeTransformer(
78
- executionResultTransformer,
79
- (executionResult) => {
80
- timeoutAbortEffect.cleanup()
81
- return executionResult
82
- },
83
- )
84
72
  }
85
73
 
86
74
  if (mirrorConsole) {
@@ -193,26 +181,6 @@ export const launchAndExecute = async ({
193
181
  )
194
182
  }
195
183
 
196
- if (stopAfterExecute) {
197
- executionResultTransformer = composeTransformer(
198
- executionResultTransformer,
199
- async (executionResult) => {
200
- // if there is an error while cleaning (stopping the runtime)
201
- // the execution is considered as failed
202
- try {
203
- await launchAndExecuteOperation.cleaner.clean(stopAfterExecuteReason)
204
- return executionResult
205
- } catch (e) {
206
- return executionResultTransformer(
207
- createErroredExecutionResult({
208
- error: e,
209
- }),
210
- )
211
- }
212
- },
213
- )
214
- }
215
-
216
184
  if (measureDuration) {
217
185
  const startMs = Date.now()
218
186
  executionResultTransformer = composeTransformer(
@@ -230,7 +198,7 @@ export const launchAndExecute = async ({
230
198
  const runtimeLabel = `${runtime.name}/${runtime.version}`
231
199
  logger.debug(`launch ${runtimeLabel} to execute something in it`)
232
200
 
233
- Abortable.throwIfAborted(launchAndExecuteOperation)
201
+ launchAndExecuteOperation.throwIfAborted()
234
202
  const launchReturnValue = await runtime.launch({
235
203
  signal: launchAndExecuteOperation.signal,
236
204
  logger,
@@ -240,14 +208,19 @@ export const launchAndExecute = async ({
240
208
  ...runtimeParams,
241
209
  })
242
210
  validateLaunchReturnValue(launchReturnValue)
243
- launchAndExecuteOperation.cleaner.addCallback(async (reason) => {
244
- await stopRuntime({
245
- logger,
246
- runtimeLabel,
247
- launchReturnValue,
248
- gracefulStopAllocatedMs,
249
- reason,
250
- })
211
+
212
+ const stopRuntime = async (reason) => {
213
+ const { stop } = launchReturnValue
214
+ logger.debug(`${runtimeLabel}: stop() because ${reason}`)
215
+ const { graceful } = await stop({ reason, gracefulStopAllocatedMs })
216
+ if (graceful) {
217
+ logger.debug(`${runtimeLabel}: runtime stopped gracefully`)
218
+ } else {
219
+ logger.debug(`${runtimeLabel}: runtime stopped`)
220
+ }
221
+ }
222
+ launchAndExecuteOperation.addAbortCallback(async () => {
223
+ await stopRuntime("Operation aborted")
251
224
  })
252
225
 
253
226
  logger.debug(createDetailedMessage(`${runtimeLabel}: runtime launched`))
@@ -255,9 +228,9 @@ export const launchAndExecute = async ({
255
228
 
256
229
  logger.debug(`${runtimeLabel}: start execution`)
257
230
  const {
258
- errorSignal,
259
- outputSignal,
260
- stoppedSignal,
231
+ errorCallbackList,
232
+ outputCallbackList,
233
+ stoppedCallbackList,
261
234
  execute,
262
235
  finalizeExecutionResult = (executionResult) => executionResult,
263
236
  } = launchReturnValue
@@ -265,104 +238,60 @@ export const launchAndExecute = async ({
265
238
  executionResultTransformer,
266
239
  finalizeExecutionResult,
267
240
  )
268
- outputSignal.addCallback(runtimeConsoleCallback)
269
-
270
- let timing = TIMING_BEFORE_EXECUTION
271
- stoppedSignal.addCallback(() => {
272
- logger.debug(`${runtimeLabel}: runtime stopped ${timing}`)
273
- runtimeStoppedCallback()
274
- })
241
+ outputCallbackList.add(runtimeConsoleCallback)
275
242
 
276
- const winnerPromise = new Promise((resolve, reject) => {
277
- raceCallbacks(
278
- {
279
- aborted: (cb) => {
280
- launchAndExecuteOperation.signal.addEventListener("abort", cb)
281
- return () => {
282
- launchAndExecuteOperation.signal.removeEventListener("abort", cb)
283
- }
284
- },
285
- error: (cb) => {
286
- return errorSignal.addCallback(cb)
287
- },
288
- stopped: (cb) => {
289
- return stoppedSignal.addCallback(cb)
290
- },
291
- executed: (cb) => {
292
- timing = TIMING_DURING_EXECUTION
293
- const executed = execute({
294
- signal: launchAndExecuteOperation.signal,
295
- ...executeParams,
296
- })
297
- executed.then(cb, reject)
298
- },
299
- },
300
- resolve,
301
- )
243
+ let executionResult = await callExecute({
244
+ launchAndExecuteOperation,
245
+ errorCallbackList,
246
+ stoppedCallbackList,
247
+ execute,
248
+ executeParams,
302
249
  })
303
250
 
304
- Abortable.throwIfAborted(launchAndExecuteOperation)
305
-
306
- const winner = await winnerPromise
307
-
308
- if (winner.name === "aborted") {
309
- Abortable.throwIfAborted(launchAndExecuteOperation)
310
- }
311
-
312
- if (winner.name === "error") {
313
- return executionResultTransformer(
314
- createErroredExecutionResult({
315
- error: winner.data,
316
- }),
317
- )
318
- }
319
-
320
- if (winner.name === "stopped") {
321
- return executionResultTransformer(
322
- createErroredExecutionResult({
323
- error: new Error(`runtime stopped during execution`),
324
- }),
325
- )
326
- }
327
-
328
- timing = TIMING_AFTER_EXECUTION
329
-
330
- if (!stopAfterExecute) {
251
+ if (stopAfterExecute) {
252
+ // stopping runtime is part of the execution
253
+ try {
254
+ await stopRuntime(stopAfterExecuteReason)
255
+ } catch (e) {
256
+ executionResult = createErroredExecutionResult({
257
+ error: e,
258
+ })
259
+ }
260
+ } else {
331
261
  // when the process is still alive
332
262
  // we want to catch error to notify runtimeErrorAfterExecutionCallback
333
263
  // and throw that error by default
334
- errorSignal.addCallback((error) => {
264
+ errorCallbackList.add((error) => {
335
265
  runtimeErrorAfterExecutionCallback(error)
336
266
  })
267
+ stoppedCallbackList.add(() => {
268
+ logger.debug(`${runtimeLabel}: runtime stopped after execution`)
269
+ runtimeStoppedCallback()
270
+ })
337
271
  }
338
272
 
339
- const executeResult = winner.data
340
- const { status } = executeResult
341
-
342
- if (status === "errored") {
273
+ if (executionResult.status === "errored") {
343
274
  // debug log level because this error happens during execution
344
275
  // there is no need to log it.
345
276
  // the code will know the execution errored because it receives
346
277
  // an errored execution result
347
278
  logger.debug(
348
- createDetailedMessage(`error ${TIMING_DURING_EXECUTION}`, {
349
- ["error stack"]: executeResult.error.stack,
279
+ createDetailedMessage(`error during execution`, {
280
+ ["error stack"]: executionResult.error.stack,
350
281
  ["execute params"]: JSON.stringify(executeParams, null, " "),
351
282
  ["runtime"]: runtime,
352
283
  }),
353
284
  )
354
- return executionResultTransformer(
355
- createErroredExecutionResult(executeResult),
356
- )
285
+ } else {
286
+ logger.debug(`${runtimeLabel}: execution ${executionResult.status}`)
357
287
  }
358
288
 
359
- logger.debug(`${runtimeLabel}: execution completed`)
360
- return executionResultTransformer(
361
- createCompletedExecutionResult(executeResult),
362
- )
289
+ return executionResultTransformer(executionResult)
363
290
  } catch (e) {
364
- if (e.name === "AbortError") {
365
- if (timeoutAbortEffect && timeoutAbortEffect.signal.aborted) {
291
+ if (Abort.isAbortError(e)) {
292
+ // we should stop runtime too
293
+
294
+ if (timeoutAbortSource && timeoutAbortSource.signal.aborted) {
366
295
  const executionResult = createTimedoutExecutionResult()
367
296
  return executionResultTransformer(executionResult)
368
297
  }
@@ -370,24 +299,71 @@ export const launchAndExecute = async ({
370
299
  return executionResultTransformer(executionResult)
371
300
  }
372
301
  throw e
302
+ } finally {
303
+ await launchAndExecuteOperation.end()
373
304
  }
374
305
  }
375
306
 
376
- const stopRuntime = async ({
377
- logger,
378
- runtimeLabel,
379
- launchReturnValue,
380
- gracefulStopAllocatedMs,
381
- reason,
307
+ const callExecute = async ({
308
+ launchAndExecuteOperation,
309
+ errorCallbackList,
310
+ stoppedCallbackList,
311
+ execute,
312
+ executeParams,
382
313
  }) => {
383
- const { stop } = launchReturnValue
384
- logger.debug(`${runtimeLabel}: stop() because ${reason}`)
385
- const { graceful } = await stop({ reason, gracefulStopAllocatedMs })
386
- if (graceful) {
387
- logger.debug(`${runtimeLabel}: runtime stopped gracefully`)
388
- } else {
389
- logger.debug(`${runtimeLabel}: runtime stopped`)
314
+ const winnerPromise = new Promise((resolve, reject) => {
315
+ raceCallbacks(
316
+ {
317
+ aborted: (cb) => {
318
+ launchAndExecuteOperation.signal.addEventListener("abort", cb)
319
+ return () => {
320
+ launchAndExecuteOperation.signal.removeEventListener("abort", cb)
321
+ }
322
+ },
323
+ error: (cb) => {
324
+ return errorCallbackList.add(cb)
325
+ },
326
+ stopped: (cb) => {
327
+ return stoppedCallbackList.add(cb)
328
+ },
329
+ executed: (cb) => {
330
+ const executed = execute({
331
+ signal: launchAndExecuteOperation.signal,
332
+ ...executeParams,
333
+ })
334
+ executed.then(cb, reject)
335
+ },
336
+ },
337
+ resolve,
338
+ )
339
+ })
340
+
341
+ launchAndExecuteOperation.throwIfAborted()
342
+ const winner = await winnerPromise
343
+
344
+ if (winner.name === "aborted") {
345
+ launchAndExecuteOperation.throwIfAborted()
390
346
  }
347
+
348
+ if (winner.name === "error") {
349
+ return createErroredExecutionResult({
350
+ error: winner.data,
351
+ })
352
+ }
353
+
354
+ if (winner.name === "stopped") {
355
+ return createErroredExecutionResult({
356
+ error: new Error(`runtime stopped during execution`),
357
+ })
358
+ }
359
+
360
+ const executeResult = winner.data
361
+ const { status } = executeResult
362
+
363
+ if (status === "errored") {
364
+ return createErroredExecutionResult(executeResult)
365
+ }
366
+ return createCompletedExecutionResult(executeResult)
391
367
  }
392
368
 
393
369
  const createAbortedExecutionResult = () => {
@@ -444,22 +420,26 @@ const composeTransformer = (previousTransformer, transformer) => {
444
420
 
445
421
  const validateLaunchReturnValue = (launchReturnValue) => {
446
422
  if (launchReturnValue === null) {
447
- throw new Error(`launch must return an object, got null`)
423
+ throw new Error(`runtime.launch must return an object, got null`)
448
424
  }
449
425
 
450
426
  if (typeof launchReturnValue !== "object") {
451
- throw new Error(`launch must return an object, got ${launchReturnValue}`)
427
+ throw new Error(
428
+ `runtime.launch must return an object, got ${launchReturnValue}`,
429
+ )
452
430
  }
453
431
 
454
432
  const { execute } = launchReturnValue
455
433
  if (typeof execute !== "function") {
456
- throw new Error(`launch must return an execute function, got ${execute}`)
434
+ throw new Error(
435
+ `runtime.launch must return an execute function, got ${execute}`,
436
+ )
457
437
  }
458
438
 
459
- const { stoppedSignal } = launchReturnValue
460
- if (!stoppedSignal) {
439
+ const { stoppedCallbackList } = launchReturnValue
440
+ if (!stoppedCallbackList) {
461
441
  throw new Error(
462
- `launch must return a stoppedSignal object, got ${stoppedSignal}`,
442
+ `runtime.launch must return a stoppedCallbackList object, got ${stoppedCallbackList}`,
463
443
  )
464
444
  }
465
445
  }
@@ -6,10 +6,13 @@ import {
6
6
  resolveUrl,
7
7
  assertFilePresence,
8
8
  } from "@jsenv/filesystem"
9
+ import {
10
+ Abort,
11
+ raceCallbacks,
12
+ createCallbackList,
13
+ createCallbackListNotifiedOnce,
14
+ } from "@jsenv/abort"
9
15
 
10
- import { Abortable } from "@jsenv/core/src/abort/main.js"
11
- import { raceCallbacks } from "@jsenv/core/src/abort/callback_race.js"
12
- import { createSignal } from "@jsenv/core/src/signal/signal.js"
13
16
  import { nodeSupportsDynamicImport } from "../runtime/node-feature-detect/nodeSupportsDynamicImport.js"
14
17
  import { jsenvCoreDirectoryUrl } from "../jsenvCoreDirectoryUrl.js"
15
18
  import { createChildProcessOptions } from "./createChildProcessOptions.js"
@@ -117,19 +120,18 @@ export const createControllableNodeProcess = async ({
117
120
  onceProcessMessage(childProcess, "ready", resolve)
118
121
  })
119
122
 
120
- const outputSignal = createSignal()
123
+ const outputCallbackList = createCallbackList()
121
124
  const removeOutputListener = installProcessOutputListener(
122
125
  childProcess,
123
126
  ({ type, text }) => {
124
- outputSignal.emit({ type, text })
127
+ outputCallbackList.notify({ type, text })
125
128
  },
126
129
  )
127
130
 
128
- const errorSignal = createSignal()
131
+ const errorCallbackList = createCallbackList()
132
+
133
+ const stoppedCallbackList = createCallbackListNotifiedOnce()
129
134
 
130
- const stoppedSignal = createSignal({
131
- once: true,
132
- })
133
135
  raceCallbacks(
134
136
  {
135
137
  // https://nodejs.org/api/child_process.html#child_process_event_disconnect
@@ -149,7 +151,7 @@ export const createControllableNodeProcess = async ({
149
151
  (winner) => {
150
152
  const raceEffects = {
151
153
  // disconnect: () => {
152
- // stoppedSignal.emit()
154
+ // stoppedCallbackList.notify()
153
155
  // },
154
156
  error: (error) => {
155
157
  removeOutputListener()
@@ -159,7 +161,7 @@ export const createControllableNodeProcess = async ({
159
161
  ) {
160
162
  return
161
163
  }
162
- errorSignal.emit(error)
164
+ errorCallbackList.notify(error)
163
165
  },
164
166
  exit: ({ code, signal }) => {
165
167
  // process.exit(1) in child process or process.exitCode = 1 + process.exit()
@@ -171,9 +173,9 @@ export const createControllableNodeProcess = async ({
171
173
  code !== SIGTERM_EXIT_CODE &&
172
174
  code !== SIGABORT_EXIT_CODE
173
175
  ) {
174
- errorSignal.emit(createExitWithFailureCodeError(code))
176
+ errorCallbackList.notify(createExitWithFailureCodeError(code))
175
177
  }
176
- stoppedSignal.emit({ code, signal })
178
+ stoppedCallbackList.notify({ code, signal })
177
179
  },
178
180
  }
179
181
  raceEffects[winner.name](winner.data)
@@ -181,15 +183,15 @@ export const createControllableNodeProcess = async ({
181
183
  )
182
184
 
183
185
  const stop = async ({ gracefulStopAllocatedMs } = {}) => {
184
- if (stoppedSignal.emitted) {
186
+ if (stoppedCallbackList.notified) {
185
187
  return {}
186
188
  }
187
189
 
188
190
  const createStoppedPromise = async () => {
189
- if (stoppedSignal.emitted) {
191
+ if (stoppedCallbackList.notified) {
190
192
  return
191
193
  }
192
- await new Promise((resolve) => stoppedSignal.addCallback(resolve))
194
+ await new Promise((resolve) => stoppedCallbackList.add(resolve))
193
195
  }
194
196
 
195
197
  if (gracefulStopAllocatedMs) {
@@ -225,10 +227,11 @@ export const createControllableNodeProcess = async ({
225
227
  actionType,
226
228
  actionParams,
227
229
  }) => {
228
- const actionAbortable = Abortable.fromSignal(signal)
230
+ const actionOperation = Abort.startOperation()
231
+ actionOperation.addAbortSignal(signal)
229
232
 
230
233
  return new Promise(async (resolve, reject) => {
231
- Abortable.throwIfAborted(actionAbortable)
234
+ actionOperation.throwIfAborted()
232
235
  await childProcessReadyPromise
233
236
 
234
237
  onceProcessMessage(childProcess, "action-result", ({ status, value }) => {
@@ -247,13 +250,13 @@ export const createControllableNodeProcess = async ({
247
250
  )
248
251
 
249
252
  try {
250
- Abortable.throwIfAborted(actionAbortable)
253
+ actionOperation.throwIfAborted()
251
254
  await sendToProcess(childProcess, "action", {
252
255
  actionType,
253
256
  actionParams,
254
257
  })
255
258
  } catch (e) {
256
- if (actionAbortable.signal.aborted && e.name === "AbortError") {
259
+ if (Abort.isAbortError(e) && actionOperation.signal.aborted) {
257
260
  throw e
258
261
  }
259
262
  logger.error(
@@ -268,9 +271,9 @@ export const createControllableNodeProcess = async ({
268
271
 
269
272
  return {
270
273
  execArgv,
271
- stoppedSignal,
272
- errorSignal,
273
- outputSignal,
274
+ stoppedCallbackList,
275
+ errorCallbackList,
276
+ outputCallbackList,
274
277
  stop,
275
278
  requestActionOnChildProcess,
276
279
  }