| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google Inc. All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  | import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedModules, ParseSourceSpan, Serializer, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isSyntaxError} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  | import * as fs from 'fs'; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  | import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics'; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | import {ModuleMetadata, createBundleIndexHost} from '../metadata/index'; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, EmitFlags, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api'; | 
					
						
							|  |  |  | import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host'; | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  | import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions'; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | import {getAngularEmitterTransformFactory} from './node_emitter_transform'; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | import {GENERATED_FILES, StructureIsReused, tsStructureIsReused} from './util'; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const emptyModules: NgAnalyzedModules = { | 
					
						
							|  |  |  |   ngModules: [], | 
					
						
							|  |  |  |   ngModuleByPipeOrDirective: new Map(), | 
					
						
							|  |  |  |   files: [] | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 15:35:19 -07:00
										 |  |  | const defaultEmitCallback: TsEmitCallback = | 
					
						
							|  |  |  |     ({program, targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, | 
					
						
							|  |  |  |       customTransformers}) => | 
					
						
							|  |  |  |         program.emit( | 
					
						
							|  |  |  |             targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | class AngularCompilerProgram implements Program { | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  |   private metadataCache: LowerMetadataCache; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   private oldProgramLibrarySummaries: LibrarySummary[] = []; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   // Note: This will be cleared out as soon as we create the _tsProgram
 | 
					
						
							|  |  |  |   private oldTsProgram: ts.Program|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   private emittedLibrarySummaries: LibrarySummary[]|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   // Lazily initialized fields
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private _typeCheckHost: TypeCheckHost; | 
					
						
							|  |  |  |   private _compiler: AotCompiler; | 
					
						
							|  |  |  |   private _tsProgram: ts.Program; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   private _analyzedModules: NgAnalyzedModules|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private _structuralDiagnostics: Diagnostic[]|undefined; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   private _programWithStubs: ts.Program|undefined; | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |   private _semanticDiagnostics: {ts: ts.Diagnostic[], ng: Diagnostic[]}|undefined; | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |   private _optionsDiagnostics: Diagnostic[] = []; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   constructor( | 
					
						
							|  |  |  |       private rootNames: string[], private options: CompilerOptions, private host: CompilerHost, | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       private oldProgram?: Program) { | 
					
						
							|  |  |  |     const [major, minor] = ts.version.split('.'); | 
					
						
							|  |  |  |     if (Number(major) < 2 || (Number(major) === 2 && Number(minor) < 4)) { | 
					
						
							|  |  |  |       throw new Error('The Angular Compiler requires TypeScript >= 2.4.'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     this.oldTsProgram = oldProgram ? oldProgram.getTsProgram() : undefined; | 
					
						
							|  |  |  |     if (oldProgram) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       this.oldProgramLibrarySummaries = oldProgram.getLibrarySummaries(); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |     if (options.flatModuleOutFile) { | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |       const {host: bundleHost, indexName, errors} = createBundleIndexHost(options, rootNames, host); | 
					
						
							|  |  |  |       if (errors) { | 
					
						
							|  |  |  |         // TODO(tbosch): once we move MetadataBundler from tsc_wrapped into compiler_cli,
 | 
					
						
							|  |  |  |         // directly create ng.Diagnostic instead of using ts.Diagnostic here.
 | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         this._optionsDiagnostics.push(...errors.map(e => ({ | 
					
						
							|  |  |  |                                                       category: e.category, | 
					
						
							|  |  |  |                                                       messageText: e.messageText as string, | 
					
						
							|  |  |  |                                                       source: SOURCE, | 
					
						
							|  |  |  |                                                       code: DEFAULT_ERROR_CODE | 
					
						
							|  |  |  |                                                     }))); | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         rootNames.push(indexName !); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         this.host = bundleHost; | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  |     this.metadataCache = new LowerMetadataCache({quotedNames: true}, !!options.strictMetadataEmit); | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   getLibrarySummaries(): LibrarySummary[] { | 
					
						
							|  |  |  |     const result = [...this.oldProgramLibrarySummaries]; | 
					
						
							|  |  |  |     if (this.emittedLibrarySummaries) { | 
					
						
							|  |  |  |       result.push(...this.emittedLibrarySummaries); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   getTsProgram(): ts.Program { return this.tsProgram; } | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken) { | 
					
						
							|  |  |  |     return this.tsProgram.getOptionsDiagnostics(cancellationToken); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[] { | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |     return [...this._optionsDiagnostics, ...getNgOptionDiagnostics(this.options)]; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getTsSyntacticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): | 
					
						
							|  |  |  |       ts.Diagnostic[] { | 
					
						
							|  |  |  |     return this.tsProgram.getSyntacticDiagnostics(sourceFile, cancellationToken); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[] { | 
					
						
							|  |  |  |     return this.structuralDiagnostics; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): | 
					
						
							|  |  |  |       ts.Diagnostic[] { | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |     return this.semanticDiagnostics.ts; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getNgSemanticDiagnostics(fileName?: string, cancellationToken?: ts.CancellationToken): | 
					
						
							|  |  |  |       Diagnostic[] { | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |     return this.semanticDiagnostics.ng; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   loadNgStructureAsync(): Promise<void> { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (this._analyzedModules) { | 
					
						
							|  |  |  |       throw new Error('Angular structure already loaded'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const {tmpProgram, sourceFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs(); | 
					
						
							|  |  |  |     return this._compiler.loadFilesAsync(sourceFiles) | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |         .catch(this.catchAnalysisError.bind(this)) | 
					
						
							|  |  |  |         .then(analyzedModules => { | 
					
						
							|  |  |  |           if (this._analyzedModules) { | 
					
						
							|  |  |  |             throw new Error('Angular structure loaded both synchronously and asynchronsly'); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |           this._updateProgramWithTypeCheckStubs( | 
					
						
							|  |  |  |               tmpProgram, analyzedModules, hostAdapter, rootNames); | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |         }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   emit( | 
					
						
							|  |  |  |       {emitFlags = EmitFlags.Default, cancellationToken, customTransformers, | 
					
						
							|  |  |  |        emitCallback = defaultEmitCallback}: { | 
					
						
							|  |  |  |         emitFlags?: EmitFlags, | 
					
						
							|  |  |  |         cancellationToken?: ts.CancellationToken, | 
					
						
							|  |  |  |         customTransformers?: CustomTransformers, | 
					
						
							|  |  |  |         emitCallback?: TsEmitCallback | 
					
						
							|  |  |  |       } = {}): ts.EmitResult { | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |     if (emitFlags & EmitFlags.I18nBundle) { | 
					
						
							|  |  |  |       const locale = this.options.i18nOutLocale || null; | 
					
						
							|  |  |  |       const file = this.options.i18nOutFile || null; | 
					
						
							|  |  |  |       const format = this.options.i18nOutFormat || null; | 
					
						
							|  |  |  |       const bundle = this.compiler.emitMessageBundle(this.analyzedModules, locale); | 
					
						
							|  |  |  |       i18nExtract(format, file, this.host, this.options, bundle); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |     if ((emitFlags & (EmitFlags.JS | EmitFlags.DTS | EmitFlags.Metadata | EmitFlags.Codegen)) === | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         0) { | 
					
						
							|  |  |  |       return {emitSkipped: true, diagnostics: [], emittedFiles: []}; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |     const {genFiles, genDiags} = this.generateFilesForEmit(emitFlags); | 
					
						
							|  |  |  |     if (genDiags.length) { | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         diagnostics: genDiags, | 
					
						
							|  |  |  |         emitSkipped: true, | 
					
						
							|  |  |  |         emittedFiles: [], | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const emittedLibrarySummaries = this.emittedLibrarySummaries = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const outSrcMapping: Array<{sourceFile: ts.SourceFile, outFileName: string}> = []; | 
					
						
							|  |  |  |     const genFileByFileName = new Map<string, GeneratedFile>(); | 
					
						
							|  |  |  |     genFiles.forEach(genFile => genFileByFileName.set(genFile.genFileUrl, genFile)); | 
					
						
							|  |  |  |     const writeTsFile: ts.WriteFileCallback = | 
					
						
							|  |  |  |         (outFileName, outData, writeByteOrderMark, onError?, sourceFiles?) => { | 
					
						
							|  |  |  |           const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null; | 
					
						
							|  |  |  |           let genFile: GeneratedFile|undefined; | 
					
						
							|  |  |  |           if (sourceFile) { | 
					
						
							|  |  |  |             outSrcMapping.push({outFileName: outFileName, sourceFile}); | 
					
						
							|  |  |  |             genFile = genFileByFileName.get(sourceFile.fileName); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           this.writeFile(outFileName, outData, writeByteOrderMark, onError, genFile, sourceFiles); | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-20 09:54:47 -07:00
										 |  |  |     // Restore the original references before we emit so TypeScript doesn't emit
 | 
					
						
							|  |  |  |     // a reference to the .d.ts file.
 | 
					
						
							|  |  |  |     const augmentedReferences = new Map<ts.SourceFile, ts.FileReference[]>(); | 
					
						
							|  |  |  |     for (const sourceFile of this.tsProgram.getSourceFiles()) { | 
					
						
							|  |  |  |       const originalReferences = getOriginalReferences(sourceFile); | 
					
						
							|  |  |  |       if (originalReferences) { | 
					
						
							|  |  |  |         augmentedReferences.set(sourceFile, sourceFile.referencedFiles); | 
					
						
							|  |  |  |         sourceFile.referencedFiles = originalReferences; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     let emitResult: ts.EmitResult; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       emitResult = emitCallback({ | 
					
						
							|  |  |  |         program: this.tsProgram, | 
					
						
							|  |  |  |         host: this.host, | 
					
						
							|  |  |  |         options: this.options, | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |         writeFile: writeTsFile, | 
					
						
							| 
									
										
										
										
											2017-09-20 09:54:47 -07:00
										 |  |  |         emitOnlyDtsFiles: (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS, | 
					
						
							|  |  |  |         customTransformers: this.calculateTransforms(genFiles, customTransformers) | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } finally { | 
					
						
							|  |  |  |       // Restore the references back to the augmented value to ensure that the
 | 
					
						
							|  |  |  |       // checks that TypeScript makes for project structure reuse will succeed.
 | 
					
						
							|  |  |  |       for (const [sourceFile, references] of Array.from(augmentedReferences)) { | 
					
						
							|  |  |  |         sourceFile.referencedFiles = references; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (!outSrcMapping.length) { | 
					
						
							|  |  |  |       // if no files were emitted by TypeScript, also don't emit .json files
 | 
					
						
							|  |  |  |       return emitResult; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     let sampleSrcFileName: string|undefined; | 
					
						
							|  |  |  |     let sampleOutFileName: string|undefined; | 
					
						
							|  |  |  |     if (outSrcMapping.length) { | 
					
						
							|  |  |  |       sampleSrcFileName = outSrcMapping[0].sourceFile.fileName; | 
					
						
							|  |  |  |       sampleOutFileName = outSrcMapping[0].outFileName; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const srcToOutPath = | 
					
						
							|  |  |  |         createSrcToOutPathMapper(this.options.outDir, sampleSrcFileName, sampleOutFileName); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |     if (emitFlags & EmitFlags.Codegen) { | 
					
						
							|  |  |  |       genFiles.forEach(gf => { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         if (gf.source) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           const outFileName = srcToOutPath(gf.genFileUrl); | 
					
						
							|  |  |  |           this.writeFile(outFileName, gf.source, false, undefined, gf); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (emitFlags & EmitFlags.Metadata) { | 
					
						
							|  |  |  |       this.tsProgram.getSourceFiles().forEach(sf => { | 
					
						
							|  |  |  |         if (!sf.isDeclarationFile && !GENERATED_FILES.test(sf.fileName)) { | 
					
						
							|  |  |  |           const metadata = this.metadataCache.getMetadata(sf); | 
					
						
							|  |  |  |           const metadataText = JSON.stringify([metadata]); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           const outFileName = srcToOutPath(sf.fileName.replace(/\.ts$/, '.metadata.json')); | 
					
						
							|  |  |  |           this.writeFile(outFileName, metadataText, false, undefined, undefined, [sf]); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     return emitResult; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Private members
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private get compiler(): AotCompiler { | 
					
						
							|  |  |  |     if (!this._compiler) { | 
					
						
							|  |  |  |       this.initSync(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._compiler !; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private get analyzedModules(): NgAnalyzedModules { | 
					
						
							|  |  |  |     if (!this._analyzedModules) { | 
					
						
							|  |  |  |       this.initSync(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._analyzedModules !; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private get structuralDiagnostics(): Diagnostic[] { | 
					
						
							|  |  |  |     if (!this._structuralDiagnostics) { | 
					
						
							|  |  |  |       this.initSync(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._structuralDiagnostics !; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private get tsProgram(): ts.Program { | 
					
						
							|  |  |  |     if (!this._tsProgram) { | 
					
						
							|  |  |  |       this.initSync(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._tsProgram !; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private get typeCheckHost(): TypeCheckHost { | 
					
						
							|  |  |  |     if (!this._typeCheckHost) { | 
					
						
							|  |  |  |       this.initSync(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this._typeCheckHost !; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |   private get semanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} { | 
					
						
							|  |  |  |     return this._semanticDiagnostics || | 
					
						
							|  |  |  |         (this._semanticDiagnostics = this.generateSemanticDiagnostics()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |   private calculateTransforms(genFiles: GeneratedFile[], customTransformers?: CustomTransformers): | 
					
						
							|  |  |  |       ts.CustomTransformers { | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |     const beforeTs: ts.TransformerFactory<ts.SourceFile>[] = []; | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  |     if (!this.options.disableExpressionLowering) { | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |       beforeTs.push(getExpressionLoweringTransformFactory(this.metadataCache)); | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |     beforeTs.push(getAngularEmitterTransformFactory(genFiles)); | 
					
						
							| 
									
										
										
										
											2017-08-16 15:35:19 -07:00
										 |  |  |     if (customTransformers && customTransformers.beforeTs) { | 
					
						
							|  |  |  |       beforeTs.push(...customTransformers.beforeTs); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const afterTs = customTransformers ? customTransformers.afterTs : undefined; | 
					
						
							|  |  |  |     return {before: beforeTs, after: afterTs}; | 
					
						
							| 
									
										
										
										
											2017-07-13 14:25:17 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private initSync() { | 
					
						
							|  |  |  |     if (this._analyzedModules) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const {tmpProgram, sourceFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs(); | 
					
						
							|  |  |  |     let analyzedModules: NgAnalyzedModules|null; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       analyzedModules = this._compiler.loadFilesSync(sourceFiles); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       analyzedModules = this.catchAnalysisError(e); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |     this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter, rootNames); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private _createProgramWithBasicStubs(): { | 
					
						
							|  |  |  |     tmpProgram: ts.Program, | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |     hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter, | 
					
						
							|  |  |  |     rootNames: string[], | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     sourceFiles: string[], | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } { | 
					
						
							|  |  |  |     if (this._analyzedModules) { | 
					
						
							|  |  |  |       throw new Error(`Internal Error: already initalized!`); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     // Note: This is important to not produce a memory leak!
 | 
					
						
							|  |  |  |     const oldTsProgram = this.oldTsProgram; | 
					
						
							|  |  |  |     this.oldTsProgram = undefined; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const codegen: CodeGenerator = { | 
					
						
							|  |  |  |       generateFile: (genFileName, baseFileName) => | 
					
						
							|  |  |  |                         this._compiler.emitBasicStub(genFileName, baseFileName), | 
					
						
							|  |  |  |       findGeneratedFileNames: (fileName) => this._compiler.findGeneratedFileNames(fileName), | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const hostAdapter = new TsCompilerAotCompilerTypeCheckHostAdapter( | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |         this.rootNames, this.options, this.host, this.metadataCache, codegen, | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |         this.oldProgramLibrarySummaries); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const aotOptions = getAotCompilerOptions(this.options); | 
					
						
							|  |  |  |     this._compiler = createAotCompiler(hostAdapter, aotOptions).compiler; | 
					
						
							|  |  |  |     this._typeCheckHost = hostAdapter; | 
					
						
							|  |  |  |     this._structuralDiagnostics = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |     let rootNames = | 
					
						
							|  |  |  |         this.rootNames.filter(fn => !GENERATED_FILES.test(fn) || !hostAdapter.isSourceFile(fn)); | 
					
						
							|  |  |  |     if (this.options.noResolve) { | 
					
						
							|  |  |  |       this.rootNames.forEach(rootName => { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |         if (hostAdapter.shouldGenerateFilesFor(rootName)) { | 
					
						
							|  |  |  |           rootNames.push(...this._compiler.findGeneratedFileNames(rootName)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const tmpProgram = ts.createProgram(rootNames, this.options, hostAdapter, oldTsProgram); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const sourceFiles: string[] = []; | 
					
						
							|  |  |  |     tmpProgram.getSourceFiles().forEach(sf => { | 
					
						
							|  |  |  |       if (hostAdapter.isSourceFile(sf.fileName)) { | 
					
						
							|  |  |  |         sourceFiles.push(sf.fileName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return {tmpProgram, sourceFiles, hostAdapter, rootNames}; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private _updateProgramWithTypeCheckStubs( | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules|null, | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |       hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter, rootNames: string[]) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     this._analyzedModules = analyzedModules || emptyModules; | 
					
						
							|  |  |  |     if (analyzedModules) { | 
					
						
							|  |  |  |       tmpProgram.getSourceFiles().forEach(sf => { | 
					
						
							|  |  |  |         if (sf.fileName.endsWith('.ngfactory.ts')) { | 
					
						
							|  |  |  |           const {generate, baseFileName} = hostAdapter.shouldGenerateFile(sf.fileName); | 
					
						
							|  |  |  |           if (generate) { | 
					
						
							|  |  |  |             // Note: ! is ok as hostAdapter.shouldGenerateFile will always return a basefileName
 | 
					
						
							|  |  |  |             // for .ngfactory.ts files.
 | 
					
						
							|  |  |  |             const genFile = this._compiler.emitTypeCheckStub(sf.fileName, baseFileName !); | 
					
						
							|  |  |  |             if (genFile) { | 
					
						
							|  |  |  |               hostAdapter.updateGeneratedFile(genFile); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-20 16:27:29 -07:00
										 |  |  |     this._tsProgram = ts.createProgram(rootNames, this.options, hostAdapter, tmpProgram); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     // Note: the new ts program should be completely reusable by TypeScript as:
 | 
					
						
							|  |  |  |     // - we cache all the files in the hostAdapter
 | 
					
						
							|  |  |  |     // - new new stubs use the exactly same imports/exports as the old once (we assert that in
 | 
					
						
							|  |  |  |     // hostAdapter.updateGeneratedFile).
 | 
					
						
							|  |  |  |     if (tsStructureIsReused(tmpProgram) !== StructureIsReused.Completely) { | 
					
						
							|  |  |  |       throw new Error(`Internal Error: The structure of the program changed during codegen.`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   private catchAnalysisError(e: any): NgAnalyzedModules|null { | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |     if (isSyntaxError(e)) { | 
					
						
							|  |  |  |       const parserErrors = getParseErrors(e); | 
					
						
							|  |  |  |       if (parserErrors && parserErrors.length) { | 
					
						
							|  |  |  |         this._structuralDiagnostics = | 
					
						
							|  |  |  |             parserErrors.map<Diagnostic>(e => ({ | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |                                            messageText: e.contextualMessage(), | 
					
						
							| 
									
										
										
										
											2017-08-09 13:45:45 -07:00
										 |  |  |                                            category: ts.DiagnosticCategory.Error, | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |                                            span: e.span, | 
					
						
							|  |  |  |                                            source: SOURCE, | 
					
						
							|  |  |  |                                            code: DEFAULT_ERROR_CODE | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |                                          })); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |         this._structuralDiagnostics = [{ | 
					
						
							|  |  |  |           messageText: e.message, | 
					
						
							|  |  |  |           category: ts.DiagnosticCategory.Error, | 
					
						
							|  |  |  |           source: SOURCE, | 
					
						
							|  |  |  |           code: DEFAULT_ERROR_CODE | 
					
						
							|  |  |  |         }]; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       return null; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     throw e; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |   // Note: this returns a ts.Diagnostic so that we
 | 
					
						
							|  |  |  |   // can return errors in a ts.EmitResult
 | 
					
						
							|  |  |  |   private generateFilesForEmit(emitFlags: EmitFlags): | 
					
						
							|  |  |  |       {genFiles: GeneratedFile[], genDiags: ts.Diagnostic[]} { | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |       if (!(emitFlags & EmitFlags.Codegen)) { | 
					
						
							|  |  |  |         return {genFiles: [], genDiags: []}; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       const genFiles = this.compiler.emitAllImpls(this.analyzedModules); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |       return {genFiles, genDiags: []}; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |       // TODO(tbosch): check whether we can actually have syntax errors here,
 | 
					
						
							|  |  |  |       // as we already parsed the metadata and templates before to create the type check block.
 | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |       if (isSyntaxError(e)) { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |         const genDiags: ts.Diagnostic[] = [{ | 
					
						
							|  |  |  |           file: undefined, | 
					
						
							|  |  |  |           start: undefined, | 
					
						
							|  |  |  |           length: undefined, | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |           messageText: e.message, | 
					
						
							|  |  |  |           category: ts.DiagnosticCategory.Error, | 
					
						
							|  |  |  |           source: SOURCE, | 
					
						
							|  |  |  |           code: DEFAULT_ERROR_CODE | 
					
						
							| 
									
										
										
										
											2017-09-19 11:41:47 -07:00
										 |  |  |         }]; | 
					
						
							|  |  |  |         return {genFiles: [], genDiags}; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |       throw e; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |   private generateSemanticDiagnostics(): {ts: ts.Diagnostic[], ng: Diagnostic[]} { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     return translateDiagnostics(this.typeCheckHost, this.tsProgram.getSemanticDiagnostics()); | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   private writeFile( | 
					
						
							|  |  |  |       outFileName: string, outData: string, writeByteOrderMark: boolean, | 
					
						
							|  |  |  |       onError?: (message: string) => void, genFile?: GeneratedFile, sourceFiles?: ts.SourceFile[]) { | 
					
						
							|  |  |  |     // collect emittedLibrarySummaries
 | 
					
						
							|  |  |  |     let baseFile: ts.SourceFile|undefined; | 
					
						
							|  |  |  |     if (genFile) { | 
					
						
							|  |  |  |       baseFile = this.tsProgram.getSourceFile(genFile.srcFileUrl); | 
					
						
							|  |  |  |       if (baseFile) { | 
					
						
							|  |  |  |         if (!this.emittedLibrarySummaries) { | 
					
						
							|  |  |  |           this.emittedLibrarySummaries = []; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (genFile.genFileUrl.endsWith('.ngsummary.json') && baseFile.fileName.endsWith('.d.ts')) { | 
					
						
							|  |  |  |           this.emittedLibrarySummaries.push({ | 
					
						
							|  |  |  |             fileName: baseFile.fileName, | 
					
						
							|  |  |  |             text: baseFile.text, | 
					
						
							|  |  |  |             sourceFile: baseFile, | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           this.emittedLibrarySummaries.push({fileName: genFile.genFileUrl, text: outData}); | 
					
						
							|  |  |  |         } else if (outFileName.endsWith('.d.ts') && baseFile.fileName.endsWith('.d.ts')) { | 
					
						
							|  |  |  |           const dtsSourceFilePath = genFile.genFileUrl.replace(/\.ts$/, '.d.ts'); | 
					
						
							|  |  |  |           // Note: Don't use sourceFiles here as the created .d.ts has a path in the outDir,
 | 
					
						
							|  |  |  |           // but we need one that is next to the .ts file
 | 
					
						
							|  |  |  |           this.emittedLibrarySummaries.push({fileName: dtsSourceFilePath, text: outData}); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Filter out generated files for which we didn't generate code.
 | 
					
						
							|  |  |  |     // This can happen as the stub caclulation is not completely exact.
 | 
					
						
							|  |  |  |     // Note: sourceFile refers to the .ngfactory.ts / .ngsummary.ts file
 | 
					
						
							|  |  |  |     const isGenerated = GENERATED_FILES.test(outFileName); | 
					
						
							|  |  |  |     if (isGenerated) { | 
					
						
							|  |  |  |       if (!genFile || !genFile.stmts || genFile.stmts.length === 0) { | 
					
						
							|  |  |  |         if (this.options.allowEmptyCodegenFiles) { | 
					
						
							|  |  |  |           outData = ''; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (baseFile) { | 
					
						
							|  |  |  |       sourceFiles = sourceFiles ? [...sourceFiles, baseFile] : [baseFile]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.host.writeFile(outFileName, outData, writeByteOrderMark, onError, sourceFiles); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:18 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | export function createProgram( | 
					
						
							|  |  |  |     {rootNames, options, host, oldProgram}: | 
					
						
							|  |  |  |         {rootNames: string[], options: CompilerOptions, host: CompilerHost, oldProgram?: Program}): | 
					
						
							|  |  |  |     Program { | 
					
						
							|  |  |  |   return new AngularCompilerProgram(rootNames, options, host, oldProgram); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  | // Compute the AotCompiler options
 | 
					
						
							|  |  |  | function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions { | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |   let missingTranslation = core.MissingTranslationStrategy.Warning; | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   switch (options.i18nInMissingTranslations) { | 
					
						
							|  |  |  |     case 'ignore': | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |       missingTranslation = core.MissingTranslationStrategy.Ignore; | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case 'error': | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |       missingTranslation = core.MissingTranslationStrategy.Error; | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let translations: string = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (options.i18nInFile) { | 
					
						
							| 
									
										
										
										
											2017-08-31 23:11:29 +02:00
										 |  |  |     if (!options.i18nInLocale) { | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |       throw new Error(`The translation file (${options.i18nInFile}) locale must be provided.`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     translations = fs.readFileSync(options.i18nInFile, 'utf8'); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     // No translations are provided, ignore any errors
 | 
					
						
							|  |  |  |     // We still go through i18n to remove i18n attributes
 | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |     missingTranslation = core.MissingTranslationStrategy.Ignore; | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     locale: options.i18nInLocale, | 
					
						
							|  |  |  |     i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation, | 
					
						
							|  |  |  |     enableLegacyTemplate: options.enableLegacyTemplate, | 
					
						
							|  |  |  |     enableSummariesForJit: true, | 
					
						
							| 
									
										
										
										
											2017-07-28 15:58:28 +02:00
										 |  |  |     preserveWhitespaces: options.preserveWhitespaces, | 
					
						
							| 
									
										
										
										
											2017-09-11 15:18:19 -07:00
										 |  |  |     fullTemplateTypeCheck: options.fullTemplateTypeCheck, | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     allowEmptyCodegenFiles: options.allowEmptyCodegenFiles, | 
					
						
							| 
									
										
										
										
											2017-08-02 11:20:07 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getNgOptionDiagnostics(options: CompilerOptions): Diagnostic[] { | 
					
						
							|  |  |  |   if (options.annotationsAs) { | 
					
						
							|  |  |  |     switch (options.annotationsAs) { | 
					
						
							|  |  |  |       case 'decorators': | 
					
						
							|  |  |  |       case 'static fields': | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return [{ | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |           messageText: | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |               'Angular compiler options "annotationsAs" only supports "static fields" and "decorators"', | 
					
						
							| 
									
										
										
										
											2017-08-18 14:03:59 -07:00
										 |  |  |           category: ts.DiagnosticCategory.Error, | 
					
						
							|  |  |  |           source: SOURCE, | 
					
						
							|  |  |  |           code: DEFAULT_ERROR_CODE | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |         }]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return []; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Returns a function that can adjust a path from source path to out path, | 
					
						
							|  |  |  |  * based on an existing mapping from source to out path. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * TODO(tbosch): talk to the TypeScript team to expose their logic for calculating the `rootDir` | 
					
						
							|  |  |  |  * if none was specified. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param outDir | 
					
						
							|  |  |  |  * @param outSrcMappings | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export function createSrcToOutPathMapper( | 
					
						
							|  |  |  |     outDir: string | undefined, sampleSrcFileName: string | undefined, | 
					
						
							|  |  |  |     sampleOutFileName: string | undefined): (srcFileName: string) => string { | 
					
						
							|  |  |  |   let srcToOutPath: (srcFileName: string) => string; | 
					
						
							|  |  |  |   if (outDir) { | 
					
						
							|  |  |  |     if (sampleSrcFileName == null || sampleOutFileName == null) { | 
					
						
							|  |  |  |       throw new Error(`Can't calculate the rootDir without a sample srcFileName / outFileName. `); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const srcFileDir = path.dirname(sampleSrcFileName); | 
					
						
							|  |  |  |     const outFileDir = path.dirname(sampleOutFileName); | 
					
						
							|  |  |  |     if (srcFileDir === outFileDir) { | 
					
						
							|  |  |  |       return (srcFileName) => srcFileName; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const srcDirParts = srcFileDir.split(path.sep); | 
					
						
							|  |  |  |     const outDirParts = outFileDir.split(path.sep); | 
					
						
							|  |  |  |     // calculate the common suffix
 | 
					
						
							|  |  |  |     let i = 0; | 
					
						
							|  |  |  |     while (i < Math.min(srcDirParts.length, outDirParts.length) && | 
					
						
							|  |  |  |            srcDirParts[srcDirParts.length - 1 - i] === outDirParts[outDirParts.length - 1 - i]) | 
					
						
							|  |  |  |       i++; | 
					
						
							|  |  |  |     const rootDir = srcDirParts.slice(0, srcDirParts.length - i).join(path.sep); | 
					
						
							|  |  |  |     srcToOutPath = (srcFileName) => path.resolve(outDir, path.relative(rootDir, srcFileName)); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     srcToOutPath = (srcFileName) => srcFileName; | 
					
						
							| 
									
										
										
										
											2017-06-09 14:50:57 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-28 11:42:58 -07:00
										 |  |  |   return srcToOutPath; | 
					
						
							| 
									
										
										
										
											2017-07-28 15:58:28 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-09-12 15:53:17 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function i18nExtract( | 
					
						
							|  |  |  |     formatName: string | null, outFile: string | null, host: ts.CompilerHost, | 
					
						
							|  |  |  |     options: CompilerOptions, bundle: MessageBundle): string[] { | 
					
						
							|  |  |  |   formatName = formatName || 'null'; | 
					
						
							|  |  |  |   // Checks the format and returns the extension
 | 
					
						
							|  |  |  |   const ext = i18nGetExtension(formatName); | 
					
						
							|  |  |  |   const content = i18nSerialize(bundle, formatName, options); | 
					
						
							|  |  |  |   const dstFile = outFile || `messages.${ext}`; | 
					
						
							|  |  |  |   const dstPath = path.resolve(options.outDir || options.basePath, dstFile); | 
					
						
							|  |  |  |   host.writeFile(dstPath, content, false); | 
					
						
							|  |  |  |   return [dstPath]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function i18nSerialize( | 
					
						
							|  |  |  |     bundle: MessageBundle, formatName: string, options: CompilerOptions): string { | 
					
						
							|  |  |  |   const format = formatName.toLowerCase(); | 
					
						
							|  |  |  |   let serializer: Serializer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (format) { | 
					
						
							|  |  |  |     case 'xmb': | 
					
						
							|  |  |  |       serializer = new Xmb(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 'xliff2': | 
					
						
							|  |  |  |     case 'xlf2': | 
					
						
							|  |  |  |       serializer = new Xliff2(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case 'xlf': | 
					
						
							|  |  |  |     case 'xliff': | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       serializer = new Xliff(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return bundle.write( | 
					
						
							|  |  |  |       serializer, (sourcePath: string) => | 
					
						
							|  |  |  |                       options.basePath ? path.relative(options.basePath, sourcePath) : sourcePath); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function i18nGetExtension(formatName: string): string { | 
					
						
							|  |  |  |   const format = (formatName || 'xlf').toLowerCase(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   switch (format) { | 
					
						
							|  |  |  |     case 'xmb': | 
					
						
							|  |  |  |       return 'xmb'; | 
					
						
							|  |  |  |     case 'xlf': | 
					
						
							|  |  |  |     case 'xlif': | 
					
						
							|  |  |  |     case 'xliff': | 
					
						
							|  |  |  |     case 'xlf2': | 
					
						
							|  |  |  |     case 'xliff2': | 
					
						
							|  |  |  |       return 'xlf'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   throw new Error(`Unsupported format "${formatName}"`); | 
					
						
							|  |  |  | } |