feat(core): add support for Types in ViewContainerRef.createComponent (#43022)

With Ivy it's possible to create a `ComponentFactory` instance based on the generated Component def, thus the `ViewContainerRef.createComponent` can accept a Component instance and create a factory inside, rather than requiring additional complexity of creating a ComponentFactory outside (by invoking `ComponentFactoryResolver`).

This should simplify the API that is used for creating components dynamically.

DEPRECATION:

Angular no longer requires component factories to dynamically create components. The factory-based signature of the `ViewContainerRef.createComponent` function is deprecated in favor of a different signature that allows passing component classes instead.

PR Close #43022
This commit is contained in:
Andrew Kushnir 2021-05-05 16:55:44 -07:00 committed by Alex Rickabaugh
parent ab3de40ba3
commit 7dccbdd27b
13 changed files with 355 additions and 36 deletions

View file

@ -54,6 +54,7 @@ v12 - v15
| `@angular/core` | [`defineInjectable`](#core) | <!--v8--> v11 |
| `@angular/core` | [`entryComponents`](api/core/NgModule#entryComponents) | <!--v9--> v11 |
| `@angular/core` | [`ANALYZE_FOR_ENTRY_COMPONENTS`](api/core/ANALYZE_FOR_ENTRY_COMPONENTS) | <!--v9--> v11 |
| `@angular/core` | [Factory-based signature of `ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent) | <!--v13--> v15 |
| `@angular/router` | [`loadChildren` string syntax](#loadChildren) | <!--v9--> v11 |
| `@angular/core/testing` | [`TestBed.get`](#testing) | <!--v9--> v12 |
| `@angular/core/testing` | [`async`](#testing) | <!--v9--> v12 |
@ -108,6 +109,7 @@ This section contains a complete list all of the currently-deprecated APIs, with
| `ViewChildren.emitDistinctChangesOnly` / `ContentChildren.emitDistinctChangesOnly` | none (was part of [issue #40091](https://github.com/angular/angular/issues/40091)) | | This is a temporary flag introduced as part of bugfix of [issue #40091](https://github.com/angular/angular/issues/40091) and will be removed. |
| Factory-based signature of [`ApplicationRef.bootstrap`](api/core/ApplicationRef#bootstrap) | Type-based signature of [`ApplicationRef.bootstrap`](api/core/ApplicationRef#bootstrap) | v13 | With Ivy, there is no need to resolve Component factory and Component Type can be provided directly. |
| [`PlatformRef.bootstrapModuleFactory`](api/core/PlatformRef#bootstrapModuleFactory) | [`PlatformRef.bootstrapModule`](api/core/PlatformRef#bootstrapModule) | v13 | With Ivy, there is no need to resolve NgModule factory and NgModule Type can be provided directly. |
| [Factory-based signature of `ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent) | [Type-based signature of `ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent) | v13 | Angular no longer requires component factories to dynamically create components. Use different signature of the `createComponent` method, which allows passing Component class directly. |
{@a testing}

View file

@ -117,6 +117,23 @@
"packages/core/src/linker/template_ref.ts",
"packages/core/src/render3/instructions/shared.ts"
],
[
"packages/core/src/error_handler.ts",
"packages/core/src/errors.ts",
"packages/core/src/view/types.ts",
"packages/core/src/linker/view_container_ref.ts",
"packages/core/src/render3/component_ref.ts",
"packages/core/src/render3/component.ts",
"packages/core/src/render3/instructions/shared.ts"
],
[
"packages/core/src/error_handler.ts",
"packages/core/src/errors.ts",
"packages/core/src/view/types.ts",
"packages/core/src/linker/view_container_ref.ts",
"packages/core/src/render3/component_ref.ts",
"packages/core/src/render3/instructions/shared.ts"
],
[
"packages/core/src/error_handler.ts",
"packages/core/src/errors.ts",

View file

@ -1358,7 +1358,14 @@ export interface ViewChildrenDecorator {
// @public
export abstract class ViewContainerRef {
abstract clear(): void;
abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
abstract createComponent<C>(componentType: Type<C>, options?: {
index?: number;
injector?: Injector;
ngModuleRef?: NgModuleRef<unknown>;
projectableNodes?: Node[][];
}): ComponentRef<C>;
// @deprecated
abstract createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModuleRef?: NgModuleRef<any>): ComponentRef<C>;
abstract createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C>;
abstract detach(index?: number): ViewRef | null;
abstract get element(): ElementRef;

View file

@ -15,7 +15,7 @@
"master": {
"uncompressed": {
"runtime-es2017": 4841,
"main-es2017": 462493,
"main-es2017": 463023,
"polyfills-es2017": 55373,
"styles": 69772,
"light-theme": 79025,

View file

@ -33,4 +33,4 @@ export {global as ɵglobal} from './util/global';
export {isObservable as ɵisObservable, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable} from './util/lang';
export {stringify as ɵstringify} from './util/stringify';
export {clearOverrides as ɵclearOverrides, initServicesIfNeeded as ɵinitServicesIfNeeded, overrideComponentView as ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from './view/index';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider_flags';

View file

@ -7,7 +7,10 @@
*/
import {Injector} from '../di/injector';
import {isType, Type} from '../interface/type';
import {assertNodeInjector} from '../render3/assert';
import {ComponentFactory as R3ComponentFactory} from '../render3/component_ref';
import {getComponentDef} from '../render3/definition';
import {getParentInjectorLocation, NodeInjector} from '../render3/di';
import {addToViewTree, createLContainer} from '../render3/instructions/shared';
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE, VIEW_REFS} from '../render3/interfaces/container';
@ -23,8 +26,9 @@ import {getParentInjectorIndex, getParentInjectorView, hasParentInjector} from '
import {getNativeByTNode, unwrapRNode, viewAttachedToContainer} from '../render3/util/view_utils';
import {ViewRef as R3ViewRef} from '../render3/view_ref';
import {addToArray, removeFromArray} from '../util/array_utils';
import {assertEqual, assertGreaterThan, assertLessThan} from '../util/assert';
import {assertDefined, assertEqual, assertGreaterThan, assertLessThan} from '../util/assert';
import {noop} from '../util/noop';
import {ComponentFactory, ComponentRef} from './component_factory';
import {createElementRef, ElementRef} from './element_ref';
import {NgModuleRef} from './ng_module_factory';
@ -111,19 +115,47 @@ export abstract class ViewContainerRef {
/**
* Instantiates a single component and inserts its host view into this container.
*
* @param componentFactory The factory to use.
* @param componentType Component Type to use.
* @param options An object that contains extra parameters:
* * index: the index at which to insert the new component's host view into this container.
* If not specified, appends the new view as the last entry.
* * injector: the injector to use as the parent for the new component.
* * ngModuleRef: an NgModuleRef of the component's NgModule, you should almost always provide
* this to ensure that all expected providers are available for the component
* instantiation.
* * projectableNodes: list of DOM nodes that should be projected through
* [`<ng-content>`](api/core/ng-content) of the new component instance.
*
* @returns The new `ComponentRef` which contains the component instance and the host view.
*/
abstract createComponent<C>(componentType: Type<C>, options?: {
index?: number,
injector?: Injector,
ngModuleRef?: NgModuleRef<unknown>,
projectableNodes?: Node[][],
}): ComponentRef<C>;
/**
* Instantiates a single component and inserts its host view into this container.
*
* @param componentFactory Component factory to use.
* @param index The index at which to insert the new component's host view into this container.
* If not specified, appends the new view as the last entry.
* @param injector The injector to use as the parent for the new component.
* @param projectableNodes
* @param ngModule
* @param projectableNodes List of DOM nodes that should be projected through
* [`<ng-content>`](api/core/ng-content) of the new component instance.
* @param ngModuleRef An instance of the NgModuleRef that represent an NgModule.
* This information is used to retrieve corresponding NgModule injector.
*
* @returns The new component instance, containing the host view.
* @returns The new `ComponentRef` which contains the component instance and the host view.
*
* @deprecated Angular no longer requires component factories to dynamically create components.
* Use different signature of the `createComponent` method, which allows passing
* Component class directly.
*/
abstract createComponent<C>(
componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
projectableNodes?: any[][], ngModuleRef?: NgModuleRef<any>): ComponentRef<C>;
/**
* Inserts a view into this container.
@ -239,10 +271,77 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
return viewRef;
}
override createComponent<C>(componentType: Type<C>, options?: {
index?: number,
injector?: Injector,
projectableNodes?: Node[][],
ngModuleRef?: NgModuleRef<unknown>,
}): ComponentRef<C>;
/**
* @deprecated Angular no longer requires component factories to dynamically create components.
* Use different signature of the `createComponent` method, which allows passing
* Component class directly.
*/
override createComponent<C>(
componentFactory: ComponentFactory<C>, index?: number|undefined,
injector?: Injector|undefined, projectableNodes?: any[][]|undefined,
ngModuleRef?: NgModuleRef<any>|undefined): ComponentRef<C>;
override createComponent<C>(
componentFactoryOrType: ComponentFactory<C>|Type<C>, indexOrOptions?: number|undefined|{
index?: number,
injector?: Injector,
ngModuleRef?: NgModuleRef<unknown>,
projectableNodes?: Node[][],
},
injector?: Injector|undefined, projectableNodes?: any[][]|undefined,
ngModuleRef?: NgModuleRef<any>|undefined): ComponentRef<C> {
const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
let index: number|undefined;
// This function supports 2 signatures and we need to handle options correctly for both:
// 1. When first argument is a Component type. This signature also requires extra
// options to be provided as as object (more ergonomic option).
// 2. First argument is a Component factory. In this case extra options are represented as
// positional arguments. This signature is less ergonomic and will be deprecated.
if (isComponentFactory) {
if (ngDevMode) {
assertEqual(
typeof indexOrOptions !== 'object', true,
'It looks like Component factory was provided as the first argument ' +
'and an options object as the second argument. This combination of arguments ' +
'is incompatible. You can either change the first argument to provide Component ' +
'type or change the second argument to be a number (representing an index at ' +
'which to insert the new component\'s host view into this container)');
}
index = indexOrOptions as number | undefined;
} else {
if (ngDevMode) {
assertDefined(
getComponentDef(componentFactoryOrType),
`Provided Component class doesn't contain Component definition. ` +
`Please check whether provided class has @Component decorator.`);
assertEqual(
typeof indexOrOptions !== 'number', true,
'It looks like Component type was provided as the first argument ' +
'and a number (representing an index at which to insert the new component\'s ' +
'host view into this container as the second argument. This combination of arguments ' +
'is incompatible. Please use an object as the second argument instead.');
}
const options = (indexOrOptions || {}) as {
index?: number,
injector?: Injector,
ngModuleRef?: NgModuleRef<unknown>,
projectableNodes?: Node[][],
};
index = options.index;
injector = options.injector;
projectableNodes = options.projectableNodes;
ngModuleRef = options.ngModuleRef;
}
const componentFactory: ComponentFactory<C> = isComponentFactory ?
componentFactoryOrType as ComponentFactory<C>:
new R3ComponentFactory(getComponentDef(componentFactoryOrType)!);
const contextInjector = injector || this.parentInjector;
if (!ngModuleRef && (componentFactory as any).ngModule == null && contextInjector) {
// DO NOT REFACTOR. The code here used to have a `value || undefined` expression

View file

@ -19,7 +19,7 @@ import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory
import {RendererFactory2} from '../render/api';
import {Sanitizer} from '../sanitization/sanitizer';
import {VERSION} from '../version';
import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider';
import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider_flags';
import {assertComponentType} from './assert';
import {createRootComponent, createRootComponentView, createRootContext, LifecycleHooksFeature} from './component';
import {getComponentDef} from './definition';

View file

@ -7,10 +7,7 @@
*/
import {ChangeDetectorRef, injectChangeDetectorRef} from '../change_detection/change_detector_ref';
import {InjectFlags} from '../di/interface/injector';
import {createTemplateRef, TemplateRef} from '../linker/template_ref';
import {throwProviderNotFoundError} from './errors_di';
import {TNode} from './interfaces/node';
import {LView} from './interfaces/view';

View file

@ -15,6 +15,7 @@ import {Renderer2} from '../render/api';
import {isObservable} from '../util/lang';
import {stringify} from '../util/stringify';
import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './provider_flags';
import {createChangeDetectorRef, createInjector} from './refs';
import {asElementData, asProviderData, BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, shouldCallLifecycleInitHook, ViewData, ViewFlags, ViewState} from './types';
import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util';
@ -318,25 +319,6 @@ function callFactory(
}
}
// This default value is when checking the hierarchy for a token.
//
// It means both:
// - the token is not provided by the current injector,
// - only the element injectors should be checked (ie do not check module injectors
//
// mod1
// /
// el1 mod2
// \ /
// el2
//
// When requesting el2.injector.get(token), we should check in the following order and return the
// first found value:
// - el2.injector.get(token, default)
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
// - mod2.injector.get(token, default)
export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
export function resolveDep(
view: ViewData, elDef: NodeDef, allowPrivateServices: boolean, depDef: DepDef,
notFoundValue: any = Injector.THROW_IF_NOT_FOUND): any {

View file

@ -0,0 +1,26 @@
/**
* @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.io/license
*/
// This default value is when checking the hierarchy for a token.
//
// It means both:
// - the token is not provided by the current injector,
// - only the element injectors should be checked (ie do not check module injectors
//
// mod1
// /
// el1 mod2
// \ /
// el2
//
// When requesting el2.injector.get(token), we should check in the following order and return the
// first found value:
// - el2.injector.get(token, default)
// - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
// - mod2.injector.get(token, default)
export const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};

View file

@ -17,6 +17,7 @@ import {InternalNgModuleRef, NgModuleRef} from '../linker/ng_module_factory';
import {TemplateRef} from '../linker/template_ref';
import {ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef, InternalViewRef, ViewRef, ViewRefTracker} from '../linker/view_ref';
import {assertEqual} from '../util/assert';
import {stringify} from '../util/stringify';
import {VERSION} from '../version';
@ -191,9 +192,20 @@ class ViewContainerRef_ implements ViewContainerData {
}
createComponent<C>(
componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
projectableNodes?: any[][], ngModuleRef?: NgModuleRef<any>): ComponentRef<C> {
componentFactoryOrType: ComponentFactory<C>|Type<C>, indexOrOptions?: number|{},
injector?: Injector, projectableNodes?: any[][],
ngModuleRef?: NgModuleRef<any>): ComponentRef<C> {
if (typeof ngDevMode === 'undefined' || ngDevMode) {
assertEqual(
typeof componentFactoryOrType !== 'function', true,
'ViewEngine does not support Type as an argument for \'componentFactoryOrType\'');
assertEqual(
typeof indexOrOptions !== 'object', true,
'ViewEngine does not support options as an object provided via second argument');
}
const index = indexOrOptions as number | undefined;
const contextInjector = injector || this.parentInjector;
const componentFactory = componentFactoryOrType as ComponentFactory<C>;
if (!ngModuleRef && !(componentFactory instanceof ComponentFactoryBoundToModule)) {
ngModuleRef = contextInjector.get(NgModuleRef);
}

View file

@ -8,10 +8,10 @@
import {CommonModule, DOCUMENT} from '@angular/common';
import {computeMsgId} from '@angular/compiler';
import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, Injector, NgModule, NO_ERRORS_SCHEMA, OnDestroy, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core';
import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, InjectionToken, Injector, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core';
import {Input} from '@angular/core/src/metadata';
import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode';
import {TestBed, TestComponentRenderer} from '@angular/core/testing';
import {ComponentFixture, TestBed, TestComponentRenderer} from '@angular/core/testing';
import {clearTranslations, loadTranslations} from '@angular/localize';
import {By, DomSanitizer, ɵDomRendererFactory2 as DomRendererFactory2} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -1495,6 +1495,123 @@ describe('ViewContainerRef', () => {
expect(fixture.debugElement.nativeElement.innerHTML).toContain('Child Component');
});
describe('createComponent using Type', () => {
const TOKEN_A = new InjectionToken('A');
const TOKEN_B = new InjectionToken('B');
@Component({
selector: 'child-a',
template: `[Child Component A]`,
})
class ChildA {
}
@Component({
selector: 'child-b',
template: `
[Child Component B]
<ng-content></ng-content>
{{ tokenA }}
{{ tokenB }}
`,
})
class ChildB {
constructor(private injector: Injector) {}
get tokenA() {
return this.injector.get(TOKEN_A);
}
get tokenB() {
return this.injector.get(TOKEN_B);
}
}
@Component({
selector: 'app',
template: '',
providers: [
{provide: TOKEN_B, useValue: '[TokenValueB]'},
]
})
class App {
constructor(
public viewContainerRef: ViewContainerRef, public ngModuleRef: NgModuleRef<unknown>,
public injector: Injector) {}
}
@NgModule({
declarations: [App, ChildA, ChildB],
providers: [
{provide: TOKEN_A, useValue: '[TokenValueA]'},
]
})
class AppModule {
}
let fixture!: ComponentFixture<App>;
beforeEach(() => {
TestBed.configureTestingModule({imports: [AppModule]});
fixture = TestBed.createComponent(App);
fixture.detectChanges();
});
it('should be able to create a component when Type is provided', () => {
if (ivyEnabled) {
fixture.componentInstance.viewContainerRef.createComponent(ChildA);
expect(fixture.nativeElement.parentNode.textContent).toContain('[Child Component A]');
} else {
expect(() => {
fixture.componentInstance.viewContainerRef.createComponent(ChildA);
}).toThrowError(/ViewEngine does not support Type/);
}
});
it('should throw if class without @Component decorator is used as Component type', () => {
class MyClassWithoutComponentDecorator {}
const createComponent = () => {
fixture.componentInstance.viewContainerRef.createComponent(
MyClassWithoutComponentDecorator);
};
if (ivyEnabled) {
expect(createComponent)
.toThrowError(/Provided Component class doesn't contain Component definition./);
} else {
expect(createComponent).toThrowError(/ViewEngine does not support Type/);
}
});
onlyInIvy('Ivy-only checks for the `createComponent` API with `options` argument')
.describe('`options` argument handling', () => {
it('should work correctly when an empty object is provided', () => {
fixture.componentInstance.viewContainerRef.createComponent(ChildA, {});
expect(fixture.nativeElement.parentNode.textContent).toContain('[Child Component A]');
});
it('should take provided `options` arguments into account', () => {
const {viewContainerRef, ngModuleRef, injector} = fixture.componentInstance;
viewContainerRef.createComponent(ChildA);
const projectableNode = document.createElement('div');
const textNode = document.createTextNode('[Projectable Node]');
projectableNode.appendChild(textNode);
const projectableNodes = [[projectableNode]];
// Insert ChildB in front of ChildA (since index = 0)
viewContainerRef.createComponent(
ChildB, {index: 0, injector, ngModuleRef, projectableNodes});
fixture.detectChanges();
expect(fixture.nativeElement.parentNode.textContent.trim())
.toContain(
'[Child Component B] ' +
'[Projectable Node] ' +
'[TokenValueA] ' +
'[TokenValueB] ' +
'[Child Component A]');
});
});
});
});
describe('insertion points and declaration points', () => {

View file

@ -5,6 +5,12 @@
{
"name": "ChangeDetectionStrategy"
},
{
"name": "ComponentFactory"
},
{
"name": "ComponentRef"
},
{
"name": "DefaultIterableDiffer"
},
@ -32,6 +38,9 @@
{
"name": "IterableDiffers"
},
{
"name": "LifecycleHooksFeature"
},
{
"name": "NG_COMP_DEF"
},
@ -56,6 +65,9 @@
{
"name": "NOT_FOUND"
},
{
"name": "NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR"
},
{
"name": "NO_CHANGE"
},
@ -92,6 +104,12 @@
{
"name": "RecordViewTuple"
},
{
"name": "RendererFactory2"
},
{
"name": "RootViewRef"
},
{
"name": "RuntimeError"
},
@ -104,6 +122,9 @@
{
"name": "SWITCH_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "Sanitizer"
},
{
"name": "SimpleChange"
},
@ -137,9 +158,15 @@
{
"name": "TodoStore"
},
{
"name": "VERSION"
},
{
"name": "VE_ViewContainerRef"
},
{
"name": "Version"
},
{
"name": "ViewContainerRef"
},
@ -260,6 +287,9 @@
{
"name": "createDirectivesInstances"
},
{
"name": "createElementNode"
},
{
"name": "createElementRef"
},
@ -275,6 +305,15 @@
{
"name": "createNodeInjector"
},
{
"name": "createRootComponent"
},
{
"name": "createRootComponentView"
},
{
"name": "createRootContext"
},
{
"name": "createTView"
},
@ -296,6 +335,9 @@
{
"name": "detachView"
},
{
"name": "detectChangesInRootView"
},
{
"name": "detectChangesInternal"
},
@ -443,6 +485,9 @@
{
"name": "getSymbolIterator"
},
{
"name": "getTNode"
},
{
"name": "getTStylingRangeNext"
},
@ -563,6 +608,9 @@
{
"name": "leaveViewLight"
},
{
"name": "locateHostElement"
},
{
"name": "lookupTokenUsingModuleInjector"
},
@ -581,6 +629,9 @@
{
"name": "markViewDirty"
},
{
"name": "maybeWrapInNotSelector"
},
{
"name": "mergeHostAttribute"
},
@ -725,12 +776,21 @@
{
"name": "stringify"
},
{
"name": "stringifyCSSSelector"
},
{
"name": "stringifyForError"
},
{
"name": "throwProviderNotFoundError"
},
{
"name": "tickRootContext"
},
{
"name": "toRefArray"
},
{
"name": "toTStylingRange"
},