feat(ivy): use fileNameToModuleName to emit imports when it's available (#28523)
The ultimate goal of this commit is to make use of fileNameToModuleName to get the module specifier to use when generating an import, when that API is available in the CompilerHost that ngtsc is created with. As part of getting there, the way in which ngtsc tracks references and generates import module specifiers is refactored considerably. References are tracked with the Reference class, and previously ngtsc had several different kinds of Reference. An AbsoluteReference represented a declaration which needed to be imported via an absolute module specifier tracked in the AbsoluteReference, and a RelativeReference represented a declaration from the local program, imported via relative path or referred to directly by identifier if possible. Thus, how to refer to a particular declaration was encoded into the Reference type _at the time of creation of the Reference_. This commit refactors that logic and reduces Reference to a single class with no subclasses. A Reference represents a node being referenced, plus context about how the node was located. This context includes a "bestGuessOwningModule", the compiler's best guess at which absolute module specifier has defined this reference. For example, if the compiler arrives at the declaration of CommonModule via an import to @angular/common, then any references obtained from CommonModule (e.g. NgIf) will also be considered to be owned by @angular/common. A ReferenceEmitter class and accompanying ReferenceEmitStrategy interface are introduced. To produce an Expression referring to a given Reference'd node, the ReferenceEmitter consults a sequence of ReferenceEmitStrategy implementations. Several different strategies are defined: - LocalIdentifierStrategy: use local ts.Identifiers if available. - AbsoluteModuleStrategy: if the Reference has a bestGuessOwningModule, import the node via an absolute import from that module specifier. - LogicalProjectStrategy: if the Reference is in the logical project (is under the project rootDirs), import the node via a relative import. - FileToModuleStrategy: use a FileToModuleHost to generate the module specifier by which to import the node. Depending on the availability of fileNameToModuleName in the CompilerHost, then, a different collection of these strategies is used for compilation. PR Close #28523
This commit is contained in:

committed by
Misko Hevery

