@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/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
|
*/
|
|
@@ -1752,11 +1752,12 @@ function rememberChangeHistoryAndInvokeOnChangesHook() {
|
|
|
1752
1752
|
}
|
|
1753
1753
|
}
|
|
1754
1754
|
function ngOnChangesSetInput(instance, value, publicName, privateName) {
|
|
1755
|
+
const declaredName = this.declaredInputs[publicName];
|
|
1756
|
+
ngDevMode && assertString(declaredName, 'Name of input in ngOnChanges has to be a string');
|
|
1755
1757
|
const simpleChangesStore = getSimpleChangesStore(instance) ||
|
|
1756
1758
|
setSimpleChangesStore(instance, { previous: EMPTY_OBJ, current: null });
|
|
1757
1759
|
const current = simpleChangesStore.current || (simpleChangesStore.current = {});
|
|
1758
1760
|
const previous = simpleChangesStore.previous;
|
|
1759
|
-
const declaredName = this.declaredInputs[publicName];
|
|
1760
1761
|
const previousChange = previous[declaredName];
|
|
1761
1762
|
current[declaredName] = new SimpleChange(previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ);
|
|
1762
1763
|
instance[privateName] = value;
|
|
@@ -4120,8 +4121,11 @@ const Attribute = makeParamDecorator('Attribute', (attributeName) => ({ attribut
|
|
|
4120
4121
|
* As you can see in the Tree-shakable InjectionToken example below.
|
|
4121
4122
|
*
|
|
4122
4123
|
* Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
|
|
4123
|
-
* overrides the above behavior and marks the token as belonging to a particular `@NgModule
|
|
4124
|
-
* mentioned above, `'root'` is the default value for
|
|
4124
|
+
* overrides the above behavior and marks the token as belonging to a particular `@NgModule` (note:
|
|
4125
|
+
* this option is now deprecated). As mentioned above, `'root'` is the default value for
|
|
4126
|
+
* `providedIn`.
|
|
4127
|
+
*
|
|
4128
|
+
* The `providedIn: NgModule` and `providedIn: 'any'` options are deprecated.
|
|
4125
4129
|
*
|
|
4126
4130
|
* @usageNotes
|
|
4127
4131
|
* ### Basic Examples
|
|
@@ -7241,7 +7245,7 @@ class Version {
|
|
|
7241
7245
|
/**
|
|
7242
7246
|
* @publicApi
|
|
7243
7247
|
*/
|
|
7244
|
-
const VERSION = new Version('15.0.0-next.
|
|
7248
|
+
const VERSION = new Version('15.0.0-next.5');
|
|
7245
7249
|
|
|
7246
7250
|
/**
|
|
7247
7251
|
* @license
|
|
@@ -12266,9 +12270,6 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
|
|
|
12266
12270
|
}
|
|
12267
12271
|
return blueprint;
|
|
12268
12272
|
}
|
|
12269
|
-
function createError(text, token) {
|
|
12270
|
-
return new Error(`Renderer: ${text} [${stringifyForError(token)}]`);
|
|
12271
|
-
}
|
|
12272
12273
|
/**
|
|
12273
12274
|
* Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
|
|
12274
12275
|
*
|
|
@@ -12392,26 +12393,49 @@ function createTNode(tView, tParent, type, index, value, attrs) {
|
|
|
12392
12393
|
}
|
|
12393
12394
|
return tNode;
|
|
12394
12395
|
}
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12396
|
+
/**
|
|
12397
|
+
* Generates the `PropertyAliases` data structure from the provided input/output mapping.
|
|
12398
|
+
* @param aliasMap Input/output mapping from the directive definition.
|
|
12399
|
+
* @param directiveIndex Index of the directive.
|
|
12400
|
+
* @param propertyAliases Object in which to store the results.
|
|
12401
|
+
* @param hostDirectiveAliasMap Object used to alias or filter out properties for host directives.
|
|
12402
|
+
* If the mapping is provided, it'll act as an allowlist, as well as a mapping of what public
|
|
12403
|
+
* name inputs/outputs should be exposed under.
|
|
12404
|
+
*/
|
|
12405
|
+
function generatePropertyAliases(aliasMap, directiveIndex, propertyAliases, hostDirectiveAliasMap) {
|
|
12406
|
+
for (let publicName in aliasMap) {
|
|
12407
|
+
if (aliasMap.hasOwnProperty(publicName)) {
|
|
12408
|
+
propertyAliases = propertyAliases === null ? {} : propertyAliases;
|
|
12409
|
+
const internalName = aliasMap[publicName];
|
|
12410
|
+
// If there are no host directive mappings, we want to remap using the alias map from the
|
|
12411
|
+
// definition itself. If there is an alias map, it has two functions:
|
|
12412
|
+
// 1. It serves as an allowlist of bindings that are exposed by the host directives. Only the
|
|
12413
|
+
// ones inside the host directive map will be exposed on the host.
|
|
12414
|
+
// 2. The public name of the property is aliased using the host directive alias map, rather
|
|
12415
|
+
// than the alias map from the definition.
|
|
12416
|
+
if (hostDirectiveAliasMap === null) {
|
|
12417
|
+
addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName);
|
|
12402
12418
|
}
|
|
12403
|
-
else {
|
|
12404
|
-
(
|
|
12419
|
+
else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
|
|
12420
|
+
addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
|
|
12405
12421
|
}
|
|
12406
12422
|
}
|
|
12407
12423
|
}
|
|
12408
|
-
return
|
|
12424
|
+
return propertyAliases;
|
|
12425
|
+
}
|
|
12426
|
+
function addPropertyAlias(propertyAliases, directiveIndex, publicName, internalName) {
|
|
12427
|
+
if (propertyAliases.hasOwnProperty(publicName)) {
|
|
12428
|
+
propertyAliases[publicName].push(directiveIndex, internalName);
|
|
12429
|
+
}
|
|
12430
|
+
else {
|
|
12431
|
+
propertyAliases[publicName] = [directiveIndex, internalName];
|
|
12432
|
+
}
|
|
12409
12433
|
}
|
|
12410
12434
|
/**
|
|
12411
12435
|
* Initializes data structures required to work with directive inputs and outputs.
|
|
12412
12436
|
* Initialization is done for all directives matched on a given TNode.
|
|
12413
12437
|
*/
|
|
12414
|
-
function initializeInputAndOutputAliases(tView, tNode) {
|
|
12438
|
+
function initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefinitionMap) {
|
|
12415
12439
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12416
12440
|
const start = tNode.directiveStart;
|
|
12417
12441
|
const end = tNode.directiveEnd;
|
|
@@ -12420,16 +12444,21 @@ function initializeInputAndOutputAliases(tView, tNode) {
|
|
|
12420
12444
|
const inputsFromAttrs = ngDevMode ? new TNodeInitialInputs() : [];
|
|
12421
12445
|
let inputsStore = null;
|
|
12422
12446
|
let outputsStore = null;
|
|
12423
|
-
for (let
|
|
12424
|
-
const directiveDef = tViewData[
|
|
12425
|
-
|
|
12426
|
-
|
|
12447
|
+
for (let directiveIndex = start; directiveIndex < end; directiveIndex++) {
|
|
12448
|
+
const directiveDef = tViewData[directiveIndex];
|
|
12449
|
+
const aliasData = hostDirectiveDefinitionMap ? hostDirectiveDefinitionMap.get(directiveDef) : null;
|
|
12450
|
+
const aliasedInputs = aliasData ? aliasData.inputs : null;
|
|
12451
|
+
const aliasedOutputs = aliasData ? aliasData.outputs : null;
|
|
12452
|
+
inputsStore =
|
|
12453
|
+
generatePropertyAliases(directiveDef.inputs, directiveIndex, inputsStore, aliasedInputs);
|
|
12454
|
+
outputsStore =
|
|
12455
|
+
generatePropertyAliases(directiveDef.outputs, directiveIndex, outputsStore, aliasedOutputs);
|
|
12427
12456
|
// Do not use unbound attributes as inputs to structural directives, since structural
|
|
12428
12457
|
// directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
|
|
12429
12458
|
// TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
|
|
12430
12459
|
// should be set for inline templates.
|
|
12431
12460
|
const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
|
|
12432
|
-
generateInitialInputs(inputsStore,
|
|
12461
|
+
generateInitialInputs(inputsStore, directiveIndex, tNodeAttrs) :
|
|
12433
12462
|
null;
|
|
12434
12463
|
inputsFromAttrs.push(initialInputs);
|
|
12435
12464
|
}
|
|
@@ -12554,16 +12583,19 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12554
12583
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12555
12584
|
let hasDirectives = false;
|
|
12556
12585
|
if (getBindingsEnabled()) {
|
|
12557
|
-
const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
|
|
12558
12586
|
const exportsMap = localRefs === null ? null : { '': -1 };
|
|
12587
|
+
const matchResult = findDirectiveDefMatches(tView, tNode);
|
|
12588
|
+
let directiveDefs;
|
|
12589
|
+
let hostDirectiveDefs;
|
|
12590
|
+
if (matchResult === null) {
|
|
12591
|
+
directiveDefs = hostDirectiveDefs = null;
|
|
12592
|
+
}
|
|
12593
|
+
else {
|
|
12594
|
+
[directiveDefs, hostDirectiveDefs] = matchResult;
|
|
12595
|
+
}
|
|
12559
12596
|
if (directiveDefs !== null) {
|
|
12560
|
-
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12561
|
-
// happen in a separate pass before the TNode flags have been initialized.
|
|
12562
|
-
for (let i = 0; i < directiveDefs.length; i++) {
|
|
12563
|
-
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directiveDefs[i].type);
|
|
12564
|
-
}
|
|
12565
12597
|
hasDirectives = true;
|
|
12566
|
-
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap);
|
|
12598
|
+
initializeDirectives(tView, lView, tNode, directiveDefs, exportsMap, hostDirectiveDefs);
|
|
12567
12599
|
}
|
|
12568
12600
|
if (exportsMap)
|
|
12569
12601
|
cacheMatchingLocalNames(tNode, localRefs, exportsMap);
|
|
@@ -12573,8 +12605,13 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
|
|
|
12573
12605
|
return hasDirectives;
|
|
12574
12606
|
}
|
|
12575
12607
|
/** Initializes the data structures necessary for a list of directives to be instantiated. */
|
|
12576
|
-
function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
12608
|
+
function initializeDirectives(tView, lView, tNode, directives, exportsMap, hostDirectiveDefs) {
|
|
12577
12609
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12610
|
+
// Publishes the directive types to DI so they can be injected. Needs to
|
|
12611
|
+
// happen in a separate pass before the TNode flags have been initialized.
|
|
12612
|
+
for (let i = 0; i < directives.length; i++) {
|
|
12613
|
+
diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, lView), tView, directives[i].type);
|
|
12614
|
+
}
|
|
12578
12615
|
initTNodeFlags(tNode, tView.data.length, directives.length);
|
|
12579
12616
|
// When the same token is provided by several directives on the same node, some rules apply in
|
|
12580
12617
|
// the viewEngine:
|
|
@@ -12620,7 +12657,7 @@ function initializeDirectives(tView, lView, tNode, directives, exportsMap) {
|
|
|
12620
12657
|
}
|
|
12621
12658
|
directiveIdx++;
|
|
12622
12659
|
}
|
|
12623
|
-
initializeInputAndOutputAliases(tView, tNode);
|
|
12660
|
+
initializeInputAndOutputAliases(tView, tNode, hostDirectiveDefs);
|
|
12624
12661
|
}
|
|
12625
12662
|
/**
|
|
12626
12663
|
* Add `hostBindings` to the `TView.hostBindingOpCodes`.
|
|
@@ -12732,12 +12769,13 @@ function invokeHostBindingsInCreationMode(def, directive) {
|
|
|
12732
12769
|
* Matches the current node against all available selectors.
|
|
12733
12770
|
* If a component is matched (at most one), it is returned in first position in the array.
|
|
12734
12771
|
*/
|
|
12735
|
-
function findDirectiveDefMatches(tView,
|
|
12772
|
+
function findDirectiveDefMatches(tView, tNode) {
|
|
12736
12773
|
var _a;
|
|
12737
12774
|
ngDevMode && assertFirstCreatePass(tView);
|
|
12738
12775
|
ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */);
|
|
12739
12776
|
const registry = tView.directiveRegistry;
|
|
12740
12777
|
let matches = null;
|
|
12778
|
+
let hostDirectiveDefs = null;
|
|
12741
12779
|
if (registry) {
|
|
12742
12780
|
for (let i = 0; i < registry.length; i++) {
|
|
12743
12781
|
const def = registry[i];
|
|
@@ -12763,7 +12801,8 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
12763
12801
|
// 4. Selector-matched directives.
|
|
12764
12802
|
if (def.findHostDirectiveDefs !== null) {
|
|
12765
12803
|
const hostDirectiveMatches = [];
|
|
12766
|
-
|
|
12804
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
12805
|
+
def.findHostDirectiveDefs(def, hostDirectiveMatches, hostDirectiveDefs);
|
|
12767
12806
|
// Add all host directives declared on this component, followed by the component itself.
|
|
12768
12807
|
// Host directives should execute first so the host has a chance to override changes
|
|
12769
12808
|
// to the DOM made by them.
|
|
@@ -12781,13 +12820,14 @@ function findDirectiveDefMatches(tView, lView, tNode) {
|
|
|
12781
12820
|
}
|
|
12782
12821
|
else {
|
|
12783
12822
|
// Append any host directives to the matches first.
|
|
12784
|
-
|
|
12823
|
+
hostDirectiveDefs = hostDirectiveDefs || new Map();
|
|
12824
|
+
(_a = def.findHostDirectiveDefs) === null || _a === void 0 ? void 0 : _a.call(def, def, matches, hostDirectiveDefs);
|
|
12785
12825
|
matches.push(def);
|
|
12786
12826
|
}
|
|
12787
12827
|
}
|
|
12788
12828
|
}
|
|
12789
12829
|
}
|
|
12790
|
-
return matches;
|
|
12830
|
+
return matches === null ? null : [matches, hostDirectiveDefs];
|
|
12791
12831
|
}
|
|
12792
12832
|
/**
|
|
12793
12833
|
* Marks a given TNode as a component's host. This consists of:
|
|
@@ -13868,15 +13908,26 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
13868
13908
|
let component;
|
|
13869
13909
|
let tElementNode;
|
|
13870
13910
|
try {
|
|
13871
|
-
const
|
|
13911
|
+
const rootComponentDef = this.componentDef;
|
|
13912
|
+
let rootDirectives;
|
|
13913
|
+
let hostDirectiveDefs = null;
|
|
13914
|
+
if (rootComponentDef.findHostDirectiveDefs) {
|
|
13915
|
+
rootDirectives = [];
|
|
13916
|
+
hostDirectiveDefs = new Map();
|
|
13917
|
+
rootComponentDef.findHostDirectiveDefs(rootComponentDef, rootDirectives, hostDirectiveDefs);
|
|
13918
|
+
rootDirectives.push(rootComponentDef);
|
|
13919
|
+
}
|
|
13920
|
+
else {
|
|
13921
|
+
rootDirectives = [rootComponentDef];
|
|
13922
|
+
}
|
|
13872
13923
|
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
|
|
13873
|
-
const componentView = createRootComponentView(hostTNode, hostRNode,
|
|
13924
|
+
const componentView = createRootComponentView(hostTNode, hostRNode, rootComponentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
|
|
13874
13925
|
tElementNode = getTNode(rootTView, HEADER_OFFSET);
|
|
13875
13926
|
// TODO(crisbeto): in practice `hostRNode` should always be defined, but there are some tests
|
|
13876
13927
|
// where the renderer is mocked out and `undefined` is returned. We should update the tests so
|
|
13877
13928
|
// that this check can be removed.
|
|
13878
13929
|
if (hostRNode) {
|
|
13879
|
-
setRootNodeAttributes(hostRenderer,
|
|
13930
|
+
setRootNodeAttributes(hostRenderer, rootComponentDef, hostRNode, rootSelectorOrNode);
|
|
13880
13931
|
}
|
|
13881
13932
|
if (projectableNodes !== undefined) {
|
|
13882
13933
|
projectNodes(tElementNode, this.ngContentSelectors, projectableNodes);
|
|
@@ -13884,7 +13935,7 @@ class ComponentFactory extends ComponentFactory$1 {
|
|
|
13884
13935
|
// TODO: should LifecycleHooksFeature and other host features be generated by the compiler and
|
|
13885
13936
|
// executed here?
|
|
13886
13937
|
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref
|
|
13887
|
-
component = createRootComponent(componentView,
|
|
13938
|
+
component = createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, [LifecycleHooksFeature]);
|
|
13888
13939
|
renderView(rootTView, rootLView, null);
|
|
13889
13940
|
}
|
|
13890
13941
|
finally {
|
|
@@ -13984,8 +14035,7 @@ function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives,
|
|
|
13984
14035
|
const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
|
|
13985
14036
|
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);
|
|
13986
14037
|
if (tView.firstCreatePass) {
|
|
13987
|
-
|
|
13988
|
-
markAsComponentHost(tView, tNode, 0);
|
|
14038
|
+
markAsComponentHost(tView, tNode, rootDirectives.length - 1);
|
|
13989
14039
|
}
|
|
13990
14040
|
addToViewTree(rootView, componentView);
|
|
13991
14041
|
// Store component view at node index, with node as the HOST
|
|
@@ -14007,12 +14057,12 @@ function applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer) {
|
|
|
14007
14057
|
* Creates a root component and sets it up with features and host bindings.Shared by
|
|
14008
14058
|
* renderComponent() and ViewContainerRef.createComponent().
|
|
14009
14059
|
*/
|
|
14010
|
-
function createRootComponent(componentView, rootComponentDef, rootDirectives, rootLView, hostFeatures) {
|
|
14060
|
+
function createRootComponent(componentView, rootComponentDef, rootDirectives, hostDirectiveDefs, rootLView, hostFeatures) {
|
|
14011
14061
|
const rootTNode = getCurrentTNode();
|
|
14012
14062
|
ngDevMode && assertDefined(rootTNode, 'tNode should have been already created');
|
|
14013
14063
|
const tView = rootLView[TVIEW];
|
|
14014
14064
|
const native = getNativeByTNode(rootTNode, rootLView);
|
|
14015
|
-
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null);
|
|
14065
|
+
initializeDirectives(tView, rootLView, rootTNode, rootDirectives, null, hostDirectiveDefs);
|
|
14016
14066
|
for (let i = 0; i < rootDirectives.length; i++) {
|
|
14017
14067
|
const directiveIndex = rootTNode.directiveStart + i;
|
|
14018
14068
|
const directiveInstance = getNodeInjectable(rootLView, tView, directiveIndex, rootTNode);
|
|
@@ -14333,7 +14383,7 @@ function ɵɵCopyDefinitionFeature(definition) {
|
|
|
14333
14383
|
* found in the LICENSE file at https://angular.io/license
|
|
14334
14384
|
*/
|
|
14335
14385
|
/**
|
|
14336
|
-
* This feature
|
|
14386
|
+
* This feature adds the host directives behavior to a directive definition by patching a
|
|
14337
14387
|
* function onto it. The expectation is that the runtime will invoke the function during
|
|
14338
14388
|
* directive matching.
|
|
14339
14389
|
*
|
|
@@ -14367,14 +14417,20 @@ function ɵɵHostDirectivesFeature(rawHostDirectives) {
|
|
|
14367
14417
|
});
|
|
14368
14418
|
};
|
|
14369
14419
|
}
|
|
14370
|
-
function findHostDirectiveDefs(
|
|
14371
|
-
if (
|
|
14372
|
-
for (const hostDirectiveConfig of
|
|
14420
|
+
function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
|
|
14421
|
+
if (currentDef.hostDirectives !== null) {
|
|
14422
|
+
for (const hostDirectiveConfig of currentDef.hostDirectives) {
|
|
14373
14423
|
const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
|
|
14374
|
-
|
|
14424
|
+
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
|
14425
|
+
validateHostDirective(hostDirectiveConfig, hostDirectiveDef, matchedDefs);
|
|
14426
|
+
}
|
|
14427
|
+
// We need to patch the `declaredInputs` so that
|
|
14428
|
+
// `ngOnChanges` can map the properties correctly.
|
|
14429
|
+
patchDeclaredInputs(hostDirectiveDef.declaredInputs, hostDirectiveConfig.inputs);
|
|
14375
14430
|
// Host directives execute before the host so that its host bindings can be overwritten.
|
|
14376
|
-
findHostDirectiveDefs(
|
|
14377
|
-
|
|
14431
|
+
findHostDirectiveDefs(hostDirectiveDef, matchedDefs, hostDirectiveDefs);
|
|
14432
|
+
hostDirectiveDefs.set(hostDirectiveDef, hostDirectiveConfig);
|
|
14433
|
+
matchedDefs.push(hostDirectiveDef);
|
|
14378
14434
|
}
|
|
14379
14435
|
}
|
|
14380
14436
|
}
|
|
@@ -14392,6 +14448,90 @@ function bindingArrayToMap(bindings) {
|
|
|
14392
14448
|
}
|
|
14393
14449
|
return result;
|
|
14394
14450
|
}
|
|
14451
|
+
/**
|
|
14452
|
+
* `ngOnChanges` has some leftover legacy ViewEngine behavior where the keys inside the
|
|
14453
|
+
* `SimpleChanges` event refer to the *declared* name of the input, not its public name or its
|
|
14454
|
+
* minified name. E.g. in `@Input('alias') foo: string`, the name in the `SimpleChanges` object
|
|
14455
|
+
* will always be `foo`, and not `alias` or the minified name of `foo` in apps using property
|
|
14456
|
+
* minification.
|
|
14457
|
+
*
|
|
14458
|
+
* This is achieved through the `DirectiveDef.declaredInputs` map that is constructed when the
|
|
14459
|
+
* definition is declared. When a property is written to the directive instance, the
|
|
14460
|
+
* `NgOnChangesFeature` will try to remap the property name being written to using the
|
|
14461
|
+
* `declaredInputs`.
|
|
14462
|
+
*
|
|
14463
|
+
* Since the host directive input remapping happens during directive matching, `declaredInputs`
|
|
14464
|
+
* won't contain the new alias that the input is available under. This function addresses the
|
|
14465
|
+
* issue by patching the host directive aliases to the `declaredInputs`. There is *not* a risk of
|
|
14466
|
+
* this patching accidentally introducing new inputs to the host directive, because `declaredInputs`
|
|
14467
|
+
* is used *only* by the `NgOnChangesFeature` when determining what name is used in the
|
|
14468
|
+
* `SimpleChanges` object which won't be reached if an input doesn't exist.
|
|
14469
|
+
*/
|
|
14470
|
+
function patchDeclaredInputs(declaredInputs, exposedInputs) {
|
|
14471
|
+
for (const publicName in exposedInputs) {
|
|
14472
|
+
if (exposedInputs.hasOwnProperty(publicName)) {
|
|
14473
|
+
const remappedPublicName = exposedInputs[publicName];
|
|
14474
|
+
const privateName = declaredInputs[publicName];
|
|
14475
|
+
// We *technically* shouldn't be able to hit this case because we can't have multiple
|
|
14476
|
+
// inputs on the same property and we have validations against conflicting aliases in
|
|
14477
|
+
// `validateMappings`. If we somehow did, it would lead to `ngOnChanges` being invoked
|
|
14478
|
+
// with the wrong name so we have a non-user-friendly assertion here just in case.
|
|
14479
|
+
if ((typeof ngDevMode === 'undefined' || ngDevMode) &&
|
|
14480
|
+
declaredInputs.hasOwnProperty(remappedPublicName)) {
|
|
14481
|
+
assertEqual(declaredInputs[remappedPublicName], declaredInputs[publicName], `Conflicting host directive input alias ${publicName}.`);
|
|
14482
|
+
}
|
|
14483
|
+
declaredInputs[remappedPublicName] = privateName;
|
|
14484
|
+
}
|
|
14485
|
+
}
|
|
14486
|
+
}
|
|
14487
|
+
/**
|
|
14488
|
+
* Verifies that the host directive has been configured correctly.
|
|
14489
|
+
* @param hostDirectiveConfig Host directive configuration object.
|
|
14490
|
+
* @param directiveDef Directive definition of the host directive.
|
|
14491
|
+
* @param matchedDefs Directives that have been matched so far.
|
|
14492
|
+
*/
|
|
14493
|
+
function validateHostDirective(hostDirectiveConfig, directiveDef, matchedDefs) {
|
|
14494
|
+
// TODO(crisbeto): implement more of these checks in the compiler.
|
|
14495
|
+
const type = hostDirectiveConfig.directive;
|
|
14496
|
+
if (directiveDef === null) {
|
|
14497
|
+
if (getComponentDef(type) !== null) {
|
|
14498
|
+
throw new RuntimeError(310 /* RuntimeErrorCode.HOST_DIRECTIVE_COMPONENT */, `Host directive ${type.name} cannot be a component.`);
|
|
14499
|
+
}
|
|
14500
|
+
throw new RuntimeError(307 /* RuntimeErrorCode.HOST_DIRECTIVE_UNRESOLVABLE */, `Could not resolve metadata for host directive ${type.name}. ` +
|
|
14501
|
+
`Make sure that the ${type.name} class is annotated with an @Directive decorator.`);
|
|
14502
|
+
}
|
|
14503
|
+
if (!directiveDef.standalone) {
|
|
14504
|
+
throw new RuntimeError(308 /* RuntimeErrorCode.HOST_DIRECTIVE_NOT_STANDALONE */, `Host directive ${directiveDef.type.name} must be standalone.`);
|
|
14505
|
+
}
|
|
14506
|
+
if (matchedDefs.indexOf(directiveDef) > -1) {
|
|
14507
|
+
throw new RuntimeError(309 /* RuntimeErrorCode.DUPLICATE_DIRECTITVE */, `Directive ${directiveDef.type.name} matches multiple times on the same element. ` +
|
|
14508
|
+
`Directives can only match an element once.`);
|
|
14509
|
+
}
|
|
14510
|
+
validateMappings('input', directiveDef, hostDirectiveConfig.inputs);
|
|
14511
|
+
validateMappings('output', directiveDef, hostDirectiveConfig.outputs);
|
|
14512
|
+
}
|
|
14513
|
+
/**
|
|
14514
|
+
* Checks that the host directive inputs/outputs configuration is valid.
|
|
14515
|
+
* @param bindingType Kind of binding that is being validated. Used in the error message.
|
|
14516
|
+
* @param def Definition of the host directive that is being validated against.
|
|
14517
|
+
* @param hostDirectiveDefs Host directive mapping object that shold be validated.
|
|
14518
|
+
*/
|
|
14519
|
+
function validateMappings(bindingType, def, hostDirectiveDefs) {
|
|
14520
|
+
const className = def.type.name;
|
|
14521
|
+
const bindings = bindingType === 'input' ? def.inputs : def.outputs;
|
|
14522
|
+
for (const publicName in hostDirectiveDefs) {
|
|
14523
|
+
if (hostDirectiveDefs.hasOwnProperty(publicName)) {
|
|
14524
|
+
if (!bindings.hasOwnProperty(publicName)) {
|
|
14525
|
+
throw new RuntimeError(311 /* RuntimeErrorCode.HOST_DIRECTIVE_UNDEFINED_BINDING */, `Directive ${className} does not have an ${bindingType} with a public name of ${publicName}.`);
|
|
14526
|
+
}
|
|
14527
|
+
const remappedPublicName = hostDirectiveDefs[publicName];
|
|
14528
|
+
if (bindings.hasOwnProperty(remappedPublicName) &&
|
|
14529
|
+
bindings[remappedPublicName] !== publicName) {
|
|
14530
|
+
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.`);
|
|
14531
|
+
}
|
|
14532
|
+
}
|
|
14533
|
+
}
|
|
14534
|
+
}
|
|
14395
14535
|
|
|
14396
14536
|
/**
|
|
14397
14537
|
* @license
|
|
@@ -24318,7 +24458,7 @@ function generateStandaloneInDeclarationsError(type, location) {
|
|
|
24318
24458
|
function verifySemanticsOfNgModuleDef(moduleType, allowDuplicateDeclarationsInRoot, importingModule) {
|
|
24319
24459
|
if (verifiedNgModule.get(moduleType))
|
|
24320
24460
|
return;
|
|
24321
|
-
// skip verifications of standalone components, directives and pipes
|
|
24461
|
+
// skip verifications of standalone components, directives, and pipes
|
|
24322
24462
|
if (isStandalone(moduleType))
|
|
24323
24463
|
return;
|
|
24324
24464
|
verifiedNgModule.set(moduleType, true);
|