@angular/core 15.0.0-next.2 → 15.0.0-next.3

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.
Files changed (31) hide show
  1. package/esm2020/src/debug/debug_node.mjs +1 -1
  2. package/esm2020/src/render3/component_ref.mjs +2 -2
  3. package/esm2020/src/render3/context_discovery.mjs +12 -9
  4. package/esm2020/src/render3/definition.mjs +3 -2
  5. package/esm2020/src/render3/features/host_directives_feature.mjs +36 -13
  6. package/esm2020/src/render3/instructions/element.mjs +1 -1
  7. package/esm2020/src/render3/instructions/listener.mjs +2 -4
  8. package/esm2020/src/render3/instructions/lview_debug.mjs +9 -9
  9. package/esm2020/src/render3/instructions/projection.mjs +1 -1
  10. package/esm2020/src/render3/instructions/shared.mjs +60 -25
  11. package/esm2020/src/render3/instructions/styling.mjs +2 -2
  12. package/esm2020/src/render3/interfaces/definition.mjs +1 -1
  13. package/esm2020/src/render3/interfaces/node.mjs +3 -3
  14. package/esm2020/src/render3/interfaces/type_checks.mjs +3 -3
  15. package/esm2020/src/render3/jit/directive.mjs +7 -2
  16. package/esm2020/src/render3/node_manipulation.mjs +6 -5
  17. package/esm2020/src/render3/node_manipulation_i18n.mjs +2 -2
  18. package/esm2020/src/version.mjs +1 -1
  19. package/esm2020/testing/src/logger.mjs +3 -3
  20. package/esm2020/testing/src/ng_zone_mock.mjs +3 -3
  21. package/fesm2015/core.mjs +137 -73
  22. package/fesm2015/core.mjs.map +1 -1
  23. package/fesm2015/testing.mjs +129 -71
  24. package/fesm2015/testing.mjs.map +1 -1
  25. package/fesm2020/core.mjs +136 -72
  26. package/fesm2020/core.mjs.map +1 -1
  27. package/fesm2020/testing.mjs +129 -70
  28. package/fesm2020/testing.mjs.map +1 -1
  29. package/index.d.ts +41 -29
  30. package/package.json +1 -1
  31. package/testing/index.d.ts +1 -1
package/fesm2020/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v15.0.0-next.2
2
+ * @license Angular v15.0.0-next.3
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -931,7 +931,8 @@ function ɵɵdefineComponent(componentDefinition) {
931
931
  setInput: null,
932
932
  schemas: componentDefinition.schemas || null,
933
933
  tView: null,
934
- applyHostDirectives: null,
934
+ findHostDirectiveDefs: null,
935
+ hostDirectives: null,
935
936
  };
936
937
  const dependencies = componentDefinition.dependencies;
937
938
  const feature = componentDefinition.features;
@@ -1272,10 +1273,10 @@ function isLContainer(value) {
1272
1273
  return Array.isArray(value) && value[TYPE] === true;
1273
1274
  }
1274
1275
  function isContentQueryHost(tNode) {
1275
- return (tNode.flags & 8 /* TNodeFlags.hasContentQuery */) !== 0;
1276
+ return (tNode.flags & 4 /* TNodeFlags.hasContentQuery */) !== 0;
1276
1277
  }
1277
1278
  function isComponentHost(tNode) {
1278
- return (tNode.flags & 2 /* TNodeFlags.isComponentHost */) === 2 /* TNodeFlags.isComponentHost */;
1279
+ return tNode.componentOffset > -1;
1279
1280
  }
