effective-progress 0.1.0 → 0.1.3

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/README.md CHANGED
@@ -1,11 +1,23 @@
1
1
  # effective-progress
2
2
 
3
- `effective-progress` is an Effect-first terminal progress library with:
3
+ [![npm version](https://img.shields.io/npm/v/effective-progress)](https://www.npmjs.com/package/effective-progress)
4
+
5
+ > [!WARNING]
6
+ > Pre-`1.0.0`, breaking changes may happen in any release. SemVer guarantees will begin at `1.0.0`.
7
+ > I recommend using only the `Progress.all` and `Progress.forEach` APIs for now, as they will likely change the least. The lower-level APIs for manual progress bar control are more likely to see breaking changes as I iterate on the design.
8
+ >
9
+ > Please open an issue or reach out if you have any questions or want to contribute!
10
+ > Feedback and contributions are very welcome!
11
+
12
+ <img alt="Showcase output" src="docs/images/showcase.gif" width="600" />
13
+
14
+ `effective-progress` is an [Effect](https://effect.website/)-first terminal progress library with:
4
15
 
5
16
  - multiple progress bars
6
17
  - nested child progress bars
7
18
  - spinner support for indeterminate work
8
- - clean log rendering alongside progress output
19
+ - clean log rendering alongside progress output, allowing you to simply use Effects `Console.log` or `Effect.logInfo`.
20
+ - simple to use `.all` and `.forEach` APIs similar to the ones you already know and love from `effect`. Just swap `Effect` for `Progress` and get progress bars for free!
9
21
 
10
22
  ## Install
11
23
 
@@ -26,18 +38,13 @@ const program = Progress.all(
26
38
  yield* Console.log(`Completed task ${i + 1}`);
27
39
  }),
28
40
  ),
29
- { description: "Running tasks in parallel", all: { concurrency: 2 } },
41
+ { description: "Running tasks in parallel", concurrency: 2 },
30
42
  );
31
43
 
32
44
  Effect.runPromise(program);
33
45
  ```
34
46
 
35
- ```bash
36
- bun run examples/basic.ts
37
- Completed task 1
38
- Completed task 2
39
- - Running tasks in parallel: ━━━━━━━━━━━━────────────────── 2/5 40%
40
- ```
47
+ <img alt="Basic example output" src="docs/images/basic.gif" width="600" />
41
48
 
42
49
  ## Nested example
43
50
 
@@ -62,25 +69,128 @@ const program = Progress.all(
62
69
  ),
63
70
  ),
64
71
  ),
65
- { description: "Running tasks in parallel", all: { concurrency: 2 } },
72
+ { description: "Running tasks in parallel", concurrency: 2 },
66
73
  );
67
74
 
68
75
  Effect.runPromise(program);
69
76
  ```
70
77
 
71
- ```bash
72
- ❯ bun run examples/nesting.ts
73
- - Running tasks in parallel: ━━━━━━━━━━━━────────────────── 2/5 40%
74
- - Running subtasks for task 3: ━━━━━━━━────────────────────── 4/15 27%
75
- - Running subtasks for task 4: ━━━━━━━━────────────────────── 4/15 27%
76
- ```
78
+ <img alt="Nested example output" src="docs/images/nesting.gif" width="600" />
77
79
 
78
80
  ## Other examples
79
81
 
80
82
  - `examples/simpleExample.ts` - low-boilerplate real-world flow
81
83
  - `examples/advancedExample.ts` - full API usage with custom config and manual task control
