@travetto/terminal 8.0.0-alpha.14 → 8.0.0-alpha.16

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/util.ts +42 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/terminal",
3
- "version": "8.0.0-alpha.14",
3
+ "version": "8.0.0-alpha.16",
4
4
  "type": "module",
5
5
  "description": "General terminal support",
6
6
  "keywords": [
@@ -25,7 +25,7 @@
25
25
  "directory": "module/terminal"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/runtime": "^8.0.0-alpha.14",
28
+ "@travetto/runtime": "^8.0.0-alpha.16",
29
29
  "chalk": "^5.6.2"
30
30
  },
31
31
  "travetto": {
package/src/util.ts CHANGED
@@ -1,11 +1,37 @@
1
+ import rl from 'node:readline/promises';
2
+
3
+ import { Env } from '@travetto/runtime';
4
+
1
5
  import { StyleUtil, type TermStyleFn, type TermStyleInput } from './style.ts';
2
6
  import { type Terminal, WAIT_TOKEN } from './terminal.ts';
3
7
 
4
- type ProgressEvent<T> = { total?: number, idx: number, value: T };
5
- type ProgressStyle = { complete: TermStyleFn, incomplete?: TermStyleFn };
8
+ export type ProgressEvent<T> = { total?: number, completed: number, value: T, failed?: number };
9
+ type ProgressStyle = { complete: TermStyleFn, failed: TermStyleFn, incomplete?: TermStyleFn };
6
10
 
7
11
  export class TerminalUtil {
8
12
 
13
+ /**
14
+ * Determine if the terminal session is interactive
15
+ */
16
+ static isInteractive(): boolean {
17
+ return process.stdout.isTTY && process.stdin.isTTY && !Env.TRV_QUIET.isTrue;
18
+ }
19
+
20
+ /**
21
+ * Prompt the user for input
22
+ */
23
+ static async prompt(message: string): Promise<string> {
24
+ if (!this.isInteractive()) {
25
+ return '';
26
+ }
27
+ const reader = rl.createInterface({ input: process.stdin, output: process.stdout });
28
+ try {
29
+ return (await reader.question(message)).trim();
30
+ } finally {
31
+ reader.close();
32
+ }
33
+ }
34
+
9
35
  /**
10
36
  * Create a progress bar updater, suitable for streaming to the bottom of the screen
11
37
  */
@@ -13,11 +39,12 @@ export class TerminalUtil {
13
39
  term: Terminal,
14
40
  config?: {
15
41
  withWaiting?: boolean;
16
- style?: { complete: TermStyleInput, incomplete?: TermStyleInput } | (() => ProgressStyle);
42
+ style?: { complete: TermStyleInput, failed?: TermStyleInput, incomplete?: TermStyleInput } | (() => ProgressStyle);
17
43
  }
18
44
  ): (event: ProgressEvent<string>) => string {
19
45
  const styleBase = typeof config?.style !== 'function' ? {
20
46
  complete: StyleUtil.getStyle(config?.style?.complete ?? { background: '#248613', text: '#ffffff' }),
47
+ failed: StyleUtil.getStyle({ background: '#880000', text: '#ffffff', inverse: false }),
21
48
  incomplete: config?.style?.incomplete ? StyleUtil.getStyle(config.style.incomplete) : undefined,
22
49
  } : undefined;
23
50
 
@@ -25,19 +52,25 @@ export class TerminalUtil {
25
52
 
26
53
  let width: number;
27
54
  return event => {
28
- const text = event.value ?? (event.total ? '%idx/%total' : '%idx');
29
- const progress = event.total === undefined ? 0 : (event.idx / event.total);
55
+ const text = event.value ?? (event.total ? '%completed/%total' : '%completed');
56
+ const progress = event.total === undefined ? 0 : (event.completed / event.total);
30
57
  if (event.total) {
31
58
  width ??= Math.trunc(Math.ceil(Math.log10(event.total ?? 10000)));
32
59
  }
33
- const state: Record<string, string> = { total: `${event.total}`, idx: `${event.idx}`.padStart(width ?? 0), progress: `${Math.trunc(progress * 100)}` };
34
- const line = ` ${text.replace(/[%](idx|total|progress)/g, (_, key) => state[key])} `;
60
+ const state: Record<string, string> = {
61
+ total: `${event.total}`,
62
+ completed: `${event.completed}`.padStart(width ?? 0),
63
+ progress: `${Math.trunc(progress * 100)}`,
64
+ failed: event.failed ? `${event.failed}` : ''
65
+ };
66
+ const line = ` ${text.replace(/[%](completed|total|progress|failed)/g, (_, key) => state[key])} `;
35
67
  const full = term.writer.padToWidth(line, config?.withWaiting ? 2 : 0);
36
68
  const mid = Math.trunc(progress * term.width);
37
69
  const [left, right] = [full.substring(0, mid), full.substring(mid)];
38
70
 
39
- const { complete, incomplete } = style();
40
- return `${config?.withWaiting ? `${WAIT_TOKEN} ` : ''}${complete(left)}${incomplete?.(right) ?? right}`;
71
+ const { complete, incomplete, failed } = style();
72
+ const color = event.failed ? failed : complete;
73
+ return `${config?.withWaiting ? `${WAIT_TOKEN} ` : ''}${color(left)}${incomplete?.(right) ?? right}`;
41
74
  };
42
75
  }
43
76
  }