| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | import * as path from 'path'; | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  | import AngularCompilerOptions from './options'; | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  | import {TsickleHost} from './compiler_host'; | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Our interface to the TypeScript standard compiler. | 
					
						
							|  |  |  |  * If you write an Angular compiler plugin for another build tool, | 
					
						
							|  |  |  |  * you should implement a similar interface. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export interface CompilerInterface { | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |   readConfiguration(project: string, basePath: string): | 
					
						
							|  |  |  |       {parsed: ts.ParsedCommandLine, ngOptions: AngularCompilerOptions}; | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |   typeCheck(compilerHost: ts.CompilerHost, program: ts.Program): void; | 
					
						
							|  |  |  |   emit(compilerHost: ts.CompilerHost, program: ts.Program): number; | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const DEBUG = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function debug(msg: string, ...o: any[]) { | 
					
						
							|  |  |  |   if (DEBUG) console.log(msg, ...o); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function formatDiagnostics(diags: ts.Diagnostic[]): string { | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |   return diags | 
					
						
							|  |  |  |       .map((d) => { | 
					
						
							|  |  |  |         let res = ts.DiagnosticCategory[d.category]; | 
					
						
							|  |  |  |         if (d.file) { | 
					
						
							|  |  |  |           res += ' at ' + d.file.fileName + ':'; | 
					
						
							|  |  |  |           const {line, character} = d.file.getLineAndCharacterOfPosition(d.start); | 
					
						
							|  |  |  |           res += (line + 1) + ':' + (character + 1) + ':'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         res += ' ' + ts.flattenDiagnosticMessageText(d.messageText, '\n'); | 
					
						
							|  |  |  |         return res; | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |       .join('\n'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function check(diags: ts.Diagnostic[]) { | 
					
						
							|  |  |  |   if (diags && diags.length && diags[0]) { | 
					
						
							|  |  |  |     throw new Error(formatDiagnostics(diags)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class Tsc implements CompilerInterface { | 
					
						
							|  |  |  |   public ngOptions: AngularCompilerOptions; | 
					
						
							|  |  |  |   public parsed: ts.ParsedCommandLine; | 
					
						
							|  |  |  |   private basePath: string; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |   constructor(private readFile = ts.sys.readFile, private readDirectory = ts.sys.readDirectory) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |   readConfiguration(project: string, basePath: string) { | 
					
						
							|  |  |  |     this.basePath = basePath; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Allow a directory containing tsconfig.json as the project value
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |     try { | 
					
						
							|  |  |  |       this.readDirectory(project); | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |       project = path.join(project, 'tsconfig.json'); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       // Was not a directory, continue on assuming it's a file
 | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |     const {config, error} = ts.readConfigFile(project, this.readFile); | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |     check([error]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this.parsed = | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |         ts.parseJsonConfigFileContent(config, {readDirectory: this.readDirectory}, basePath); | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     check(this.parsed.errors); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Default codegen goes to the current directory
 | 
					
						
							|  |  |  |     // Parsed options are already converted to absolute paths
 | 
					
						
							|  |  |  |     this.ngOptions = config.angularCompilerOptions || {}; | 
					
						
							|  |  |  |     this.ngOptions.genDir = path.join(basePath, this.ngOptions.genDir || '.'); | 
					
						
							| 
									
										
										
										
											2016-05-24 10:53:48 -07:00
										 |  |  |     for (const key of Object.keys(this.parsed.options)) { | 
					
						
							|  |  |  |       this.ngOptions[key] = this.parsed.options[key]; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |     return {parsed: this.parsed, ngOptions: this.ngOptions}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-07 15:42:27 -07:00
										 |  |  |   typeCheck(compilerHost: ts.CompilerHost, program: ts.Program): void { | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |     debug('Checking global diagnostics...'); | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |     check(program.getGlobalDiagnostics()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |     let diagnostics: ts.Diagnostic[] = []; | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |     debug('Type checking...'); | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (let sf of program.getSourceFiles()) { | 
					
						
							|  |  |  |       diagnostics.push(...ts.getPreEmitDiagnostics(program, sf)); | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |     check(diagnostics); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |   emit(compilerHost: TsickleHost, oldProgram: ts.Program): number { | 
					
						
							|  |  |  |     // Create a new program since the host may be different from the old program.
 | 
					
						
							|  |  |  |     const program = ts.createProgram(this.parsed.fileNames, this.parsed.options, compilerHost); | 
					
						
							| 
									
										
										
										
											2016-05-26 10:45:37 -07:00
										 |  |  |     debug('Emitting outputs...'); | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |     const emitResult = program.emit(); | 
					
						
							|  |  |  |     let diagnostics: ts.Diagnostic[] = []; | 
					
						
							|  |  |  |     diagnostics.push(...emitResult.diagnostics); | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     check(compilerHost.diagnostics); | 
					
						
							| 
									
										
										
										
											2016-05-01 11:22:39 -07:00
										 |  |  |     return emitResult.emitSkipped ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2016-04-28 21:57:16 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | export var tsc: CompilerInterface = new Tsc(); |