typescript-assistant
Version:
Combines and integrates professional Typescript tools into your project
118 lines (107 loc) • 3.8 kB
text/typescript
import { Bus } from './bus';
import { Logger } from './logger';
import { Task, TaskRunner } from './taskrunner';
import { absolutePath } from './util';
import * as glob from 'glob';
import { parallelLimit } from 'async';
import * as fs from 'fs';
export interface Compiler {
start(): void;
stop(): void;
runOnce(tscArgs: string[]): Promise<boolean>;
}
type TaskFunctionCallback = () => void;
type TaskFunction = (callback: TaskFunctionCallback) => void;
let runningTasks: Task[] = [];
export let createCompiler = (dependencies: { taskRunner: TaskRunner, logger: Logger, bus: Bus }): Compiler => {
let { taskRunner, logger, bus } = dependencies;
let busyCompilers = 0;
let errors: string[] = [];
let handleOutput = (line: string) => {
if (/Starting incremental compilation...$/.test(line)) {
if (busyCompilers === 0) {
bus.report({ tool: 'compiler', status: 'busy' });
errors = [];
}
busyCompilers++;
logger.log('compiler', 'compiling...');
bus.signal('compile-started');
} else if (/Watching for file changes.$/.test(line)) {
busyCompilers--;
logger.log('compiler', `ready, found ${errors.length} errors`);
bus.signal(errors.length === 0 ? 'compile-compiled' : 'compile-errored');
if (busyCompilers === 0) {
bus.report({ tool: 'compiler', status: 'ready', errors: errors.length });
}
} else {
let matches = /([^(]+)\((\d+),(\d+)\): (error TS\d+: )?(.*)$/.exec(line);
if (matches) {
errors.push(matches[0]);
logger.log('compiler', `${absolutePath(matches[1])}:${matches[2]}:${matches[3]} ${matches[5]}`);
} else {
matches = /error TS\d+: (.+)$/.exec(line);
if (matches) {
errors.push(matches[1]);
logger.log('compiler', `${matches[1]}`);
} else {
// just echo the output
logger.log('compiler', line);
}
}
}
return true;
};
let taskFunctions: TaskFunction[] = [];
return {
runOnce: () => {
return new Promise((resolve, reject) => {
glob('**/tsconfig.json', { ignore: '**/node_modules/**' }, (error: Error | null, tsConfigFiles: string[]) => {
if (error) {
reject(error);
}
tsConfigFiles.forEach(file => {
let args = ['-p', file];
let taskFunction = (callback: TaskFunctionCallback) => {
let task = taskRunner.runTask(`./node_modules/.bin/tsc`, args, {
name: `tsc -p ${file}`,
logger,
handleOutput
});
runningTasks.push(task);
task.result.then(() => {
runningTasks.splice(runningTasks.indexOf(task), 1);
}).then(callback).catch(reject);
};
taskFunctions.push(taskFunction);
});
let limit = 2;
parallelLimit(taskFunctions, limit, resolve);
});
});
},
start: () => {
const tsConfigFiles = ['./tsconfig.json', './src/tsconfig.json']; // Watching all **/tsconfig.json files has proven to cost too much CPU
tsConfigFiles.forEach(tsconfigFile => {
if (fs.existsSync(tsconfigFile)) {
let task = taskRunner.runTask('./node_modules/.bin/tsc', ['-p', tsconfigFile, '--watch', '--noEmit'], {
name: `tsc -p ${tsconfigFile} --watch`,
logger,
handleOutput
});
runningTasks.push(task);
busyCompilers++;
task.result.catch(err => {
logger.error('compiler', err.message);
process.exit(1);
});
}
});
},
stop: () => {
runningTasks.forEach(task => {
task.kill();
});
runningTasks = [];
}
};
};