Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/lib/task.ts
4770 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import fancyLog from 'fancy-log';
7
import ansiColors from 'ansi-colors';
8
9
export interface BaseTask {
10
displayName?: string;
11
taskName?: string;
12
_tasks?: Task[];
13
}
14
export interface PromiseTask extends BaseTask {
15
(): Promise<void>;
16
}
17
export interface StreamTask extends BaseTask {
18
(): NodeJS.ReadWriteStream;
19
}
20
export interface CallbackTask extends BaseTask {
21
(cb?: (err?: Error) => void): void;
22
}
23
24
export type Task = PromiseTask | StreamTask | CallbackTask;
25
26
function _isPromise(p: Promise<void> | NodeJS.ReadWriteStream): p is Promise<void> {
27
return typeof (p as Promise<void>).then === 'function';
28
}
29
30
function _renderTime(time: number): string {
31
return `${Math.round(time)} ms`;
32
}
33
34
async function _execute(task: Task): Promise<void> {
35
const name = task.taskName || task.displayName || `<anonymous>`;
36
if (!task._tasks) {
37
fancyLog('Starting', ansiColors.cyan(name), '...');
38
}
39
const startTime = process.hrtime();
40
await _doExecute(task);
41
const elapsedArr = process.hrtime(startTime);
42
const elapsedNanoseconds = (elapsedArr[0] * 1e9 + elapsedArr[1]);
43
if (!task._tasks) {
44
fancyLog(`Finished`, ansiColors.cyan(name), 'after', ansiColors.magenta(_renderTime(elapsedNanoseconds / 1e6)));
45
}
46
}
47
48
async function _doExecute(task: Task): Promise<void> {
49
// Always invoke as if it were a callback task
50
return new Promise((resolve, reject) => {
51
if (task.length === 1) {
52
// this is a callback task
53
task((err) => {
54
if (err) {
55
return reject(err);
56
}
57
resolve();
58
});
59
return;
60
}
61
62
const taskResult = task();
63
64
if (typeof taskResult === 'undefined') {
65
// this is a sync task
66
resolve();
67
return;
68
}
69
70
if (_isPromise(taskResult)) {
71
// this is a promise returning task
72
taskResult.then(resolve, reject);
73
return;
74
}
75
76
// this is a stream returning task
77
taskResult.on('end', _ => resolve());
78
taskResult.on('error', err => reject(err));
79
});
80
}
81
82
export function series(...tasks: Task[]): PromiseTask {
83
const result = async () => {
84
for (let i = 0; i < tasks.length; i++) {
85
await _execute(tasks[i]);
86
}
87
};
88
result._tasks = tasks;
89
return result;
90
}
91
92
export function parallel(...tasks: Task[]): PromiseTask {
93
const result = async () => {
94
await Promise.all(tasks.map(t => _execute(t)));
95
};
96
result._tasks = tasks;
97
return result;
98
}
99
100
export function define(name: string, task: Task): Task {
101
if (task._tasks) {
102
// This is a composite task
103
const lastTask = task._tasks[task._tasks.length - 1];
104
105
if (lastTask._tasks || lastTask.taskName) {
106
// This is a composite task without a real task function
107
// => generate a fake task function
108
return define(name, series(task, () => Promise.resolve()));
109
}
110
111
lastTask.taskName = name;
112
task.displayName = name;
113
return task;
114
}
115
116
// This is a simple task
117
task.taskName = name;
118
task.displayName = name;
119
return task;
120
}
121
122