11import semver from 'semver' ;
2+ import { Remote } from 'stagehand' ;
3+ import { connect } from 'stagehand/lib/adapters/child-process' ;
24import { hasPlugin , addPlugin , AddPluginOptions } from 'ember-cli-babel-plugin-helpers' ;
35import Addon from 'ember-cli/lib/models/addon' ;
46import { addon } from './lib/utilities/ember-cli-entities' ;
7+ import fork from './lib/utilities/fork' ;
8+ import TypecheckWorker from './lib/typechecking/worker' ;
9+ import TypecheckMiddleware from './lib/typechecking/middleware' ;
510
611export default addon ( {
712 name : 'ember-cli-typescript' ,
@@ -10,6 +15,12 @@ export default addon({
1015 this . _super . included . apply ( this , arguments ) ;
1116 this . _checkDevelopment ( ) ;
1217 this . _checkBabelVersion ( ) ;
18+
19+ // If we're a direct dependency of the host app, go ahead and start up the
20+ // typecheck worker so we don't wait until the end of the build to check
21+ if ( this . parent === this . project ) {
22+ this . _getTypecheckWorker ( ) ;
23+ }
1324 } ,
1425
1526 includedCommands ( ) {
@@ -25,7 +36,30 @@ export default addon({
2536 return `${ __dirname } /blueprints` ;
2637 } ,
2738
28- setupPreprocessorRegistry ( type : string ) {
39+ serverMiddleware ( { app } ) {
40+ let workerPromise = this . _getTypecheckWorker ( ) ;
41+ let middleware = new TypecheckMiddleware ( this . project , workerPromise ) ;
42+ middleware . register ( app ) ;
43+ } ,
44+
45+ async postBuild ( ) {
46+ // This code makes the fundamental assumption that the TS compiler's fs watcher
47+ // will notice a file change before the full Broccoli build completes. Otherwise
48+ // the `getStatus` call here might report the status of the previous check. In
49+ // practice, though, building takes much longer than the time to trigger the
50+ // compiler's "hey, a file changed" hook, and once the typecheck has begun, the
51+ // `getStatus` call will block until it's complete.
52+ let worker = await this . _getTypecheckWorker ( ) ;
53+ let { failed } = await worker . getStatus ( ) ;
54+
55+ if ( failed ) {
56+ // The actual details of the errors will already have been printed
57+ // with nice highlighting and formatting separately.
58+ throw new Error ( 'Typechecking failed' ) ;
59+ }
60+ } ,
61+
62+ setupPreprocessorRegistry ( type ) {
2963 if ( type !== 'parent' ) return ;
3064
3165 // Normally this is the sort of logic that would live in `included()`, but
@@ -52,10 +86,11 @@ export default addon({
5286
5387 _checkBabelVersion ( ) {
5488 let babel = this . parent . addons . find ( addon => addon . name === 'ember-cli-babel' ) ;
55- if ( ! babel || ! semver . satisfies ( babel . pkg . version , '>=7.0.0-alpha.0 <8' ) ) {
56- let version = babel ? `version ${ babel . pkg . version } ` : `no instance of ember-cli-babel` ;
89+ let version = babel && babel . pkg . version ;
90+ if ( ! babel || ! ( semver . gte ( version ! , '7.1.0' ) && semver . lt ( version ! , '8.0.0' ) ) ) {
91+ let versionString = babel ? `version ${ babel . pkg . version } ` : `no instance of ember-cli-babel` ;
5792 this . ui . writeWarnLine (
58- `ember-cli-typescript requires ember-cli-babel@7 , but you have ${ version } installed; ` +
93+ `ember-cli-typescript requires ember-cli-babel ^7.1.0 , but you have ${ versionString } installed; ` +
5994 'your TypeScript files may not be transpiled correctly.'
6095 ) ;
6196 }
@@ -95,4 +130,29 @@ export default addon({
95130 extensions . push ( 'ts' ) ;
96131 }
97132 } ,
133+
134+ _typecheckWorker : undefined as Promise < Remote < TypecheckWorker > > | undefined ,
135+
136+ _getTypecheckWorker ( ) {
137+ if ( ! this . _typecheckWorker ) {
138+ this . _typecheckWorker = this . _forkTypecheckWorker ( ) ;
139+ }
140+
141+ return this . _typecheckWorker ;
142+ } ,
143+
144+ async _forkTypecheckWorker ( ) {
145+ let childProcess = fork ( `${ __dirname } /lib/typechecking/worker/launch` ) ;
146+ let worker = await connect < TypecheckWorker > ( childProcess ) ;
147+
148+ await worker . onTypecheck ( status => {
149+ for ( let error of status . errors ) {
150+ this . ui . writeLine ( error ) ;
151+ }
152+ } ) ;
153+
154+ await worker . start ( this . project . root ) ;
155+
156+ return worker ;
157+ } ,
98158} ) ;
0 commit comments