/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/core/src/render3/metadata.ts
121 строка
5 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 {AbstractType, Type} from '../interface/type'; import {noSideEffects} from '../util/closure'; interface TypeWithMetadata extends Type<any> { decorators?: any[]; ctorParameters?: () => any[]; propDecorators?: {[field: string]: any}; } /** * The name of a field that Angular monkey-patches onto a component * class to store a function that loads defer-loadable dependencies * and applies metadata to a class. */ const ASYNC_COMPONENT_METADATA_FN = '__ngAsyncComponentMetadataFn__'; const ASYNC_METADATA_LOADED = '__ngAsyncMetadataLoaded__'; /** * If a given component has unresolved async metadata - returns a reference * to a function that applies component metadata after resolving defer-loadable * dependencies. Otherwise - this function returns `null`. */ export function getAsyncClassMetadataFn( type: Type<unknown>, ): (() => Promise<Array<Type<unknown>>>) | null { const componentClass = type as any; // cast to `any`, so that we can read a monkey-patched field if (componentClass[ASYNC_COMPONENT_METADATA_FN] === ASYNC_METADATA_LOADED) { return null; } return componentClass[ASYNC_COMPONENT_METADATA_FN] ?? null; } /** * Checks if a given component has async metadata. * Independent of whether the metadata is already loaded or not. */ export function hasAsyncClassMetadata(type: Type<unknown>): boolean { const componentClass = type as any; // cast to `any`, so that we can monkey-patch it return !!componentClass[ASYNC_COMPONENT_METADATA_FN]; } /** * Handles the process of applying metadata info to a component class in case * component template has defer blocks (thus some dependencies became deferrable). * * @param type Component class where metadata should be added * @param dependencyLoaderFn Function that loads dependencies * @param metadataSetterFn Function that forms a scope in which the `setClassMetadata` is invoked */ export function setClassMetadataAsync( type: Type<any> | AbstractType<any>, dependencyLoaderFn: () => Array<Promise<Type<unknown> | AbstractType<unknown>>>, metadataSetterFn: (...types: (Type<unknown> | AbstractType<unknown>)[]) => void, ): () => Promise<Array<Type<unknown> | AbstractType<unknown>>> { const componentClass = type as any; // cast to `any`, so that we can monkey-patch it componentClass[ASYNC_COMPONENT_METADATA_FN] = () => Promise.all(dependencyLoaderFn()).then((dependencies) => { metadataSetterFn(...dependencies); // Metadata is now set, reset field value to indicate that this component // can by used/compiled synchronously. componentClass[ASYNC_COMPONENT_METADATA_FN] = ASYNC_METADATA_LOADED; return dependencies; }); return componentClass[ASYNC_COMPONENT_METADATA_FN]; } /** * Adds decorator, constructor, and property metadata to a given type via static metadata fields * on the type. * * These metadata fields can later be read with Angular's `ReflectionCapabilities` API. * * Calls to `setClassMetadata` can be guarded by ngDevMode, resulting in the metadata assignments * being tree-shaken away during production builds. */ export function setClassMetadata( type: any, decorators: any[] | null, ctorParameters: (() => any[]) | null, propDecorators: {[field: string]: any} | null, ): void { return noSideEffects(() => { const clazz = type as TypeWithMetadata; if (decorators !== null) { if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) { clazz.decorators.push(...decorators); } else { clazz.decorators = decorators; } } if (ctorParameters !== null) { // Rather than merging, clobber the existing parameters. If other projects exist which // use tsickle-style annotations and reflect over them in the same way, this could // cause issues, but that is vanishingly unlikely. clazz.ctorParameters = ctorParameters; } if (propDecorators !== null) { // The property decorator objects are merged as it is possible different fields have // different decorator types. Decorators on individual fields are not merged, as it's // also incredibly unlikely that a field will be decorated both with an Angular // decorator and a non-Angular decorator that's also been downleveled. if (clazz.hasOwnProperty('propDecorators') && clazz.propDecorators !== undefined) { clazz.propDecorators = {...clazz.propDecorators, ...propDecorators}; } else { clazz.propDecorators = propDecorators; } } }) as never; }