@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/fesm2015/testing.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
|
*/
|
|
@@ -3164,11 +3164,12 @@ function rememberChangeHistoryAndInvokeOnChangesHook() {
|
|
|
3164
3164
|
}
|
|
3165
3165
|
}
|
|
3166
3166
|
function ngOnChangesSetInput(instance, value, publicName, privateName) {
|
|
3167
|
+
const declaredName = this.declaredInputs[publicName];
|
|
3168
|
+
ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
|
|
3167
3169
|
const simpleChangesStore = getSimpleChangesStore(instance) ||
|
|
3168
3170
|
setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
|
|
3169
3171
|
const current = simpleChangesStore.current || (simpleChangesStore.current = {});
|
|
3170
3172
|
const previous = simpleChangesStore.previous;
|
|
3171
|
-
const declaredName = this.declaredInputs[publicName];
|
|
3172
3173
|
const previousChange = previous[declaredName];
|
|
3173
3174
|
current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
|
|
3174
3175
|
instance[privateName] = value;
|
|
@@ -6639,8 +6640,11 @@ function getSanitizer() {
|
|
|
6639
6640
|
* As you can see in the Tree-shakable InjectionToken example below.
|
|
6640
6641
|
*
|
|
6641
6642
|
* Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
|
|
6642
|
-
* overrides the above behavior and marks the token as belonging to a particular `@NgModule
|
|
6643
|
-
* mentioned above, `'root'` is the default value for
|
|
6643
|
+
* overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
|
|
6644
|
+
* this option is now deprecated). As mentioned above, `'root'` is the default value for
|
|
6645
|
+
* `providedIn`.
|
|
6646
|
+
*
|
|
6647
|
+
* The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
|
|
6644
6648
|
*
|
|
6645
6649
|
* @usageNotes
|
|
6646
6650
|
* ### Basic Examples
|
|
@@ -7642,7 +7646,7 @@ class Version {
|
|
|
7642
7646
|
/**
|
|
7643
7647
|
* @publicApi
|
|
7644
7648
|
*/
|
|
7645
|
-
const VERSION = new Version('15.0.0-next.
|
|
7649
|
+
const VERSION = new Version('15.0.0-next.5');
|
|
7646
7650
|
|
|
7647
7651
|
/**
|
|
7648
7652
|
* @license
|
|
@@ -12612,9 +12616,6 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
|
|
|
12612
12616
|
}
|
|
12613
12617
|
return blueprint;
|
|
12614
12618
|
}
|
|
12615
|
-
function createError(text, token) {
|
|
12616
|
-
return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
|
|
12617
|
-
}
|
|
12618
12619
|
/**
|
|
12619
12620
|
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
|
12620
12621
|
*
|
|
@@ -12738,26 +12739,49 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12738
12739
|
}
|
|
12739
12740
|
return tNode;
|
|
12740
12741
|
}
|
|
12741
|
-
|
|
12742
|
-
|
|
12743
|
-
|
|
12744
|
-
|
|
12745
|
-
|
|
12746
|
-
|
|
12747
|
-
|
|
12742
|
+
/**
|
|
12743
|
+
* Generates the `PropertyAliases` data structure from the provided input/output mapping.
|
|
12744
|
+
* @param aliasMap Input/output mapping from the directive definition.
|
|
12745
|
+
* @param directiveIndex Index of the directive.
|
|
12746
|
+
* @param propertyAliases Object in which to store the results.
|
|
12747
|
+
* @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
|
|
12748
|
+
* If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
|
|
12749
|
+
* name inputs/outputs should be exposed under.
|
|
12750
|
+
*/
|
|
12751
|
+
function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
|
|
12752
|
+
for (let publicName in aliasMap) {
|
|
12753
|
+
if (aliasMap.hasOwnProperty(publicName)) {
|
|
12754
|
+
propertyAliases = propertyAliases === null ? {} : propertyAliases;
|
|
12755
|
+
const internalName = aliasMap[publicName];
|
|
12756
|
+
// If there are no host directive mappings, we want to remap using the alias map from the
|
|
12757
|
+
// definition itself. If there is an alias map, it has two functions:
|
|
12758
|
+
// 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
|
|
12759
|
+
// ones inside the host directive map will be exposed on the host.
|
|
12760
|
+
// 2. The public name of the property is aliased using the host directive alias map, rather
|
|
12761
|
+
// than the alias map from the definition.
|
|
12762
|
+
if (hostDirectiveAliasMap === null) {
|
|
12763
|
+
addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
|
|
12748
12764
|
}
|
|
12749
|
-
else {
|
|
12750
|
-
(
|
|
12765
|
+
else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
12766
|
+
addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
|
|
12751
12767
|
}
|
|
12752
12768
|
}
|
|
12753
12769
|
}
|
|
12754
|
-
return
|
|
12770
|
+
return propertyAliases;
|
|
12771
|
+
}
|
|
12772
|
+
function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
|
|
12773
|
+
if (propertyAliases.hasOwnProperty(publicName)) {
|
|
12774
|
+
propertyAliases[publicName].push(directiveIndex, internalName);
|
|
12775
|
+
}
|
|
12776
|
+
else {
|
|
12777
|
+
propertyAliases[publicName] = [directiveIndex, internalName];
|
|
12778
|
+
}
|
|
12755
12779
|
}
|
|
12756
12780
|
/**
|
|
12757
12781
|
* Initializes data structures required to work with directive inputs and outputs.
|
|
12758
12782
|
* Initialization is done for all directives matched on a given TNode.
|
|
12759
12783
|
*/
|
|
12760
|
-
function initializeInputAndOutputAliases(tView, tNode) {
|
|
12784
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
|
|
12761
12785
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12762
12786
|
const start = tNode.directiveStart;
|
|
12763
12787
|
const end = tNode.directiveEnd;
|
|
@@ -12766,16 +12790,21 @@ function initializeInputAndOutputAliases(tView, tNode) {
|
|
|
12766
12790
|
const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
|
|
12767
12791
|
let inputsStore = null;
|
|
12768
12792
|
let outputsStore = null;
|
|
12769
|
-
for (let
|
|
12770
|
-
const directiveDef = tViewData[
|
|
12771
|
-
|
|
12772
|
-
|
|
12793
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
12794
|
+
const directiveDef = tViewData[directiveIndex];
|
|
12795
|
+
const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
|
|
12796
|
+
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
12797
|
+
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
12798
|
+
inputsStore =
|
|
12799
|
+
generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
12800
|
+
outputsStore =
|
|
12801
|
+
generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
12773
12802
|
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
12774
12803
|
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
12775
12804
|
// TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
|
|
12776
12805
|
// should be set for inline templates.
|
|
12777
12806
|
const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12778
|
-
generateInitialInputs(inputsStore,
|
|
12807
|
+
generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
|
|
12779
12808
|
null;
|
|
12780
12809
|
inputsFromAttrs.push(initialInputs);
|
|
12781
12810
|
}
|
|
@@ -12900,16 +12929,19 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12900
12929
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12901
12930
|
let hasDirectives = false;
|
|
12902
12931
|
if (getBindingsEnabled()) {
|
|
12903
|
-
const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
|
|
12904
12932
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
12933
|
+
const matchResult = findDirectiveDefMatches(tView, tNode);
|
|
12934
|
+
let directiveDefs;
|
|
12935
|
+
let hostDirectiveDefs;
|
|
12936
|
+
if (matchResult === null) {
|
|
12937
|
+
directiveDefs = hostDirectiveDefs = null;
|
|
12938
|
+
}
|
|
12939
|
+
else {
|
|
12940
|
+
[directiveDefs, hostDirectiveDefs] = matchResult;
|
|
12941
|
+
}
|
|
12905
12942
|
if (directiveDefs !== null) {
|
|
12906
|
-
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12907
|
-
// happen in a separate pass before the TNode flags have been initialized.
|
|
12908
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12909
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directiveDefs[i].type);
|
|
12910
|
-
}
|
|
12911
12943
|
hasDirectives = true;
|
|
12912
|
-
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap);
|
|
12944
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
|
|
12913
12945
|
}
|
|
12914
12946
|
if (exportsMap)
|
|
12915
12947
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -12919,8 +12951,13 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12919
12951
|
return hasDirectives;
|
|
12920
12952
|
}
|
|
12921
12953
|
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
12922
|
-
function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
12954
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
12923
12955
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12956
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12957
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
12958
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12959
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
|
|
12960
|
+
}
|
|
12924
12961
|
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
12925
12962
|
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12926
12963
|
// the viewEngine:
|
|
@@ -12966,7 +13003,7 @@ function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
|
12966
13003
|
}
|
|
12967
13004
|
directiveIdx++;
|
|
12968
13005
|
}
|
|
12969
|
-
initializeInputAndOutputAliases(tView, tNode);
|
|
13006
|
+
initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
|
|
12970
13007
|
}
|
|
12971
13008
|
/**
|
|
12972
13009
|
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
@@ -13078,12 +13115,13 @@ function invokeHostBindingsInCreationMode(def, directive) {
|
|
|
13078
13115
|
* Matches the current node against all available selectors.
|
|
13079
13116
|
* If a component is matched (at most one), it is returned in first position in the array.
|
|
13080
13117
|
*/
|
|
13081
|
-
function findDirectiveDefMatches(tView,
|
|
13118
|
+
function findDirectiveDefMatches(tView, tNode) {
|
|
13082
13119
|
var _a;
|
|
13083
13120
|
ngDevMode && assertFirstCreatePass(tView);
|
|
13084
13121
|
ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
|
|
13085
13122
|
const registry = tView.directiveRegistry;
|
|
13086
13123
|
let matches = null;
|
|
13124
|
+
let hostDirectiveDefs = null;
|
|
13087
13125
|
if (registry) {
|
|
13088
13126
|
for (let i = 0; i < registry.length; i++) {
|
|
13089
13127
|
const def = registry[i];
|
|
@@ -13109,7 +13147,8 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
13109
13147
|
// 4. Selector-matched directives.
|
|
13110
13148
|
if (def.findHostDirectiveDefs !== null) {
|
|
13111
13149
|
const hostDirectiveMatches = [];
|
|
13112
|
-
|
|
13150
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
13151
|
+
def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
|
|
13113
13152
|
// Add all host directives declared on this component, followed by the component itself.
|
|
13114
13153
|
// Host directives should execute first so the host has a chance to override changes
|
|
13115
13154
|
// to the DOM made by them.
|
|
@@ -13127,13 +13166,14 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
13127
13166
|
}
|
|
13128
13167
|
else {
|
|
13129
13168
|
// Append any host directives to the matches first.
|
|
13130
|
-
|
|
13169
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
13170
|
+
(_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, def, matches, hostDirectiveDefs);
|
|
13131
13171
|
matches.push(def);
|
|
13132
13172
|
}
|
|
13133
13173
|
}
|
|
13134
13174
|
}
|
|
13135
13175
|
}
|
|
13136
|
-
return matches;
|
|
13176
|
+
return matches === null ? null : [matches, hostDirectiveDefs];
|
|
13137
13177
|
}
|
|
13138
13178
|
/**
|
|
13139
13179
|
* Marks a given TNode as a component's host. This consists of:
|
|
@@ -14214,15 +14254,26 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
14214
14254
|
let component;
|
|
14215
14255
|
let tElementNode;
|
|
14216
14256
|
try {
|
|
14217
|
-
const
|
|
14257
|
+
const rootComponentDef = this.componentDef;
|
|
14258
|
+
let rootDirectives;
|
|
14259
|
+
let hostDirectiveDefs = null;
|
|
14260
|
+
if (rootComponentDef.findHostDirectiveDefs) {
|
|
14261
|
+
rootDirectives = [];
|
|
14262
|
+
hostDirectiveDefs = new Map();
|
|
14263
|
+
rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
|
|
14264
|
+
rootDirectives.push(rootComponentDef);
|
|
14265
|
+
}
|
|
14266
|
+
else {
|
|
14267
|
+
rootDirectives = [rootComponentDef];
|
|
14268
|
+
}
|
|
14218
14269
|
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
|
|
14219
|
-
const componentView = createRootComponentView(hostTNode, hostRNode,
|
|
14270
|
+
const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
|
|
14220
14271
|
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
14221
14272
|
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
|
|
14222
14273
|
// where the renderer is mocked out and `undefined` is returned. We should update the tests so
|
|
14223
14274
|
// that this check can be removed.
|
|
14224
14275
|
if (hostRNode) {
|
|
14225
|
-
setRootNodeAttributes(hostRenderer,
|
|
14276
|
+
setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
|
|
14226
14277
|
}
|
|
14227
14278
|
if (projectableNodes !== undefined) {
|
|
14228
14279
|
projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
|
|
@@ -14230,7 +14281,7 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
14230
14281
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
|
14231
14282
|
// executed here?
|
|
14232
14283
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
|
14233
|
-
component = createRootComponent(componentView,
|
|
14284
|
+
component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
|
|
14234
14285
|
renderView(rootTView, rootLView, null);
|
|
14235
14286
|
}
|
|
14236
14287
|
finally {
|
|
@@ -14330,8 +14381,7 @@ function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives,
|
|
|
14330
14381
|
const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
|
|
14331
14382
|
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);
|
|
14332
14383
|
if (tView.firstCreatePass) {
|
|
14333
|
-
|
|
14334
|
-
markAsComponentHost(tView, tNode, 0);
|
|
14384
|
+
markAsComponentHost(tView, tNode, rootDirectives.length - 1);
|
|
14335
14385
|
}
|
|
14336
14386
|
addToViewTree(rootView, componentView);
|
|
14337
14387
|
// Store component view at node index, with node as the HOST
|
|
@@ -14353,12 +14403,12 @@ function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
|
|
|
14353
14403
|
* Creates a root component and sets it up with features and host bindings.Shared by
|
|
14354
14404
|
* renderComponent() and ViewContainerRef.createComponent().
|
|
14355
14405
|
*/
|
|
14356
|
-
function createRootComponent(componentView, rootComponentDef, rootDirectives, rootLView, hostFeatures) {
|
|
14406
|
+
function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
|
|
14357
14407
|
const rootTNode = getCurrentTNode();
|
|
14358
14408
|
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
|
14359
14409
|
const tView = rootLView[TVIEW];
|
|
14360
14410
|
const native = getNativeByTNode(rootTNode, rootLView);
|
|
14361
|
-
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null);
|
|
14411
|
+
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
|
|
14362
14412
|
for (let i = 0; i < rootDirectives.length; i++) {
|
|
14363
14413
|
const directiveIndex = rootTNode.directiveStart + i;
|
|
14364
14414
|
const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
|
|
@@ -14679,7 +14729,7 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14679
14729
|
* found in the LICENSE file at https://angular.io/license
|
|
14680
14730
|
*/
|
|
14681
14731
|
/**
|
|
14682
|
-
* This feature
|
|
14732
|
+
* This feature adds the host directives behavior to a directive definition by patching a
|
|
14683
14733
|
* function onto it. The expectation is that the runtime will invoke the function during
|
|
14684
14734
|
* directive matching.
|
|
14685
14735
|
*
|
|
@@ -14713,14 +14763,20 @@ function ɵɵHostDirectivesFeature(rawHostDirectives) {
|
|
|
14713
14763
|
});
|
|
14714
14764
|
};
|
|
14715
14765
|
}
|
|
14716
|
-
function findHostDirectiveDefs(
|
|
14717
|
-
if (
|
|
14718
|
-
for (const hostDirectiveConfig of
|
|
14766
|
+
function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
|
|
14767
|
+
if (currentDef.hostDirectives !== null) {
|
|
14768
|
+
for (const hostDirectiveConfig of currentDef.hostDirectives) {
|
|
14719
14769
|
const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
|
|
14720
|
-
|
|
14770
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
14771
|
+
validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
|
|
14772
|
+
}
|
|
14773
|
+
// We need to patch the `declaredInputs` so that
|
|
14774
|
+
// `ngOnChanges` can map the properties correctly.
|
|
14775
|
+
patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
|
|
14721
14776
|
// Host directives execute before the host so that its host bindings can be overwritten.
|
|
14722
|
-
findHostDirectiveDefs(
|
|
14723
|
-
|
|
14777
|
+
findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
|
|
14778
|
+
hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
|
|
14779
|
+
matchedDefs.push(hostDirectiveDef);
|
|
14724
14780
|
}
|
|
14725
14781
|
}
|
|
14726
14782
|
}
|
|
@@ -14738,6 +14794,90 @@ function bindingArrayToMap(bindings) {
|
|
|
14738
14794
|
}
|
|
14739
14795
|
return result;
|
|
14740
14796
|
}
|
|
14797
|
+
/**
|
|
14798
|
+
* `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
|
|
14799
|
+
* `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
|
|
14800
|
+
* minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
|
|
14801
|
+
* will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
|
|
14802
|
+
* minification.
|
|
14803
|
+
*
|
|
14804
|
+
* This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
|
|
14805
|
+
* definition is declared. When a property is written to the directive instance, the
|
|
14806
|
+
* `NgOnChangesFeature` will try to remap the property name being written to using the
|
|
14807
|
+
* `declaredInputs`.
|
|
14808
|
+
*
|
|
14809
|
+
* Since the host directive input remapping happens during directive matching, `declaredInputs`
|
|
14810
|
+
* won't contain the new alias that the input is available under. This function addresses the
|
|
14811
|
+
* issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
|
|
14812
|
+
* this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
|
|
14813
|
+
* is used *only* by the `NgOnChangesFeature` when determining what name is used in the
|
|
14814
|
+
* `SimpleChanges` object which won't be reached if an input doesn't exist.
|
|
14815
|
+
*/
|
|
14816
|
+
function patchDeclaredInputs(declaredInputs, exposedInputs) {
|
|
14817
|
+
for (const publicName in exposedInputs) {
|
|
14818
|
+
if (exposedInputs.hasOwnProperty(publicName)) {
|
|
14819
|
+
const remappedPublicName = exposedInputs[publicName];
|
|
14820
|
+
const privateName = declaredInputs[publicName];
|
|
14821
|
+
// We *technically* shouldn't be able to hit this case because we can't have multiple
|
|
14822
|
+
// inputs on the same property and we have validations against conflicting aliases in
|
|
14823
|
+
// `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
|
|
14824
|
+
// with the wrong name so we have a non-user-friendly assertion here just in case.
|
|
14825
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
14826
|
+
declaredInputs.hasOwnProperty(remappedPublicName)) {
|
|
14827
|
+
assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
|
|
14828
|
+
}
|
|
14829
|
+
declaredInputs[remappedPublicName] = privateName;
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
}
|
|
14833
|
+
/**
|
|
14834
|
+
* Verifies that the host directive has been configured correctly.
|
|
14835
|
+
* @param hostDirectiveConfig Host directive configuration object.
|
|
14836
|
+
* @param directiveDef Directive definition of the host directive.
|
|
14837
|
+
* @param matchedDefs Directives that have been matched so far.
|
|
14838
|
+
*/
|
|
14839
|
+
function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
|
|
14840
|
+
// TODO(crisbeto): implement more of these checks in the compiler.
|
|
14841
|
+
const type = hostDirectiveConfig.directive;
|
|
14842
|
+
if (directiveDef === null) {
|
|
14843
|
+
if (getComponentDef$1(type) !== null) {
|
|
14844
|
+
throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
|
|
14845
|
+
}
|
|
14846
|
+
throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
|
|
14847
|
+
`Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
|
|
14848
|
+
}
|
|
14849
|
+
if (!directiveDef.standalone) {
|
|
14850
|
+
throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
|
|
14851
|
+
}
|
|
14852
|
+
if (matchedDefs.indexOf(directiveDef) > -1) {
|
|
14853
|
+
throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
|
|
14854
|
+
`Directives can only match an element once.`);
|
|
14855
|
+
}
|
|
14856
|
+
validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
|
|
14857
|
+
validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
|
|
14858
|
+
}
|
|
14859
|
+
/**
|
|
14860
|
+
* Checks that the host directive inputs/outputs configuration is valid.
|
|
14861
|
+
* @param bindingType Kind of binding that is being validated. Used in the error message.
|
|
14862
|
+
* @param def Definition of the host directive that is being validated against.
|
|
14863
|
+
* @param hostDirectiveDefs Host directive mapping object that shold be validated.
|
|
14864
|
+
*/
|
|
14865
|
+
function validateMappings(bindingType, def, hostDirectiveDefs) {
|
|
14866
|
+
const className = def.type.name;
|
|
14867
|
+
const bindings = bindingType === 'input' ? def.inputs : def.outputs;
|
|
14868
|
+
for (const publicName in hostDirectiveDefs) {
|
|
14869
|
+
if (hostDirectiveDefs.hasOwnProperty(publicName)) {
|
|
14870
|
+
if (!bindings.hasOwnProperty(publicName)) {
|
|
14871
|
+
throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
|
|
14872
|
+
}
|
|
14873
|
+
const remappedPublicName = hostDirectiveDefs[publicName];
|
|
14874
|
+
if (bindings.hasOwnProperty(remappedPublicName) &&
|
|
14875
|
+
bindings[remappedPublicName] !== publicName) {
|
|
14876
|
+
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.`);
|
|
14877
|
+
}
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14880
|
+
}
|
|
14741
14881
|
|
|
14742
14882
|
/**
|
|
14743
14883
|
* @license
|
|
@@ -24641,7 +24781,7 @@ function generateStandaloneInDeclarationsError(type, location) {
|
|
|
24641
24781
|
function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
|
|
24642
24782
|
if (verifiedNgModule.get(moduleType))
|
|
24643
24783
|
return;
|
|
24644
|
-
// skip verifications of standalone components, directives and pipes
|
|
24784
|
+
// skip verifications of standalone components, directives, and pipes
|
|
24645
24785
|
if (isStandalone(moduleType))
|
|
24646
24786
|
return;
|
|
24647
24787
|
verifiedNgModule.set(moduleType, true);
|