fix(ivy): in ngcc, handle inline exports in commonjs code (#32129)
One of the compiler's tasks is to enumerate the exports of a given ES module. This can happen for example to resolve `foo.bar` where `foo` is a namespace import: ```typescript import * as foo from './foo'; @NgModule({ directives: [foo.DIRECTIVES], }) ``` In this case, the compiler must enumerate the exports of `foo.ts` in order to evaluate the expression `foo.DIRECTIVES`. When this operation occurs under ngcc, it must deal with the different module formats and types of exports that occur. In commonjs code, a problem arises when certain exports are downleveled. ```typescript export const DIRECTIVES = [ FooDir, BarDir, ]; ``` can be downleveled to: ```javascript exports.DIRECTIVES = [ FooDir, BarDir, ``` Previously, ngtsc and ngcc expected that any export would have an associated `ts.Declaration` node. `export class`, `export function`, etc. all retain `ts.Declaration`s even when downleveled. But the `export const` construct above does not. Therefore, ngcc would not detect `DIRECTIVES` as an export of `foo.ts`, and the evaluation of `foo.DIRECTIVES` would therefore fail. To solve this problem, the core concept of an exported `Declaration` according to the `ReflectionHost` API is split into a `ConcreteDeclaration` which has a `ts.Declaration`, and an `InlineDeclaration` which instead has a `ts.Expression`. Differentiating between these allows ngcc to return an `InlineDeclaration` for `DIRECTIVES` and correctly keep track of this export. PR Close #32129
This commit is contained in:

committed by
Andrew Kushnir

parent
69ce1c2d41
commit
02bab8cf90
@ -8,7 +8,7 @@
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteFsPath, absoluteFromSourceFile} from '../../../src/ngtsc/file_system';
|
||||
import {Declaration} from '../../../src/ngtsc/reflection';
|
||||
import {ConcreteDeclaration} from '../../../src/ngtsc/reflection';
|
||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||
import {hasNameIdentifier, isDefined} from '../utils';
|
||||
import {NgccReferencesRegistry} from './ngcc_references_registry';
|
||||
@ -40,15 +40,15 @@ export class PrivateDeclarationsAnalyzer {
|
||||
|
||||
private getPrivateDeclarations(
|
||||
rootFiles: ts.SourceFile[],
|
||||
declarations: Map<ts.Identifier, Declaration>): PrivateDeclarationsAnalyses {
|
||||
const privateDeclarations: Map<ts.Identifier, Declaration> = new Map(declarations);
|
||||
declarations: Map<ts.Identifier, ConcreteDeclaration>): PrivateDeclarationsAnalyses {
|
||||
const privateDeclarations: Map<ts.Identifier, ConcreteDeclaration> = new Map(declarations);
|
||||
const exportAliasDeclarations: Map<ts.Identifier, string> = new Map();
|
||||
|
||||
rootFiles.forEach(f => {
|
||||
const exports = this.host.getExportsOfModule(f);
|
||||
if (exports) {
|
||||
exports.forEach((declaration, exportedName) => {
|
||||
if (hasNameIdentifier(declaration.node)) {
|
||||
if (declaration.node !== null && hasNameIdentifier(declaration.node)) {
|
||||
if (privateDeclarations.has(declaration.node.name)) {
|
||||
const privateDeclaration = privateDeclarations.get(declaration.node.name) !;
|
||||
if (privateDeclaration.node !== declaration.node) {
|
||||
|
Reference in New Issue
Block a user