@allurereport/plugin-progress 3.15.0 → 3.16.1

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/plugin.d.ts CHANGED
@@ -5,10 +5,13 @@ export declare class ProgressPlugin implements Plugin {
5
5
  readonly options: {
6
6
  stream?: WriteStream;
7
7
  preserve?: boolean;
8
+ minRenderIntervalMs?: number;
8
9
  };
9
10
  constructor(options?: {
10
11
  stream?: WriteStream;
11
12
  preserve?: boolean;
13
+ minRenderIntervalMs?: number;
12
14
  });
13
15
  start: (context: PluginContext, store: AllureStore, realtime: RealtimeSubscriber) => Promise<void>;
16
+ done: (context: PluginContext, store: AllureStore) => Promise<void>;
14
17
  }
package/dist/plugin.js CHANGED
@@ -9,50 +9,94 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _ProgressPlugin_terminal, _ProgressPlugin_preserve, _ProgressPlugin_render;
12
+ var _ProgressPlugin_terminal, _ProgressPlugin_preserve, _ProgressPlugin_minRenderIntervalMs, _ProgressPlugin_lastRenderAt, _ProgressPlugin_pendingStore, _ProgressPlugin_pumping, _ProgressPlugin_pumpDone, _ProgressPlugin_pump, _ProgressPlugin_render;
13
+ import console from "node:console";
13
14
  import * as process from "node:process";
15
+ import { setTimeout as delay } from "node:timers/promises";
14
16
  import { green, red, yellow } from "yoctocolors";
15
17
  import { Terminal } from "./terminal.js";
