@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/fesm2020/core.mjs CHANGED
@@ -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
  */
@@ -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`. As
4131
- * mentioned above, `'root'` is the default value for `providedIn`.
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.4');
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
- function generatePropertyAliases(inputAliasMap, directiveDefIdx, propStore) {
12409
- for (let publicName in inputAliasMap) {
12410
- if (inputAliasMap.hasOwnProperty(publicName)) {
12411
- propStore = propStore === null ? {} : propStore;
12412
- const internalName = inputAliasMap[publicName];
12413
- if (propStore.hasOwnProperty(publicName)) {
12414
- propStore[publicName].push(directiveDefIdx, internalName);
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
- (propStore[publicName] = [directiveDefIdx, internalName]);
12432
+ else if (hostDirectiveAliasMap.hasOwnProperty(publicName)) {
12433
+ addPropertyAlias(propertyAliases, directiveIndex, hostDirectiveAliasMap[publicName], internalName);
12418
12434
  }
12419
12435
  }
12420
12436
  }
12421
- return propStore;
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 i = start; i < end; i++) {
12437
- const directiveDef = tViewData[i];
12438
- inputsStore = generatePropertyAliases(directiveDef.inputs, i, inputsStore);
12439
- outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
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, i, tNodeAttrs) :
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, lView, tNode) {
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
- def.findHostDirectiveDefs(hostDirectiveMatches, def, tView, lView, tNode);
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
- def.findHostDirectiveDefs?.(matches, def, tView, lView, tNode);
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 rootDirectives = [this.componentDef];
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, this.componentDef, rootDirectives, rootLView, rendererFactory, hostRenderer);
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, this.componentDef, hostRNode, rootSelectorOrNode);
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, this.componentDef, rootDirectives, rootLView, [LifecycleHooksFeature]);
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
- diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, rootComponentDef.type);
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 add the host directives behavior to a directive definition by patching a
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(matches, def, tView, lView, tNode) {
14383
- if (def.hostDirectives !== null) {
14384
- for (const hostDirectiveConfig of def.hostDirectives) {
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
- // TODO(crisbeto): assert that the def exists.
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(matches, hostDirectiveDef, tView, lView, tNode);
14389
- matches.push(hostDirectiveDef);
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);