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
@ -12,6 +12,7 @@ ts_library(
|
||||
deps = [
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/typecheck",
|
||||
|
@ -10,6 +10,7 @@ import {ConstantPool} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {FatalDiagnosticError} from '../../diagnostics';
|
||||
import {ImportRewriter} from '../../imports';
|
||||
import {Decorator, ReflectionHost, reflectNameOfDeclaration} from '../../reflection';
|
||||
import {TypeCheckContext} from '../../typecheck';
|
||||
|
||||
@ -17,6 +18,7 @@ import {AnalysisOutput, CompileResult, DecoratorHandler} from './api';
|
||||
import {DtsFileTransformer} from './declaration';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Record of an adapter which decided to emit a static field, and the analysis it performed to
|
||||
* prepare for that operation.
|
||||
@ -63,7 +65,7 @@ export class IvyCompilation {
|
||||
*/
|
||||
constructor(
|
||||
private handlers: DecoratorHandler<any, any>[], private checker: ts.TypeChecker,
|
||||
private reflector: ReflectionHost, private coreImportsFrom: ts.SourceFile|null,
|
||||
private reflector: ReflectionHost, private importRewriter: ImportRewriter,
|
||||
private sourceToFactorySymbols: Map<string, Set<string>>|null) {}
|
||||
|
||||
|
||||
@ -227,7 +229,7 @@ export class IvyCompilation {
|
||||
|
||||
private getDtsTransformer(tsFileName: string): DtsFileTransformer {
|
||||
if (!this.dtsMap.has(tsFileName)) {
|
||||
this.dtsMap.set(tsFileName, new DtsFileTransformer(this.coreImportsFrom));
|
||||
this.dtsMap.set(tsFileName, new DtsFileTransformer(this.importRewriter));
|
||||
}
|
||||
return this.dtsMap.get(tsFileName) !;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ImportRewriter} from '../../imports';
|
||||
import {ImportManager, translateType} from '../../translator';
|
||||
|
||||
import {CompileResult} from './api';
|
||||
@ -21,8 +22,8 @@ export class DtsFileTransformer {
|
||||
private ivyFields = new Map<string, CompileResult[]>();
|
||||
private imports: ImportManager;
|
||||
|
||||
constructor(private coreImportsFrom: ts.SourceFile|null, importPrefix?: string) {
|
||||
this.imports = new ImportManager(coreImportsFrom !== null, importPrefix);
|
||||
constructor(private importRewriter: ImportRewriter, importPrefix?: string) {
|
||||
this.imports = new ImportManager(importRewriter, importPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +57,7 @@ export class DtsFileTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
const imports = this.imports.getAllImports(tsPath, this.coreImportsFrom);
|
||||
const imports = this.imports.getAllImports(tsPath);
|
||||
if (imports.length !== 0) {
|
||||
dts = imports.map(i => `import * as ${i.as} from '${i.name}';\n`).join('') + dts;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
import {ConstantPool} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ImportRewriter} from '../../imports';
|
||||
import {Decorator, ReflectionHost} from '../../reflection';
|
||||
import {ImportManager, translateExpression, translateStatement} from '../../translator';
|
||||
import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor';
|
||||
@ -19,11 +20,11 @@ import {IvyCompilation} from './compilation';
|
||||
const NO_DECORATORS = new Set<ts.Decorator>();
|
||||
|
||||
export function ivyTransformFactory(
|
||||
compilation: IvyCompilation, reflector: ReflectionHost,
|
||||
coreImportsFrom: ts.SourceFile | null): ts.TransformerFactory<ts.SourceFile> {
|
||||
compilation: IvyCompilation, reflector: ReflectionHost, importRewriter: ImportRewriter,
|
||||
isCore: boolean): ts.TransformerFactory<ts.SourceFile> {
|
||||
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
|
||||
return (file: ts.SourceFile): ts.SourceFile => {
|
||||
return transformIvySourceFile(compilation, context, reflector, coreImportsFrom, file);
|
||||
return transformIvySourceFile(compilation, context, reflector, importRewriter, isCore, file);
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -188,13 +189,12 @@ class IvyVisitor extends Visitor {
|
||||
*/
|
||||
function transformIvySourceFile(
|
||||
compilation: IvyCompilation, context: ts.TransformationContext, reflector: ReflectionHost,
|
||||
coreImportsFrom: ts.SourceFile | null, file: ts.SourceFile): ts.SourceFile {
|
||||
importRewriter: ImportRewriter, isCore: boolean, file: ts.SourceFile): ts.SourceFile {
|
||||
const constantPool = new ConstantPool();
|
||||
const importManager = new ImportManager(coreImportsFrom !== null);
|
||||
const importManager = new ImportManager(importRewriter);
|
||||
|
||||
// Recursively scan through the AST and perform any updates requested by the IvyCompilation.
|
||||
const visitor =
|
||||
new IvyVisitor(compilation, reflector, importManager, coreImportsFrom !== null, constantPool);
|
||||
const visitor = new IvyVisitor(compilation, reflector, importManager, isCore, constantPool);
|
||||
const sf = visit(file, visitor, context);
|
||||
|
||||
// Generate the constant statements first, as they may involve adding additional imports
|
||||
@ -202,7 +202,7 @@ function transformIvySourceFile(
|
||||
const constants = constantPool.statements.map(stmt => translateStatement(stmt, importManager));
|
||||
|
||||
// Generate the import statements to prepend.
|
||||
const addedImports = importManager.getAllImports(file.fileName, coreImportsFrom).map(i => {
|
||||
const addedImports = importManager.getAllImports(file.fileName).map(i => {
|
||||
return ts.createImportDeclaration(
|
||||
undefined, undefined,
|
||||
ts.createImportClause(undefined, ts.createNamespaceImport(ts.createIdentifier(i.as))),
|
||||
|
Reference in New Issue
Block a user