@jsenv/core 23.8.2 → 23.8.7
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/dist/jsenv_browser_system.js +46 -39
- package/dist/jsenv_browser_system.js.map +14 -14
- package/dist/jsenv_compile_proxy.js.map +6 -6
- package/dist/jsenv_exploring_index.js.map +5 -5
- package/dist/jsenv_exploring_redirector.js.map +12 -12
- package/dist/jsenv_toolbar.js.map +7 -7
- package/dist/jsenv_toolbar_injector.js.map +5 -5
- package/helpers/babel/.eslintrc.cjs +24 -24
- package/helpers/babel/AsyncGenerator/AsyncGenerator.js +81 -81
- package/helpers/babel/AwaitValue/AwaitValue.js +3 -3
- package/helpers/babel/applyDecoratorDescriptor/applyDecoratorDescriptor.js +33 -33
- package/helpers/babel/arrayLikeToArray/arrayLikeToArray.js +7 -7
- package/helpers/babel/arrayWithHoles/arrayWithHoles.js +4 -4
- package/helpers/babel/arrayWithoutHoles/arrayWithoutHoles.js +6 -6
- package/helpers/babel/assertThisInitialized/assertThisInitialized.js +7 -7
- package/helpers/babel/asyncGeneratorDelegate/asyncGeneratorDelegate.js +40 -40
- package/helpers/babel/asyncIterator/asyncIterator.js +12 -12
- package/helpers/babel/asyncToGenerator/asyncToGenerator.js +34 -34
- package/helpers/babel/awaitAsyncGenerator/awaitAsyncGenerator.js +5 -5
- package/helpers/babel/classApplyDescriptorDestructureSet/classApplyDescriptorDestructureSet.js +20 -20
- package/helpers/babel/classApplyDescriptorGet/classApplyDescriptorGet.js +6 -6
- package/helpers/babel/classApplyDescriptorSet/classApplyDescriptorSet.js +13 -13
- package/helpers/babel/classCallCheck/classCallCheck.js +5 -5
- package/helpers/babel/classCheckPrivateStaticAccess/classCheckPrivateStaticAccess.js +5 -5
- package/helpers/babel/classCheckPrivateStaticFieldDescriptor/classCheckPrivateStaticFieldDescriptor.js +6 -6
- package/helpers/babel/classExtractFieldDescriptor/classExtractFieldDescriptor.js +7 -7
- package/helpers/babel/classNameTDZError/classNameTDZError.js +4 -4
- package/helpers/babel/classPrivateFieldDestructureSet/classPrivateFieldDestructureSet.js +7 -7
- package/helpers/babel/classPrivateFieldGet/classPrivateFieldGet.js +7 -7
- package/helpers/babel/classPrivateFieldLooseBase/classPrivateFieldLooseBase.js +6 -6
- package/helpers/babel/classPrivateFieldLooseKey/classPrivateFieldLooseKey.js +5 -5
- package/helpers/babel/classPrivateFieldSet/classPrivateFieldSet.js +8 -8
- package/helpers/babel/classPrivateMethodGet/classPrivateMethodGet.js +6 -6
- package/helpers/babel/classPrivateMethodSet/classPrivateMethodSet.js +3 -3
- package/helpers/babel/classStaticPrivateFieldSpecGet/classStaticPrivateFieldSpecGet.js +9 -9
- package/helpers/babel/classStaticPrivateFieldSpecSet/classStaticPrivateFieldSpecSet.js +15 -15
- package/helpers/babel/classStaticPrivateMethodGet/classStaticPrivateMethodGet.js +6 -6
- package/helpers/babel/classStaticPrivateMethodSet/classStaticPrivateMethodSet.js +3 -3
- package/helpers/babel/construct/construct.js +16 -16
- package/helpers/babel/createClass/createClass.js +15 -15
- package/helpers/babel/createForOfIteratorHelper/createForOfIteratorHelper.js +60 -60
- package/helpers/babel/createForOfIteratorHelperLoose/createForOfIteratorHelperLoose.js +23 -23
- package/helpers/babel/createRawReactElement/createRawReactElement.js +50 -50
- package/helpers/babel/createSuper/createSuper.js +22 -22
- package/helpers/babel/decorate/decorate.js +403 -403
- package/helpers/babel/defaults/defaults.js +11 -11
- package/helpers/babel/defineEnumerableProperties/defineEnumerableProperties.js +23 -23
- package/helpers/babel/defineProperty/defineProperty.js +18 -18
- package/helpers/babel/extends/extends.js +14 -14
- package/helpers/babel/get/get.js +13 -13
- package/helpers/babel/getPrototypeOf/getPrototypeOf.js +4 -4
- package/helpers/babel/inherits/inherits.js +15 -15
- package/helpers/babel/inheritsLoose/inheritsLoose.js +7 -7
- package/helpers/babel/initializerDefineProperty/initializerDefineProperty.js +10 -10
- package/helpers/babel/initializerWarningHelper/initializerWarningHelper.js +6 -6
- package/helpers/babel/instanceof/instanceof.js +6 -6
- package/helpers/babel/interopRequireDefault/interopRequireDefault.js +3 -3
- package/helpers/babel/interopRequireWildcard/interopRequireWildcard.js +37 -37
- package/helpers/babel/isNativeFunction/isNativeFunction.js +4 -4
- package/helpers/babel/isNativeReflectConstruct/isNativeReflectConstruct.js +21 -21
- package/helpers/babel/iterableToArray/iterableToArray.js +7 -7
- package/helpers/babel/iterableToArrayLimit/iterableToArrayLimit.js +36 -36
- package/helpers/babel/iterableToArrayLimitLoose/iterableToArrayLimitLoose.js +10 -10
- package/helpers/babel/jsx/jsx.js +45 -45
- package/helpers/babel/maybeArrayLike/maybeArrayLike.js +10 -10
- package/helpers/babel/newArrowCheck/newArrowCheck.js +5 -5
- package/helpers/babel/nonIterableRest/nonIterableRest.js +5 -5
- package/helpers/babel/nonIterableSpread/nonIterableSpread.js +5 -5
- package/helpers/babel/objectDestructuringEmpty/objectDestructuringEmpty.js +3 -3
- package/helpers/babel/objectSpread/objectSpread.js +23 -23
- package/helpers/babel/objectSpread2/objectSpread2.js +33 -33
- package/helpers/babel/objectWithoutProperties/objectWithoutProperties.js +19 -19
- package/helpers/babel/objectWithoutPropertiesLoose/objectWithoutPropertiesLoose.js +13 -13
- package/helpers/babel/possibleConstructorReturn/possibleConstructorReturn.js +10 -10
- package/helpers/babel/readOnlyError/readOnlyError.js +4 -4
- package/helpers/babel/readme.md +9 -9
- package/helpers/babel/set/set.js +44 -44
- package/helpers/babel/setPrototypeOf/setPrototypeOf.js +6 -6
- package/helpers/babel/skipFirstGeneratorNext/skipFirstGeneratorNext.js +8 -8
- package/helpers/babel/slicedToArray/slicedToArray.js +10 -10
- package/helpers/babel/slicedToArrayLoose/slicedToArrayLoose.js +13 -13
- package/helpers/babel/superPropBase/superPropBase.js +10 -10
- package/helpers/babel/taggedTemplateLiteral/taggedTemplateLiteral.js +10 -10
- package/helpers/babel/taggedTemplateLiteralLoose/taggedTemplateLiteralLoose.js +7 -7
- package/helpers/babel/tdz/tdz.js +4 -4
- package/helpers/babel/temporalRef/temporalRef.js +6 -6
- package/helpers/babel/temporalUndefined/temporalUndefined.js +3 -3
- package/helpers/babel/toArray/toArray.js +10 -10
- package/helpers/babel/toConsumableArray/toConsumableArray.js +10 -10
- package/helpers/babel/toPrimitive/toPrimitive.js +10 -10
- package/helpers/babel/toPropertyKey/toPropertyKey.js +6 -6
- package/helpers/babel/typeof/typeof.js +14 -14
- package/helpers/babel/unsupportedIterableToArray/unsupportedIterableToArray.js +12 -12
- package/helpers/babel/wrapAsyncGenerator/wrapAsyncGenerator.js +8 -8
- package/helpers/babel/wrapNativeSuper/wrapNativeSuper.js +30 -30
- package/helpers/babel/wrapRegExp/wrapRegExp.js +63 -63
- package/helpers/babel/writeOnlyError/writeOnlyError.js +4 -4
- package/helpers/regenerator-runtime/regenerator-runtime.js +748 -748
- package/{LICENSE → license} +21 -21
- package/package.json +2 -2
- package/src/buildProject.js +300 -300
- package/src/execute.js +184 -184
- package/src/internal/browser-launcher/jsenv-browser-system.js +203 -199
- package/src/internal/building/buildUsingRollup.js +2 -10
- package/src/internal/compiling/babel_plugin_import_assertions.js +121 -121
- package/src/internal/compiling/babel_plugin_import_metadata.js +22 -22
- package/src/internal/compiling/babel_plugin_import_visitor.js +84 -84
- package/src/internal/compiling/compile-directory/getOrGenerateCompiledFile.js +268 -268
- package/src/internal/compiling/compile-directory/updateMeta.js +154 -154
- package/src/internal/compiling/compile-directory/validateCache.js +265 -265
- package/src/internal/compiling/compileFile.js +233 -224
- package/src/internal/compiling/compileHtml.js +550 -550
- package/src/internal/compiling/createCompiledFileService.js +291 -291
- package/src/internal/compiling/html_source_file_service.js +403 -404
- package/src/internal/compiling/js-compilation-service/jsenvTransform.js +272 -270
- package/src/internal/compiling/jsenvCompilerForHtml.js +374 -308
- package/src/internal/compiling/jsenvCompilerForJavaScript.js +2 -0
- package/src/internal/compiling/startCompileServer.js +1086 -1048
- package/src/internal/compiling/transformResultToCompilationResult.js +220 -220
- package/src/internal/executing/coverage/babel_plugin_instrument.js +90 -90
- package/src/internal/executing/coverage/reportToCoverage.js +193 -187
- package/src/internal/executing/executePlan.js +183 -183
- package/src/internal/executing/launchAndExecute.js +458 -458
- package/src/internal/generateGroupMap/featuresCompatMap.js +29 -0
- package/src/internal/generateGroupMap/jsenvBabelPluginCompatMap.js +1 -8
- package/src/internal/runtime/createBrowserRuntime/scanBrowserRuntimeFeatures.js +246 -246
- package/src/internal/runtime/createNodeRuntime/scanNodeRuntimeFeatures.js +112 -112
- package/src/internal/runtime/s.js +727 -727
- package/src/internal/toolbar/jsenv-logo.svg +144 -144
- package/src/internal/toolbar/toolbar.main.css +196 -196
- package/src/internal/toolbar/toolbar.main.js +227 -227
- package/src/internal/url_conversion.js +317 -317
- package/src/startExploring.js +309 -309
|
@@ -1,458 +1,458 @@
|
|
|
1
|
-
import cuid from "cuid"
|
|
2
|
-
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
3
|
-
import { Abort, raceCallbacks } from "@jsenv/abort"
|
|
4
|
-
import { resolveUrl, writeFile } from "@jsenv/filesystem"
|
|
5
|
-
|
|
6
|
-
import { composeTwoFileByFileIstanbulCoverages } from "./coverage_utils/istanbul_coverage_composition.js"
|
|
7
|
-
|
|
8
|
-
export const launchAndExecute = async ({
|
|
9
|
-
signal = new AbortController().signal,
|
|
10
|
-
launchAndExecuteLogLevel,
|
|
11
|
-
|
|
12
|
-
runtime,
|
|
13
|
-
runtimeParams,
|
|
14
|
-
executeParams,
|
|
15
|
-
|
|
16
|
-
allocatedMs,
|
|
17
|
-
mirrorConsole = false,
|
|
18
|
-
captureConsole = false, // rename collectConsole ?
|
|
19
|
-
inheritCoverage = false,
|
|
20
|
-
collectCoverage = false,
|
|
21
|
-
coverageTempDirectoryUrl,
|
|
22
|
-
measurePerformance,
|
|
23
|
-
collectPerformance = false,
|
|
24
|
-
|
|
25
|
-
// stopAfterExecute false by default because you want to keep browser alive
|
|
26
|
-
// or nodejs process
|
|
27
|
-
// however unit test will pass true because they want to move on
|
|
28
|
-
stopAfterExecute = false,
|
|
29
|
-
stopAfterExecuteReason = "stop after execute",
|
|
30
|
-
// when launch returns { stoppedCallbackList, gracefulStop, stop }
|
|
31
|
-
// the launched runtime have that amount of ms for disconnected to resolve
|
|
32
|
-
// before we call stop
|
|
33
|
-
gracefulStopAllocatedMs = 4000,
|
|
34
|
-
|
|
35
|
-
runtimeConsoleCallback = () => {},
|
|
36
|
-
runtimeStartedCallback = () => {},
|
|
37
|
-
runtimeStoppedCallback = () => {},
|
|
38
|
-
runtimeErrorAfterExecutionCallback = (error) => {
|
|
39
|
-
// by default throw on error after execution
|
|
40
|
-
throw error
|
|
41
|
-
},
|
|
42
|
-
} = {}) => {
|
|
43
|
-
const logger = createLogger({ logLevel: launchAndExecuteLogLevel })
|
|
44
|
-
|
|
45
|
-
if (typeof runtime !== "object") {
|
|
46
|
-
throw new TypeError(`runtime must be an object, got ${runtime}`)
|
|
47
|
-
}
|
|
48
|
-
if (typeof runtime.launch !== "function") {
|
|
49
|
-
throw new TypeError(
|
|
50
|
-
`runtime.launch must be a function, got ${runtime.launch}`,
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let executionResultTransformer = (executionResult) => executionResult
|
|
55
|
-
|
|
56
|
-
const launchAndExecuteOperation = Abort.startOperation()
|
|
57
|
-
launchAndExecuteOperation.addAbortSignal(signal)
|
|
58
|
-
|
|
59
|
-
const hasAllocatedMs =
|
|
60
|
-
typeof allocatedMs === "number" && allocatedMs !== Infinity
|
|
61
|
-
let timeoutAbortSource
|
|
62
|
-
|
|
63
|
-
if (hasAllocatedMs) {
|
|
64
|
-
timeoutAbortSource = launchAndExecuteOperation.timeout(
|
|
65
|
-
// FIXME: if allocatedMs is veryyyyyy big
|
|
66
|
-
// setTimeout may be called immediatly
|
|
67
|
-
// in that case we should just throw that the number is too big
|
|
68
|
-
allocatedMs,
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (mirrorConsole) {
|
|
73
|
-
runtimeConsoleCallback = composeCallback(
|
|
74
|
-
runtimeConsoleCallback,
|
|
75
|
-
({ type, text }) => {
|
|
76
|
-
if (type === "error") {
|
|
77
|
-
process.stderr.write(text)
|
|
78
|
-
} else {
|
|
79
|
-
process.stdout.write(text)
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (captureConsole) {
|
|
86
|
-
const consoleCalls = []
|
|
87
|
-
runtimeConsoleCallback = composeCallback(
|
|
88
|
-
runtimeConsoleCallback,
|
|
89
|
-
({ type, text }) => {
|
|
90
|
-
consoleCalls.push({ type, text })
|
|
91
|
-
},
|
|
92
|
-
)
|
|
93
|
-
executionResultTransformer = composeTransformer(
|
|
94
|
-
executionResultTransformer,
|
|
95
|
-
(executionResult) => {
|
|
96
|
-
executionResult.consoleCalls = consoleCalls
|
|
97
|
-
return executionResult
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
executionResultTransformer = composeTransformer(
|
|
103
|
-
executionResultTransformer,
|
|
104
|
-
(executionResult) => {
|
|
105
|
-
executionResult.runtimeName = runtime.name
|
|
106
|
-
executionResult.runtimeVersion = runtime.version
|
|
107
|
-
return executionResult
|
|
108
|
-
},
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
inheritCoverage &&
|
|
113
|
-
// NODE_V8_COVERAGE is doing the coverage propagation for us
|
|
114
|
-
!process.env.NODE_V8_COVERAGE
|
|
115
|
-
) {
|
|
116
|
-
const collectCoverageSaved = collectCoverage
|
|
117
|
-
collectCoverage = true
|
|
118
|
-
executionResultTransformer = composeTransformer(
|
|
119
|
-
executionResultTransformer,
|
|
120
|
-
(executionResult) => {
|
|
121
|
-
const { coverage } = executionResult
|
|
122
|
-
// propagate coverage from execution to this process
|
|
123
|
-
global.__coverage__ = composeTwoFileByFileIstanbulCoverages(
|
|
124
|
-
global.__coverage__ || {},
|
|
125
|
-
coverage || {},
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
if (!collectCoverageSaved) {
|
|
129
|
-
delete executionResult.coverage
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return executionResult
|
|
133
|
-
},
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (collectCoverage) {
|
|
138
|
-
executionResultTransformer = composeTransformer(
|
|
139
|
-
executionResultTransformer,
|
|
140
|
-
async (executionResult) => {
|
|
141
|
-
// we do not keep coverage in memory, it can grow very big
|
|
142
|
-
// instead we store it on the filesystem, they will be read and merged together later on
|
|
143
|
-
// in "executeConcurrently"
|
|
144
|
-
const { coverage } = executionResult
|
|
145
|
-
if (coverage) {
|
|
146
|
-
const coverageFileUrl = resolveUrl(
|
|
147
|
-
`./${runtime.name}/${cuid()}`,
|
|
148
|
-
coverageTempDirectoryUrl,
|
|
149
|
-
)
|
|
150
|
-
await writeFile(coverageFileUrl, JSON.stringify(coverage, null, " "))
|
|
151
|
-
executionResult.coverageFileUrl = coverageFileUrl
|
|
152
|
-
delete executionResult.coverage
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// indirectCoverage is a feature making possible to collect
|
|
156
|
-
// coverage generated by executing a node process which executes
|
|
157
|
-
// a browser. The coverage coming the browser execution would be lost
|
|
158
|
-
// if not propagated somehow.
|
|
159
|
-
// This is possible if the node process collect the browser coverage
|
|
160
|
-
// and write it into global.__indirectCoverage__
|
|
161
|
-
// This is used by jsenv during tests execution
|
|
162
|
-
const { indirectCoverage } = executionResult
|
|
163
|
-
if (indirectCoverage) {
|
|
164
|
-
const indirectCoverageFileUrl = resolveUrl(
|
|
165
|
-
`./${runtime.name}/${cuid()}`,
|
|
166
|
-
coverageTempDirectoryUrl,
|
|
167
|
-
)
|
|
168
|
-
await writeFile(
|
|
169
|
-
indirectCoverageFileUrl,
|
|
170
|
-
JSON.stringify(indirectCoverage, null, " "),
|
|
171
|
-
)
|
|
172
|
-
executionResult.indirectCoverageFileUrl = indirectCoverageFileUrl
|
|
173
|
-
delete executionResult.indirectCoverage
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return executionResult
|
|
177
|
-
},
|
|
178
|
-
)
|
|
179
|
-
} else {
|
|
180
|
-
executionResultTransformer = composeTransformer(
|
|
181
|
-
executionResultTransformer,
|
|
182
|
-
(executionResult) => {
|
|
183
|
-
// as collectCoverage is disabled
|
|
184
|
-
// executionResult.coverage is undefined or {}
|
|
185
|
-
// we delete it just to have a cleaner object
|
|
186
|
-
delete executionResult.coverage
|
|
187
|
-
delete executionResult.indirectCoverage
|
|
188
|
-
return executionResult
|
|
189
|
-
},
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const startMs = Date.now()
|
|
194
|
-
executionResultTransformer = composeTransformer(
|
|
195
|
-
executionResultTransformer,
|
|
196
|
-
(executionResult) => {
|
|
197
|
-
executionResult.duration = Date.now() - startMs
|
|
198
|
-
return executionResult
|
|
199
|
-
},
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
const runtimeLabel = `${runtime.name}/${runtime.version}`
|
|
204
|
-
logger.debug(`launch ${runtimeLabel} to execute something in it`)
|
|
205
|
-
|
|
206
|
-
launchAndExecuteOperation.throwIfAborted()
|
|
207
|
-
const launchReturnValue = await runtime.launch({
|
|
208
|
-
signal: launchAndExecuteOperation.signal,
|
|
209
|
-
logger,
|
|
210
|
-
stopAfterExecute,
|
|
211
|
-
measurePerformance,
|
|
212
|
-
collectPerformance,
|
|
213
|
-
...runtimeParams,
|
|
214
|
-
})
|
|
215
|
-
validateLaunchReturnValue(launchReturnValue)
|
|
216
|
-
|
|
217
|
-
const stopRuntime = async (reason) => {
|
|
218
|
-
const { stop } = launchReturnValue
|
|
219
|
-
logger.debug(`${runtimeLabel}: stop() because ${reason}`)
|
|
220
|
-
const { graceful } = await stop({ reason, gracefulStopAllocatedMs })
|
|
221
|
-
if (graceful) {
|
|
222
|
-
logger.debug(`${runtimeLabel}: runtime stopped gracefully`)
|
|
223
|
-
} else {
|
|
224
|
-
logger.debug(`${runtimeLabel}: runtime stopped`)
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
launchAndExecuteOperation.addAbortCallback(async () => {
|
|
228
|
-
await stopRuntime("Operation aborted")
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
logger.debug(createDetailedMessage(`${runtimeLabel}: runtime launched`))
|
|
232
|
-
runtimeStartedCallback()
|
|
233
|
-
|
|
234
|
-
logger.debug(`${runtimeLabel}: start execution`)
|
|
235
|
-
const {
|
|
236
|
-
errorCallbackList,
|
|
237
|
-
outputCallbackList,
|
|
238
|
-
stoppedCallbackList,
|
|
239
|
-
execute,
|
|
240
|
-
finalizeExecutionResult = (executionResult) => executionResult,
|
|
241
|
-
} = launchReturnValue
|
|
242
|
-
executionResultTransformer = composeTransformer(
|
|
243
|
-
executionResultTransformer,
|
|
244
|
-
finalizeExecutionResult,
|
|
245
|
-
)
|
|
246
|
-
outputCallbackList.add(runtimeConsoleCallback)
|
|
247
|
-
|
|
248
|
-
let executionResult = await callExecute({
|
|
249
|
-
launchAndExecuteOperation,
|
|
250
|
-
errorCallbackList,
|
|
251
|
-
stoppedCallbackList,
|
|
252
|
-
execute,
|
|
253
|
-
executeParams,
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
if (stopAfterExecute) {
|
|
257
|
-
// stopping runtime is part of the execution
|
|
258
|
-
try {
|
|
259
|
-
await stopRuntime(stopAfterExecuteReason)
|
|
260
|
-
} catch (e) {
|
|
261
|
-
executionResult = createErroredExecutionResult({
|
|
262
|
-
error: e,
|
|
263
|
-
})
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
// when the process is still alive
|
|
267
|
-
// we want to catch error to notify runtimeErrorAfterExecutionCallback
|
|
268
|
-
// and throw that error by default
|
|
269
|
-
errorCallbackList.add((error) => {
|
|
270
|
-
runtimeErrorAfterExecutionCallback(error)
|
|
271
|
-
})
|
|
272
|
-
stoppedCallbackList.add(() => {
|
|
273
|
-
logger.debug(`${runtimeLabel}: runtime stopped after execution`)
|
|
274
|
-
runtimeStoppedCallback()
|
|
275
|
-
})
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (executionResult.status === "errored") {
|
|
279
|
-
// debug log level because this error happens during execution
|
|
280
|
-
// there is no need to log it.
|
|
281
|
-
// the code will know the execution errored because it receives
|
|
282
|
-
// an errored execution result
|
|
283
|
-
logger.debug(
|
|
284
|
-
createDetailedMessage(`error during execution`, {
|
|
285
|
-
["error stack"]: executionResult.error.stack,
|
|
286
|
-
["execute params"]: JSON.stringify(executeParams, null, " "),
|
|
287
|
-
["runtime"]: runtime,
|
|
288
|
-
}),
|
|
289
|
-
)
|
|
290
|
-
} else {
|
|
291
|
-
logger.debug(`${runtimeLabel}: execution ${executionResult.status}`)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return executionResultTransformer(executionResult)
|
|
295
|
-
} catch (e) {
|
|
296
|
-
if (Abort.isAbortError(e)) {
|
|
297
|
-
if (timeoutAbortSource && timeoutAbortSource.signal.aborted) {
|
|
298
|
-
const executionResult = createTimedoutExecutionResult()
|
|
299
|
-
return executionResultTransformer(executionResult)
|
|
300
|
-
}
|
|
301
|
-
const executionResult = createAbortedExecutionResult()
|
|
302
|
-
return executionResultTransformer(executionResult)
|
|
303
|
-
}
|
|
304
|
-
throw e
|
|
305
|
-
} finally {
|
|
306
|
-
await launchAndExecuteOperation.end()
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const callExecute = async ({
|
|
311
|
-
launchAndExecuteOperation,
|
|
312
|
-
errorCallbackList,
|
|
313
|
-
stoppedCallbackList,
|
|
314
|
-
execute,
|
|
315
|
-
executeParams,
|
|
316
|
-
}) => {
|
|
317
|
-
const winnerPromise = new Promise((resolve, reject) => {
|
|
318
|
-
raceCallbacks(
|
|
319
|
-
{
|
|
320
|
-
aborted: (cb) => {
|
|
321
|
-
launchAndExecuteOperation.signal.addEventListener("abort", cb)
|
|
322
|
-
return () => {
|
|
323
|
-
launchAndExecuteOperation.signal.removeEventListener("abort", cb)
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
error: (cb) => {
|
|
327
|
-
return errorCallbackList.add(cb)
|
|
328
|
-
},
|
|
329
|
-
stopped: (cb) => {
|
|
330
|
-
return stoppedCallbackList.add(cb)
|
|
331
|
-
},
|
|
332
|
-
executed: async (cb) => {
|
|
333
|
-
try {
|
|
334
|
-
const executionResult = await execute({
|
|
335
|
-
signal: launchAndExecuteOperation.signal,
|
|
336
|
-
...executeParams,
|
|
337
|
-
})
|
|
338
|
-
cb(executionResult)
|
|
339
|
-
} catch (e) {
|
|
340
|
-
if (Abort.isAbortError(e)) {
|
|
341
|
-
cb(e)
|
|
342
|
-
return
|
|
343
|
-
}
|
|
344
|
-
reject(e)
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
},
|
|
348
|
-
resolve,
|
|
349
|
-
)
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
launchAndExecuteOperation.throwIfAborted()
|
|
353
|
-
const winner = await winnerPromise
|
|
354
|
-
|
|
355
|
-
if (winner.name === "aborted") {
|
|
356
|
-
launchAndExecuteOperation.throwIfAborted()
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (winner.name === "error") {
|
|
360
|
-
return createErroredExecutionResult({
|
|
361
|
-
error: winner.data,
|
|
362
|
-
})
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (winner.name === "stopped") {
|
|
366
|
-
return createErroredExecutionResult({
|
|
367
|
-
error: new Error(`runtime stopped during execution`),
|
|
368
|
-
})
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const executeResult = winner.data
|
|
372
|
-
if (Abort.isAbortError(executeResult)) {
|
|
373
|
-
throw executeResult
|
|
374
|
-
}
|
|
375
|
-
const { status } = executeResult
|
|
376
|
-
if (status === "errored") {
|
|
377
|
-
return createErroredExecutionResult(executeResult)
|
|
378
|
-
}
|
|
379
|
-
return createCompletedExecutionResult(executeResult)
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const createAbortedExecutionResult = () => {
|
|
383
|
-
return {
|
|
384
|
-
status: "aborted",
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const createTimedoutExecutionResult = () => {
|
|
389
|
-
return {
|
|
390
|
-
status: "timedout",
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const createErroredExecutionResult = (executionResult) => {
|
|
395
|
-
return {
|
|
396
|
-
...executionResult,
|
|
397
|
-
status: "errored",
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const createCompletedExecutionResult = (executionResult) => {
|
|
402
|
-
return {
|
|
403
|
-
...executionResult,
|
|
404
|
-
status: "completed",
|
|
405
|
-
namespace: normalizeNamespace(executionResult.namespace),
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const normalizeNamespace = (namespace) => {
|
|
410
|
-
if (typeof namespace !== "object") return namespace
|
|
411
|
-
if (namespace instanceof Promise) return namespace
|
|
412
|
-
const normalized = {}
|
|
413
|
-
// remove "__esModule" or Symbol.toStringTag from namespace object
|
|
414
|
-
Object.keys(namespace).forEach((key) => {
|
|
415
|
-
normalized[key] = namespace[key]
|
|
416
|
-
})
|
|
417
|
-
return normalized
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const composeCallback = (previousCallback, callback) => {
|
|
421
|
-
return (...args) => {
|
|
422
|
-
previousCallback(...args)
|
|
423
|
-
return callback(...args)
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const composeTransformer = (previousTransformer, transformer) => {
|
|
428
|
-
return async (value) => {
|
|
429
|
-
const transformedValue = await previousTransformer(value)
|
|
430
|
-
return transformer(transformedValue)
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const validateLaunchReturnValue = (launchReturnValue) => {
|
|
435
|
-
if (launchReturnValue === null) {
|
|
436
|
-
throw new Error(`runtime.launch must return an object, got null`)
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (typeof launchReturnValue !== "object") {
|
|
440
|
-
throw new Error(
|
|
441
|
-
`runtime.launch must return an object, got ${launchReturnValue}`,
|
|
442
|
-
)
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const { execute } = launchReturnValue
|
|
446
|
-
if (typeof execute !== "function") {
|
|
447
|
-
throw new Error(
|
|
448
|
-
`runtime.launch must return an execute function, got ${execute}`,
|
|
449
|
-
)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
const { stoppedCallbackList } = launchReturnValue
|
|
453
|
-
if (!stoppedCallbackList) {
|
|
454
|
-
throw new Error(
|
|
455
|
-
`runtime.launch must return a stoppedCallbackList object, got ${stoppedCallbackList}`,
|
|
456
|
-
)
|
|
457
|
-
}
|
|
458
|
-
}
|
|
1
|
+
import cuid from "cuid"
|
|
2
|
+
import { createLogger, createDetailedMessage } from "@jsenv/logger"
|
|
3
|
+
import { Abort, raceCallbacks } from "@jsenv/abort"
|
|
4
|
+
import { resolveUrl, writeFile } from "@jsenv/filesystem"
|
|
5
|
+
|
|
6
|
+
import { composeTwoFileByFileIstanbulCoverages } from "./coverage_utils/istanbul_coverage_composition.js"
|
|
7
|
+
|
|
8
|
+
export const launchAndExecute = async ({
|
|
9
|
+
signal = new AbortController().signal,
|
|
10
|
+
launchAndExecuteLogLevel,
|
|
11
|
+
|
|
12
|
+
runtime,
|
|
13
|
+
runtimeParams,
|
|
14
|
+
executeParams,
|
|
15
|
+
|
|
16
|
+
allocatedMs,
|
|
17
|
+
mirrorConsole = false,
|
|
18
|
+
captureConsole = false, // rename collectConsole ?
|
|
19
|
+
inheritCoverage = false,
|
|
20
|
+
collectCoverage = false,
|
|
21
|
+
coverageTempDirectoryUrl,
|
|
22
|
+
measurePerformance,
|
|
23
|
+
collectPerformance = false,
|
|
24
|
+
|
|
25
|
+
// stopAfterExecute false by default because you want to keep browser alive
|
|
26
|
+
// or nodejs process
|
|
27
|
+
// however unit test will pass true because they want to move on
|
|
28
|
+
stopAfterExecute = false,
|
|
29
|
+
stopAfterExecuteReason = "stop after execute",
|
|
30
|
+
// when launch returns { stoppedCallbackList, gracefulStop, stop }
|
|
31
|
+
// the launched runtime have that amount of ms for disconnected to resolve
|
|
32
|
+
// before we call stop
|
|
33
|
+
gracefulStopAllocatedMs = 4000,
|
|
34
|
+
|
|
35
|
+
runtimeConsoleCallback = () => {},
|
|
36
|
+
runtimeStartedCallback = () => {},
|
|
37
|
+
runtimeStoppedCallback = () => {},
|
|
38
|
+
runtimeErrorAfterExecutionCallback = (error) => {
|
|
39
|
+
// by default throw on error after execution
|
|
40
|
+
throw error
|
|
41
|
+
},
|
|
42
|
+
} = {}) => {
|
|
43
|
+
const logger = createLogger({ logLevel: launchAndExecuteLogLevel })
|
|
44
|
+
|
|
45
|
+
if (typeof runtime !== "object") {
|
|
46
|
+
throw new TypeError(`runtime must be an object, got ${runtime}`)
|
|
47
|
+
}
|
|
48
|
+
if (typeof runtime.launch !== "function") {
|
|
49
|
+
throw new TypeError(
|
|
50
|
+
`runtime.launch must be a function, got ${runtime.launch}`,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let executionResultTransformer = (executionResult) => executionResult
|
|
55
|
+
|
|
56
|
+
const launchAndExecuteOperation = Abort.startOperation()
|
|
57
|
+
launchAndExecuteOperation.addAbortSignal(signal)
|
|
58
|
+
|
|
59
|
+
const hasAllocatedMs =
|
|
60
|
+
typeof allocatedMs === "number" && allocatedMs !== Infinity
|
|
61
|
+
let timeoutAbortSource
|
|
62
|
+
|
|
63
|
+
if (hasAllocatedMs) {
|
|
64
|
+
timeoutAbortSource = launchAndExecuteOperation.timeout(
|
|
65
|
+
// FIXME: if allocatedMs is veryyyyyy big
|
|
66
|
+
// setTimeout may be called immediatly
|
|
67
|
+
// in that case we should just throw that the number is too big
|
|
68
|
+
allocatedMs,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (mirrorConsole) {
|
|
73
|
+
runtimeConsoleCallback = composeCallback(
|
|
74
|
+
runtimeConsoleCallback,
|
|
75
|
+
({ type, text }) => {
|
|
76
|
+
if (type === "error") {
|
|
77
|
+
process.stderr.write(text)
|
|
78
|
+
} else {
|
|
79
|
+
process.stdout.write(text)
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (captureConsole) {
|
|
86
|
+
const consoleCalls = []
|
|
87
|
+
runtimeConsoleCallback = composeCallback(
|
|
88
|
+
runtimeConsoleCallback,
|
|
89
|
+
({ type, text }) => {
|
|
90
|
+
consoleCalls.push({ type, text })
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
executionResultTransformer = composeTransformer(
|
|
94
|
+
executionResultTransformer,
|
|
95
|
+
(executionResult) => {
|
|
96
|
+
executionResult.consoleCalls = consoleCalls
|
|
97
|
+
return executionResult
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
executionResultTransformer = composeTransformer(
|
|
103
|
+
executionResultTransformer,
|
|
104
|
+
(executionResult) => {
|
|
105
|
+
executionResult.runtimeName = runtime.name
|
|
106
|
+
executionResult.runtimeVersion = runtime.version
|
|
107
|
+
return executionResult
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
inheritCoverage &&
|
|
113
|
+
// NODE_V8_COVERAGE is doing the coverage propagation for us
|
|
114
|
+
!process.env.NODE_V8_COVERAGE
|
|
115
|
+
) {
|
|
116
|
+
const collectCoverageSaved = collectCoverage
|
|
117
|
+
collectCoverage = true
|
|
118
|
+
executionResultTransformer = composeTransformer(
|
|
119
|
+
executionResultTransformer,
|
|
120
|
+
(executionResult) => {
|
|
121
|
+
const { coverage } = executionResult
|
|
122
|
+
// propagate coverage from execution to this process
|
|
123
|
+
global.__coverage__ = composeTwoFileByFileIstanbulCoverages(
|
|
124
|
+
global.__coverage__ || {},
|
|
125
|
+
coverage || {},
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
if (!collectCoverageSaved) {
|
|
129
|
+
delete executionResult.coverage
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return executionResult
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (collectCoverage) {
|
|
138
|
+
executionResultTransformer = composeTransformer(
|
|
139
|
+
executionResultTransformer,
|
|
140
|
+
async (executionResult) => {
|
|
141
|
+
// we do not keep coverage in memory, it can grow very big
|
|
142
|
+
// instead we store it on the filesystem, they will be read and merged together later on
|
|
143
|
+
// in "executeConcurrently"
|
|
144
|
+
const { coverage } = executionResult
|
|
145
|
+
if (coverage) {
|
|
146
|
+
const coverageFileUrl = resolveUrl(
|
|
147
|
+
`./${runtime.name}/${cuid()}`,
|
|
148
|
+
coverageTempDirectoryUrl,
|
|
149
|
+
)
|
|
150
|
+
await writeFile(coverageFileUrl, JSON.stringify(coverage, null, " "))
|
|
151
|
+
executionResult.coverageFileUrl = coverageFileUrl
|
|
152
|
+
delete executionResult.coverage
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// indirectCoverage is a feature making possible to collect
|
|
156
|
+
// coverage generated by executing a node process which executes
|
|
157
|
+
// a browser. The coverage coming the browser execution would be lost
|
|
158
|
+
// if not propagated somehow.
|
|
159
|
+
// This is possible if the node process collect the browser coverage
|
|
160
|
+
// and write it into global.__indirectCoverage__
|
|
161
|
+
// This is used by jsenv during tests execution
|
|
162
|
+
const { indirectCoverage } = executionResult
|
|
163
|
+
if (indirectCoverage) {
|
|
164
|
+
const indirectCoverageFileUrl = resolveUrl(
|
|
165
|
+
`./${runtime.name}/${cuid()}`,
|
|
166
|
+
coverageTempDirectoryUrl,
|
|
167
|
+
)
|
|
168
|
+
await writeFile(
|
|
169
|
+
indirectCoverageFileUrl,
|
|
170
|
+
JSON.stringify(indirectCoverage, null, " "),
|
|
171
|
+
)
|
|
172
|
+
executionResult.indirectCoverageFileUrl = indirectCoverageFileUrl
|
|
173
|
+
delete executionResult.indirectCoverage
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return executionResult
|
|
177
|
+
},
|
|
178
|
+
)
|
|
179
|
+
} else {
|
|
180
|
+
executionResultTransformer = composeTransformer(
|
|
181
|
+
executionResultTransformer,
|
|
182
|
+
(executionResult) => {
|
|
183
|
+
// as collectCoverage is disabled
|
|
184
|
+
// executionResult.coverage is undefined or {}
|
|
185
|
+
// we delete it just to have a cleaner object
|
|
186
|
+
delete executionResult.coverage
|
|
187
|
+
delete executionResult.indirectCoverage
|
|
188
|
+
return executionResult
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const startMs = Date.now()
|
|
194
|
+
executionResultTransformer = composeTransformer(
|
|
195
|
+
executionResultTransformer,
|
|
196
|
+
(executionResult) => {
|
|
197
|
+
executionResult.duration = Date.now() - startMs
|
|
198
|
+
return executionResult
|
|
199
|
+
},
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const runtimeLabel = `${runtime.name}/${runtime.version}`
|
|
204
|
+
logger.debug(`launch ${runtimeLabel} to execute something in it`)
|
|
205
|
+
|
|
206
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
207
|
+
const launchReturnValue = await runtime.launch({
|
|
208
|
+
signal: launchAndExecuteOperation.signal,
|
|
209
|
+
logger,
|
|
210
|
+
stopAfterExecute,
|
|
211
|
+
measurePerformance,
|
|
212
|
+
collectPerformance,
|
|
213
|
+
...runtimeParams,
|
|
214
|
+
})
|
|
215
|
+
validateLaunchReturnValue(launchReturnValue)
|
|
216
|
+
|
|
217
|
+
const stopRuntime = async (reason) => {
|
|
218
|
+
const { stop } = launchReturnValue
|
|
219
|
+
logger.debug(`${runtimeLabel}: stop() because ${reason}`)
|
|
220
|
+
const { graceful } = await stop({ reason, gracefulStopAllocatedMs })
|
|
221
|
+
if (graceful) {
|
|
222
|
+
logger.debug(`${runtimeLabel}: runtime stopped gracefully`)
|
|
223
|
+
} else {
|
|
224
|
+
logger.debug(`${runtimeLabel}: runtime stopped`)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
launchAndExecuteOperation.addAbortCallback(async () => {
|
|
228
|
+
await stopRuntime("Operation aborted")
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
logger.debug(createDetailedMessage(`${runtimeLabel}: runtime launched`))
|
|
232
|
+
runtimeStartedCallback()
|
|
233
|
+
|
|
234
|
+
logger.debug(`${runtimeLabel}: start execution`)
|
|
235
|
+
const {
|
|
236
|
+
errorCallbackList,
|
|
237
|
+
outputCallbackList,
|
|
238
|
+
stoppedCallbackList,
|
|
239
|
+
execute,
|
|
240
|
+
finalizeExecutionResult = (executionResult) => executionResult,
|
|
241
|
+
} = launchReturnValue
|
|
242
|
+
executionResultTransformer = composeTransformer(
|
|
243
|
+
executionResultTransformer,
|
|
244
|
+
finalizeExecutionResult,
|
|
245
|
+
)
|
|
246
|
+
outputCallbackList.add(runtimeConsoleCallback)
|
|
247
|
+
|
|
248
|
+
let executionResult = await callExecute({
|
|
249
|
+
launchAndExecuteOperation,
|
|
250
|
+
errorCallbackList,
|
|
251
|
+
stoppedCallbackList,
|
|
252
|
+
execute,
|
|
253
|
+
executeParams,
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
if (stopAfterExecute) {
|
|
257
|
+
// stopping runtime is part of the execution
|
|
258
|
+
try {
|
|
259
|
+
await stopRuntime(stopAfterExecuteReason)
|
|
260
|
+
} catch (e) {
|
|
261
|
+
executionResult = createErroredExecutionResult({
|
|
262
|
+
error: e,
|
|
263
|
+
})
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
// when the process is still alive
|
|
267
|
+
// we want to catch error to notify runtimeErrorAfterExecutionCallback
|
|
268
|
+
// and throw that error by default
|
|
269
|
+
errorCallbackList.add((error) => {
|
|
270
|
+
runtimeErrorAfterExecutionCallback(error)
|
|
271
|
+
})
|
|
272
|
+
stoppedCallbackList.add(() => {
|
|
273
|
+
logger.debug(`${runtimeLabel}: runtime stopped after execution`)
|
|
274
|
+
runtimeStoppedCallback()
|
|
275
|
+
})
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (executionResult.status === "errored") {
|
|
279
|
+
// debug log level because this error happens during execution
|
|
280
|
+
// there is no need to log it.
|
|
281
|
+
// the code will know the execution errored because it receives
|
|
282
|
+
// an errored execution result
|
|
283
|
+
logger.debug(
|
|
284
|
+
createDetailedMessage(`error during execution`, {
|
|
285
|
+
["error stack"]: executionResult.error.stack,
|
|
286
|
+
["execute params"]: JSON.stringify(executeParams, null, " "),
|
|
287
|
+
["runtime"]: runtime,
|
|
288
|
+
}),
|
|
289
|
+
)
|
|
290
|
+
} else {
|
|
291
|
+
logger.debug(`${runtimeLabel}: execution ${executionResult.status}`)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return executionResultTransformer(executionResult)
|
|
295
|
+
} catch (e) {
|
|
296
|
+
if (Abort.isAbortError(e)) {
|
|
297
|
+
if (timeoutAbortSource && timeoutAbortSource.signal.aborted) {
|
|
298
|
+
const executionResult = createTimedoutExecutionResult()
|
|
299
|
+
return executionResultTransformer(executionResult)
|
|
300
|
+
}
|
|
301
|
+
const executionResult = createAbortedExecutionResult()
|
|
302
|
+
return executionResultTransformer(executionResult)
|
|
303
|
+
}
|
|
304
|
+
throw e
|
|
305
|
+
} finally {
|
|
306
|
+
await launchAndExecuteOperation.end()
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const callExecute = async ({
|
|
311
|
+
launchAndExecuteOperation,
|
|
312
|
+
errorCallbackList,
|
|
313
|
+
stoppedCallbackList,
|
|
314
|
+
execute,
|
|
315
|
+
executeParams,
|
|
316
|
+
}) => {
|
|
317
|
+
const winnerPromise = new Promise((resolve, reject) => {
|
|
318
|
+
raceCallbacks(
|
|
319
|
+
{
|
|
320
|
+
aborted: (cb) => {
|
|
321
|
+
launchAndExecuteOperation.signal.addEventListener("abort", cb)
|
|
322
|
+
return () => {
|
|
323
|
+
launchAndExecuteOperation.signal.removeEventListener("abort", cb)
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
error: (cb) => {
|
|
327
|
+
return errorCallbackList.add(cb)
|
|
328
|
+
},
|
|
329
|
+
stopped: (cb) => {
|
|
330
|
+
return stoppedCallbackList.add(cb)
|
|
331
|
+
},
|
|
332
|
+
executed: async (cb) => {
|
|
333
|
+
try {
|
|
334
|
+
const executionResult = await execute({
|
|
335
|
+
signal: launchAndExecuteOperation.signal,
|
|
336
|
+
...executeParams,
|
|
337
|
+
})
|
|
338
|
+
cb(executionResult)
|
|
339
|
+
} catch (e) {
|
|
340
|
+
if (Abort.isAbortError(e)) {
|
|
341
|
+
cb(e)
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
reject(e)
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
resolve,
|
|
349
|
+
)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
353
|
+
const winner = await winnerPromise
|
|
354
|
+
|
|
355
|
+
if (winner.name === "aborted") {
|
|
356
|
+
launchAndExecuteOperation.throwIfAborted()
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (winner.name === "error") {
|
|
360
|
+
return createErroredExecutionResult({
|
|
361
|
+
error: winner.data,
|
|
362
|
+
})
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (winner.name === "stopped") {
|
|
366
|
+
return createErroredExecutionResult({
|
|
367
|
+
error: new Error(`runtime stopped during execution`),
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const executeResult = winner.data
|
|
372
|
+
if (Abort.isAbortError(executeResult)) {
|
|
373
|
+
throw executeResult
|
|
374
|
+
}
|
|
375
|
+
const { status } = executeResult
|
|
376
|
+
if (status === "errored") {
|
|
377
|
+
return createErroredExecutionResult(executeResult)
|
|
378
|
+
}
|
|
379
|
+
return createCompletedExecutionResult(executeResult)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const createAbortedExecutionResult = () => {
|
|
383
|
+
return {
|
|
384
|
+
status: "aborted",
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const createTimedoutExecutionResult = () => {
|
|
389
|
+
return {
|
|
390
|
+
status: "timedout",
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const createErroredExecutionResult = (executionResult) => {
|
|
395
|
+
return {
|
|
396
|
+
...executionResult,
|
|
397
|
+
status: "errored",
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const createCompletedExecutionResult = (executionResult) => {
|
|
402
|
+
return {
|
|
403
|
+
...executionResult,
|
|
404
|
+
status: "completed",
|
|
405
|
+
namespace: normalizeNamespace(executionResult.namespace),
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const normalizeNamespace = (namespace) => {
|
|
410
|
+
if (typeof namespace !== "object") return namespace
|
|
411
|
+
if (namespace instanceof Promise) return namespace
|
|
412
|
+
const normalized = {}
|
|
413
|
+
// remove "__esModule" or Symbol.toStringTag from namespace object
|
|
414
|
+
Object.keys(namespace).forEach((key) => {
|
|
415
|
+
normalized[key] = namespace[key]
|
|
416
|
+
})
|
|
417
|
+
return normalized
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const composeCallback = (previousCallback, callback) => {
|
|
421
|
+
return (...args) => {
|
|
422
|
+
previousCallback(...args)
|
|
423
|
+
return callback(...args)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const composeTransformer = (previousTransformer, transformer) => {
|
|
428
|
+
return async (value) => {
|
|
429
|
+
const transformedValue = await previousTransformer(value)
|
|
430
|
+
return transformer(transformedValue)
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const validateLaunchReturnValue = (launchReturnValue) => {
|
|
435
|
+
if (launchReturnValue === null) {
|
|
436
|
+
throw new Error(`runtime.launch must return an object, got null`)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (typeof launchReturnValue !== "object") {
|
|
440
|
+
throw new Error(
|
|
441
|
+
`runtime.launch must return an object, got ${launchReturnValue}`,
|
|
442
|
+
)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const { execute } = launchReturnValue
|
|
446
|
+
if (typeof execute !== "function") {
|
|
447
|
+
throw new Error(
|
|
448
|
+
`runtime.launch must return an execute function, got ${execute}`,
|
|
449
|
+
)
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const { stoppedCallbackList } = launchReturnValue
|
|
453
|
+
if (!stoppedCallbackList) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
`runtime.launch must return a stoppedCallbackList object, got ${stoppedCallbackList}`,
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
}
|