@jsenv/core 27.3.2 → 27.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +16 -4
  2. package/dist/controllable_child_process.mjs +1 -0
  3. package/dist/controllable_worker_thread.mjs +1 -0
  4. package/dist/js/event_source_client.js +45 -24
  5. package/dist/js/execute_using_dynamic_import.js +5 -3
  6. package/dist/js/html_supervisor_installer.js +368 -139
  7. package/dist/main.js +668 -471
  8. package/package.json +5 -6
  9. package/src/build/build.js +6 -4
  10. package/src/build/graph_utils.js +14 -11
  11. package/src/execute/run.js +29 -28
  12. package/src/execute/runtimes/browsers/from_playwright.js +90 -92
  13. package/src/execute/runtimes/node/execute_using_dynamic_import.js +8 -2
  14. package/src/execute/runtimes/node/node_child_process.js +2 -0
  15. package/src/execute/runtimes/node/node_worker_thread.js +11 -6
  16. package/src/helpers/event_source/event_source.js +38 -17
  17. package/src/omega/errors.js +41 -9
  18. package/src/omega/kitchen.js +35 -19
  19. package/src/omega/omega_server.js +54 -1
  20. package/src/omega/server/file_service.js +30 -3
  21. package/src/omega/url_graph/url_graph_report.js +2 -4
  22. package/src/omega/url_graph.js +29 -16
  23. package/src/plugins/autoreload/dev_sse/client/event_source_client.js +8 -8
  24. package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +160 -172
  25. package/src/plugins/autoreload/jsenv_plugin_autoreload.js +0 -4
  26. package/src/plugins/bundling/js_module/bundle_js_module.js +0 -1
  27. package/src/plugins/html_supervisor/client/error_in_document.js +268 -121
  28. package/src/plugins/html_supervisor/client/html_supervisor_installer.js +47 -5
  29. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +37 -12
  30. package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +1 -2
  31. package/src/plugins/plugins.js +0 -2
  32. package/src/plugins/url_analysis/js/js_urls.js +0 -9
  33. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +3 -1
  34. package/src/test/coverage/report_to_coverage.js +16 -11
  35. package/src/test/execute_plan.js +3 -2
  36. package/src/test/execute_test_plan.js +3 -1
  37. package/src/test/logs_file_execution.js +60 -27
  38. package/src/test/logs_file_execution.test.mjs +41 -0
@@ -50,7 +50,7 @@ export const reportToCoverage = async (
50
50
  coverageMethodForNodeJs !== "NODE_V8_COVERAGE"
51
51
  ) {
52
52
  logger.warn(
53
- `No "coverageFileUrl" from execution named "${executionName}" of ${file}`,
53
+ `"${executionName}" execution of ${file} did not properly write coverage into ${executionResult.coverageFileUrl}`,
54
54
  )
55
55
  }
56
56
  },
