diff --git a/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts b/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts index acda1fb7928..3053b5f66cb 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/component-tree.ts @@ -15,7 +15,7 @@ import type { Injector, Type, ValueProvider, - ɵComponentDebugMetadata as ComponentDebugMetadata, + ɵAngularComponentDebugMetadata as AngularComponentDebugMetadata, ɵProviderRecord as ProviderRecord, } from '@angular/core'; import { @@ -219,7 +219,7 @@ const enum DirectiveMetadataKey { // the method directly interacts with the directive/component definition. const getDirectiveMetadata = (dir: any): DirectiveMetadata => { const getMetadata = ngDebugClient().getDirectiveMetadata!; - const metadata = getMetadata?.(dir) as ComponentDebugMetadata; + const metadata = getMetadata?.(dir) as AngularComponentDebugMetadata; if (metadata) { return { inputs: metadata.inputs, diff --git a/devtools/projects/ng-devtools-backend/src/lib/ng-debug-api/ng-debug-api.ts b/devtools/projects/ng-devtools-backend/src/lib/ng-debug-api/ng-debug-api.ts index b642f7af5a2..77d0d1e2be8 100644 --- a/devtools/projects/ng-devtools-backend/src/lib/ng-debug-api/ng-debug-api.ts +++ b/devtools/projects/ng-devtools-backend/src/lib/ng-debug-api/ng-debug-api.ts @@ -6,24 +6,24 @@ * found in the LICENSE file at https://angular.dev/license */ -import type {ɵGlobalDevModeUtils as GlobalDevModeUtils} from '@angular/core'; +import type {ɵFrameworkAgnosticGlobalUtils as GlobalUtils} from '@angular/core'; /** * Returns a handle to window.ng APIs (global angular debugging). * * @returns window.ng */ -export const ngDebugClient = () => (window as any).ng as Partial; +export const ngDebugClient = () => (window as any).ng as Partial; /** * Type guard that checks whether a given debug API is supported within window.ng * * @returns whether the ng object includes the given debug API */ -export function ngDebugApiIsSupported< - T extends Partial, - K extends keyof T, ->(ng: T, api: K): ng is T & Record> { +export function ngDebugApiIsSupported, K extends keyof T>( + ng: T, + api: K, +): ng is T & Record> { return typeof ng[api] === 'function'; } diff --git a/goldens/public-api/core/global_utils.api.md b/goldens/public-api/core/global_utils.api.md index 5b7650e9543..5e225ebbe6e 100644 --- a/goldens/public-api/core/global_utils.api.md +++ b/goldens/public-api/core/global_utils.api.md @@ -8,20 +8,7 @@ export function applyChanges(component: {}): void; // @public -export interface ComponentDebugMetadata extends DirectiveDebugMetadata { - // (undocumented) - changeDetection: ChangeDetectionStrategy; - // (undocumented) - encapsulation: ViewEncapsulation; -} - -// @public -export interface DirectiveDebugMetadata { - // (undocumented) - inputs: Record; - // (undocumented) - outputs: Record; -} +export type DirectiveDebugMetadata = AngularDirectiveDebugMetadata | AcxDirectiveDebugMetadata | AngularComponentDebugMetadata | AcxComponentDebugMetadata | WizComponentDebugMetadata; // @public export function getComponent(element: Element): T | null; @@ -30,7 +17,7 @@ export function getComponent(element: Element): T | null; export function getContext(element: Element): T | null; // @public -export function getDirectiveMetadata(directiveOrComponentInstance: any): ComponentDebugMetadata | DirectiveDebugMetadata | null; +export function getDirectiveMetadata(directiveOrComponentInstance: any): AngularComponentDebugMetadata | AngularDirectiveDebugMetadata | null; // @public export function getDirectives(node: Node): {}[]; diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index ee80cf956e4..9b65dbee6c9 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -39,7 +39,6 @@ export { export { AttributeMarker as ɵAttributeMarker, ComponentDef as ɵComponentDef, - ComponentDebugMetadata as ɵComponentDebugMetadata, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, ComponentType as ɵComponentType, @@ -62,6 +61,16 @@ export { ɵDeferBlockDependencyInterceptor, ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, ɵDEFER_BLOCK_CONFIG, + Framework as ɵFramework, + BaseDirectiveDebugMetadata as ɵBaseDirectiveDebugMetadata, + AngularDirectiveDebugMetadata as ɵAngularDirectiveDebugMetadata, + AngularComponentDebugMetadata as ɵAngularComponentDebugMetadata, + AcxChangeDetectionStrategy as ɵAcxChangeDetectionStrategy, + AcxViewEncapsulation as ɵAcxViewEncapsulation, + AcxDirectiveDebugMetadata as ɵAcxDirectiveDebugMetadata, + AcxComponentDebugMetadata as ɵAcxComponentDebugMetadata, + WizComponentDebugMetadata as ɵWizComponentDebugMetadata, + DirectiveDebugMetadata as ɵDirectiveDebugMetadata, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, @@ -282,7 +291,10 @@ export { export {compilePipe as ɵcompilePipe} from './render3/jit/pipe'; export {isNgModule as ɵisNgModule} from './render3/jit/util'; export {Profiler as ɵProfiler, ProfilerEvent as ɵProfilerEvent} from './render3/profiler_types'; -export {GlobalDevModeUtils as ɵGlobalDevModeUtils} from './render3/util/global_utils'; +export { + FrameworkAgnosticGlobalUtils as ɵFrameworkAgnosticGlobalUtils, + GlobalDevModeUtils as ɵGlobalDevModeUtils, +} from './render3/util/global_utils'; export { ViewRef as ɵViewRef, isViewDirty as ɵisViewDirty, diff --git a/packages/core/src/render3/global_utils_api.ts b/packages/core/src/render3/global_utils_api.ts index 672d97821ba..3e621a6d32d 100644 --- a/packages/core/src/render3/global_utils_api.ts +++ b/packages/core/src/render3/global_utils_api.ts @@ -17,7 +17,6 @@ export {applyChanges} from './util/change_detection_utils'; export { - ComponentDebugMetadata, DirectiveDebugMetadata, getComponent, getContext, diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 1ddd36cac18..def4206f36f 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -30,7 +30,15 @@ import { } from './interfaces/public_definitions'; import {ɵɵsetComponentScope, ɵɵsetNgModuleScope} from './scope'; import { - ComponentDebugMetadata, + Framework, + BaseDirectiveDebugMetadata, + AngularDirectiveDebugMetadata, + AngularComponentDebugMetadata, + AcxChangeDetectionStrategy, + AcxViewEncapsulation, + AcxDirectiveDebugMetadata, + AcxComponentDebugMetadata, + WizComponentDebugMetadata, DirectiveDebugMetadata, getComponent, getDirectiveMetadata, @@ -223,10 +231,18 @@ export {ɵsetClassDebugInfo} from './debug/set_debug_info'; export {ɵɵreplaceMetadata} from './hmr'; export { - ComponentDebugMetadata, ComponentDef, ComponentTemplate, ComponentType, + Framework, + BaseDirectiveDebugMetadata, + AngularDirectiveDebugMetadata, + AngularComponentDebugMetadata, + AcxChangeDetectionStrategy, + AcxViewEncapsulation, + AcxDirectiveDebugMetadata, + AcxComponentDebugMetadata, + WizComponentDebugMetadata, DirectiveDebugMetadata, DirectiveDef, DirectiveType, diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index ab638cc3aaa..d28bd245401 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -224,34 +224,79 @@ export function getDirectives(node: Node): {}[] { return context.directives === null ? [] : [...context.directives]; } +/** The framework used to author a particular application or component. */ +export enum Framework { + Angular = 'angular', + ACX = 'acx', + Wiz = 'wiz', +} + +/** Metadata common to directives from all frameworks. */ +export interface BaseDirectiveDebugMetadata { + name?: string; + framework?: Framework; +} + /** - * Partial metadata for a given directive instance. - * This information might be useful for debugging purposes or tooling. - * Currently only `inputs` and `outputs` metadata is available. + * Partial metadata for a given Angular directive instance. * * @publicApi */ -export interface DirectiveDebugMetadata { +export interface AngularDirectiveDebugMetadata extends BaseDirectiveDebugMetadata { + framework?: Framework.Angular; // Optional for backwards compatibility. inputs: Record; outputs: Record; } /** - * Partial metadata for a given component instance. - * This information might be useful for debugging purposes or tooling. - * Currently the following fields are available: - * - inputs - * - outputs - * - encapsulation - * - changeDetection + * Partial metadata for a given Angular component instance. * * @publicApi */ -export interface ComponentDebugMetadata extends DirectiveDebugMetadata { +export interface AngularComponentDebugMetadata extends AngularDirectiveDebugMetadata { encapsulation: ViewEncapsulation; changeDetection: ChangeDetectionStrategy; } +/** ACX change detection strategies. */ +export enum AcxChangeDetectionStrategy { + Default = 0, + OnPush = 1, +} + +/** ACX view encapsulation modes. */ +export enum AcxViewEncapsulation { + Emulated = 0, + None = 1, +} + +/** Partial metadata for a given ACX directive instance. */ +export interface AcxDirectiveDebugMetadata extends BaseDirectiveDebugMetadata { + framework: Framework.ACX; + inputs: Record; + outputs: Record; +} + +/** Partial metadata for a given ACX component instance. */ +export interface AcxComponentDebugMetadata extends AcxDirectiveDebugMetadata { + changeDetection: AcxChangeDetectionStrategy; + encapsulation: AcxViewEncapsulation; +} + +/** Partial metadata for a given Wiz component instance. */ +export interface WizComponentDebugMetadata extends BaseDirectiveDebugMetadata { + framework: Framework.Wiz; + props: Record; +} + +/** All potential debug metadata types across all frameworks. */ +export type DirectiveDebugMetadata = + | AngularDirectiveDebugMetadata + | AcxDirectiveDebugMetadata + | AngularComponentDebugMetadata + | AcxComponentDebugMetadata + | WizComponentDebugMetadata; + /** * Returns the debug (partial) metadata for a particular directive or component instance. * The function accepts an instance of a directive or component and returns the corresponding @@ -264,7 +309,7 @@ export interface ComponentDebugMetadata extends DirectiveDebugMetadata { */ export function getDirectiveMetadata( directiveOrComponentInstance: any, -): ComponentDebugMetadata | DirectiveDebugMetadata | null { +): AngularComponentDebugMetadata | AngularDirectiveDebugMetadata | null { const {constructor} = directiveOrComponentInstance; if (!constructor) { throw new Error('Unable to find the instance constructor'); @@ -478,7 +523,7 @@ function assertDomElement(value: any) { * mappings for backwards compatibility. */ function extractInputDebugMetadata(inputs: DirectiveDef['inputs']) { - const res: DirectiveDebugMetadata['inputs'] = {}; + const res: AngularDirectiveDebugMetadata['inputs'] = {}; for (const key in inputs) { if (inputs.hasOwnProperty(key)) { diff --git a/packages/core/src/render3/util/global_utils.ts b/packages/core/src/render3/util/global_utils.ts index 57918222ea0..3ff0d93e1a9 100644 --- a/packages/core/src/render3/util/global_utils.ts +++ b/packages/core/src/render3/util/global_utils.ts @@ -14,6 +14,7 @@ import {isSignal} from '../reactivity/api'; import {applyChanges} from './change_detection_utils'; import {getDeferBlocks} from './defer'; import { + DirectiveDebugMetadata, getComponent, getContext, getDirectiveMetadata, @@ -125,6 +126,21 @@ export function publishGlobalUtil( publishUtil(name, fn); } +/** + * Defines the framework-agnostic `ng` global type, not just the `@angular/core` implementation. + * + * `typeof globalUtilsFunctions` is specifically the `@angular/core` implementation, so we + * overwrite some properties to make them more framework-agnostic. Longer term, we should define + * the `ng` global type as an interface implemented by `globalUtilsFunctions` rather than a type + * derived from it. + */ +export type FrameworkAgnosticGlobalUtils = Omit< + typeof globalUtilsFunctions, + 'getDirectiveMetadata' +> & { + getDirectiveMetadata(directiveOrComponentInstance: any): DirectiveDebugMetadata | null; +}; + /** * Publishes the given function to `window.ng` from package other than @angular/core * So that it can be used from the browser console when an application is not in production. diff --git a/packages/core/test/acceptance/discover_utils_spec.ts b/packages/core/test/acceptance/discover_utils_spec.ts index b4a72d2472f..03b2c7a040d 100644 --- a/packages/core/test/acceptance/discover_utils_spec.ts +++ b/packages/core/test/acceptance/discover_utils_spec.ts @@ -24,7 +24,7 @@ import {ComponentFixture, TestBed} from '../../testing'; import {getLContext} from '../../src/render3/context_discovery'; import {getHostElement} from '../../src/render3/index'; import { - ComponentDebugMetadata, + AngularComponentDebugMetadata, getComponent, getComponentLView, getContext, @@ -383,13 +383,11 @@ describe('discovery utils', () => { describe('getDirectiveMetadata', () => { it('should work with components', () => { - const metadata = getDirectiveMetadata(myApp); - expect(metadata!.inputs).toEqual({a: 'b'}); - expect(metadata!.outputs).toEqual({c: 'd'}); - expect((metadata as ComponentDebugMetadata).changeDetection).toBe( - ChangeDetectionStrategy.Default, - ); - expect((metadata as ComponentDebugMetadata).encapsulation).toBe(ViewEncapsulation.None); + const metadata = getDirectiveMetadata(myApp)! as AngularComponentDebugMetadata; + expect(metadata.inputs).toEqual({a: 'b'}); + expect(metadata.outputs).toEqual({c: 'd'}); + expect(metadata.changeDetection).toBe(ChangeDetectionStrategy.Default); + expect(metadata.encapsulation).toBe(ViewEncapsulation.None); }); it('should work with directives', () => {