From 927ae3abc805ebe41c3350cdca978b520208bd04 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Wed, 1 Apr 2026 10:46:42 +0200 Subject: [PATCH] refactor(compiler): move matchSource into base metadata Moves the `matchSource` into the base metadata so the binder can use it. --- .../src/ngtsc/annotations/component/src/handler.ts | 2 +- .../src/ngtsc/annotations/directive/src/handler.ts | 2 +- .../annotations/directive/test/directive_spec.ts | 2 ++ .../compiler-cli/src/ngtsc/indexer/test/util.ts | 2 ++ .../compiler-cli/src/ngtsc/metadata/src/api.ts | 12 +----------- .../compiler-cli/src/ngtsc/metadata/src/dts.ts | 2 +- .../ngtsc/metadata/src/host_directives_resolver.ts | 3 ++- .../compiler-cli/src/ngtsc/typecheck/api/api.ts | 2 ++ .../src/ngtsc/typecheck/src/tcb_adapter.ts | 1 + .../src/ngtsc/typecheck/testing/index.ts | 3 ++- packages/compiler/src/render3/view/t2_api.ts | 14 ++++++++++++++ .../compiler/test/render3/view/binding_spec.ts | 11 ++++++++++- 12 files changed, 39 insertions(+), 17 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index 98d844df6f7..5246e41c23f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -42,6 +42,7 @@ import { ViewEncapsulation, DirectiveMatcher, SelectorlessMatcher, + MatchSource, } from '@angular/compiler'; import ts from 'typescript'; @@ -73,7 +74,6 @@ import { DirectiveMeta, extractDirectiveTypeCheckMeta, HostDirectivesResolver, - MatchSource, MetadataReader, MetadataRegistry, MetaKind, diff --git a/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts index aa8fae7f8d0..57ce2e4fabc 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts @@ -14,6 +14,7 @@ import { ConstantPool, FactoryTarget, makeBindingParser, + MatchSource, R3ClassMetadata, R3DirectiveMetadata, R3TargetBinder, @@ -33,7 +34,6 @@ import { extractDirectiveTypeCheckMeta, HostDirectiveMeta, InputMapping, - MatchSource, MetadataReader, MetadataRegistry, MetaKind, diff --git a/packages/compiler-cli/src/ngtsc/annotations/directive/test/directive_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/directive/test/directive_spec.ts index 41b8d0c00ad..cd03b5d7b91 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/directive/test/directive_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/directive/test/directive_spec.ts @@ -12,6 +12,7 @@ import { R3TargetBinder, SelectorMatcher, TmplAstElement, + MatchSource, } from '@angular/compiler'; import ts from 'typescript'; @@ -137,6 +138,7 @@ runInEachFileSystem(() => { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }; matcher.addSelectables(CssSelector.parse('[dir]'), [dirMeta]); diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/util.ts b/packages/compiler-cli/src/ngtsc/indexer/test/util.ts index f7626d05940..91390273e13 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/util.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/test/util.ts @@ -10,6 +10,7 @@ import { BoundTarget, CssSelector, DirectiveMatcher, + MatchSource, parseTemplate, ParseTemplateOptions, R3TargetBinder, @@ -69,6 +70,7 @@ export function getBoundTemplate( animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, })); let matcher: DirectiveMatcher; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/api.ts b/packages/compiler-cli/src/ngtsc/metadata/src/api.ts index b2d2b503d2f..c33c258a100 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/api.ts @@ -11,6 +11,7 @@ import { Expression, SchemaMetadata, ExternalReference, + MatchSource, } from '@angular/compiler'; import ts from 'typescript'; @@ -134,17 +135,6 @@ export enum MetaKind { NgModule, } -/** - * Possible ways that a directive can be matched. - */ -export enum MatchSource { - /** The directive was matched by its selector. */ - Selector, - - /** The directive was applied as a host directive. */ - HostDirective, -} - /** Metadata for a single input mapping. */ export type InputMapping = InputOrOutput & { required: boolean; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts b/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts index 7de2f035558..633982e8db1 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {MatchSource} from '@angular/compiler'; import ts from 'typescript'; import {OwningModule, Reference} from '../../imports'; @@ -21,7 +22,6 @@ import { DirectiveMeta, HostDirectiveMeta, InputMapping, - MatchSource, MetadataReader, MetaKind, NgModuleMeta, diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/host_directives_resolver.ts b/packages/compiler-cli/src/ngtsc/metadata/src/host_directives_resolver.ts index abb77c1b12e..e9c03a6979f 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/host_directives_resolver.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/host_directives_resolver.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.dev/license */ -import {DirectiveMeta, InputMapping, MatchSource, MetadataReader} from '../../metadata/src/api'; +import {MatchSource} from '@angular/compiler'; +import {DirectiveMeta, InputMapping, MetadataReader} from '../../metadata/src/api'; import {ClassDeclaration} from '../../reflection'; import {ClassPropertyMapping, InputOrOutput} from '../src/property_mapping'; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts index e34b9425979..aec6355ccb5 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts @@ -11,6 +11,7 @@ import { BoundTarget, DirectiveMeta, LegacyAnimationTriggerNames, + MatchSource, ParseSourceSpan, SchemaMetadata, } from '@angular/compiler'; @@ -88,6 +89,7 @@ export interface TcbDirectiveMetadata { isExplicitlyDeferred: boolean; preserveWhitespaces: boolean; exportAs: string[] | null; + matchSource: MatchSource; /** Type parameters of the directive, if available. */ typeParameters: TcbTypeParameter[] | null; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_adapter.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_adapter.ts index c97824bf1b8..fc697a282ca 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_adapter.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_adapter.ts @@ -111,6 +111,7 @@ export function adaptTypeCheckBlockMetadata( stringLiteralInputFields: dir.stringLiteralInputFields, undeclaredInputFields: dir.undeclaredInputFields, publicMethods: dir.publicMethods, + matchSource: dir.matchSource, ref: extractRef(dir.ref as Reference), isGeneric: dir.isGeneric, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts index 397bf1e6cdf..eaa917f436d 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts @@ -10,6 +10,7 @@ import { AST, BindingPipe, CssSelector, + MatchSource, ParseSourceFile, parseTemplate, ParseTemplateOptions, @@ -60,7 +61,6 @@ import { DirectiveMeta, HostDirectivesResolver, InputMapping, - MatchSource, MetadataReaderWithIndex, MetaKind, NgModuleIndex, @@ -913,6 +913,7 @@ function getDirectiveMetaFromDeclaration( isExplicitlyDeferred: false, imports: decl.imports, rawImports: null, + matchSource: MatchSource.Selector, hostDirectives: decl.hostDirectives === undefined ? null diff --git a/packages/compiler/src/render3/view/t2_api.ts b/packages/compiler/src/render3/view/t2_api.ts index b6629381b4f..c7406e9412d 100644 --- a/packages/compiler/src/render3/view/t2_api.ts +++ b/packages/compiler/src/render3/view/t2_api.ts @@ -156,6 +156,20 @@ export interface DirectiveMeta { * Only includes the legacy animation names. */ animationTriggerNames: LegacyAnimationTriggerNames | null; + + /** Tracks how the directive was matched. */ + matchSource: MatchSource; +} + +/** + * Possible ways that a directive can be matched. + */ +export enum MatchSource { + /** The directive was matched by its selector. */ + Selector, + + /** The directive was applied as a host directive. */ + HostDirective, } /** diff --git a/packages/compiler/test/render3/view/binding_spec.ts b/packages/compiler/test/render3/view/binding_spec.ts index 88fe7586ab9..a97ebe2546a 100644 --- a/packages/compiler/test/render3/view/binding_spec.ts +++ b/packages/compiler/test/render3/view/binding_spec.ts @@ -8,7 +8,7 @@ import * as e from '../../../src/expression_parser/ast'; import * as a from '../../../src/render3/r3_ast'; -import {DirectiveMeta, InputOutputPropertySet} from '../../../src/render3/view/t2_api'; +import {DirectiveMeta, InputOutputPropertySet, MatchSource} from '../../../src/render3/view/t2_api'; import {findMatchingDirectivesAndPipes, R3TargetBinder} from '../../../src/render3/view/t2_binder'; import {parseTemplate, ParseTemplateOptions} from '../../../src/render3/view/template'; import {CssSelector, SelectorlessMatcher, SelectorMatcher} from '../../../src/directive_matching'; @@ -44,6 +44,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); matcher.addSelectables(CssSelector.parse('[dir]'), [ @@ -58,6 +59,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); matcher.addSelectables(CssSelector.parse('[hasOutput]'), [ @@ -72,6 +74,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); matcher.addSelectables(CssSelector.parse('[hasInput]'), [ @@ -86,6 +89,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); matcher.addSelectables(CssSelector.parse('[sameSelectorAsInput]'), [ @@ -100,6 +104,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); matcher.addSelectables(CssSelector.parse('comp'), [ @@ -114,6 +119,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); @@ -133,6 +139,7 @@ function makeSelectorMatcher(): SelectorMatcher { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); } @@ -282,6 +289,7 @@ describe('t2 binding', () => { animationTriggerNames: null, ngContentSelectors: null, preserveWhitespaces: false, + matchSource: MatchSource.Selector, }, ]); const binder = new R3TargetBinder(matcher); @@ -1039,6 +1047,7 @@ describe('t2 binding', () => { preserveWhitespaces: false, animationTriggerNames: null, isComponent: false, + matchSource: MatchSource.Selector, }; function makeSelectorlessMatcher(