@jsenv/core 27.0.1 → 27.1.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/dist/main.js CHANGED
@@ -332,23 +332,27 @@ const canUseUnicode = isUnicodeSupported();
332
332
  const COMMAND_RAW = canUseUnicode ? `❯` : `>`;
333
333
  const OK_RAW = canUseUnicode ? `✔` : `√`;
334
334
  const FAILURE_RAW = canUseUnicode ? `✖` : `×`;
335
+ const DEBUG_RAW = canUseUnicode ? `◆` : `♦`;
335
336
  const INFO_RAW = canUseUnicode ? `ℹ` : `i`;
336
337
  const WARNING_RAW = canUseUnicode ? `⚠` : `‼`;
337
338
  const COMMAND = ANSI.color(COMMAND_RAW, ANSI.GREY); // ANSI_MAGENTA)
338
339
 
339
340
  const OK = ANSI.color(OK_RAW, ANSI.GREEN);
340
341
  const FAILURE = ANSI.color(FAILURE_RAW, ANSI.RED);
342
+ const DEBUG = ANSI.color(DEBUG_RAW, ANSI.GREY);
341
343
  const INFO = ANSI.color(INFO_RAW, ANSI.BLUE);
342
344
  const WARNING = ANSI.color(WARNING_RAW, ANSI.YELLOW);
