@jsenv/humanize 1.3.1 → 1.5.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.
@@ -1,27 +1,73 @@
1
1
  const createDetailedMessage = (message, details = {}) => {
2
- let string = "".concat(message);
3
- Object.keys(details).forEach(key => {
4
- const value = details[key];
5
- string += "\n--- ".concat(key, " ---\n").concat(Array.isArray(value) ? value.join("\n") : value);
6
- });
7
- return string;
2
+ let text = "".concat(message);
3
+ const namedSectionsText = renderNamedSections(details);
4
+ if (namedSectionsText) {
5
+ text += "\n".concat(namedSectionsText);
6
+ }
7
+ return text;
8
+ };
9
+ const renderNamedSections = namedSections => {
10
+ let text = "";
11
+ let keys = Object.keys(namedSections);
12
+ for (const key of keys) {
13
+ const isLastKey = key === keys[keys.length - 1];
14
+ const value = namedSections[key];
15
+ text += "--- ".concat(key, " ---\n").concat(Array.isArray(value) ? value.join("\n") : value);
16
+ if (!isLastKey) {
17
+ text += "\n";
18
+ }
19
+ }
20
+ return text;
8
21
  };
9
22
 
10
23
  // https://github.com/Marak/colors.js/blob/master/lib/styles.js
11
24
  // https://stackoverflow.com/a/75985833/2634179
12
25
  const RESET = "\x1b[0m";
