| 
									
										
										
										
											2017-01-26 09:35:49 -08: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-05-17 11:21:08 -07:00
										 |  |  | import {AotCompilerHost, AotCompilerOptions, GeneratedFile, createAotCompiler, toTypeScript} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2017-09-13 16:55:42 -07:00
										 |  |  | import {MetadataBundlerHost} from '@angular/compiler-cli/src/metadata/bundler'; | 
					
						
							|  |  |  | import {MetadataCollector} from '@angular/compiler-cli/src/metadata/collector'; | 
					
						
							|  |  |  | import {ModuleMetadata} from '@angular/compiler-cli/src/metadata/index'; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 10:22:17 -07:00
										 |  |  | export interface MetadataProvider { getMetadata(source: ts.SourceFile): ModuleMetadata|undefined; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | let nodeModulesPath: string; | 
					
						
							|  |  |  | let angularSourcePath: string; | 
					
						
							|  |  |  | let rootPath: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | calcPathsOnDisc(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type MockFileOrDirectory = string | MockDirectory; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export type MockDirectory = { | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |   [name: string]: MockFileOrDirectory | undefined; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | export function isDirectory(data: MockFileOrDirectory | undefined): data is MockDirectory { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   return typeof data !== 'string'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const NODE_MODULES = '/node_modules/'; | 
					
						
							|  |  |  | const IS_GENERATED = /\.(ngfactory|ngstyle)$/; | 
					
						
							|  |  |  | const angularts = /@angular\/(\w|\/|-)+\.tsx?$/; | 
					
						
							|  |  |  | const rxjs = /\/rxjs\//; | 
					
						
							|  |  |  | const tsxfile = /\.tsx$/; | 
					
						
							|  |  |  | export const settings: ts.CompilerOptions = { | 
					
						
							|  |  |  |   target: ts.ScriptTarget.ES5, | 
					
						
							|  |  |  |   declaration: true, | 
					
						
							|  |  |  |   module: ts.ModuleKind.CommonJS, | 
					
						
							|  |  |  |   moduleResolution: ts.ModuleResolutionKind.NodeJs, | 
					
						
							|  |  |  |   emitDecoratorMetadata: true, | 
					
						
							|  |  |  |   experimentalDecorators: true, | 
					
						
							|  |  |  |   removeComments: false, | 
					
						
							|  |  |  |   noImplicitAny: false, | 
					
						
							|  |  |  |   skipLibCheck: true, | 
					
						
							| 
									
										
										
										
											2017-05-11 10:15:54 -07:00
										 |  |  |   strictNullChecks: true, | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   lib: ['lib.es2015.d.ts', 'lib.dom.d.ts'], | 
					
						
							|  |  |  |   types: [] | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  | export interface EmitterOptions { | 
					
						
							|  |  |  |   emitMetadata: boolean; | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |   mockData?: MockDirectory; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function calcPathsOnDisc() { | 
					
						
							|  |  |  |   const moduleFilename = module.filename.replace(/\\/g, '/'); | 
					
						
							|  |  |  |   const distIndex = moduleFilename.indexOf('/dist/all'); | 
					
						
							|  |  |  |   if (distIndex >= 0) { | 
					
						
							|  |  |  |     rootPath = moduleFilename.substr(0, distIndex); | 
					
						
							|  |  |  |     nodeModulesPath = path.join(rootPath, 'node_modules'); | 
					
						
							|  |  |  |     angularSourcePath = path.join(rootPath, 'packages'); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | export class EmittingCompilerHost implements ts.CompilerHost { | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   private addedFiles = new Map<string, string>(); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   private writtenFiles = new Map<string, string>(); | 
					
						
							|  |  |  |   private scriptNames: string[]; | 
					
						
							|  |  |  |   private root = '/'; | 
					
						
							|  |  |  |   private collector = new MetadataCollector(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   constructor(scriptNames: string[], private options: EmitterOptions) { | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |     // Rewrite references to scripts with '@angular' to its corresponding location in
 | 
					
						
							|  |  |  |     // the source tree.
 | 
					
						
							|  |  |  |     this.scriptNames = scriptNames.map(f => this.effectiveName(f)); | 
					
						
							|  |  |  |     this.root = rootPath; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public writtenAngularFiles(target = new Map<string, string>()): Map<string, string> { | 
					
						
							|  |  |  |     this.written.forEach((value, key) => { | 
					
						
							|  |  |  |       const path = `/node_modules/@angular${key.substring(angularSourcePath.length)}`; | 
					
						
							|  |  |  |       target.set(path, value); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return target; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   public addScript(fileName: string, content: string) { | 
					
						
							|  |  |  |     const scriptName = this.effectiveName(fileName); | 
					
						
							|  |  |  |     this.addedFiles.set(scriptName, content); | 
					
						
							|  |  |  |     this.scriptNames.push(scriptName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public override(fileName: string, content: string) { | 
					
						
							|  |  |  |     const scriptName = this.effectiveName(fileName); | 
					
						
							|  |  |  |     this.addedFiles.set(scriptName, content); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public addWrittenFile(fileName: string, content: string) { | 
					
						
							|  |  |  |     this.writtenFiles.set(this.effectiveName(fileName), content); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   public getWrittenFiles(): {name: string, content: string}[] { | 
					
						
							|  |  |  |     return Array.from(this.writtenFiles).map(f => ({name: f[0], content: f[1]})); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public get scripts(): string[] { return this.scriptNames; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public get written(): Map<string, string> { return this.writtenFiles; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   public effectiveName(fileName: string): string { | 
					
						
							| 
									
										
										
										
											2017-03-08 15:53:45 -08:00
										 |  |  |     const prefix = '@angular/'; | 
					
						
							|  |  |  |     return fileName.startsWith('@angular/') ? | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |         path.join(angularSourcePath, fileName.substr(prefix.length)) : | 
					
						
							| 
									
										
										
										
											2017-03-08 15:53:45 -08:00
										 |  |  |         fileName; | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   // ts.ModuleResolutionHost
 | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   fileExists(fileName: string): boolean { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     return this.addedFiles.has(fileName) || open(fileName, this.options.mockData) != null || | 
					
						
							|  |  |  |         fs.existsSync(fileName); | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   readFile(fileName: string): string { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     const result = this.addedFiles.get(fileName) || open(fileName, this.options.mockData); | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |     if (result) return result; | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     let basename = path.basename(fileName); | 
					
						
							|  |  |  |     if (/^lib.*\.d\.ts$/.test(basename)) { | 
					
						
							|  |  |  |       let libPath = ts.getDefaultLibFilePath(settings); | 
					
						
							|  |  |  |       return fs.readFileSync(path.join(path.dirname(libPath), basename), 'utf8'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return fs.readFileSync(fileName, 'utf8'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   directoryExists(directoryName: string): boolean { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     return directoryExists(directoryName, this.options.mockData) || | 
					
						
							|  |  |  |         (fs.existsSync(directoryName) && fs.statSync(directoryName).isDirectory()); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCurrentDirectory(): string { return this.root; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getDirectories(dir: string): string[] { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     const result = open(dir, this.options.mockData); | 
					
						
							|  |  |  |     if (result && typeof result !== 'string') { | 
					
						
							|  |  |  |       return Object.keys(result); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     return fs.readdirSync(dir).filter(p => { | 
					
						
							|  |  |  |       const name = path.join(dir, p); | 
					
						
							|  |  |  |       const stat = fs.statSync(name); | 
					
						
							|  |  |  |       return stat && stat.isDirectory(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ts.CompilerHost
 | 
					
						
							|  |  |  |   getSourceFile( | 
					
						
							|  |  |  |       fileName: string, languageVersion: ts.ScriptTarget, | 
					
						
							|  |  |  |       onError?: (message: string) => void): ts.SourceFile { | 
					
						
							|  |  |  |     const content = this.readFile(fileName); | 
					
						
							|  |  |  |     if (content) { | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |       return ts.createSourceFile(fileName, content, languageVersion, /* setParentNodes */ true); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |     throw new Error(`File not found '${fileName}'.`); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   writeFile: ts.WriteFileCallback = | 
					
						
							|  |  |  |       (fileName: string, data: string, writeByteOrderMark: boolean, | 
					
						
							|  |  |  |        onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => { | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |         this.addWrittenFile(fileName, data); | 
					
						
							|  |  |  |         if (this.options.emitMetadata && sourceFiles && sourceFiles.length && DTS.test(fileName)) { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |           const metadataFilePath = fileName.replace(DTS, '.metadata.json'); | 
					
						
							|  |  |  |           const metadata = this.collector.getMetadata(sourceFiles[0]); | 
					
						
							| 
									
										
										
										
											2017-02-14 13:33:06 -08:00
										 |  |  |           if (metadata) { | 
					
						
							|  |  |  |             this.addWrittenFile(metadataFilePath, JSON.stringify(metadata)); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCanonicalFileName(fileName: string): string { | 
					
						
							|  |  |  |     return fileName; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   useCaseSensitiveFileNames(): boolean { return false; } | 
					
						
							|  |  |  |   getNewLine(): string { return '\n'; } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockCompilerHost implements ts.CompilerHost { | 
					
						
							|  |  |  |   scriptNames: string[]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 14:51:29 -07:00
										 |  |  |   public overrides = new Map<string, string>(); | 
					
						
							|  |  |  |   public writtenFiles = new Map<string, string>(); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   private sourceFiles = new Map<string, ts.SourceFile>(); | 
					
						
							|  |  |  |   private assumeExists = new Set<string>(); | 
					
						
							|  |  |  |   private traces: string[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |   constructor(scriptNames: string[], private data: MockDirectory) { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     this.scriptNames = scriptNames.slice(0); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Test API
 | 
					
						
							|  |  |  |   override(fileName: string, content: string) { | 
					
						
							|  |  |  |     if (content) { | 
					
						
							|  |  |  |       this.overrides.set(fileName, content); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.overrides.delete(fileName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.sourceFiles.delete(fileName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   addScript(fileName: string, content: string) { | 
					
						
							|  |  |  |     this.overrides.set(fileName, content); | 
					
						
							|  |  |  |     this.scriptNames.push(fileName); | 
					
						
							|  |  |  |     this.sourceFiles.delete(fileName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   assumeFileExists(fileName: string) { this.assumeExists.add(fileName); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   remove(files: string[]) { | 
					
						
							|  |  |  |     // Remove the files from the list of scripts.
 | 
					
						
							|  |  |  |     const fileSet = new Set(files); | 
					
						
							|  |  |  |     this.scriptNames = this.scriptNames.filter(f => fileSet.has(f)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Remove files from written files
 | 
					
						
							|  |  |  |     files.forEach(f => this.writtenFiles.delete(f)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ts.ModuleResolutionHost
 | 
					
						
							|  |  |  |   fileExists(fileName: string): boolean { | 
					
						
							|  |  |  |     if (this.overrides.has(fileName) || this.writtenFiles.has(fileName) || | 
					
						
							|  |  |  |         this.assumeExists.has(fileName)) { | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const effectiveName = this.getEffectiveName(fileName); | 
					
						
							|  |  |  |     if (effectiveName == fileName) { | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |       return open(fileName, this.data) != null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (fileName.match(rxjs)) { | 
					
						
							|  |  |  |       return fs.existsSync(effectiveName); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |   readFile(fileName: string): string { return this.getFileContent(fileName) !; } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   trace(s: string): void { this.traces.push(s); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCurrentDirectory(): string { return '/'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getDirectories(dir: string): string[] { | 
					
						
							|  |  |  |     const effectiveName = this.getEffectiveName(dir); | 
					
						
							|  |  |  |     if (effectiveName === dir) { | 
					
						
							|  |  |  |       const data = find(dir, this.data); | 
					
						
							|  |  |  |       if (isDirectory(data)) { | 
					
						
							|  |  |  |         return Object.keys(data).filter(k => isDirectory(data[k])); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |     return []; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // ts.CompilerHost
 | 
					
						
							|  |  |  |   getSourceFile( | 
					
						
							|  |  |  |       fileName: string, languageVersion: ts.ScriptTarget, | 
					
						
							|  |  |  |       onError?: (message: string) => void): ts.SourceFile { | 
					
						
							|  |  |  |     let result = this.sourceFiles.get(fileName); | 
					
						
							|  |  |  |     if (!result) { | 
					
						
							|  |  |  |       const content = this.getFileContent(fileName); | 
					
						
							|  |  |  |       if (content) { | 
					
						
							|  |  |  |         result = ts.createSourceFile(fileName, content, languageVersion); | 
					
						
							|  |  |  |         this.sourceFiles.set(fileName, result); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |     return result !; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   writeFile: ts.WriteFileCallback = | 
					
						
							|  |  |  |       (fileName: string, data: string, writeByteOrderMark: boolean) => { | 
					
						
							|  |  |  |         this.writtenFiles.set(fileName, data); | 
					
						
							|  |  |  |         this.sourceFiles.delete(fileName); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getCanonicalFileName(fileName: string): string { | 
					
						
							|  |  |  |     return fileName; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   useCaseSensitiveFileNames(): boolean { return false; } | 
					
						
							|  |  |  |   getNewLine(): string { return '\n'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Private methods
 | 
					
						
							|  |  |  |   private getFileContent(fileName: string): string|undefined { | 
					
						
							|  |  |  |     if (this.overrides.has(fileName)) { | 
					
						
							|  |  |  |       return this.overrides.get(fileName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this.writtenFiles.has(fileName)) { | 
					
						
							|  |  |  |       return this.writtenFiles.get(fileName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     let basename = path.basename(fileName); | 
					
						
							|  |  |  |     if (/^lib.*\.d\.ts$/.test(basename)) { | 
					
						
							|  |  |  |       let libPath = ts.getDefaultLibFilePath(settings); | 
					
						
							|  |  |  |       return fs.readFileSync(path.join(path.dirname(libPath), basename), 'utf8'); | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     let effectiveName = this.getEffectiveName(fileName); | 
					
						
							|  |  |  |     if (effectiveName === fileName) { | 
					
						
							|  |  |  |       return open(fileName, this.data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (fileName.match(rxjs) && fs.existsSync(fileName)) { | 
					
						
							|  |  |  |       return fs.readFileSync(fileName, 'utf8'); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private getEffectiveName(name: string): string { | 
					
						
							|  |  |  |     const node_modules = 'node_modules'; | 
					
						
							|  |  |  |     const rxjs = '/rxjs'; | 
					
						
							|  |  |  |     if (name.startsWith('/' + node_modules)) { | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |       if (nodeModulesPath && name.startsWith('/' + node_modules + rxjs)) { | 
					
						
							|  |  |  |         return path.join(nodeModulesPath, name.substr(node_modules.length + 1)); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return name; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/; | 
					
						
							|  |  |  | const DTS = /\.d\.ts$/; | 
					
						
							|  |  |  | const GENERATED_FILES = /\.ngfactory\.ts$|\.ngstyle\.ts$/; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class MockAotCompilerHost implements AotCompilerHost { | 
					
						
							|  |  |  |   private metadataVisible: boolean = true; | 
					
						
							|  |  |  |   private dtsAreSource: boolean = true; | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |   private resolveModuleNameHost: ts.ModuleResolutionHost; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 10:22:17 -07:00
										 |  |  |   constructor( | 
					
						
							|  |  |  |       private tsHost: MockCompilerHost, | 
					
						
							|  |  |  |       private metadataProvider: MetadataProvider = new MetadataCollector()) { | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |     this.resolveModuleNameHost = Object.create(tsHost); | 
					
						
							|  |  |  |     this.resolveModuleNameHost.fileExists = (fileName) => { | 
					
						
							|  |  |  |       fileName = stripNgResourceSuffix(fileName); | 
					
						
							|  |  |  |       return tsHost.fileExists(fileName); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   hideMetadata() { this.metadataVisible = false; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   tsFilesOnly() { this.dtsAreSource = false; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // StaticSymbolResolverHost
 | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |   getMetadataFor(modulePath: string): {[key: string]: any}[]|undefined { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     if (!this.tsHost.fileExists(modulePath)) { | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |       return undefined; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (DTS.test(modulePath)) { | 
					
						
							|  |  |  |       if (this.metadataVisible) { | 
					
						
							|  |  |  |         const metadataPath = modulePath.replace(DTS, '.metadata.json'); | 
					
						
							|  |  |  |         if (this.tsHost.fileExists(metadataPath)) { | 
					
						
							|  |  |  |           let result = JSON.parse(this.tsHost.readFile(metadataPath)); | 
					
						
							|  |  |  |           return Array.isArray(result) ? result : [result]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       const sf = this.tsHost.getSourceFile(modulePath, ts.ScriptTarget.Latest); | 
					
						
							| 
									
										
										
										
											2017-08-23 10:22:17 -07:00
										 |  |  |       const metadata = this.metadataProvider.getMetadata(sf); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |       return metadata ? [metadata] : []; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-14 14:40:56 -07:00
										 |  |  |     return undefined; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   moduleNameToFileName(moduleName: string, containingFile: string): string|null { | 
					
						
							|  |  |  |     if (!containingFile || !containingFile.length) { | 
					
						
							|  |  |  |       if (moduleName.indexOf('.') === 0) { | 
					
						
							|  |  |  |         throw new Error('Resolution of relative paths requires a containing file.'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       // Any containing file gives the same result for absolute imports
 | 
					
						
							|  |  |  |       containingFile = path.join('/', 'index.ts'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     moduleName = moduleName.replace(EXT, ''); | 
					
						
							|  |  |  |     const resolved = ts.resolveModuleName( | 
					
						
							|  |  |  |                            moduleName, containingFile.replace(/\\/g, '/'), | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |                            {baseDir: '/', genDir: '/'}, this.resolveModuleNameHost) | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |                          .resolvedModule; | 
					
						
							|  |  |  |     return resolved ? resolved.resolvedFileName : null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |   resourceNameToFileName(resourceName: string, containingFile: string) { | 
					
						
							|  |  |  |     // Note: we convert package paths into relative paths to be compatible with the the
 | 
					
						
							|  |  |  |     // previous implementation of UrlResolver.
 | 
					
						
							|  |  |  |     if (resourceName && resourceName.charAt(0) !== '.' && !path.isAbsolute(resourceName)) { | 
					
						
							|  |  |  |       resourceName = `./${resourceName}`; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const filePathWithNgResource = | 
					
						
							|  |  |  |         this.moduleNameToFileName(addNgResourceSuffix(resourceName), containingFile); | 
					
						
							|  |  |  |     return filePathWithNgResource ? stripNgResourceSuffix(filePathWithNgResource) : null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   // AotSummaryResolverHost
 | 
					
						
							|  |  |  |   loadSummary(filePath: string): string|null { return this.tsHost.readFile(filePath); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isSourceFile(sourceFilePath: string): boolean { | 
					
						
							|  |  |  |     return !GENERATED_FILES.test(sourceFilePath) && | 
					
						
							|  |  |  |         (this.dtsAreSource || !DTS.test(sourceFilePath)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  |   toSummaryFileName(filePath: string): string { return filePath.replace(EXT, '') + '.d.ts'; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fromSummaryFileName(filePath: string): string { return filePath; } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // AotCompilerHost
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   fileNameToModuleName(importedFile: string, containingFile: string): string { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |     return importedFile.replace(EXT, ''); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   loadResource(path: string): string { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     if (this.tsHost.fileExists(path)) { | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |       return this.tsHost.readFile(path); | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |       throw new Error(`Resource ${path} not found.`); | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 13:30:40 -08:00
										 |  |  | export class MockMetadataBundlerHost implements MetadataBundlerHost { | 
					
						
							|  |  |  |   private collector = new MetadataCollector(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(private host: ts.CompilerHost) {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 12:52:48 -07:00
										 |  |  |   getMetadataFor(moduleName: string): ModuleMetadata|undefined { | 
					
						
							| 
									
										
										
										
											2017-02-15 13:30:40 -08:00
										 |  |  |     const source = this.host.getSourceFile(moduleName + '.ts', ts.ScriptTarget.Latest); | 
					
						
							|  |  |  |     return this.collector.getMetadata(source); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | function find(fileName: string, data: MockFileOrDirectory | undefined): MockFileOrDirectory| | 
					
						
							|  |  |  |     undefined { | 
					
						
							| 
									
										
										
										
											2017-03-20 16:31:11 -07:00
										 |  |  |   if (!data) return undefined; | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   const names = fileName.split('/'); | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   if (names.length && !names[0].length) names.shift(); | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |   let current: MockFileOrDirectory|undefined = data; | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   for (const name of names) { | 
					
						
							|  |  |  |     if (typeof current !== 'object') { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |       return undefined; | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     current = current[name]; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   return current; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | function open(fileName: string, data: MockFileOrDirectory | undefined): string|undefined { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   let result = find(fileName, data); | 
					
						
							|  |  |  |   if (typeof result === 'string') { | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return undefined; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | function directoryExists(dirname: string, data: MockFileOrDirectory | undefined): boolean { | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  |   let result = find(dirname, data); | 
					
						
							| 
									
										
										
										
											2017-03-24 09:59:58 -07:00
										 |  |  |   return !!result && typeof result !== 'string'; | 
					
						
							| 
									
										
										
										
											2017-01-26 09:35:49 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export type MockFileArray = { | 
					
						
							|  |  |  |   fileName: string, | 
					
						
							|  |  |  |   content: string | 
					
						
							|  |  |  | }[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export type MockData = MockDirectory | Map<string, string>| (MockDirectory | Map<string, string>)[]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function toMockFileArray(data: MockData, target: MockFileArray = []): MockFileArray { | 
					
						
							|  |  |  |   if (data instanceof Map) { | 
					
						
							|  |  |  |     mapToMockFileArray(data, target); | 
					
						
							|  |  |  |   } else if (Array.isArray(data)) { | 
					
						
							|  |  |  |     data.forEach(entry => toMockFileArray(entry, target)); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     mockDirToFileArray(data, '', target); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return target; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function mockDirToFileArray(dir: MockDirectory, path: string, target: MockFileArray) { | 
					
						
							|  |  |  |   Object.keys(dir).forEach((localFileName) => { | 
					
						
							|  |  |  |     const value = dir[localFileName] !; | 
					
						
							|  |  |  |     const fileName = `${path}/${localFileName}`; | 
					
						
							|  |  |  |     if (typeof value === 'string') { | 
					
						
							|  |  |  |       target.push({fileName, content: value}); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       mockDirToFileArray(value, fileName, target); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function mapToMockFileArray(files: Map<string, string>, target: MockFileArray) { | 
					
						
							|  |  |  |   files.forEach((content, fileName) => { target.push({fileName, content}); }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function arrayToMockMap(arr: MockFileArray): Map<string, string> { | 
					
						
							|  |  |  |   const map = new Map<string, string>(); | 
					
						
							|  |  |  |   arr.forEach(({fileName, content}) => { map.set(fileName, content); }); | 
					
						
							|  |  |  |   return map; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function arrayToMockDir(arr: MockFileArray): MockDirectory { | 
					
						
							|  |  |  |   const rootDir: MockDirectory = {}; | 
					
						
							|  |  |  |   arr.forEach(({fileName, content}) => { | 
					
						
							|  |  |  |     let pathParts = fileName.split('/'); | 
					
						
							|  |  |  |     // trim trailing slash
 | 
					
						
							|  |  |  |     let startIndex = pathParts[0] ? 0 : 1; | 
					
						
							|  |  |  |     // get/create the directory
 | 
					
						
							|  |  |  |     let currentDir = rootDir; | 
					
						
							|  |  |  |     for (let i = startIndex; i < pathParts.length - 1; i++) { | 
					
						
							|  |  |  |       const pathPart = pathParts[i]; | 
					
						
							|  |  |  |       let localDir = <MockDirectory>currentDir[pathPart]; | 
					
						
							|  |  |  |       if (!localDir) { | 
					
						
							|  |  |  |         currentDir[pathPart] = localDir = {}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       currentDir = localDir; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // write the file
 | 
					
						
							|  |  |  |     currentDir[pathParts[pathParts.length - 1]] = content; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   return rootDir; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const minCoreIndex = `
 | 
					
						
							|  |  |  |   export * from './src/application_module'; | 
					
						
							|  |  |  |   export * from './src/change_detection'; | 
					
						
							|  |  |  |   export * from './src/metadata'; | 
					
						
							|  |  |  |   export * from './src/di/metadata'; | 
					
						
							|  |  |  |   export * from './src/di/injector'; | 
					
						
							|  |  |  |   export * from './src/di/injection_token'; | 
					
						
							|  |  |  |   export * from './src/linker'; | 
					
						
							|  |  |  |   export * from './src/render'; | 
					
						
							|  |  |  |   export * from './src/codegen_private_exports'; | 
					
						
							|  |  |  | `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-13 17:16:56 -06:00
										 |  |  | export function setup(options: {compileAngular: boolean, compileAnimations: boolean} = { | 
					
						
							|  |  |  |   compileAngular: true, | 
					
						
							|  |  |  |   compileAnimations: true, | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | }) { | 
					
						
							|  |  |  |   let angularFiles = new Map<string, string>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeAll(() => { | 
					
						
							|  |  |  |     if (options.compileAngular) { | 
					
						
							|  |  |  |       const emittingHost = new EmittingCompilerHost([], {emitMetadata: true}); | 
					
						
							|  |  |  |       emittingHost.addScript('@angular/core/index.ts', minCoreIndex); | 
					
						
							|  |  |  |       const emittingProgram = ts.createProgram(emittingHost.scripts, settings, emittingHost); | 
					
						
							|  |  |  |       emittingProgram.emit(); | 
					
						
							|  |  |  |       emittingHost.writtenAngularFiles(angularFiles); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-07-13 17:16:56 -06:00
										 |  |  |     if (options.compileAnimations) { | 
					
						
							|  |  |  |       const emittingHost = | 
					
						
							|  |  |  |           new EmittingCompilerHost(['@angular/animations/index.ts'], {emitMetadata: true}); | 
					
						
							|  |  |  |       const emittingProgram = ts.createProgram(emittingHost.scripts, settings, emittingHost); | 
					
						
							|  |  |  |       emittingProgram.emit(); | 
					
						
							|  |  |  |       emittingHost.writtenAngularFiles(angularFiles); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return angularFiles; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function expectNoDiagnostics(program: ts.Program) { | 
					
						
							|  |  |  |   function fileInfo(diagnostic: ts.Diagnostic): string { | 
					
						
							|  |  |  |     if (diagnostic.file) { | 
					
						
							|  |  |  |       return `${diagnostic.file.fileName}(${diagnostic.start}): `; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function chars(len: number, ch: string): string { return new Array(len).fill(ch).join(''); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function lineNoOf(offset: number, text: string): number { | 
					
						
							|  |  |  |     let result = 1; | 
					
						
							|  |  |  |     for (let i = 0; i < offset; i++) { | 
					
						
							|  |  |  |       if (text[i] == '\n') result++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function lineInfo(diagnostic: ts.Diagnostic): string { | 
					
						
							|  |  |  |     if (diagnostic.file) { | 
					
						
							| 
									
										
										
										
											2017-08-02 16:26:42 -07:00
										 |  |  |       const start = diagnostic.start !; | 
					
						
							|  |  |  |       let end = diagnostic.start ! + diagnostic.length !; | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |       const source = diagnostic.file.text; | 
					
						
							|  |  |  |       let lineStart = start; | 
					
						
							|  |  |  |       let lineEnd = end; | 
					
						
							|  |  |  |       while (lineStart > 0 && source[lineStart] != '\n') lineStart--; | 
					
						
							|  |  |  |       if (lineStart < start) lineStart++; | 
					
						
							|  |  |  |       while (lineEnd < source.length && source[lineEnd] != '\n') lineEnd++; | 
					
						
							|  |  |  |       let line = source.substring(lineStart, lineEnd); | 
					
						
							|  |  |  |       const lineIndex = line.indexOf('/n'); | 
					
						
							|  |  |  |       if (lineIndex > 0) { | 
					
						
							|  |  |  |         line = line.substr(0, lineIndex); | 
					
						
							|  |  |  |         end = start + lineIndex; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const lineNo = lineNoOf(start, source) + ': '; | 
					
						
							|  |  |  |       return '\n' + lineNo + line + '\n' + chars(start - lineStart + lineNo.length, ' ') + | 
					
						
							|  |  |  |           chars(end - start, '^'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function expectNoDiagnostics(diagnostics: ts.Diagnostic[]) { | 
					
						
							|  |  |  |     if (diagnostics && diagnostics.length) { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |           'Errors from TypeScript:\n' + | 
					
						
							|  |  |  |           diagnostics.map(d => `${fileInfo(d)}${d.messageText}${lineInfo(d)}`).join(' \n')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   expectNoDiagnostics(program.getOptionsDiagnostics()); | 
					
						
							|  |  |  |   expectNoDiagnostics(program.getSyntacticDiagnostics()); | 
					
						
							|  |  |  |   expectNoDiagnostics(program.getSemanticDiagnostics()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-01 11:13:50 -06:00
										 |  |  | export function isSource(fileName: string): boolean { | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |   return !isDts(fileName) && /\.ts$/.test(fileName); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function isDts(fileName: string): boolean { | 
					
						
							|  |  |  |   return /\.d.ts$/.test(fileName); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function isSourceOrDts(fileName: string): boolean { | 
					
						
							|  |  |  |   return /\.ts$/.test(fileName); | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-11 10:26:02 -07:00
										 |  |  | export function compile( | 
					
						
							|  |  |  |     rootDirs: MockData, options: { | 
					
						
							|  |  |  |       emit?: boolean, | 
					
						
							|  |  |  |       useSummaries?: boolean, | 
					
						
							|  |  |  |       preCompile?: (program: ts.Program) => void, | 
					
						
							|  |  |  |       postCompile?: (program: ts.Program) => void, | 
					
						
							|  |  |  |     }& AotCompilerOptions = {}, | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |     tsOptions: ts.CompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} { | 
					
						
							|  |  |  |   // when using summaries, always emit so the next step can use the results.
 | 
					
						
							|  |  |  |   const emit = options.emit || options.useSummaries; | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   const preCompile = options.preCompile || (() => {}); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   const postCompile = options.postCompile || expectNoDiagnostics; | 
					
						
							|  |  |  |   const rootDirArr = toMockFileArray(rootDirs); | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |   const scriptNames = rootDirArr.map(entry => entry.fileName) | 
					
						
							|  |  |  |                           .filter(options.useSummaries ? isSource : isSourceOrDts); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const host = new MockCompilerHost(scriptNames, arrayToMockDir(rootDirArr)); | 
					
						
							|  |  |  |   const aotHost = new MockAotCompilerHost(host); | 
					
						
							|  |  |  |   if (options.useSummaries) { | 
					
						
							|  |  |  |     aotHost.hideMetadata(); | 
					
						
							|  |  |  |     aotHost.tsFilesOnly(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const tsSettings = {...settings, ...tsOptions}; | 
					
						
							|  |  |  |   const program = ts.createProgram(host.scriptNames.slice(0), tsSettings, host); | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   preCompile(program); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   const {compiler, reflector} = createAotCompiler(aotHost, options); | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   const analyzedModules = | 
					
						
							|  |  |  |       compiler.analyzeModulesSync(program.getSourceFiles().map(sf => sf.fileName)); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   const genFiles = compiler.emitAllImpls(analyzedModules); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   genFiles.forEach((file) => { | 
					
						
							|  |  |  |     const source = file.source || toTypeScript(file); | 
					
						
							|  |  |  |     if (isSource(file.genFileUrl)) { | 
					
						
							|  |  |  |       host.addScript(file.genFileUrl, source); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       host.override(file.genFileUrl, source); | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   const newProgram = ts.createProgram(host.scriptNames.slice(0), tsSettings, host); | 
					
						
							| 
									
										
										
										
											2017-05-23 13:40:50 -07:00
										 |  |  |   postCompile(newProgram); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   if (emit) { | 
					
						
							|  |  |  |     newProgram.emit(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   let outDir: MockDirectory = {}; | 
					
						
							|  |  |  |   if (emit) { | 
					
						
							| 
									
										
										
										
											2017-08-16 09:00:03 -07:00
										 |  |  |     const dtsFilesWithGenFiles = new Set<string>(genFiles.map(gf => gf.srcFileUrl).filter(isDts)); | 
					
						
							|  |  |  |     outDir = | 
					
						
							|  |  |  |         arrayToMockDir(toMockFileArray([host.writtenFiles, host.overrides]) | 
					
						
							|  |  |  |                            .filter((entry) => !isSource(entry.fileName)) | 
					
						
							|  |  |  |                            .concat(rootDirArr.filter(e => dtsFilesWithGenFiles.has(e.fileName)))); | 
					
						
							| 
									
										
										
										
											2017-05-17 15:39:08 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   return {genFiles, outDir}; | 
					
						
							| 
									
										
										
										
											2017-04-26 09:24:42 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | function stripNgResourceSuffix(fileName: string): string { | 
					
						
							|  |  |  |   return fileName.replace(/\.\$ngresource\$.*/, ''); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function addNgResourceSuffix(fileName: string): string { | 
					
						
							|  |  |  |   return `${fileName}.$ngresource$`; | 
					
						
							|  |  |  | } |