fix(ivy): allow relative imports of .d.ts files (#25080)
ngtsc used to assume that all .d.ts dependencies (that is, third party packages) were imported via an absolute module path. It turns out this assumption isn't valid; some build tools allow relative imports of other compilation units. In the absolute case, ngtsc assumes (and still does) that all referenced types are available through the entrypoint from which an @NgModule was imported. This commit adds support for relative imports, in which case ngtsc will use relative path resolution to determine the imports. PR Close #25080
This commit is contained in:
parent
13a0d527f6
commit
e0c0c44d99
|
@ -10,7 +10,7 @@ import {Expression, ExternalExpr, ExternalReference} from '@angular/compiler';
|
|||
import * as ts from 'typescript';
|
||||
|
||||
import {ReflectionHost} from '../../host';
|
||||
import {AbsoluteReference, Reference, reflectTypeEntityToDeclaration} from '../../metadata';
|
||||
import {AbsoluteReference, Reference, ResolvedReference, reflectTypeEntityToDeclaration} from '../../metadata';
|
||||
import {reflectIdentifierOfDeclaration, reflectNameOfDeclaration} from '../../metadata/src/reflector';
|
||||
|
||||
import {toR3Reference} from './util';
|
||||
|
@ -199,10 +199,6 @@ export class SelectorScopeRegistry {
|
|||
} else {
|
||||
// The module wasn't analyzed before, and probably has a precompiled ngModuleDef with a type
|
||||
// annotation that specifies the needed metadata.
|
||||
if (ngModuleImportedFrom === null) {
|
||||
// TODO(alxhub): handle hand-compiled ngModuleDef in the current Program.
|
||||
throw new Error(`Need to read .d.ts module but ngModuleImportedFrom is unspecified`);
|
||||
}
|
||||
data = this._readMetadataFromCompiledClass(node, ngModuleImportedFrom);
|
||||
// Note that data here could still be null, if the class didn't have a precompiled
|
||||
// ngModuleDef.
|
||||
|
@ -267,7 +263,7 @@ export class SelectorScopeRegistry {
|
|||
* @param ngModuleImportedFrom module specifier of the import path to assume for all declarations
|
||||
* stemming from this module.
|
||||
*/
|
||||
private _readMetadataFromCompiledClass(clazz: ts.Declaration, ngModuleImportedFrom: string):
|
||||
private _readMetadataFromCompiledClass(clazz: ts.Declaration, ngModuleImportedFrom: string|null):
|
||||
ModuleData|null {
|
||||
// This operation is explicitly not memoized, as it depends on `ngModuleImportedFrom`.
|
||||
// TODO(alxhub): investigate caching of .d.ts module metadata.
|
||||
|
@ -348,7 +344,8 @@ export class SelectorScopeRegistry {
|
|||
* This operation assumes that these types should be imported from `ngModuleImportedFrom` unless
|
||||
* they themselves were imported from another absolute path.
|
||||
*/
|
||||
private _extractReferencesFromType(def: ts.TypeNode, ngModuleImportedFrom: string): Reference[] {
|
||||
private _extractReferencesFromType(def: ts.TypeNode, ngModuleImportedFrom: string|null):
|
||||
Reference[] {
|
||||
if (!ts.isTupleTypeNode(def)) {
|
||||
return [];
|
||||
}
|
||||
|
@ -357,11 +354,16 @@ export class SelectorScopeRegistry {
|
|||
throw new Error(`Expected TypeQueryNode`);
|
||||
}
|
||||
const type = element.exprName;
|
||||
if (ngModuleImportedFrom !== null) {
|
||||
const {node, from} = reflectTypeEntityToDeclaration(type, this.checker);
|
||||
const moduleName = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom);
|
||||
const clazz = node as ts.Declaration;
|
||||
const id = reflectIdentifierOfDeclaration(clazz);
|
||||
const id = reflectIdentifierOfDeclaration(node);
|
||||
return new AbsoluteReference(node, id !, moduleName, id !.text);
|
||||
} else {
|
||||
const {node} = reflectTypeEntityToDeclaration(type, this.checker);
|
||||
const id = reflectIdentifierOfDeclaration(node);
|
||||
return new ResolvedReference(node, id !);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
*/
|
||||
|
||||
export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration} from './src/reflector';
|
||||
export {AbsoluteReference, ImportMode, Reference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver';
|
||||
export {AbsoluteReference, ImportMode, Reference, ResolvedReference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver';
|
||||
|
|
Loading…
Reference in New Issue