@angular/core 15.0.0-next.4 → 15.0.0-next.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2020/src/di/injectable.mjs +1 -1
- package/esm2020/src/di/injection_token.mjs +6 -3
- package/esm2020/src/errors.mjs +1 -1
- package/esm2020/src/metadata/directives.mjs +1 -1
- package/esm2020/src/render3/component_ref.mjs +20 -10
- package/esm2020/src/render3/features/host_directives_feature.mjs +101 -9
- package/esm2020/src/render3/features/ng_onchanges_feature.mjs +4 -2
- package/esm2020/src/render3/instructions/shared.mjs +70 -34
- package/esm2020/src/render3/interfaces/definition.mjs +1 -1
- package/esm2020/src/render3/jit/module.mjs +2 -2
- package/esm2020/src/version.mjs +1 -1
- package/esm2020/testing/src/logger.mjs +3 -3
- package/esm2020/testing/src/ng_zone_mock.mjs +3 -3
- package/fesm2015/core.mjs +193 -53
- package/fesm2015/core.mjs.map +1 -1
- package/fesm2015/testing.mjs +193 -53
- package/fesm2015/testing.mjs.map +1 -1
- package/fesm2020/core.mjs +193 -53
- package/fesm2020/core.mjs.map +1 -1
- package/fesm2020/testing.mjs +193 -53
- package/fesm2020/testing.mjs.map +1 -1
- package/index.d.ts +46 -20
- package/package.json +1 -1
- package/testing/index.d.ts +1 -1
package/fesm2020/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v15.0.0-next.
|
|
2
|
+
* @license Angular v15.0.0-next.5
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -1759,11 +1759,12 @@ function rememberChangeHistoryAndInvokeOnChangesHook() {
|
|
|
1759
1759
|
}
|
|
1760
1760
|
}
|
|
1761
1761
|
function ngOnChangesSetInput(instance, value, publicName, privateName) {
|
|
1762
|
+
const declaredName = this.declaredInputs[publicName];
|
|
1763
|
+
ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
|
|
1762
1764
|
const simpleChangesStore = getSimpleChangesStore(instance) ||
|
|
1763
1765
|
setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
|
|
1764
1766
|
const current = simpleChangesStore.current || (simpleChangesStore.current = {});
|
|
1765
1767
|
const previous = simpleChangesStore.previous;
|
|
1766
|
-
const declaredName = this.declaredInputs[publicName];
|
|
1767
1768
|
const previousChange = previous[declaredName];
|
|
1768
1769
|
current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
|
|
1769
1770
|
instance[privateName] = value;
|
|
@@ -4127,8 +4128,11 @@ const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attribut
|
|
|
4127
4128
|
* As you can see in the Tree-shakable InjectionToken example below.
|
|
4128
4129
|
*
|
|
4129
4130
|
* Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
|
|
4130
|
-
* overrides the above behavior and marks the token as belonging to a particular `@NgModule
|
|
4131
|
-
* mentioned above, `'root'` is the default value for
|
|
4131
|
+
* overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
|
|
4132
|
+
* this option is now deprecated). As mentioned above, `'root'` is the default value for
|
|
4133
|
+
* `providedIn`.
|
|
4134
|
+
*
|
|
4135
|
+
* The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
|
|
4132
4136
|
*
|
|
4133
4137
|
* @usageNotes
|
|
4134
4138
|
* ### Basic Examples
|
|
@@ -7256,7 +7260,7 @@ class Version {
|
|
|
7256
7260
|
/**
|
|
7257
7261
|
* @publicApi
|
|
7258
7262
|
*/
|
|
7259
|
-
const VERSION = new Version('15.0.0-next.
|
|
7263
|
+
const VERSION = new Version('15.0.0-next.5');
|
|
7260
7264
|
|
|
7261
7265
|
/**
|
|
7262
7266
|
* @license
|
|
@@ -12279,9 +12283,6 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
|
|
|
12279
12283
|
}
|
|
12280
12284
|
return blueprint;
|
|
12281
12285
|
}
|
|
12282
|
-
function createError(text, token) {
|
|
12283
|
-
return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
|
|
12284
|
-
}
|
|
12285
12286
|
/**
|
|
12286
12287
|
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
|
12287
12288
|
*
|
|
@@ -12405,26 +12406,49 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12405
12406
|
}
|
|
12406
12407
|
return tNode;
|
|
12407
12408
|
}
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12409
|
+
/**
|
|
12410
|
+
* Generates the `PropertyAliases` data structure from the provided input/output mapping.
|
|
12411
|
+
* @param aliasMap Input/output mapping from the directive definition.
|
|
12412
|
+
* @param directiveIndex Index of the directive.
|
|
12413
|
+
* @param propertyAliases Object in which to store the results.
|
|
12414
|
+
* @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
|
|
12415
|
+
* If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
|
|
12416
|
+
* name inputs/outputs should be exposed under.
|
|
12417
|
+
*/
|
|
12418
|
+
function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
|
|
12419
|
+
for (let publicName in aliasMap) {
|
|
12420
|
+
if (aliasMap.hasOwnProperty(publicName)) {
|
|
12421
|
+
propertyAliases = propertyAliases === null ? {} : propertyAliases;
|
|
12422
|
+
const internalName = aliasMap[publicName];
|
|
12423
|
+
// If there are no host directive mappings, we want to remap using the alias map from the
|
|
12424
|
+
// definition itself. If there is an alias map, it has two functions:
|
|
12425
|
+
// 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
|
|
12426
|
+
// ones inside the host directive map will be exposed on the host.
|
|
12427
|
+
// 2. The public name of the property is aliased using the host directive alias map, rather
|
|
12428
|
+
// than the alias map from the definition.
|
|
12429
|
+
if (hostDirectiveAliasMap === null) {
|
|
12430
|
+
addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
|
|
12415
12431
|
}
|
|
12416
|
-
else {
|
|
12417
|
-
(
|
|
12432
|
+
else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
12433
|
+
addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
|
|
12418
12434
|
}
|
|
12419
12435
|
}
|
|
12420
12436
|
}
|
|
12421
|
-
return
|
|
12437
|
+
return propertyAliases;
|
|
12438
|
+
}
|
|
12439
|
+
function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
|
|
12440
|
+
if (propertyAliases.hasOwnProperty(publicName)) {
|
|
12441
|
+
propertyAliases[publicName].push(directiveIndex, internalName);
|
|
12442
|
+
}
|
|
12443
|
+
else {
|
|
12444
|
+
propertyAliases[publicName] = [directiveIndex, internalName];
|
|
12445
|
+
}
|
|
12422
12446
|
}
|
|
12423
12447
|
/**
|
|
12424
12448
|
* Initializes data structures required to work with directive inputs and outputs.
|
|
12425
12449
|
* Initialization is done for all directives matched on a given TNode.
|
|
12426
12450
|
*/
|
|
12427
|
-
function initializeInputAndOutputAliases(tView, tNode) {
|
|
12451
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
|
|
12428
12452
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12429
12453
|
const start = tNode.directiveStart;
|
|
12430
12454
|
const end = tNode.directiveEnd;
|
|
@@ -12433,16 +12457,21 @@ function initializeInputAndOutputAliases(tView, tNode) {
|
|
|
12433
12457
|
const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
|
|
12434
12458
|
let inputsStore = null;
|
|
12435
12459
|
let outputsStore = null;
|
|
12436
|
-
for (let
|
|
12437
|
-
const directiveDef = tViewData[
|
|
12438
|
-
|
|
12439
|
-
|
|
12460
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
12461
|
+
const directiveDef = tViewData[directiveIndex];
|
|
12462
|
+
const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
|
|
12463
|
+
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
12464
|
+
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
12465
|
+
inputsStore =
|
|
12466
|
+
generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
12467
|
+
outputsStore =
|
|
12468
|
+
generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
12440
12469
|
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
12441
12470
|
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
12442
12471
|
// TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
|
|
12443
12472
|
// should be set for inline templates.
|
|
12444
12473
|
const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12445
|
-
generateInitialInputs(inputsStore,
|
|
12474
|
+
generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
|
|
12446
12475
|
null;
|
|
12447
12476
|
inputsFromAttrs.push(initialInputs);
|
|
12448
12477
|
}
|
|
@@ -12567,16 +12596,19 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12567
12596
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12568
12597
|
let hasDirectives = false;
|
|
12569
12598
|
if (getBindingsEnabled()) {
|
|
12570
|
-
const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
|
|
12571
12599
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
12600
|
+
const matchResult = findDirectiveDefMatches(tView, tNode);
|
|
12601
|
+
let directiveDefs;
|
|
12602
|
+
let hostDirectiveDefs;
|
|
12603
|
+
if (matchResult === null) {
|
|
12604
|
+
directiveDefs = hostDirectiveDefs = null;
|
|
12605
|
+
}
|
|
12606
|
+
else {
|
|
12607
|
+
[directiveDefs, hostDirectiveDefs] = matchResult;
|
|
12608
|
+
}
|
|
12572
12609
|
if (directiveDefs !== null) {
|
|
12573
|
-
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12574
|
-
// happen in a separate pass before the TNode flags have been initialized.
|
|
12575
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12576
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directiveDefs[i].type);
|
|
12577
|
-
}
|
|
12578
12610
|
hasDirectives = true;
|
|
12579
|
-
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap);
|
|
12611
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
|
|
12580
12612
|
}
|
|
12581
12613
|
if (exportsMap)
|
|
12582
12614
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -12586,8 +12618,13 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12586
12618
|
return hasDirectives;
|
|
12587
12619
|
}
|
|
12588
12620
|
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
12589
|
-
function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
12621
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
12590
12622
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12623
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12624
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
12625
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12626
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
|
|
12627
|
+
}
|
|
12591
12628
|
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
12592
12629
|
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12593
12630
|
// the viewEngine:
|
|
@@ -12633,7 +12670,7 @@ function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
|
12633
12670
|
}
|
|
12634
12671
|
directiveIdx++;
|
|
12635
12672
|
}
|
|
12636
|
-
initializeInputAndOutputAliases(tView, tNode);
|
|
12673
|
+
initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
|
|
12637
12674
|
}
|
|
12638
12675
|
/**
|
|
12639
12676
|
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
@@ -12745,11 +12782,12 @@ function invokeHostBindingsInCreationMode(def, directive) {
|
|
|
12745
12782
|
* Matches the current node against all available selectors.
|
|
12746
12783
|
* If a component is matched (at most one), it is returned in first position in the array.
|
|
12747
12784
|
*/
|
|
12748
|
-
function findDirectiveDefMatches(tView,
|
|
12785
|
+
function findDirectiveDefMatches(tView, tNode) {
|
|
12749
12786
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12750
12787
|
ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
|
|
12751
12788
|
const registry = tView.directiveRegistry;
|
|
12752
12789
|
let matches = null;
|
|
12790
|
+
let hostDirectiveDefs = null;
|
|
12753
12791
|
if (registry) {
|
|
12754
12792
|
for (let i = 0; i < registry.length; i++) {
|
|
12755
12793
|
const def = registry[i];
|
|
@@ -12775,7 +12813,8 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
12775
12813
|
// 4. Selector-matched directives.
|
|
12776
12814
|
if (def.findHostDirectiveDefs !== null) {
|
|
12777
12815
|
const hostDirectiveMatches = [];
|
|
12778
|
-
|
|
12816
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
12817
|
+
def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
|
|
12779
12818
|
// Add all host directives declared on this component, followed by the component itself.
|
|
12780
12819
|
// Host directives should execute first so the host has a chance to override changes
|
|
12781
12820
|
// to the DOM made by them.
|
|
@@ -12793,13 +12832,14 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
12793
12832
|
}
|
|
12794
12833
|
else {
|
|
12795
12834
|
// Append any host directives to the matches first.
|
|
12796
|
-
|
|
12835
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
12836
|
+
def.findHostDirectiveDefs?.(def, matches, hostDirectiveDefs);
|
|
12797
12837
|
matches.push(def);
|
|
12798
12838
|
}
|
|
12799
12839
|
}
|
|
12800
12840
|
}
|
|
12801
12841
|
}
|
|
12802
|
-
return matches;
|
|
12842
|
+
return matches === null ? null : [matches, hostDirectiveDefs];
|
|
12803
12843
|
}
|
|
12804
12844
|
/**
|
|
12805
12845
|
* Marks a given TNode as a component's host. This consists of:
|
|
@@ -13880,15 +13920,26 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
13880
13920
|
let component;
|
|
13881
13921
|
let tElementNode;
|
|
13882
13922
|
try {
|
|
13883
|
-
const
|
|
13923
|
+
const rootComponentDef = this.componentDef;
|
|
13924
|
+
let rootDirectives;
|
|
13925
|
+
let hostDirectiveDefs = null;
|
|
13926
|
+
if (rootComponentDef.findHostDirectiveDefs) {
|
|
13927
|
+
rootDirectives = [];
|
|
13928
|
+
hostDirectiveDefs = new Map();
|
|
13929
|
+
rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
|
|
13930
|
+
rootDirectives.push(rootComponentDef);
|
|
13931
|
+
}
|
|
13932
|
+
else {
|
|
13933
|
+
rootDirectives = [rootComponentDef];
|
|
13934
|
+
}
|
|
13884
13935
|
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
|
|
13885
|
-
const componentView = createRootComponentView(hostTNode, hostRNode,
|
|
13936
|
+
const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
|
|
13886
13937
|
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
13887
13938
|
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
|
|
13888
13939
|
// where the renderer is mocked out and `undefined` is returned. We should update the tests so
|
|
13889
13940
|
// that this check can be removed.
|
|
13890
13941
|
if (hostRNode) {
|
|
13891
|
-
setRootNodeAttributes(hostRenderer,
|
|
13942
|
+
setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
|
|
13892
13943
|
}
|
|
13893
13944
|
if (projectableNodes !== undefined) {
|
|
13894
13945
|
projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
|
|
@@ -13896,7 +13947,7 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
13896
13947
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
|
13897
13948
|
// executed here?
|
|
13898
13949
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
|
13899
|
-
component = createRootComponent(componentView,
|
|
13950
|
+
component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
|
|
13900
13951
|
renderView(rootTView, rootLView, null);
|
|
13901
13952
|
}
|
|
13902
13953
|
finally {
|
|
@@ -13996,8 +14047,7 @@ function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives,
|
|
|
13996
14047
|
const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
|
|
13997
14048
|
const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, rootComponentDef.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[tNode.index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
|
|
13998
14049
|
if (tView.firstCreatePass) {
|
|
13999
|
-
|
|
14000
|
-
markAsComponentHost(tView, tNode, 0);
|
|
14050
|
+
markAsComponentHost(tView, tNode, rootDirectives.length - 1);
|
|
14001
14051
|
}
|
|
14002
14052
|
addToViewTree(rootView, componentView);
|
|
14003
14053
|
// Store component view at node index, with node as the HOST
|
|
@@ -14019,12 +14069,12 @@ function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
|
|
|
14019
14069
|
* Creates a root component and sets it up with features and host bindings.Shared by
|
|
14020
14070
|
* renderComponent() and ViewContainerRef.createComponent().
|
|
14021
14071
|
*/
|
|
14022
|
-
function createRootComponent(componentView, rootComponentDef, rootDirectives, rootLView, hostFeatures) {
|
|
14072
|
+
function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
|
|
14023
14073
|
const rootTNode = getCurrentTNode();
|
|
14024
14074
|
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
|
14025
14075
|
const tView = rootLView[TVIEW];
|
|
14026
14076
|
const native = getNativeByTNode(rootTNode, rootLView);
|
|
14027
|
-
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null);
|
|
14077
|
+
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
|
|
14028
14078
|
for (let i = 0; i < rootDirectives.length; i++) {
|
|
14029
14079
|
const directiveIndex = rootTNode.directiveStart + i;
|
|
14030
14080
|
const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
|
|
@@ -14345,7 +14395,7 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14345
14395
|
* found in the LICENSE file at https://angular.io/license
|
|
14346
14396
|
*/
|
|
14347
14397
|
/**
|
|
14348
|
-
* This feature
|
|
14398
|
+
* This feature adds the host directives behavior to a directive definition by patching a
|
|
14349
14399
|
* function onto it. The expectation is that the runtime will invoke the function during
|
|
14350
14400
|
* directive matching.
|
|
14351
14401
|
*
|
|
@@ -14379,14 +14429,20 @@ function ɵɵHostDirectivesFeature(rawHostDirectives) {
|
|
|
14379
14429
|
});
|
|
14380
14430
|
};
|
|
14381
14431
|
}
|
|
14382
|
-
function findHostDirectiveDefs(
|
|
14383
|
-
if (
|
|
14384
|
-
for (const hostDirectiveConfig of
|
|
14432
|
+
function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
|
|
14433
|
+
if (currentDef.hostDirectives !== null) {
|
|
14434
|
+
for (const hostDirectiveConfig of currentDef.hostDirectives) {
|
|
14385
14435
|
const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
|
|
14386
|
-
|
|
14436
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
14437
|
+
validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
|
|
14438
|
+
}
|
|
14439
|
+
// We need to patch the `declaredInputs` so that
|
|
14440
|
+
// `ngOnChanges` can map the properties correctly.
|
|
14441
|
+
patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
|
|
14387
14442
|
// Host directives execute before the host so that its host bindings can be overwritten.
|
|
14388
|
-
findHostDirectiveDefs(
|
|
14389
|
-
|
|
14443
|
+
findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
|
|
14444
|
+
hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
|
|
14445
|
+
matchedDefs.push(hostDirectiveDef);
|
|
14390
14446
|
}
|
|
14391
14447
|
}
|
|
14392
14448
|
}
|
|
@@ -14404,6 +14460,90 @@ function bindingArrayToMap(bindings) {
|
|
|
14404
14460
|
}
|
|
14405
14461
|
return result;
|
|
14406
14462
|
}
|
|
14463
|
+
/**
|
|
14464
|
+
* `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
|
|
14465
|
+
* `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
|
|
14466
|
+
* minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
|
|
14467
|
+
* will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
|
|
14468
|
+
* minification.
|
|
14469
|
+
*
|
|
14470
|
+
* This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
|
|
14471
|
+
* definition is declared. When a property is written to the directive instance, the
|
|
14472
|
+
* `NgOnChangesFeature` will try to remap the property name being written to using the
|
|
14473
|
+
* `declaredInputs`.
|
|
14474
|
+
*
|
|
14475
|
+
* Since the host directive input remapping happens during directive matching, `declaredInputs`
|
|
14476
|
+
* won't contain the new alias that the input is available under. This function addresses the
|
|
14477
|
+
* issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
|
|
14478
|
+
* this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
|
|
14479
|
+
* is used *only* by the `NgOnChangesFeature` when determining what name is used in the
|
|
14480
|
+
* `SimpleChanges` object which won't be reached if an input doesn't exist.
|
|
14481
|
+
*/
|
|
14482
|
+
function patchDeclaredInputs(declaredInputs, exposedInputs) {
|
|
14483
|
+
for (const publicName in exposedInputs) {
|
|
14484
|
+
if (exposedInputs.hasOwnProperty(publicName)) {
|
|
14485
|
+
const remappedPublicName = exposedInputs[publicName];
|
|
14486
|
+
const privateName = declaredInputs[publicName];
|
|
14487
|
+
// We *technically* shouldn't be able to hit this case because we can't have multiple
|
|
14488
|
+
// inputs on the same property and we have validations against conflicting aliases in
|
|
14489
|
+
// `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
|
|
14490
|
+
// with the wrong name so we have a non-user-friendly assertion here just in case.
|
|
14491
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
14492
|
+
declaredInputs.hasOwnProperty(remappedPublicName)) {
|
|
14493
|
+
assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
|
|
14494
|
+
}
|
|
14495
|
+
declaredInputs[remappedPublicName] = privateName;
|
|
14496
|
+
}
|
|
14497
|
+
}
|
|
14498
|
+
}
|
|
14499
|
+
/**
|
|
14500
|
+
* Verifies that the host directive has been configured correctly.
|
|
14501
|
+
* @param hostDirectiveConfig Host directive configuration object.
|
|
14502
|
+
* @param directiveDef Directive definition of the host directive.
|
|
14503
|
+
* @param matchedDefs Directives that have been matched so far.
|
|
14504
|
+
*/
|
|
14505
|
+
function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
|
|
14506
|
+
// TODO(crisbeto): implement more of these checks in the compiler.
|
|
14507
|
+
const type = hostDirectiveConfig.directive;
|
|
14508
|
+
if (directiveDef === null) {
|
|
14509
|
+
if (getComponentDef(type) !== null) {
|
|
14510
|
+
throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
|
|
14511
|
+
}
|
|
14512
|
+
throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
|
|
14513
|
+
`Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
|
|
14514
|
+
}
|
|
14515
|
+
if (!directiveDef.standalone) {
|
|
14516
|
+
throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
|
|
14517
|
+
}
|
|
14518
|
+
if (matchedDefs.indexOf(directiveDef) > -1) {
|
|
14519
|
+
throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
|
|
14520
|
+
`Directives can only match an element once.`);
|
|
14521
|
+
}
|
|
14522
|
+
validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
|
|
14523
|
+
validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
|
|
14524
|
+
}
|
|
14525
|
+
/**
|
|
14526
|
+
* Checks that the host directive inputs/outputs configuration is valid.
|
|
14527
|
+
* @param bindingType Kind of binding that is being validated. Used in the error message.
|
|
14528
|
+
* @param def Definition of the host directive that is being validated against.
|
|
14529
|
+
* @param hostDirectiveDefs Host directive mapping object that shold be validated.
|
|
14530
|
+
*/
|
|
14531
|
+
function validateMappings(bindingType, def, hostDirectiveDefs) {
|
|
14532
|
+
const className = def.type.name;
|
|
14533
|
+
const bindings = bindingType === 'input' ? def.inputs : def.outputs;
|
|
14534
|
+
for (const publicName in hostDirectiveDefs) {
|
|
14535
|
+
if (hostDirectiveDefs.hasOwnProperty(publicName)) {
|
|
14536
|
+
if (!bindings.hasOwnProperty(publicName)) {
|
|
14537
|
+
throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
|
|
14538
|
+
}
|
|
14539
|
+
const remappedPublicName = hostDirectiveDefs[publicName];
|
|
14540
|
+
if (bindings.hasOwnProperty(remappedPublicName) &&
|
|
14541
|
+
bindings[remappedPublicName] !== publicName) {
|
|
14542
|
+
throw new RuntimeError(312 /* RuntimeErrorCode.HOST_DIRECTIVE_CONFLICTING_ALIAS */, `Cannot alias ${bindingType} ${publicName} of host directive ${className} to ${remappedPublicName}, because it already has a different ${bindingType} with the same public name.`);
|
|
14543
|
+
}
|
|
14544
|
+
}
|
|
14545
|
+
}
|
|
14546
|
+
}
|
|
14407
14547
|
|
|
14408
14548
|
/**
|
|
14409
14549
|
* @license
|
|
@@ -24329,7 +24469,7 @@ function generateStandaloneInDeclarationsError(type, location) {
|
|
|
24329
24469
|
function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
|
|
24330
24470
|
if (verifiedNgModule.get(moduleType))
|
|
24331
24471
|
return;
|
|
24332
|
-
// skip verifications of standalone components, directives and pipes
|
|
24472
|
+
// skip verifications of standalone components, directives, and pipes
|
|
24333
24473
|
if (isStandalone(moduleType))
|
|
24334
24474
|
return;
|
|
24335
24475
|
verifiedNgModule.set(moduleType, true);
|