@jsenv/core 23.2.2 → 23.4.2
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/package.json +13 -14
- package/readme.md +4 -4
- package/src/buildProject.js +12 -13
- package/src/execute.js +92 -93
- package/src/executeTestPlan.js +9 -8
- package/src/internal/browser-launcher/executeHtmlFile.js +26 -23
- 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 +21 -6
- 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/generateCoverageJsonFile.js → coverage_reporter/coverage_reporter_json_file.js} +0 -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 +65 -0
- package/src/internal/executing/coverage_utils/v8_coverage_to_istanbul.js +90 -0
- package/src/internal/executing/createSummaryLog.js +15 -15
- 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 +172 -169
- package/src/internal/node-launcher/createControllableNodeProcess.js +26 -23
- package/src/launchBrowser.js +72 -69
- package/src/launchNode.js +11 -99
- 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/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
|
@@ -1,12 +1,9 @@
|
|
|
1
|
+
import cuid from "cuid"
|
|
1
2
|
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
3
|
+
import { Abort, raceCallbacks } from "@jsenv/abort"
|
|
4
|
+
import { resolveUrl, writeFile } from "@jsenv/filesystem"
|
|
2
5
|
|
|
3
|
-
import {
|
|
4
|
-
import { raceCallbacks } from "../../abort/callback_race.js"
|
|
5
|
-
import { composeIstanbulCoverages } from "./coverage/composeIstanbulCoverages.js"
|
|
6
|
-
|
|
7
|
-
const TIMING_BEFORE_EXECUTION = "before-execution"
|
|
8
|
-
const TIMING_DURING_EXECUTION = "during-execution"
|
|
9
|
-
const TIMING_AFTER_EXECUTION = "after-execution"
|
|
6
|
+
import { composeTwoFileByFileIstanbulCoverages } from "./coverage_utils/istanbul_coverage_composition.js"
|
|
10
7
|
|
|
11
8
|
export const launchAndExecute = async ({
|
|
12
9
|
signal = new AbortController().signal,
|
|
@@ -24,6 +21,7 @@ export const launchAndExecute = async ({
|
|
|
24
21
|
collectRuntimeVersion = false,
|
|
25
22
|
inheritCoverage = false,
|
|
26
23
|
collectCoverage = false,
|
|
24
|
+
coverageTempDirectoryUrl,
|
|
27
25
|
measurePerformance,
|
|
28
26
|
collectPerformance = false,
|
|
29
27
|
|
|
@@ -32,7 +30,7 @@ export const launchAndExecute = async ({
|
|
|
32
30
|
// however unit test will pass true because they want to move on
|
|
33
31
|
stopAfterExecute = false,
|
|
34
32
|
stopAfterExecuteReason = "stop after execute",
|
|
35
|
-
// when launch returns {
|
|
33
|
+
// when launch returns { stoppedCallbackList, gracefulStop, stop }
|
|
36
34
|
// the launched runtime have that amount of ms for disconnected to resolve
|
|
37
35
|
// before we call stop
|
|
38
36
|
gracefulStopAllocatedMs = 4000,
|
|
@@ -44,8 +42,6 @@ export const launchAndExecute = async ({
|
|
|
44
42
|
// by default throw on error after execution
|
|
45
43
|
throw error
|
|
46
44
|
},
|
|
47
|
-
|
|
48
|
-
coverageV8MergeConflictIsExpected,
|
|
49
45
|
} = {}) => {
|
|
50
46
|
const logger = createLogger({ logLevel: launchAndExecuteLogLevel })
|
|
51
47
|
|
|
@@ -60,27 +56,20 @@ export const launchAndExecute = async ({
|
|
|
60
56
|
|
|
61
57
|
let executionResultTransformer = (executionResult) => executionResult
|
|
62
58
|
|
|
63
|
-
const launchAndExecuteOperation =
|
|
59
|
+
const launchAndExecuteOperation = Abort.startOperation()
|
|
60
|
+
launchAndExecuteOperation.addAbortSignal(signal)
|
|
64
61
|
|
|
65
62
|
const hasAllocatedMs =
|
|
66
63
|
typeof allocatedMs === "number" && allocatedMs !== Infinity
|
|
67
|
-
let
|
|
64
|
+
let timeoutAbortSource
|
|
68
65
|
|
|
69
66
|
if (hasAllocatedMs) {
|
|
70
|
-
|
|
71
|
-
launchAndExecuteOperation,
|
|
67
|
+
timeoutAbortSource = launchAndExecuteOperation.timeout(
|
|
72
68
|
// FIXME: if allocatedMs is veryyyyyy big
|
|
73
69
|
// setTimeout may be called immediatly
|
|
74
70
|
// in that case we should just throw that the number is too big
|
|
75
71
|
allocatedMs,
|
|
76
72
|
)
|
|
77
|
-
executionResultTransformer = composeTransformer(
|
|
78
|
-
executionResultTransformer,
|
|
79
|
-
(executionResult) => {
|
|
80
|
-
timeoutAbortEffect.cleanup()
|
|
81
|
-
return executionResult
|
|
82
|
-
},
|
|
83
|
-
)
|
|
84
73
|
}
|
|
85
74
|
|
|
86
75
|
if (mirrorConsole) {
|
|
@@ -143,40 +132,61 @@ export const launchAndExecute = async ({
|
|
|
143
132
|
executionResultTransformer = composeTransformer(
|
|
144
133
|
executionResultTransformer,
|
|
145
134
|
(executionResult) => {
|
|
146
|
-
const { coverage
|
|
147
|
-
//
|
|
148
|
-
global.__coverage__ =
|
|
135
|
+
const { coverage } = executionResult
|
|
136
|
+
// propagate coverage from execution to this process
|
|
137
|
+
global.__coverage__ = composeTwoFileByFileIstanbulCoverages(
|
|
149
138
|
global.__coverage__ || {},
|
|
150
139
|
coverage || {},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
if (!collectCoverageSaved) {
|
|
143
|
+
delete executionResult.coverage
|
|
154
144
|
}
|
|
155
|
-
|
|
145
|
+
|
|
146
|
+
return executionResult
|
|
156
147
|
},
|
|
157
148
|
)
|
|
158
149
|
}
|
|
159
150
|
|
|
160
|
-
// indirectCoverage is a feature making possible to collect
|
|
161
|
-
// coverage generated by executing a node process which executes
|
|
162
|
-
// a browser. The coverage coming the browser executionwould be lost
|
|
163
|
-
// if not propagated somehow.
|
|
164
|
-
// This is possible if the node process collect the browser coverage
|
|
165
|
-
// and write it into global.__indirectCoverage__
|
|
166
|
-
// This is used by jsenv during tests execution
|
|
167
151
|
if (collectCoverage) {
|
|
168
152
|
executionResultTransformer = composeTransformer(
|
|
169
153
|
executionResultTransformer,
|
|
170
|
-
(executionResult) => {
|
|
171
|
-
|
|
154
|
+
async (executionResult) => {
|
|
155
|
+
// we do not keep coverage in memory, it can grow very big
|
|
156
|
+
// instead we store it on the filesystem, they will be read and merged together later on
|
|
157
|
+
// in "executeConcurrently"
|
|
158
|
+
const { coverage } = executionResult
|
|
159
|
+
if (coverage) {
|
|
160
|
+
const coverageFileUrl = resolveUrl(
|
|
161
|
+
`./${runtime.name}/${cuid()}`,
|
|
162
|
+
coverageTempDirectoryUrl,
|
|
163
|
+
)
|
|
164
|
+
await writeFile(coverageFileUrl, JSON.stringify(coverage, null, " "))
|
|
165
|
+
executionResult.coverageFileUrl = coverageFileUrl
|
|
166
|
+
delete executionResult.coverage
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// indirectCoverage is a feature making possible to collect
|
|
170
|
+
// coverage generated by executing a node process which executes
|
|
171
|
+
// a browser. The coverage coming the browser execution would be lost
|
|
172
|
+
// if not propagated somehow.
|
|
173
|
+
// This is possible if the node process collect the browser coverage
|
|
174
|
+
// and write it into global.__indirectCoverage__
|
|
175
|
+
// This is used by jsenv during tests execution
|
|
176
|
+
const { indirectCoverage } = executionResult
|
|
172
177
|
if (indirectCoverage) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
const indirectCoverageFileUrl = resolveUrl(
|
|
179
|
+
`./${runtime.name}/${cuid()}`,
|
|
180
|
+
coverageTempDirectoryUrl,
|
|
181
|
+
)
|
|
182
|
+
await writeFile(
|
|
183
|
+
indirectCoverageFileUrl,
|
|
184
|
+
JSON.stringify(indirectCoverage, null, " "),
|
|
178
185
|
)
|
|
186
|
+
executionResult.indirectCoverageFileUrl = indirectCoverageFileUrl
|
|
187
|
+
delete executionResult.indirectCoverage
|
|
179
188
|
}
|
|
189
|
+
|
|
180
190
|
return executionResult
|
|
181
191
|
},
|
|
182
192
|
)
|
|
@@ -188,31 +198,12 @@ export const launchAndExecute = async ({
|
|
|
188
198
|
// executionResult.coverage is undefined or {}
|
|
189
199
|
// we delete it just to have a cleaner object
|
|
190
200
|
delete executionResult.coverage
|
|
201
|
+
delete executionResult.indirectCoverage
|
|
191
202
|
return executionResult
|
|
192
203
|
},
|
|
193
204
|
)
|
|
194
205
|
}
|
|
195
206
|
|
|
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
207
|
if (measureDuration) {
|
|
217
208
|
const startMs = Date.now()
|
|
218
209
|
executionResultTransformer = composeTransformer(
|
|
@@ -230,7 +221,7 @@ export const launchAndExecute = async ({
|
|
|
230
221
|
const runtimeLabel = `${runtime.name}/${runtime.version}`
|
|
231
222
|
logger.debug(`launch ${runtimeLabel} to execute something in it`)
|
|
232
223
|
|
|
233
|
-
|
|
224
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
234
225
|
const launchReturnValue = await runtime.launch({
|
|
235
226
|
signal: launchAndExecuteOperation.signal,
|
|
236
227
|
logger,
|
|
@@ -240,14 +231,19 @@ export const launchAndExecute = async ({
|
|
|
240
231
|
...runtimeParams,
|
|
241
232
|
})
|
|
242
233
|
validateLaunchReturnValue(launchReturnValue)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
234
|
+
|
|
235
|
+
const stopRuntime = async (reason) => {
|
|
236
|
+
const { stop } = launchReturnValue
|
|
237
|
+
logger.debug(`${runtimeLabel}: stop() because ${reason}`)
|
|
238
|
+
const { graceful } = await stop({ reason, gracefulStopAllocatedMs })
|
|
239
|
+
if (graceful) {
|
|
240
|
+
logger.debug(`${runtimeLabel}: runtime stopped gracefully`)
|
|
241
|
+
} else {
|
|
242
|
+
logger.debug(`${runtimeLabel}: runtime stopped`)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
launchAndExecuteOperation.addAbortCallback(async () => {
|
|
246
|
+
await stopRuntime("Operation aborted")
|
|
251
247
|
})
|
|
252
248
|
|
|
253
249
|
logger.debug(createDetailedMessage(`${runtimeLabel}: runtime launched`))
|
|
@@ -255,9 +251,9 @@ export const launchAndExecute = async ({
|
|
|
255
251
|
|
|
256
252
|
logger.debug(`${runtimeLabel}: start execution`)
|
|
257
253
|
const {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
254
|
+
errorCallbackList,
|
|
255
|
+
outputCallbackList,
|
|
256
|
+
stoppedCallbackList,
|
|
261
257
|
execute,
|
|
262
258
|
finalizeExecutionResult = (executionResult) => executionResult,
|
|
263
259
|
} = launchReturnValue
|
|
@@ -265,104 +261,60 @@ export const launchAndExecute = async ({
|
|
|
265
261
|
executionResultTransformer,
|
|
266
262
|
finalizeExecutionResult,
|
|
267
263
|
)
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
let timing = TIMING_BEFORE_EXECUTION
|
|
271
|
-
stoppedSignal.addCallback(() => {
|
|
272
|
-
logger.debug(`${runtimeLabel}: runtime stopped ${timing}`)
|
|
273
|
-
runtimeStoppedCallback()
|
|
274
|
-
})
|
|
264
|
+
outputCallbackList.add(runtimeConsoleCallback)
|
|
275
265
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
)
|
|
266
|
+
let executionResult = await callExecute({
|
|
267
|
+
launchAndExecuteOperation,
|
|
268
|
+
errorCallbackList,
|
|
269
|
+
stoppedCallbackList,
|
|
270
|
+
execute,
|
|
271
|
+
executeParams,
|
|
302
272
|
})
|
|
303
273
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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) {
|
|
274
|
+
if (stopAfterExecute) {
|
|
275
|
+
// stopping runtime is part of the execution
|
|
276
|
+
try {
|
|
277
|
+
await stopRuntime(stopAfterExecuteReason)
|
|
278
|
+
} catch (e) {
|
|
279
|
+
executionResult = createErroredExecutionResult({
|
|
280
|
+
error: e,
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
331
284
|
// when the process is still alive
|
|
332
285
|
// we want to catch error to notify runtimeErrorAfterExecutionCallback
|
|
333
286
|
// and throw that error by default
|
|
334
|
-
|
|
287
|
+
errorCallbackList.add((error) => {
|
|
335
288
|
runtimeErrorAfterExecutionCallback(error)
|
|
336
289
|
})
|
|
290
|
+
stoppedCallbackList.add(() => {
|
|
291
|
+
logger.debug(`${runtimeLabel}: runtime stopped after execution`)
|
|
292
|
+
runtimeStoppedCallback()
|
|
293
|
+
})
|
|
337
294
|
}
|
|
338
295
|
|
|
339
|
-
|
|
340
|
-
const { status } = executeResult
|
|
341
|
-
|
|
342
|
-
if (status === "errored") {
|
|
296
|
+
if (executionResult.status === "errored") {
|
|
343
297
|
// debug log level because this error happens during execution
|
|
344
298
|
// there is no need to log it.
|
|
345
299
|
// the code will know the execution errored because it receives
|
|
346
300
|
// an errored execution result
|
|
347
301
|
logger.debug(
|
|
348
|
-
createDetailedMessage(`error
|
|
349
|
-
["error stack"]:
|
|
302
|
+
createDetailedMessage(`error during execution`, {
|
|
303
|
+
["error stack"]: executionResult.error.stack,
|
|
350
304
|
["execute params"]: JSON.stringify(executeParams, null, " "),
|
|
351
305
|
["runtime"]: runtime,
|
|
352
306
|
}),
|
|
353
307
|
)
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
)
|
|
308
|
+
} else {
|
|
309
|
+
logger.debug(`${runtimeLabel}: execution ${executionResult.status}`)
|
|
357
310
|
}
|
|
358
311
|
|
|
359
|
-
|
|
360
|
-
return executionResultTransformer(
|
|
361
|
-
createCompletedExecutionResult(executeResult),
|
|
362
|
-
)
|
|
312
|
+
return executionResultTransformer(executionResult)
|
|
363
313
|
} catch (e) {
|
|
364
|
-
if (e
|
|
365
|
-
|
|
314
|
+
if (Abort.isAbortError(e)) {
|
|
315
|
+
// we should stop runtime too
|
|
316
|
+
|
|
317
|
+
if (timeoutAbortSource && timeoutAbortSource.signal.aborted) {
|
|
366
318
|
const executionResult = createTimedoutExecutionResult()
|
|
367
319
|
return executionResultTransformer(executionResult)
|
|
368
320
|
}
|
|
@@ -370,24 +322,71 @@ export const launchAndExecute = async ({
|
|
|
370
322
|
return executionResultTransformer(executionResult)
|
|
371
323
|
}
|
|
372
324
|
throw e
|
|
325
|
+
} finally {
|
|
326
|
+
await launchAndExecuteOperation.end()
|
|
373
327
|
}
|
|
374
328
|
}
|
|
375
329
|
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
330
|
+
const callExecute = async ({
|
|
331
|
+
launchAndExecuteOperation,
|
|
332
|
+
errorCallbackList,
|
|
333
|
+
stoppedCallbackList,
|
|
334
|
+
execute,
|
|
335
|
+
executeParams,
|
|
382
336
|
}) => {
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
337
|
+
const winnerPromise = new Promise((resolve, reject) => {
|
|
338
|
+
raceCallbacks(
|
|
339
|
+
{
|
|
340
|
+
aborted: (cb) => {
|
|
341
|
+
launchAndExecuteOperation.signal.addEventListener("abort", cb)
|
|
342
|
+
return () => {
|
|
343
|
+
launchAndExecuteOperation.signal.removeEventListener("abort", cb)
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
error: (cb) => {
|
|
347
|
+
return errorCallbackList.add(cb)
|
|
348
|
+
},
|
|
349
|
+
stopped: (cb) => {
|
|
350
|
+
return stoppedCallbackList.add(cb)
|
|
351
|
+
},
|
|
352
|
+
executed: (cb) => {
|
|
353
|
+
const executed = execute({
|
|
354
|
+
signal: launchAndExecuteOperation.signal,
|
|
355
|
+
...executeParams,
|
|
356
|
+
})
|
|
357
|
+
executed.then(cb, reject)
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
resolve,
|
|
361
|
+
)
|
|
362
|
+
})
|
|
363
|
+
|
|
364
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
365
|
+
const winner = await winnerPromise
|
|
366
|
+
|
|
367
|
+
if (winner.name === "aborted") {
|
|
368
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (winner.name === "error") {
|
|
372
|
+
return createErroredExecutionResult({
|
|
373
|
+
error: winner.data,
|
|
374
|
+
})
|
|
390
375
|
}
|
|
376
|
+
|
|
377
|
+
if (winner.name === "stopped") {
|
|
378
|
+
return createErroredExecutionResult({
|
|
379
|
+
error: new Error(`runtime stopped during execution`),
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const executeResult = winner.data
|
|
384
|
+
const { status } = executeResult
|
|
385
|
+
|
|
386
|
+
if (status === "errored") {
|
|
387
|
+
return createErroredExecutionResult(executeResult)
|
|
388
|
+
}
|
|
389
|
+
return createCompletedExecutionResult(executeResult)
|
|
391
390
|
}
|
|
392
391
|
|
|
393
392
|
const createAbortedExecutionResult = () => {
|
|
@@ -444,22 +443,26 @@ const composeTransformer = (previousTransformer, transformer) => {
|
|
|
444
443
|
|
|
445
444
|
const validateLaunchReturnValue = (launchReturnValue) => {
|
|
446
445
|
if (launchReturnValue === null) {
|
|
447
|
-
throw new Error(`launch must return an object, got null`)
|
|
446
|
+
throw new Error(`runtime.launch must return an object, got null`)
|
|
448
447
|
}
|
|
449
448
|
|
|
450
449
|
if (typeof launchReturnValue !== "object") {
|
|
451
|
-
throw new Error(
|
|
450
|
+
throw new Error(
|
|
451
|
+
`runtime.launch must return an object, got ${launchReturnValue}`,
|
|
452
|
+
)
|
|
452
453
|
}
|
|
453
454
|
|
|
454
455
|
const { execute } = launchReturnValue
|
|
455
456
|
if (typeof execute !== "function") {
|
|
456
|
-
throw new Error(
|
|
457
|
+
throw new Error(
|
|
458
|
+
`runtime.launch must return an execute function, got ${execute}`,
|
|
459
|
+
)
|
|
457
460
|
}
|
|
458
461
|
|
|
459
|
-
const {
|
|
460
|
-
if (!
|
|
462
|
+
const { stoppedCallbackList } = launchReturnValue
|
|
463
|
+
if (!stoppedCallbackList) {
|
|
461
464
|
throw new Error(
|
|
462
|
-
`launch must return a
|
|
465
|
+
`runtime.launch must return a stoppedCallbackList object, got ${stoppedCallbackList}`,
|
|
463
466
|
)
|
|
464
467
|
}
|
|
465
468
|
}
|
|
@@ -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
|
|
123
|
+
const outputCallbackList = createCallbackList()
|
|
121
124
|
const removeOutputListener = installProcessOutputListener(
|
|
122
125
|
childProcess,
|
|
123
126
|
({ type, text }) => {
|
|
124
|
-
|
|
127
|
+
outputCallbackList.notify({ type, text })
|
|
125
128
|
},
|
|
126
129
|
)
|
|
127
130
|
|
|
128
|
-
const
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
176
|
+
errorCallbackList.notify(createExitWithFailureCodeError(code))
|
|
175
177
|
}
|
|
176
|
-
|
|
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 (
|
|
186
|
+
if (stoppedCallbackList.notified) {
|
|
185
187
|
return {}
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
const createStoppedPromise = async () => {
|
|
189
|
-
if (
|
|
191
|
+
if (stoppedCallbackList.notified) {
|
|
190
192
|
return
|
|
191
193
|
}
|
|
192
|
-
await new Promise((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
|
|
230
|
+
const actionOperation = Abort.startOperation()
|
|
231
|
+
actionOperation.addAbortSignal(signal)
|
|
229
232
|
|
|
230
233
|
return new Promise(async (resolve, reject) => {
|
|
231
|
-
|
|
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
|
-
|
|
253
|
+
actionOperation.throwIfAborted()
|
|
251
254
|
await sendToProcess(childProcess, "action", {
|
|
252
255
|
actionType,
|
|
253
256
|
actionParams,
|
|
254
257
|
})
|
|
255
258
|
} catch (e) {
|
|
256
|
-
if (
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
+
stoppedCallbackList,
|
|
275
|
+
errorCallbackList,
|
|
276
|
+
outputCallbackList,
|
|
274
277
|
stop,
|
|
275
278
|
requestActionOnChildProcess,
|
|
276
279
|
}
|