From e0c0c44d997ef3deb9a021500c00e95466dcbdfb Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Thu, 26 Jul 2018 08:49:14 -0700 Subject: [PATCH] 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 --- .../ngtsc/annotations/src/selector_scope.ts | 26 ++++++++++--------- .../compiler-cli/src/ngtsc/metadata/index.ts | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts index 8927f24c84..f504411411 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/selector_scope.ts @@ -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; - 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); - return new AbsoluteReference(node, id !, moduleName, id !.text); + if (ngModuleImportedFrom !== null) { + const {node, from} = reflectTypeEntityToDeclaration(type, this.checker); + const moduleName = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom); + 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 !); + } }); } } diff --git a/packages/compiler-cli/src/ngtsc/metadata/index.ts b/packages/compiler-cli/src/ngtsc/metadata/index.ts index 3178a1376e..b15062c49d 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/index.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/index.ts @@ -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';