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 304222014a
commit ea1e34c4dd
14 changed files with 58 additions and 28 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,
@ -231,10 +231,12 @@ const isUsedPipe = (decl: AnyUsedType): decl is UsedPipe =>
/**
* `DecoratorHandler` which handles the `@Component` annotation.
*/
export class ComponentDecoratorHandler
implements
DecoratorHandler<Decorator, ComponentAnalysisData, ComponentSymbol, ComponentResolutionData>
{
export class ComponentDecoratorHandler implements DecoratorHandler<
Decorator,
ComponentAnalysisData,
ComponentSymbol,
ComponentResolutionData
> {
constructor(
private reflector: ReflectionHost,
private evaluator: PartialEvaluator,

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,
@ -132,9 +132,12 @@ export interface DirectiveHandlerData {
resources: DirectiveResources;
}
export class DirectiveDecoratorHandler
implements DecoratorHandler<Decorator | null, DirectiveHandlerData, DirectiveSymbol, unknown>
{
export class DirectiveDecoratorHandler implements DecoratorHandler<
Decorator | null,
DirectiveHandlerData,
DirectiveSymbol,
unknown
> {
constructor(
private reflector: ReflectionHost,
private evaluator: PartialEvaluator,

View file

@ -12,6 +12,7 @@ import {
R3TargetBinder,
SelectorMatcher,
TmplAstElement,
MatchSource,
} from '@angular/compiler';
import ts from 'typescript';
@ -140,6 +141,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,
@ -20,7 +21,10 @@ import ts from 'typescript';
import {absoluteFrom, AbsoluteFsPath} from '../../file_system';
import {Reference} from '../../imports';
<<<<<<< HEAD
import {ClassPropertyMapping} from '../../metadata';
=======
>>>>>>> 773161ec0f (fixup! refactor(compiler): move matchSource into base metadata)
import {ClassDeclaration} from '../../reflection';
import {getDeclaration, makeProgram} from '../../testing';
import {ComponentMeta} from '../src/context';
@ -69,6 +73,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

@ -53,9 +53,9 @@ export interface InputOrOutput {
* Allows bidirectional querying of the mapping - looking up all inputs/outputs with a given
* property name, or mapping from a specific class property to its binding property name.
*/
export class ClassPropertyMapping<T extends InputOrOutput = InputOrOutput>
implements InputOutputPropertySet
{
export class ClassPropertyMapping<
T extends InputOrOutput = InputOrOutput,
> implements InputOutputPropertySet {
/**
* Mapping from class property names to the single `InputOrOutput` for that class property.
*/

View file

@ -14,7 +14,6 @@ import {
CompoundMetadataRegistry,
DirectiveMeta,
LocalMetadataRegistry,
MatchSource,
MetadataRegistry,
MetaKind,
PipeMeta,
@ -23,6 +22,7 @@ import {ClassDeclaration} from '../../reflection';
import {LocalModuleScope, ScopeData} from '../src/api';
import {DtsModuleScopeResolver} from '../src/dependency';
import {LocalModuleScopeRegistry} from '../src/local';
import {MatchSource} from '@angular/compiler';
function registerFakeRefs(registry: MetadataRegistry): {
[name: string]: Reference<ClassDeclaration>;

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(