refactor(compiler): remove old ngtools api and add listLazyRoutes to new api (#19836)
Usages of `NgTools_InternalApi_NG_2` from `@angular/compiler-cli` will now throw an error. Adds `listLazyRoutes` to `@angular/compiler-cli/ngtools2.ts` for getting the lazy routes of a `ng.Program`. PR Close #19836
This commit is contained in:

committed by
Matias Niemelä

parent
5da96c75a2
commit
8d45fefc31
@ -229,6 +229,12 @@ export interface LibrarySummary {
|
||||
sourceFile?: ts.SourceFile;
|
||||
}
|
||||
|
||||
export interface LazyRoute {
|
||||
route: string;
|
||||
module: {name: string, filePath: string};
|
||||
referencedModule: {name: string, filePath: string};
|
||||
}
|
||||
|
||||
export interface Program {
|
||||
/**
|
||||
* Retrieve the TypeScript program used to produce semantic diagnostics and emit the sources.
|
||||
@ -293,6 +299,14 @@ export interface Program {
|
||||
*/
|
||||
loadNgStructureAsync(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns the lazy routes in the program.
|
||||
* @param entryRoute A reference to an NgModule like `someModule#name`. If given,
|
||||
* will recursively analyze routes starting from this symbol only.
|
||||
* Otherwise will list all routes for all NgModules in the program/
|
||||
*/
|
||||
listLazyRoutes(entryRoute?: string): LazyRoute[];
|
||||
|
||||
/**
|
||||
* Emit the files requested by emitFlags implied by the program.
|
||||
*
|
||||
|
@ -6,19 +6,18 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {EmitterVisitorContext, ExternalReference, GeneratedFile, ParseSourceSpan, TypeScriptEmitter, collectExternalReferences, syntaxError} from '@angular/compiler';
|
||||
import {AotCompilerHost, EmitterVisitorContext, ExternalReference, GeneratedFile, ParseSourceSpan, TypeScriptEmitter, collectExternalReferences, syntaxError} from '@angular/compiler';
|
||||
import * as path from 'path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {BaseAotCompilerHost} from '../compiler_host';
|
||||
import {TypeCheckHost} from '../diagnostics/translate_diagnostics';
|
||||
import {ModuleMetadata} from '../metadata/index';
|
||||
import {METADATA_VERSION, ModuleMetadata} from '../metadata/index';
|
||||
|
||||
import {CompilerHost, CompilerOptions, LibrarySummary} from './api';
|
||||
import {GENERATED_FILES} from './util';
|
||||
import {MetadataReaderHost, createMetadataReaderCache, readMetadata} from './metadata_reader';
|
||||
import {DTS, GENERATED_FILES} from './util';
|
||||
|
||||
const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-)+|(@(\w|-)+\/(\w|-)+))/;
|
||||
const DTS = /\.d\.ts$/;
|
||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
|
||||
export function createCompilerHost(
|
||||
@ -48,9 +47,12 @@ export interface CodeGenerator {
|
||||
* - AotCompilerHost for @angular/compiler
|
||||
* - TypeCheckHost for mapping ts errors to ng errors (via translateDiagnostics)
|
||||
*/
|
||||
export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
BaseAotCompilerHost<CompilerHost> implements ts.CompilerHost,
|
||||
export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHost, AotCompilerHost,
|
||||
TypeCheckHost {
|
||||
private metadataReaderCache = createMetadataReaderCache();
|
||||
private flatModuleIndexCache = new Map<string, boolean>();
|
||||
private flatModuleIndexNames = new Set<string>();
|
||||
private flatModuleIndexRedirectNames = new Set<string>();
|
||||
private rootDirs: string[];
|
||||
private moduleResolutionCache: ts.ModuleResolutionCache;
|
||||
private originalSourceFiles = new Map<string, ts.SourceFile|undefined>();
|
||||
@ -58,6 +60,8 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
private generatedSourceFiles = new Map<string, GenSourceFile>();
|
||||
private generatedCodeFor = new Map<string, string[]>();
|
||||
private emitter = new TypeScriptEmitter();
|
||||
private metadataReaderHost: MetadataReaderHost;
|
||||
|
||||
getCancellationToken: () => ts.CancellationToken;
|
||||
getDefaultLibLocation: () => string;
|
||||
trace: (s: string) => void;
|
||||
@ -65,10 +69,9 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
directoryExists?: (directoryName: string) => boolean;
|
||||
|
||||
constructor(
|
||||
private rootFiles: string[], options: CompilerOptions, context: CompilerHost,
|
||||
private rootFiles: string[], private options: CompilerOptions, private context: CompilerHost,
|
||||
private metadataProvider: MetadataProvider, private codeGenerator: CodeGenerator,
|
||||
private librarySummaries = new Map<string, LibrarySummary>()) {
|
||||
super(options, context);
|
||||
this.moduleResolutionCache = ts.createModuleResolutionCache(
|
||||
this.context.getCurrentDirectory !(), this.context.getCanonicalFileName.bind(this.context));
|
||||
const basePath = this.options.basePath !;
|
||||
@ -103,6 +106,15 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
if (context.fromSummaryFileName) {
|
||||
this.fromSummaryFileName = context.fromSummaryFileName.bind(context);
|
||||
}
|
||||
this.metadataReaderHost = {
|
||||
cacheMetadata: () => true,
|
||||
getSourceFileMetadata: (filePath) => {
|
||||
const sf = this.getOriginalSourceFile(filePath);
|
||||
return sf ? this.metadataProvider.getMetadata(sf) : undefined;
|
||||
},
|
||||
fileExists: (filePath) => this.originalFileExists(filePath),
|
||||
readFile: (filePath) => this.context.readFile(filePath),
|
||||
};
|
||||
}
|
||||
|
||||
private resolveModuleName(moduleName: string, containingFile: string): ts.ResolvedModule
|
||||
@ -251,14 +263,6 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
return sf;
|
||||
}
|
||||
|
||||
getMetadataForSourceFile(filePath: string): ModuleMetadata|undefined {
|
||||
const sf = this.getOriginalSourceFile(filePath);
|
||||
if (!sf) {
|
||||
return undefined;
|
||||
}
|
||||
return this.metadataProvider.getMetadata(sf);
|
||||
}
|
||||
|
||||
updateGeneratedFile(genFile: GeneratedFile): ts.SourceFile {
|
||||
if (!genFile.stmts) {
|
||||
throw new Error(
|
||||
@ -415,7 +419,10 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
if (summary) {
|
||||
return summary.text;
|
||||
}
|
||||
return super.loadSummary(filePath);
|
||||
if (this.originalFileExists(filePath)) {
|
||||
return this.context.readFile(filePath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
isSourceFile(filePath: string): boolean {
|
||||
@ -424,7 +431,21 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
if (this.librarySummaries.has(filePath)) {
|
||||
return false;
|
||||
}
|
||||
return super.isSourceFile(filePath);
|
||||
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;
|
||||
}
|
||||
|
||||
readFile(fileName: string) {
|
||||
@ -434,6 +455,76 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter extends
|
||||
}
|
||||
return this.context.readFile(fileName);
|
||||
}
|
||||
|
||||
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}`);
|
||||
}
|
||||
return this.context.readFile(filePath);
|
||||
}
|
||||
|
||||
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;
|
||||
const packageContent: any = JSON.parse(this.context.readFile(packageFile));
|
||||
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)) {
|
||||
const metadata = JSON.parse(this.context.readFile(metadataFile));
|
||||
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;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 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));
|
||||
}
|
||||
|
||||
getDefaultLibFileName = (options: ts.CompilerOptions) =>
|
||||
this.context.getDefaultLibFileName(options)
|
||||
getCurrentDirectory = () => this.context.getCurrentDirectory();
|
||||
|
128
packages/compiler-cli/src/transformers/metadata_reader.ts
Normal file
128
packages/compiler-cli/src/transformers/metadata_reader.ts
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {METADATA_VERSION, ModuleMetadata} from '../metadata';
|
||||
|
||||
import {DTS} from './util';
|
||||
|
||||
export interface MetadataReaderHost {
|
||||
getSourceFileMetadata(filePath: string): ModuleMetadata|undefined;
|
||||
cacheMetadata?(fileName: string): boolean;
|
||||
fileExists(filePath: string): boolean;
|
||||
readFile(filePath: string): string;
|
||||
}
|
||||
|
||||
export interface MetadataReaderCache {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
data: Map<string, ModuleMetadata[]|undefined>;
|
||||
}
|
||||
|
||||
export function createMetadataReaderCache(): MetadataReaderCache {
|
||||
const data = new Map<string, ModuleMetadata[]|undefined>();
|
||||
return {data};
|
||||
}
|
||||
|
||||
export function readMetadata(
|
||||
filePath: string, host: MetadataReaderHost, cache?: MetadataReaderCache): ModuleMetadata[]|
|
||||
undefined {
|
||||
let metadatas = cache && cache.data.get(filePath);
|
||||
if (metadatas) {
|
||||
return metadatas;
|
||||
}
|
||||
if (host.fileExists(filePath)) {
|
||||
// If the file doesn't exists then we cannot return metadata for the file.
|
||||
// This will occur if the user referenced a declared module for which no file
|
||||
// exists for the module (i.e. jQuery or angularjs).
|
||||
if (DTS.test(filePath)) {
|
||||
metadatas = readMetadataFile(host, filePath);
|
||||
if (!metadatas) {
|
||||
// If there is a .d.ts file but no metadata file we need to produce a
|
||||
// metadata from the .d.ts file as metadata files capture reexports
|
||||
// (starting with v3).
|
||||
metadatas = [upgradeMetadataWithDtsData(
|
||||
host, {'__symbolic': 'module', 'version': 1, 'metadata': {}}, filePath)];
|
||||
}
|
||||
} else {
|
||||
const metadata = host.getSourceFileMetadata(filePath);
|
||||
metadatas = metadata ? [metadata] : [];
|
||||
}
|
||||
}
|
||||
if (cache && (!host.cacheMetadata || host.cacheMetadata(filePath))) {
|
||||
cache.data.set(filePath, metadatas);
|
||||
}
|
||||
return metadatas;
|
||||
}
|
||||
|
||||
|
||||
function readMetadataFile(host: MetadataReaderHost, dtsFilePath: string): ModuleMetadata[]|
|
||||
undefined {
|
||||
const metadataPath = dtsFilePath.replace(DTS, '.metadata.json');
|
||||
if (!host.fileExists(metadataPath)) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const metadataOrMetadatas = JSON.parse(host.readFile(metadataPath));
|
||||
const metadatas: ModuleMetadata[] = metadataOrMetadatas ?
|
||||
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
|
||||
[];
|
||||
if (metadatas.length) {
|
||||
let maxMetadata = metadatas.reduce((p, c) => p.version > c.version ? p : c);
|
||||
if (maxMetadata.version < METADATA_VERSION) {
|
||||
metadatas.push(upgradeMetadataWithDtsData(host, maxMetadata, dtsFilePath));
|
||||
}
|
||||
}
|
||||
return metadatas;
|
||||
} catch (e) {
|
||||
console.error(`Failed to read JSON file ${metadataPath}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function upgradeMetadataWithDtsData(
|
||||
host: MetadataReaderHost, oldMetadata: ModuleMetadata, dtsFilePath: string): ModuleMetadata {
|
||||
// patch v1 to v3 by adding exports and the `extends` clause.
|
||||
// patch v3 to v4 by adding `interface` symbols for TypeAlias
|
||||
let newMetadata: ModuleMetadata = {
|
||||
'__symbolic': 'module',
|
||||
'version': METADATA_VERSION,
|
||||
'metadata': {...oldMetadata.metadata},
|
||||
};
|
||||
if (oldMetadata.exports) {
|
||||
newMetadata.exports = oldMetadata.exports;
|
||||
}
|
||||
if (oldMetadata.importAs) {
|
||||
newMetadata.importAs = oldMetadata.importAs;
|
||||
}
|
||||
if (oldMetadata.origins) {
|
||||
newMetadata.origins = oldMetadata.origins;
|
||||
}
|
||||
const dtsMetadata = host.getSourceFileMetadata(dtsFilePath);
|
||||
if (dtsMetadata) {
|
||||
for (let prop in dtsMetadata.metadata) {
|
||||
if (!newMetadata.metadata[prop]) {
|
||||
newMetadata.metadata[prop] = dtsMetadata.metadata[prop];
|
||||
}
|
||||
}
|
||||
|
||||
// Only copy exports from exports from metadata prior to version 3.
|
||||
// Starting with version 3 the collector began collecting exports and
|
||||
// this should be redundant. Also, with bundler will rewrite the exports
|
||||
// which will hoist the exports from modules referenced indirectly causing
|
||||
// the imports to be different than the .d.ts files and using the .d.ts file
|
||||
// exports would cause the StaticSymbolResolver to redirect symbols to the
|
||||
// incorrect location.
|
||||
if ((!oldMetadata.version || oldMetadata.version < 3) && dtsMetadata.exports) {
|
||||
newMetadata.exports = dtsMetadata.exports;
|
||||
}
|
||||
}
|
||||
return newMetadata;
|
||||
}
|
@ -14,12 +14,13 @@ import * as ts from 'typescript';
|
||||
import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics';
|
||||
import {ModuleMetadata, createBundleIndexHost} from '../metadata/index';
|
||||
|
||||
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, EmitFlags, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api';
|
||||
import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback} from './api';
|
||||
import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host';
|
||||
import {LowerMetadataCache, getExpressionLoweringTransformFactory} from './lower_expressions';
|
||||
import {getAngularEmitterTransformFactory} from './node_emitter_transform';
|
||||
import {GENERATED_FILES, StructureIsReused, createMessageDiagnostic, tsStructureIsReused} from './util';
|
||||
|
||||
|
||||
/**
|
||||
* Maximum number of files that are emitable via calling ts.Program.emit
|
||||
* passing individual targetSourceFiles.
|
||||
@ -50,8 +51,8 @@ class AngularCompilerProgram implements Program {
|
||||
private emittedSourceFiles: ts.SourceFile[]|undefined;
|
||||
|
||||
// Lazily initialized fields
|
||||
private _typeCheckHost: TypeCheckHost;
|
||||
private _compiler: AotCompiler;
|
||||
private _hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter;
|
||||
private _tsProgram: ts.Program;
|
||||
private _analyzedModules: NgAnalyzedModules|undefined;
|
||||
private _structuralDiagnostics: Diagnostic[]|undefined;
|
||||
@ -167,7 +168,7 @@ class AngularCompilerProgram implements Program {
|
||||
diags.push(...this.tsProgram.getSemanticDiagnostics(sf, cancellationToken));
|
||||
}
|
||||
});
|
||||
const {ng} = translateDiagnostics(this.typeCheckHost, diags);
|
||||
const {ng} = translateDiagnostics(this.hostAdapter, diags);
|
||||
return ng;
|
||||
}
|
||||
|
||||
@ -175,18 +176,23 @@ class AngularCompilerProgram implements Program {
|
||||
if (this._analyzedModules) {
|
||||
throw new Error('Angular structure already loaded');
|
||||
}
|
||||
const {tmpProgram, sourceFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
|
||||
return this._compiler.loadFilesAsync(sourceFiles)
|
||||
const {tmpProgram, sourceFiles, rootNames} = this._createProgramWithBasicStubs();
|
||||
return this.compiler.loadFilesAsync(sourceFiles)
|
||||
.catch(this.catchAnalysisError.bind(this))
|
||||
.then(analyzedModules => {
|
||||
if (this._analyzedModules) {
|
||||
throw new Error('Angular structure loaded both synchronously and asynchronsly');
|
||||
}
|
||||
this._updateProgramWithTypeCheckStubs(
|
||||
tmpProgram, analyzedModules, hostAdapter, rootNames);
|
||||
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, rootNames);
|
||||
});
|
||||
}
|
||||
|
||||
listLazyRoutes(route?: string): LazyRoute[] {
|
||||
// Note: Don't analyzedModules if a route is given
|
||||
// to be fast enough.
|
||||
return this.compiler.listLazyRoutes(route, route ? undefined : this.analyzedModules);
|
||||
}
|
||||
|
||||
emit(
|
||||
{emitFlags = EmitFlags.Default, cancellationToken, customTransformers,
|
||||
emitCallback = defaultEmitCallback}: {
|
||||
@ -341,11 +347,18 @@ class AngularCompilerProgram implements Program {
|
||||
// Private members
|
||||
private get compiler(): AotCompiler {
|
||||
if (!this._compiler) {
|
||||
this.initSync();
|
||||
this._createCompiler();
|
||||
}
|
||||
return this._compiler !;
|
||||
}
|
||||
|
||||
private get hostAdapter(): TsCompilerAotCompilerTypeCheckHostAdapter {
|
||||
if (!this._hostAdapter) {
|
||||
this._createCompiler();
|
||||
}
|
||||
return this._hostAdapter !;
|
||||
}
|
||||
|
||||
private get analyzedModules(): NgAnalyzedModules {
|
||||
if (!this._analyzedModules) {
|
||||
this.initSync();
|
||||
@ -367,13 +380,6 @@ class AngularCompilerProgram implements Program {
|
||||
return this._tsProgram !;
|
||||
}
|
||||
|
||||
private get typeCheckHost(): TypeCheckHost {
|
||||
if (!this._typeCheckHost) {
|
||||
this.initSync();
|
||||
}
|
||||
return this._typeCheckHost !;
|
||||
}
|
||||
|
||||
private calculateTransforms(
|
||||
genFiles: Map<string, GeneratedFile>,
|
||||
customTransformers?: CustomTransformers): ts.CustomTransformers {
|
||||
@ -393,19 +399,41 @@ class AngularCompilerProgram implements Program {
|
||||
if (this._analyzedModules) {
|
||||
return;
|
||||
}
|
||||
const {tmpProgram, sourceFiles, hostAdapter, rootNames} = this._createProgramWithBasicStubs();
|
||||
const {tmpProgram, sourceFiles, rootNames} = this._createProgramWithBasicStubs();
|
||||
let analyzedModules: NgAnalyzedModules|null;
|
||||
try {
|
||||
analyzedModules = this._compiler.loadFilesSync(sourceFiles);
|
||||
analyzedModules = this.compiler.loadFilesSync(sourceFiles);
|
||||
} catch (e) {
|
||||
analyzedModules = this.catchAnalysisError(e);
|
||||
}
|
||||
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, hostAdapter, rootNames);
|
||||
this._updateProgramWithTypeCheckStubs(tmpProgram, analyzedModules, rootNames);
|
||||
}
|
||||
|
||||
private _createCompiler() {
|
||||
const codegen: CodeGenerator = {
|
||||
generateFile: (genFileName, baseFileName) =>
|
||||
this._compiler.emitBasicStub(genFileName, baseFileName),
|
||||
findGeneratedFileNames: (fileName) => this._compiler.findGeneratedFileNames(fileName),
|
||||
};
|
||||
|
||||
this._hostAdapter = new TsCompilerAotCompilerTypeCheckHostAdapter(
|
||||
this.rootNames, this.options, this.host, this.metadataCache, codegen,
|
||||
this.oldProgramLibrarySummaries);
|
||||
const aotOptions = getAotCompilerOptions(this.options);
|
||||
this._structuralDiagnostics = [];
|
||||
const errorCollector = (err: any) => {
|
||||
this._structuralDiagnostics !.push({
|
||||
messageText: err.toString(),
|
||||
category: ts.DiagnosticCategory.Error,
|
||||
source: SOURCE,
|
||||
code: DEFAULT_ERROR_CODE
|
||||
});
|
||||
};
|
||||
this._compiler = createAotCompiler(this._hostAdapter, aotOptions, errorCollector).compiler;
|
||||
}
|
||||
|
||||
private _createProgramWithBasicStubs(): {
|
||||
tmpProgram: ts.Program,
|
||||
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter,
|
||||
rootNames: string[],
|
||||
sourceFiles: string[],
|
||||
} {
|
||||
@ -418,58 +446,56 @@ class AngularCompilerProgram implements Program {
|
||||
|
||||
const codegen: CodeGenerator = {
|
||||
generateFile: (genFileName, baseFileName) =>
|
||||
this._compiler.emitBasicStub(genFileName, baseFileName),
|
||||
findGeneratedFileNames: (fileName) => this._compiler.findGeneratedFileNames(fileName),
|
||||
this.compiler.emitBasicStub(genFileName, baseFileName),
|
||||
findGeneratedFileNames: (fileName) => this.compiler.findGeneratedFileNames(fileName),
|
||||
};
|
||||
|
||||
const hostAdapter = new TsCompilerAotCompilerTypeCheckHostAdapter(
|
||||
this.rootNames, this.options, this.host, this.metadataCache, codegen,
|
||||
this.oldProgramLibrarySummaries);
|
||||
const aotOptions = getAotCompilerOptions(this.options);
|
||||
this._compiler = createAotCompiler(hostAdapter, aotOptions).compiler;
|
||||
this._typeCheckHost = hostAdapter;
|
||||
this._structuralDiagnostics = [];
|
||||
|
||||
let rootNames =
|
||||
this.rootNames.filter(fn => !GENERATED_FILES.test(fn) || !hostAdapter.isSourceFile(fn));
|
||||
let rootNames = this.rootNames;
|
||||
if (this.options.generateCodeForLibraries !== false) {
|
||||
// if we should generateCodeForLibraries, enver include
|
||||
// generated files in the program as otherwise we will
|
||||
// ovewrite them and typescript will report the error
|
||||
// TS5055: Cannot write file ... because it would overwrite input file.
|
||||
rootNames = this.rootNames.filter(fn => !GENERATED_FILES.test(fn));
|
||||
}
|
||||
if (this.options.noResolve) {
|
||||
this.rootNames.forEach(rootName => {
|
||||
if (hostAdapter.shouldGenerateFilesFor(rootName)) {
|
||||
rootNames.push(...this._compiler.findGeneratedFileNames(rootName));
|
||||
if (this.hostAdapter.shouldGenerateFilesFor(rootName)) {
|
||||
rootNames.push(...this.compiler.findGeneratedFileNames(rootName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const tmpProgram = ts.createProgram(rootNames, this.options, hostAdapter, oldTsProgram);
|
||||
const tmpProgram = ts.createProgram(rootNames, this.options, this.hostAdapter, oldTsProgram);
|
||||
const sourceFiles: string[] = [];
|
||||
tmpProgram.getSourceFiles().forEach(sf => {
|
||||
if (hostAdapter.isSourceFile(sf.fileName)) {
|
||||
if (this.hostAdapter.isSourceFile(sf.fileName)) {
|
||||
sourceFiles.push(sf.fileName);
|
||||
}
|
||||
});
|
||||
return {tmpProgram, sourceFiles, hostAdapter, rootNames};
|
||||
return {tmpProgram, sourceFiles, rootNames};
|
||||
}
|
||||
|
||||
private _updateProgramWithTypeCheckStubs(
|
||||
tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules|null,
|
||||
hostAdapter: TsCompilerAotCompilerTypeCheckHostAdapter, rootNames: string[]) {
|
||||
tmpProgram: ts.Program, analyzedModules: NgAnalyzedModules|null, rootNames: string[]) {
|
||||
this._analyzedModules = analyzedModules || emptyModules;
|
||||
if (analyzedModules) {
|
||||
tmpProgram.getSourceFiles().forEach(sf => {
|
||||
if (sf.fileName.endsWith('.ngfactory.ts')) {
|
||||
const {generate, baseFileName} = hostAdapter.shouldGenerateFile(sf.fileName);
|
||||
const {generate, baseFileName} = this.hostAdapter.shouldGenerateFile(sf.fileName);
|
||||
if (generate) {
|
||||
// Note: ! is ok as hostAdapter.shouldGenerateFile will always return a basefileName
|
||||
// for .ngfactory.ts files.
|
||||
const genFile = this._compiler.emitTypeCheckStub(sf.fileName, baseFileName !);
|
||||
const genFile = this.compiler.emitTypeCheckStub(sf.fileName, baseFileName !);
|
||||
if (genFile) {
|
||||
hostAdapter.updateGeneratedFile(genFile);
|
||||
this.hostAdapter.updateGeneratedFile(genFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
this._tsProgram = ts.createProgram(rootNames, this.options, hostAdapter, tmpProgram);
|
||||
this._tsProgram = ts.createProgram(rootNames, this.options, this.hostAdapter, tmpProgram);
|
||||
// Note: the new ts program should be completely reusable by TypeScript as:
|
||||
// - we cache all the files in the hostAdapter
|
||||
// - new new stubs use the exactly same imports/exports as the old once (we assert that in
|
||||
|
@ -11,6 +11,7 @@ import * as ts from 'typescript';
|
||||
import {DEFAULT_ERROR_CODE, Diagnostic, SOURCE} from './api';
|
||||
|
||||
export const GENERATED_FILES = /(.*?)\.(ngfactory|shim\.ngstyle|ngstyle|ngsummary)\.(js|d\.ts|ts)$/;
|
||||
export const DTS = /\.d\.ts$/;
|
||||
|
||||
export const enum StructureIsReused {Not = 0, SafeModules = 1, Completely = 2}
|
||||
|
||||
|
Reference in New Issue
Block a user