26
+ const RED = "red";
27
+ const GREEN = "green";
28
+ const YELLOW = "yellow";
29
+ const BLUE = "blue";
30
+ const MAGENTA = "magenta";
31
+ const CYAN = "cyan";
32
+ const GREY = "grey";
33
+ const WHITE = "white";
34
+ const BLACK = "black";
35
+ const TEXT_COLOR_ANSI_CODES = {
36
+ [RED]: "\x1b[31m",
37
+ [GREEN]: "\x1b[32m",
38
+ [YELLOW]: "\x1b[33m",
39
+ [BLUE]: "\x1b[34m",
40
+ [MAGENTA]: "\x1b[35m",
41
+ [CYAN]: "\x1b[36m",
42
+ [GREY]: "\x1b[90m",
43
+ [WHITE]: "\x1b[37m",
44
+ [BLACK]: "\x1b[30m"
45
+ };
46
+ const BACKGROUND_COLOR_ANSI_CODES = {
47
+ [RED]: "\x1b[41m",
48
+ [GREEN]: "\x1b[42m",
49
+ [YELLOW]: "\x1b[43m",
50
+ [BLUE]: "\x1b[44m",
51
+ [MAGENTA]: "\x1b[45m",
52
+ [CYAN]: "\x1b[46m",
53
+ [GREY]: "\x1b[100m",
54
+ [WHITE]: "\x1b[47m",
55
+ [BLACK]: "\x1b[40m"
56
+ };
13
57
  const createAnsi = ({
14
58
  supported
15
59
  }) => {
16
60
  const ANSI = {
17
61
  supported,
18
- RED: "\x1b[31m",
19
- GREEN: "\x1b[32m",
20
- YELLOW: "\x1b[33m",
21
- BLUE: "\x1b[34m",
22
- MAGENTA: "\x1b[35m",
23
- CYAN: "\x1b[36m",
24
- GREY: "\x1b[90m",
62
+ RED,
63
+ GREEN,
64
+ YELLOW,
65
+ BLUE,
66
+ MAGENTA,
67
+ CYAN,
68
+ GREY,
69
+ WHITE,
70
+ BLACK,
25
71
  color: (text, color) => {
26
72
  if (!ANSI.supported) {
27
73
  return text;
@@ -33,7 +79,28 @@ const createAnsi = ({
33
79
  // cannot set color of blank chars
34
80
  return text;
35
81
  }
36
- return "".concat(color).concat(text).concat(RESET);
82
+ const ansiEscapeCodeForTextColor = TEXT_COLOR_ANSI_CODES[color];
83
+ if (!ansiEscapeCodeForTextColor) {
84
+ return text;
85
+ }
86
+ return "".concat(ansiEscapeCodeForTextColor).concat(text).concat(RESET);
87
+ },
88
+ backgroundColor: (text, color) => {
89
+ if (!ANSI.supported) {
90
+ return text;
91
+ }
92
+ if (!color) {
93
+ return text;
94
+ }
95
+ if (typeof text === "string" && text.trim() === "") {
96
+ // cannot set background color of blank chars
97
+ return text;
98
+ }
99
+ const ansiEscapeCodeForBackgroundColor = BACKGROUND_COLOR_ANSI_CODES[color];
100
+ if (!ansiEscapeCodeForBackgroundColor) {
101
+ return text;
102
+ }
103
+ return "".concat(ansiEscapeCodeForBackgroundColor).concat(text).concat(RESET);
37
104
  },
38
105
  BOLD: "\x1b[1m",
39
106
  UNDERLINE: "\x1b[4m",
@@ -49,7 +116,8 @@ const createAnsi = ({
49
116
  if (text === "") {
50
117
  return text;
51
118
  }
52
- return "".concat(effect).concat(text).concat(RESET);
119
+ const ansiEscapeCodeForEffect = effect;
120
+ return "".concat(ansiEscapeCodeForEffect).concat(text).concat(RESET);
53
121
  }
54
122
  };
55
123
  return ANSI;
@@ -1272,4 +1340,65 @@ const fillLeft = (value, biggestValue, char = " ") => {
1272
1340
  return padded;
1273
1341
  };
1274
1342
 
1275
- export { ANSI, UNICODE, createDetailedMessage, distributePercentages, generateContentFrame, humanize, humanizeDuration, humanizeEllapsedTime, humanizeFileSize, humanizeMemory, humanizeMethodSymbol };
1343
+ const createCallOrderer = () => {
1344
+ const queue = [];
1345
+ const callWhenPreviousExecutionAreDone = (executionIndex, callback) => {
1346
+ if (queue[executionIndex]) {
1347
+ throw new Error("".concat(executionIndex, " already used"));
1348
+ }
1349
+ let allBeforeAreDone = true;
1350
+ if (executionIndex > 0) {
1351
+ let beforeIndex = executionIndex - 1;
1352
+ do {
1353
+ const value = queue[beforeIndex];
1354
+ if (!value) {
1355
+ allBeforeAreDone = false;
1356
+ break;
1357
+ }
1358
+ } while (beforeIndex--);
1359
+ }
1360
+ if (!allBeforeAreDone) {
1361
+ queue[executionIndex] = callback;
1362
+ return;
1363
+ }
1364
+ queue[executionIndex] = true;
1365
+ callback();
1366
+ let afterIndex = executionIndex + 1;
1367
+ while (afterIndex < queue.length) {
1368
+ const value = queue[afterIndex];
1369
+ if (value === undefined) {
1370
+ break;
1371
+ }
1372
+ if (typeof value === "function") {
1373
+ queue[afterIndex] = true;
1374
+ value();
1375
+ }
1376
+ afterIndex++;
1377
+ }
1378
+ };
1379
+ return callWhenPreviousExecutionAreDone;
1380
+ };
1381
+
1382
+ const errorToMarkdown = error => {
1383
+ const errorIsAPrimitive = error === null || typeof error !== "object" && typeof error !== "function";
1384
+ if (errorIsAPrimitive) {
1385
+ return "```js\n".concat(error, "\n```");
1386
+ }
1387
+ return "```\n".concat(error.stack, "\n```");
1388
+ };
1389
+
1390
+ const errorToHTML = error => {
1391
+ const errorIsAPrimitive = error === null || typeof error !== "object" && typeof error !== "function";
1392
+ if (errorIsAPrimitive) {
1393
+ if (typeof error === "string") {
1394
+ return "<pre>".concat(escapeHtml(error), "</pre>");
1395
+ }
1396
+ return "<pre>".concat(JSON.stringify(error, null, " "), "</pre>");
1397
+ }
1398
+ return "<pre>".concat(escapeHtml(error.stack), "</pre>");
1399
+ };
1400
+ const escapeHtml = string => {
1401
+ return string.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1402
+ };
1403
+
1404
+ export { ANSI, UNICODE, createCallOrderer, createDetailedMessage, distributePercentages, errorToHTML, errorToMarkdown, generateContentFrame, humanize, humanizeDuration, humanizeEllapsedTime, humanizeFileSize, humanizeMemory, humanizeMethodSymbol };
@@ -1,42 +1,89 @@
1
- import { createSupportsColor, isUnicodeSupported, clearTerminal, eraseLines } from "./js/vendors.js";
2
- import stringWidth from "string-width";
1
+ import { createSupportsColor, isUnicodeSupported, stripAnsi, emojiRegex, eastAsianWidth, clearTerminal, eraseLines } from "./jsenv_humanize_node_modules.js";
2
+ import { stripVTControlCharacters } from "node:util";
3
3
  import "node:process";
4
4
  import "node:os";
5
5
  import "node:tty";
6
6
 
7
7
  const createDetailedMessage = (message, details = {}) => {
8
- let string = `${message}`;
8
+ let text = `${message}`;
9
+ const namedSectionsText = renderNamedSections(details);
10
+ if (namedSectionsText) {
11
+ text += `
12
+ ${namedSectionsText}`;
13
+ }
14
+ return text;
15
+ };
9
16
 
10
- Object.keys(details).forEach((key) => {
11
- const value = details[key];
12
- string += `
13
- --- ${key} ---
17
+ const renderNamedSections = (namedSections) => {
18
+ let text = "";
19
+ let keys = Object.keys(namedSections);
20
+ for (const key of keys) {
21
+ const isLastKey = key === keys[keys.length - 1];
22
+ const value = namedSections[key];
23
+ text += `--- ${key} ---
14
24
  ${
15
25
  Array.isArray(value)
16
26
  ? value.join(`
17
27
  `)
18
28
  : value
19
29
  }`;
20
- });
21
-
22
- return string;
30
+ if (!isLastKey) {
31
+ text += "\n";
32
+ }
33
+ }
34
+ return text;
23
35
  };
24
36
 
25
37
  // https://github.com/Marak/colors.js/blob/master/lib/styles.js
26
38
  // https://stackoverflow.com/a/75985833/2634179
27
39
  const RESET = "\x1b[0m";
28
40
 
41
+ const RED = "red";
42
+ const GREEN = "green";
43
+ const YELLOW = "yellow";
44
+ const BLUE = "blue";
45
+ const MAGENTA = "magenta";
46
+ const CYAN = "cyan";
47
+ const GREY = "grey";
48
+ const WHITE = "white";
49
+ const BLACK = "black";
50
+
51
+ const TEXT_COLOR_ANSI_CODES = {
52
+ [RED]: "\x1b[31m",
53
+ [GREEN]: "\x1b[32m",
54
+ [YELLOW]: "\x1b[33m",
55
+ [BLUE]: "\x1b[34m",
56
+ [MAGENTA]: "\x1b[35m",
57
+ [CYAN]: "\x1b[36m",
58
+ [GREY]: "\x1b[90m",
59
+ [WHITE]: "\x1b[37m",
60
+ [BLACK]: "\x1b[30m",
61
+ };
62
+ const BACKGROUND_COLOR_ANSI_CODES = {
63
+ [RED]: "\x1b[41m",
64
+ [GREEN]: "\x1b[42m",
65
+ [YELLOW]: "\x1b[43m",
66
+ [BLUE]: "\x1b[44m",
67
+ [MAGENTA]: "\x1b[45m",
68
+ [CYAN]: "\x1b[46m",
69
+ [GREY]: "\x1b[100m",
70
+ [WHITE]: "\x1b[47m",
71
+ [BLACK]: "\x1b[40m",
72
+ };
73
+
29
74
  const createAnsi = ({ supported }) => {
30
75
  const ANSI = {
31
76
  supported,
32
77
 
33
- RED: "\x1b[31m",
34
- GREEN: "\x1b[32m",
35
- YELLOW: "\x1b[33m",
36
- BLUE: "\x1b[34m",
37
- MAGENTA: "\x1b[35m",
38
- CYAN: "\x1b[36m",
39
- GREY: "\x1b[90m",
78
+ RED,
79
+ GREEN,
80
+ YELLOW,
81
+ BLUE,
82
+ MAGENTA,
83
+ CYAN,
84
+ GREY,
85
+ WHITE,
86
+ BLACK,
40
87
  color: (text, color) => {
41
88
  if (!ANSI.supported) {
42
89
  return text;
@@ -48,7 +95,29 @@ const createAnsi = ({ supported }) => {
48
95
  // cannot set color of blank chars
49
96
  return text;
50
97
  }
51
- return `${color}${text}${RESET}`;
98
+ const ansiEscapeCodeForTextColor = TEXT_COLOR_ANSI_CODES[color];
99
+ if (!ansiEscapeCodeForTextColor) {
100
+ return text;
101
+ }
102
+ return `${ansiEscapeCodeForTextColor}${text}${RESET}`;
103
+ },
104
+ backgroundColor: (text, color) => {
105
+ if (!ANSI.supported) {
106
+ return text;
107
+ }
108
+ if (!color) {
109
+ return text;
110
+ }
111
+ if (typeof text === "string" && text.trim() === "") {
112
+ // cannot set background color of blank chars
113
+ return text;
114
+ }
115
+ const ansiEscapeCodeForBackgroundColor =
116
+ BACKGROUND_COLOR_ANSI_CODES[color];
117
+ if (!ansiEscapeCodeForBackgroundColor) {
118
+ return text;
119
+ }
120
+ return `${ansiEscapeCodeForBackgroundColor}${text}${RESET}`;
52
121
  },
53
122
 
54
123
  BOLD: "\x1b[1m",
@@ -65,7 +134,8 @@ const createAnsi = ({ supported }) => {
65
134
  if (text === "") {
66
135
  return text;
67
136
  }
68
- return `${effect}${text}${RESET}`;
137
+ const ansiEscapeCodeForEffect = effect;
138
+ return `${ansiEscapeCodeForEffect}${text}${RESET}`;
69
139
  },
70
140
  };
71
141
 
@@ -1297,6 +1367,157 @@ const fillLeft = (value, biggestValue, char = " ") => {
1297
1367
  return padded;
1298
1368
  };
1299
1369
 
1370
+ const createCallOrderer = () => {
1371
+ const queue = [];
1372
+ const callWhenPreviousExecutionAreDone = (executionIndex, callback) => {
1373
+ if (queue[executionIndex]) {
1374
+ throw new Error(`${executionIndex} already used`);
1375
+ }
1376
+
1377
+ let allBeforeAreDone = true;
1378
+ if (executionIndex > 0) {
1379
+ let beforeIndex = executionIndex - 1;
1380
+ do {
1381
+ const value = queue[beforeIndex];
1382
+ if (!value) {
1383
+ allBeforeAreDone = false;
1384
+ break;
1385
+ }
1386
+ } while (beforeIndex--);
1387
+ }
1388
+ if (!allBeforeAreDone) {
1389
+ queue[executionIndex] = callback;
1390
+ return;
1391
+ }
1392
+ queue[executionIndex] = true;
1393
+ callback();
1394
+ let afterIndex = executionIndex + 1;
1395
+ while (afterIndex < queue.length) {
1396
+ const value = queue[afterIndex];
1397
+ if (value === undefined) {
1398
+ break;
1399
+ }
1400
+ if (typeof value === "function") {
1401
+ queue[afterIndex] = true;
1402
+ value();
1403
+ }
1404
+ afterIndex++;
1405
+ }
1406
+ };
1407
+ return callWhenPreviousExecutionAreDone;
1408
+ };
1409
+
1410
+ const errorToMarkdown = (error) => {
1411
+ const errorIsAPrimitive =
1412
+ error === null ||
1413
+ (typeof error !== "object" && typeof error !== "function");
1414
+
1415
+ if (errorIsAPrimitive) {
1416
+ return `\`\`\`js
1417
+ ${error}
1418
+ \`\`\``;
1419
+ }
1420
+ return `\`\`\`
1421
+ ${error.stack}
1422
+ \`\`\``;
1423
+ };
1424
+
1425
+ const errorToHTML = (error) => {
1426
+ const errorIsAPrimitive =
1427
+ error === null ||
1428
+ (typeof error !== "object" && typeof error !== "function");
1429
+
1430
+ if (errorIsAPrimitive) {
1431
+ if (typeof error === "string") {
1432
+ return `<pre>${escapeHtml(error)}</pre>`;
1433
+ }
1434
+ return `<pre>${JSON.stringify(error, null, " ")}</pre>`;
1435
+ }
1436
+ return `<pre>${escapeHtml(error.stack)}</pre>`;
1437
+ };
1438
+
1439
+ const escapeHtml = (string) => {
1440
+ return string
1441
+ .replace(/&/g, "&amp;")
1442
+ .replace(/</g, "&lt;")
1443
+ .replace(/>/g, "&gt;")
1444
+ .replace(/"/g, "&quot;")
1445
+ .replace(/'/g, "&#039;");
1446
+ };
1447
+
1448
+ const renderBigSection = (params) => {
1449
+ return renderSection({
1450
+ width: 45,
1451
+ ...params,
1452
+ });
1453
+ };
1454
+
1455
+ const renderSection = ({
1456
+ title,
1457
+ content,
1458
+ dashColor = ANSI.GREY,
1459
+ width = 38,
1460
+ bottomSeparator = true,
1461
+ }) => {
1462
+ let section = "";
1463
+
1464
+ if (title) {
1465
+ const titleWidth = stripAnsi(title).length;
1466
+ const minWidthRequired = `--- … ---`.length;
1467
+ const needsTruncate = titleWidth + minWidthRequired >= width;
1468
+ if (needsTruncate) {
1469
+ const titleTruncated = title.slice(0, width - minWidthRequired);
1470
+ const leftDashes = ANSI.color("---", dashColor);
1471
+ const rightDashes = ANSI.color("---", dashColor);
1472
+ section += `${leftDashes} ${titleTruncated}… ${rightDashes}`;
1473
+ } else {
1474
+ const remainingWidth = width - titleWidth - 2; // 2 for spaces around the title
1475
+ const dashLeftCount = Math.floor(remainingWidth / 2);
1476
+ const dashRightCount = remainingWidth - dashLeftCount;
1477
+ const leftDashes = ANSI.color("-".repeat(dashLeftCount), dashColor);
1478
+ const rightDashes = ANSI.color("-".repeat(dashRightCount), dashColor);
1479
+ section += `${leftDashes} ${title} ${rightDashes}`;
1480
+ }
1481
+ section += "\n";
1482
+ } else {
1483
+ const topDashes = ANSI.color(`-`.repeat(width), dashColor);
1484
+ section += topDashes;
1485
+ section += "\n";
1486
+ }
1487
+ section += `${content}`;
1488
+ if (bottomSeparator) {
1489
+ section += "\n";
1490
+ const bottomDashes = ANSI.color(`-`.repeat(width), dashColor);
1491
+ section += bottomDashes;
1492
+ }
1493
+ return section;
1494
+ };
1495
+
1496
+ const renderDetails = (data) => {
1497
+ const details = [];
1498
+ for (const key of Object.keys(data)) {
1499
+ const value = data[key];
1500
+ let valueString = "";
1501
+ valueString += ANSI.color(`${key}:`, ANSI.GREY);
1502
+ const useNonGreyAnsiColor =
1503
+ typeof value === "string" && value.includes("\x1b");
1504
+ valueString += " ";
1505
+ valueString += useNonGreyAnsiColor
1506
+ ? value
1507
+ : ANSI.color(String(value), ANSI.GREY);
1508
+ details.push(valueString);
1509
+ }
1510
+ if (details.length === 0) {
1511
+ return "";
1512
+ }
1513
+
1514
+ let string = "";
1515
+ string += ` ${ANSI.color("(", ANSI.GREY)}`;
1516
+ string += details.join(ANSI.color(", ", ANSI.GREY));
1517
+ string += ANSI.color(")", ANSI.GREY);
1518
+ return string;
1519
+ };
1520
+
1300
1521
  const LOG_LEVEL_OFF = "off";
1301
1522
 
1302
1523
  const LOG_LEVEL_DEBUG = "debug";
@@ -1385,6 +1606,101 @@ const error = (...args) => console.error(...args);
1385
1606
 
1386
1607
  const errorDisabled = () => {};
1387
1608
 
1609
+ const createMeasureTextWidth = ({ stripAnsi }) => {
1610
+ const segmenter = new Intl.Segmenter();
1611
+ const defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
1612
+
1613
+ const measureTextWidth = (
1614
+ string,
1615
+ {
1616
+ ambiguousIsNarrow = true,
1617
+ countAnsiEscapeCodes = false,
1618
+ skipEmojis = false,
1619
+ } = {},
1620
+ ) => {
1621
+ if (typeof string !== "string" || string.length === 0) {
1622
+ return 0;
1623
+ }
1624
+
1625
+ if (!countAnsiEscapeCodes) {
1626
+ string = stripAnsi(string);
1627
+ }
1628
+
1629
+ if (string.length === 0) {
1630
+ return 0;
1631
+ }
1632
+
1633
+ let width = 0;
1634
+ const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
1635
+
1636
+ for (const { segment: character } of segmenter.segment(string)) {
1637
+ const codePoint = character.codePointAt(0);
1638
+
1639
+ // Ignore control characters
1640
+ if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
1641
+ continue;
1642
+ }
1643
+
1644
+ // Ignore zero-width characters
1645
+ if (
1646
+ (codePoint >= 0x20_0b && codePoint <= 0x20_0f) || // Zero-width space, non-joiner, joiner, left-to-right mark, right-to-left mark
1647
+ codePoint === 0xfe_ff // Zero-width no-break space
1648
+ ) {
1649
+ continue;
1650
+ }
1651
+
1652
+ // Ignore combining characters
1653
+ if (
1654
+ (codePoint >= 0x3_00 && codePoint <= 0x3_6f) || // Combining diacritical marks
1655
+ (codePoint >= 0x1a_b0 && codePoint <= 0x1a_ff) || // Combining diacritical marks extended
1656
+ (codePoint >= 0x1d_c0 && codePoint <= 0x1d_ff) || // Combining diacritical marks supplement
1657
+ (codePoint >= 0x20_d0 && codePoint <= 0x20_ff) || // Combining diacritical marks for symbols
1658
+ (codePoint >= 0xfe_20 && codePoint <= 0xfe_2f) // Combining half marks
1659
+ ) {
1660
+ continue;
1661
+ }
1662
+
1663
+ // Ignore surrogate pairs
1664
+ if (codePoint >= 0xd8_00 && codePoint <= 0xdf_ff) {
1665
+ continue;
1666
+ }
1667
+
1668
+ // Ignore variation selectors
1669
+ if (codePoint >= 0xfe_00 && codePoint <= 0xfe_0f) {
1670
+ continue;
1671
+ }
1672
+
1673
+ // This covers some of the above cases, but we still keep them for performance reasons.
1674
+ if (defaultIgnorableCodePointRegex.test(character)) {
1675
+ continue;
1676
+ }
1677
+
1678
+ if (!skipEmojis && emojiRegex().test(character)) {
1679
+ if (process.env.CAPTURING_SIDE_EFFECTS) {
1680
+ if (character === "✔️") {
1681
+ width += 2;
1682
+ continue;
1683
+ }
1684
+ }
1685
+ width += measureTextWidth(character, {
1686
+ skipEmojis: true,
1687
+ countAnsiEscapeCodes: true, // to skip call to stripAnsi
1688
+ });
1689
+ continue;
1690
+ }
1691
+
1692
+ width += eastAsianWidth(codePoint, eastAsianWidthOptions);
1693
+ }
1694
+
1695
+ return width;
1696
+ };
1697
+ return measureTextWidth;
1698
+ };
1699
+
1700
+ const measureTextWidth = createMeasureTextWidth({
1701
+ stripAnsi: stripVTControlCharacters,
1702
+ });
1703
+
1388
1704
  /*
1389
1705
  * see also https://github.com/vadimdemedes/ink
1390
1706
  */
@@ -1420,7 +1736,7 @@ const createDynamicLog = ({
1420
1736
  const logLines = lastOutput.split(/\r\n|\r|\n/);
1421
1737
  let visualLineCount = 0;
1422
1738
  for (const logLine of logLines) {
1423
- const width = stringWidth(logLine);
1739
+ const width = measureTextWidth(logLine);
1424
1740
  if (width === 0) {
1425
1741
  visualLineCount++;
1426
1742
  } else {
@@ -1485,7 +1801,8 @@ const createDynamicLog = ({
1485
1801
  update("");
1486
1802
 
1487
1803
  writing = true;
1488
- callback();
1804
+ callback(update);
1805
+ lastOutput = "";
1489
1806
  writing = false;
1490
1807
 
1491
1808
  update(ouputAfterCallback);
@@ -1685,4 +2002,4 @@ const createTaskLog = (
1685
2002
  };
1686
2003
  };
1687
2004
 
1688
- export { ANSI, UNICODE, createDetailedMessage, createDynamicLog, createLogger, createTaskLog, distributePercentages, generateContentFrame, humanize, humanizeDuration, humanizeEllapsedTime, humanizeFileSize, humanizeMemory, humanizeMethodSymbol, startSpinner };
2005
+ export { ANSI, UNICODE, createCallOrderer, createDetailedMessage, createDynamicLog, createLogger, createTaskLog, distributePercentages, errorToHTML, errorToMarkdown, generateContentFrame, humanize, humanizeDuration, humanizeEllapsedTime, humanizeFileSize, humanizeMemory, humanizeMethodSymbol, renderBigSection, renderDetails, renderNamedSections, renderSection, startSpinner };