/** * @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 */ /** * Transform template html and css into executable code. * Intended to be used in a build step. */ import * as compiler from '@angular/compiler'; import {AngularCompilerOptions, NgcCliOptions} from '@angular/tsc-wrapped'; import {readFileSync} from 'fs'; import * as ts from 'typescript'; import {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter} from './compiler_host'; import {PathMappedCompilerHost} from './path_mapped_compiler_host'; const GENERATED_META_FILES = /\.json$/; const PREAMBLE = `/** * @fileoverview This file is generated by the Angular template compiler. * Do not edit. * @suppress {suspiciousCode,uselessCode,missingProperties,missingOverride} */ /* tslint:disable */ `; export interface CodeGeneratorI18nOptions { i18nFormat: string|null; i18nFile: string|null; locale: string|null; missingTranslation: string|null; } export class CodeGenerator { constructor( private options: AngularCompilerOptions, private program: ts.Program, public host: ts.CompilerHost, private compiler: compiler.AotCompiler, private ngCompilerHost: CompilerHost) {} codegen(): Promise { return this.compiler .analyzeModulesAsync(this.program.getSourceFiles().map( sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName))) .then(analyzedModules => this.emit(analyzedModules)); } codegenSync(): string[] { const analyzed = this.compiler.analyzeModulesSync(this.program.getSourceFiles().map( sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName))); return this.emit(analyzed); } private emit(analyzedModules: compiler.NgAnalyzedModules) { const generatedModules = this.compiler.emitAllImpls(analyzedModules); return generatedModules.map(generatedModule => { const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl); const emitPath = this.ngCompilerHost.calculateEmitPath(generatedModule.genFileUrl); const source = generatedModule.source || compiler.toTypeScript(generatedModule, PREAMBLE); this.host.writeFile(emitPath, source, false, () => {}, [sourceFile]); return emitPath; }); } static create( options: AngularCompilerOptions, i18nOptions: CodeGeneratorI18nOptions, program: ts.Program, tsCompilerHost: ts.CompilerHost, compilerHostContext?: CompilerHostContext, ngCompilerHost?: CompilerHost): CodeGenerator { if (!ngCompilerHost) { const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0; const context = compilerHostContext || new ModuleResolutionHostAdapter(tsCompilerHost); ngCompilerHost = usePathMapping ? new PathMappedCompilerHost(program, options, context) : new CompilerHost(program, options, context); } let transContent: string = ''; if (i18nOptions.i18nFile) { if (!i18nOptions.locale) { throw new Error( `The translation file (${i18nOptions.i18nFile}) locale must be provided. Use the --locale option.`); } transContent = readFileSync(i18nOptions.i18nFile, 'utf8'); } let missingTranslation = compiler.core.MissingTranslationStrategy.Warning; if (i18nOptions.missingTranslation) { switch (i18nOptions.missingTranslation) { case 'error': missingTranslation = compiler.core.MissingTranslationStrategy.Error; break; case 'warning': missingTranslation = compiler.core.MissingTranslationStrategy.Warning; break; case 'ignore': missingTranslation = compiler.core.MissingTranslationStrategy.Ignore; break; default: throw new Error( `Unknown option for missingTranslation (${i18nOptions.missingTranslation}). Use either error, warning or ignore.`); } } if (!transContent) { missingTranslation = compiler.core.MissingTranslationStrategy.Ignore; } const {compiler: aotCompiler} = compiler.createAotCompiler(ngCompilerHost, { translations: transContent, i18nFormat: i18nOptions.i18nFormat || undefined, locale: i18nOptions.locale || undefined, missingTranslation, enableLegacyTemplate: options.enableLegacyTemplate === true, enableSummariesForJit: options.enableSummariesForJit !== false, preserveWhitespaces: options.preserveWhitespaces, }); return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost); } }