refactor(compiler): move symbol extraction to AotCompiler
				
					
				
			This commit is contained in:
		
							parent
							
								
									2235048432
								
							
						
					
					
						commit
						b15039d228
					
				| @ -62,11 +62,11 @@ export class CodeGenerator { | ||||
|     return path.join(this.options.genDir, relativePath); | ||||
|   } | ||||
| 
 | ||||
|   codegen(options: {transitiveModules: boolean}): Promise<any> { | ||||
|     const staticSymbols = | ||||
|         extractProgramSymbols(this.program, this.staticReflector, this.ngHost, this.options); | ||||
| 
 | ||||
|     return this.compiler.compileModules(staticSymbols, options).then(generatedModules => { | ||||
|   codegen(): Promise<any> { | ||||
|     return this.compiler | ||||
|         .compileAll( | ||||
|             this.program.getSourceFiles().map(sf => this.ngHost.getCanonicalFileName(sf.fileName))) | ||||
|         .then(generatedModules => { | ||||
|           generatedModules.forEach(generatedModule => { | ||||
|             const sourceFile = this.program.getSourceFile(generatedModule.fileUrl); | ||||
|             const emitPath = this.calculateEmitPath(generatedModule.moduleUrl); | ||||
| @ -78,7 +78,14 @@ export class CodeGenerator { | ||||
| 
 | ||||
|   static create( | ||||
|       options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program, | ||||
|       compilerHost: ts.CompilerHost, ngHost?: NgHost): CodeGenerator { | ||||
|       compilerHost: ts.CompilerHost, ngHostContext?: NgHostContext, | ||||
|       ngHost?: NgHost): CodeGenerator { | ||||
|     if (!ngHost) { | ||||
|       const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0; | ||||
|       ngHost = usePathMapping ? | ||||
|           new PathMappedNgHost(program, compilerHost, options, ngHostContext) : | ||||
|           new NgHost(program, compilerHost, options, ngHostContext); | ||||
|     } | ||||
|     const transFile = cliOptions.i18nFile; | ||||
|     const locale = cliOptions.locale; | ||||
|     let transContent: string = ''; | ||||
| @ -93,7 +100,9 @@ export class CodeGenerator { | ||||
|       debug: options.debug === true, | ||||
|       translations: transContent, | ||||
|       i18nFormat: cliOptions.i18nFormat, | ||||
|       locale: cliOptions.locale | ||||
|       locale: cliOptions.locale, | ||||
|       excludeFilePattern: options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : | ||||
|                                                                        GENERATED_FILES | ||||
|     }); | ||||
|     return new CodeGenerator(options, program, compilerHost, reflector, aotCompiler, ngHost); | ||||
|   } | ||||
| @ -102,37 +111,10 @@ export class CodeGenerator { | ||||
| export function extractProgramSymbols( | ||||
|     program: ts.Program, staticReflector: compiler.StaticReflector, ngHost: NgHost, | ||||
|     options: AngularCompilerOptions): compiler.StaticSymbol[] { | ||||
|   // Compare with false since the default should be true
 | ||||
|   const skipFileNames = | ||||
|       options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES; | ||||
| 
 | ||||
|   const staticSymbols: compiler.StaticSymbol[] = []; | ||||
| 
 | ||||
|   program.getSourceFiles() | ||||
|       .filter(sourceFile => !skipFileNames.test(sourceFile.fileName)) | ||||
|       .forEach(sourceFile => { | ||||
|         const absSrcPath = ngHost.getCanonicalFileName(sourceFile.fileName); | ||||
| 
 | ||||
|         const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath); | ||||
|         if (!moduleMetadata) { | ||||
|           console.log(`WARNING: no metadata found for ${absSrcPath}`); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         const metadata = moduleMetadata['metadata']; | ||||
| 
 | ||||
|         if (!metadata) { | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         for (const symbol of Object.keys(metadata)) { | ||||
|           if (metadata[symbol] && metadata[symbol].__symbolic == 'error') { | ||||
|             // Ignore symbols that are only included to record error information.
 | ||||
|             continue; | ||||
|           } | ||||
|           staticSymbols.push(staticReflector.findDeclaration(absSrcPath, symbol, absSrcPath)); | ||||
|         } | ||||
|   return compiler.extractProgramSymbols( | ||||
|       staticReflector, program.getSourceFiles().map(sf => ngHost.getCanonicalFileName(sf.fileName)), | ||||
|       { | ||||
|         excludeFilePattern: options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : | ||||
|                                                                          GENERATED_FILES | ||||
|       }); | ||||
| 
 | ||||
|   return staticSymbols; | ||||
| } | ||||
|  | ||||
| @ -19,9 +19,7 @@ import {CodeGenerator} from './codegen'; | ||||
| function codegen( | ||||
|     ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program, | ||||
|     host: ts.CompilerHost) { | ||||
|   return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen({ | ||||
|     transitiveModules: true | ||||
|   }); | ||||
|   return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen(); | ||||
| } | ||||
| 
 | ||||
| // CLI entry point
 | ||||
|  | ||||
| @ -23,100 +23,14 @@ import {CompiledStylesheet, StyleCompiler} from '../style_compiler'; | ||||
| import {TemplateParser} from '../template_parser/template_parser'; | ||||
| import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler'; | ||||
| 
 | ||||
| import {AotCompilerOptions} from './compiler_options'; | ||||
| import {StaticReflector} from './static_reflector'; | ||||
| import {StaticSymbol} from './static_symbol'; | ||||
| 
 | ||||
| export class SourceModule { | ||||
|   constructor(public fileUrl: string, public moduleUrl: string, public source: string) {} | ||||
| } | ||||
| 
 | ||||
| export interface NgAnalyzedModules { | ||||
|   ngModules: CompileNgModuleMetadata[]; | ||||
|   ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>; | ||||
|   files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>; | ||||
|   symbolsMissingModule?: StaticSymbol[]; | ||||
| } | ||||
| 
 | ||||
| // Returns all the source files and a mapping from modules to directives
 | ||||
| export function analyzeNgModules( | ||||
|     programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean}, | ||||
|     metadataResolver: CompileMetadataResolver): NgAnalyzedModules { | ||||
|   const {ngModules, symbolsMissingModule} = | ||||
|       _createNgModules(programStaticSymbols, options, metadataResolver); | ||||
|   return _analyzeNgModules(ngModules, symbolsMissingModule); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| export function analyzeAndValidateNgModules( | ||||
|     programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean}, | ||||
|     metadataResolver: CompileMetadataResolver): NgAnalyzedModules { | ||||
|   const result = analyzeNgModules(programStaticSymbols, options, metadataResolver); | ||||
|   if (result.symbolsMissingModule && result.symbolsMissingModule.length) { | ||||
|     const messages = result.symbolsMissingModule.map( | ||||
|         s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`); | ||||
|     throw new Error(messages.join('\n')); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| // Wait for the directives in the given modules have been loaded
 | ||||
| export function loadNgModuleDirectives(ngModules: CompileNgModuleMetadata[]) { | ||||
|   return Promise | ||||
|       .all(ListWrapper.flatten(ngModules.map( | ||||
|           (ngModule) => ngModule.transitiveModule.directiveLoaders.map(loader => loader())))) | ||||
|       .then(() => {}); | ||||
| } | ||||
| 
 | ||||
| function _analyzeNgModules( | ||||
|     ngModuleMetas: CompileNgModuleMetadata[], | ||||
|     symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules { | ||||
|   const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>(); | ||||
|   ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule)); | ||||
|   const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>(); | ||||
|   const ngModulesByFile = new Map<string, StaticSymbol[]>(); | ||||
|   const ngDirectivesByFile = new Map<string, StaticSymbol[]>(); | ||||
|   const filePaths = new Set<string>(); | ||||
| 
 | ||||
|   // Looping over all modules to construct:
 | ||||
|   // - a map from file to modules `ngModulesByFile`,
 | ||||
|   // - a map from file to directives `ngDirectivesByFile`,
 | ||||
|   // - a map from directive/pipe to module `ngModuleByPipeOrDirective`.
 | ||||
|   ngModuleMetas.forEach((ngModuleMeta) => { | ||||
|     const srcFileUrl = ngModuleMeta.type.reference.filePath; | ||||
|     filePaths.add(srcFileUrl); | ||||
|     ngModulesByFile.set( | ||||
|         srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference)); | ||||
| 
 | ||||
|     ngModuleMeta.declaredDirectives.forEach((dirIdentifier) => { | ||||
|       const fileUrl = dirIdentifier.reference.filePath; | ||||
|       filePaths.add(fileUrl); | ||||
|       ngDirectivesByFile.set( | ||||
|           fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirIdentifier.reference)); | ||||
|       ngModuleByPipeOrDirective.set(dirIdentifier.reference, ngModuleMeta); | ||||
|     }); | ||||
|     ngModuleMeta.declaredPipes.forEach((pipeIdentifier) => { | ||||
|       const fileUrl = pipeIdentifier.reference.filePath; | ||||
|       filePaths.add(fileUrl); | ||||
|       ngModuleByPipeOrDirective.set(pipeIdentifier.reference, ngModuleMeta); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = []; | ||||
| 
 | ||||
|   filePaths.forEach((srcUrl) => { | ||||
|     const directives = ngDirectivesByFile.get(srcUrl) || []; | ||||
|     const ngModules = ngModulesByFile.get(srcUrl) || []; | ||||
|     files.push({srcUrl, directives, ngModules}); | ||||
|   }); | ||||
| 
 | ||||
|   return { | ||||
|     // map directive/pipe to module
 | ||||
|     ngModuleByPipeOrDirective, | ||||
|     // list modules and directives for every source file
 | ||||
|     files, | ||||
|     ngModules: ngModuleMetas, symbolsMissingModule | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export class AotCompiler { | ||||
|   private _animationCompiler = new AnimationCompiler(); | ||||
| 
 | ||||
| @ -126,14 +40,20 @@ export class AotCompiler { | ||||
|       private _dirWrapperCompiler: DirectiveWrapperCompiler, | ||||
|       private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter, | ||||
|       private _localeId: string, private _translationFormat: string, | ||||
|       private _animationParser: AnimationParser) {} | ||||
|       private _animationParser: AnimationParser, private _staticReflector: StaticReflector, | ||||
|       private _options: AotCompilerOptions) {} | ||||
| 
 | ||||
|   clearCache() { this._metadataResolver.clearCache(); } | ||||
| 
 | ||||
|   compileModules(staticSymbols: StaticSymbol[], options: {transitiveModules: boolean}): | ||||
|       Promise<SourceModule[]> { | ||||
|   compileAll(rootFiles: string[]): Promise<SourceModule[]> { | ||||
|     const options = { | ||||
|       transitiveModules: true, | ||||
|       excludeFilePattern: this._options.excludeFilePattern, | ||||
|       includeFilePattern: this._options.includeFilePattern | ||||
|     }; | ||||
|     const programSymbols = extractProgramSymbols(this._staticReflector, rootFiles, options); | ||||
|     const {ngModuleByPipeOrDirective, files, ngModules} = | ||||
|         analyzeAndValidateNgModules(staticSymbols, options, this._metadataResolver); | ||||
|         analyzeAndValidateNgModules(programSymbols, options, this._metadataResolver); | ||||
|     return loadNgModuleDirectives(ngModules).then(() => { | ||||
|       const sourceModules = files.map( | ||||
|           file => this._compileSrcFile( | ||||
| @ -358,11 +278,133 @@ function _splitTypescriptSuffix(path: string): string[] { | ||||
|   return [path, '']; | ||||
| } | ||||
| 
 | ||||
| export interface NgAnalyzedModules { | ||||
|   ngModules: CompileNgModuleMetadata[]; | ||||
|   ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>; | ||||
|   files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>; | ||||
|   symbolsMissingModule?: StaticSymbol[]; | ||||
| } | ||||
| 
 | ||||
| // Returns all the source files and a mapping from modules to directives
 | ||||
| export function analyzeNgModules( | ||||
|     programStaticSymbols: StaticSymbol[], | ||||
|     options: {transitiveModules: boolean, includeFilePattern?: RegExp, excludeFilePattern?: RegExp}, | ||||
|     metadataResolver: CompileMetadataResolver): NgAnalyzedModules { | ||||
|   const {ngModules, symbolsMissingModule} = | ||||
|       _createNgModules(programStaticSymbols, options, metadataResolver); | ||||
|   return _analyzeNgModules(ngModules, symbolsMissingModule); | ||||
| } | ||||
| 
 | ||||
| export function analyzeAndValidateNgModules( | ||||
|     programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean}, | ||||
|     metadataResolver: CompileMetadataResolver): NgAnalyzedModules { | ||||
|   const result = analyzeNgModules(programStaticSymbols, options, metadataResolver); | ||||
|   if (result.symbolsMissingModule && result.symbolsMissingModule.length) { | ||||
|     const messages = result.symbolsMissingModule.map( | ||||
|         s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`); | ||||
|     throw new Error(messages.join('\n')); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| // Wait for the directives in the given modules have been loaded
 | ||||
| export function loadNgModuleDirectives(ngModules: CompileNgModuleMetadata[]) { | ||||
|   return Promise | ||||
|       .all(ListWrapper.flatten(ngModules.map( | ||||
|           (ngModule) => ngModule.transitiveModule.directiveLoaders.map(loader => loader())))) | ||||
|       .then(() => {}); | ||||
| } | ||||
| 
 | ||||
| function _analyzeNgModules( | ||||
|     ngModuleMetas: CompileNgModuleMetadata[], | ||||
|     symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules { | ||||
|   const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>(); | ||||
|   ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule)); | ||||
|   const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>(); | ||||
|   const ngModulesByFile = new Map<string, StaticSymbol[]>(); | ||||
|   const ngDirectivesByFile = new Map<string, StaticSymbol[]>(); | ||||
|   const filePaths = new Set<string>(); | ||||
| 
 | ||||
|   // Looping over all modules to construct:
 | ||||
|   // - a map from file to modules `ngModulesByFile`,
 | ||||
|   // - a map from file to directives `ngDirectivesByFile`,
 | ||||
|   // - a map from directive/pipe to module `ngModuleByPipeOrDirective`.
 | ||||
|   ngModuleMetas.forEach((ngModuleMeta) => { | ||||
|     const srcFileUrl = ngModuleMeta.type.reference.filePath; | ||||
|     filePaths.add(srcFileUrl); | ||||
|     ngModulesByFile.set( | ||||
|         srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference)); | ||||
| 
 | ||||
|     ngModuleMeta.declaredDirectives.forEach((dirIdentifier) => { | ||||
|       const fileUrl = dirIdentifier.reference.filePath; | ||||
|       filePaths.add(fileUrl); | ||||
|       ngDirectivesByFile.set( | ||||
|           fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirIdentifier.reference)); | ||||
|       ngModuleByPipeOrDirective.set(dirIdentifier.reference, ngModuleMeta); | ||||
|     }); | ||||
|     ngModuleMeta.declaredPipes.forEach((pipeIdentifier) => { | ||||
|       const fileUrl = pipeIdentifier.reference.filePath; | ||||
|       filePaths.add(fileUrl); | ||||
|       ngModuleByPipeOrDirective.set(pipeIdentifier.reference, ngModuleMeta); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = []; | ||||
| 
 | ||||
|   filePaths.forEach((srcUrl) => { | ||||
|     const directives = ngDirectivesByFile.get(srcUrl) || []; | ||||
|     const ngModules = ngModulesByFile.get(srcUrl) || []; | ||||
|     files.push({srcUrl, directives, ngModules}); | ||||
|   }); | ||||
| 
 | ||||
|   return { | ||||
|     // map directive/pipe to module
 | ||||
|     ngModuleByPipeOrDirective, | ||||
|     // list modules and directives for every source file
 | ||||
|     files, | ||||
|     ngModules: ngModuleMetas, symbolsMissingModule | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function extractProgramSymbols( | ||||
|     staticReflector: StaticReflector, files: string[], | ||||
|     options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp} = {}): StaticSymbol[] { | ||||
|   const staticSymbols: StaticSymbol[] = []; | ||||
|   files | ||||
|       .filter( | ||||
|           fileName => _filterFileByPatterns( | ||||
|               fileName, options.includeFilePattern, options.includeFilePattern)) | ||||
|       .forEach(sourceFile => { | ||||
|         const moduleMetadata = staticReflector.getModuleMetadata(sourceFile); | ||||
|         if (!moduleMetadata) { | ||||
|           console.log(`WARNING: no metadata found for ${sourceFile}`); | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         const metadata = moduleMetadata['metadata']; | ||||
| 
 | ||||
|         if (!metadata) { | ||||
|           return; | ||||
|         } | ||||
| 
 | ||||
|         for (const symbol of Object.keys(metadata)) { | ||||
|           if (metadata[symbol] && metadata[symbol].__symbolic == 'error') { | ||||
|             // Ignore symbols that are only included to record error information.
 | ||||
|             continue; | ||||
|           } | ||||
|           staticSymbols.push(staticReflector.findDeclaration(sourceFile, symbol, sourceFile)); | ||||
|         } | ||||
|       }); | ||||
| 
 | ||||
|   return staticSymbols; | ||||
| } | ||||
| 
 | ||||
| // Load the NgModules and check
 | ||||
| // that all directives / pipes that are present in the program
 | ||||
| // are also declared by a module.
 | ||||
| function _createNgModules( | ||||
|     programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean}, | ||||
|     programStaticSymbols: StaticSymbol[], | ||||
|     options: {transitiveModules: boolean, includeFilePattern?: RegExp, excludeFilePattern?: RegExp}, | ||||
|     metadataResolver: CompileMetadataResolver): | ||||
|     {ngModules: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]} { | ||||
|   const ngModules = new Map<any, CompileNgModuleMetadata>(); | ||||
| @ -370,7 +412,9 @@ function _createNgModules( | ||||
|   const ngModulePipesAndDirective = new Set<StaticSymbol>(); | ||||
| 
 | ||||
|   const addNgModule = (staticSymbol: any) => { | ||||
|     if (ngModules.has(staticSymbol)) { | ||||
|     if (ngModules.has(staticSymbol) || | ||||
|         !_filterFileByPatterns( | ||||
|             staticSymbol.filePath, options.includeFilePattern, options.excludeFilePattern)) { | ||||
|       return false; | ||||
|     } | ||||
|     const ngModule = metadataResolver.getUnloadedNgModuleMetadata(staticSymbol, false, false); | ||||
| @ -398,3 +442,15 @@ function _createNgModules( | ||||
| 
 | ||||
|   return {ngModules: Array.from(ngModules.values()), symbolsMissingModule}; | ||||
| } | ||||
| 
 | ||||
| function _filterFileByPatterns( | ||||
|     fileName: string, includeFilePattern: RegExp, excludeFilePattern: RegExp) { | ||||
|   let match = true; | ||||
|   if (includeFilePattern) { | ||||
|     match = match && !!includeFilePattern.exec(fileName); | ||||
|   } | ||||
|   if (excludeFilePattern) { | ||||
|     match = match && !excludeFilePattern.exec(fileName); | ||||
|   } | ||||
|   return match; | ||||
| } | ||||
| @ -31,15 +31,11 @@ import {ViewCompiler} from '../view_compiler/view_compiler'; | ||||
| 
 | ||||
| import {AotCompiler} from './compiler'; | ||||
| import {AotCompilerHost} from './compiler_host'; | ||||
| import {AotCompilerOptions} from './compiler_options'; | ||||
| import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities'; | ||||
| import {StaticReflector} from './static_reflector'; | ||||
| 
 | ||||
| export interface AotCompilerOptions { | ||||
|   debug?: boolean; | ||||
|   locale?: string; | ||||
|   i18nFormat?: string; | ||||
|   translations?: string; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Creates a new AotCompiler based on options and a host. | ||||
| @ -74,6 +70,6 @@ export function createAotCompiler(ngHost: AotCompilerHost, options: AotCompilerO | ||||
|       new ViewCompiler(config, elementSchemaRegistry), | ||||
|       new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console), | ||||
|       new NgModuleCompiler(), new TypeScriptEmitter(ngHost), options.locale, options.i18nFormat, | ||||
|       new AnimationParser(elementSchemaRegistry)); | ||||
|       new AnimationParser(elementSchemaRegistry), staticReflector, options); | ||||
|   return {compiler, reflector: staticReflector}; | ||||
| } | ||||
|  | ||||
							
								
								
									
										16
									
								
								modules/@angular/compiler/src/aot/compiler_options.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								modules/@angular/compiler/src/aot/compiler_options.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| /** | ||||
|  * @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
 | ||||
|  */ | ||||
| 
 | ||||
| export interface AotCompilerOptions { | ||||
|   debug?: boolean; | ||||
|   locale?: string; | ||||
|   i18nFormat?: string; | ||||
|   translations?: string; | ||||
|   includeFilePattern?: RegExp; | ||||
|   excludeFilePattern?: RegExp; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user