@@ -152,18 +152,23 @@ const getCoverageFromReport = async ({ signal, report, onMissing }) => {
152
152
  const executionResultForFileOnRuntime =
153
153
  executionResultForFile[executionName]
154
154
  const { coverageFileUrl } = executionResultForFileOnRuntime
155
- if (!coverageFileUrl) {
156
- onMissing({
157
- executionName,
158
- file,
159
- executionResult: executionResultForFileOnRuntime,
160
- })
161
- return
155
+ let executionCoverage
156
+ try {
157
+ executionCoverage = JSON.parse(
158
+ String(readFileSync(new URL(coverageFileUrl))),
159
+ )
160
+ } catch (e) {
161
+ if (e.code === "ENOENT" || e.name === "SyntaxError") {
162
+ onMissing({
163
+ executionName,
164
+ file,
165
+ executionResult: executionResultForFileOnRuntime,
166
+ })
167
+ return
168
+ }
169
+ throw e
162
170
  }
163
171
 
164
- const executionCoverage = JSON.parse(
165
- String(readFileSync(new URL(coverageFileUrl))),
166
- )
167
172
  if (isV8Coverage(executionCoverage)) {
168
173
  v8Coverage = v8Coverage
169
174
  ? composeTwoV8Coverages(v8Coverage, executionCoverage)
@@ -143,7 +143,7 @@ export const executePlan = async (
143
143
  createDetailedMessage(
144
144
  `process.env.NODE_V8_COVERAGE is required to generate coverage for Node.js subprocesses`,
145
145
  {
146
- "suggestion": `Preprend NODE_V8_COVERAGE=.coverage/node to the command executing this process`,
146
+ "suggestion": `set process.env.NODE_V8_COVERAGE`,
147
147
  "suggestion 2": `use coverageMethodForNodeJs: "Profiler". But it means coverage for child_process and worker_thread cannot be collected`,
148
148
  },
149
149
  ),
@@ -224,7 +224,8 @@ export const executePlan = async (
224
224
  getCustomBabelPlugins: ({ clientRuntimeCompat }) => {
225
225
  if (
226
226
  coverageEnabled &&
227
- Object.keys(clientRuntimeCompat)[0] !== "chrome"
227
+ (coverageMethodForBrowsers !== "playwright_api" ||
228
+ Object.keys(clientRuntimeCompat)[0] !== "chrome")
228
229
  ) {
229
230
  return {
230
231
  "transform-instrument": [
@@ -67,7 +67,9 @@ export const executeTestPlan = async ({
67
67
  },
68
68
  coverageIncludeMissing = true,
69
69
  coverageAndExecutionAllowed = false,
70
- coverageMethodForNodeJs = "NODE_V8_COVERAGE", // "Profiler" also accepted
70
+ coverageMethodForNodeJs = process.env.NODE_V8_COVERAGE
71
+ ? "NODE_V8_COVERAGE"
72
+ : "Profiler",
71
73
  coverageMethodForBrowsers = "playwright_api", // "istanbul" also accepted
72
74
  coverageV8ConflictWarning = true,
73
75
  coverageTempDirectoryRelativeUrl = "./.coverage/tmp/",
@@ -217,7 +217,6 @@ const formatConsoleCalls = (consoleCalls) => {
217
217
  if (consoleCalls.length === 0) {
218
218
  return ""
219
219
  }
220
-
221
220
  const repartition = {
222
221
  debug: 0,
223
222
  info: 0,
@@ -225,17 +224,10 @@ const formatConsoleCalls = (consoleCalls) => {
225
224
  error: 0,
226
225
  log: 0,
227
226
  }
228
- let consoleOutput = ``
229
227
  consoleCalls.forEach((consoleCall) => {
230
228
  repartition[consoleCall.type]++
231
- const text = consoleCall.text
232
- const textFormatted = prefixFirstAndIndentRemainingLines({
233
- prefix: CONSOLE_ICONS[consoleCall.type],
234
- text,
235
- trimLastLine: consoleCall === consoleCalls[consoleCalls.length - 1],
236
- })
237
- consoleOutput += textFormatted
238
229
  })
230
+ const consoleOutput = formatConsoleOutput(consoleCalls)
239
231
 
240
232
  return `${ANSI.color(
241
233
  `-------- ${formatConsoleSummary(repartition)} --------`,
@@ -245,6 +237,65 @@ ${consoleOutput}
245
237
  ${ANSI.color(`-------------------------`, ANSI.GREY)}`
246
238
  }
247
239
 
240
+ export const formatConsoleOutput = (consoleCalls) => {
241
+ // inside Node.js you can do process.stdout.write()
242
+ // and in that case the consoleCall is not suffixed with "\n"
243
+ // we want to keep these calls together in the output
244
+ const regroupedCalls = []
245
+ consoleCalls.forEach((consoleCall, index) => {
246
+ if (index === 0) {
247
+ regroupedCalls.push(consoleCall)
248
+ return
249
+ }
250
+ const previousCall = consoleCalls[index - 1]
251
+ if (previousCall.type !== consoleCall.type) {
252
+ regroupedCalls.push(consoleCall)
253
+ return
254
+ }
255
+ if (previousCall.text.endsWith("\n")) {
256
+ regroupedCalls.push(consoleCall)
257
+ return
258
+ }
259
+ if (previousCall.text.endsWith("\r")) {
260
+ regroupedCalls.push(consoleCall)
261
+ return
262
+ }
263
+ const previousRegroupedCallIndex = regroupedCalls.length - 1
264
+ const previousRegroupedCall = regroupedCalls[previousRegroupedCallIndex]
265
+ previousRegroupedCall.text = `${previousRegroupedCall.text}${consoleCall.text}`
266
+ })
267
+
268
+ let consoleOutput = ``
269
+ regroupedCalls.forEach((regroupedCall, index) => {
270
+ const text = regroupedCall.text
271
+ const textFormatted = prefixFirstAndIndentRemainingLines({
272
+ prefix: CONSOLE_ICONS[regroupedCall.type],
273
+ text,
274
+ trimLastLine: index === regroupedCalls.length - 1,
275
+ })
276
+ consoleOutput += textFormatted
277
+ })
278
+ return consoleOutput
279
+ }
280
+
281
+ const prefixFirstAndIndentRemainingLines = ({ prefix, text, trimLastLine }) => {
282
+ const lines = text.split(/\r?\n/)
283
+ const firstLine = lines.shift()
284
+ let result = `${prefix} ${firstLine}`
285
+ let i = 0
286
+ const indentation = ` `
287
+ while (i < lines.length) {
288
+ const line = lines[i].trim()
289
+ i++
290
+ result += line.length
291
+ ? `\n${indentation}${line}`
292
+ : trimLastLine && i === lines.length
293
+ ? ""
294
+ : `\n`
295
+ }
296
+ return result
297
+ }
298
+
248
299
  const CONSOLE_ICONS = {
249
300
  debug: UNICODE.DEBUG,
250
301
  info: UNICODE.INFO,
@@ -274,24 +325,6 @@ const formatConsoleSummary = (repartition) => {
274
325
  return `console (${parts.join(" ")})`
275
326
  }
276
327
 
277
- const prefixFirstAndIndentRemainingLines = ({ prefix, text, trimLastLine }) => {
278
- const lines = text.split(/\r?\n/)
279
- const firstLine = lines.shift()
280
- let result = `${prefix} ${firstLine}`
281
- let i = 0
282
- const indentation = ` `
283
- while (i < lines.length) {
284
- const line = lines[i].trim()
285
- i++
286
- result += line.length
287
- ? `\n${indentation}${line}`
288
- : trimLastLine && i === lines.length
289
- ? ""
290
- : `\n`
291
- }
292
- return result
293
- }
294
-
295
328
  const formatExecution = ({ label, details = {}, consoleOutput }) => {
296
329
  let message = ``
297
330
  message += label
@@ -0,0 +1,41 @@
1
+ import { assert } from "@jsenv/assert"
2
+
3
+ import { formatConsoleOutput } from "./logs_file_execution.js"
4
+
5
+ {
6
+ const actual = formatConsoleOutput([
7
+ { type: "log", text: "a\n" },
8
+ { type: "log", text: "b\n" },
9
+ ])
10
+ const expected = ` a
11
+ b`
12
+ assert({ actual, expected })
13
+ }
14
+
15
+ {
16
+ const actual = formatConsoleOutput([
17
+ { type: "log", text: "a" },
18
+ { type: "log", text: "b" },
19
+ ])
20
+ const expected = ` ab`
21
+ assert({ actual, expected })
22
+ }
23
+
24
+ {
25
+ const actual = formatConsoleOutput([
26
+ {
27
+ type: "log",
28
+ text: `1
29
+ 2`,
30
+ },
31
+ {
32
+ type: "log",
33
+ text: `alpha
34
+ beta`,
35
+ },
36
+ ])
37
+ const expected = ` 1
38
+ 2alpha
39
+ beta`
40
+ assert({ actual, expected })
41
+ }