-
Notifications
You must be signed in to change notification settings - Fork 16
/
gulpfile.ts
153 lines (120 loc) · 4.15 KB
/
gulpfile.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* eslint-disable no-control-regex */
import chalk from "chalk";
import { exec } from "child_process";
import del from "del";
import { series, src, task, watch } from "gulp";
import mocha from "gulp-mocha";
import * as path from "path";
task("test", () => src("out/tests/Main.js", { read: false })
.pipe(mocha({ reporter: "even-more-min" }))
.on("error", () => process.exitCode = 1));
task("build", series(
clean,
compile,
"test"));
task("watch", series("build", done =>
watch("./src/**/*.ts", series("build"))
&& done()));
async function compile () {
await new TypescriptWatch("src", "out").once();
}
async function clean () {
await del("out");
}
export default class TypescriptWatch {
private onDataHandler: (data: string) => any;
private onCompleteHandler: (done: () => any) => any;
private initialized: (() => void) | true | undefined;
private readonly inDir: string;
private readonly outDir: string;
private declaration: string | undefined;
public constructor (dir: string, outDir: string) {
this.inDir = path.resolve(dir);
this.outDir = path.resolve(outDir);
}
public onData (handler: (data: string) => boolean | undefined | void) {
this.onDataHandler = handler;
return this;
}
public onComplete (handler: (done: () => any) => any) {
this.onCompleteHandler = handler;
return this;
}
public setDeclaration (dir: string) {
this.declaration = path.resolve(dir);
return this;
}
public async once () {
const ocwd = process.cwd();
process.chdir(this.inDir);
const declaration = this.declaration ? `--declaration --declarationDir ${this.declaration}` : "";
const task = exec(`npx tsc --outDir ${this.outDir} --pretty ${declaration}`);
process.chdir(ocwd);
task.stderr!.on("data", data => process.stderr.write(data));
task.stdout!.on("data", (data: Buffer) => {
if (this.onDataHandler && this.onDataHandler(data.toString()) === false)
return;
process.stdout.write(handleTscOut(0, data, `${path.relative(ocwd, this.inDir).replace(/\\/g, "/")}/`));
});
return new Promise<void>((resolve, reject) => task.on("close", code => {
if (!code) resolve();
else reject(code);
}));
}
public watch () {
const ocwd = process.cwd();
process.chdir(this.inDir);
const declaration = this.declaration ? `--declaration --declarationDir ${this.declaration}` : "";
const task = exec(`npx tsc --outDir ${this.outDir} --pretty --watch ${declaration}`);
process.chdir(ocwd);
task.stderr!.on("data", data => process.stderr.write(data));
let start: number;
task.stdout!.on("data", (data: Buffer) => {
if (this.onDataHandler && this.onDataHandler(data.toString()) === false)
return;
if (/\bincremental compilation|in watch mode\b/.test(data.toString()))
start = Date.now();
process.stdout.write(handleTscOut(start, data, `${path.relative(ocwd, this.inDir).replace(/\\/g, "/")}/`));
if (/Watching for file changes./.test(data.toString()) && this.initialized) {
if (typeof this.initialized === "function") {
this.initialized();
this.initialized = true;
} else {
this.onCompleteHandler(() => { return; });
}
}
});
return this;
}
public async waitForInitial () {
return new Promise<void>(resolve => {
if (this.initialized === true) return resolve();
this.initialized = resolve;
});
}
}
function handleTscOut (startTime: number, data: string | Buffer, prefix?: string) {
data = data.toString()
.replace("\u001bc", "")
.replace(/. Watching for file changes.\r\n/, ` after ${getTimeString(startTime)}`)
.replace(/(incremental compilation...|in watch mode...)\r\n/g, "$1")
.replace(/( TS\d{4}: [^\r\n]*?\r\n)\r\n/g, "$1")
.replace(/(~+[^\r\n]*?\r\n)\r\n\r\n/g, "$1")
.replace(/(?=\[30;47m(\d+| +)\u001b\[0m)/g, "\t");
if (prefix) {
data = data.replace(/(\u001b\[96m.*?\u001b\[0m:\u001b\[93m)/g, chalk.cyan(`${prefix}$1`));
}
return data;
}
function getTimeString (start: number) {
const time = Date.now() - start;
let timeString;
if (time >= 1000) {
timeString = `${(time / 1000).toFixed(2).replace(/0+$/, "")} s`;
} else if (time >= 100) {
timeString = `${(time / 100).toFixed(0)} ms`;
} else {
timeString = `${time} μs`;
}
return chalk.magenta(timeString);
}