diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 7c2d673034f7b..1f6d14489f920 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -16,6 +16,7 @@ import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from import {DependencyTracker} from '../../incremental/api'; import {IndexingContext} from '../../indexer'; import {ClassPropertyMapping, DirectiveMeta, DirectiveTypeCheckMeta, extractDirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata'; +import {flattenInheritedDirectiveMetadata} from '../../metadata/src/inheritance'; import {EnumValue, PartialEvaluator} from '../../partial_evaluator'; import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; import {ComponentScopeReader, LocalModuleScopeRegistry} from '../../scope'; @@ -30,7 +31,6 @@ import {createValueHasWrongTypeError, getDirectiveDiagnostics, getProviderDiagno import {extractDirectiveMetadata, parseFieldArrayValue} from './directive'; import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; -import {TypeCheckScopes} from './typecheck_scopes'; import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util'; const EMPTY_MAP = new Map(); @@ -95,7 +95,6 @@ export class ComponentDecoratorHandler implements private literalCache = new Map(); private elementSchemaRegistry = new DomElementSchemaRegistry(); - private typeCheckScopes = new TypeCheckScopes(this.scopeReader, this.metaReader); /** * During the asynchronous preanalyze phase, it's necessary to parse the template to extract @@ -424,15 +423,36 @@ export class ComponentDecoratorHandler implements return; } - const scope = this.typeCheckScopes.getTypeCheckScope(node); + const matcher = new SelectorMatcher(); + const pipes = new Map>>(); + let schemas: SchemaMetadata[] = []; + + const scope = this.scopeReader.getScopeForComponent(node); if (scope === 'error') { // Don't type-check components that had errors in their scopes. return; } - const binder = new R3TargetBinder(scope.matcher); + if (scope !== null) { + for (const meta of scope.compilation.directives) { + if (meta.selector !== null) { + const extMeta = flattenInheritedDirectiveMetadata(this.metaReader, meta.ref); + matcher.addSelectables(CssSelector.parse(meta.selector), extMeta); + } + } + for (const {name, ref} of scope.compilation.pipes) { + if (!ts.isClassDeclaration(ref.node)) { + throw new Error(`Unexpected non-class declaration ${ + ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`); + } + pipes.set(name, ref as Reference>); + } + schemas = scope.schemas; + } + + const binder = new R3TargetBinder(matcher); ctx.addTemplate( - new Reference(node), binder, meta.template.diagNodes, scope.pipes, scope.schemas, + new Reference(node), binder, meta.template.diagNodes, pipes, schemas, meta.template.sourceMapping, meta.template.file); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/typecheck_scopes.ts b/packages/compiler-cli/src/ngtsc/annotations/src/typecheck_scopes.ts deleted file mode 100644 index aada9e0df4e55..0000000000000 --- a/packages/compiler-cli/src/ngtsc/annotations/src/typecheck_scopes.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {CssSelector, SchemaMetadata, SelectorMatcher} from '@angular/compiler'; -import * as ts from 'typescript'; - -import {Reference} from '../../imports'; -import {DirectiveMeta, flattenInheritedDirectiveMetadata, MetadataReader} from '../../metadata'; -import {ClassDeclaration} from '../../reflection'; -import {ComponentScopeReader} from '../../scope'; - -/** - * The scope that is used for type-check code generation of a component template. - */ -export interface TypeCheckScope { - /** - * A `SelectorMatcher` instance that contains the flattened directive metadata of all directives - * that are in the compilation scope of the declaring NgModule. - */ - matcher: SelectorMatcher; - - /** - * The pipes that are available in the compilation scope. - */ - pipes: Map>>; - - /** - * The schemas that are used in this scope. - */ - schemas: SchemaMetadata[]; -} - -/** - * Computes scope information to be used in template type checking. - */ -export class TypeCheckScopes { - /** - * Cache of flattened directive metadata. Because flattened metadata is scope-invariant it's - * cached individually, such that all scopes refer to the same flattened metadata. - */ - private flattenedDirectiveMetaCache = new Map(); - - /** - * Cache of the computed type check scope per NgModule declaration. - */ - private scopeCache = new Map(); - - constructor(private scopeReader: ComponentScopeReader, private metaReader: MetadataReader) {} - - /** - * Computes the type-check scope information for the component declaration. If the NgModule - * contains an error, then 'error' is returned. If the component is not declared in any NgModule, - * an empty type-check scope is returned. - */ - getTypeCheckScope(node: ClassDeclaration): TypeCheckScope|'error' { - const matcher = new SelectorMatcher(); - const pipes = new Map>>(); - - const scope = this.scopeReader.getScopeForComponent(node); - if (scope === null) { - return {matcher, pipes, schemas: []}; - } else if (scope === 'error') { - return scope; - } - - if (this.scopeCache.has(scope.ngModule)) { - return this.scopeCache.get(scope.ngModule)!; - } - - for (const meta of scope.compilation.directives) { - if (meta.selector !== null) { - const extMeta = this.getInheritedDirectiveMetadata(meta.ref); - matcher.addSelectables(CssSelector.parse(meta.selector), extMeta); - } - } - - for (const {name, ref} of scope.compilation.pipes) { - if (!ts.isClassDeclaration(ref.node)) { - throw new Error(`Unexpected non-class declaration ${ - ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`); - } - pipes.set(name, ref as Reference>); - } - - const typeCheckScope: TypeCheckScope = {matcher, pipes, schemas: scope.schemas}; - this.scopeCache.set(scope.ngModule, typeCheckScope); - return typeCheckScope; - } - - private getInheritedDirectiveMetadata(ref: Reference): DirectiveMeta { - const clazz = ref.node; - if (this.flattenedDirectiveMetaCache.has(clazz)) { - return this.flattenedDirectiveMetaCache.get(clazz)!; - } - - const meta = flattenInheritedDirectiveMetadata(this.metaReader, ref); - this.flattenedDirectiveMetaCache.set(clazz, meta); - return meta; - } -} diff --git a/packages/compiler-cli/src/ngtsc/metadata/index.ts b/packages/compiler-cli/src/ngtsc/metadata/index.ts index 9ee4e1a977ac4..2f857eee0bc40 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/index.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/index.ts @@ -8,7 +8,6 @@ export * from './src/api'; export {DtsMetadataReader} from './src/dts'; -export {flattenInheritedDirectiveMetadata} from './src/inheritance'; export {CompoundMetadataRegistry, LocalMetadataRegistry, InjectableClassRegistry} from './src/registry'; export {extractDirectiveTypeCheckMeta, CompoundMetadataReader} from './src/util'; export {BindingPropertyName, ClassPropertyMapping, ClassPropertyName, InputOrOutput} from './src/property_mapping'; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts b/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts index b923de6e2a589..f5271f4351d32 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts @@ -26,9 +26,6 @@ export function flattenInheritedDirectiveMetadata( if (topMeta === null) { throw new Error(`Metadata not found for directive: ${dir.debugName}`); } - if (topMeta.baseClass === null) { - return topMeta; - } const coercedInputFields = new Set(); const undeclaredInputFields = new Set(); diff --git a/packages/compiler-cli/src/ngtsc/scope/src/local.ts b/packages/compiler-cli/src/ngtsc/scope/src/local.ts index da7f3aa9397c1..985058a157d98 100644 --- a/packages/compiler-cli/src/ngtsc/scope/src/local.ts +++ b/packages/compiler-cli/src/ngtsc/scope/src/local.ts @@ -26,7 +26,6 @@ export interface LocalNgModuleData { } export interface LocalModuleScope extends ExportScope { - ngModule: ClassDeclaration; compilation: ScopeData; reexports: Reexport[]|null; schemas: SchemaMetadata[]; @@ -434,8 +433,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop } // Finally, produce the `LocalModuleScope` with both the compilation and export scopes. - const scope: LocalModuleScope = { - ngModule: ngModule.ref.node, + const scope = { compilation: { directives: Array.from(compilationDirectives.values()), pipes: Array.from(compilationPipes.values()),