18
+ const DEFAULT_MIN_RENDER_INTERVAL_MS = 300;
16
19
  export class ProgressPlugin {
17
20
  constructor(options = {}) {
18
21
  this.options = options;
19
22
  _ProgressPlugin_terminal.set(this, void 0);
20
- _ProgressPlugin_preserve.set(this, false);
23
+ _ProgressPlugin_preserve.set(this, void 0);
24
+ _ProgressPlugin_minRenderIntervalMs.set(this, void 0);
25
+ _ProgressPlugin_lastRenderAt.set(this, 0);
26
+ _ProgressPlugin_pendingStore.set(this, void 0);
27
+ _ProgressPlugin_pumping.set(this, false);
28
+ _ProgressPlugin_pumpDone.set(this, Promise.resolve());
21
29
  this.start = async (context, store, realtime) => {
22
30
  realtime.onTestResults(async () => {
23
- await __classPrivateFieldGet(this, _ProgressPlugin_render, "f").call(this, store);
31
+ __classPrivateFieldSet(this, _ProgressPlugin_pendingStore, store, "f");
32
+ if (!__classPrivateFieldGet(this, _ProgressPlugin_pumping, "f")) {
33
+ __classPrivateFieldSet(this, _ProgressPlugin_pumpDone, __classPrivateFieldGet(this, _ProgressPlugin_pump, "f").call(this), "f");
34
+ }
24
35
  });
25
36
  };
37
+ this.done = async (context, store) => {
38
+ try {
39
+ await __classPrivateFieldGet(this, _ProgressPlugin_pumpDone, "f");
40
+ await __classPrivateFieldGet(this, _ProgressPlugin_render, "f").call(this, store);
41
+ }
42
+ finally {
43
+ if (__classPrivateFieldGet(this, _ProgressPlugin_terminal, "f")?.isTTY()) {
44
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").newline();
45
+ }
46
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f")?.detach();
47
+ }
48
+ };
49
+ _ProgressPlugin_pump.set(this, async () => {
50
+ __classPrivateFieldSet(this, _ProgressPlugin_pumping, true, "f");
51
+ try {
52
+ while (__classPrivateFieldGet(this, _ProgressPlugin_pendingStore, "f")) {
53
+ const elapsed = Date.now() - __classPrivateFieldGet(this, _ProgressPlugin_lastRenderAt, "f");
54
+ const wait = Math.max(0, __classPrivateFieldGet(this, _ProgressPlugin_minRenderIntervalMs, "f") - elapsed);
55
+ if (wait > 0) {
56
+ await delay(wait);
57
+ }
58
+ const store = __classPrivateFieldGet(this, _ProgressPlugin_pendingStore, "f");
59
+ __classPrivateFieldSet(this, _ProgressPlugin_pendingStore, undefined, "f");
60
+ __classPrivateFieldSet(this, _ProgressPlugin_lastRenderAt, Date.now(), "f");
61
+ try {
62
+ await __classPrivateFieldGet(this, _ProgressPlugin_render, "f").call(this, store);
63
+ }
64
+ catch (error) {
65
+ console.error("can't render progress", error);
66
+ }
67
+ }
68
+ }
69
+ finally {
70
+ __classPrivateFieldSet(this, _ProgressPlugin_pumping, false, "f");
71
+ }
72
+ });
26
73
  _ProgressPlugin_render.set(this, async (store) => {
27
74
  if (!__classPrivateFieldGet(this, _ProgressPlugin_terminal, "f")) {
28
75
  return;
29
76
  }
30
- if (!__classPrivateFieldGet(this, _ProgressPlugin_preserve, "f")) {
31
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").cursorRelativeReset();
32
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").clearLine();
33
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").clearBottom();
34
- }
35
77
  const testsStatistic = await store.testsStatistic();
36
- if (testsStatistic.failed) {
37
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(`${red("failed")}: ${testsStatistic.failed}`);
38
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").newline();
39
- }
40
- if (testsStatistic.broken) {
41
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(`${yellow("broken")}: ${testsStatistic.broken}`);
42
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").newline();
43
- }
44
- if (testsStatistic.passed) {
45
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(`${green("passed")}: ${testsStatistic.passed}`);
78
+ const parts = [
79
+ testsStatistic.failed ? `${red("failed")}: ${testsStatistic.failed}` : undefined,
80
+ testsStatistic.broken ? `${yellow("broken")}: ${testsStatistic.broken}` : undefined,
81
+ testsStatistic.passed ? `${green("passed")}: ${testsStatistic.passed}` : undefined,
82
+ `total: ${testsStatistic.total}`,
83
+ ].filter((part) => !!part);
84
+ const line = parts.join(" ");
85
+ if (!__classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").isTTY() || __classPrivateFieldGet(this, _ProgressPlugin_preserve, "f")) {
86
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(line);
46
87
  __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").newline();
88
+ return;
47
89
  }
48
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(`total: ${testsStatistic.total}`);
49
- __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").newline();
90
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").cursorTo(0);
91
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").clearLine();
92
+ __classPrivateFieldGet(this, _ProgressPlugin_terminal, "f").write(line);
50
93
  });
51
- const { stream = process.stdout, preserve = false } = this.options;
94
+ const { stream = process.stdout, preserve = false, minRenderIntervalMs = DEFAULT_MIN_RENDER_INTERVAL_MS, } = this.options;
52
95
  if (stream) {
53
96
  __classPrivateFieldSet(this, _ProgressPlugin_terminal, new Terminal(stream), "f");
54
97
  }
55
98
  __classPrivateFieldSet(this, _ProgressPlugin_preserve, preserve, "f");
99
+ __classPrivateFieldSet(this, _ProgressPlugin_minRenderIntervalMs, minRenderIntervalMs, "f");
56
100
  }
57
101
  }
58
- _ProgressPlugin_terminal = new WeakMap(), _ProgressPlugin_preserve = new WeakMap(), _ProgressPlugin_render = new WeakMap();
102
+ _ProgressPlugin_terminal = new WeakMap(), _ProgressPlugin_preserve = new WeakMap(), _ProgressPlugin_minRenderIntervalMs = new WeakMap(), _ProgressPlugin_lastRenderAt = new WeakMap(), _ProgressPlugin_pendingStore = new WeakMap(), _ProgressPlugin_pumping = new WeakMap(), _ProgressPlugin_pumpDone = new WeakMap(), _ProgressPlugin_pump = new WeakMap(), _ProgressPlugin_render = new WeakMap();
@@ -2,6 +2,7 @@ import type { WriteStream } from "node:tty";
2
2
  export declare class Terminal {
3
3
  #private;
4
4
  constructor(outputStream: WriteStream);
5
+ detach(): void;
5
6
  cursorSave(): void;
6
7
  cursorRestore(): void;
7
8
  cursor(enabled: boolean): void;
package/dist/terminal.js CHANGED
@@ -9,90 +9,115 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _Terminal_stream, _Terminal_wrapLines, _Terminal_dy;
12
+ var _Terminal_instances, _Terminal_stream, _Terminal_originalWrite, _Terminal_rawStream, _Terminal_wrapLines, _Terminal_dy, _Terminal_lineActive, _Terminal_interceptForeignWrites;
13
13
  import { clearLine, clearScreenDown, cursorTo, moveCursor } from "node:readline";
14
+ const patchedStreams = new WeakMap();
14
15
  export class Terminal {
15
16
  constructor(outputStream) {
17
+ _Terminal_instances.add(this);
16
18
  _Terminal_stream.set(this, void 0);
19
+ _Terminal_originalWrite.set(this, void 0);
20
+ _Terminal_rawStream.set(this, void 0);
17
21
  _Terminal_wrapLines.set(this, void 0);
18
22
  _Terminal_dy.set(this, void 0);
23
+ _Terminal_lineActive.set(this, false);
19
24
  __classPrivateFieldSet(this, _Terminal_stream, outputStream, "f");
25
+ __classPrivateFieldSet(this, _Terminal_originalWrite, patchedStreams.get(outputStream)?.originalWrite ?? outputStream.write.bind(outputStream), "f");
26
+ __classPrivateFieldSet(this, _Terminal_rawStream, { write: __classPrivateFieldGet(this, _Terminal_originalWrite, "f") }, "f");
20
27
  __classPrivateFieldSet(this, _Terminal_wrapLines, true, "f");
21
28
  __classPrivateFieldSet(this, _Terminal_dy, 0, "f");
29
+ if (outputStream.isTTY) {
30
+ __classPrivateFieldGet(this, _Terminal_instances, "m", _Terminal_interceptForeignWrites).call(this);
31
+ }
32
+ }
33
+ detach() {
34
+ const state = patchedStreams.get(__classPrivateFieldGet(this, _Terminal_stream, "f"));
35
+ if (!state) {
36
+ return;
37
+ }
38
+ state.owners.delete(this);
39
+ if (state.owners.size === 0) {
40
+ patchedStreams.delete(__classPrivateFieldGet(this, _Terminal_stream, "f"));
41
+ __classPrivateFieldGet(this, _Terminal_stream, "f").write = state.originalWrite;
42
+ }
22
43
  }
23
44
  cursorSave() {
24
45
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
25
46
  return;
26
47
  }
27
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B7");
48
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B7");
28
49
  }
29
50
  cursorRestore() {
30
51
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
31
52
  return;
32
53
  }
33
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B8");
54
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B8");
34
55
  }
35
56
  cursor(enabled) {
36
57
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
37
58
  return;
38
59
  }
39
60
  if (enabled) {
40
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B[?25h");
61
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B[?25h");
41
62
  }
42
63
  else {
43
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B[?25l");
64
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B[?25l");
44
65
  }
45
66
  }
46
67
  cursorTo(x, y) {
47
68
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
48
69
  return;
49
70
  }
50
- cursorTo(__classPrivateFieldGet(this, _Terminal_stream, "f"), x, y);
71
+ cursorTo(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), x, y);
51
72
  }
52
73
  cursorRelative(dx, dy) {
53
74
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
54
75
  return;
55
76
  }
56
77
  __classPrivateFieldSet(this, _Terminal_dy, __classPrivateFieldGet(this, _Terminal_dy, "f") + dy, "f");
57
- moveCursor(__classPrivateFieldGet(this, _Terminal_stream, "f"), dx, dy);
78
+ moveCursor(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), dx, dy);
58
79
  }