84
+ - `examples/showcase.ts` - nested concurrent tasks, spinner workloads, and mixed Effect/Console logging
85
+
86
+ ## Log retention
87
+
88
+ - `maxLogLines` on `RendererConfig` controls in-memory log retention.
89
+ - Omitted or set to `0` means no log history is kept in memory.
90
+ - `maxLogLines > 0` keeps only the latest `N` log lines in memory.
91
+
92
+ ## Configuring renderer and progress bars
93
+
94
+ Configure global renderer behavior once, and a global base progress bar style:
95
+
96
+ ```ts
97
+ import { Effect } from "effect";
98
+ import * as Progress from "effective-progress";
99
+
100
+ const configured = program.pipe(
101
+ Effect.provideService(Progress.RendererConfig, {
102
+ maxLogLines: 12,
103
+ nonTtyUpdateStep: 2,
104
+ }),
105
+ Effect.provideService(Progress.ProgressBarConfig, {
106
+ barWidth: 36,
107
+ colors: {
108
+ fill: { kind: "hex", value: "#00b894" },
109
+ spinner: { kind: "ansi256", value: 214 },
110
+ },
111
+ }),
112
+ );
113
+
114
+ Effect.runPromise(configured);
115
+ ```
116
+
117
+ Task-level `progressbar` config is optional and inherits from its parent task (or from global `ProgressBarConfig` for root tasks):
118
+
119
+ ```ts
120
+ yield *
121
+ progress.withTask(
122
+ {
123
+ description: "Worker pipeline",
124
+ progressbar: {
125
+ barWidth: 20,
126
+ spinnerFrames: [".", "o", "O", "0"],
127
+ colors: {
128
+ spinner: { kind: "named", value: "magentaBright" },
129
+ },
130
+ },
131
+ },
132
+ () => Effect.sleep("1 second"),
133
+ );
134
+ ```
135
+
136
+ For manual service usage, capture logs explicitly:
137
+
138
+ ```ts
139
+ const program = Progress.provide(
140
+ Effect.gen(function* () {
141
+ const progress = yield* Progress.Progress;
142
+
143
+ yield* progress.withTask({ description: "Manual task" }, () =>
144
+ progress.withCapturedLogs(
145
+ Effect.gen(function* () {
146
+ yield* Console.log("This log is rendered through progress output");
147
+ yield* Effect.sleep("1 second");
148
+ }),
149
+ ),
150
+ );
151
+ }),
152
+ );
153
+ ```
154
+
155
+ ## Progress bar colors
156
+
157
+ `progressbar.colors` is configured with typed color tokens that are validated by Effect Schema.
158
+
159
+ ```ts
160
+ progressbar: {
161
+ spinnerFrames: ["-", "\\", "|", "/"],
162
+ barWidth: 30,
163
+ fillChar: "━",
164
+ emptyChar: "─",
165
+ leftBracket: "",
166
+ rightBracket: "",
167
+ colors: {
168
+ fill: { kind: "named", value: "cyan" },
169
+ empty: { kind: "hex", value: "#9ca3af", modifiers: ["dim"] },
170
+ brackets: { kind: "rgb", value: { r: 156, g: 163, b: 175 } },
171
+ percent: { kind: "named", value: "whiteBright", modifiers: ["bold"] },
172
+ spinner: { kind: "ansi256", value: 214 },
173
+ done: { kind: "named", value: "greenBright" },
174
+ failed: { kind: "named", value: "redBright", modifiers: ["bold"] },
175
+ },
176
+ }
177
+ ```
178
+
179
+ Supported color styles:
180
+
181
+ - `named` (for example `cyan`, `greenBright`)
182
+ - `hex` (for example `#00b894`)
183
+ - `rgb` (for example `{ r: 0, g: 184, b: 148 }`)
184
+ - `ansi256` (for example `214`)
185
+
186
+ Supported modifiers:
187
+
188
+ - `bold`, `dim`, `italic`, `underline`, `inverse`, `hidden`, `strikethrough`
189
+
190
+ ## Dependencies & package size
191
+
192
+ This library is designed for CLI workflows, where package size is typically a lower-priority concern. Alongside `effect`, it relies on two mature runtime dependencies: `chalk` and `es-toolkit`.
82
193
 
83
194
  ## Notes
84
195
 