parent
a529f53031
commit
423b39e216
@ -12,7 +12,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {CycleAnalyzer} from '../../cycles';
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {ModuleResolver, ResolvedReference} from '../../imports';
|
||||
import {ModuleResolver, Reference} from '../../imports';
|
||||
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||
import {Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
|
||||
@ -225,7 +225,7 @@ export class ComponentDecoratorHandler implements
|
||||
// If the component has a selector, it should be registered with the `SelectorScopeRegistry` so
|
||||
// when this component appears in an `@NgModule` scope, its selector can be determined.
|
||||
if (metadata.selector !== null) {
|
||||
const ref = new ResolvedReference(node, node.name !);
|
||||
const ref = new Reference(node);
|
||||
this.scopeRegistry.registerDirective(node, {
|
||||
ref,
|
||||
name: node.name !.text,
|
||||
|
@ -10,7 +10,7 @@ import {ConstantPool, Expression, ParseError, R3DirectiveMetadata, R3QueryMetada
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {Reference, ResolvedReference} from '../../imports';
|
||||
import {Reference} from '../../imports';
|
||||
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
|
||||
import {ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
|
||||
@ -57,7 +57,7 @@ export class DirectiveDecoratorHandler implements
|
||||
// If the directive has a selector, it should be registered with the `SelectorScopeRegistry` so
|
||||
// when this directive appears in an `@NgModule` scope, its selector can be determined.
|
||||
if (analysis && analysis.selector !== null) {
|
||||
let ref = new ResolvedReference(node, node.name !);
|
||||
const ref = new Reference(node);
|
||||
this.scopeRegistry.registerDirective(node, {
|
||||
ref,
|
||||
directive: ref,
|
||||
|
@ -10,11 +10,12 @@ import {Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, R3Identi
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {Reference, ResolvedReference} from '../../imports';
|
||||
import {Reference, ReferenceEmitter} from '../../imports';
|
||||
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
|
||||
import {Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection';
|
||||
import {NgModuleRouteAnalyzer} from '../../routing';
|
||||
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
|
||||
import {getSourceFile} from '../../util/src/typescript';
|
||||
|
||||
import {generateSetClassMetadataCall} from './metadata';
|
||||
import {ReferencesRegistry} from './references_registry';
|
||||
@ -37,7 +38,8 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
constructor(
|
||||
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
|
||||
private scopeRegistry: SelectorScopeRegistry, private referencesRegistry: ReferencesRegistry,
|
||||
private isCore: boolean, private routeAnalyzer: NgModuleRouteAnalyzer|null) {}
|
||||
private isCore: boolean, private routeAnalyzer: NgModuleRouteAnalyzer|null,
|
||||
private refEmitter: ReferenceEmitter) {}
|
||||
|
||||
readonly precedence = HandlerPrecedence.PRIMARY;
|
||||
|
||||
@ -177,10 +179,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
if (analysis.metadataStmt !== null) {
|
||||
ngModuleStatements.push(analysis.metadataStmt);
|
||||
}
|
||||
let context = node.getSourceFile();
|
||||
if (context === undefined) {
|
||||
context = ts.getOriginalNode(node).getSourceFile();
|
||||
}
|
||||
const context = getSourceFile(node);
|
||||
for (const decl of analysis.declarations) {
|
||||
if (this.scopeRegistry.requiresRemoteScope(decl.node)) {
|
||||
const scope = this.scopeRegistry.lookupCompilationScopeAsRefs(decl.node);
|
||||
@ -190,11 +189,11 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
const directives: Expression[] = [];
|
||||
const pipes: Expression[] = [];
|
||||
scope.directives.forEach(
|
||||
(directive, _) => { directives.push(directive.ref.toExpression(context) !); });
|
||||
scope.pipes.forEach(pipe => pipes.push(pipe.toExpression(context) !));
|
||||
(directive, _) => { directives.push(this.refEmitter.emit(directive.ref, context) !); });
|
||||
scope.pipes.forEach(pipe => pipes.push(this.refEmitter.emit(pipe, context) !));
|
||||
const directiveArray = new LiteralArrayExpr(directives);
|
||||
const pipesArray = new LiteralArrayExpr(pipes);
|
||||
const declExpr = decl.toExpression(context) !;
|
||||
const declExpr = this.refEmitter.emit(decl, context) !;
|
||||
const setComponentScope = new ExternalExpr(R3Identifiers.setComponentScope);
|
||||
const callExpr =
|
||||
new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]);
|
||||
@ -221,15 +220,15 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
private _toR3Reference(
|
||||
valueRef: Reference<ts.Declaration>, valueContext: ts.SourceFile,
|
||||
typeContext: ts.SourceFile): R3Reference {
|
||||
if (!(valueRef instanceof ResolvedReference)) {
|
||||
return toR3Reference(valueRef, valueRef, valueContext, valueContext);
|
||||
if (valueRef.hasOwningModuleGuess) {
|
||||
return toR3Reference(valueRef, valueRef, valueContext, valueContext, this.refEmitter);
|
||||
} else {
|
||||
let typeRef = valueRef;
|
||||
let typeNode = this.reflector.getDtsDeclaration(typeRef.node);
|
||||
if (typeNode !== null && ts.isClassDeclaration(typeNode)) {
|
||||
typeRef = new ResolvedReference(typeNode, typeNode.name !);
|
||||
typeRef = new Reference(typeNode);
|
||||
}
|
||||
return toR3Reference(valueRef, typeRef, valueContext, typeContext);
|
||||
return toR3Reference(valueRef, typeRef, valueContext, typeContext, this.refEmitter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,10 +327,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||
// Recurse into nested arrays.
|
||||
refList.push(...this.resolveTypeList(expr, entry, name));
|
||||
} else if (isDeclarationReference(entry)) {
|
||||
if (!entry.expressable) {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `One entry in ${name} is not a type`);
|
||||
} else if (!this.reflector.isClass(entry.node)) {
|
||||
if (!this.reflector.isClass(entry.node)) {
|
||||
throw new FatalDiagnosticError(
|
||||
ErrorCode.VALUE_HAS_WRONG_TYPE, entry.node,
|
||||
`Entry is not a type, but is used as such in ${name} array`);
|
||||
|
@ -9,7 +9,7 @@
|
||||
import {Expression, WrappedNodeExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteReference, Reference, ReferenceResolver, ResolvedReference} from '../../imports';
|
||||
import {Reference, ReferenceEmitter} from '../../imports';
|
||||
import {ReflectionHost, reflectIdentifierOfDeclaration, reflectNameOfDeclaration, reflectTypeEntityToDeclaration} from '../../reflection';
|
||||
import {TypeCheckableDirectiveMeta} from '../../typecheck';
|
||||
|
||||
@ -96,7 +96,7 @@ export class SelectorScopeRegistry {
|
||||
|
||||
constructor(
|
||||
private checker: ts.TypeChecker, private reflector: ReflectionHost,
|
||||
private resolver: ReferenceResolver) {}
|
||||
private refEmitter: ReferenceEmitter) {}
|
||||
|
||||
/**
|
||||
* Register a module's metadata with the registry.
|
||||
@ -224,7 +224,7 @@ export class SelectorScopeRegistry {
|
||||
*/
|
||||
lookupCompilationScope(node: ts.Declaration): CompilationScope<Expression>|null {
|
||||
const scope = this.lookupCompilationScopeAsRefs(node);
|
||||
return scope !== null ? convertScopeToExpressions(scope, node) : null;
|
||||
return scope !== null ? convertScopeToExpressions(scope, node, this.refEmitter) : null;
|
||||
}
|
||||
|
||||
private lookupScopesOrDie(
|
||||
@ -273,20 +273,20 @@ export class SelectorScopeRegistry {
|
||||
// Expand imports to the exported scope of those imports.
|
||||
...flatten(data.imports.map(
|
||||
ref =>
|
||||
this.lookupScopesOrDie(ref.node as ts.Declaration, absoluteModuleName(ref), context)
|
||||
this.lookupScopesOrDie(ref.node as ts.Declaration, ref.ownedByModuleGuess, context)
|
||||
.exported)),
|
||||
// And include the compilation scope of exported modules.
|
||||
...flatten(
|
||||
data.exports
|
||||
.map(
|
||||
ref => this.lookupScopes(
|
||||
ref.node as ts.Declaration, absoluteModuleName(ref), context))
|
||||
ref.node as ts.Declaration, ref.ownedByModuleGuess, context))
|
||||
.filter((scope: SelectorScopes | null): scope is SelectorScopes => scope !== null)
|
||||
.map(scope => scope.exported))
|
||||
],
|
||||
exported: flatten(data.exports.map(ref => {
|
||||
const scope =
|
||||
this.lookupScopes(ref.node as ts.Declaration, absoluteModuleName(ref), context);
|
||||
this.lookupScopes(ref.node as ts.Declaration, ref.ownedByModuleGuess, context);
|
||||
if (scope !== null) {
|
||||
return scope.exported;
|
||||
} else {
|
||||
@ -438,11 +438,11 @@ export class SelectorScopeRegistry {
|
||||
const type = element.exprName;
|
||||
if (ngModuleImportedFrom !== null) {
|
||||
const {node, from} = reflectTypeEntityToDeclaration(type, this.checker);
|
||||
const moduleName = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom);
|
||||
return this.resolver.resolve(node, moduleName, resolutionContext);
|
||||
const specifier = (from !== null && !from.startsWith('.') ? from : ngModuleImportedFrom);
|
||||
return new Reference(node, {specifier, resolutionContext});
|
||||
} else {
|
||||
const {node} = reflectTypeEntityToDeclaration(type, this.checker);
|
||||
return this.resolver.resolve(node, null, resolutionContext);
|
||||
return new Reference(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -455,17 +455,11 @@ function flatten<T>(array: T[][]): T[] {
|
||||
}, [] as T[]);
|
||||
}
|
||||
|
||||
function absoluteModuleName(ref: Reference): string|null {
|
||||
if (!(ref instanceof AbsoluteReference)) {
|
||||
return null;
|
||||
}
|
||||
return ref.moduleName;
|
||||
}
|
||||
|
||||
function convertDirectiveReferenceList(
|
||||
input: ScopeDirective<Reference>[], context: ts.SourceFile): ScopeDirective<Expression>[] {
|
||||
input: ScopeDirective<Reference>[], context: ts.SourceFile,
|
||||
refEmitter: ReferenceEmitter): ScopeDirective<Expression>[] {
|
||||
return input.map(meta => {
|
||||
const directive = meta.directive.toExpression(context);
|
||||
const directive = refEmitter.emit(meta.directive, context);
|
||||
if (directive === null) {
|
||||
throw new Error(`Could not write expression to reference ${meta.directive.node}`);
|
||||
}
|
||||
@ -474,10 +468,11 @@ function convertDirectiveReferenceList(
|
||||
}
|
||||
|
||||
function convertPipeReferenceMap(
|
||||
map: Map<string, Reference>, context: ts.SourceFile): Map<string, Expression> {
|
||||
map: Map<string, Reference>, context: ts.SourceFile,
|
||||
refEmitter: ReferenceEmitter): Map<string, Expression> {
|
||||
const newMap = new Map<string, Expression>();
|
||||
map.forEach((meta, selector) => {
|
||||
const pipe = meta.toExpression(context);
|
||||
const pipe = refEmitter.emit(meta, context);
|
||||
if (pipe === null) {
|
||||
throw new Error(`Could not write expression to reference ${meta.node}`);
|
||||
}
|
||||
@ -487,10 +482,11 @@ function convertPipeReferenceMap(
|
||||
}
|
||||
|
||||
function convertScopeToExpressions(
|
||||
scope: CompilationScope<Reference>, context: ts.Declaration): CompilationScope<Expression> {
|
||||
scope: CompilationScope<Reference>, context: ts.Declaration,
|
||||
refEmitter: ReferenceEmitter): CompilationScope<Expression> {
|
||||
const sourceContext = ts.getOriginalNode(context).getSourceFile();
|
||||
const directives = convertDirectiveReferenceList(scope.directives, sourceContext);
|
||||
const pipes = convertPipeReferenceMap(scope.pipes, sourceContext);
|
||||
const directives = convertDirectiveReferenceList(scope.directives, sourceContext, refEmitter);
|
||||
const pipes = convertPipeReferenceMap(scope.pipes, sourceContext, refEmitter);
|
||||
const declPointer = maybeUnwrapNameOfDeclaration(context);
|
||||
let containsForwardDecls = false;
|
||||
directives.forEach(meta => {
|
||||
|
@ -10,7 +10,7 @@ import {R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNode
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {AbsoluteReference, ImportMode, Reference} from '../../imports';
|
||||
import {ImportMode, Reference, ReferenceEmitter} from '../../imports';
|
||||
import {ClassMemberKind, CtorParameter, Decorator, ReflectionHost} from '../../reflection';
|
||||
|
||||
export enum ConstructorDepErrorKind {
|
||||
@ -119,9 +119,9 @@ export function validateConstructorDependencies(
|
||||
|
||||
export function toR3Reference(
|
||||
valueRef: Reference, typeRef: Reference, valueContext: ts.SourceFile,
|
||||
typeContext: ts.SourceFile): R3Reference {
|
||||
const value = valueRef.toExpression(valueContext, ImportMode.UseExistingImport);
|
||||
const type = typeRef.toExpression(typeContext, ImportMode.ForceNewImport);
|
||||
typeContext: ts.SourceFile, refEmitter: ReferenceEmitter): R3Reference {
|
||||
const value = refEmitter.emit(valueRef, valueContext, ImportMode.UseExistingImport);
|
||||
const type = refEmitter.emit(typeRef, typeContext, ImportMode.ForceNewImport);
|
||||
if (value === null || type === null) {
|
||||
throw new Error(`Could not refer to ${ts.SyntaxKind[valueRef.node.kind]}`);
|
||||
}
|
||||
@ -133,8 +133,7 @@ export function isAngularCore(decorator: Decorator): boolean {
|
||||
}
|
||||
|
||||
export function isAngularCoreReference(reference: Reference, symbolName: string) {
|
||||
return reference instanceof AbsoluteReference && reference.moduleName === '@angular/core' &&
|
||||
reference.symbolName === symbolName;
|
||||
return reference.ownedByModuleGuess === '@angular/core' && reference.debugName === symbolName;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -209,8 +208,7 @@ export function unwrapForwardRef(node: ts.Expression, reflector: ReflectionHost)
|
||||
export function forwardRefResolver(
|
||||
ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration>,
|
||||
args: ts.Expression[]): ts.Expression|null {
|
||||
if (!(ref instanceof AbsoluteReference) || ref.moduleName !== '@angular/core' ||
|
||||
ref.symbolName !== 'forwardRef' || args.length !== 1) {
|
||||
if (!isAngularCoreReference(ref, 'forwardRef') || args.length !== 1) {
|
||||
return null;
|
||||
}
|
||||
return expandForwardRef(args[0]);
|
||||
|
@ -16,9 +16,11 @@ ts_library(
|
||||
"//packages/compiler-cli/src/ngtsc/diagnostics",
|
||||
"//packages/compiler-cli/src/ngtsc/imports",
|
||||
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
|
||||
"//packages/compiler-cli/src/ngtsc/path",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/testing",
|
||||
"//packages/compiler-cli/src/ngtsc/translator",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@ngdeps//typescript",
|
||||
],
|
||||
)
|
||||
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
||||
|
||||
import {CycleAnalyzer, ImportGraph} from '../../cycles';
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||
import {ModuleResolver, TsReferenceResolver} from '../../imports';
|
||||
import {ModuleResolver, ReferenceEmitter} from '../../imports';
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
||||
@ -44,15 +44,15 @@ describe('ComponentDecoratorHandler', () => {
|
||||
]);
|
||||
const checker = program.getTypeChecker();
|
||||
const reflectionHost = new TypeScriptReflectionHost(checker);
|
||||
const resolver = new TsReferenceResolver(program, checker, options, host);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker, resolver);
|
||||
const evaluator = new PartialEvaluator(reflectionHost, checker);
|
||||
const moduleResolver = new ModuleResolver(program, options, host);
|
||||
const importGraph = new ImportGraph(moduleResolver);
|
||||
const cycleAnalyzer = new CycleAnalyzer(importGraph);
|
||||
|
||||
const handler = new ComponentDecoratorHandler(
|
||||
reflectionHost, evaluator, new SelectorScopeRegistry(checker, reflectionHost, resolver),
|
||||
false, new NoopResourceLoader(), [''], false, true, moduleResolver, cycleAnalyzer);
|
||||
reflectionHost, evaluator,
|
||||
new SelectorScopeRegistry(checker, reflectionHost, new ReferenceEmitter([])), false,
|
||||
new NoopResourceLoader(), [''], false, true, moduleResolver, cycleAnalyzer);
|
||||
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', ts.isClassDeclaration);
|
||||
const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp));
|
||||
if (detected === undefined) {
|
||||
|
@ -8,9 +8,11 @@
|
||||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteReference, ResolvedReference, TsReferenceResolver} from '../../imports';
|
||||
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, Reference, ReferenceEmitter} from '../../imports';
|
||||
import {LogicalFileSystem} from '../../path';
|
||||
import {TypeScriptReflectionHost} from '../../reflection';
|
||||
import {getDeclaration, makeProgram} from '../../testing/in_memory_typescript';
|
||||
import {getRootDirs} from '../../util/src/typescript';
|
||||
import {SelectorScopeRegistry} from '../src/selector_scope';
|
||||
|
||||
describe('SelectorScopeRegistry', () => {
|
||||
@ -63,18 +65,19 @@ describe('SelectorScopeRegistry', () => {
|
||||
expect(ProgramModule).toBeDefined();
|
||||
expect(SomeModule).toBeDefined();
|
||||
|
||||
const ProgramCmpRef = new ResolvedReference(ProgramCmp, ProgramCmp.name !);
|
||||
|
||||
const resolver = new TsReferenceResolver(program, checker, options, host);
|
||||
const registry = new SelectorScopeRegistry(checker, reflectionHost, resolver);
|
||||
const ProgramCmpRef = new Reference(ProgramCmp);
|
||||
const refEmitter = makeReferenceEmitter(program, checker, options, host);
|
||||
const registry = new SelectorScopeRegistry(checker, reflectionHost, refEmitter);
|
||||
|
||||
registry.registerModule(ProgramModule, {
|
||||
declarations: [new ResolvedReference(ProgramCmp, ProgramCmp.name !)],
|
||||
declarations: [new Reference(ProgramCmp)],
|
||||
exports: [],
|
||||
imports: [new AbsoluteReference(SomeModule, SomeModule.name !, 'some_library', 'SomeModule')],
|
||||
imports: [new Reference(
|
||||
SomeModule,
|
||||
{specifier: 'some_library', resolutionContext: '/node_modules/some_library/index.d.ts'})],
|
||||
});
|
||||
|
||||
const ref = new ResolvedReference(ProgramCmp, ProgramCmp.name !);
|
||||
const ref = new Reference(ProgramCmp);
|
||||
registry.registerDirective(ProgramCmp, {
|
||||
name: 'ProgramCmp',
|
||||
ref: ProgramCmpRef,
|
||||
@ -136,14 +139,15 @@ describe('SelectorScopeRegistry', () => {
|
||||
expect(ProgramModule).toBeDefined();
|
||||
expect(SomeModule).toBeDefined();
|
||||
|
||||
const ProgramCmpRef = new ResolvedReference(ProgramCmp, ProgramCmp.name !);
|
||||
|
||||
const resolver = new TsReferenceResolver(program, checker, options, host);
|
||||
const registry = new SelectorScopeRegistry(checker, reflectionHost, resolver);
|
||||
const ProgramCmpRef = new Reference(ProgramCmp);
|
||||
const refEmitter = makeReferenceEmitter(program, checker, options, host);
|
||||
const registry = new SelectorScopeRegistry(checker, reflectionHost, refEmitter);
|
||||
|
||||
registry.registerModule(ProgramModule, {
|
||||
declarations: [new ResolvedReference(ProgramCmp, ProgramCmp.name !)],
|
||||
exports: [new AbsoluteReference(SomeModule, SomeModule.name !, 'some_library', 'SomeModule')],
|
||||
declarations: [new Reference(ProgramCmp)],
|
||||
exports: [new Reference(
|
||||
SomeModule,
|
||||
{specifier: 'some_library', resolutionContext: '/node_modules/some_library/index.d.ts'})],
|
||||
imports: [],
|
||||
});
|
||||
|
||||
@ -166,4 +170,15 @@ describe('SelectorScopeRegistry', () => {
|
||||
expect(scope.directives).toBeDefined();
|
||||
expect(scope.directives.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function makeReferenceEmitter(
|
||||
program: ts.Program, checker: ts.TypeChecker, options: ts.CompilerOptions,
|
||||
host: ts.CompilerHost): ReferenceEmitter {
|
||||
const rootDirs = getRootDirs(host, options);
|
||||
return new ReferenceEmitter([
|
||||
new LocalIdentifierStrategy(),
|
||||
new AbsoluteModuleStrategy(program, checker, options, host),
|
||||
new LogicalProjectStrategy(checker, new LogicalFileSystem(rootDirs)),
|
||||
]);
|
||||
}
|
||||
|
Reference in New Issue
Block a user