1280
1281
  function isDirectiveHost(tNode) {
1281
1282
  return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
@@ -2685,7 +2686,7 @@ const unusedValueExportToPlacateAjd$5 = 1;
2685
2686
  * @param tNode
2686
2687
  */
2687
2688
  function hasClassInput(tNode) {
2688
- return (tNode.flags & 16 /* TNodeFlags.hasClassInput */) !== 0;
2689
+ return (tNode.flags & 8 /* TNodeFlags.hasClassInput */) !== 0;
2689
2690
  }
2690
2691
  /**
2691
2692
  * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
@@ -2709,7 +2710,7 @@ function hasClassInput(tNode) {
2709
2710
  * @param tNode
2710
2711
  */
2711
2712
  function hasStyleInput(tNode) {
2712
- return (tNode.flags & 32 /* TNodeFlags.hasStyleInput */) !== 0;
2713
+ return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
2713
2714
  }
2714
2715
 
2715
2716
  /**
@@ -7250,7 +7251,7 @@ class Version {
7250
7251
  /**
7251
7252
  * @publicApi
7252
7253
  */
7253
- const VERSION = new Version('15.0.0-next.2');
7254
+ const VERSION = new Version('15.0.0-next.3');
7254
7255
 
7255
7256
  /**
7256
7257
  * @license
@@ -8069,18 +8070,21 @@ function findViaDirective(lView, directiveInstance) {
8069
8070
  */
8070
8071
  function getDirectivesAtNodeIndex(nodeIndex, lView, includeComponents) {
8071
8072
  const tNode = lView[TVIEW].data[nodeIndex];
8072
- let directiveStartIndex = tNode.directiveStart;
8073
- if (directiveStartIndex == 0)
8073
+ if (tNode.directiveStart === 0)
8074
8074
  return EMPTY_ARRAY;
8075
- const directiveEndIndex = tNode.directiveEnd;
8076
- if (!includeComponents && tNode.flags & 2 /* TNodeFlags.isComponentHost */)
8077
- directiveStartIndex++;
8078
- return lView.slice(directiveStartIndex, directiveEndIndex);
8075
+ const results = [];
8076
+ for (let i = tNode.directiveStart; i < tNode.directiveEnd; i++) {
8077
+ const directiveInstance = lView[i];
8078
+ if (!isComponentInstance(directiveInstance) || includeComponents) {
8079
+ results.push(directiveInstance);
8080
+ }
8081
+ }
8082
+ return results;
8079
8083
  }
8080
8084
  function getComponentAtNodeIndex(nodeIndex, lView) {
8081
8085
  const tNode = lView[TVIEW].data[nodeIndex];
8082
- let directiveStartIndex = tNode.directiveStart;
8083
- return tNode.flags & 2 /* TNodeFlags.isComponentHost */ ? lView[directiveStartIndex] : null;
8086
+ const { directiveStart, componentOffset } = tNode;
8087
+ return componentOffset > -1 ? lView[directiveStart + componentOffset] : null;
8084
8088
  }
8085
8089
  /**
8086
8090
  * Returns a map of local references (local reference name => element or directive instance) that
@@ -8883,9 +8887,10 @@ function getClosestRElement(tView, tNode, lView) {
8883
8887
  }
8884
8888
  else {
8885
8889
  ngDevMode && assertTNodeType(parentTNode, 3 /* TNodeType.AnyRNode */ | 4 /* TNodeType.Container */);