85
- - This is a WIP library, so expect breaking changes. Feedback and contributions are very welcome!
86
196
  - As Effect 4.0 is around the corner with some changes to logging, there may be some adjustments needed to align with the new Effect APIs.
package/package.json CHANGED
@@ -1,37 +1,44 @@
1
1
  {
2
2
  "name": "effective-progress",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Effect-first terminal progress bars with nested multibar support",
5
+ "homepage": "https://github.com/stromseng/effective-progress#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/stromseng/effective-progress/issues"
8
+ },
5
9
  "license": "MIT",
6
10
  "repository": {
7
11
  "type": "git",
8
12
  "url": "git+https://github.com/stromseng/effective-progress.git"
9
13
  },
10
- "bugs": {
11
- "url": "https://github.com/stromseng/effective-progress/issues"
12
- },
13
- "homepage": "https://github.com/stromseng/effective-progress#readme",
14
- "type": "module",
15
- "module": "index.ts",
16
14
  "files": [
17
15
  "index.ts",
18
16
  "src",
19
17
  "README.md",
20
18
  "LICENSE"
21
19
  ],
20
+ "type": "module",
21
+ "module": "index.ts",
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
25
25
  "scripts": {
26
- "prepare": "effect-language-service patch"
26
+ "prepare": "effect-language-service patch",
27
+ "typecheck": "tsc --noEmit",
28
+ "lint": "oxlint .",
29
+ "format": "oxfmt --write .",
30
+ "format:check": "oxfmt --check ."
27
31
  },
28
32
  "dependencies": {
29
- "@effect/language-service": "^0.73.1",
30
33
  "chalk": "^5.6.2",
31
- "effect": "^3.19.16"
34
+ "effect": "^3.19.16",
35
+ "es-toolkit": "^1.44.0",
36
+ "type-fest": "^5.4.4"
32
37
  },
33
38
  "devDependencies": {
39
+ "@effect/language-service": "^0.73.1",
34
40
  "@types/bun": "latest",
41
+ "oxfmt": "^0.32.0",
35
42
  "oxlint": "^1.47.0"
36
43
  },
