/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/core/src/render3/interfaces/definition.ts
626 строк
20 KB
Andrew Scott
refactor(core): ComponentDef should allow abstract types too
11 июн 2026, 23:08
11 июн 2026, 23:08
8984c59
Код
Авторство
О чём код?
/** * @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.dev/license */ import {InputSignalNode} from '../../authoring/input/input_signal_node'; import {ModuleWithProviders, ProcessProvidersFunction} from '../../di/interface/provider'; import {EnvironmentInjector} from '../../di/r3_injector'; import {AbstractType, Type} from '../../interface/type'; import {SchemaMetadata} from '../../metadata/schema'; import {ViewEncapsulation} from '../../metadata/view'; import {FactoryFn} from '../definition_factory'; import {TAttributes, TConstantsOrFactory} from './node'; import {CssSelectorList} from './projection'; import type {TView} from './view'; import type {ControlDirectiveDef} from './control'; /** * Definition of what a template rendering function should look like for a component. */ export type ComponentTemplate<T> = { // Note: the ctx parameter is typed as T|U, as using only U would prevent a template with // e.g. ctx: {} from being assigned to ComponentTemplate<any> as TypeScript won't infer U = any // in that scenario. By including T this incompatibility is resolved. <U extends T>(rf: RenderFlags, ctx: T | U): void; }; /** * Definition of what a view queries function should look like. */ export type ViewQueriesFunction<T> = <U extends T>(rf: RenderFlags, ctx: U) => void; /** Function that resolves providers and publishes them to the DI system. */ export type ProvidersResolver = ( def: DirectiveDef<unknown>, processProvidersFn?: ProcessProvidersFunction, ) => void; /** * Definition of what a content queries function should look like. */ export type ContentQueriesFunction<T> = <U extends T>( rf: RenderFlags, ctx: U, directiveIndex: number, ) => void; export interface ClassDebugInfo { className: string; filePath?: string; lineNumber?: number; forbidOrphanRendering?: boolean; } /** * Flags passed into template functions to determine which blocks (i.e. creation, update) * should be executed. * * Typically, a template runs both the creation block and the update block on initialization and * subsequent runs only execute the update block. However, dynamically created views require that * the creation block be executed separately from the update block (for backwards compat). */ export const enum RenderFlags { /* Whether to run the creation block (e.g. create elements and directives) */ Create = 0b01, /* Whether to run the update block (e.g. refresh bindings) */ Update = 0b10, } /** * A subclass of `Type` which has a static `ɵcmp`:`ComponentDef` field making it * consumable for rendering. */ export interface ComponentType<T> extends Type<T> { ɵcmp: unknown; } /** * A subclass of `Type` which has a static `ɵdir`:`DirectiveDef` field making it * consumable for rendering. */ export interface DirectiveType<T> extends Type<T> { ɵdir: unknown; ɵfac: unknown; } /** * A subclass of `Type` which has a static `ɵpipe`:`PipeDef` field making it * consumable for rendering. */ export interface PipeType<T> extends Type<T> { ɵpipe: unknown; } /** * Runtime link information for Directives. * * This is an internal data structure used by the render to link * directives into templates. * * NOTE: Always use `defineDirective` function to create this object, * never create the object directly since the shape of this object * can change between versions. * * @param Selector type metadata specifying the selector of the directive or component * * See: {@link defineDirective} */ export interface DirectiveDef<T> { /** * A dictionary mapping the inputs' public name to their minified property names * (along with flags if there are any). */ readonly inputs: Record< string, [minifiedName: string, flags: number, transform: InputTransformFunction | null] >; /** * Contains the raw input information produced by the compiler. Can be * used to do further processing after the `inputs` have been inverted. */ readonly inputConfig: { [P in keyof T]?: string | [number, string, string?, InputTransformFunction?]; }; /** * @deprecated This is only here because `NgOnChanges` incorrectly uses declared name instead of * public or minified name. */ readonly declaredInputs: Record<string, string>; /** * A dictionary mapping the outputs' minified property names to their public API names, which * are their aliases if any, or their original unminified property names * (as in `@Output('alias') propertyName: any;`). */ readonly outputs: Record<string, string>; /** * Function to create and refresh content queries associated with a given directive. */ contentQueries: ContentQueriesFunction<T> | null; /** * Query-related instructions for a directive. Note that while directives don't have a * view and as such view queries won't necessarily do anything, there might be * components that extend the directive. */ viewQuery: ViewQueriesFunction<T> | null; /** * Refreshes host bindings on the associated directive. */ readonly hostBindings: HostBindingsFunction<T> | null; /** * The number of bindings in this directive `hostBindings` (including pure fn bindings). * * Used to calculate the length of the component's LView array, so we * can pre-fill the array and set the host binding start index. */ readonly hostVars: number; /** * Assign static attribute values to a host element. * * This property will assign static attribute values as well as class and style * values to a host element. Since attribute values can consist of different types of values, the * `hostAttrs` array must include the values in the following format: * * attrs = [ * // static attributes (like `title`, `name`, `id`...) * attr1, value1, attr2, value, * * // a single namespace value (like `x:id`) * NAMESPACE_MARKER, namespaceUri1, name1, value1, * * // another single namespace value (like `x:name`) * NAMESPACE_MARKER, namespaceUri2, name2, value2, * * // a series of CSS classes that will be applied to the element (no spaces) * CLASSES_MARKER, class1, class2, class3, * * // a series of CSS styles (property + value) that will be applied to the element * STYLES_MARKER, prop1, value1, prop2, value2 * ] * * All non-class and non-style attributes must be defined at the start of the list * first before all class and style values are set. When there is a change in value * type (like when classes and styles are introduced) a marker must be used to separate * the entries. The marker values themselves are set via entries found in the * [AttributeMarker] enum. */ readonly hostAttrs: TAttributes | null; /** Token representing the directive. Used by DI. */ readonly type: Type<T> | AbstractType<T>; /** Function that resolves `providers` and publishes them into the DI system. */ providersResolver: ProvidersResolver | null; /** Function that resolves `viewProviders` and publishes them into the DI system. */ viewProvidersResolver: ProvidersResolver | null; /** The selectors that will be used to match nodes to this directive. */ readonly selectors: CssSelectorList; /** * Name under which the directive is exported (for use with local references in template) */ readonly exportAs: string[] | null; /** * Whether this directive (or component) is standalone. */ readonly standalone: boolean; /** * Whether this directive (or component) uses the signals authoring experience. */ readonly signals: boolean; /** * Factory function used to create a new directive instance. Will be null initially. * Populated when the factory is first requested by directive instantiation logic. */ readonly factory: FactoryFn<T> | null; /** * The features applied to this directive */ readonly features: DirectiveDefFeature[] | null; /** * Info related to debugging/troubleshooting for this component. This info is only available in * dev mode. */ debugInfo: ClassDebugInfo | null; /** * Function inteded to be called after template selector matching is done * in order to resolve information about their host directives. Patched * onto the definition by the `ɵɵHostDirectivesFeature`. */ resolveHostDirectives: ((matches: DirectiveDef<unknown>[]) => HostDirectiveResolution) | null; /** * Additional directives to be applied whenever the directive has been matched. * * `HostDirectiveConfig` objects represent a host directive that can be resolved eagerly and were * already pre-processed when the definition was created. A function needs to be resolved lazily * during directive matching, because it's a forward reference. * * **Note:** we can't use `HostDirectiveConfig` in the array, because there's no way to * distinguish if a function in the array is a `Type` or a `() => HostDirectiveConfig[]`. */ hostDirectives: (HostDirectiveDef | (() => HostDirectiveConfig[]))[] | null; controlDef: ControlDirectiveDef | null; /** * Cache of inputs that this custom control directive covers, * used by the signal forms system. */ signalFormsInputPresence: Record<string, boolean> | null; setInput: | (<U extends T>( this: DirectiveDef<U>, instance: U, inputSignalNode: null | InputSignalNode<unknown, unknown>, value: any, publicName: string, privateName: string, ) => void) | null; } /** * Runtime link information for Components. * * This is an internal data structure used by the render to link * components into templates. * * NOTE: Always use `defineComponent` function to create this object, * never create the object directly since the shape of this object * can change between versions. * * See: {@link defineComponent} */ export interface ComponentDef<T> extends DirectiveDef<T> { /** * Unique ID for the component. Used in view encapsulation and * to keep track of the injector in standalone components. */ readonly id: string; /** * The View template of the component. */ readonly template: ComponentTemplate<T>; /** Constants associated with the component's view. */ readonly consts: TConstantsOrFactory | null; /** * An array of `ngContent[selector]` values that were found in the template. */ readonly ngContentSelectors?: string[]; /** * A set of styles that the component needs to be present for component to render correctly. */ readonly styles: string[]; /** * The number of nodes, local refs, and pipes in this component template. * * Used to calculate the length of the component's LView array, so we * can pre-fill the array and set the binding start index. */ // TODO(kara): remove queries from this count readonly decls: number; /** * The number of bindings in this component template (including pure fn bindings). * * Used to calculate the length of the component's LView array, so we * can pre-fill the array and set the host binding start index. */ readonly vars: number; /** * Query-related instructions for a component. */ viewQuery: ViewQueriesFunction<T> | null; /** * The view encapsulation type, which determines how styles are applied to * DOM elements. One of * - `Emulated` (default): Emulate native scoping of styles. * - `Native`: Use the native encapsulation mechanism of the renderer. * - `ShadowDom`: Use modern [ShadowDOM](https://w3c.github.io/webcomponents/spec/shadow/) and * create a ShadowRoot for component's host element. * - `None`: Do not provide any template or style encapsulation. */ readonly encapsulation: ViewEncapsulation; /** * Defines arbitrary developer-defined data to be stored on a renderer instance. * This is useful for renderers that delegate to other renderers. */ readonly data: { [kind: string]: any; animation?: any[]; }; /** Whether or not this component's ChangeDetectionStrategy is OnPush */ readonly onPush: boolean; /** Whether or not this component is signal-based. */ readonly signals: boolean; /** * Registry of directives and components that may be found in this view. * * The property is either an array of `DirectiveDef`s or a function which returns the array of * `DirectiveDef`s. The function is necessary to be able to support forward declarations. */ directiveDefs: DirectiveDefListOrFactory | null; /** * Registry of pipes that may be found in this view. * * The property is either an array of `PipeDefs`s or a function which returns the array of * `PipeDefs`s. The function is necessary to be able to support forward declarations. */ pipeDefs: PipeDefListOrFactory | null; /** * Unfiltered list of all dependencies of a component, or `null` if none. */ dependencies: TypeOrFactory<DependencyTypeList> | null; /** * The set of schemas that declare elements to be allowed in the component's template. */ schemas: SchemaMetadata[] | null; /** * Ivy runtime uses this place to store the computed tView for the component. This gets filled on * the first run of component. */ tView: TView | null; /** * A function used by the framework to create standalone injectors. */ getStandaloneInjector: | ((parentInjector: EnvironmentInjector) => EnvironmentInjector | null) | null; /** * A function used by the framework to create the list of external runtime style URLs. */ getExternalStyles: ((encapsulationId?: string) => string[]) | null; /** * Used to store the result of `noSideEffects` function so that it is not removed by closure * compiler. The property should never be read. */ readonly _?: unknown; } /** * Runtime link information for Pipes. * * This is an internal data structure used by the renderer to link * pipes into templates. * * NOTE: Always use `definePipe` function to create this object, * never create the object directly since the shape of this object * can change between versions. * * See: {@link definePipe} */ export interface PipeDef<T> { /** Token representing the pipe. */ type: Type<T> | AbstractType<T>; /** * Pipe name. * * Used to resolve pipe in templates. */ readonly name: string; /** * Factory function used to create a new pipe instance. Will be null initially. * Populated when the factory is first requested by pipe instantiation logic. */ factory: FactoryFn<T> | null; /** * Whether or not the pipe is pure. * * Pure pipes result only depends on the pipe input and not on internal * state of the pipe. */ readonly pure: boolean; /** * Whether this pipe is standalone. */ readonly standalone: boolean; /* The following are lifecycle hooks for this pipe */ onDestroy: (() => void) | null; } export interface DirectiveDefFeature { <T>(directiveDef: DirectiveDef<T>): void; /** * Marks a feature as something that {@link InheritDefinitionFeature} will execute * during inheritance. * * NOTE: DO NOT SET IN ROOT OF MODULE! Doing so will result in tree-shakers/bundlers * identifying the change as a side effect, and the feature will be included in * every bundle. */ ngInherit?: true; } /** Data produced after host directives are resolved for a node. */ export type HostDirectiveResolution = [ matches: DirectiveDef<unknown>[], hostDirectiveDefs: HostDirectiveDefs | null, hostDirectiveRanges: HostDirectiveRanges | null, ]; /** * Map that tracks a selector-matched directive to the range within which its host directives * are declared. Host directives for a specific directive are always contiguous within the runtime. * Note that both the start and end are inclusive and they're both **after** `tNode.directiveStart`. */ export type HostDirectiveRanges = Map<DirectiveDef<unknown>, [start: number, end: number]>; /** Runtime information used to configure a host directive. */ export interface HostDirectiveDef<T = unknown> { /** Class representing the host directive. */ directive: Type<T>; /** Directive inputs that have been exposed. */ inputs: HostDirectiveBindingMap; /** Directive outputs that have been exposed. */ outputs: HostDirectiveBindingMap; } /** * Mapping between the public aliases of directive bindings and the underlying inputs/outputs that * they represent. Also serves as an allowlist of the inputs/outputs from the host directive that * the author has decided to expose. */ export type HostDirectiveBindingMap = { [publicName: string]: string; }; /** * Mapping between a directive that was used as a host directive * and the configuration that was used to define it as such. */ export type HostDirectiveDefs = Map<DirectiveDef<unknown>, HostDirectiveDef>; /** Value that can be used to configure a host directive. */ export type HostDirectiveConfig = | Type<unknown> | { directive: Type<unknown>; inputs?: string[]; outputs?: string[]; }; export interface ComponentDefFeature { <T>(componentDef: ComponentDef<T>): void; /** * Marks a feature as something that {@link InheritDefinitionFeature} will execute * during inheritance. * * NOTE: DO NOT SET IN ROOT OF MODULE! Doing so will result in tree-shakers/bundlers * identifying the change as a side effect, and the feature will be included in * every bundle. */ ngInherit?: true; } /** Function that can be used to transform incoming input values. */ export type InputTransformFunction = (value: any) => any; /** * Type used for directiveDefs on component definition. * * The function is necessary to be able to support forward declarations. */ export type DirectiveDefListOrFactory = (() => DirectiveDefList) | DirectiveDefList; export type DirectiveDefList = (DirectiveDef<any> | ComponentDef<any>)[]; export type DependencyDef = DirectiveDef<unknown> | ComponentDef<unknown> | PipeDef<unknown>; export type DirectiveTypesOrFactory = (() => DirectiveTypeList) | DirectiveTypeList; export type DirectiveTypeList = (DirectiveType<any> | ComponentType<any> | Type<any>)[]; /* Type as workaround for: Microsoft/TypeScript/issues/4881 */ export type DependencyType = DirectiveType<any> | ComponentType<any> | PipeType<any> | Type<any>; export type DependencyTypeList = Array<DependencyType>; export type TypeOrFactory<T> = T | (() => T); export type HostBindingsFunction<T> = <U extends T>(rf: RenderFlags, ctx: U) => void; /** * Type used for PipeDefs on component definition. * * The function is necessary to be able to support forward declarations. */ export type PipeDefListOrFactory = (() => PipeDefList) | PipeDefList; export type PipeDefList = PipeDef<any>[]; export type PipeTypesOrFactory = (() => PipeTypeList) | PipeTypeList; export type PipeTypeList = (PipeType<any> | Type<any>)[]; /* Type as workaround for: Microsoft/TypeScript/issues/4881 */ /** * NgModule scope info as provided by AoT compiler * * In full compilation Ivy resolved all the "module with providers" and forward refs the whole array * if at least one element is forward refed. So we end up with type `Type<any>[]|(() => * Type<any>[])`. * * In local mode the compiler passes the raw info as they are to the runtime functions as it is not * possible to resolve them any further due to limited info at compile time. So we end up with type * `RawScopeInfoFromDecorator[]`. */ export interface NgModuleScopeInfoFromDecorator { /** List of components, directives, and pipes declared by this module. */ declarations?: Type<any>[] | (() => Type<any>[]) | RawScopeInfoFromDecorator[]; /** List of modules or `ModuleWithProviders` or standalone components imported by this module. */ imports?: Type<any>[] | (() => Type<any>[]) | RawScopeInfoFromDecorator[]; /** * List of modules, `ModuleWithProviders`, components, directives, or pipes exported by this * module. */ exports?: Type<any>[] | (() => Type<any>[]) | RawScopeInfoFromDecorator[]; /** * The set of components that are bootstrapped when this module is bootstrapped. This field is * only available in local compilation mode. In full compilation mode bootstrap info is passed * directly to the module def runtime after statically analyzed and resolved. */ bootstrap?: Type<any>[] | (() => Type<any>[]) | RawScopeInfoFromDecorator[]; } /** * The array element type passed to: * - NgModule's annotation imports/exports/declarations fields * - standalone component annotation imports field */ export type RawScopeInfoFromDecorator = | Type<any> | ModuleWithProviders<any> | (() => Type<any>) | (() => ModuleWithProviders<any>) | any[];