59
80
  cursorRelativeReset() {
60
81
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
61
82
  return;
62
83
  }
63
- moveCursor(__classPrivateFieldGet(this, _Terminal_stream, "f"), 0, -__classPrivateFieldGet(this, _Terminal_dy, "f"));
64
- cursorTo(__classPrivateFieldGet(this, _Terminal_stream, "f"), 0);
84
+ moveCursor(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), 0, -__classPrivateFieldGet(this, _Terminal_dy, "f"));
85
+ cursorTo(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), 0);
65
86
  __classPrivateFieldSet(this, _Terminal_dy, 0, "f");
66
87
  }
67
88
  clearRight() {
68
89
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
69
90
  return;
70
91
  }
71
- clearLine(__classPrivateFieldGet(this, _Terminal_stream, "f"), 1);
92
+ clearLine(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), 1);
72
93
  }
73
94
  clearLine() {
74
95
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
75
96
  return;
76
97
  }
77
- clearLine(__classPrivateFieldGet(this, _Terminal_stream, "f"), 0);
98
+ clearLine(__classPrivateFieldGet(this, _Terminal_rawStream, "f"), 0);
78
99
  }
79
100
  clearBottom() {
80
101
  if (!__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY) {
81
102
  return;
82
103
  }
83
- clearScreenDown(__classPrivateFieldGet(this, _Terminal_stream, "f"));
104
+ clearScreenDown(__classPrivateFieldGet(this, _Terminal_rawStream, "f"));
84
105
  }
