forked from gilamran/tsc-watch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtsc-watch.js
149 lines (126 loc) · 4.55 KB
/
tsc-watch.js
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
#!/usr/bin/env node
'use strict';
const chalk = require('chalk');
const spawn = require('cross-spawn');
const killer = require('./killer');
const compilationStartedRegex = /Starting incremental compilation/;
const compilationCompleteRegex = / Compilation complete\. Watching for file changes\./;
const typescriptSuccessRegex = /Compilation complete/;
const typescriptWatchCommandRegex = /Watch input files\./;
const typescriptErrorRegex = /\(\d+,\d+\): error TS\d+:/;
const onSuccessCommandSyntax = ' --onSuccess COMMAND Run the COMMAND on each successful compilation';
const onFirstSuccessCommandSyntax = ' --onFirstSuccess COMMAND Run the COMMAND on the first successful compilation (Will not run the onSuccess)';
const newAdditionToSyntax = ['Watch input files. [always on]', onSuccessCommandSyntax, onFirstSuccessCommandSyntax].join('\n');
let hadErrors = false;
let firstTime = true;
let firstSuccessProcess = null;
let firstSuccessProcessExited = null;
let successProcess = null;
let successProcessExited = null;
function color(line) {
if (typescriptErrorRegex.test(line)) {
return chalk.red(line);
}
if (typescriptSuccessRegex.test(line) || typescriptWatchCommandRegex.test(line)) {
return chalk.green(line);
}
return chalk.white(line);
}
function print(lines) {
return lines.forEach(line => console.log(color(line)));
}
function cleanArgs(inputArgs) {
return inputArgs
.splice(2)
.filter(arg => arg.toLowerCase() !== '-w')
.filter(arg => arg.toLowerCase() !== '--watch')
.filter(arg => arg.toLowerCase() !== '--onsuccess')
.filter(arg => arg.toLowerCase() !== '--onfirstsuccess');
}
function getCommandIdx(inputArgs, command) {
const idx = inputArgs.indexOf(command);
if (idx > -1 && idx + 1 < inputArgs.length) {
return idx;
} else {
return -1;
}
}
function runCommand(fullCommand) {
if (fullCommand) {
const parts = fullCommand.split(' ').filter(a => a.length > 0);
return spawn(parts[0], parts.slice(1), {stdio: 'inherit'})
}
}
function killAllProcesses() {
const promises = [];
if (firstSuccessProcess) {
promises.push(killer(firstSuccessProcess).then(() => firstSuccessProcess = null));
promises.push(firstSuccessProcessExited.then(() => firstSuccessProcessExited = null));
}
if (successProcess) {
promises.push(killer(successProcess).then(() => successProcess = null));
promises.push(successProcessExited.then(() => successProcessExited = null));
}
return Promise.all(promises);
}
let allArgs = process.argv;
// onSuccess
let onSuccessCommandIdx = getCommandIdx(allArgs, '--onSuccess');
let onSuccessCommand = null;
if (onSuccessCommandIdx > -1) {
onSuccessCommand = allArgs[onSuccessCommandIdx + 1];
allArgs.splice(onSuccessCommandIdx, 2)
}
// onFirstSuccess
let onFirstSuccessCommandIdx = getCommandIdx(allArgs, '--onFirstSuccess');
let onFirstSuccessCommand = null;
if (onFirstSuccessCommandIdx > -1) {
onFirstSuccessCommand = allArgs[onFirstSuccessCommandIdx + 1];
allArgs.splice(onFirstSuccessCommandIdx, 2)
}
let args = cleanArgs(allArgs);
args.push('--watch'); // force watch
const bin = require.resolve('typescript/bin/tsc');
const tscProcess = spawn(bin, [...args]);
tscProcess.stdout.on('data', buffer => {
const lines = buffer.toString()
.split('\n')
.filter(a => a.length > 0)
// .filter(a => a !== '\r')
.map(a => a.replace(typescriptWatchCommandRegex, newAdditionToSyntax));
print(lines);
const newCompilation = lines.some(line => compilationStartedRegex.test(line));
if (newCompilation) {
hadErrors = false;
}
const error = lines.some(line => typescriptErrorRegex.test(line));
if (error) {
hadErrors = true;
}
const compilationComplete = lines.some(line => compilationCompleteRegex.test(line));
if (compilationComplete) {
if (hadErrors) {
console.log('Had errors, not spawning');
} else {
killAllProcesses().then(() => {
if (firstTime && onFirstSuccessCommand) {
firstTime = false;
firstSuccessProcess = runCommand(onFirstSuccessCommand);
firstSuccessProcessExited = new Promise(resolve => {
firstSuccessProcess.on('exit', code => {
resolve(code);
});
});
} else if (onSuccessCommand) {
successProcess = runCommand(onSuccessCommand);
successProcessExited = new Promise(resolve => {
successProcess.on('exit', code => {
resolve(code);
});
});
}
});
}
}
});
tscProcess.on('exit', killAllProcesses);