8886
- if (parentTNode.flags & 2 /* TNodeFlags.isComponentHost */) {
8890
+ const { componentOffset } = parentTNode;
8891
+ if (componentOffset > -1) {
8887
8892
  ngDevMode && assertTNodeForLView(parentTNode, lView);
8888
- const encapsulation = tView.data[parentTNode.directiveStart].encapsulation;
8893
+ const { encapsulation } = tView.data[parentTNode.directiveStart + componentOffset];
8889
8894
  // We've got a parent which is an element in the current view. We just need to verify if the
8890
8895
  // parent element is not a component. Component's content nodes are not inserted immediately
8891
8896
  // because they will be projected, and so doing insert at this point would be wasteful.
@@ -9118,10 +9123,10 @@ function applyNodes(renderer, action, tNode, lView, parentRElement, beforeNode,
9118
9123
  if (isProjection) {
9119
9124
  if (action === 0 /* WalkTNodeTreeAction.Create */) {
9120
9125
  rawSlotValue && attachPatchData(unwrapRNode(rawSlotValue), lView);
9121
- tNode.flags |= 4 /* TNodeFlags.isProjected */;
9126
+ tNode.flags |= 2 /* TNodeFlags.isProjected */;
9122
9127
  }
9123
9128
  }
9124
- if ((tNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
9129
+ if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
9125
9130
  if (tNodeType & 8 /* TNodeType.ElementContainer */) {
9126
9131
  applyNodes(renderer, action, tNode.child, lView, parentRElement, beforeNode, false);
9127
9132
  applyToElementOrContainer(action, renderer, parentRElement, rawSlotValue, beforeNode);
@@ -11175,6 +11180,7 @@ class TNode {
11175
11180
  index, //
11176
11181
  insertBeforeIndex, //
11177
11182
  injectorIndex, //
11183
+ componentOffset, //
11178
11184
  directiveStart, //
11179
11185
  directiveEnd, //
11180
11186
  directiveStylingLast, //
@@ -11207,6 +11213,7 @@ class TNode {
11207
11213
  this.index = index;
11208
11214
  this.insertBeforeIndex = insertBeforeIndex;
11209
11215
  this.injectorIndex = injectorIndex;
11216
+ this.componentOffset = componentOffset;
11210
11217
  this.directiveStart = directiveStart;
11211
11218
  this.directiveEnd = directiveEnd;
11212
11219
  this.directiveStylingLast = directiveStylingLast;
@@ -11284,21 +11291,19 @@ class TNode {
11284
11291
  }
11285
11292
  get flags_() {
11286
11293
  const flags = [];
11287
- if (this.flags & 16 /* TNodeFlags.hasClassInput */)
11294
+ if (this.flags & 8 /* TNodeFlags.hasClassInput */)
11288
11295
  flags.push('TNodeFlags.hasClassInput');
11289
- if (this.flags & 8 /* TNodeFlags.hasContentQuery */)
11296
+ if (this.flags & 4 /* TNodeFlags.hasContentQuery */)
11290
11297
  flags.push('TNodeFlags.hasContentQuery');
11291
- if (this.flags & 32 /* TNodeFlags.hasStyleInput */)
11298
+ if (this.flags & 16 /* TNodeFlags.hasStyleInput */)
11292
11299
  flags.push('TNodeFlags.hasStyleInput');
11293
- if (this.flags & 128 /* TNodeFlags.hasHostBindings */)
11300
+ if (this.flags & 64 /* TNodeFlags.hasHostBindings */)
11294
11301
  flags.push('TNodeFlags.hasHostBindings');
11295
- if (this.flags & 2 /* TNodeFlags.isComponentHost */)
11296
- flags.push('TNodeFlags.isComponentHost');
11297
11302
  if (this.flags & 1 /* TNodeFlags.isDirectiveHost */)
11298
11303
  flags.push('TNodeFlags.isDirectiveHost');
11299
- if (this.flags & 64 /* TNodeFlags.isDetached */)
11304
+ if (this.flags & 32 /* TNodeFlags.isDetached */)
11300
11305
  flags.push('TNodeFlags.isDetached');
11301
- if (this.flags & 4 /* TNodeFlags.isProjected */)
11306
+ if (this.flags & 2 /* TNodeFlags.isProjected */)
11302
11307
  flags.push('TNodeFlags.isProjected');
11303
11308
  return flags.join('|');
11304
11309
  }
@@ -11808,7 +11813,7 @@ function getOrCreateTNode(tView, index, type, name, attrs) {
11808
11813
  // See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
11809
11814
  // If the `TNode` was not pre-declared than it means it was not mentioned which means it was
11810
11815
  // removed, so we mark it as detached.
11811
- tNode.flags |= 64 /* TNodeFlags.isDetached */;
11816
+ tNode.flags |= 32 /* TNodeFlags.isDetached */;
11812
11817
  }
11813
11818
  }
11814
11819
  else if (tNode.type & 64 /* TNodeType.Placeholder */) {
@@ -12112,7 +12117,7 @@ function createDirectivesInstances(tView, lView, tNode) {
12112
12117
  if (!getBindingsEnabled())
12113
12118
  return;
12114
12119
  instantiateAllDirectives(tView, lView, tNode, getNativeByTNode(tNode, lView));
12115
- if ((tNode.flags & 128 /* TNodeFlags.hasHostBindings */) === 128 /* TNodeFlags.hasHostBindings */) {
12120
+ if ((tNode.flags & 64 /* TNodeFlags.hasHostBindings */) === 64 /* TNodeFlags.hasHostBindings */) {
12116
12121
  invokeDirectivesHostBindings(tView, lView, tNode);
12117
12122
  }
12118
12123
  }
@@ -12312,6 +12317,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
12312
12317
  index, // index: number
12313
12318
  null, // insertBeforeIndex: null|-1|number|number[]
12314
12319
  injectorIndex, // injectorIndex: number
12320
+ -1, // componentOffset: number
12315
12321
  -1, // directiveStart: number
12316
12322
  -1, // directiveEnd: number
12317
12323
  -1, // directiveStylingLast: number
@@ -12347,6 +12353,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
12347
12353
  directiveStart: -1,
12348
12354
  directiveEnd: -1,
12349
12355
  directiveStylingLast: -1,
12356
+ componentOffset: -1,
12350
12357
  propertyBindings: null,
12351
12358
  flags: 0,
12352
12359
  providerIndexes: 0,
@@ -12410,24 +12417,23 @@ function initializeInputAndOutputAliases(tView, tNode) {
12410
12417
  let outputsStore = null;
12411
12418
  for (let i = start; i < end; i++) {
12412
12419
  const directiveDef = tViewData[i];
12413
- const directiveInputs = directiveDef.inputs;
12420
+ inputsStore = generatePropertyAliases(directiveDef.inputs, i, inputsStore);
12421
+ outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
12414
12422
  // Do not use unbound attributes as inputs to structural directives, since structural
12415
12423
  // directive inputs can only be set using microsyntax (e.g. `<div *dir="exp">`).
12416
12424
  // TODO(FW-1930): microsyntax expressions may also contain unbound/static attributes, which
12417
12425
  // should be set for inline templates.
12418
- const initialInputs = (tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
12419
- generateInitialInputs(directiveInputs, tNodeAttrs) :
12426
+ const initialInputs = (inputsStore !== null && tNodeAttrs !== null && !isInlineTemplate(tNode)) ?
12427
+ generateInitialInputs(inputsStore, i, tNodeAttrs) :
12420
12428
  null;
12421
12429
  inputsFromAttrs.push(initialInputs);
12422
- inputsStore = generatePropertyAliases(directiveInputs, i, inputsStore);
12423
- outputsStore = generatePropertyAliases(directiveDef.outputs, i, outputsStore);
12424
12430
  }
12425
12431
  if (inputsStore !== null) {
12426
12432
  if (inputsStore.hasOwnProperty('class')) {
12427
- tNode.flags |= 16 /* TNodeFlags.hasClassInput */;
12433
+ tNode.flags |= 8 /* TNodeFlags.hasClassInput */;
12428
12434
  }
12429
12435
  if (inputsStore.hasOwnProperty('style')) {
12430
- tNode.flags |= 32 /* TNodeFlags.hasStyleInput */;
12436
+ tNode.flags |= 16 /* TNodeFlags.hasStyleInput */;
12431
12437
  }
12432
12438
  }
12433
12439
  tNode.initialInputs = inputsFromAttrs;
@@ -12548,7 +12554,7 @@ function instantiateRootComponent(tView, lView, def) {
12548
12554
  configureViewWithDirective(tView, rootTNode, lView, directiveIndex, def);
12549
12555
  initializeInputAndOutputAliases(tView, rootTNode);
12550
12556
  }
12551
- const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart, rootTNode);
12557
+ const directive = getNodeInjectable(lView, tView, rootTNode.directiveStart + rootTNode.componentOffset, rootTNode);
12552
12558
  attachPatchData(directive, lView);
12553
12559
  const native = getNativeByTNode(rootTNode, lView);
12554
12560
  if (native) {
@@ -12565,7 +12571,10 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
12565
12571
  ngDevMode && assertFirstCreatePass(tView);
12566
12572
  let hasDirectives = false;
12567
12573
  if (getBindingsEnabled()) {
12568
- const directiveDefs = findDirectiveDefMatches(tView, lView, tNode);
12574
+ const directiveDefsMatchedBySelectors = findDirectiveDefMatches(tView, lView, tNode);
12575
+ const directiveDefs = directiveDefsMatchedBySelectors ?
12576
+ findHostDirectiveDefs$1(directiveDefsMatchedBySelectors, tView, lView, tNode) :
12577
+ null;
12569
12578
  const exportsMap = localRefs === null ? null : { '': -1 };
12570
12579
  if (directiveDefs !== null) {
12571
12580
  hasDirectives = true;
@@ -12594,9 +12603,9 @@ function resolveDirectives(tView, lView, tNode, localRefs) {
12594
12603
  configureViewWithDirective(tView, tNode, lView, directiveIdx, def);
12595
12604
  saveNameToExportMap(directiveIdx, def, exportsMap);
12596
12605
  if (def.contentQueries !== null)
12597
- tNode.flags |= 8 /* TNodeFlags.hasContentQuery */;
12606
+ tNode.flags |= 4 /* TNodeFlags.hasContentQuery */;
12598
12607
  if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0)
12599
- tNode.flags |= 128 /* TNodeFlags.hasHostBindings */;
12608
+ tNode.flags |= 64 /* TNodeFlags.hasHostBindings */;
12600
12609
  const lifeCycleHooks = def.type.prototype;
12601
12610
  // Only push a node index into the preOrderHooks array if this is the first
12602
12611
  // pre-order hook found on this node.
@@ -12749,20 +12758,19 @@ function findDirectiveDefMatches(tView, viewData, tNode) {
12749
12758
  if (ngDevMode) {
12750
12759
  assertTNodeType(tNode, 2 /* TNodeType.Element */, `"${tNode.value}" tags cannot be used as component hosts. ` +
12751
12760
  `Please use a different tag to activate the ${stringify(def.type)} component.`);
12752
- if (tNode.flags & 2 /* TNodeFlags.isComponentHost */) {
12761
+ if (isComponentHost(tNode)) {
12753
12762
  // If another component has been matched previously, it's the first element in the
12754
12763
  // `matches` array, see how we store components/directives in `matches` below.
12755
12764
  throwMultipleComponentError(tNode, matches[0].type, def.type);
12756
12765
  }
12757
12766
  }
12758
- markAsComponentHost(tView, tNode);
12767
+ markAsComponentHost(tView, tNode, 0);
12759
12768
  // The component is always stored first with directives after.
12760
12769
  matches.unshift(def);
12761
12770
  }
12762
12771
  else {
12763
12772
  matches.push(def);
12764
12773
  }
12765
- def.applyHostDirectives?.(tView, viewData, tNode, matches);
12766
12774
  }
12767
12775
  }
12768
12776
  }
@@ -12770,15 +12778,36 @@ function findDirectiveDefMatches(tView, viewData, tNode) {
12770
12778
  }
12771
12779
  /**
12772
12780
  * Marks a given TNode as a component's host. This consists of:
12773
- * - setting appropriate TNode flags;
12781
+ * - setting the component offset on the TNode.
12774
12782
  * - storing index of component's host element so it will be queued for view refresh during CD.
12775
12783
  */
12776
- function markAsComponentHost(tView, hostTNode) {
12784
+ function markAsComponentHost(tView, hostTNode, componentOffset) {
12777
12785
  ngDevMode && assertFirstCreatePass(tView);
12778
- hostTNode.flags |= 2 /* TNodeFlags.isComponentHost */;
12786
+ ngDevMode && assertGreaterThan(componentOffset, -1, 'componentOffset must be great than -1');
12787
+ hostTNode.componentOffset = componentOffset;
12779
12788
  (tView.components || (tView.components = ngDevMode ? new TViewComponents() : []))
12780
12789
  .push(hostTNode.index);
12781
12790
  }
12791
+ /**
12792
+ * Given an array of directives that were matched by their selectors, this function
12793
+ * produces a new array that also includes any host directives that have to be applied.
12794
+ * @param selectorMatches Directives matched in a template based on their selectors.
12795
+ * @param tView Current TView.
12796
+ * @param lView Current LView.
12797
+ * @param tNode Current TNode that is being matched.
12798
+ */
12799
+ function findHostDirectiveDefs$1(selectorMatches, tView, lView, tNode) {
12800
+ const matches = [];
12801
+ for (const def of selectorMatches) {
12802
+ if (def.findHostDirectiveDefs === null) {
12803
+ matches.push(def);
12804
+ }
12805
+ else {
12806
+ def.findHostDirectiveDefs(matches, def, tView, lView, tNode);
12807
+ }
12808
+ }
12809
+ return matches;
12810
+ }
12782
12811
  /** Caches local names and their matching directive indices for query and template lookups. */
12783
12812
  function cacheMatchingLocalNames(tNode, localRefs, exportsMap) {
12784
12813
  if (localRefs) {
@@ -12921,10 +12950,11 @@ function setInputsFromAttrs(lView, directiveIndex, instance, def, tNode, initial
12921
12950
  *
12922
12951
  * <my-component name="Bess"></my-component>
12923
12952
  *
12924
- * @param inputs The list of inputs from the directive def
12925
- * @param attrs The static attrs on this node
12953
+ * @param inputs Input alias map that was generated from the directive def inputs.
12954
+ * @param directiveIndex Index of the directive that is currently being processed.
12955
+ * @param attrs Static attrs on this node.
12926
12956
  */
12927
- function generateInitialInputs(inputs, attrs) {
12957
+ function generateInitialInputs(inputs, directiveIndex, attrs) {
12928
12958
  let inputsToStore = null;
12929
12959
  let i = 0;
12930
12960
  while (i < attrs.length) {
@@ -12945,7 +12975,17 @@ function generateInitialInputs(inputs, attrs) {
12945
12975
  if (inputs.hasOwnProperty(attrName)) {
12946
12976
  if (inputsToStore === null)
12947
12977
  inputsToStore = [];
12948
- inputsToStore.push(attrName, inputs[attrName], attrs[i + 1]);
12978
+ // Find the input's public name from the input store. Note that we can be found easier
12979
+ // through the directive def, but we want to do it using the inputs store so that it can
12980
+ // account for host directive aliases.
12981
+ const inputConfig = inputs[attrName];
12982
+ for (let j = 0; j < inputConfig.length; j += 2) {
12983
+ if (inputConfig[j] === directiveIndex) {
12984
+ inputsToStore.push(attrName, inputConfig[j + 1], attrs[i + 1]);
12985
+ // A directive can't have multiple inputs with the same name so we can break here.
12986
+ break;
12987
+ }
12988
+ }
12949
12989
  }
12950
12990
  i += 2;
12951
12991
  }
@@ -13978,7 +14018,7 @@ function createRootComponentView(rNode, def, rootView, rendererFactory, hostRend
13978
14018
  const componentView = createLView(rootView, getOrCreateComponentTView(def), null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
13979
14019
  if (tView.firstCreatePass) {
13980
14020
  diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, rootView), tView, def.type);
13981
- markAsComponentHost(tView, tNode);
14021
+ markAsComponentHost(tView, tNode, 0);
13982
14022
  initTNodeFlags(tNode, rootView.length, 1);
13983
14023
  }
13984
14024
  addToViewTree(rootView, componentView);
@@ -14275,6 +14315,13 @@ function ɵɵCopyDefinitionFeature(definition) {
14275
14315
  }
14276
14316
  }
14277
14317
 
14318
+ /**
14319
+ * @license
14320
+ * Copyright Google LLC All Rights Reserved.
14321
+ *
14322
+ * Use of this source code is governed by an MIT-style license that can be
14323
+ * found in the LICENSE file at https://angular.io/license
14324
+ */
14278
14325
  /**
14279
14326
  * This feature add the host directives behavior to a directive definition by patching a
14280
14327
  * function onto it. The expectation is that the runtime will invoke the function during
@@ -14296,29 +14343,43 @@ function ɵɵCopyDefinitionFeature(definition) {
14296
14343
  * @codeGenApi
14297
14344
  */
14298
14345
  function ɵɵHostDirectivesFeature(rawHostDirectives) {
14299
- const unwrappedHostDirectives = Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives();
14300
- const hostDirectives = unwrappedHostDirectives.map(dir => typeof dir === 'function' ? { directive: dir, inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } : {
14301
- directive: dir.directive,
14302
- inputs: bindingArrayToMap(dir.inputs),
14303
- outputs: bindingArrayToMap(dir.outputs)
14304
- });
14305
14346
  return (definition) => {
14306
- // TODO(crisbeto): implement host directive matching logic.
14307
- definition.applyHostDirectives =
14308
- (tView, viewData, tNode, matches) => { };
14347
+ definition.findHostDirectiveDefs = findHostDirectiveDefs;
14348
+ definition.hostDirectives =
14349
+ (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
14350
+ return typeof dir === 'function' ?
14351
+ { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
14352
+ {
14353
+ directive: resolveForwardRef(dir.directive),
14354
+ inputs: bindingArrayToMap(dir.inputs),
14355
+ outputs: bindingArrayToMap(dir.outputs)
14356
+ };
14357
+ });
14309
14358
  };
14310
14359
  }
14360
+ function findHostDirectiveDefs(matches, def, tView, lView, tNode) {
14361
+ if (def.hostDirectives !== null) {
14362
+ for (const hostDirectiveConfig of def.hostDirectives) {
14363
+ const hostDirectiveDef = getDirectiveDef(hostDirectiveConfig.directive);
14364
+ // TODO(crisbeto): assert that the def exists.
14365
+ // Host directives execute before the host so that its host bindings can be overwritten.
14366
+ findHostDirectiveDefs(matches, hostDirectiveDef, tView, lView, tNode);
14367
+ }
14368
+ }
14369
+ // Push the def itself at the end since it needs to execute after the host directives.
14370
+ matches.push(def);
14371
+ }
14311
14372
  /**
14312
14373
  * Converts an array in the form of `['publicName', 'alias', 'otherPublicName', 'otherAlias']` into
14313
14374
  * a map in the form of `{publicName: 'alias', otherPublicName: 'otherAlias'}`.
14314
14375
  */
14315
14376
  function bindingArrayToMap(bindings) {
14316
- if (!bindings || bindings.length === 0) {
14377
+ if (bindings === undefined || bindings.length === 0) {
14317
14378
  return EMPTY_OBJ;
14318
14379
  }
14319
14380
  const result = {};
14320
- for (let i = 1; i < bindings.length; i += 2) {
14321
- result[bindings[i - 1]] = bindings[i];
14381
+ for (let i = 0; i < bindings.length; i += 2) {
14382
+ result[bindings[i]] = bindings[i + 1];
14322
14383
  }
14323
14384
  return result;
14324
14385
  }
@@ -15277,7 +15338,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
15277
15338
  if (styles !== null) {
15278
15339
  writeDirectStyle(renderer, native, styles);
15279
15340
  }
15280
- if ((tNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
15341
+ if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
15281
15342
  // In the i18n case, the translation may have removed this element, so only add it if it is not
15282
15343
  // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
15283
15344
  appendChild(tView, lView, native, tNode);
@@ -15715,9 +15776,7 @@ function wrapListener(tNode, lView, context, listenerFn, wrapWithPreventDefault)
15715
15776
  }
15716
15777
  // In order to be backwards compatible with View Engine, events on component host nodes
15717
15778
  // must also mark the component view itself dirty (i.e. the view that it owns).
15718
- const startView = tNode.flags & 2 /* TNodeFlags.isComponentHost */ ?
15719
- getComponentLViewByIndex(tNode.index, lView) :
15720
- lView;
15779
+ const startView = tNode.componentOffset > -1 ? getComponentLViewByIndex(tNode.index, lView) : lView;
15721
15780
  markViewDirty(startView);
15722
15781
  let result = executeListenerWithErrorHandling(lView, context, listenerFn, e);
15723
15782
  // A just-invoked listener function might have coalesced listeners so we need to check for
@@ -15874,7 +15933,7 @@ function ɵɵprojection(nodeIndex, selectorIndex = 0, attrs) {
15874
15933
  tProjectionNode.projection = selectorIndex;
15875
15934
  // `<ng-content>` has no content
15876
15935
  setCurrentTNodeAsNotParent();
15877
- if ((tProjectionNode.flags & 64 /* TNodeFlags.isDetached */) !== 64 /* TNodeFlags.isDetached */) {
15936
+ if ((tProjectionNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
15878
15937
  // re-distribution of projectable nodes is stored on a component's view level
15879
15938
  applyProjection(tView, lView, tProjectionNode);
15880
15939
  }
@@ -17788,7 +17847,7 @@ function normalizeSuffix(value, suffix) {
17788
17847
  * @param isClassBased `true` if `class` (`false` if `style`)
17789
17848
  */
17790
17849
  function hasStylingInputShadow(tNode, isClassBased) {
17791
- return (tNode.flags & (isClassBased ? 16 /* TNodeFlags.hasClassInput */ : 32 /* TNodeFlags.hasStyleInput */)) !== 0;
17850
+ return (tNode.flags & (isClassBased ? 8 /* TNodeFlags.hasClassInput */ : 16 /* TNodeFlags.hasStyleInput */)) !== 0;
17792
17851
  }
17793
17852
 
17794
17853
  /**
@@ -19480,7 +19539,7 @@ function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parent
19480
19539
  anchorRNode = i18nParent;
19481
19540
  i18nParent = parentRElement;
19482
19541
  }
19483
- if (i18nParent !== null && (childTNode.flags & 2 /* TNodeFlags.isComponentHost */) === 0) {
19542
+ if (i18nParent !== null && childTNode.componentOffset === -1) {
19484
19543
  for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
19485
19544
  // No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
19486
19545
  // see `assertDomNode` below.
@@ -24981,7 +25040,12 @@ function directiveMetadata(type, metadata) {
24981
25040
  providers: metadata.providers || null,
24982
25041
  viewQueries: extractQueriesMetadata(type, propMetadata, isViewQuery),
24983
25042
  isStandalone: !!metadata.standalone,
24984
- hostDirectives: null,
25043
+ hostDirectives:
25044
+ // TODO(crisbeto): remove the `as any` usage here and down in the `map` call once
25045
+ // host directives are exposed in the public API.
25046
+ metadata
25047
+ .hostDirectives?.map((directive) => typeof directive === 'function' ? { directive } : directive) ||
25048
+ null
24985
25049
  };
24986
25050
  }
24987
25051
  /**
@@ -28235,7 +28299,7 @@ function _queryNodeChildren(tNode, lView, predicate, matches, elementsOnly, root
28235
28299
  if (rootNativeNode !== nativeNode) {
28236
28300
  // To determine the next node to be processed, we need to use the next or the projectionNext
28237
28301
  // link, depending on whether the current node has been projected.
28238
- const nextTNode = (tNode.flags & 4 /* TNodeFlags.isProjected */) ? tNode.projectionNext : tNode.next;
28302
+ const nextTNode = (tNode.flags & 2 /* TNodeFlags.isProjected */) ? tNode.projectionNext : tNode.next;
28239
28303
  if (nextTNode) {
28240
28304
  _queryNodeChildren(nextTNode, lView, predicate, matches, elementsOnly, rootNativeNode);
28241
28305
  }