refactor(compiler-cli): use the transformer based compiler by default
The source map does not currently work with the transformer pipeline. It will be re-enabled after TypeScript 2.4 is made the min version. To revert to the former compiler, use the `disableTransformerPipeline` in tsconfig.json: ``` { "angularCompilerOptions": { "disableTransformerPipeline": true } } ```
This commit is contained in:
@ -6,20 +6,22 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AotCompiler, GeneratedFile, NgAnalyzedModules, createAotCompiler, getParseErrors, isSyntaxError, toTypeScript} from '@angular/compiler';
|
||||
import {MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||
import {writeFileSync} from 'fs';
|
||||
import {AotCompiler, AotCompilerOptions, GeneratedFile, NgAnalyzedModules, createAotCompiler, getParseErrors, isSyntaxError, toTypeScript} from '@angular/compiler';
|
||||
import {MissingTranslationStrategy} from '@angular/core';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as tsickle from 'tsickle';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {CompilerHost as AotCompilerHost, CompilerHostContext} from '../compiler_host';
|
||||
import {CompilerHost as AotCompilerHost} from '../compiler_host';
|
||||
import {TypeChecker} from '../diagnostics/check_types';
|
||||
|
||||
import {CompilerHost, CompilerOptions, Diagnostic, DiagnosticCategory, EmitFlags, Program} from './api';
|
||||
import {CompilerHost, CompilerOptions, Diagnostic, DiagnosticCategory, EmitFlags, EmitResult, Program} from './api';
|
||||
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
|
||||
import {getAngularEmitterTransformFactory} from './node_emitter_transform';
|
||||
|
||||
const GENERATED_FILES = /\.ngfactory\.js$|\.ngstyle\.js$|\.ngsummary\.js$/;
|
||||
|
||||
const SUMMARY_JSON_FILES = /\.ngsummary.json$/;
|
||||
|
||||
const emptyModules: NgAnalyzedModules = {
|
||||
@ -52,17 +54,20 @@ class AngularCompilerProgram implements Program {
|
||||
private rootNames: string[], private options: CompilerOptions, private host: CompilerHost,
|
||||
private oldProgram?: Program) {
|
||||
this.oldTsProgram = oldProgram ? oldProgram.getTsProgram() : undefined;
|
||||
|
||||
this.tsProgram = ts.createProgram(rootNames, options, host, this.oldTsProgram);
|
||||
this.srcNames = this.tsProgram.getSourceFiles().map(sf => sf.fileName);
|
||||
this.srcNames =
|
||||
this.tsProgram.getSourceFiles()
|
||||
.map(sf => sf.fileName)
|
||||
.filter(f => !f.match(/\.ngfactory\.[\w.]+$|\.ngstyle\.[\w.]+$|\.ngsummary\.[\w.]+$/));
|
||||
this.metadataCache = new LowerMetadataCache({quotedNames: true}, !!options.strictMetadataEmit);
|
||||
this.aotCompilerHost = new AotCompilerHost(
|
||||
this.tsProgram, options, host, /* collectorOptions */ undefined, this.metadataCache);
|
||||
if (host.readResource) {
|
||||
this.aotCompilerHost.loadResource = host.readResource.bind(host);
|
||||
}
|
||||
const {compiler} = createAotCompiler(this.aotCompilerHost, options);
|
||||
this.compiler = compiler;
|
||||
|
||||
const aotOptions = getAotCompilerOptions(options);
|
||||
this.compiler = createAotCompiler(this.aotCompilerHost, aotOptions).compiler;
|
||||
}
|
||||
|
||||
// Program implementation
|
||||
@ -115,25 +120,56 @@ class AngularCompilerProgram implements Program {
|
||||
getLazyRoutes(cancellationToken?: ts.CancellationToken): {[route: string]: string} { return {}; }
|
||||
|
||||
emit({emitFlags = EmitFlags.Default, cancellationToken}:
|
||||
{emitFlags?: EmitFlags, cancellationToken?: ts.CancellationToken}): ts.EmitResult {
|
||||
{emitFlags?: EmitFlags, cancellationToken?: ts.CancellationToken}): EmitResult {
|
||||
const emitMap = new Map<string, string>();
|
||||
const result = this.programWithStubs.emit(
|
||||
|
||||
const tsickleCompilerHostOptions: tsickle.TransformerOptions = {
|
||||
googmodule: false,
|
||||
untyped: true,
|
||||
convertIndexImportShorthand: true,
|
||||
transformDecorators: this.options.annotationsAs !== 'decorators',
|
||||
transformTypesToClosure: this.options.annotateForClosureCompiler,
|
||||
};
|
||||
|
||||
const tsickleHost: tsickle.TransformerHost = {
|
||||
shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName),
|
||||
pathToModuleName: (context, importPath) => '',
|
||||
shouldIgnoreWarningsForPath: (filePath) => false,
|
||||
fileNameToModuleId: (fileName) => fileName,
|
||||
};
|
||||
|
||||
const expectedOut = this.options.expectedOut ?
|
||||
this.options.expectedOut.map(f => path.resolve(process.cwd(), f)) :
|
||||
undefined;
|
||||
|
||||
const result = tsickle.emitWithTsickle(
|
||||
this.programWithStubs, tsickleHost, tsickleCompilerHostOptions, this.host, this.options,
|
||||
/* targetSourceFile */ undefined,
|
||||
createWriteFileCallback(emitFlags, this.host, this.metadataCache, emitMap),
|
||||
createWriteFileCallback(emitFlags, this.host, this.metadataCache, emitMap, expectedOut),
|
||||
cancellationToken, (emitFlags & (EmitFlags.DTS | EmitFlags.JS)) == EmitFlags.DTS,
|
||||
this.calculateTransforms());
|
||||
|
||||
this.generatedFiles.forEach(file => {
|
||||
// In order not to replicate the TS calculation of the out folder for files
|
||||
// derive the out location for .json files from the out location of the .ts files
|
||||
if (file.source && file.source.length && SUMMARY_JSON_FILES.test(file.genFileUrl)) {
|
||||
// If we have emitted the ngsummary.ts file, ensure the ngsummary.json file is emitted to
|
||||
// the same location.
|
||||
|
||||
const emittedFile = emitMap.get(file.srcFileUrl);
|
||||
const fileName = emittedFile ?
|
||||
path.join(path.dirname(emittedFile), path.basename(file.genFileUrl)) :
|
||||
file.genFileUrl;
|
||||
this.host.writeFile(fileName, file.source, false, error => {});
|
||||
|
||||
if (emittedFile) {
|
||||
const fileName = path.join(path.dirname(emittedFile), path.basename(file.genFileUrl));
|
||||
this.host.writeFile(fileName, file.source, false, error => {});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure that expected output files exist.
|
||||
for (const out of expectedOut || []) {
|
||||
fs.appendFileSync(out, '', 'utf8');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -183,19 +219,15 @@ class AngularCompilerProgram implements Program {
|
||||
return this.generatedFiles && this._generatedFileDiagnostics !;
|
||||
}
|
||||
|
||||
private calculateTransforms(): ts.CustomTransformers {
|
||||
const before: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||
const after: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||
private calculateTransforms(): tsickle.EmitTransformers {
|
||||
const beforeTs: ts.TransformerFactory<ts.SourceFile>[] = [];
|
||||
if (!this.options.disableExpressionLowering) {
|
||||
before.push(getExpressionLoweringTransformFactory(this.metadataCache));
|
||||
beforeTs.push(getExpressionLoweringTransformFactory(this.metadataCache));
|
||||
}
|
||||
if (!this.options.skipTemplateCodegen) {
|
||||
after.push(getAngularEmitterTransformFactory(this.generatedFiles));
|
||||
beforeTs.push(getAngularEmitterTransformFactory(this.generatedFiles));
|
||||
}
|
||||
const result: ts.CustomTransformers = {};
|
||||
if (before.length) result.before = before;
|
||||
if (after.length) result.after = after;
|
||||
return result;
|
||||
return {beforeTs};
|
||||
}
|
||||
|
||||
private catchAnalysisError(e: any): NgAnalyzedModules {
|
||||
@ -228,8 +260,8 @@ class AngularCompilerProgram implements Program {
|
||||
private generateStubs() {
|
||||
return this.options.skipTemplateCodegen ? [] :
|
||||
this.options.generateCodeForLibraries === false ?
|
||||
this.compiler.emitAllStubs(this.analyzedModules) :
|
||||
this.compiler.emitPartialStubs(this.analyzedModules);
|
||||
this.compiler.emitPartialStubs(this.analyzedModules) :
|
||||
this.compiler.emitAllStubs(this.analyzedModules);
|
||||
}
|
||||
|
||||
private generateFiles() {
|
||||
@ -270,6 +302,40 @@ export function createProgram(
|
||||
return new AngularCompilerProgram(rootNames, options, host, oldProgram);
|
||||
}
|
||||
|
||||
// Compute the AotCompiler options
|
||||
function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions {
|
||||
let missingTranslation = MissingTranslationStrategy.Warning;
|
||||
|
||||
switch (options.i18nInMissingTranslations) {
|
||||
case 'ignore':
|
||||
missingTranslation = MissingTranslationStrategy.Ignore;
|
||||
break;
|
||||
case 'error':
|
||||
missingTranslation = MissingTranslationStrategy.Error;
|
||||
break;
|
||||
}
|
||||
|
||||
let translations: string = '';
|
||||
|
||||
if (options.i18nInFile) {
|
||||
if (!options.locale) {
|
||||
throw new Error(`The translation file (${options.i18nInFile}) locale must be provided.`);
|
||||
}
|
||||
translations = fs.readFileSync(options.i18nInFile, 'utf8');
|
||||
} else {
|
||||
// No translations are provided, ignore any errors
|
||||
// We still go through i18n to remove i18n attributes
|
||||
missingTranslation = MissingTranslationStrategy.Ignore;
|
||||
}
|
||||
|
||||
return {
|
||||
locale: options.i18nInLocale,
|
||||
i18nFormat: options.i18nInFormat || options.i18nOutFormat, translations, missingTranslation,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate,
|
||||
enableSummariesForJit: true,
|
||||
};
|
||||
}
|
||||
|
||||
function writeMetadata(
|
||||
emitFilePath: string, sourceFile: ts.SourceFile, metadataCache: LowerMetadataCache) {
|
||||
if (/\.js$/.test(emitFilePath)) {
|
||||
@ -287,38 +353,36 @@ function writeMetadata(
|
||||
const metadata = metadataCache.getMetadata(collectableFile);
|
||||
if (metadata) {
|
||||
const metadataText = JSON.stringify([metadata]);
|
||||
writeFileSync(path, metadataText, {encoding: 'utf-8'});
|
||||
fs.writeFileSync(path, metadataText, {encoding: 'utf-8'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createWriteFileCallback(
|
||||
emitFlags: EmitFlags, host: ts.CompilerHost, metadataCache: LowerMetadataCache,
|
||||
emitMap: Map<string, string>) {
|
||||
const withMetadata =
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
||||
const generatedFile = GENERATED_FILES.test(fileName);
|
||||
if (!generatedFile || data != '') {
|
||||
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
}
|
||||
if (!generatedFile && sourceFiles && sourceFiles.length == 1) {
|
||||
emitMap.set(sourceFiles[0].fileName, fileName);
|
||||
writeMetadata(fileName, sourceFiles[0], metadataCache);
|
||||
}
|
||||
};
|
||||
const withoutMetadata =
|
||||
(fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
||||
const generatedFile = GENERATED_FILES.test(fileName);
|
||||
if (!generatedFile || data != '') {
|
||||
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
}
|
||||
if (!generatedFile && sourceFiles && sourceFiles.length == 1) {
|
||||
emitMap.set(sourceFiles[0].fileName, fileName);
|
||||
}
|
||||
};
|
||||
return (emitFlags & EmitFlags.Metadata) != 0 ? withMetadata : withoutMetadata;
|
||||
emitMap: Map<string, string>, expectedOut?: string[]) {
|
||||
return (fileName: string, data: string, writeByteOrderMark: boolean,
|
||||
onError?: (message: string) => void, sourceFiles?: ts.SourceFile[]) => {
|
||||
|
||||
let srcFile: ts.SourceFile|undefined;
|
||||
|
||||
if (sourceFiles && sourceFiles.length == 1) {
|
||||
srcFile = sourceFiles[0];
|
||||
emitMap.set(srcFile.fileName, fileName);
|
||||
}
|
||||
|
||||
const absFile = path.resolve(process.cwd(), fileName);
|
||||
const generatedFile = GENERATED_FILES.test(fileName);
|
||||
|
||||
// Don't emit unexpected files nor empty generated files
|
||||
if ((!expectedOut || expectedOut.indexOf(absFile) > -1) && (!generatedFile || data)) {
|
||||
host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||
|
||||
if (srcFile && !generatedFile && (emitFlags & EmitFlags.Metadata) != 0) {
|
||||
writeMetadata(fileName, srcFile, metadataCache);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getNgOptionDiagnostics(options: CompilerOptions): Diagnostic[] {
|
||||
|
Reference in New Issue
Block a user