refactor(compiler): move matchSource into base metadata

Moves the `matchSource` into the base metadata so the binder can use it.
This commit is contained in:
Kristiyan Kostadinov 2026-04-01 10:46:42 +02:00 committed by Andrew Scott
parent 4651b93a92
commit 927ae3abc8
12 changed files with 39 additions and 17 deletions

View file

@ -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,

View file

@ -14,6 +14,7 @@ import {
ConstantPool,
FactoryTarget,
makeBindingParser,
MatchSource,
R3ClassMetadata,
R3DirectiveMetadata,
R3TargetBinder,
@ -33,7 +34,6 @@ import {
extractDirectiveTypeCheckMeta,
HostDirectiveMeta,
InputMapping,
MatchSource,
MetadataReader,
MetadataRegistry,
MetaKind,

View file

@ -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]);

View file

@ -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<ComponentMeta>;

View file

@ -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;

View file

@ -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,

View file

@ -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';

View file

@ -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;

View file

@ -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<ClassDeclaration>),
isGeneric: dir.isGeneric,

View file

@ -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

View file

@ -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,
}
/**

View file

@ -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<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
matcher.addSelectables(CssSelector.parse('[dir]'), [
@ -58,6 +59,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
matcher.addSelectables(CssSelector.parse('[hasOutput]'), [
@ -72,6 +74,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
matcher.addSelectables(CssSelector.parse('[hasInput]'), [
@ -86,6 +89,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
matcher.addSelectables(CssSelector.parse('[sameSelectorAsInput]'), [
@ -100,6 +104,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
matcher.addSelectables(CssSelector.parse('comp'), [
@ -114,6 +119,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
animationTriggerNames: null,
ngContentSelectors: null,
preserveWhitespaces: false,
matchSource: MatchSource.Selector,
},
]);
@ -133,6 +139,7 @@ function makeSelectorMatcher(): SelectorMatcher<DirectiveMeta[]> {
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(