85
106
  newline() {
86
107
  var _a;
87
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\n");
108
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\n");
88
109
  __classPrivateFieldSet(this, _Terminal_dy, (_a = __classPrivateFieldGet(this, _Terminal_dy, "f"), _a++, _a), "f");
110
+ __classPrivateFieldSet(this, _Terminal_lineActive, false, "f");
89
111
  }
90
112
  write(s, rawWrite = false) {
91
113
  if (__classPrivateFieldGet(this, _Terminal_wrapLines, "f") && !rawWrite) {
92
- __classPrivateFieldGet(this, _Terminal_stream, "f").write(s.slice(0, this.getWidth()));
114
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, s.slice(0, this.getWidth()));
93
115
  }
94
116
  else {
95
- __classPrivateFieldGet(this, _Terminal_stream, "f").write(s);
117
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, s);
118
+ }
119
+ if (s.length > 0) {
120
+ __classPrivateFieldSet(this, _Terminal_lineActive, true, "f");
96
121
  }
97
122
  }
98
123
  lineWrapping(enabled) {
@@ -101,10 +126,10 @@ export class Terminal {
101
126
  }
102
127
  __classPrivateFieldSet(this, _Terminal_wrapLines, enabled, "f");
103
128
  if (enabled) {
104
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B[?7h");
129
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B[?7h");
105
130
  }
106
131
  else {
107
- __classPrivateFieldGet(this, _Terminal_stream, "f").write("\x1B[?7l");
132
+ __classPrivateFieldGet(this, _Terminal_originalWrite, "f").call(this, "\x1B[?7l");
108
133
  }
109
134
  }
110
135
  isTTY() {
@@ -114,4 +139,22 @@ export class Terminal {
114
139
  return __classPrivateFieldGet(this, _Terminal_stream, "f").columns || (__classPrivateFieldGet(this, _Terminal_stream, "f").isTTY ? 80 : 200);
115
140
  }
116
141
  }
117
- _Terminal_stream = new WeakMap(), _Terminal_wrapLines = new WeakMap(), _Terminal_dy = new WeakMap();
142
+ _Terminal_stream = new WeakMap(), _Terminal_originalWrite = new WeakMap(), _Terminal_rawStream = new WeakMap(), _Terminal_wrapLines = new WeakMap(), _Terminal_dy = new WeakMap(), _Terminal_lineActive = new WeakMap(), _Terminal_instances = new WeakSet(), _Terminal_interceptForeignWrites = function _Terminal_interceptForeignWrites() {
143
+ const existing = patchedStreams.get(__classPrivateFieldGet(this, _Terminal_stream, "f"));
144
+ if (existing) {
145
+ existing.owners.add(this);
146
+ return;
147
+ }
148
+ const originalWrite = __classPrivateFieldGet(this, _Terminal_originalWrite, "f");
149
+ const owners = new Set([this]);
150
+ patchedStreams.set(__classPrivateFieldGet(this, _Terminal_stream, "f"), { originalWrite, owners });
151
+ __classPrivateFieldGet(this, _Terminal_stream, "f").write = ((...args) => {
152
+ if ([...owners].some((owner) => __classPrivateFieldGet(owner, _Terminal_lineActive, "f"))) {
153
+ originalWrite("\n");
154
+ for (const owner of owners) {
155
+ __classPrivateFieldSet(owner, _Terminal_lineActive, false, "f");
156
+ }
157
+ }
158
+ return originalWrite(...args);
159
+ });
160
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-progress",
3
- "version": "3.15.0",
3
+ "version": "3.16.1",
4
4
  "description": "Allure Plugin to show generation progress in console",
5
5
  "keywords": [
6
6
  "allure",
@@ -31,8 +31,8 @@
31
31
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
32
32
  },
33
33
  "dependencies": {
34
- "@allurereport/core-api": "3.15.0",
35
- "@allurereport/plugin-api": "3.15.0",
34
+ "@allurereport/core-api": "3.16.1",
35
+ "@allurereport/plugin-api": "3.16.1",
36
36
  "yoctocolors": "^2.1.2"
37
37
  },
38
38
  "devDependencies": {