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