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
@ -6,5 +6,6 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core';
|
||||
export {AbsoluteReference, ImportMode, NodeReference, Reference, ResolvedReference} from './src/references';
|
||||
export {ReferenceResolver, TsReferenceResolver} from './src/resolver';
|
||||
|
103
packages/compiler-cli/src/ngtsc/imports/src/core.ts
Normal file
103
packages/compiler-cli/src/ngtsc/imports/src/core.ts
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @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 {relativePathBetween} from '../../util/src/path';
|
||||
|
||||
/**
|
||||
* Rewrites imports of symbols being written into generated code.
|
||||
*/
|
||||
export interface ImportRewriter {
|
||||
/**
|
||||
* Should the given symbol be imported at all?
|
||||
*
|
||||
* If `true`, the symbol should be imported from the given specifier. If `false`, the symbol
|
||||
* should be referenced directly, without an import.
|
||||
*/
|
||||
shouldImportSymbol(symbol: string, specifier: string): boolean;
|
||||
|
||||
/**
|
||||
* Optionally rewrite a reference to an imported symbol, changing either the binding prefix or the
|
||||
* symbol name itself.
|
||||
*/
|
||||
rewriteSymbol(symbol: string, specifier: string): string;
|
||||
|
||||
/**
|
||||
* Optionally rewrite the given module specifier in the context of a given file.
|
||||
*/
|
||||
rewriteSpecifier(specifier: string, inContextOfFile: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* `ImportRewriter` that does no rewriting.
|
||||
*/
|
||||
export class NoopImportRewriter implements ImportRewriter {
|
||||
shouldImportSymbol(symbol: string, specifier: string): boolean { return true; }
|
||||
|
||||
rewriteSymbol(symbol: string, specifier: string): string { return symbol; }
|
||||
|
||||
rewriteSpecifier(specifier: string, inContextOfFile: string): string { return specifier; }
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping of supported symbols that can be imported from within @angular/core, and the names by
|
||||
* which they're exported from r3_symbols.
|
||||
*/
|
||||
const CORE_SUPPORTED_SYMBOLS = new Map<string, string>([
|
||||
['defineInjectable', 'defineInjectable'],
|
||||
['defineInjector', 'defineInjector'],
|
||||
['ɵdefineNgModule', 'defineNgModule'],
|
||||
['inject', 'inject'],
|
||||
['ɵsetClassMetadata', 'setClassMetadata'],
|
||||
['ɵInjectableDef', 'InjectableDef'],
|
||||
['ɵInjectorDef', 'InjectorDef'],
|
||||
['ɵNgModuleDefWithMeta', 'NgModuleDefWithMeta'],
|
||||
['ɵNgModuleFactory', 'NgModuleFactory'],
|
||||
]);
|
||||
|
||||
const CORE_MODULE = '@angular/core';
|
||||
|
||||
/**
|
||||
* `ImportRewriter` that rewrites imports from '@angular/core' to be imported from the r3_symbols.ts
|
||||
* file instead.
|
||||
*/
|
||||
export class R3SymbolsImportRewriter implements ImportRewriter {
|
||||
constructor(private r3SymbolsPath: string) {}
|
||||
|
||||
shouldImportSymbol(symbol: string, specifier: string): boolean { return true; }
|
||||
|
||||
rewriteSymbol(symbol: string, specifier: string): string {
|
||||
if (specifier !== CORE_MODULE) {
|
||||
// This import isn't from core, so ignore it.
|
||||
return symbol;
|
||||
}
|
||||
|
||||
return validateAndRewriteCoreSymbol(symbol);
|
||||
}
|
||||
|
||||
rewriteSpecifier(specifier: string, inContextOfFile: string): string {
|
||||
if (specifier !== CORE_MODULE) {
|
||||
// This module isn't core, so ignore it.
|
||||
return specifier;
|
||||
}
|
||||
|
||||
const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath);
|
||||
if (relativePathToR3Symbols === null) {
|
||||
throw new Error(
|
||||
`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${this.r3SymbolsPath}`);
|
||||
}
|
||||
|
||||
return relativePathToR3Symbols;
|
||||
}
|
||||
}
|
||||
|
||||
export function validateAndRewriteCoreSymbol(name: string): string {
|
||||
if (!CORE_SUPPORTED_SYMBOLS.has(name)) {
|
||||
throw new Error(`Importing unexpected symbol ${name} while compiling ${CORE_MODULE}`);
|
||||
}
|
||||
return CORE_SUPPORTED_SYMBOLS.get(name) !;
|
||||
}
|
Reference in New Issue
Block a user