@tsed/cli-tasks 7.0.0-beta.13
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/lib/esm/domain/TaskLogger.js +270 -0
- package/lib/esm/fn/taskLogger.js +4 -0
- package/lib/esm/index.js +4 -0
- package/lib/esm/interfaces/Task.js +1 -0
- package/lib/esm/tasks.js +101 -0
- package/lib/tsconfig.esm.tsbuildinfo +1 -0
- package/lib/types/domain/TaskLogger.d.ts +37 -0
- package/lib/types/fn/taskLogger.d.ts +2 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/interfaces/Task.d.ts +12 -0
- package/lib/types/tasks.d.ts +12 -0
- package/package.json +53 -0
- package/src/domain/TaskLogger.spec.ts +324 -0
- package/src/domain/TaskLogger.ts +319 -0
- package/src/fn/taskLogger.ts +5 -0
- package/src/index.ts +4 -0
- package/src/interfaces/Task.ts +15 -0
- package/src/tasks.spec.ts +193 -0
- package/src/tasks.ts +131 -0
- package/test.js +68 -0
- package/tsconfig.esm.json +27 -0
- package/vitest.config.mts +20 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import {contextLogger, DITest, runInContext} from "@tsed/di";
|
|
2
|
+
import type {MockInstance} from "vitest";
|
|
3
|
+
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
|
|
4
|
+
|
|
5
|
+
import type {TaskLogger as TaskLoggerClass} from "./TaskLogger.js";
|
|
6
|
+
|
|
7
|
+
type ProgressStub = {
|
|
8
|
+
start: ReturnType<typeof vi.fn>;
|
|
9
|
+
stop: ReturnType<typeof vi.fn>;
|
|
10
|
+
advance: ReturnType<typeof vi.fn>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type SpinnerStub = {
|
|
14
|
+
start: ReturnType<typeof vi.fn>;
|
|
15
|
+
stop: ReturnType<typeof vi.fn>;
|
|
16
|
+
message: ReturnType<typeof vi.fn>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type TaskLogStub = {
|
|
20
|
+
title: string;
|
|
21
|
+
info: ReturnType<typeof vi.fn>;
|
|
22
|
+
warn: ReturnType<typeof vi.fn>;
|
|
23
|
+
error: ReturnType<typeof vi.fn>;
|
|
24
|
+
message: ReturnType<typeof vi.fn>;
|
|
25
|
+
success: ReturnType<typeof vi.fn>;
|
|
26
|
+
group: ReturnType<typeof vi.fn>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type LogMock = {
|
|
30
|
+
info: ReturnType<typeof vi.fn>;
|
|
31
|
+
warn: ReturnType<typeof vi.fn>;
|
|
32
|
+
error: ReturnType<typeof vi.fn>;
|
|
33
|
+
message: ReturnType<typeof vi.fn>;
|
|
34
|
+
success: ReturnType<typeof vi.fn>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type ClackMocks = {
|
|
38
|
+
logMock: LogMock;
|
|
39
|
+
progressInstances: ProgressStub[];
|
|
40
|
+
spinnerInstances: SpinnerStub[];
|
|
41
|
+
taskLogInstances: TaskLogStub[];
|
|
42
|
+
progressMock: ReturnType<typeof vi.fn>;
|
|
43
|
+
spinnerMock: ReturnType<typeof vi.fn>;
|
|
44
|
+
taskLogMock: ReturnType<typeof vi.fn>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const clack = vi.hoisted(() => {
|
|
48
|
+
const logMock: LogMock = {
|
|
49
|
+
info: vi.fn(),
|
|
50
|
+
warn: vi.fn(),
|
|
51
|
+
error: vi.fn(),
|
|
52
|
+
message: vi.fn(),
|
|
53
|
+
success: vi.fn()
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const progressInstances: ProgressStub[] = [];
|
|
57
|
+
const spinnerInstances: SpinnerStub[] = [];
|
|
58
|
+
const taskLogInstances: TaskLogStub[] = [];
|
|
59
|
+
|
|
60
|
+
const createProgressInstance = () => {
|
|
61
|
+
const instance: ProgressStub = {
|
|
62
|
+
start: vi.fn(),
|
|
63
|
+
stop: vi.fn(),
|
|
64
|
+
advance: vi.fn()
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
progressInstances.push(instance);
|
|
68
|
+
return instance;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const createSpinnerInstance = () => {
|
|
72
|
+
const instance: SpinnerStub = {
|
|
73
|
+
start: vi.fn(),
|
|
74
|
+
stop: vi.fn(),
|
|
75
|
+
message: vi.fn()
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
spinnerInstances.push(instance);
|
|
79
|
+
return instance;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const createTaskLogInstance = (title: string): TaskLogStub => {
|
|
83
|
+
const instance: TaskLogStub = {
|
|
84
|
+
title,
|
|
85
|
+
info: vi.fn(),
|
|
86
|
+
warn: vi.fn(),
|
|
87
|
+
error: vi.fn(),
|
|
88
|
+
message: vi.fn(),
|
|
89
|
+
success: vi.fn(),
|
|
90
|
+
group: vi.fn()
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
instance.group.mockImplementation((childTitle: string) => createTaskLogInstance(childTitle));
|
|
94
|
+
taskLogInstances.push(instance);
|
|
95
|
+
|
|
96
|
+
return instance;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
logMock,
|
|
101
|
+
progressInstances,
|
|
102
|
+
spinnerInstances,
|
|
103
|
+
taskLogInstances,
|
|
104
|
+
progressMock: vi.fn(() => createProgressInstance()),
|
|
105
|
+
spinnerMock: vi.fn(() => createSpinnerInstance()),
|
|
106
|
+
taskLogMock: vi.fn(({title}: {title: string}) => createTaskLogInstance(title))
|
|
107
|
+
};
|
|
108
|
+
}) as ClackMocks;
|
|
109
|
+
|
|
110
|
+
vi.mock("@clack/prompts", () => ({
|
|
111
|
+
log: clack.logMock,
|
|
112
|
+
progress: clack.progressMock,
|
|
113
|
+
spinner: clack.spinnerMock,
|
|
114
|
+
taskLog: clack.taskLogMock
|
|
115
|
+
}));
|
|
116
|
+
|
|
117
|
+
const {logMock, progressInstances, spinnerInstances, taskLogInstances} = clack;
|
|
118
|
+
const originalNodeEnv = process.env.NODE_ENV;
|
|
119
|
+
|
|
120
|
+
describe("TaskLogger", () => {
|
|
121
|
+
beforeEach(() => {
|
|
122
|
+
vi.clearAllMocks();
|
|
123
|
+
progressInstances.length = 0;
|
|
124
|
+
spinnerInstances.length = 0;
|
|
125
|
+
taskLogInstances.length = 0;
|
|
126
|
+
process.env.NODE_ENV = "development";
|
|
127
|
+
|
|
128
|
+
return DITest.create({
|
|
129
|
+
env: "test"
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
afterEach(() => {
|
|
134
|
+
process.env.NODE_ENV = originalNodeEnv;
|
|
135
|
+
return DITest.reset();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("logs start/done using the default log prompt", () => {
|
|
139
|
+
const logger = TaskLogger.from({
|
|
140
|
+
title: "Build project",
|
|
141
|
+
index: 0
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(logger.type).toBe("log");
|
|
145
|
+
|
|
146
|
+
logger.start();
|
|
147
|
+
logger.done();
|
|
148
|
+
|
|
149
|
+
expect(logMock.info).toHaveBeenCalledWith("Build project...");
|
|
150
|
+
expect(logMock.success).toHaveBeenCalledWith("Build project completed");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("emits message when the title changes", () => {
|
|
154
|
+
const logger = TaskLogger.from({
|
|
155
|
+
title: "Initial",
|
|
156
|
+
index: 0
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
logger.title = "Updated title";
|
|
160
|
+
|
|
161
|
+
expect(logMock.message).toHaveBeenCalledWith("Updated title");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("advances the parent progress bar for child progress tasks", () => {
|
|
165
|
+
const parent = new TaskLogger({
|
|
166
|
+
title: "Install dependencies",
|
|
167
|
+
index: 0,
|
|
168
|
+
type: "progress"
|
|
169
|
+
});
|
|
170
|
+
parent.max = 4;
|
|
171
|
+
|
|
172
|
+
const child = TaskLogger.from({
|
|
173
|
+
title: "Install packages",
|
|
174
|
+
index: 1,
|
|
175
|
+
parent
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
child.start();
|
|
179
|
+
|
|
180
|
+
expect(progressInstances[0]?.advance).toHaveBeenCalledWith(25, "Install packages");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("returns the spinner parent when nested spinner tasks are requested", () => {
|
|
184
|
+
const spinnerParent = new TaskLogger({
|
|
185
|
+
title: "Loading spinner",
|
|
186
|
+
index: 0,
|
|
187
|
+
type: "spinner"
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const nested = TaskLogger.from({
|
|
191
|
+
title: "Nested spinner",
|
|
192
|
+
index: 1,
|
|
193
|
+
parent: spinnerParent
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(nested).toBe(spinnerParent);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("marks taskLog children as skipped via error logger", () => {
|
|
200
|
+
const parent = new TaskLogger({
|
|
201
|
+
title: "Parent log",
|
|
202
|
+
index: 0,
|
|
203
|
+
type: "taskLog"
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const child = TaskLogger.from({
|
|
207
|
+
title: "Child log",
|
|
208
|
+
index: 1,
|
|
209
|
+
parent
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
child.skip();
|
|
213
|
+
|
|
214
|
+
const childLogger = taskLogInstances.find((instance) => instance.title === "Child log");
|
|
215
|
+
expect(childLogger?.error).toHaveBeenCalledWith("Child log skipped...");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("creates grouped loggers for nested taskLog hierarchies", () => {
|
|
219
|
+
const root = new TaskLogger({
|
|
220
|
+
title: "Root task",
|
|
221
|
+
index: 0,
|
|
222
|
+
type: "taskLog"
|
|
223
|
+
});
|
|
224
|
+
const child = TaskLogger.from({
|
|
225
|
+
title: "Child task",
|
|
226
|
+
index: 1,
|
|
227
|
+
parent: root
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
TaskLogger.from({
|
|
231
|
+
title: "Grandchild task",
|
|
232
|
+
index: 2,
|
|
233
|
+
parent: child
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const childLogger = taskLogInstances.find((instance) => instance.title === "Child task");
|
|
237
|
+
const grandChildLogger = taskLogInstances.find((instance) => instance.title === "Grandchild task");
|
|
238
|
+
|
|
239
|
+
expect(childLogger?.group).toHaveBeenCalledWith("Grandchild task");
|
|
240
|
+
expect(grandChildLogger).toBeDefined();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("routes verbose output through the context logger", async () => {
|
|
244
|
+
const ctx = DITest.createDIContext();
|
|
245
|
+
let infoSpy!: MockInstance;
|
|
246
|
+
let warnSpy!: MockInstance;
|
|
247
|
+
let errorSpy!: MockInstance;
|
|
248
|
+
|
|
249
|
+
await runInContext(ctx, () => {
|
|
250
|
+
const scopedLogger = contextLogger();
|
|
251
|
+
infoSpy = vi.spyOn(scopedLogger, "info");
|
|
252
|
+
warnSpy = vi.spyOn(scopedLogger, "warn");
|
|
253
|
+
errorSpy = vi.spyOn(scopedLogger, "error");
|
|
254
|
+
|
|
255
|
+
const logger = new TaskLogger({
|
|
256
|
+
title: "Verbose task",
|
|
257
|
+
index: 0,
|
|
258
|
+
type: "log",
|
|
259
|
+
verbose: true
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
logger.message("hello");
|
|
263
|
+
logger.warn("be careful");
|
|
264
|
+
logger.error("boom");
|
|
265
|
+
logger.report("report payload");
|
|
266
|
+
|
|
267
|
+
return logger;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
expect(infoSpy).toHaveBeenCalledWith({
|
|
271
|
+
state: "MSG",
|
|
272
|
+
title: "Verbose task",
|
|
273
|
+
message: "Verbose task - hello"
|
|
274
|
+
});
|
|
275
|
+
expect(warnSpy).toHaveBeenCalledWith({
|
|
276
|
+
title: "Verbose task",
|
|
277
|
+
message: "Verbose task - be careful"
|
|
278
|
+
});
|
|
279
|
+
expect(errorSpy).toHaveBeenCalledWith({
|
|
280
|
+
title: "Verbose task",
|
|
281
|
+
message: "Verbose task - boom"
|
|
282
|
+
});
|
|
283
|
+
expect(infoSpy).toHaveBeenCalledWith({
|
|
284
|
+
title: "Verbose task",
|
|
285
|
+
message: "report payload"
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("does not emit context logger output when NODE_ENV=test", async () => {
|
|
290
|
+
process.env.NODE_ENV = "test";
|
|
291
|
+
const ctx = DITest.createDIContext();
|
|
292
|
+
|
|
293
|
+
await runInContext(ctx, () => {
|
|
294
|
+
const scopedLogger = contextLogger();
|
|
295
|
+
const infoSpy = vi.spyOn(scopedLogger, "info");
|
|
296
|
+
|
|
297
|
+
const logger = new TaskLogger({
|
|
298
|
+
title: "Suppressed task",
|
|
299
|
+
index: 0,
|
|
300
|
+
type: "log",
|
|
301
|
+
verbose: true
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
logger.message("should not show");
|
|
305
|
+
expect(infoSpy).not.toHaveBeenCalled();
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("writes raw output through info fallback", () => {
|
|
310
|
+
const logger = TaskLogger.from({
|
|
311
|
+
title: "Output task",
|
|
312
|
+
index: 0
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
logger.output = "custom message";
|
|
316
|
+
|
|
317
|
+
expect(logMock.info).toHaveBeenCalledWith("custom message");
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
let TaskLogger: typeof TaskLoggerClass;
|
|
321
|
+
|
|
322
|
+
beforeAll(async () => {
|
|
323
|
+
({TaskLogger} = await import("./TaskLogger.js"));
|
|
324
|
+
});
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import {log, progress, spinner, taskLog} from "@clack/prompts";
|
|
2
|
+
import {contextLogger} from "@tsed/di";
|
|
3
|
+
|
|
4
|
+
export interface TaskLoggerOptions {
|
|
5
|
+
title: string;
|
|
6
|
+
index: number;
|
|
7
|
+
type?: "group" | "taskLog" | "log" | "spinner" | "progress";
|
|
8
|
+
parent?: TaskLogger;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class TaskLogger {
|
|
13
|
+
readonly type: TaskLoggerOptions["type"];
|
|
14
|
+
public max: number;
|
|
15
|
+
#title: string;
|
|
16
|
+
#logger: any;
|
|
17
|
+
#verbose: boolean | undefined;
|
|
18
|
+
#parent: TaskLogger | undefined;
|
|
19
|
+
#index: number;
|
|
20
|
+
|
|
21
|
+
constructor(opts: TaskLoggerOptions) {
|
|
22
|
+
this.#title = opts.title;
|
|
23
|
+
this.type = opts.type;
|
|
24
|
+
this.#parent = opts.parent;
|
|
25
|
+
this.#verbose = opts.verbose;
|
|
26
|
+
|
|
27
|
+
this.#logger = this.create({
|
|
28
|
+
...opts,
|
|
29
|
+
verbose: this.#verbose
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get parent() {
|
|
34
|
+
return this.#parent;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get isReady() {
|
|
38
|
+
return !!this.#logger;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get title() {
|
|
42
|
+
return this.#title;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
set title(title: string) {
|
|
46
|
+
if (title) {
|
|
47
|
+
this.#title = title;
|
|
48
|
+
this.#logger.message?.(title);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
set output(message: string) {
|
|
53
|
+
if (message) {
|
|
54
|
+
(this.#logger.info || this.#logger.message)?.(message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static from(opts: TaskLoggerOptions) {
|
|
59
|
+
if (opts.parent) {
|
|
60
|
+
switch (opts.parent.type) {
|
|
61
|
+
case "progress":
|
|
62
|
+
return new TaskLogger({
|
|
63
|
+
...opts,
|
|
64
|
+
type: "progress",
|
|
65
|
+
parent: opts.parent
|
|
66
|
+
});
|
|
67
|
+
case "spinner":
|
|
68
|
+
return opts.parent;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (opts.parent) {
|
|
73
|
+
if (opts.parent?.parent) {
|
|
74
|
+
opts.type = opts.type || "group";
|
|
75
|
+
} else {
|
|
76
|
+
opts.type = opts.type || "taskLog";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
opts.type = opts.type || "log";
|
|
81
|
+
|
|
82
|
+
return new TaskLogger(opts);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
log(message: string) {
|
|
86
|
+
this.#logger.message(`${this.title} - ${message}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
message(message: string) {
|
|
90
|
+
this.#logger.message(`${this.title} - ${message}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
advance() {
|
|
94
|
+
if (this.isReady && this.type === "progress") {
|
|
95
|
+
if (this.isRaw()) {
|
|
96
|
+
this.info(`${this.title} [${this.#index}/${this.parent!.max}]`);
|
|
97
|
+
} else {
|
|
98
|
+
const it = Math.round((1 / this.parent!.max) * 100);
|
|
99
|
+
this.#logger.advance(it, this.title);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
start() {
|
|
107
|
+
if (this.isReady) {
|
|
108
|
+
const msg = `${this.title}...`;
|
|
109
|
+
switch (this.type) {
|
|
110
|
+
default:
|
|
111
|
+
this.#logger.message(msg);
|
|
112
|
+
break;
|
|
113
|
+
case "log":
|
|
114
|
+
this.#logger.info(msg);
|
|
115
|
+
break;
|
|
116
|
+
case "progress":
|
|
117
|
+
if (this.isChildProgress()) {
|
|
118
|
+
this.advance();
|
|
119
|
+
} else {
|
|
120
|
+
this.#logger.start(this.title);
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
case "spinner":
|
|
124
|
+
this.#logger.start(this.title);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
done() {
|
|
133
|
+
if (this.isReady) {
|
|
134
|
+
const msg = `${this.title} completed`;
|
|
135
|
+
|
|
136
|
+
switch (this.type) {
|
|
137
|
+
default:
|
|
138
|
+
this.#logger.success(msg);
|
|
139
|
+
break;
|
|
140
|
+
case "progress":
|
|
141
|
+
if (!this.isChildProgress()) {
|
|
142
|
+
this.#logger.stop(msg);
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
case "spinner":
|
|
146
|
+
this.#logger.stop(msg);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
error(message: string | Error) {
|
|
155
|
+
if (this.isReady) {
|
|
156
|
+
this.#logger.error(`${this.title} - ${message}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
info(message: string) {
|
|
163
|
+
if (this.isReady) {
|
|
164
|
+
switch (this.type) {
|
|
165
|
+
case "log":
|
|
166
|
+
case "taskLog":
|
|
167
|
+
this.#logger.info(`${this.title} - ${message}`);
|
|
168
|
+
break;
|
|
169
|
+
default:
|
|
170
|
+
this.#logger.message(`${this.title} - ${message}`);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
warn(message: string) {
|
|
179
|
+
if (this.isReady) {
|
|
180
|
+
switch (this.type) {
|
|
181
|
+
case "log":
|
|
182
|
+
case "taskLog":
|
|
183
|
+
this.#logger.warn(`${this.title} - ${message}`);
|
|
184
|
+
break;
|
|
185
|
+
default:
|
|
186
|
+
this.#logger.message(`${this.title} - WARN ${message}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
skip() {
|
|
194
|
+
if (this.isReady) {
|
|
195
|
+
switch (this.type) {
|
|
196
|
+
default:
|
|
197
|
+
case "log":
|
|
198
|
+
this.#logger.warn(`${this.title} skipped...`);
|
|
199
|
+
break;
|
|
200
|
+
case "group":
|
|
201
|
+
case "taskLog":
|
|
202
|
+
this.#logger.error(`${this.title} skipped...`);
|
|
203
|
+
break;
|
|
204
|
+
case "progress":
|
|
205
|
+
this.advance();
|
|
206
|
+
break;
|
|
207
|
+
case "spinner":
|
|
208
|
+
this.#logger.stop(`${this.title} skipped...`);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @ddeprecated use info or message instead
|
|
217
|
+
* @param message
|
|
218
|
+
*/
|
|
219
|
+
report(message: string) {
|
|
220
|
+
(this.#logger.info || this.#logger.message)?.(message);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected isChildProgress() {
|
|
224
|
+
return this.parent?.type === "progress" && this.type === "progress";
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
protected create(opts: TaskLoggerOptions) {
|
|
228
|
+
const {type, title, parent} = opts;
|
|
229
|
+
|
|
230
|
+
if (this.isRaw()) {
|
|
231
|
+
const success = (message: string) => {
|
|
232
|
+
!this.isEnvTest() &&
|
|
233
|
+
contextLogger()?.info({
|
|
234
|
+
state: "SUCCESS",
|
|
235
|
+
title,
|
|
236
|
+
message
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
const start = (message: string) => {
|
|
240
|
+
!this.isEnvTest() &&
|
|
241
|
+
contextLogger()?.info({
|
|
242
|
+
title,
|
|
243
|
+
message
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
const defaultLogger = {
|
|
247
|
+
message: (message: string) => {
|
|
248
|
+
!this.isEnvTest() &&
|
|
249
|
+
contextLogger()?.info({
|
|
250
|
+
state: "MSG",
|
|
251
|
+
title,
|
|
252
|
+
message
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
stop: success,
|
|
256
|
+
success,
|
|
257
|
+
info: start,
|
|
258
|
+
start,
|
|
259
|
+
warn: (message: string) => {
|
|
260
|
+
!this.isEnvTest() &&
|
|
261
|
+
contextLogger()?.warn({
|
|
262
|
+
title,
|
|
263
|
+
message
|
|
264
|
+
});
|
|
265
|
+
},
|
|
266
|
+
error: (message: string) => {
|
|
267
|
+
!this.isEnvTest() &&
|
|
268
|
+
contextLogger()?.error({
|
|
269
|
+
title,
|
|
270
|
+
message
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
defaultLogger.message("...");
|
|
276
|
+
return defaultLogger;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
switch (type) {
|
|
280
|
+
case "spinner":
|
|
281
|
+
const spin = spinner();
|
|
282
|
+
spin.message(title);
|
|
283
|
+
|
|
284
|
+
return spin;
|
|
285
|
+
case "progress":
|
|
286
|
+
if (parent && this.isChildProgress()) {
|
|
287
|
+
return parent.#logger;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return progress({
|
|
291
|
+
style: "block",
|
|
292
|
+
max: 100
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
case "taskLog":
|
|
296
|
+
return taskLog({
|
|
297
|
+
title: this.title
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
case "log":
|
|
301
|
+
return log;
|
|
302
|
+
|
|
303
|
+
case "group":
|
|
304
|
+
if (!parent || parent.type !== "taskLog") {
|
|
305
|
+
return log;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return parent.#logger.group(this.title);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private isRaw() {
|
|
313
|
+
return this.#verbose || this.isEnvTest();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private isEnvTest() {
|
|
317
|
+
return process.env.NODE_ENV === "test";
|
|
318
|
+
}
|
|
319
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type {Observable} from "rxjs";
|
|
2
|
+
|
|
3
|
+
import {TaskLogger, type TaskLoggerOptions} from "../domain/TaskLogger.js";
|
|
4
|
+
|
|
5
|
+
export type MaybePromise<T> = Promise<T> | T;
|
|
6
|
+
|
|
7
|
+
type TaskPredicate = MaybePromise<boolean | string | undefined>;
|
|
8
|
+
|
|
9
|
+
export interface Task<Ctx = any> {
|
|
10
|
+
title: string;
|
|
11
|
+
task: (ctx: Ctx, operation: TaskLogger) => MaybePromise<Task[] | unknown> | Observable<unknown>;
|
|
12
|
+
skip?: boolean | string | ((ctx: Ctx) => TaskPredicate);
|
|
13
|
+
enabled?: boolean | ((ctx: Ctx) => MaybePromise<boolean>);
|
|
14
|
+
type?: TaskLoggerOptions["type"];
|
|
15
|
+
}
|