Skip to content

Commit 9fc14c5

Browse files
committed
Invoke tsc programmatically
1 parent fa0e27f commit 9fc14c5

File tree

4 files changed

+128
-42
lines changed

4 files changed

+128
-42
lines changed

lib/incremental-typescript-compiler.js

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ const path = require('path');
1111
const fs = require('fs');
1212
const resolve = require('resolve');
1313
const compile = require('./utilities/compile');
14+
const ts = require('typescript');
1415

1516
const debugCompiler = require('debug')('ember-cli-typescript:compiler');
1617
const debugAutoresolve = require('debug')('ember-cli-typescript:autoresolve');
1718

19+
const formatHost = {
20+
getCanonicalFileName: path => path,
21+
getCurrentDirectory: ts.sys.getCurrentDirectory,
22+
getNewLine: () => ts.sys.newLine,
23+
};
24+
1825
module.exports = class IncrementalTypescriptCompiler {
1926
constructor(app, project) {
2027
if (project._incrementalTsCompiler) {
@@ -106,43 +113,72 @@ module.exports = class IncrementalTypescriptCompiler {
106113

107114
let project = this.project;
108115
let outDir = this.outDir();
109-
let flags = ['--watch'];
110-
let tsc = compile({ project, outDir, flags });
111-
112-
tsc.stdout.on('data', data => {
113-
let text = data
114-
.toString()
115-
.trim()
116-
.replace(/\u001bc/g, '');
117-
118-
if (text) {
119-
this.project.ui.writeLine(text);
120-
}
116+
let tsc = compile(project, { outDir, watch: true }, {
117+
reportWatchStatus: (diagnostic) => {
118+
let text = diagnostic.messageText;
119+
120+
if (text.indexOf('Starting incremental compilation') !== -1) {
121+
debugCompiler('tsc detected a file change');
122+
this.willRebuild();
123+
clearTimeout(this._pendingAutoresolve);
124+
}
121125

122-
if (data.indexOf('Starting incremental compilation') !== -1) {
123-
debugCompiler('tsc detected a file change');
124-
this.willRebuild();
125-
clearTimeout(this._pendingAutoresolve);
126-
}
126+
if (text.indexOf('Compilation complete') !== -1) {
127+
debugCompiler('rebuild completed');
127128

128-
if (data.indexOf('Compilation complete') !== -1) {
129-
debugCompiler('rebuild completed');
129+
this.didSync();
130130

131-
this.didSync();
131+
if (this._didAutoresolve) {
132+
this._touchRebuildTrigger();
133+
this.maxBuildCount++;
134+
}
132135

133-
if (this._didAutoresolve) {
134-
this._touchRebuildTrigger();
135-
this.maxBuildCount++;
136+
clearTimeout(this._pendingAutoresolve);
137+
this._didAutoresolve = false;
136138
}
139+
},
137140

138-
clearTimeout(this._pendingAutoresolve);
139-
this._didAutoresolve = false;
141+
reportDiagnostic: (diagnostic) => {
142+
// if (diagnostic.category !== 2) {
143+
// this.project.ui.write(ts.formatDiagnostic(diagnostic, formatHost));
144+
// }
140145
}
141146
});
142147

143-
tsc.stderr.on('data', data => {
144-
this.project.ui.writeError(data.toString().trim());
145-
});
148+
// tsc.stdout.on('data', data => {
149+
// let text = data
150+
// .toString()
151+
// .trim()
152+
// .replace(/\u001bc/g, '');
153+
154+
// if (text) {
155+
// this.project.ui.writeLine(text);
156+
// }
157+
158+
// if (data.indexOf('Starting incremental compilation') !== -1) {
159+
// debugCompiler('tsc detected a file change');
160+
// this.willRebuild();
161+
// clearTimeout(this._pendingAutoresolve);
162+
// }
163+
164+
// if (data.indexOf('Compilation complete') !== -1) {
165+
// debugCompiler('rebuild completed');
166+
167+
// this.didSync();
168+
169+
// if (this._didAutoresolve) {
170+
// this._touchRebuildTrigger();
171+
// this.maxBuildCount++;
172+
// }
173+
174+
// clearTimeout(this._pendingAutoresolve);
175+
// this._didAutoresolve = false;
176+
// }
177+
// });
178+
179+
// tsc.stderr.on('data', data => {
180+
// this.project.ui.writeError(data.toString().trim());
181+
// });
146182
}
147183

148184
willRebuild() {

lib/utilities/compile.js

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,56 @@
11
/* eslint-env node */
22
'use strict';
33

4-
const execa = require('execa');
54
const mkdirp = require('mkdirp');
5+
const ts = require('typescript');
6+
const sane = require('sane');
7+
const fs = require('fs-extra');
68

7-
module.exports = function compile(options) {
9+
module.exports = function compile(project, tsOptions, callbacks) {
810
// Ensure the output directory is created even if no files are generated
9-
mkdirp.sync(options.outDir);
10-
11-
// argument sequence here is meaningful; don't apply prettier.
12-
// prettier-ignore
13-
let args = [
14-
'--outDir', options.outDir,
15-
'--rootDir', options.project.root,
16-
'--allowJs', 'false',
17-
'--noEmit', 'false'
18-
];
19-
20-
return execa('tsc', args.concat(options.flags));
11+
mkdirp.sync(tsOptions.outDir);
12+
13+
let fullOptions = Object.assign({
14+
rootDir: project.root,
15+
allowJs: false,
16+
noEmit: false
17+
}, tsOptions);
18+
19+
let watchedFiles = new Map();
20+
let sys = Object.assign({}, ts.sys, {
21+
watchFile(file, callback) {
22+
watchedFiles.set(file, callback);
23+
24+
return {
25+
close() {
26+
watchedFiles.delete(file);
27+
}
28+
};
29+
},
30+
31+
watchDirectory(dir, callback) {
32+
if (!fs.existsSync(dir)) return;
33+
34+
let watcher = new sane.WatchmanWatcher(dir, { ignored: 'tmp/**' });
35+
36+
let invoke = (type, path) => {
37+
let fullPath = `${dir}/${path}`;
38+
if (type === 'add') {
39+
callback(path);
40+
} else if (watchedFiles.has(fullPath)) {
41+
watchedFiles.get(fullPath)(fullPath, type === 'change' ? 1 : 2);
42+
}
43+
};
44+
45+
watcher.on('all', invoke);
46+
47+
return watcher;
48+
}
49+
});
50+
51+
let configPath = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json');
52+
let createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram;
53+
let host = ts.createWatchCompilerHost(configPath, fullOptions, sys, createProgram, callbacks.reportDiagnostic, callbacks.reportWatchStatus);
54+
55+
return ts.createWatchProgram(host);
2156
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"resolve": "^1.5.0",
5656
"rimraf": "^2.6.2",
5757
"rsvp": "^4.8.1",
58+
"sane": "^2.4.1",
5859
"silent-error": "^1.1.0",
5960
"symlink-or-copy": "^1.1.8",
6061
"walk-sync": "^0.3.2"

yarn.lock

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6122,6 +6122,20 @@ sane@^2.2.0:
61226122
optionalDependencies:
61236123
fsevents "^1.1.1"
61246124

6125+
sane@^2.4.1:
6126+
version "2.4.1"
6127+
resolved "https://registry.yarnpkg.com/sane/-/sane-2.4.1.tgz#29f991208cf28636720efdc584293e7fd66663a5"
6128+
dependencies:
6129+
anymatch "^1.3.0"
6130+
exec-sh "^0.2.0"
6131+
fb-watchman "^2.0.0"
6132+
minimatch "^3.0.2"
6133+
minimist "^1.1.1"
6134+
walker "~1.0.5"
6135+
watch "~0.18.0"
6136+
optionalDependencies:
6137+
fsevents "^1.1.1"
6138+
61256139
semver@^4.3.1:
61266140
version "4.3.6"
61276141
resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"

0 commit comments

Comments
 (0)