refactor(ivy): move metadata registration to its own package (#29698)

Previously, metadata registration (the recording of collected metadata
during analysis of directives, pipes, and NgModules) was only used to
produce the `LocalModuleScope`, and thus was handled by the
`LocalModuleScopeRegistry`.

However, the template type-checker also needs information about registered
directives, outside of the NgModule scope determinations. Rather than
reuse the scope registry for an unintended purpose, this commit introduces
new abstractions for metadata registration and lookups in a separate
'metadata' package, which the scope registry implements.

This paves the way for a future commit to make use of this metadata for the
template type-checking system.

Testing strategy: this commit is a refactoring which introduces no new
functionality, so existing tests are sufficient.

PR Close #29698
This commit is contained in:
Alex Rickabaugh
2019-03-26 14:02:16 -07:00
committed by Ben Lesh
parent 410151b07f
commit 9277afce61
27 changed files with 532 additions and 290 deletions

View File

@ -12,6 +12,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/cycles",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/reflection",
"//packages/compiler-cli/src/ngtsc/routing",

View File

@ -13,9 +13,10 @@ import * as ts from 'typescript';
import {CycleAnalyzer} from '../../cycles';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from '../../imports';
import {DirectiveMeta, MetadataRegistry, extractDirectiveGuards} from '../../metadata';
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
import {LocalModuleScopeRegistry, ScopeDirective, extractDirectiveGuards} from '../../scope';
import {LocalModuleScopeRegistry} from '../../scope';
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence, ResolveResult} from '../../transform';
import {TypeCheckContext} from '../../typecheck';
import {tsSourceMapBug29300Fixed} from '../../util/src/ts_source_map_bug_29300';
@ -41,14 +42,14 @@ export class ComponentDecoratorHandler implements
DecoratorHandler<ComponentHandlerData, Decorator> {
constructor(
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: LocalModuleScopeRegistry, private isCore: boolean,
private resourceLoader: ResourceLoader, private rootDirs: string[],
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[],
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean,
private moduleResolver: ModuleResolver, private cycleAnalyzer: CycleAnalyzer,
private refEmitter: ReferenceEmitter, private defaultImportRecorder: DefaultImportRecorder) {}
private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
private boundTemplateCache = new Map<ts.Declaration, BoundTarget<ScopeDirective>>();
private boundTemplateCache = new Map<ts.Declaration, BoundTarget<DirectiveMeta>>();
private elementSchemaRegistry = new DomElementSchemaRegistry();
/**
@ -211,7 +212,7 @@ export class ComponentDecoratorHandler implements
// determined.
if (metadata.selector !== null) {
const ref = new Reference(node);
this.scopeRegistry.registerDirective({
this.metaRegistry.registerDirectiveMetadata({
ref,
name: node.name.text,
selector: metadata.selector,
@ -220,6 +221,7 @@ export class ComponentDecoratorHandler implements
outputs: metadata.outputs,
queries: metadata.queries.map(query => query.propertyName),
isComponent: true, ...extractDirectiveGuards(node, this.reflector),
baseClass: null,
});
}
@ -302,7 +304,7 @@ export class ComponentDecoratorHandler implements
return;
}
const scope = this.scopeRegistry.getScopeForComponent(node);
const matcher = new SelectorMatcher<ScopeDirective>();
const matcher = new SelectorMatcher<DirectiveMeta>();
if (scope !== null) {
for (const meta of scope.compilation.directives) {
matcher.addSelectables(CssSelector.parse(meta.selector), meta);
@ -343,7 +345,7 @@ export class ComponentDecoratorHandler implements
// Set up the R3TargetBinder, as well as a 'directives' array and a 'pipes' map that are later
// fed to the TemplateDefinitionBuilder. First, a SelectorMatcher is constructed to match
// directives that are in scope.
const matcher = new SelectorMatcher<ScopeDirective&{expression: Expression}>();
const matcher = new SelectorMatcher<DirectiveMeta&{expression: Expression}>();
const directives: {selector: string, expression: Expression}[] = [];
for (const dir of scope.compilation.directives) {

View File

@ -11,10 +11,11 @@ import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {DefaultImportRecorder, Reference} from '../../imports';
import {MetadataRegistry} from '../../metadata';
import {extractDirectiveGuards} from '../../metadata/src/util';
import {DynamicValue, EnumValue, PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection';
import {LocalModuleScopeRegistry} from '../../scope/src/local';
import {extractDirectiveGuards} from '../../scope/src/util';
import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';
@ -30,8 +31,8 @@ export class DirectiveDecoratorHandler implements
DecoratorHandler<DirectiveHandlerData, Decorator> {
constructor(
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: LocalModuleScopeRegistry,
private defaultImportRecorder: DefaultImportRecorder, private isCore: boolean) {}
private metaRegistry: MetadataRegistry, private defaultImportRecorder: DefaultImportRecorder,
private isCore: boolean) {}
readonly precedence = HandlerPrecedence.PRIMARY;
@ -59,7 +60,7 @@ export class DirectiveDecoratorHandler implements
// when this directive appears in an `@NgModule` scope, its selector can be determined.
if (analysis && analysis.selector !== null) {
const ref = new Reference(node);
this.scopeRegistry.registerDirective({
this.metaRegistry.registerDirectiveMetadata({
ref,
name: node.name.text,
selector: analysis.selector,
@ -68,6 +69,7 @@ export class DirectiveDecoratorHandler implements
outputs: analysis.outputs,
queries: analysis.queries.map(query => query.propertyName),
isComponent: false, ...extractDirectiveGuards(node, this.reflector),
baseClass: null,
});
}

View File

@ -11,6 +11,7 @@ import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {DefaultImportRecorder, Reference, ReferenceEmitter} from '../../imports';
import {MetadataRegistry} from '../../metadata';
import {PartialEvaluator, ResolvedValue} from '../../partial_evaluator';
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral, typeNodeToValueExpr} from '../../reflection';
import {NgModuleRouteAnalyzer} from '../../routing';
@ -39,7 +40,7 @@ export interface NgModuleAnalysis {
export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalysis, Decorator> {
constructor(
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: LocalModuleScopeRegistry,
private metaRegistry: MetadataRegistry, private scopeRegistry: LocalModuleScopeRegistry,
private referencesRegistry: ReferencesRegistry, private isCore: boolean,
private routeAnalyzer: NgModuleRouteAnalyzer|null, private refEmitter: ReferenceEmitter,
private defaultImportRecorder: DefaultImportRecorder) {}
@ -134,8 +135,12 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
// during the compile() phase, the module's metadata is available for selector scope
// computation.
this.scopeRegistry.registerNgModule(
node, {declarations: declarationRefs, imports: importRefs, exports: exportRefs});
this.metaRegistry.registerNgModuleMetadata({
ref: new Reference(node),
declarations: declarationRefs,
imports: importRefs,
exports: exportRefs
});
const valueContext = node.getSourceFile();

View File

@ -11,6 +11,7 @@ import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {DefaultImportRecorder, Reference} from '../../imports';
import {MetadataRegistry} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
import {LocalModuleScopeRegistry} from '../../scope/src/local';
@ -27,8 +28,8 @@ export interface PipeHandlerData {
export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, Decorator> {
constructor(
private reflector: ReflectionHost, private evaluator: PartialEvaluator,
private scopeRegistry: LocalModuleScopeRegistry,
private defaultImportRecorder: DefaultImportRecorder, private isCore: boolean) {}
private metaRegistry: MetadataRegistry, private defaultImportRecorder: DefaultImportRecorder,
private isCore: boolean) {}
readonly precedence = HandlerPrecedence.PRIMARY;
@ -76,7 +77,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, D
ErrorCode.VALUE_HAS_WRONG_TYPE, pipeNameExpr, `@Pipe.name must be a string`);
}
const ref = new Reference(clazz);
this.scopeRegistry.registerPipe({ref, name: pipeName});
this.metaRegistry.registerPipeMetadata({ref, name: pipeName});
let pure = true;
if (pipe.has('pure')) {

View File

@ -15,6 +15,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/cycles",
"//packages/compiler-cli/src/ngtsc/diagnostics",
"//packages/compiler-cli/src/ngtsc/imports",
"//packages/compiler-cli/src/ngtsc/metadata",
"//packages/compiler-cli/src/ngtsc/partial_evaluator",
"//packages/compiler-cli/src/ngtsc/path",
"//packages/compiler-cli/src/ngtsc/reflection",

View File

@ -11,6 +11,7 @@ import * as ts from 'typescript';
import {CycleAnalyzer, ImportGraph} from '../../cycles';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {DtsMetadataReader, LocalMetadataRegistry} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
@ -48,14 +49,16 @@ describe('ComponentDecoratorHandler', () => {
const moduleResolver = new ModuleResolver(program, options, host);
const importGraph = new ImportGraph(moduleResolver);
const cycleAnalyzer = new CycleAnalyzer(importGraph);
const metaRegistry = new LocalMetadataRegistry();
const dtsReader = new DtsMetadataReader(checker, reflectionHost);
const scopeRegistry = new LocalModuleScopeRegistry(
new MetadataDtsModuleScopeResolver(checker, reflectionHost, null), new ReferenceEmitter([]),
metaRegistry, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]),
null);
const refEmitter = new ReferenceEmitter([]);
const handler = new ComponentDecoratorHandler(
reflectionHost, evaluator, scopeRegistry, false, new NoopResourceLoader(), [''], false,
true, moduleResolver, cycleAnalyzer, refEmitter, NOOP_DEFAULT_IMPORT_RECORDER);
reflectionHost, evaluator, metaRegistry, scopeRegistry, false, new NoopResourceLoader(),
[''], false, true, moduleResolver, cycleAnalyzer, refEmitter, NOOP_DEFAULT_IMPORT_RECORDER);
const TestCmp = getDeclaration(program, 'entry.ts', 'TestCmp', isNamedClassDeclaration);
const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp));
if (detected === undefined) {

View File

@ -9,6 +9,7 @@
import * as ts from 'typescript';
import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {DtsMetadataReader, LocalMetadataRegistry} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
@ -40,8 +41,10 @@ describe('DirectiveDecoratorHandler', () => {
const checker = program.getTypeChecker();
const reflectionHost = new TestReflectionHost(checker);
const evaluator = new PartialEvaluator(reflectionHost, checker);
const metaReader = new LocalMetadataRegistry();
const dtsReader = new DtsMetadataReader(checker, reflectionHost);
const scopeRegistry = new LocalModuleScopeRegistry(
new MetadataDtsModuleScopeResolver(checker, reflectionHost, null), new ReferenceEmitter([]),
metaReader, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]),
null);
const handler = new DirectiveDecoratorHandler(
reflectionHost, evaluator, scopeRegistry, NOOP_DEFAULT_IMPORT_RECORDER, false);

View File

@ -11,6 +11,7 @@ import {R3Reference} from '@angular/compiler/src/compiler';
import * as ts from 'typescript';
import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports';
import {DtsMetadataReader, LocalMetadataRegistry} from '../../metadata';
import {PartialEvaluator} from '../../partial_evaluator';
import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope';
@ -55,14 +56,16 @@ describe('NgModuleDecoratorHandler', () => {
const reflectionHost = new TypeScriptReflectionHost(checker);
const evaluator = new PartialEvaluator(reflectionHost, checker);
const referencesRegistry = new NoopReferencesRegistry();
const metaRegistry = new LocalMetadataRegistry();
const dtsReader = new DtsMetadataReader(checker, reflectionHost);
const scopeRegistry = new LocalModuleScopeRegistry(
new MetadataDtsModuleScopeResolver(checker, reflectionHost, null), new ReferenceEmitter([]),
metaRegistry, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]),
null);
const refEmitter = new ReferenceEmitter([new LocalIdentifierStrategy()]);
const handler = new NgModuleDecoratorHandler(
reflectionHost, evaluator, scopeRegistry, referencesRegistry, false, null, refEmitter,
NOOP_DEFAULT_IMPORT_RECORDER);
reflectionHost, evaluator, metaRegistry, scopeRegistry, referencesRegistry, false, null,
refEmitter, NOOP_DEFAULT_IMPORT_RECORDER);
const TestModule = getDeclaration(program, 'entry.ts', 'TestModule', isNamedClassDeclaration);
const detected =
handler.detect(TestModule, reflectionHost.getDecoratorsOfDeclaration(TestModule));