37
44
  "peerDependencies": {
package/src/api.ts CHANGED
@@ -1,134 +1,115 @@
1
- import { Console, Effect, Option } from "effect";
2
- import { makeProgressConsole } from "./console";
1
+ import { Effect, Option } from "effect";
2
+ import type { Concurrency } from "effect/Types";
3
3
  import { makeProgressService } from "./runtime";
4
4
  import { Progress } from "./types";
5
5
  import type { TrackOptions } from "./types";
6
+ import { inferTotal } from "./utils";
6
7
 
7
- export interface TrackEffectsOptions {
8
- readonly description: string;
9
- readonly total?: number;
10
- readonly transient?: boolean;
11
- readonly all?: {
12
- readonly concurrency?: number | "unbounded";
13
- readonly batching?: boolean | "inherit";
14
- readonly concurrentFinalizers?: boolean;
15
- };
8
+ export interface EffectExecutionOptions {
9
+ readonly concurrency?: Concurrency;
10
+ readonly batching?: boolean | "inherit";
11
+ readonly concurrentFinalizers?: boolean;
16
12
  }
17
13
 
18
- export interface ForEachOptions extends TrackOptions {
19
- readonly forEach?: {
20
- readonly concurrency?: number | "unbounded";
21
- readonly batching?: boolean | "inherit";
22
- readonly concurrentFinalizers?: boolean;
23
- };
14
+ export interface EffectAllExecutionOptions extends EffectExecutionOptions {
15
+ readonly discard?: boolean;
16
+ readonly mode?: "default" | "validate" | "either";
24
17
  }
25
18
 
26
- const inferTotal = (iterable: Iterable<unknown>): number | undefined => {
27
- if (Array.isArray(iterable)) {
28
- return iterable.length;
29
- }
19
+ export type AllOptions = Omit<TrackOptions, "total"> & EffectAllExecutionOptions;
20
+ export type AllReturn<
21
+ Arg extends ReadonlyArray<Effect.Effect<any, any, any>>,
22
+ O extends EffectAllExecutionOptions,
23
+ > =
24
+ [Effect.All.ReturnTuple<Arg, Effect.All.IsDiscard<O>, Effect.All.ExtractMode<O>>] extends
25
+ [Effect.Effect<infer A, infer E, infer R>] ? Effect.Effect<A, E, Exclude<R, Progress>>
26
+ : never;
30
27
 
31
- if (typeof iterable === "string") {
32
- return iterable.length;
33
- }
34
-
35
- const candidate = iterable as { length?: unknown; size?: unknown };
36
- if (typeof candidate.length === "number") {
37
- return candidate.length;
38
- }
39
-
40
- if (typeof candidate.size === "number") {
41
- return candidate.size;
42
- }
28
+ export interface ForEachExecutionOptions extends EffectExecutionOptions {
29
+ readonly discard?: false | undefined;
30
+ }
43
31
 
44
- return undefined;
45
- };
32
+ export type ForEachOptions = TrackOptions & ForEachExecutionOptions;
46
33
 
47
- export const withProgressService = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
34
+ export const provide = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
48
35
  Effect.gen(function* () {
49
- const outerConsole = yield* Console.consoleWith((console) => Effect.succeed(console));
50
36
  const existing = yield* Effect.serviceOption(Progress);
51
37
  if (Option.isSome(existing)) {
52
- const console = makeProgressConsole(existing.value, outerConsole);
53
- return yield* Effect.withConsole(
54
- Effect.provideService(effect, Progress, existing.value),
55
- console,
56
- );
38
+ return yield* Effect.provideService(effect, Progress, existing.value);
57
39
  }
58
40
 
59
41
  return yield* Effect.scoped(
60
42
  Effect.gen(function* () {
61
43
  const service = yield* makeProgressService;
62
- const console = makeProgressConsole(service, outerConsole);
63
- return yield* Effect.withConsole(Effect.provideService(effect, Progress, service), console);
44
+ return yield* Effect.provideService(effect, Progress, service);
64
45
  }),
65
46
  );
66
47
  });
67
48
 
68
- export const all = <A, E, R>(
69
- effects: ReadonlyArray<Effect.Effect<A, E, R>>,
70
- options: TrackEffectsOptions,
71
- ): Effect.Effect<ReadonlyArray<A>, E, Exclude<R, Progress>> =>
72
- withProgressService(
49
+ export const all = <
50
+ const Arg extends ReadonlyArray<Effect.Effect<any, any, any>>,
51
+ O extends EffectAllExecutionOptions,
52
+ >(
53
+ effects: Arg,
54
+ options: Omit<TrackOptions, "total"> & O,
55
+ ): AllReturn<Arg, O> =>
56
+ provide(
73
57
  Effect.gen(function* () {
74
58
  const progress = yield* Progress;
75
59
  return yield* progress.withTask(
76
60
  {
77
61
  description: options.description,
78
- total: options.total ?? effects.length,
62
+ total: effects.length,
79
63
  transient: options.transient,
64
+ progressbar: options.progressbar,
80
65
  },
81
66
  (taskId) =>
82
- Effect.forEach(
83
- effects.map((effect) => Effect.tap(effect, () => progress.advanceTask(taskId, 1))),
84
- (effect) => effect,
67
+ Effect.all(
68
+ effects.map((effect) =>
69
+ Effect.tap(progress.withCapturedLogs(effect), () => progress.advanceTask(taskId, 1)),
70
+ ),
85
71
  {
86
- concurrency: options.all?.concurrency,
87
- batching: options.all?.batching,
88
- concurrentFinalizers: options.all?.concurrentFinalizers,
72
+ concurrency: options.concurrency,
73
+ batching: options.batching,
74
+ discard: options.discard,
75
+ mode: options.mode,
76
+ concurrentFinalizers: options.concurrentFinalizers,
89
77
  },
90
78
  ),
91
79
  );
92
80
  }),
93
- );
81
+ ) as AllReturn<Arg, O>;
94
82
 
95
83
  export const forEach = <A, B, E, R>(
96
84
  iterable: Iterable<A>,
97
85
  f: (item: A, index: number) => Effect.Effect<B, E, R>,
98
86
  options: ForEachOptions,
99
87
  ): Effect.Effect<ReadonlyArray<B>, E, Exclude<R, Progress>> =>
100
- withProgressService(
88
+ provide(
101
89
  Effect.gen(function* () {
102
90
  const progress = yield* Progress;
103
91
 
104
- const items = Array.from(iterable);
105
- const total = options.total ?? inferTotal(iterable);
106
-
107
92
  return yield* progress.withTask(
108
93
  {
109
94
  description: options.description,
110
- total,
95
+ total: options.total ?? inferTotal(iterable),
111
96
  transient: options.transient,
97
+ progressbar: options.progressbar,
112
98
  },
113
99
  (taskId) =>
114
100
  Effect.forEach(
115
- items,
116
- (item, index) => Effect.tap(f(item, index), () => progress.advanceTask(taskId, 1)),
101
+ iterable,
102
+ (item, index) =>
103
+ Effect.tap(progress.withCapturedLogs(f(item, index)), () =>
104
+ progress.advanceTask(taskId, 1),
105
+ ),
117
106
  {
118
- concurrency: options.forEach?.concurrency,
119
- batching: options.forEach?.batching,
120
- concurrentFinalizers: options.forEach?.concurrentFinalizers,
107
+ concurrency: options.concurrency,
108
+ batching: options.batching,
109
+ discard: options.discard,
110
+ concurrentFinalizers: options.concurrentFinalizers,
121
111
  },
122
112
  ),
123
113
  );
124
114
  }),
125
115
  );
126
-
127
- export const trackProgress = all;
128
-
129
- export const track = <A, B, E, R>(
130
- iterable: Iterable<A>,
131
- options: TrackOptions,
132
- f: (item: A, index: number) => Effect.Effect<B, E, R>,
133
- ): Effect.Effect<ReadonlyArray<B>, E, Exclude<R, Progress>> =>
134
- forEach(iterable, f, options);
package/src/colors.ts ADDED
@@ -0,0 +1,206 @@
1
+ import chalk from "chalk";
2
+ import type { ChalkInstance } from "chalk";
3
+ import { Schema } from "effect";
4
+
5
+ export const StyleModifierSchema = Schema.Literal(
6
+ "bold",
7
+ "dim",
8
+ "italic",
9
+ "underline",
10
+ "inverse",
11
+ "hidden",
12
+ "strikethrough",
13
+ );
14
+ export type StyleModifier = typeof StyleModifierSchema.Type;
15
+
16
+ export const NamedColorSchema = Schema.Literal(
17
+ "black",
18
+ "red",
19
+ "green",
20
+ "yellow",
21
+ "blue",
22
+ "magenta",
23
+ "cyan",
24
+ "white",
25
+ "blackBright",
26
+ "redBright",
27
+ "greenBright",
28
+ "yellowBright",
29
+ "blueBright",
30
+ "magentaBright",
31
+ "cyanBright",
32
+ "whiteBright",
33
+ );
34
+ export type NamedColor = typeof NamedColorSchema.Type;
35
+
36
+ const HexColorSchema = Schema.String.pipe(Schema.pattern(/^#(?:[A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/));
37
+ const ColorChannelSchema = Schema.Number.pipe(
38
+ Schema.int(),
39
+ Schema.greaterThanOrEqualTo(0),
40
+ Schema.lessThanOrEqualTo(255),
41
+ );
42
+ const Ansi256Schema = Schema.Number.pipe(
43
+ Schema.int(),
44
+ Schema.greaterThanOrEqualTo(0),
45
+ Schema.lessThanOrEqualTo(255),
46
+ );
47
+ const ModifiersSchema = Schema.optional(Schema.Array(StyleModifierSchema));
48
+
49
+ export const NamedColorStyleSchema = Schema.Struct({
50
+ kind: Schema.Literal("named"),
51
+ value: NamedColorSchema,
52
+ modifiers: ModifiersSchema,
53
+ });
54
+
55
+ export const HexColorStyleSchema = Schema.Struct({
56
+ kind: Schema.Literal("hex"),
57
+ value: HexColorSchema,
58
+ modifiers: ModifiersSchema,
59
+ });
60
+
61
+ export const RgbColorStyleSchema = Schema.Struct({
62
+ kind: Schema.Literal("rgb"),
63
+ value: Schema.Struct({
64
+ r: ColorChannelSchema,
65
+ g: ColorChannelSchema,
66
+ b: ColorChannelSchema,
67
+ }),
68
+ modifiers: ModifiersSchema,
69
+ });
70
+
71
+ export const Ansi256ColorStyleSchema = Schema.Struct({
72
+ kind: Schema.Literal("ansi256"),
73
+ value: Ansi256Schema,
74
+ modifiers: ModifiersSchema,
75
+ });
76
+
77
+ export const ColorStyleSchema = Schema.Union(
78
+ NamedColorStyleSchema,
79
+ HexColorStyleSchema,
80
+ RgbColorStyleSchema,
81
+ Ansi256ColorStyleSchema,
82
+ );
83
+ export type ColorStyle = typeof ColorStyleSchema.Type;
84
+
85
+ export const ProgressBarColorsSchema = Schema.Struct({
86
+ fill: ColorStyleSchema,
87
+ empty: ColorStyleSchema,
88
+ brackets: ColorStyleSchema,
89
+ percent: ColorStyleSchema,
90
+ spinner: ColorStyleSchema,
91
+ done: ColorStyleSchema,
92
+ failed: ColorStyleSchema,
93
+ });
94
+ export type ProgressBarColors = typeof ProgressBarColorsSchema.Type;
95
+
96
+ export const defaultProgressBarColors: ProgressBarColors = {
97
+ fill: { kind: "named", value: "cyan" },
98
+ empty: { kind: "named", value: "white", modifiers: ["dim"] },
99
+ brackets: { kind: "named", value: "white", modifiers: ["dim"] },
100
+ percent: { kind: "named", value: "white", modifiers: ["bold"] },
101
+ spinner: { kind: "named", value: "yellow" },
102
+ done: { kind: "named", value: "green" },
103
+ failed: { kind: "named", value: "red" },
104
+ };
105
+
106
+ const applyModifier = (instance: ChalkInstance, modifier: StyleModifier): ChalkInstance => {
107
+ switch (modifier) {
108
+ case "bold":
109
+ return instance.bold;
110
+ case "dim":
111
+ return instance.dim;
112
+ case "italic":
113
+ return instance.italic;
114
+ case "underline":
115
+ return instance.underline;
116
+ case "inverse":
117
+ return instance.inverse;
118
+ case "hidden":
119
+ return instance.hidden;
120
+ case "strikethrough":
121
+ return instance.strikethrough;
122
+ }
123
+ };
124
+
125
+ const applyNamedColor = (instance: ChalkInstance, color: NamedColor): ChalkInstance => {
126
+ switch (color) {
127
+ case "black":
128
+ return instance.black;
129
+ case "red":
130
+ return instance.red;
131
+ case "green":
132
+ return instance.green;
133
+ case "yellow":
134
+ return instance.yellow;
135
+ case "blue":
136
+ return instance.blue;
137
+ case "magenta":
138
+ return instance.magenta;
139
+ case "cyan":
140
+ return instance.cyan;
141
+ case "white":
142
+ return instance.white;
143
+ case "blackBright":
144
+ return instance.blackBright;
145
+ case "redBright":
146
+ return instance.redBright;
147
+ case "greenBright":
148
+ return instance.greenBright;
149
+ case "yellowBright":
150
+ return instance.yellowBright;
151
+ case "blueBright":
152
+ return instance.blueBright;
153
+ case "magentaBright":
154
+ return instance.magentaBright;
155
+ case "cyanBright":
156
+ return instance.cyanBright;
157
+ case "whiteBright":
158
+ return instance.whiteBright;
159
+ }
160
+ };
161
+
162
+ const resolveBaseStyle = (style: ColorStyle): ChalkInstance => {
163
+ switch (style.kind) {
164
+ case "named":
165
+ return applyNamedColor(chalk, style.value);
166
+ case "hex":
167
+ return chalk.hex(style.value);
168
+ case "rgb":
169
+ return chalk.rgb(style.value.r, style.value.g, style.value.b);
170
+ case "ansi256":
171
+ return chalk.ansi256(style.value);
172
+ }
173
+ };
174
+
175
+ const applyModifiers = (instance: ChalkInstance, modifiers: ReadonlyArray<StyleModifier>) => {
176
+ let styled = instance;
177
+ for (const modifier of modifiers) {
178
+ styled = applyModifier(styled, modifier);
179
+ }
180
+ return styled;
181
+ };
182
+
183
+ export const applyColorStyle = (style: ColorStyle, text: string): string => {
184
+ const styled = applyModifiers(resolveBaseStyle(style), style.modifiers ?? []);
185
+ return styled(text);
186
+ };
187
+
188
+ export interface CompiledProgressBarColors {
189
+ readonly fill: (text: string) => string;
190
+ readonly empty: (text: string) => string;
191
+ readonly brackets: (text: string) => string;
192
+ readonly percent: (text: string) => string;
193
+ readonly spinner: (text: string) => string;
194
+ readonly done: (text: string) => string;
195
+ readonly failed: (text: string) => string;
196
+ }
197
+
198
+ export const compileProgressBarColors = (colors: ProgressBarColors): CompiledProgressBarColors => ({
199
+ fill: (text) => applyColorStyle(colors.fill, text),
200
+ empty: (text) => applyColorStyle(colors.empty, text),
201
+ brackets: (text) => applyColorStyle(colors.brackets, text),
202
+ percent: (text) => applyColorStyle(colors.percent, text),
203
+ spinner: (text) => applyColorStyle(colors.spinner, text),
204
+ done: (text) => applyColorStyle(colors.done, text),
205
+ failed: (text) => applyColorStyle(colors.failed, text),
206
+ });
package/src/console.ts CHANGED
@@ -1,14 +1,13 @@
1
1
  import { Console, Effect } from "effect";
2
2
  import { formatWithOptions } from "node:util";
3
- import type { ProgressService } from "./types";
4
3
 
5
4
  export const makeProgressConsole = (
6
- progress: ProgressService,
5
+ progressLog: (...args: ReadonlyArray<unknown>) => Effect.Effect<void, never, never>,
7
6
  outerConsole: Console.Console,
8
7
  ): Console.Console => {
9
- const log = (...args: ReadonlyArray<unknown>) => progress.log(...args);
8
+ const log = (...args: ReadonlyArray<unknown>) => progressLog(...args);
10
9
  const unsafeLog = (...args: ReadonlyArray<unknown>) => {
11
- Effect.runFork(progress.log(...args));
10
+ Effect.runFork(progressLog(...args));
12
11
  };
13
12
 
14
13
  const delegate = (effect: Effect.Effect<void, never, never>) => effect;
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./api";
2
+ export * from "./colors";
2
3
  export * from "./runtime";
3
4
  export * from "./types";