When compiling libraries, this feature extracts the minimal information from the directives/pipes/modules of the library into `.ngsummary.json` files, so that applications that use this library only need to be recompiled if one of the summary files change, but not on every change of the libraries (e.g. one of the templates). Only works if individual codegen for libraries is enabled, see the `generateCodeForLibraries: false` option. Closes #12787
116 lines
4.6 KiB
TypeScript
116 lines
4.6 KiB
TypeScript
/**
|
|
* @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 {ViewEncapsulation} from '@angular/core';
|
|
import {AngularCompilerOptions, NgcCliOptions} from '@angular/tsc-wrapped';
|
|
import {readFileSync} from 'fs';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
|
|
import {CompilerHost, CompilerHostContext, ModuleResolutionHostAdapter} from './compiler_host';
|
|
import {PathMappedCompilerHost} from './path_mapped_compiler_host';
|
|
import {Console} from './private_import_core';
|
|
|
|
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
|
const GENERATED_META_FILES = /\.json$/;
|
|
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
|
|
|
const PREAMBLE = `/**
|
|
* @fileoverview This file is generated by the Angular 2 template compiler.
|
|
* Do not edit.
|
|
* @suppress {suspiciousCode,uselessCode,missingProperties}
|
|
*/
|
|
/* tslint:disable */
|
|
|
|
`;
|
|
|
|
export class CodeGenerator {
|
|
constructor(
|
|
private options: AngularCompilerOptions, private program: ts.Program,
|
|
public host: ts.CompilerHost, private compiler: compiler.AotCompiler,
|
|
private ngCompilerHost: CompilerHost) {}
|
|
|
|
// Write codegen in a directory structure matching the sources.
|
|
private calculateEmitPath(filePath: string): string {
|
|
let root = this.options.basePath;
|
|
for (const eachRootDir of this.options.rootDirs || []) {
|
|
if (this.options.trace) {
|
|
console.error(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
|
}
|
|
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
|
root = eachRootDir;
|
|
}
|
|
}
|
|
|
|
// transplant the codegen path to be inside the `genDir`
|
|
let relativePath: string = path.relative(root, filePath);
|
|
while (relativePath.startsWith('..' + path.sep)) {
|
|
// Strip out any `..` path such as: `../node_modules/@foo` as we want to put everything
|
|
// into `genDir`.
|
|
relativePath = relativePath.substr(3);
|
|
}
|
|
|
|
return path.join(this.options.genDir, relativePath);
|
|
}
|
|
|
|
codegen(): Promise<any> {
|
|
return this.compiler
|
|
.compileAll(this.program.getSourceFiles().map(
|
|
sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName)))
|
|
.then(generatedModules => {
|
|
generatedModules.forEach(generatedModule => {
|
|
const sourceFile = this.program.getSourceFile(generatedModule.srcFileUrl);
|
|
const emitPath = this.calculateEmitPath(generatedModule.genFileUrl);
|
|
const source = GENERATED_META_FILES.test(emitPath) ? generatedModule.source :
|
|
PREAMBLE + generatedModule.source;
|
|
this.host.writeFile(emitPath, source, false, () => {}, [sourceFile]);
|
|
});
|
|
});
|
|
}
|
|
|
|
static create(
|
|
options: AngularCompilerOptions, cliOptions: NgcCliOptions, 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);
|
|
}
|
|
const transFile = cliOptions.i18nFile;
|
|
const locale = cliOptions.locale;
|
|
let transContent: string = '';
|
|
if (transFile) {
|
|
if (!locale) {
|
|
throw new Error(
|
|
`The translation file (${transFile}) locale must be provided. Use the --locale option.`);
|
|
}
|
|
transContent = readFileSync(transFile, 'utf8');
|
|
}
|
|
const {compiler: aotCompiler} = compiler.createAotCompiler(ngCompilerHost, {
|
|
debug: options.debug === true,
|
|
translations: transContent,
|
|
i18nFormat: cliOptions.i18nFormat,
|
|
locale: cliOptions.locale,
|
|
excludeFilePattern: options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES :
|
|
GENERATED_FILES
|
|
});
|
|
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
|
|
}
|
|
}
|
|
|
|
export function excludeFilePattern(options: AngularCompilerOptions): RegExp {
|
|
return options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
|
}
|