| 
									
										
										
										
											2017-08-14 11:04:55 -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-10-20 09:46:41 -07:00
										 |  |  | import {AotCompilerHost, EmitterVisitorContext, ExternalReference, GeneratedFile, ParseSourceSpan, TypeScriptEmitter, collectExternalReferences, syntaxError} from '@angular/compiler'; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as ts from 'typescript'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | import {TypeCheckHost} from '../diagnostics/translate_diagnostics'; | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  | import {METADATA_VERSION, ModuleMetadata} from '../metadata/index'; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | import {CompilerHost, CompilerOptions, LibrarySummary} from './api'; | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  | import {MetadataReaderHost, createMetadataReaderCache, readMetadata} from './metadata_reader'; | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  | import {DTS, GENERATED_FILES, isInRootDir, relativeToRootDirs} from './util'; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-26 19:04:46 +01:00
										 |  |  | const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-|\.)+|(@(\w|-|\.)+\/(\w|-|\.)+))/; | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  | const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/; | 
					
						
							| 
									
										
										
										
											2019-01-15 13:35:28 -08:00
										 |  |  | const CSS_PREPROCESSOR_EXT = /(\.scss|\.less|\.styl)$/; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-18 11:21:29 -07:00
										 |  |  | let wrapHostForTest: ((host: ts.CompilerHost) => ts.CompilerHost)|null = null; | 
					
						
							| 
									
										
										
										
											2019-02-19 17:36:26 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-18 11:21:29 -07:00
										 |  |  | export function setWrapHostForTest(wrapFn: ((host: ts.CompilerHost) => ts.CompilerHost) | null): | 
					
						
							|  |  |  |     void { | 
					
						
							|  |  |  |   wrapHostForTest = wrapFn; | 
					
						
							| 
									
										
										
										
											2019-02-19 17:36:26 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | export function createCompilerHost( | 
					
						
							|  |  |  |     {options, tsHost = ts.createCompilerHost(options, true)}: | 
					
						
							|  |  |  |         {options: CompilerOptions, tsHost?: ts.CompilerHost}): CompilerHost { | 
					
						
							| 
									
										
										
										
											2019-03-18 11:21:29 -07:00
										 |  |  |   if (wrapHostForTest !== null) { | 
					
						
							|  |  |  |     tsHost = wrapHostForTest(tsHost); | 
					
						
							| 
									
										
										
										
											2019-02-19 17:36:26 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   return tsHost; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | export interface MetadataProvider { | 
					
						
							|  |  |  |   getMetadata(sourceFile: ts.SourceFile): ModuleMetadata|undefined; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | interface GenSourceFile { | 
					
						
							|  |  |  |   externalReferences: Set<string>; | 
					
						
							|  |  |  |   sourceFile: ts.SourceFile; | 
					
						
							|  |  |  |   emitCtx: EmitterVisitorContext; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | export interface CodeGenerator { | 
					
						
							|  |  |  |   generateFile(genFileName: string, baseFileName?: string): GeneratedFile; | 
					
						
							|  |  |  |   findGeneratedFileNames(fileName: string): string[]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  | function assert<T>(condition: T | null | undefined) { | 
					
						
							|  |  |  |   if (!condition) { | 
					
						
							|  |  |  |     // TODO(chuckjaz): do the right thing
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return condition !; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Implements the following hosts based on an api.CompilerHost: | 
					
						
							|  |  |  |  * - ts.CompilerHost to be consumed by a ts.Program | 
					
						
							|  |  |  |  * - AotCompilerHost for @angular/compiler | 
					
						
							|  |  |  |  * - TypeCheckHost for mapping ts errors to ng errors (via translateDiagnostics) | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  | export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHost, AotCompilerHost, | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     TypeCheckHost { | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |   private metadataReaderCache = createMetadataReaderCache(); | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |   private fileNameToModuleNameCache = new Map<string, string>(); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |   private flatModuleIndexCache = new Map<string, boolean>(); | 
					
						
							|  |  |  |   private flatModuleIndexNames = new Set<string>(); | 
					
						
							|  |  |  |   private flatModuleIndexRedirectNames = new Set<string>(); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |   private rootDirs: string[]; | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |   private moduleResolutionCache: ts.ModuleResolutionCache; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |   private originalSourceFiles = new Map<string, ts.SourceFile|null>(); | 
					
						
							| 
									
										
										
										
											2017-09-20 16:31:32 -07:00
										 |  |  |   private originalFileExistsCache = new Map<string, boolean>(); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private generatedSourceFiles = new Map<string, GenSourceFile>(); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   private generatedCodeFor = new Map<string, string[]>(); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private emitter = new TypeScriptEmitter(); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |   private metadataReaderHost: MetadataReaderHost; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-18 16:38:33 -07:00
										 |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   getCancellationToken !: () => ts.CancellationToken; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   getDefaultLibLocation !: () => string; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   trace !: (s: string) => void; | 
					
						
							|  |  |  |   // TODO(issue/24571): remove '!'.
 | 
					
						
							|  |  |  |   getDirectories !: (path: string) => string[]; | 
					
						
							| 
									
										
										
										
											2018-08-20 12:58:33 -07:00
										 |  |  |   resolveTypeReferenceDirectives?: | 
					
						
							| 
									
										
										
										
											2018-08-28 13:36:16 -07:00
										 |  |  |       (names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[]; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   directoryExists?: (directoryName: string) => boolean; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   constructor( | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |       private rootFiles: ReadonlyArray<string>, private options: CompilerOptions, | 
					
						
							|  |  |  |       private context: CompilerHost, private metadataProvider: MetadataProvider, | 
					
						
							|  |  |  |       private codeGenerator: CodeGenerator, | 
					
						
							| 
									
										
										
										
											2017-09-29 15:02:11 -07:00
										 |  |  |       private librarySummaries = new Map<string, LibrarySummary>()) { | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |     this.moduleResolutionCache = ts.createModuleResolutionCache( | 
					
						
							|  |  |  |         this.context.getCurrentDirectory !(), this.context.getCanonicalFileName.bind(this.context)); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     const basePath = this.options.basePath !; | 
					
						
							|  |  |  |     this.rootDirs = | 
					
						
							|  |  |  |         (this.options.rootDirs || [this.options.basePath !]).map(p => path.resolve(basePath, p)); | 
					
						
							|  |  |  |     if (context.getDirectories) { | 
					
						
							|  |  |  |       this.getDirectories = path => context.getDirectories !(path); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.directoryExists) { | 
					
						
							|  |  |  |       this.directoryExists = directoryName => context.directoryExists !(directoryName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.getCancellationToken) { | 
					
						
							|  |  |  |       this.getCancellationToken = () => context.getCancellationToken !(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.getDefaultLibLocation) { | 
					
						
							|  |  |  |       this.getDefaultLibLocation = () => context.getDefaultLibLocation !(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-08-20 12:58:33 -07:00
										 |  |  |     if (context.resolveTypeReferenceDirectives) { | 
					
						
							| 
									
										
										
										
											2018-08-28 13:36:16 -07:00
										 |  |  |       // Backward compatibility with TypeScript 2.9 and older since return
 | 
					
						
							|  |  |  |       // type has changed from (ts.ResolvedTypeReferenceDirective | undefined)[]
 | 
					
						
							|  |  |  |       // to ts.ResolvedTypeReferenceDirective[] in Typescript 3.0
 | 
					
						
							|  |  |  |       type ts3ResolveTypeReferenceDirectives = (names: string[], containingFile: string) => | 
					
						
							|  |  |  |           ts.ResolvedTypeReferenceDirective[]; | 
					
						
							| 
									
										
										
										
											2018-08-20 12:58:33 -07:00
										 |  |  |       this.resolveTypeReferenceDirectives = (names: string[], containingFile: string) => | 
					
						
							| 
									
										
										
										
											2018-08-28 13:36:16 -07:00
										 |  |  |           (context.resolveTypeReferenceDirectives as ts3ResolveTypeReferenceDirectives) !( | 
					
						
							|  |  |  |               names, containingFile); | 
					
						
							| 
									
										
										
										
											2018-08-20 12:58:33 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (context.trace) { | 
					
						
							|  |  |  |       this.trace = s => context.trace !(s); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.fileNameToModuleName) { | 
					
						
							|  |  |  |       this.fileNameToModuleName = context.fileNameToModuleName.bind(context); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Note: don't copy over context.moduleNameToFileName as we first
 | 
					
						
							|  |  |  |     // normalize undefined containingFile to a filled containingFile.
 | 
					
						
							|  |  |  |     if (context.resourceNameToFileName) { | 
					
						
							|  |  |  |       this.resourceNameToFileName = context.resourceNameToFileName.bind(context); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.toSummaryFileName) { | 
					
						
							|  |  |  |       this.toSummaryFileName = context.toSummaryFileName.bind(context); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (context.fromSummaryFileName) { | 
					
						
							|  |  |  |       this.fromSummaryFileName = context.fromSummaryFileName.bind(context); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     this.metadataReaderHost = { | 
					
						
							|  |  |  |       cacheMetadata: () => true, | 
					
						
							|  |  |  |       getSourceFileMetadata: (filePath) => { | 
					
						
							|  |  |  |         const sf = this.getOriginalSourceFile(filePath); | 
					
						
							|  |  |  |         return sf ? this.metadataProvider.getMetadata(sf) : undefined; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       fileExists: (filePath) => this.originalFileExists(filePath), | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  |       readFile: (filePath) => assert(this.context.readFile(filePath)), | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private resolveModuleName(moduleName: string, containingFile: string): ts.ResolvedModule | 
					
						
							|  |  |  |       |undefined { | 
					
						
							|  |  |  |     const rm = ts.resolveModuleName( | 
					
						
							| 
									
										
										
										
											2017-10-03 13:47:39 -07:00
										 |  |  |                      moduleName, containingFile.replace(/\\/g, '/'), this.options, this, | 
					
						
							|  |  |  |                      this.moduleResolutionCache) | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |                    .resolvedModule; | 
					
						
							| 
									
										
										
										
											2017-12-15 14:51:42 -08:00
										 |  |  |     if (rm && this.isSourceFile(rm.resolvedFileName) && DTS.test(rm.resolvedFileName)) { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       // Case: generateCodeForLibraries = true and moduleName is
 | 
					
						
							|  |  |  |       // a .d.ts file in a node_modules folder.
 | 
					
						
							|  |  |  |       // Need to set isExternalLibraryImport to false so that generated files for that file
 | 
					
						
							|  |  |  |       // are emitted.
 | 
					
						
							|  |  |  |       rm.isExternalLibraryImport = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return rm; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Note: We implement this method so that TypeScript and Angular share the same
 | 
					
						
							|  |  |  |   // ts.ModuleResolutionCache
 | 
					
						
							|  |  |  |   // and that we can tell ts.Program about our different opinion about
 | 
					
						
							|  |  |  |   // ResolvedModule.isExternalLibraryImport
 | 
					
						
							|  |  |  |   // (see our isSourceFile method).
 | 
					
						
							|  |  |  |   resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModule[] { | 
					
						
							|  |  |  |     // TODO(tbosch): this seems to be a typing error in TypeScript,
 | 
					
						
							|  |  |  |     // as it contains assertions that the result contains the same number of entries
 | 
					
						
							|  |  |  |     // as the given module names.
 | 
					
						
							|  |  |  |     return <ts.ResolvedModule[]>moduleNames.map( | 
					
						
							|  |  |  |         moduleName => this.resolveModuleName(moduleName, containingFile)); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   moduleNameToFileName(m: string, containingFile?: string): string|null { | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     if (!containingFile) { | 
					
						
							|  |  |  |       if (m.indexOf('.') === 0) { | 
					
						
							|  |  |  |         throw new Error('Resolution of relative paths requires a containing file.'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       // Any containing file gives the same result for absolute imports
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       containingFile = this.rootFiles[0]; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (this.context.moduleNameToFileName) { | 
					
						
							|  |  |  |       return this.context.moduleNameToFileName(m, containingFile); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const resolved = this.resolveModuleName(m, containingFile); | 
					
						
							|  |  |  |     return resolved ? resolved.resolvedFileName : null; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * We want a moduleId that will appear in import statements in the generated code | 
					
						
							|  |  |  |    * which will be written to `containingFile`. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Note that we also generate files for files in node_modules, as libraries | 
					
						
							|  |  |  |    * only ship .metadata.json files but not the generated code. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Logic: | 
					
						
							|  |  |  |    * 1. if the importedFile and the containingFile are from the project sources | 
					
						
							|  |  |  |    *    or from the same node_modules package, use a relative path | 
					
						
							|  |  |  |    * 2. if the importedFile is in a node_modules package, | 
					
						
							|  |  |  |    *    use a path that starts with the package name. | 
					
						
							|  |  |  |    * 3. Error if the containingFile is in the node_modules package | 
					
						
							|  |  |  |    *    and the importedFile is in the project soures, | 
					
						
							|  |  |  |    *    as that is a violation of the principle that node_modules packages cannot | 
					
						
							|  |  |  |    *    import project sources. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   fileNameToModuleName(importedFile: string, containingFile: string): string { | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |     const cacheKey = `${importedFile}:${containingFile}`; | 
					
						
							|  |  |  |     let moduleName = this.fileNameToModuleNameCache.get(cacheKey); | 
					
						
							|  |  |  |     if (moduleName != null) { | 
					
						
							|  |  |  |       return moduleName; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     const originalImportedFile = importedFile; | 
					
						
							|  |  |  |     if (this.options.traceResolution) { | 
					
						
							|  |  |  |       console.error( | 
					
						
							|  |  |  |           'fileNameToModuleName from containingFile', containingFile, 'to importedFile', | 
					
						
							|  |  |  |           importedFile); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     // drop extension
 | 
					
						
							|  |  |  |     importedFile = importedFile.replace(EXT, ''); | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |     const importedFilePackageName = getPackageName(importedFile); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     const containingFilePackageName = getPackageName(containingFile); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |     if (importedFilePackageName === containingFilePackageName || | 
					
						
							| 
									
										
										
										
											2017-10-30 11:54:40 -07:00
										 |  |  |         GENERATED_FILES.test(originalImportedFile)) { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       const rootedContainingFile = relativeToRootDirs(containingFile, this.rootDirs); | 
					
						
							|  |  |  |       const rootedImportedFile = relativeToRootDirs(importedFile, this.rootDirs); | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (rootedContainingFile !== containingFile && rootedImportedFile !== importedFile) { | 
					
						
							|  |  |  |         // if both files are contained in the `rootDirs`, then strip the rootDirs
 | 
					
						
							|  |  |  |         containingFile = rootedContainingFile; | 
					
						
							|  |  |  |         importedFile = rootedImportedFile; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       moduleName = dotRelative(path.dirname(containingFile), importedFile); | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |     } else if (importedFilePackageName) { | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |       moduleName = stripNodeModulesPrefix(importedFile); | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |       if (originalImportedFile.endsWith('.d.ts')) { | 
					
						
							|  |  |  |         // the moduleName for these typings could be shortented to the npm package name
 | 
					
						
							|  |  |  |         // if the npm package typings matches the importedFile
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           const modulePath = importedFile.substring(0, importedFile.length - moduleName.length) + | 
					
						
							|  |  |  |               importedFilePackageName; | 
					
						
							|  |  |  |           const packageJson = require(modulePath + '/package.json'); | 
					
						
							|  |  |  |           const packageTypings = path.posix.join(modulePath, packageJson.typings); | 
					
						
							|  |  |  |           if (packageTypings === originalImportedFile) { | 
					
						
							|  |  |  |             moduleName = importedFilePackageName; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-08-14 15:34:51 +02:00
										 |  |  |         } catch { | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  |           // the above require() will throw if there is no package.json file
 | 
					
						
							|  |  |  |           // and this is safe to ignore and correct to keep the longer
 | 
					
						
							|  |  |  |           // moduleName in this case
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |           `Trying to import a source file from a node_modules package: import ${originalImportedFile} from ${containingFile}`); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-04-06 11:08:19 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     this.fileNameToModuleNameCache.set(cacheKey, moduleName); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     return moduleName; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   resourceNameToFileName(resourceName: string, containingFile: string): string|null { | 
					
						
							|  |  |  |     // Note: we convert package paths into relative paths to be compatible with the the
 | 
					
						
							|  |  |  |     // previous implementation of UrlResolver.
 | 
					
						
							|  |  |  |     const firstChar = resourceName[0]; | 
					
						
							|  |  |  |     if (firstChar === '/') { | 
					
						
							|  |  |  |       resourceName = resourceName.slice(1); | 
					
						
							|  |  |  |     } else if (firstChar !== '.') { | 
					
						
							|  |  |  |       resourceName = `./${resourceName}`; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-01-15 13:35:28 -08:00
										 |  |  |     let filePathWithNgResource = | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         this.moduleNameToFileName(addNgResourceSuffix(resourceName), containingFile); | 
					
						
							| 
									
										
										
										
											2019-01-15 13:35:28 -08:00
										 |  |  |     // If the user specified styleUrl pointing to *.scss, but the Sass compiler was run before
 | 
					
						
							|  |  |  |     // Angular, then the resource may have been generated as *.css. Simply try the resolution again.
 | 
					
						
							|  |  |  |     if (!filePathWithNgResource && CSS_PREPROCESSOR_EXT.test(resourceName)) { | 
					
						
							|  |  |  |       const fallbackResourceName = resourceName.replace(CSS_PREPROCESSOR_EXT, '.css'); | 
					
						
							|  |  |  |       filePathWithNgResource = | 
					
						
							|  |  |  |           this.moduleNameToFileName(addNgResourceSuffix(fallbackResourceName), containingFile); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-08 08:36:18 -08:00
										 |  |  |     const result = filePathWithNgResource ? stripNgResourceSuffix(filePathWithNgResource) : null; | 
					
						
							|  |  |  |     // Used under Bazel to report more specific error with remediation advice
 | 
					
						
							|  |  |  |     if (!result && (this.context as any).reportMissingResource) { | 
					
						
							|  |  |  |       (this.context as any).reportMissingResource(resourceName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  |   toSummaryFileName(fileName: string, referringSrcFileName: string): string { | 
					
						
							|  |  |  |     return this.fileNameToModuleName(fileName, referringSrcFileName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fromSummaryFileName(fileName: string, referringLibFileName: string): string { | 
					
						
							|  |  |  |     const resolved = this.moduleNameToFileName(fileName, referringLibFileName); | 
					
						
							|  |  |  |     if (!resolved) { | 
					
						
							|  |  |  |       throw new Error(`Could not resolve ${fileName} from ${referringLibFileName}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return resolved; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   parseSourceSpanOf(fileName: string, line: number, character: number): ParseSourceSpan|null { | 
					
						
							|  |  |  |     const data = this.generatedSourceFiles.get(fileName); | 
					
						
							|  |  |  |     if (data && data.emitCtx) { | 
					
						
							|  |  |  |       return data.emitCtx.spanOf(line, character); | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     return null; | 
					
						
							| 
									
										
										
										
											2017-08-15 17:06:09 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   private getOriginalSourceFile( | 
					
						
							|  |  |  |       filePath: string, languageVersion?: ts.ScriptTarget, | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       onError?: ((message: string) => void)|undefined): ts.SourceFile|null { | 
					
						
							|  |  |  |     // Note: we need the explicit check via `has` as we also cache results
 | 
					
						
							|  |  |  |     // that were null / undefined.
 | 
					
						
							|  |  |  |     if (this.originalSourceFiles.has(filePath)) { | 
					
						
							|  |  |  |       return this.originalSourceFiles.get(filePath) !; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!languageVersion) { | 
					
						
							|  |  |  |       languageVersion = this.options.target || ts.ScriptTarget.Latest; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     // Note: This can also return undefined,
 | 
					
						
							|  |  |  |     // as the TS typings are not correct!
 | 
					
						
							|  |  |  |     const sf = this.context.getSourceFile(filePath, languageVersion, onError) || null; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     this.originalSourceFiles.set(filePath, sf); | 
					
						
							|  |  |  |     return sf; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   updateGeneratedFile(genFile: GeneratedFile): ts.SourceFile { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (!genFile.stmts) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       throw new Error( | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |           `Invalid Argument: Expected a GenerateFile with statements. ${genFile.genFileUrl}`); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |     const oldGenFile = this.generatedSourceFiles.get(genFile.genFileUrl); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (!oldGenFile) { | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |       throw new Error(`Illegal State: previous GeneratedFile not found for ${genFile.genFileUrl}.`); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     const newRefs = genFileExternalReferences(genFile); | 
					
						
							|  |  |  |     const oldRefs = oldGenFile.externalReferences; | 
					
						
							|  |  |  |     let refsAreEqual = oldRefs.size === newRefs.size; | 
					
						
							|  |  |  |     if (refsAreEqual) { | 
					
						
							|  |  |  |       newRefs.forEach(r => refsAreEqual = refsAreEqual && oldRefs.has(r)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!refsAreEqual) { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |           `Illegal State: external references changed in ${genFile.genFileUrl}.\nOld: ${Array.from(oldRefs)}.\nNew: ${Array.from(newRefs)}`); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     return this.addGeneratedFile(genFile, newRefs); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   private addGeneratedFile(genFile: GeneratedFile, externalReferences: Set<string>): ts.SourceFile { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     if (!genFile.stmts) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       throw new Error( | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |           `Invalid Argument: Expected a GenerateFile with statements. ${genFile.genFileUrl}`); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     const {sourceText, context} = this.emitter.emitStatementsAndContext( | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |         genFile.genFileUrl, genFile.stmts, /* preamble */ '', | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |         /* emitSourceMaps */ false); | 
					
						
							|  |  |  |     const sf = ts.createSourceFile( | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |         genFile.genFileUrl, sourceText, this.options.target || ts.ScriptTarget.Latest); | 
					
						
							| 
									
										
										
										
											2019-03-18 09:52:50 -07:00
										 |  |  |     if (this.options.module === ts.ModuleKind.AMD || this.options.module === ts.ModuleKind.UMD) { | 
					
						
							|  |  |  |       if (this.context.amdModuleName) { | 
					
						
							|  |  |  |         const moduleName = this.context.amdModuleName(sf); | 
					
						
							|  |  |  |         if (moduleName) sf.moduleName = moduleName; | 
					
						
							|  |  |  |       } else if (/node_modules/.test(genFile.genFileUrl)) { | 
					
						
							|  |  |  |         // If we are generating an ngModule file under node_modules, we know the right module name
 | 
					
						
							|  |  |  |         // We don't need the host to supply a function in this case.
 | 
					
						
							|  |  |  |         sf.moduleName = stripNodeModulesPrefix(genFile.genFileUrl.replace(EXT, '')); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-11-14 11:29:16 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-12 16:09:49 -07:00
										 |  |  |     this.generatedSourceFiles.set(genFile.genFileUrl, { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       sourceFile: sf, | 
					
						
							|  |  |  |       emitCtx: context, externalReferences, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return sf; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   shouldGenerateFile(fileName: string): {generate: boolean, baseFileName?: string} { | 
					
						
							|  |  |  |     // TODO(tbosch): allow generating files that are not in the rootDir
 | 
					
						
							|  |  |  |     // See https://github.com/angular/angular/issues/19337
 | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |     if (!isInRootDir(fileName, this.options)) { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       return {generate: false}; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const genMatch = GENERATED_FILES.exec(fileName); | 
					
						
							|  |  |  |     if (!genMatch) { | 
					
						
							|  |  |  |       return {generate: false}; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const [, base, genSuffix, suffix] = genMatch; | 
					
						
							| 
									
										
										
										
											2017-11-29 15:27:16 +08:00
										 |  |  |     if (suffix !== 'ts' && suffix !== 'tsx') { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       return {generate: false}; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     let baseFileName: string|undefined; | 
					
						
							|  |  |  |     if (genSuffix.indexOf('ngstyle') >= 0) { | 
					
						
							|  |  |  |       // Note: ngstyle files have names like `afile.css.ngstyle.ts`
 | 
					
						
							|  |  |  |       if (!this.originalFileExists(base)) { | 
					
						
							|  |  |  |         return {generate: false}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       // Note: on-the-fly generated files always have a `.ts` suffix,
 | 
					
						
							| 
									
										
										
										
											2017-11-29 15:27:16 +08:00
										 |  |  |       // but the file from which we generated it can be a `.ts`/ `.tsx`/ `.d.ts`
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |       // (see options.generateCodeForLibraries).
 | 
					
						
							| 
									
										
										
										
											2017-11-29 15:27:16 +08:00
										 |  |  |       baseFileName = [`${base}.ts`, `${base}.tsx`, `${base}.d.ts`].find( | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |           baseFileName => this.isSourceFile(baseFileName) && this.originalFileExists(baseFileName)); | 
					
						
							|  |  |  |       if (!baseFileName) { | 
					
						
							|  |  |  |         return {generate: false}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return {generate: true, baseFileName}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   shouldGenerateFilesFor(fileName: string) { | 
					
						
							|  |  |  |     // TODO(tbosch): allow generating files that are not in the rootDir
 | 
					
						
							|  |  |  |     // See https://github.com/angular/angular/issues/19337
 | 
					
						
							|  |  |  |     return !GENERATED_FILES.test(fileName) && this.isSourceFile(fileName) && | 
					
						
							| 
									
										
										
										
											2017-10-17 16:51:04 -07:00
										 |  |  |         isInRootDir(fileName, this.options); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getSourceFile( | 
					
						
							|  |  |  |       fileName: string, languageVersion: ts.ScriptTarget, | 
					
						
							|  |  |  |       onError?: ((message: string) => void)|undefined): ts.SourceFile { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     // Note: Don't exit early in this method to make sure
 | 
					
						
							|  |  |  |     // we always have up to date references on the file!
 | 
					
						
							|  |  |  |     let genFileNames: string[] = []; | 
					
						
							|  |  |  |     let sf = this.getGeneratedFile(fileName); | 
					
						
							|  |  |  |     if (!sf) { | 
					
						
							|  |  |  |       const summary = this.librarySummaries.get(fileName); | 
					
						
							|  |  |  |       if (summary) { | 
					
						
							|  |  |  |         if (!summary.sourceFile) { | 
					
						
							|  |  |  |           summary.sourceFile = ts.createSourceFile( | 
					
						
							|  |  |  |               fileName, summary.text, this.options.target || ts.ScriptTarget.Latest); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         sf = summary.sourceFile; | 
					
						
							|  |  |  |         genFileNames = []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!sf) { | 
					
						
							|  |  |  |       sf = this.getOriginalSourceFile(fileName); | 
					
						
							|  |  |  |       const cachedGenFiles = this.generatedCodeFor.get(fileName); | 
					
						
							|  |  |  |       if (cachedGenFiles) { | 
					
						
							|  |  |  |         genFileNames = cachedGenFiles; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (!this.options.noResolve && this.shouldGenerateFilesFor(fileName)) { | 
					
						
							| 
									
										
										
										
											2017-10-17 16:10:15 -07:00
										 |  |  |           genFileNames = this.codeGenerator.findGeneratedFileNames(fileName).filter( | 
					
						
							|  |  |  |               fileName => this.shouldGenerateFile(fileName).generate); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |         this.generatedCodeFor.set(fileName, genFileNames); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (sf) { | 
					
						
							|  |  |  |       addReferencesToSourceFile(sf, genFileNames); | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     // TODO(tbosch): TypeScript's typings for getSourceFile are incorrect,
 | 
					
						
							|  |  |  |     // as it can very well return undefined.
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     return sf !; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private getGeneratedFile(fileName: string): ts.SourceFile|null { | 
					
						
							|  |  |  |     const genSrcFile = this.generatedSourceFiles.get(fileName); | 
					
						
							|  |  |  |     if (genSrcFile) { | 
					
						
							|  |  |  |       return genSrcFile.sourceFile; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const {generate, baseFileName} = this.shouldGenerateFile(fileName); | 
					
						
							|  |  |  |     if (generate) { | 
					
						
							|  |  |  |       const genFile = this.codeGenerator.generateFile(fileName, baseFileName); | 
					
						
							|  |  |  |       return this.addGeneratedFile(genFile, genFileExternalReferences(genFile)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return null; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-20 16:31:32 -07:00
										 |  |  |   private originalFileExists(fileName: string): boolean { | 
					
						
							|  |  |  |     let fileExists = this.originalFileExistsCache.get(fileName); | 
					
						
							|  |  |  |     if (fileExists == null) { | 
					
						
							|  |  |  |       fileExists = this.context.fileExists(fileName); | 
					
						
							|  |  |  |       this.originalFileExistsCache.set(fileName, fileExists); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return fileExists; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   fileExists(fileName: string): boolean { | 
					
						
							|  |  |  |     fileName = stripNgResourceSuffix(fileName); | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     if (this.librarySummaries.has(fileName) || this.generatedSourceFiles.has(fileName)) { | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     if (this.shouldGenerateFile(fileName).generate) { | 
					
						
							|  |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     return this.originalFileExists(fileName); | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   loadSummary(filePath: string): string|null { | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     const summary = this.librarySummaries.get(filePath); | 
					
						
							|  |  |  |     if (summary) { | 
					
						
							|  |  |  |       return summary.text; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     if (this.originalFileExists(filePath)) { | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  |       return assert(this.context.readFile(filePath)); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     return null; | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isSourceFile(filePath: string): boolean { | 
					
						
							| 
									
										
										
										
											2017-10-24 11:26:04 -07:00
										 |  |  |     // Don't generate any files nor typecheck them
 | 
					
						
							|  |  |  |     // if skipTemplateCodegen is set and fullTemplateTypeCheck is not yet set,
 | 
					
						
							|  |  |  |     // for backwards compatibility.
 | 
					
						
							|  |  |  |     if (this.options.skipTemplateCodegen && !this.options.fullTemplateTypeCheck) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |     // If we have a summary from a previous compilation,
 | 
					
						
							|  |  |  |     // treat the file never as a source file.
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |     if (this.librarySummaries.has(filePath)) { | 
					
						
							| 
									
										
										
										
											2017-09-19 11:43:34 -07:00
										 |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |     if (GENERATED_FILES.test(filePath)) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (this.options.generateCodeForLibraries === false && DTS.test(filePath)) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (DTS.test(filePath)) { | 
					
						
							|  |  |  |       // Check for a bundle index.
 | 
					
						
							|  |  |  |       if (this.hasBundleIndex(filePath)) { | 
					
						
							|  |  |  |         const normalFilePath = path.normalize(filePath); | 
					
						
							|  |  |  |         return this.flatModuleIndexNames.has(normalFilePath) || | 
					
						
							|  |  |  |             this.flatModuleIndexRedirectNames.has(normalFilePath); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 18:05:07 -07:00
										 |  |  |   readFile(fileName: string) { | 
					
						
							|  |  |  |     const summary = this.librarySummaries.get(fileName); | 
					
						
							|  |  |  |     if (summary) { | 
					
						
							|  |  |  |       return summary.text; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this.context.readFile(fileName); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   getMetadataFor(filePath: string): ModuleMetadata[]|undefined { | 
					
						
							|  |  |  |     return readMetadata(filePath, this.metadataReaderHost, this.metadataReaderCache); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   loadResource(filePath: string): Promise<string>|string { | 
					
						
							|  |  |  |     if (this.context.readResource) return this.context.readResource(filePath); | 
					
						
							|  |  |  |     if (!this.originalFileExists(filePath)) { | 
					
						
							|  |  |  |       throw syntaxError(`Error: Resource file not found: ${filePath}`); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  |     return assert(this.context.readFile(filePath)); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 09:55:03 -08:00
										 |  |  |   getOutputName(filePath: string): string { | 
					
						
							|  |  |  |     return path.relative(this.getCurrentDirectory(), filePath); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |   private hasBundleIndex(filePath: string): boolean { | 
					
						
							|  |  |  |     const checkBundleIndex = (directory: string): boolean => { | 
					
						
							|  |  |  |       let result = this.flatModuleIndexCache.get(directory); | 
					
						
							|  |  |  |       if (result == null) { | 
					
						
							|  |  |  |         if (path.basename(directory) == 'node_module') { | 
					
						
							|  |  |  |           // Don't look outside the node_modules this package is installed in.
 | 
					
						
							|  |  |  |           result = false; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           // A bundle index exists if the typings .d.ts file has a metadata.json that has an
 | 
					
						
							|  |  |  |           // importAs.
 | 
					
						
							|  |  |  |           try { | 
					
						
							|  |  |  |             const packageFile = path.join(directory, 'package.json'); | 
					
						
							|  |  |  |             if (this.originalFileExists(packageFile)) { | 
					
						
							|  |  |  |               // Once we see a package.json file, assume false until it we find the bundle index.
 | 
					
						
							|  |  |  |               result = false; | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  |               const packageContent: any = JSON.parse(assert(this.context.readFile(packageFile))); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |               if (packageContent.typings) { | 
					
						
							|  |  |  |                 const typings = path.normalize(path.join(directory, packageContent.typings)); | 
					
						
							|  |  |  |                 if (DTS.test(typings)) { | 
					
						
							|  |  |  |                   const metadataFile = typings.replace(DTS, '.metadata.json'); | 
					
						
							|  |  |  |                   if (this.originalFileExists(metadataFile)) { | 
					
						
							| 
									
										
										
										
											2017-11-02 12:15:47 -07:00
										 |  |  |                     const metadata = JSON.parse(assert(this.context.readFile(metadataFile))); | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |                     if (metadata.flatModuleIndexRedirect) { | 
					
						
							|  |  |  |                       this.flatModuleIndexRedirectNames.add(typings); | 
					
						
							|  |  |  |                       // Note: don't set result = true,
 | 
					
						
							|  |  |  |                       // as this would mark this folder
 | 
					
						
							|  |  |  |                       // as having a bundleIndex too early without
 | 
					
						
							|  |  |  |                       // filling the bundleIndexNames.
 | 
					
						
							|  |  |  |                     } else if (metadata.importAs) { | 
					
						
							|  |  |  |                       this.flatModuleIndexNames.add(typings); | 
					
						
							|  |  |  |                       result = true; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                   } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |               const parent = path.dirname(directory); | 
					
						
							|  |  |  |               if (parent != directory) { | 
					
						
							|  |  |  |                 // Try the parent directory.
 | 
					
						
							|  |  |  |                 result = checkBundleIndex(parent); | 
					
						
							|  |  |  |               } else { | 
					
						
							|  |  |  |                 result = false; | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2018-08-14 15:34:51 +02:00
										 |  |  |           } catch { | 
					
						
							| 
									
										
										
										
											2017-10-20 09:46:41 -07:00
										 |  |  |             // If we encounter any errors assume we this isn't a bundle index.
 | 
					
						
							|  |  |  |             result = false; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this.flatModuleIndexCache.set(directory, result); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return result; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return checkBundleIndex(path.dirname(filePath)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   getDefaultLibFileName = (options: ts.CompilerOptions) => | 
					
						
							| 
									
										
										
										
											2017-09-22 19:51:03 +02:00
										 |  |  |       this.context.getDefaultLibFileName(options) | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   getCurrentDirectory = () => this.context.getCurrentDirectory(); | 
					
						
							|  |  |  |   getCanonicalFileName = (fileName: string) => this.context.getCanonicalFileName(fileName); | 
					
						
							|  |  |  |   useCaseSensitiveFileNames = () => this.context.useCaseSensitiveFileNames(); | 
					
						
							|  |  |  |   getNewLine = () => this.context.getNewLine(); | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  |   // Make sure we do not `host.realpath()` from TS as we do not want to resolve symlinks.
 | 
					
						
							|  |  |  |   // https://github.com/Microsoft/TypeScript/issues/9552
 | 
					
						
							| 
									
										
										
										
											2018-07-22 09:30:25 +02:00
										 |  |  |   realpath = (p: string) => p; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   writeFile = this.context.writeFile.bind(this.context); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  | function genFileExternalReferences(genFile: GeneratedFile): Set<string> { | 
					
						
							|  |  |  |   return new Set(collectExternalReferences(genFile.stmts !).map(er => er.moduleName !)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function addReferencesToSourceFile(sf: ts.SourceFile, genFileNames: string[]) { | 
					
						
							|  |  |  |   // Note: as we modify ts.SourceFiles we need to keep the original
 | 
					
						
							|  |  |  |   // value for `referencedFiles` around in cache the original host is caching ts.SourceFiles.
 | 
					
						
							|  |  |  |   // Note: cloning the ts.SourceFile is expensive as the nodes in have parent pointers,
 | 
					
						
							|  |  |  |   // i.e. we would also need to clone and adjust all nodes.
 | 
					
						
							| 
									
										
										
										
											2017-12-22 09:36:47 -08:00
										 |  |  |   let originalReferencedFiles: ReadonlyArray<ts.FileReference> = | 
					
						
							|  |  |  |       (sf as any).originalReferencedFiles; | 
					
						
							| 
									
										
										
										
											2017-09-12 09:40:28 -07:00
										 |  |  |   if (!originalReferencedFiles) { | 
					
						
							|  |  |  |     originalReferencedFiles = sf.referencedFiles; | 
					
						
							|  |  |  |     (sf as any).originalReferencedFiles = originalReferencedFiles; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   const newReferencedFiles = [...originalReferencedFiles]; | 
					
						
							|  |  |  |   genFileNames.forEach(gf => newReferencedFiles.push({fileName: gf, pos: 0, end: 0})); | 
					
						
							|  |  |  |   sf.referencedFiles = newReferencedFiles; | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-20 09:54:47 -07:00
										 |  |  | export function getOriginalReferences(sourceFile: ts.SourceFile): ts.FileReference[]|undefined { | 
					
						
							|  |  |  |   return sourceFile && (sourceFile as any).originalReferencedFiles; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-14 11:04:55 -07:00
										 |  |  | function dotRelative(from: string, to: string): string { | 
					
						
							|  |  |  |   const rPath: string = path.relative(from, to).replace(/\\/g, '/'); | 
					
						
							|  |  |  |   return rPath.startsWith('.') ? rPath : './' + rPath; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Moves the path into `genDir` folder while preserving the `node_modules` directory. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function getPackageName(filePath: string): string|null { | 
					
						
							|  |  |  |   const match = NODE_MODULES_PACKAGE_NAME.exec(filePath); | 
					
						
							|  |  |  |   return match ? match[1] : null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function stripNodeModulesPrefix(filePath: string): string { | 
					
						
							|  |  |  |   return filePath.replace(/.*node_modules\//, ''); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 14:41:48 -07:00
										 |  |  | function getNodeModulesPrefix(filePath: string): string|null { | 
					
						
							|  |  |  |   const match = /.*node_modules\//.exec(filePath); | 
					
						
							|  |  |  |   return match ? match[1] : null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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$`; | 
					
						
							|  |  |  | } |