343
345
  const UNICODE = {
344
346
  COMMAND,
345
347
  OK,
346
348
  FAILURE,
349
+ DEBUG,
347
350
  INFO,
348
351
  WARNING,
349
352
  COMMAND_RAW,
350
353
  OK_RAW,
351
354
  FAILURE_RAW,
355
+ DEBUG_RAW,
352
356
  INFO_RAW,
353
357
  WARNING_RAW,
354
358
  supported: canUseUnicode
@@ -19850,7 +19854,7 @@ const rollupPluginJsenv = ({
19850
19854
  outputOptions: outputOptions => {
19851
19855
  // const sourcemapFile = buildDirectoryUrl
19852
19856
  Object.assign(outputOptions, {
19853
- format: "esm",
19857
+ format: jsModuleUrlInfos.some(jsModuleUrlInfo => jsModuleUrlInfo.filename.endsWith(".cjs")) ? "cjs" : "esm",
19854
19858
  dir: fileUrlConverter.asFilePath(buildDirectoryUrl),
19855
19859
  sourcemap: sourcemaps === "file" || sourcemaps === "inline",
19856
19860
  // sourcemapFile,
@@ -21446,6 +21450,7 @@ const createUrlInfo = url => {
21446
21450
  content: undefined,
21447
21451
  sourcemap: null,
21448
21452
  sourcemapReference: null,
21453
+ sourcemapIsWrong: false,
21449
21454
  timing: {},
21450
21455
  headers: {}
21451
21456
  };
@@ -21891,7 +21896,8 @@ const createUrlInfoTransformer = ({
21891
21896
  type,
21892
21897
  contentType,
21893
21898
  content,
21894
- sourcemap
21899
+ sourcemap,
21900
+ sourcemapIsWrong
21895
21901
  } = transformations;
21896
21902
 
21897
21903
  if (type) {
@@ -21910,7 +21916,17 @@ const createUrlInfoTransformer = ({
21910
21916
  const sourcemapNormalized = normalizeSourcemap(urlInfo, sourcemap);
21911
21917
  const finalSourcemap = await composeTwoSourcemaps(urlInfo.sourcemap, sourcemapNormalized);
21912
21918
  const finalSourcemapNormalized = normalizeSourcemap(urlInfo, finalSourcemap);
21913
- urlInfo.sourcemap = finalSourcemapNormalized;
21919
+ urlInfo.sourcemap = finalSourcemapNormalized; // A plugin is allowed to modify url content
21920
+ // without returning a sourcemap
21921
+ // This is the case for preact and react plugins.
21922
+ // They are currently generating wrong source mappings
21923
+ // when used.
21924
+ // Generating the correct sourcemap in this situation
21925
+ // is a nightmare no-one could solve in years so
21926
+ // jsenv won't emit a warning and use the following strategy:
21927
+ // "no sourcemap is better than wrong sourcemap"
21928
+
21929
+ urlInfo.sourcemapIsWrong = sourcemapIsWrong;
21914
21930
  }
21915
21931
  };
21916
21932
 
@@ -21939,16 +21955,18 @@ const createUrlInfoTransformer = ({
21939
21955
 
21940
21956
  sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ");
21941
21957
 
21942
- if (sourcemaps === "inline") {
21943
- sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
21944
- }
21958
+ if (!urlInfo.sourcemapIsWrong) {
21959
+ if (sourcemaps === "inline") {
21960
+ sourcemapReference.generatedSpecifier = generateSourcemapDataUrl(sourcemap);
21961
+ }
21945
21962
 
21946
- if (sourcemaps === "file" || sourcemaps === "inline") {
21947
- urlInfo.content = SOURCEMAP.writeComment({
21948
- contentType: urlInfo.contentType,
21949
- content: urlInfo.content,
21950
- specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
21951
- });
21963
+ if (sourcemaps === "file" || sourcemaps === "inline") {
21964
+ urlInfo.content = SOURCEMAP.writeComment({
21965
+ contentType: urlInfo.contentType,
21966
+ content: urlInfo.content,
21967
+ specifier: sourcemaps === "file" && sourcemapsRelativeSources ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url) : sourcemapReference.generatedSpecifier
21968
+ });
21969
+ }
21952
21970
  }
21953
21971
  } else if (urlInfo.sourcemapReference) {
21954
21972
  // in the end we don't use the sourcemap placeholder
@@ -24839,6 +24857,8 @@ const createExecutionLog = ({
24839
24857
  }, {
24840
24858
  completedExecutionLogAbbreviation,
24841
24859
  counters,
24860
+ logRuntime,
24861
+ logEachDuration,
24842
24862
  timeEllapsed,
24843
24863
  memoryHeap
24844
24864
  }) => {
@@ -24871,8 +24891,12 @@ const createExecutionLog = ({
24871
24891
  label: `${description}${summary}`,
24872
24892
  details: {
24873
24893
  file: fileRelativeUrl,
24874
- runtime: `${runtimeName}/${runtimeVersion}`,
24875
- duration: status === "executing" ? msAsEllapsedTime(Date.now() - startMs) : msAsDuration(endMs - startMs),
24894
+ ...(logRuntime ? {
24895
+ runtime: `${runtimeName}/${runtimeVersion}`
24896
+ } : {}),
24897
+ ...(logEachDuration ? {
24898
+ duration: status === "executing" ? msAsEllapsedTime(Date.now() - startMs) : msAsDuration(endMs - startMs)
24899
+ } : {}),
24876
24900
  ...(error ? {
24877
24901
  error: error.stack || error.message || error
24878
24902
  } : {})
@@ -25026,22 +25050,93 @@ const descriptionFormatters = {
25026
25050
  };
25027
25051
 
25028
25052
  const formatConsoleCalls = consoleCalls => {
25029
- const consoleOutput = consoleCalls.reduce((previous, {
25030
- text
25031
- }) => {
25032
- return `${previous}${text}`;
25033
- }, "");
25034
- const consoleOutputTrimmed = consoleOutput.trim();
25035
-
25036
- if (consoleOutputTrimmed === "") {
25053
+ if (consoleCalls.length === 0) {
25037
25054
  return "";
25038
25055
  }
25039
25056
 
25040
- return `${ANSI.color(`-------- console output --------`, ANSI.GREY)}
25041
- ${consoleOutputTrimmed}
25057
+ const repartition = {
25058
+ debug: 0,
25059
+ info: 0,
25060
+ warning: 0,
25061
+ error: 0,
25062
+ log: 0
25063
+ };
25064
+ let consoleOutput = ``;
25065
+ consoleCalls.forEach(consoleCall => {
25066
+ repartition[consoleCall.type]++;
25067
+ const text = consoleCall.text;
25068
+ const textFormatted = prefixFirstAndIndentRemainingLines({
25069
+ prefix: CONSOLE_ICONS[consoleCall.type],
25070
+ text,
25071
+ trimLastLine: consoleCall === consoleCalls[consoleCalls.length - 1]
25072
+ });
25073
+ consoleOutput += textFormatted;
25074
+ });
25075
+ return `${ANSI.color(`-------- ${formatConsoleSummary(repartition)} --------`, ANSI.GREY)}
25076
+ ${consoleOutput}
25042
25077
  ${ANSI.color(`-------------------------`, ANSI.GREY)}`;
25043
25078
  };
25044
25079
 
25080
+ const CONSOLE_ICONS = {
25081
+ debug: UNICODE.DEBUG,
25082
+ info: UNICODE.INFO,
25083
+ warning: UNICODE.WARNING,
25084
+ error: UNICODE.FAILURE,
25085
+ log: " "
25086
+ };
25087
+
25088
+ const formatConsoleSummary = repartition => {
25089
+ const {
25090
+ debug,
25091
+ info,
25092
+ warning,
25093
+ error
25094
+ } = repartition;
25095
+ const parts = [];
25096
+
25097
+ if (error) {
25098
+ parts.push(`${CONSOLE_ICONS.error} ${error}`);
25099
+ }
25100
+
25101
+ if (warning) {
25102
+ parts.push(`${CONSOLE_ICONS.warning} ${warning}`);
25103
+ }
25104
+
25105
+ if (info) {
25106
+ parts.push(`${CONSOLE_ICONS.info} ${info}`);
25107
+ }
25108
+
25109
+ if (debug) {
25110
+ parts.push(`${CONSOLE_ICONS.debug} ${debug}`);
25111
+ }
25112
+
25113
+ if (parts.length === 0) {
25114
+ return `console`;
25115
+ }
25116
+
25117
+ return `console (${parts.join(" ")})`;
25118
+ };
25119
+
25120
+ const prefixFirstAndIndentRemainingLines = ({
25121
+ prefix,
25122
+ text,
25123
+ trimLastLine
25124
+ }) => {
25125
+ const lines = text.split(/\r?\n/);
25126
+ const firstLine = lines.shift();
25127
+ let result = `${prefix} ${firstLine}`;
25128
+ let i = 0;
25129
+ const indentation = ` `;
25130
+
25131
+ while (i < lines.length) {
25132
+ const line = lines[i].trim();
25133
+ i++;
25134
+ result += line.length ? `\n${indentation}${line}` : trimLastLine && i === lines.length ? "" : `\n`;
25135
+ }
25136
+
25137
+ return result;
25138
+ };
25139
+
25045
25140
  const formatExecution = ({
25046
25141
  label,
25047
25142
  details = {},
@@ -25066,6 +25161,8 @@ const executePlan = async (plan, {
25066
25161
  signal,
25067
25162
  handleSIGINT,
25068
25163
  logger,
25164
+ logRuntime,
25165
+ logEachDuration,
25069
25166
  logSummary,
25070
25167
  logTimeUsage,
25071
25168
  logMemoryHeapUsage,
@@ -25361,6 +25458,8 @@ const executePlan = async (plan, {
25361
25458
  render: () => {
25362
25459
  return createExecutionLog(beforeExecutionInfo, {
25363
25460
  counters,
25461
+ logRuntime,
25462
+ logEachDuration,
25364
25463
  ...(logTimeUsage ? {
25365
25464
  timeEllapsed: Date.now() - startMs
25366
25465
  } : {}),
@@ -25434,6 +25533,8 @@ const executePlan = async (plan, {
25434
25533
  let log = createExecutionLog(afterExecutionInfo, {
25435
25534
  completedExecutionLogAbbreviation,
25436
25535
  counters,
25536
+ logRuntime,
25537
+ logEachDuration,
25437
25538
  ...(logTimeUsage ? {
25438
25539
  timeEllapsed: Date.now() - startMs
25439
25540
  } : {}),
@@ -25478,6 +25579,7 @@ const executePlan = async (plan, {
25478
25579
  });
25479
25580
 
25480
25581
  if (!keepRunning) {
25582
+ logger.debug("stopAfterAllSignal.notify()");
25481
25583
  await stopAfterAllSignal.notify();
25482
25584
  }
25483
25585
 
@@ -25639,6 +25741,8 @@ const executeTestPlan = async ({
25639
25741
  signal = new AbortController().signal,
25640
25742
  handleSIGINT = true,
25641
25743
  logLevel = "info",
25744
+ logRuntime = true,
25745
+ logEachDuration = true,
25642
25746
  logSummary = true,
25643
25747
  logTimeUsage = false,
25644
25748
  logMemoryHeapUsage = false,
@@ -25736,6 +25840,8 @@ const executeTestPlan = async ({
25736
25840
  logger,
25737
25841
  logLevel,
25738
25842
  logSummary,
25843
+ logRuntime,
25844
+ logEachDuration,
25739
25845
  logTimeUsage,
25740
25846
  logMemoryHeapUsage,
25741
25847
  logFileRelativeUrl,
@@ -25888,7 +25994,7 @@ const createRuntimeFromPlaywright = ({
25888
25994
 
25889
25995
  runtime.run = async ({
25890
25996
  signal = new AbortController().signal,
25891
- // logger,
25997
+ logger,
25892
25998
  rootDirectoryUrl,
25893
25999
  fileRelativeUrl,
25894
26000
  server,
@@ -25947,10 +26053,10 @@ const createRuntimeFromPlaywright = ({
25947
26053
  };
25948
26054
 
25949
26055
  browser.on("disconnected", disconnectedCallback);
25950
- }) : Promise.resolve(); // for some reason without this 100ms timeout
26056
+ }) : Promise.resolve(); // for some reason without this 150ms timeout
25951
26057
  // browser.close() never resolves (playwright does not like something)
25952
26058
 
25953
- await new Promise(resolve => setTimeout(resolve, 100));
26059
+ await new Promise(resolve => setTimeout(resolve, 150));
25954
26060
 
25955
26061
  try {
25956
26062
  await browser.close();
@@ -26148,6 +26254,7 @@ const createRuntimeFromPlaywright = ({
26148
26254
  stopAfterAllSignal.notify = async () => {
26149
26255
  await notifyPrevious();
26150
26256
  browser.removeListener("disconnected", disconnectedCallback);
26257
+ logger.debug(`stopAfterAllSignal notified -> closing ${browserName}`);
26151
26258
  await closeBrowser();
26152
26259
  };
26153
26260
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.1",
3
+ "version": "27.1.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -43,26 +43,26 @@
43
43
  "eslint": "npx eslint . --ext=.js,.mjs,.cjs,.html",
44
44
  "dev": "node --conditions=development ./scripts/dev/dev.mjs",
45
45
  "test": "node --conditions=development ./scripts/test/test.mjs",
46
- "test-packages": "npm run test --workspaces --if-present -- --workspace",
46
+ "test:coverage": "npm run test -- --coverage",
47
47
  "build": "node --conditions=development ./scripts/build/build.mjs",
48
- "start_file_server": "node ./scripts/dev/start_file_server.mjs",
49
- "workspace-versions": "node ./scripts/publish/workspace_versions.mjs",
50
- "workspace-publish": "node ./scripts/publish/workspace_publish.mjs",
48
+ "workspace:test": "npm run test --workspaces --if-present -- --workspace",
49
+ "workspace:versions": "node ./scripts/publish/workspace_versions.mjs",
50
+ "workspace:publish": "node ./scripts/publish/workspace_publish.mjs",
51
51
  "performances": "node --expose-gc ./scripts/performance/generate_performance_report.mjs --log --once",
52
52
  "file-size": "node ./scripts/file_size/file_size.mjs --log",
53
+ "start_file_server": "node ./scripts/dev/start_file_server.mjs",
53
54
  "prettier": "prettier --write .",
54
55
  "playwright-install": "npx playwright install-deps && npx playwright install",
55
56
  "certificate-install": "node ./scripts/dev/install_certificate_authority.mjs",
56
- "test-with-coverage": "npm run test -- --coverage",
57
57
  "prepublishOnly": "npm run build"
58
58
  },
59
59
  "optionalDependencies": {
60
60
  "playwright": "1.x"
61
61
  },
62
62
  "dependencies": {
63
- "@babel/plugin-proposal-dynamic-import": "7.16.7",
63
+ "@babel/plugin-proposal-dynamic-import": "7.18.6",
64
64
  "@babel/plugin-transform-modules-systemjs": "7.18.6",
65
- "@babel/plugin-transform-modules-umd": "7.18.0",
65
+ "@babel/plugin-transform-modules-umd": "7.18.6",
66
66
  "@c88/v8-coverage": "0.1.1",
67
67
  "@financial-times/polyfill-useragent-normaliser": "2.0.1",
68
68
  "@jsenv/ast": "1.1.1",
@@ -71,13 +71,13 @@
71
71
  "@jsenv/importmap": "1.2.1",
72
72
  "@jsenv/integrity": "0.0.1",
73
73
  "@jsenv/node-esm-resolution": "0.1.0",
74
- "@jsenv/server": "12.7.4",
74
+ "@jsenv/server": "12.7.5",
75
75
  "@jsenv/uneval": "1.6.0",
76
76
  "@jsenv/url-meta": "7.0.0",
77
77
  "@jsenv/urls": "1.2.6",
78
78
  "@jsenv/utils": "2.0.1",
79
79
  "@jsenv/babel-plugins": "1.0.5",
80
- "@jsenv/log": "3.0.2",
80
+ "@jsenv/log": "3.1.0",
81
81
  "@jsenv/sourcemap": "1.0.1",
82
82
  "acorn-import-assertions": "1.8.0",
83
83
  "cuid": "2.1.8",
@@ -96,9 +96,9 @@
96
96
  },
97
97
  "devDependencies": {
98
98
  "@babel/eslint-parser": "7.18.2",
99
- "@babel/plugin-syntax-import-assertions": "7.17.12",
99
+ "@babel/plugin-syntax-import-assertions": "7.18.6",
100
100
  "@jsenv/assert": "2.6.0",
101
- "@jsenv/eslint-config": "16.0.9",
101
+ "@jsenv/eslint-config": "16.1.0",
102
102
  "@jsenv/file-size-impact": "13.0.1",
103
103
  "@jsenv/https-local": "2.1.0",
104
104
  "@jsenv/package-workspace": "0.4.1",
@@ -30,7 +30,7 @@ export const createRuntimeFromPlaywright = ({
30
30
  let browserAndContextPromise
31
31
  runtime.run = async ({
32
32
  signal = new AbortController().signal,
33
- // logger,
33
+ logger,
34
34
  rootDirectoryUrl,
35
35
  fileRelativeUrl,
36
36
  server,
@@ -82,9 +82,9 @@ export const createRuntimeFromPlaywright = ({
82
82
  browser.on("disconnected", disconnectedCallback)
83
83
  })
84
84
  : Promise.resolve()
85
- // for some reason without this 100ms timeout
85
+ // for some reason without this 150ms timeout
86
86
  // browser.close() never resolves (playwright does not like something)
87
- await new Promise((resolve) => setTimeout(resolve, 100))
87
+ await new Promise((resolve) => setTimeout(resolve, 150))
88
88
  try {
89
89
  await browser.close()
90
90
  } catch (e) {
@@ -275,6 +275,9 @@ export const createRuntimeFromPlaywright = ({
275
275
  stopAfterAllSignal.notify = async () => {
276
276
  await notifyPrevious()
277
277
  browser.removeListener("disconnected", disconnectedCallback)
278
+ logger.debug(
279
+ `stopAfterAllSignal notified -> closing ${browserName}`,
280
+ )
278
281
  await closeBrowser()
279
282
  }
280
283
  }
@@ -117,7 +117,8 @@ export const createUrlInfoTransformer = ({
117
117
  if (!transformations) {
118
118
  return
119
119
  }
120
- const { type, contentType, content, sourcemap } = transformations
120
+ const { type, contentType, content, sourcemap, sourcemapIsWrong } =
121
+ transformations
121
122
  if (type) {
122
123
  urlInfo.type = type
123
124
  }
@@ -138,6 +139,16 @@ export const createUrlInfoTransformer = ({
138
139
  finalSourcemap,
139
140
  )
140
141
  urlInfo.sourcemap = finalSourcemapNormalized
142
+ // A plugin is allowed to modify url content
143
+ // without returning a sourcemap
144
+ // This is the case for preact and react plugins.
145
+ // They are currently generating wrong source mappings
146
+ // when used.
147
+ // Generating the correct sourcemap in this situation
148
+ // is a nightmare no-one could solve in years so
149
+ // jsenv won't emit a warning and use the following strategy:
150
+ // "no sourcemap is better than wrong sourcemap"
151
+ urlInfo.sourcemapIsWrong = sourcemapIsWrong
141
152
  }
142
153
  }
143
154
 
@@ -162,19 +173,21 @@ export const createUrlInfoTransformer = ({
162
173
  })
163
174
  }
164
175
  sourcemapUrlInfo.content = JSON.stringify(sourcemap, null, " ")
165
- if (sourcemaps === "inline") {
166
- sourcemapReference.generatedSpecifier =
167
- generateSourcemapDataUrl(sourcemap)
168
- }
169
- if (sourcemaps === "file" || sourcemaps === "inline") {
170
- urlInfo.content = SOURCEMAP.writeComment({
171
- contentType: urlInfo.contentType,
172
- content: urlInfo.content,
173
- specifier:
174
- sourcemaps === "file" && sourcemapsRelativeSources
175
- ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
176
- : sourcemapReference.generatedSpecifier,
177
- })
176
+ if (!urlInfo.sourcemapIsWrong) {
177
+ if (sourcemaps === "inline") {
178
+ sourcemapReference.generatedSpecifier =
179
+ generateSourcemapDataUrl(sourcemap)
180
+ }
181
+ if (sourcemaps === "file" || sourcemaps === "inline") {
182
+ urlInfo.content = SOURCEMAP.writeComment({
183
+ contentType: urlInfo.contentType,
184
+ content: urlInfo.content,
185
+ specifier:
186
+ sourcemaps === "file" && sourcemapsRelativeSources
187
+ ? urlToRelativeUrl(sourcemapReference.url, urlInfo.url)
188
+ : sourcemapReference.generatedSpecifier,
189
+ })
190
+ }
178
191
  }
179
192
  } else if (urlInfo.sourcemapReference) {
180
193
  // in the end we don't use the sourcemap placeholder
@@ -215,6 +215,7 @@ const createUrlInfo = (url) => {
215
215
 
216
216
  sourcemap: null,
217
217
  sourcemapReference: null,
218
+ sourcemapIsWrong: false,
218
219
  timing: {},
219
220
  headers: {},
220
221
  }
@@ -147,7 +147,11 @@ const rollupPluginJsenv = ({
147
147
  outputOptions: (outputOptions) => {
148
148
  // const sourcemapFile = buildDirectoryUrl
149
149
  Object.assign(outputOptions, {
150
- format: "esm",
150
+ format: jsModuleUrlInfos.some((jsModuleUrlInfo) =>
151
+ jsModuleUrlInfo.filename.endsWith(".cjs"),
152
+ )
153
+ ? "cjs"
154
+ : "esm",
151
155
  dir: fileUrlConverter.asFilePath(buildDirectoryUrl),
152
156
  sourcemap: sourcemaps === "file" || sourcemaps === "inline",
153
157
  // sourcemapFile,
@@ -37,6 +37,8 @@ export const executePlan = async (
37
37
  signal,
38
38
  handleSIGINT,
39
39
  logger,
40
+ logRuntime,
41
+ logEachDuration,
40
42
  logSummary,
41
43
  logTimeUsage,
42
44
  logMemoryHeapUsage,
@@ -338,6 +340,8 @@ export const executePlan = async (
338
340
  render: () => {
339
341
  return createExecutionLog(beforeExecutionInfo, {
340
342
  counters,
343
+ logRuntime,
344
+ logEachDuration,
341
345
  ...(logTimeUsage
342
346
  ? {
343
347
  timeEllapsed: Date.now() - startMs,
@@ -411,6 +415,8 @@ export const executePlan = async (
411
415
  let log = createExecutionLog(afterExecutionInfo, {
412
416
  completedExecutionLogAbbreviation,
413
417
  counters,
418
+ logRuntime,
419
+ logEachDuration,
414
420
  ...(logTimeUsage
415
421
  ? {
416
422
  timeEllapsed: Date.now() - startMs,
@@ -457,6 +463,7 @@ export const executePlan = async (
457
463
  },
458
464
  })
459
465
  if (!keepRunning) {
466
+ logger.debug("stopAfterAllSignal.notify()")
460
467
  await stopAfterAllSignal.notify()
461
468
  }
462
469
 
@@ -36,6 +36,8 @@ export const executeTestPlan = async ({
36
36
  signal = new AbortController().signal,
37
37
  handleSIGINT = true,
38
38
  logLevel = "info",
39
+ logRuntime = true,
40
+ logEachDuration = true,
39
41
  logSummary = true,
40
42
  logTimeUsage = false,
41
43
  logMemoryHeapUsage = false,
@@ -138,6 +140,8 @@ export const executeTestPlan = async ({
138
140
  logger,
139
141
  logLevel,
140
142
  logSummary,
143
+ logRuntime,
144
+ logEachDuration,
141
145
  logTimeUsage,
142
146
  logMemoryHeapUsage,
143
147
  logFileRelativeUrl,
@@ -19,7 +19,14 @@ export const createExecutionLog = (
19
19
  startMs,
20
20
  endMs,
21
21
  },
22
- { completedExecutionLogAbbreviation, counters, timeEllapsed, memoryHeap },
22
+ {
23
+ completedExecutionLogAbbreviation,
24
+ counters,
25
+ logRuntime,
26
+ logEachDuration,
27
+ timeEllapsed,
28
+ memoryHeap,
29
+ },
23
30
  ) => {
24
31
  const { status } = executionResult
25
32
  const descriptionFormatter = descriptionFormatters[status]
@@ -43,11 +50,15 @@ export const createExecutionLog = (
43
50
  label: `${description}${summary}`,
44
51
  details: {
45
52
  file: fileRelativeUrl,
46
- runtime: `${runtimeName}/${runtimeVersion}`,
47
- duration:
48
- status === "executing"
49
- ? msAsEllapsedTime(Date.now() - startMs)
50
- : msAsDuration(endMs - startMs),
53
+ ...(logRuntime ? { runtime: `${runtimeName}/${runtimeVersion}` } : {}),
54
+ ...(logEachDuration
55
+ ? {
56
+ duration:
57
+ status === "executing"
58
+ ? msAsEllapsedTime(Date.now() - startMs)
59
+ : msAsDuration(endMs - startMs),
60
+ }
61
+ : {}),
51
62
  ...(error ? { error: error.stack || error.message || error } : {}),
52
63
  },
53
64
  consoleOutput,
@@ -203,18 +214,84 @@ const descriptionFormatters = {
203
214
  }
204
215
 
205
216
  const formatConsoleCalls = (consoleCalls) => {
206
- const consoleOutput = consoleCalls.reduce((previous, { text }) => {
207
- return `${previous}${text}`
208
- }, "")
209
- const consoleOutputTrimmed = consoleOutput.trim()
210
- if (consoleOutputTrimmed === "") {
217
+ if (consoleCalls.length === 0) {
211
218
  return ""
212
219
  }
213
- return `${ANSI.color(`-------- console output --------`, ANSI.GREY)}
214
- ${consoleOutputTrimmed}
220
+
221
+ const repartition = {
222
+ debug: 0,
223
+ info: 0,
224
+ warning: 0,
225
+ error: 0,
226
+ log: 0,
227
+ }
228
+ let consoleOutput = ``
229
+ consoleCalls.forEach((consoleCall) => {
230
+ 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
+ })
239
+
240
+ return `${ANSI.color(
241
+ `-------- ${formatConsoleSummary(repartition)} --------`,
242
+ ANSI.GREY,
243
+ )}
244
+ ${consoleOutput}
215
245
  ${ANSI.color(`-------------------------`, ANSI.GREY)}`
216
246
  }
217
247
 
248
+ const CONSOLE_ICONS = {
249
+ debug: UNICODE.DEBUG,
250
+ info: UNICODE.INFO,
251
+ warning: UNICODE.WARNING,
252
+ error: UNICODE.FAILURE,
253
+ log: " ",
254
+ }
255
+
256
+ const formatConsoleSummary = (repartition) => {
257
+ const { debug, info, warning, error } = repartition
258
+ const parts = []
259
+ if (error) {
260
+ parts.push(`${CONSOLE_ICONS.error} ${error}`)
261
+ }
262
+ if (warning) {
263
+ parts.push(`${CONSOLE_ICONS.warning} ${warning}`)
264
+ }
265
+ if (info) {
266
+ parts.push(`${CONSOLE_ICONS.info} ${info}`)
267
+ }
268
+ if (debug) {
269
+ parts.push(`${CONSOLE_ICONS.debug} ${debug}`)
270
+ }
271
+ if (parts.length === 0) {
272
+ return `console`
273
+ }
274
+ return `console (${parts.join(" ")})`
275
+ }
276
+
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
+
218
295
  const formatExecution = ({ label, details = {}, consoleOutput }) => {
219
296
  let message = ``
220
297
  message += label