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/src/types.ts CHANGED
@@ -1,39 +1,55 @@
1
1
  import { Brand, Context, Effect, Option, Schema } from "effect";
2
+ import type { PartialDeep } from "type-fest";
3
+ import { defaultProgressBarColors, ProgressBarColorsSchema } from "./colors";
2
4
 
3
- export const SPINNER_FRAMES = ["-", "\\", "|", "/"] as const;
4
- export const DEFAULT_PROGRESS_BAR_WIDTH = 30;
5
-
6
- export const ProgressBarConfigSchema = Schema.Struct({
5
+ export const RendererConfigSchema = Schema.Struct({
7
6
  isTTY: Schema.Boolean,
8
7
  disableUserInput: Schema.Boolean,
8
+ renderIntervalMillis: Schema.Number,
9
+ maxLogLines: Schema.optional(Schema.Number),
10
+ nonTtyUpdateStep: Schema.Number,
11
+ });
12
+ export type RendererConfigShape = typeof RendererConfigSchema.Type;
13
+ export const decodeRendererConfigSync = Schema.decodeUnknownSync(RendererConfigSchema);
14
+
15
+ export const ProgressBarConfigSchema = Schema.Struct({
9
16
  spinnerFrames: Schema.NonEmptyArray(Schema.String),
10
17
  barWidth: Schema.Number,
11
18
  fillChar: Schema.String,
12
19
  emptyChar: Schema.String,
13
20
  leftBracket: Schema.String,
14
21
  rightBracket: Schema.String,
15
- maxLogLines: Schema.Number,
16
- nonTtyUpdateStep: Schema.Number,
22
+ colors: ProgressBarColorsSchema,
17
23
  });
18
-
19
24
  export type ProgressBarConfigShape = typeof ProgressBarConfigSchema.Type;
25
+ export const decodeProgressBarConfigSync = Schema.decodeUnknownSync(ProgressBarConfigSchema);
20
26
 
21
- export const defaultProgressBarConfig: ProgressBarConfigShape = {
27
+ export const defaultRendererConfig: RendererConfigShape = {
22
28
  isTTY: Boolean(process.stderr.isTTY),
23
29
  disableUserInput: true,
24
- spinnerFrames: SPINNER_FRAMES,
25
- barWidth: DEFAULT_PROGRESS_BAR_WIDTH,
30
+ renderIntervalMillis: 50, // 20 FPS
31
+ maxLogLines: 0,
32
+ nonTtyUpdateStep: 5,
33
+ };
34
+
35
+ export const defaultProgressBarConfig: ProgressBarConfigShape = {
36
+ spinnerFrames: ["-", "\\", "|", "/"],
37
+ barWidth: 30,
26
38
  fillChar: "━",
27
39
  emptyChar: "─",
28
40
  leftBracket: "",
29
41
  rightBracket: "",
30
- maxLogLines: 0,
31
- nonTtyUpdateStep: 5,
42
+ colors: defaultProgressBarColors,
32
43
  };
33
44
 
45
+ export class RendererConfig extends Context.Tag("stromseng.dev/RendererConfig")<
46
+ RendererConfig,
47
+ PartialDeep<RendererConfigShape>
48
+ >() {}
49
+
34
50
  export class ProgressBarConfig extends Context.Tag("stromseng.dev/ProgressBarConfig")<
35
51
  ProgressBarConfig,
36
- ProgressBarConfigShape
52
+ PartialDeep<ProgressBarConfigShape>
37
53
  >() {}
38
54
 
39
55
  const TaskIdSchema = Schema.Number.pipe(Schema.brand("TaskId"));
@@ -50,6 +66,7 @@ export interface AddTaskOptions {
50
66
  readonly total?: number;
51
67
  readonly transient?: boolean;
52
68
  readonly parentId?: TaskId;
69
+ readonly progressbar?: PartialDeep<ProgressBarConfigShape>;
53
70
  }
54
71
 
55
72
  export interface UpdateTaskOptions {
@@ -59,11 +76,7 @@ export interface UpdateTaskOptions {
59
76
  readonly transient?: boolean;
60
77
  }
61
78
 
62
- export interface TrackOptions {
63
- readonly description: string;
64
- readonly total?: number;
65
- readonly transient?: boolean;
66
- }
79
+ export type TrackOptions = Exclude<AddTaskOptions, "parentId">;
67
80
 
68
81
  export class DeterminateTaskUnits extends Schema.TaggedClass<DeterminateTaskUnits>()(
69
82
  "DeterminateTaskUnits",
@@ -91,6 +104,7 @@ export class TaskSnapshot extends Schema.TaggedClass<TaskSnapshot>()("TaskSnapsh
91
104
  status: TaskStatusSchema,
92
105
  transient: Schema.Boolean,
93
106
  units: TaskUnitsSchema,
107
+ progressbar: ProgressBarConfigSchema,
94
108
  }) {}
95
109
 
96
110
  export interface ProgressService {
@@ -100,6 +114,7 @@ export interface ProgressService {
100
114
  readonly completeTask: (taskId: TaskId) => Effect.Effect<void>;
101
115
  readonly failTask: (taskId: TaskId) => Effect.Effect<void>;
102
116
  readonly log: (...args: ReadonlyArray<unknown>) => Effect.Effect<void>;
117
+ readonly withCapturedLogs: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
103
118
  readonly getTask: (taskId: TaskId) => Effect.Effect<Option.Option<TaskSnapshot>>;
104
119
  readonly listTasks: Effect.Effect<ReadonlyArray<TaskSnapshot>>;
105
120
  readonly withTask: <A, E, R>(
@@ -160,8 +175,3 @@ export const ProgressTaskEventSchema = Schema.Union(
160
175
  export type ProgressTaskEvent = typeof ProgressTaskEventSchema.Type;
161
176
 
162
177
  export const decodeProgressTaskEvent = Schema.decodeUnknownSync(ProgressTaskEventSchema);
163
-
164
- export const isIndeterminateTask = (snapshot: TaskSnapshot) =>
165
- snapshot.units._tag === "IndeterminateTaskUnits";
166
-
167
- export const nextSpinnerFrame = (index: number) => (index + 1) % SPINNER_FRAMES.length;
package/src/utils.ts ADDED
@@ -0,0 +1,20 @@
1
+ export const inferTotal = (iterable: Iterable<unknown>): number | undefined => {
2
+ if (Array.isArray(iterable)) {
3
+ return iterable.length;
4
+ }
5
+
6
+ if (typeof iterable === "string") {
7
+ return iterable.length;
8
+ }
9
+
10
+ const candidate = iterable as { length?: unknown; size?: unknown };
11
+ if (typeof candidate.length === "number") {
12
+ return candidate.length;
13
+ }
14
+
15
+ if (typeof candidate.size === "number") {
16
+ return candidate.size;
17
+ }
18
+
19
+ return undefined;
20
+ };