refactor(ivy): extract import rewriting into a separate interface (#27998)
Currently the ImportManager class handles various rewriting actions of imports when compiling @angular/core. This is required as code compiled within @angular/core cannot import from '@angular/core'. To work around this, imports are rewritten to get core symbols from a particular file, r3_symbols.ts. In this refactoring, this rewriting logic is moved out of the ImportManager and put behind an interface, ImportRewriter. There are three implementers of the interface: * NoopImportRewriter, used for compiling all non-core packages. * R3SymbolsImportRewriter, used when ngtsc compiles @angular/core. * NgccFlatImportRewriter, used when ngcc compiles @angular/core (special logic is needed because ngcc has to rewrite imports in flat bundles differently than in non-flat bundles). This is a precursor to using this rewriting logic in other contexts besides the ImportManager. PR Close #27998
This commit is contained in:

committed by
Andrew Kushnir

parent
5a0deb8d69
commit
3cf1b62722
@ -1,22 +0,0 @@
|
||||
|
||||
/**
|
||||
* @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 {ImportManager} from '../../../ngtsc/translator';
|
||||
|
||||
export class NgccImportManager extends ImportManager {
|
||||
constructor(private isFlat: boolean, isCore: boolean, prefix?: string) { super(isCore, prefix); }
|
||||
|
||||
generateNamedImport(moduleName: string, symbol: string):
|
||||
{moduleImport: string | null, symbol: string} {
|
||||
if (this.isFlat && this.isCore && moduleName === '@angular/core') {
|
||||
return {moduleImport: null, symbol: this.rewriteSymbol(moduleName, symbol)};
|
||||
}
|
||||
return super.generateNamedImport(moduleName, symbol);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
|
||||
/**
|
||||
* @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 {ImportRewriter, validateAndRewriteCoreSymbol} from '../../../ngtsc/imports';
|
||||
|
||||
export class NgccFlatImportRewriter implements ImportRewriter {
|
||||
shouldImportSymbol(symbol: string, specifier: string): boolean {
|
||||
if (specifier === '@angular/core') {
|
||||
// Don't use imports for @angular/core symbols in a flat bundle, as they'll be visible
|
||||
// directly.
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
rewriteSymbol(symbol: string, specifier: string): string {
|
||||
if (specifier === '@angular/core') {
|
||||
return validateAndRewriteCoreSymbol(symbol);
|
||||
} else {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
rewriteSpecifier(originalModulePath: string, inContextOfFile: string): string {
|
||||
return originalModulePath;
|
||||
}
|
||||
}
|
@ -13,9 +13,10 @@ import {basename, dirname, relative, resolve} from 'canonical-path';
|
||||
import {SourceMapConsumer, SourceMapGenerator, RawSourceMap} from 'source-map';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {NoopImportRewriter, ImportRewriter, R3SymbolsImportRewriter} from '@angular/compiler-cli/src/ngtsc/imports';
|
||||
import {CompileResult} from '@angular/compiler-cli/src/ngtsc/transform';
|
||||
import {translateStatement, translateType, ImportManager} from '../../../ngtsc/translator';
|
||||
import {NgccImportManager} from './ngcc_import_manager';
|
||||
import {NgccFlatImportRewriter} from './ngcc_import_rewriter';
|
||||
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer';
|
||||
import {ModuleWithProvidersInfo, ModuleWithProvidersAnalyses} from '../analysis/module_with_providers_analyzer';
|
||||
import {PrivateDeclarationsAnalyses, ExportInfo} from '../analysis/private_declarations_analyzer';
|
||||
@ -135,7 +136,8 @@ export abstract class Renderer {
|
||||
}
|
||||
|
||||
if (compiledFile) {
|
||||
const importManager = new NgccImportManager(this.bundle.isFlat, this.isCore, IMPORT_PREFIX);
|
||||
const importManager = new ImportManager(
|
||||
this.getImportRewriter(this.bundle.src.r3SymbolsFile, this.bundle.isFlat), IMPORT_PREFIX);
|
||||
|
||||
// TODO: remove constructor param metadata and property decorators (we need info from the
|
||||
// handlers to do this)
|
||||
@ -152,9 +154,7 @@ export abstract class Renderer {
|
||||
renderConstantPool(compiledFile.sourceFile, compiledFile.constantPool, importManager),
|
||||
compiledFile.sourceFile);
|
||||
|
||||
this.addImports(
|
||||
outputText, importManager.getAllImports(
|
||||
compiledFile.sourceFile.fileName, this.bundle.src.r3SymbolsFile));
|
||||
this.addImports(outputText, importManager.getAllImports(compiledFile.sourceFile.fileName));
|
||||
}
|
||||
|
||||
// Add exports to the entry-point file
|
||||
@ -169,7 +169,8 @@ export abstract class Renderer {
|
||||
renderDtsFile(dtsFile: ts.SourceFile, renderInfo: DtsRenderInfo): FileInfo[] {
|
||||
const input = this.extractSourceMap(dtsFile);
|
||||
const outputText = new MagicString(input.source);
|
||||
const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX);
|
||||
const importManager = new ImportManager(
|
||||
this.getImportRewriter(this.bundle.dts !.r3SymbolsFile, false), IMPORT_PREFIX);
|
||||
|
||||
renderInfo.classInfo.forEach(dtsClass => {
|
||||
const endOfClass = dtsClass.dtsDeclaration.getEnd();
|
||||
@ -181,8 +182,7 @@ export abstract class Renderer {
|
||||
});
|
||||
|
||||
this.addModuleWithProvidersParams(outputText, renderInfo.moduleWithProviders, importManager);
|
||||
this.addImports(
|
||||
outputText, importManager.getAllImports(dtsFile.fileName, this.bundle.dts !.r3SymbolsFile));
|
||||
this.addImports(outputText, importManager.getAllImports(dtsFile.fileName));
|
||||
|
||||
this.addExports(outputText, dtsFile.fileName, renderInfo.privateExports);
|
||||
|
||||
@ -199,7 +199,7 @@ export abstract class Renderer {
|
||||
*/
|
||||
protected addModuleWithProvidersParams(
|
||||
outputText: MagicString, moduleWithProviders: ModuleWithProvidersInfo[],
|
||||
importManager: NgccImportManager): void {
|
||||
importManager: ImportManager): void {
|
||||
moduleWithProviders.forEach(info => {
|
||||
const ngModuleName = (info.ngModule.node as ts.ClassDeclaration).name !.text;
|
||||
const declarationFile = info.declaration.getSourceFile().fileName;
|
||||
@ -417,6 +417,16 @@ export abstract class Renderer {
|
||||
return (
|
||||
id && id.name === 'ModuleWithProviders' && (this.isCore || id.from === '@angular/core'));
|
||||
}
|
||||
|
||||
private getImportRewriter(r3SymbolsFile: ts.SourceFile|null, isFlat: boolean): ImportRewriter {
|
||||
if (this.isCore && isFlat) {
|
||||
return new NgccFlatImportRewriter();
|
||||
} else if (this.isCore) {
|
||||
return new R3SymbolsImportRewriter(r3SymbolsFile !.fileName);
|
||||
} else {
|
||||
return new NoopImportRewriter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -451,7 +461,7 @@ export function mergeSourceMaps(
|
||||
* Render the constant pool as source code for the given class.
|
||||
*/
|
||||
export function renderConstantPool(
|
||||
sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: NgccImportManager): string {
|
||||
sourceFile: ts.SourceFile, constantPool: ConstantPool, imports: ImportManager): string {
|
||||
const printer = ts.createPrinter();
|
||||
return constantPool.statements.map(stmt => translateStatement(stmt, imports))
|
||||
.map(stmt => printer.printNode(ts.EmitHint.Unspecified, stmt, sourceFile))
|
||||
@ -467,7 +477,7 @@ export function renderConstantPool(
|
||||
* @param imports An object that tracks the imports that are needed by the rendered definitions.
|
||||
*/
|
||||
export function renderDefinitions(
|
||||
sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: NgccImportManager): string {
|
||||
sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: ImportManager): string {
|
||||
const printer = ts.createPrinter();
|
||||
const name = (compiledClass.declaration as ts.NamedDeclaration).name !;
|
||||
const definitions =
|
||||
|
Reference in New Issue
Block a user