@jsenv/core 34.2.2 → 35.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/html/explorer.html +5 -4
- package/dist/{jsenv.js → jsenv_core.js} +840 -3914
- package/package.json +7 -21
- package/src/build/build.js +34 -16
- package/src/build/version_mappings_injection.js +20 -27
- package/src/dev/file_service.js +9 -9
- package/src/dev/start_dev_server.js +3 -3
- package/src/dev/user_agent.js +1 -1
- package/src/kitchen/kitchen.js +5 -3
- package/src/main.js +0 -23
- package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +2 -2
- package/src/plugins/importmap/jsenv_plugin_importmap.js +6 -2
- package/src/plugins/{inline/jsenv_plugin_html_inline_content.js → inline_content_analysis/jsenv_plugin_html_inline_content_analysis.js} +12 -6
- package/src/plugins/{inline/jsenv_plugin_inline.js → inline_content_analysis/jsenv_plugin_inline_content_analysis.js} +8 -10
- package/src/plugins/{inline/jsenv_plugin_js_inline_content.js → inline_content_analysis/jsenv_plugin_js_inline_content_analysis.js} +4 -2
- package/src/plugins/inlining/jsenv_plugin_inlining.js +22 -0
- package/src/plugins/{inline/jsenv_plugin_inline_query_param.js → inlining/jsenv_plugin_inlining_as_data_url.js} +16 -9
- package/src/plugins/inlining/jsenv_plugin_inlining_into_html.js +149 -0
- package/src/plugins/plugins.js +5 -2
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +11 -10
- package/src/plugins/server_events/jsenv_plugin_server_events_client_injection.js +2 -2
- package/src/plugins/supervisor/html_supervisor_injection.js +23 -25
- package/src/plugins/supervisor/jsenv_plugin_supervisor.js +1 -1
- package/src/plugins/transpilation/babel/require_babel_plugin.js +1 -1
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +20 -5
- package/src/plugins/transpilation/js_module_fallback/convert_js_module_to_js_classic.js +1 -1
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_inside_html.js +2 -2
- package/src/plugins/transpilation/js_module_fallback/jsenv_plugin_js_module_fallback_on_workers.js +3 -3
- package/src/plugins/url_analysis/html/html_urls.js +1 -1
- package/dist/controllable_child_process.mjs +0 -129
- package/dist/controllable_worker_thread.mjs +0 -91
- package/dist/js/execute_using_dynamic_import.js +0 -850
- package/dist/js/v8_coverage.js +0 -508
- package/src/execute/execute.js +0 -109
- package/src/execute/run.js +0 -161
- package/src/execute/runtimes/browsers/chromium.js +0 -10
- package/src/execute/runtimes/browsers/firefox.js +0 -9
- package/src/execute/runtimes/browsers/from_playwright.js +0 -574
- package/src/execute/runtimes/browsers/middleware_istanbul.js +0 -65
- package/src/execute/runtimes/browsers/middleware_js_supervisor.js +0 -100
- package/src/execute/runtimes/browsers/webkit.js +0 -26
- package/src/execute/runtimes/node/child_exec_options.js +0 -166
- package/src/execute/runtimes/node/controllable_child_process.mjs +0 -135
- package/src/execute/runtimes/node/controllable_worker_thread.mjs +0 -103
- package/src/execute/runtimes/node/exec_options.js +0 -44
- package/src/execute/runtimes/node/execute_using_dynamic_import.js +0 -55
- package/src/execute/runtimes/node/exit_codes.js +0 -9
- package/src/execute/runtimes/node/kill_process_tree.js +0 -76
- package/src/execute/runtimes/node/node_child_process.js +0 -348
- package/src/execute/runtimes/node/node_execution_performance.js +0 -67
- package/src/execute/runtimes/node/node_worker_thread.js +0 -282
- package/src/execute/runtimes/node/profiler_v8_coverage.js +0 -56
- package/src/execute/runtimes/readme.md +0 -13
- package/src/execute/web_server_param.js +0 -74
- package/src/test/coverage/babel_plugin_instrument.js +0 -48
- package/src/test/coverage/coverage_reporter_html_directory.js +0 -32
- package/src/test/coverage/coverage_reporter_json_file.js +0 -17
- package/src/test/coverage/coverage_reporter_text_log.js +0 -19
- package/src/test/coverage/empty_coverage_factory.js +0 -52
- package/src/test/coverage/file_by_file_coverage.js +0 -25
- package/src/test/coverage/istanbul_coverage_composition.js +0 -28
- package/src/test/coverage/istanbul_coverage_map_from_coverage.js +0 -16
- package/src/test/coverage/list_files_not_covered.js +0 -15
- package/src/test/coverage/missing_coverage.js +0 -41
- package/src/test/coverage/report_to_coverage.js +0 -198
- package/src/test/coverage/v8_and_istanbul.js +0 -37
- package/src/test/coverage/v8_coverage.js +0 -26
- package/src/test/coverage/v8_coverage_composition.js +0 -24
- package/src/test/coverage/v8_coverage_node_directory.js +0 -85
- package/src/test/coverage/v8_coverage_to_istanbul.js +0 -99
- package/src/test/execute_steps.js +0 -425
- package/src/test/execute_test_plan.js +0 -372
- package/src/test/execution_colors.js +0 -10
- package/src/test/execution_steps.js +0 -65
- package/src/test/gc.js +0 -9
- package/src/test/logs_file_execution.js +0 -427
- package/src/test/logs_file_execution.test.mjs +0 -41
- package/src/test/readme.md +0 -3
- /package/src/{basic_fetch.js → helpers/basic_fetch.js} +0 -0
- /package/src/{lookup_package_directory.js → helpers/lookup_package_directory.js} +0 -0
- /package/src/{ping_server.js → helpers/ping_server.js} +0 -0
- /package/src/{require_from_jsenv.js → helpers/require_from_jsenv.js} +0 -0
- /package/src/{watch_source_files.js → helpers/watch_source_files.js} +0 -0
- /package/src/{web_url_converter.js → helpers/web_url_converter.js} +0 -0
- /package/src/plugins/{inline → inline_content_analysis}/client/inline_content.js +0 -0
- /package/src/plugins/{inline → inline_content_analysis}/jsenv_plugin_data_urls.js +0 -0
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs"
|
|
2
|
-
|
|
3
|
-
import { urlToExtension } from "@jsenv/urls"
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
injectSupervisorIntoHTML,
|
|
7
|
-
supervisorFileUrl,
|
|
8
|
-
} from "../../../plugins/supervisor/html_supervisor_injection.js"
|
|
9
|
-
|
|
10
|
-
export const initJsSupervisorMiddleware = async (
|
|
11
|
-
page,
|
|
12
|
-
{ webServer, fileUrl, fileServerUrl },
|
|
13
|
-
) => {
|
|
14
|
-
const inlineScriptContents = new Map()
|
|
15
|
-
|
|
16
|
-
const interceptHtmlToExecute = async ({ route }) => {
|
|
17
|
-
const response = await route.fetch()
|
|
18
|
-
const originalBody = await response.text()
|
|
19
|
-
const injectionResult = await injectSupervisorIntoHTML(
|
|
20
|
-
{
|
|
21
|
-
content: originalBody,
|
|
22
|
-
url: fileUrl,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
supervisorScriptSrc: `/@fs/${supervisorFileUrl.slice(
|
|
26
|
-
"file:///".length,
|
|
27
|
-
)}`,
|
|
28
|
-
supervisorOptions: {},
|
|
29
|
-
inlineAsRemote: true,
|
|
30
|
-
webServer,
|
|
31
|
-
onInlineScript: ({ src, textContent }) => {
|
|
32
|
-
const inlineScriptWebUrl = new URL(src, `${webServer.origin}/`).href
|
|
33
|
-
inlineScriptContents.set(inlineScriptWebUrl, textContent)
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
)
|
|
37
|
-
route.fulfill({
|
|
38
|
-
response,
|
|
39
|
-
body: injectionResult.content,
|
|
40
|
-
headers: {
|
|
41
|
-
...response.headers(),
|
|
42
|
-
"content-length": Buffer.byteLength(injectionResult.content),
|
|
43
|
-
},
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const interceptInlineScript = ({ url, route }) => {
|
|
48
|
-
const inlineScriptContent = inlineScriptContents.get(url)
|
|
49
|
-
route.fulfill({
|
|
50
|
-
status: 200,
|
|
51
|
-
body: inlineScriptContent,
|
|
52
|
-
headers: {
|
|
53
|
-
"content-type": "text/javascript",
|
|
54
|
-
"content-length": Buffer.byteLength(inlineScriptContent),
|
|
55
|
-
},
|
|
56
|
-
})
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const interceptFileSystemUrl = ({ url, route }) => {
|
|
60
|
-
const relativeUrl = url.slice(webServer.origin.length)
|
|
61
|
-
const fsPath = relativeUrl.slice("/@fs/".length)
|
|
62
|
-
const fsUrl = `file:///${fsPath}`
|
|
63
|
-
const fileContent = readFileSync(new URL(fsUrl), "utf8")
|
|
64
|
-
route.fulfill({
|
|
65
|
-
status: 200,
|
|
66
|
-
body: fileContent,
|
|
67
|
-
headers: {
|
|
68
|
-
"content-type": "text/javascript",
|
|
69
|
-
"content-length": Buffer.byteLength(fileContent),
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await page.route("**", async (route) => {
|
|
75
|
-
const request = route.request()
|
|
76
|
-
const url = request.url()
|
|
77
|
-
if (url === fileServerUrl && urlToExtension(url) === ".html") {
|
|
78
|
-
interceptHtmlToExecute({
|
|
79
|
-
url,
|
|
80
|
-
request,
|
|
81
|
-
route,
|
|
82
|
-
})
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
if (inlineScriptContents.has(url)) {
|
|
86
|
-
interceptInlineScript({
|
|
87
|
-
url,
|
|
88
|
-
request,
|
|
89
|
-
route,
|
|
90
|
-
})
|
|
91
|
-
return
|
|
92
|
-
}
|
|
93
|
-
const fsServerUrl = new URL("/@fs/", webServer.origin)
|
|
94
|
-
if (url.startsWith(fsServerUrl)) {
|
|
95
|
-
interceptFileSystemUrl({ url, request, route })
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
route.fallback()
|
|
99
|
-
})
|
|
100
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createRuntimeFromPlaywright } from "./from_playwright.js"
|
|
2
|
-
|
|
3
|
-
export const webkit = createRuntimeFromPlaywright({
|
|
4
|
-
browserName: "webkit",
|
|
5
|
-
// browserVersion will be set by "browser._initializer.version"
|
|
6
|
-
// see also https://github.com/microsoft/playwright/releases
|
|
7
|
-
browserVersion: "unset",
|
|
8
|
-
shouldIgnoreError: (error) => {
|
|
9
|
-
// we catch error during execution but safari throw unhandled rejection
|
|
10
|
-
// in a non-deterministic way.
|
|
11
|
-
// I suppose it's due to some race condition to decide if the promise is catched or not
|
|
12
|
-
// for now we'll ignore unhandled rejection on wekbkit
|
|
13
|
-
if (error.name === "Unhandled Promise Rejection") {
|
|
14
|
-
return true
|
|
15
|
-
}
|
|
16
|
-
return false
|
|
17
|
-
},
|
|
18
|
-
transformErrorHook: (error) => {
|
|
19
|
-
// Force error stack to contain the error message
|
|
20
|
-
// because it's not the case on webkit
|
|
21
|
-
error.stack = `${error.message}
|
|
22
|
-
at ${error.stack}`
|
|
23
|
-
return error
|
|
24
|
-
},
|
|
25
|
-
})
|
|
26
|
-
export const webkitIsolatedTab = webkit.isolatedTab
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { findFreePort } from "@jsenv/server"
|
|
2
|
-
|
|
3
|
-
import { createDetailedMessage } from "@jsenv/log"
|
|
4
|
-
import { ExecOptions } from "./exec_options.js"
|
|
5
|
-
|
|
6
|
-
export const createChildExecOptions = async ({
|
|
7
|
-
signal = new AbortController().signal,
|
|
8
|
-
// https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_automatically-attach-debugger-to-nodejs-subprocesses
|
|
9
|
-
processExecArgv = process.execArgv,
|
|
10
|
-
processDebugPort = process.debugPort,
|
|
11
|
-
|
|
12
|
-
debugPort = 0,
|
|
13
|
-
debugMode = "inherit",
|
|
14
|
-
debugModeInheritBreak = true,
|
|
15
|
-
} = {}) => {
|
|
16
|
-
if (
|
|
17
|
-
typeof debugMode === "string" &&
|
|
18
|
-
AVAILABLE_DEBUG_MODE.indexOf(debugMode) === -1
|
|
19
|
-
) {
|
|
20
|
-
throw new TypeError(
|
|
21
|
-
createDetailedMessage(`unexpected debug mode.`, {
|
|
22
|
-
["debug mode"]: debugMode,
|
|
23
|
-
["allowed debug mode"]: AVAILABLE_DEBUG_MODE,
|
|
24
|
-
}),
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
const childExecOptions = ExecOptions.fromExecArgv(processExecArgv)
|
|
28
|
-
await mutateDebuggingOptions(childExecOptions, {
|
|
29
|
-
signal,
|
|
30
|
-
processDebugPort,
|
|
31
|
-
debugMode,
|
|
32
|
-
debugPort,
|
|
33
|
-
debugModeInheritBreak,
|
|
34
|
-
})
|
|
35
|
-
return childExecOptions
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const AVAILABLE_DEBUG_MODE = [
|
|
39
|
-
"none",
|
|
40
|
-
"inherit",
|
|
41
|
-
"inspect",
|
|
42
|
-
"inspect-brk",
|
|
43
|
-
"debug",
|
|
44
|
-
"debug-brk",
|
|
45
|
-
]
|
|
46
|
-
|
|
47
|
-
const mutateDebuggingOptions = async (
|
|
48
|
-
childExecOptions,
|
|
49
|
-
{
|
|
50
|
-
// ensure multiline
|
|
51
|
-
signal,
|
|
52
|
-
processDebugPort,
|
|
53
|
-
debugMode,
|
|
54
|
-
debugPort,
|
|
55
|
-
debugModeInheritBreak,
|
|
56
|
-
},
|
|
57
|
-
) => {
|
|
58
|
-
const parentDebugInfo = getDebugInfo(childExecOptions)
|
|
59
|
-
const parentDebugModeOptionName = parentDebugInfo.debugModeOptionName
|
|
60
|
-
const parentDebugPortOptionName = parentDebugInfo.debugPortOptionName
|
|
61
|
-
const childDebugModeOptionName = getChildDebugModeOptionName({
|
|
62
|
-
parentDebugModeOptionName,
|
|
63
|
-
debugMode,
|
|
64
|
-
debugModeInheritBreak,
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
if (!childDebugModeOptionName) {
|
|
68
|
-
// remove debug mode and debug port fron child options
|
|
69
|
-
if (parentDebugModeOptionName) {
|
|
70
|
-
delete childExecOptions[parentDebugModeOptionName]
|
|
71
|
-
}
|
|
72
|
-
if (parentDebugPortOptionName) {
|
|
73
|
-
delete childExecOptions[parentDebugPortOptionName]
|
|
74
|
-
}
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// replace child debug mode
|
|
79
|
-
if (
|
|
80
|
-
parentDebugModeOptionName &&
|
|
81
|
-
parentDebugModeOptionName !== childDebugModeOptionName
|
|
82
|
-
) {
|
|
83
|
-
delete childExecOptions[parentDebugModeOptionName]
|
|
84
|
-
}
|
|
85
|
-
childExecOptions[childDebugModeOptionName] = ""
|
|
86
|
-
|
|
87
|
-
// this is required because vscode does not
|
|
88
|
-
// support assigning a child spawned without a specific port
|
|
89
|
-
const childDebugPortOptionValue =
|
|
90
|
-
debugPort === 0
|
|
91
|
-
? await findFreePort(processDebugPort + 37, { signal })
|
|
92
|
-
: debugPort
|
|
93
|
-
// replace child debug port
|
|
94
|
-
if (parentDebugPortOptionName) {
|
|
95
|
-
delete childExecOptions[parentDebugPortOptionName]
|
|
96
|
-
}
|
|
97
|
-
childExecOptions[childDebugModeOptionName] = portToArgValue(
|
|
98
|
-
childDebugPortOptionValue,
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const getChildDebugModeOptionName = ({
|
|
103
|
-
parentDebugModeOptionName,
|
|
104
|
-
debugMode,
|
|
105
|
-
debugModeInheritBreak,
|
|
106
|
-
}) => {
|
|
107
|
-
if (debugMode === "none") {
|
|
108
|
-
return undefined
|
|
109
|
-
}
|
|
110
|
-
if (debugMode !== "inherit") {
|
|
111
|
-
return `--${debugMode}`
|
|
112
|
-
}
|
|
113
|
-
if (!parentDebugModeOptionName) {
|
|
114
|
-
return undefined
|
|
115
|
-
}
|
|
116
|
-
if (!debugModeInheritBreak && parentDebugModeOptionName === "--inspect-brk") {
|
|
117
|
-
return "--inspect"
|
|
118
|
-
}
|
|
119
|
-
if (!debugModeInheritBreak && parentDebugModeOptionName === "--debug-brk") {
|
|
120
|
-
return "--debug"
|
|
121
|
-
}
|
|
122
|
-
return parentDebugModeOptionName
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const portToArgValue = (port) => {
|
|
126
|
-
if (typeof port !== "number") return ""
|
|
127
|
-
if (port === 0) return ""
|
|
128
|
-
return port
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// https://nodejs.org/en/docs/guides/debugging-getting-started/
|
|
132
|
-
const getDebugInfo = (processOptions) => {
|
|
133
|
-
const inspectOption = processOptions["--inspect"]
|
|
134
|
-
if (inspectOption !== undefined) {
|
|
135
|
-
return {
|
|
136
|
-
debugModeOptionName: "--inspect",
|
|
137
|
-
debugPortOptionName: "--inspect-port",
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const inspectBreakOption = processOptions["--inspect-brk"]
|
|
141
|
-
if (inspectBreakOption !== undefined) {
|
|
142
|
-
return {
|
|
143
|
-
debugModeOptionName: "--inspect-brk",
|
|
144
|
-
debugPortOptionName: "--inspect-port",
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const debugOption = processOptions["--debug"]
|
|
148
|
-
if (debugOption !== undefined) {
|
|
149
|
-
return {
|
|
150
|
-
debugModeOptionName: "--debug",
|
|
151
|
-
debugPortOptionName: "--debug-port",
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const debugBreakOption = processOptions["--debug-brk"]
|
|
155
|
-
if (debugBreakOption !== undefined) {
|
|
156
|
-
return {
|
|
157
|
-
debugModeOptionName: "--debug-brk",
|
|
158
|
-
debugPortOptionName: "--debug-port",
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return {}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// export const processIsExecutedByVSCode = () => {
|
|
165
|
-
// return typeof process.env.VSCODE_PID === "string"
|
|
166
|
-
// }
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { uneval } from "@jsenv/uneval"
|
|
2
|
-
|
|
3
|
-
import { executeUsingDynamicImport } from "./execute_using_dynamic_import.js"
|
|
4
|
-
|
|
5
|
-
const ACTIONS_AVAILABLE = {
|
|
6
|
-
"execute-using-dynamic-import": executeUsingDynamicImport,
|
|
7
|
-
"execute-using-require": async ({ fileUrl }) => {
|
|
8
|
-
const { createRequire } = await import("node:module")
|
|
9
|
-
const { fileURLToPath } = await import("node:url")
|
|
10
|
-
const filePath = fileURLToPath(fileUrl)
|
|
11
|
-
const require = createRequire(fileUrl)
|
|
12
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
13
|
-
const namespace = require(filePath)
|
|
14
|
-
const namespaceResolved = {}
|
|
15
|
-
await Promise.all(
|
|
16
|
-
Object.keys(namespace).map(async (key) => {
|
|
17
|
-
const value = await namespace[key]
|
|
18
|
-
namespaceResolved[key] = value
|
|
19
|
-
}),
|
|
20
|
-
)
|
|
21
|
-
return namespaceResolved
|
|
22
|
-
},
|
|
23
|
-
}
|
|
24
|
-
const ACTION_REQUEST_EVENT_NAME = "action"
|
|
25
|
-
const ACTION_RESPONSE_EVENT_NAME = "action-result"
|
|
26
|
-
const ACTION_RESPONSE_STATUS_FAILED = "action-failed"
|
|
27
|
-
const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed"
|
|
28
|
-
|
|
29
|
-
const sendActionFailed = (error) => {
|
|
30
|
-
if (error.hasOwnProperty("toString")) {
|
|
31
|
-
delete error.toString
|
|
32
|
-
}
|
|
33
|
-
sendToParent(
|
|
34
|
-
ACTION_RESPONSE_EVENT_NAME,
|
|
35
|
-
// process.send algorithm does not send non enumerable values
|
|
36
|
-
// so use @jsenv/uneval
|
|
37
|
-
uneval(
|
|
38
|
-
{
|
|
39
|
-
status: ACTION_RESPONSE_STATUS_FAILED,
|
|
40
|
-
value: error,
|
|
41
|
-
},
|
|
42
|
-
{ ignoreSymbols: true },
|
|
43
|
-
),
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const sendActionCompleted = (value) => {
|
|
48
|
-
sendToParent(
|
|
49
|
-
ACTION_RESPONSE_EVENT_NAME,
|
|
50
|
-
// here we use JSON.stringify because we should not
|
|
51
|
-
// have non enumerable value (unlike there is on Error objects)
|
|
52
|
-
// otherwise uneval is quite slow to turn a giant object
|
|
53
|
-
// into a string (and value can be giant when using coverage)
|
|
54
|
-
JSON.stringify({
|
|
55
|
-
status: ACTION_RESPONSE_STATUS_COMPLETED,
|
|
56
|
-
value,
|
|
57
|
-
}),
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const sendToParent = (type, data) => {
|
|
62
|
-
// https://nodejs.org/api/process.html#process_process_connected
|
|
63
|
-
// not connected anymore, cannot communicate with parent
|
|
64
|
-
if (!process.connected) {
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
// this can keep process alive longer than expected
|
|
68
|
-
// when source is a long string.
|
|
69
|
-
// It means node process may stay alive longer than expected
|
|
70
|
-
// the time to send the data to the parent.
|
|
71
|
-
process.send({
|
|
72
|
-
jsenv: true,
|
|
73
|
-
type,
|
|
74
|
-
data,
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const onceParentMessage = (type, callback) => {
|
|
79
|
-
const listener = (message) => {
|
|
80
|
-
if (message && message.jsenv && message.type === type) {
|
|
81
|
-
removeListener() // commenting this line keep this process alive
|
|
82
|
-
callback(message.data)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const removeListener = () => {
|
|
86
|
-
process.removeListener("message", listener)
|
|
87
|
-
}
|
|
88
|
-
process.on("message", listener)
|
|
89
|
-
return removeListener
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const removeActionRequestListener = onceParentMessage(
|
|
93
|
-
ACTION_REQUEST_EVENT_NAME,
|
|
94
|
-
async ({ actionType, actionParams }) => {
|
|
95
|
-
const action = ACTIONS_AVAILABLE[actionType]
|
|
96
|
-
if (!action) {
|
|
97
|
-
sendActionFailed(new Error(`unknown action ${actionType}`))
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let value
|
|
102
|
-
let failed = false
|
|
103
|
-
try {
|
|
104
|
-
value = await action(actionParams)
|
|
105
|
-
} catch (e) {
|
|
106
|
-
failed = true
|
|
107
|
-
value = e
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// setTimeout(() => {}, 100)
|
|
111
|
-
|
|
112
|
-
if (failed) {
|
|
113
|
-
sendActionFailed(value)
|
|
114
|
-
} else {
|
|
115
|
-
sendActionCompleted(value)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// removeActionRequestListener()
|
|
119
|
-
if (actionParams.exitAfterAction) {
|
|
120
|
-
removeActionRequestListener()
|
|
121
|
-
// for some reason this fixes v8 coverage directory sometimes empty on Ubuntu
|
|
122
|
-
// process.exit()
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
// remove listener to process.on('message')
|
|
128
|
-
// which is sufficient to let child process die
|
|
129
|
-
// assuming nothing else keeps it alive
|
|
130
|
-
// process.once("SIGTERM", removeActionRequestListener)
|
|
131
|
-
// process.once("SIGINT", removeActionRequestListener)
|
|
132
|
-
|
|
133
|
-
setTimeout(() => {
|
|
134
|
-
sendToParent("ready")
|
|
135
|
-
})
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { parentPort } from "node:worker_threads"
|
|
2
|
-
import { uneval } from "@jsenv/uneval"
|
|
3
|
-
|
|
4
|
-
import { executeUsingDynamicImport } from "./execute_using_dynamic_import.js"
|
|
5
|
-
|
|
6
|
-
const ACTIONS_AVAILABLE = {
|
|
7
|
-
"execute-using-dynamic-import": executeUsingDynamicImport,
|
|
8
|
-
}
|
|
9
|
-
const ACTION_REQUEST_EVENT_NAME = "action"
|
|
10
|
-
const ACTION_RESPONSE_EVENT_NAME = "action-result"
|
|
11
|
-
const ACTION_RESPONSE_STATUS_FAILED = "action-failed"
|
|
12
|
-
const ACTION_RESPONSE_STATUS_COMPLETED = "action-completed"
|
|
13
|
-
|
|
14
|
-
const sendActionFailed = (error) => {
|
|
15
|
-
if (error.hasOwnProperty("toString")) {
|
|
16
|
-
delete error.toString
|
|
17
|
-
}
|
|
18
|
-
sendToParent(
|
|
19
|
-
ACTION_RESPONSE_EVENT_NAME,
|
|
20
|
-
// process.send algorithm does not send non enumerable values
|
|
21
|
-
// so use @jsenv/uneval
|
|
22
|
-
uneval(
|
|
23
|
-
{
|
|
24
|
-
status: ACTION_RESPONSE_STATUS_FAILED,
|
|
25
|
-
value: error,
|
|
26
|
-
},
|
|
27
|
-
{ ignoreSymbols: true },
|
|
28
|
-
),
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const sendActionCompleted = (value) => {
|
|
33
|
-
sendToParent(
|
|
34
|
-
ACTION_RESPONSE_EVENT_NAME,
|
|
35
|
-
// here we use JSON.stringify because we should not
|
|
36
|
-
// have non enumerable value (unlike there is on Error objects)
|
|
37
|
-
// otherwise uneval is quite slow to turn a giant object
|
|
38
|
-
// into a string (and value can be giant when using coverage)
|
|
39
|
-
JSON.stringify({
|
|
40
|
-
status: ACTION_RESPONSE_STATUS_COMPLETED,
|
|
41
|
-
value,
|
|
42
|
-
}),
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const sendToParent = (type, data) => {
|
|
47
|
-
// this can keep process alive longer than expected
|
|
48
|
-
// when source is a long string.
|
|
49
|
-
// It means node process may stay alive longer than expected
|
|
50
|
-
// the time to send the data to the parent.
|
|
51
|
-
parentPort.postMessage({
|
|
52
|
-
jsenv: true,
|
|
53
|
-
type,
|
|
54
|
-
data,
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const onceParentMessage = (type, callback) => {
|
|
59
|
-
const listener = (message) => {
|
|
60
|
-
if (message && message.jsenv && message.type === type) {
|
|
61
|
-
removeListener() // commenting this line keep this worker alive
|
|
62
|
-
callback(message.data)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const removeListener = () => {
|
|
66
|
-
parentPort.removeListener("message", listener)
|
|
67
|
-
}
|
|
68
|
-
parentPort.on("message", listener)
|
|
69
|
-
return removeListener
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const removeActionRequestListener = onceParentMessage(
|
|
73
|
-
ACTION_REQUEST_EVENT_NAME,
|
|
74
|
-
async ({ actionType, actionParams }) => {
|
|
75
|
-
const action = ACTIONS_AVAILABLE[actionType]
|
|
76
|
-
if (!action) {
|
|
77
|
-
sendActionFailed(new Error(`unknown action ${actionType}`))
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
let value
|
|
82
|
-
let failed = false
|
|
83
|
-
try {
|
|
84
|
-
value = await action(actionParams)
|
|
85
|
-
} catch (e) {
|
|
86
|
-
failed = true
|
|
87
|
-
value = e
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (failed) {
|
|
91
|
-
sendActionFailed(value)
|
|
92
|
-
} else {
|
|
93
|
-
sendActionCompleted(value)
|
|
94
|
-
}
|
|
95
|
-
if (actionParams.exitAfterAction) {
|
|
96
|
-
removeActionRequestListener()
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
setTimeout(() => {
|
|
102
|
-
sendToParent("ready")
|
|
103
|
-
})
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export const ExecOptions = {
|
|
2
|
-
fromExecArgv: (execArgv) => {
|
|
3
|
-
const execOptions = {}
|
|
4
|
-
let i = 0
|
|
5
|
-
while (i < execArgv.length) {
|
|
6
|
-
const execArg = execArgv[i]
|
|
7
|
-
const option = execOptionFromExecArg(execArg)
|
|
8
|
-
execOptions[option.name] = option.value
|
|
9
|
-
i++
|
|
10
|
-
}
|
|
11
|
-
return execOptions
|
|
12
|
-
},
|
|
13
|
-
toExecArgv: (execOptions) => {
|
|
14
|
-
const execArgv = []
|
|
15
|
-
Object.keys(execOptions).forEach((optionName) => {
|
|
16
|
-
const optionValue = execOptions[optionName]
|
|
17
|
-
if (optionValue === "unset") {
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
if (optionValue === "") {
|
|
21
|
-
execArgv.push(optionName)
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
execArgv.push(`${optionName}=${optionValue}`)
|
|
25
|
-
})
|
|
26
|
-
return execArgv
|
|
27
|
-
},
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const execOptionFromExecArg = (execArg) => {
|
|
31
|
-
const equalCharIndex = execArg.indexOf("=")
|
|
32
|
-
if (equalCharIndex === -1) {
|
|
33
|
-
return {
|
|
34
|
-
name: execArg,
|
|
35
|
-
value: "",
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const name = execArg.slice(0, equalCharIndex)
|
|
39
|
-
const value = execArg.slice(equalCharIndex + 1)
|
|
40
|
-
return {
|
|
41
|
-
name,
|
|
42
|
-
value,
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { writeFileSync } from "node:fs"
|
|
2
|
-
|
|
3
|
-
import { startJsCoverage } from "./profiler_v8_coverage.js"
|
|
4
|
-
import { startObservingPerformances } from "./node_execution_performance.js"
|
|
5
|
-
|
|
6
|
-
export const executeUsingDynamicImport = async ({
|
|
7
|
-
rootDirectoryUrl,
|
|
8
|
-
fileUrl,
|
|
9
|
-
collectPerformance,
|
|
10
|
-
coverageEnabled,
|
|
11
|
-
coverageConfig,
|
|
12
|
-
coverageMethodForNodeJs,
|
|
13
|
-
coverageFileUrl,
|
|
14
|
-
}) => {
|
|
15
|
-
const result = {}
|
|
16
|
-
const afterImportCallbacks = []
|
|
17
|
-
if (coverageEnabled && coverageMethodForNodeJs === "Profiler") {
|
|
18
|
-
const { filterV8Coverage } = await import(
|
|
19
|
-
"@jsenv/core/src/test/coverage/v8_coverage.js"
|
|
20
|
-
)
|
|
21
|
-
const { stopJsCoverage } = await startJsCoverage()
|
|
22
|
-
afterImportCallbacks.push(async () => {
|
|
23
|
-
const coverage = await stopJsCoverage()
|
|
24
|
-
const coverageLight = await filterV8Coverage(coverage, {
|
|
25
|
-
rootDirectoryUrl,
|
|
26
|
-
coverageConfig,
|
|
27
|
-
})
|
|
28
|
-
writeFileSync(
|
|
29
|
-
new URL(coverageFileUrl),
|
|
30
|
-
JSON.stringify(coverageLight, null, " "),
|
|
31
|
-
)
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
if (collectPerformance) {
|
|
35
|
-
const getPerformance = startObservingPerformances()
|
|
36
|
-
afterImportCallbacks.push(async () => {
|
|
37
|
-
const performance = await getPerformance()
|
|
38
|
-
result.performance = performance
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
const namespace = await import(fileUrl)
|
|
42
|
-
const namespaceResolved = {}
|
|
43
|
-
await Promise.all(
|
|
44
|
-
Object.keys(namespace).map(async (key) => {
|
|
45
|
-
const value = await namespace[key]
|
|
46
|
-
namespaceResolved[key] = value
|
|
47
|
-
}),
|
|
48
|
-
)
|
|
49
|
-
result.namespace = namespaceResolved
|
|
50
|
-
await afterImportCallbacks.reduce(async (previous, afterImportCallback) => {
|
|
51
|
-
await previous
|
|
52
|
-
await afterImportCallback()
|
|
53
|
-
}, Promise.resolve())
|
|
54
|
-
return result
|
|
55
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// https://nodejs.org/api/process.html#process_signal_events
|
|
2
|
-
const SIGINT_SIGNAL_NUMBER = 2
|
|
3
|
-
const SIGABORT_SIGNAL_NUMBER = 6
|
|
4
|
-
const SIGTERM_SIGNAL_NUMBER = 15
|
|
5
|
-
export const EXIT_CODES = {
|
|
6
|
-
SIGINT: 128 + SIGINT_SIGNAL_NUMBER,
|
|
7
|
-
SIGABORT: 128 + SIGABORT_SIGNAL_NUMBER,
|
|
8
|
-
SIGTERM: 128 + SIGTERM_SIGNAL_NUMBER,
|
|
9
|
-
}
|