@angular/core 17.0.4 → 17.0.6

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 (32) hide show
  1. package/esm2022/src/application_init.mjs +2 -2
  2. package/esm2022/src/hydration/annotate.mjs +30 -20
  3. package/esm2022/src/hydration/interfaces.mjs +1 -1
  4. package/esm2022/src/hydration/node_lookup_utils.mjs +23 -2
  5. package/esm2022/src/render3/features/host_directives_feature.mjs +20 -13
  6. package/esm2022/src/render3/instructions/change_detection.mjs +3 -4
  7. package/esm2022/src/render3/node_manipulation.mjs +2 -2
  8. package/esm2022/src/render3/util/view_utils.mjs +11 -12
  9. package/esm2022/src/render3/view_manipulation.mjs +13 -5
  10. package/esm2022/src/version.mjs +1 -1
  11. package/esm2022/testing/src/logger.mjs +3 -3
  12. package/esm2022/testing/src/test_bed.mjs +3 -3
  13. package/esm2022/testing/src/test_bed_compiler.mjs +19 -10
  14. package/fesm2022/core.mjs +94 -50
  15. package/fesm2022/core.mjs.map +1 -1
  16. package/fesm2022/primitives/signals.mjs +1 -1
  17. package/fesm2022/rxjs-interop.mjs +1 -1
  18. package/fesm2022/testing.mjs +21 -12
  19. package/fesm2022/testing.mjs.map +1 -1
  20. package/index.d.ts +8 -3
  21. package/package.json +1 -1
  22. package/primitives/signals/index.d.ts +1 -1
  23. package/rxjs-interop/index.d.ts +1 -1
  24. package/schematics/migrations/block-template-entities/bundle.js +812 -457
  25. package/schematics/migrations/block-template-entities/bundle.js.map +4 -4
  26. package/schematics/migrations/compiler-options/bundle.js +13 -13
  27. package/schematics/migrations/transfer-state/bundle.js +13 -13
  28. package/schematics/ng-generate/control-flow-migration/bundle.js +1126 -557
  29. package/schematics/ng-generate/control-flow-migration/bundle.js.map +4 -4
  30. package/schematics/ng-generate/standalone-migration/bundle.js +1206 -735
  31. package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
  32. package/testing/index.d.ts +1 -1
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.4
2
+ * @license Angular v17.0.6
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2722,20 +2722,19 @@ function walkUpViews(nestingLevel, currentView) {
2722
2722
  }
2723
2723
  return currentView;
2724
2724
  }
2725
+ function requiresRefreshOrTraversal(lView) {
2726
+ return lView[FLAGS] & (1024 /* LViewFlags.RefreshView */ | 8192 /* LViewFlags.HasChildViewsToRefresh */) ||
2727
+ lView[REACTIVE_TEMPLATE_CONSUMER]?.dirty;
2728
+ }
2725
2729
  /**
2726
- * Updates the `DESCENDANT_VIEWS_TO_REFRESH` counter on the parents of the `LView` as well as the
2727
- * parents above that whose
2728
- * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
2729
- * or
2730
- * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
2731
- * When attaching/re-attaching an `LView` to the change detection tree, we need to ensure that the
2732
- * views above it are traversed during change detection if this one is marked for refresh or has
2733
- * some child or descendant that needs to be refreshed.
2730
+ * Updates the `HasChildViewsToRefresh` flag on the parents of the `LView` as well as the
2731
+ * parents above.
2734
2732
  */
2735
2733
  function updateAncestorTraversalFlagsOnAttach(lView) {
2736
- if (lView[FLAGS] & (1024 /* LViewFlags.RefreshView */ | 8192 /* LViewFlags.HasChildViewsToRefresh */)) {
2737
- markAncestorsForTraversal(lView);
2734
+ if (!requiresRefreshOrTraversal(lView)) {
2735
+ return;
2738
2736
  }
2737
+ markAncestorsForTraversal(lView);
2739
2738
  }
2740
2739
  /**
2741
2740
  * Ensures views above the given `lView` are traversed during change detection even when they are
@@ -8268,7 +8267,6 @@ function detachView(lContainer, removeIndex) {
8268
8267
  function destroyLView(tView, lView) {
8269
8268
  if (!(lView[FLAGS] & 256 /* LViewFlags.Destroyed */)) {
8270
8269
  const renderer = lView[RENDERER];
8271
- lView[REACTIVE_TEMPLATE_CONSUMER] && consumerDestroy$1(lView[REACTIVE_TEMPLATE_CONSUMER]);
8272
8270
  if (renderer.destroyNode) {
8273
8271
  applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
8274
8272
  }
@@ -8294,6 +8292,7 @@ function cleanUpView(tView, lView) {
8294
8292
  // This also aligns with the ViewEngine behavior. It also means that the onDestroy hook is
8295
8293
  // really more of an "afterDestroy" hook if you think about it.
8296
8294
  lView[FLAGS] |= 256 /* LViewFlags.Destroyed */;
8295
+ lView[REACTIVE_TEMPLATE_CONSUMER] && consumerDestroy$1(lView[REACTIVE_TEMPLATE_CONSUMER]);
8297
8296
  executeOnDestroys(tView, lView);
8298
8297
  processCleanups(tView, lView);
8299
8298
  // For component views only, the local renderer is destroyed at clean up time.
@@ -10428,7 +10427,7 @@ class Version {
10428
10427
  /**
10429
10428
  * @publicApi
10430
10429
  */
10431
- const VERSION = new Version('17.0.4');
10430
+ const VERSION = new Version('17.0.6');
10432
10431
 
10433
10432
  // This default value is when checking the hierarchy for a token.
10434
10433
  //
@@ -13335,8 +13334,7 @@ function detectChangesInViewWhileDirty(lView) {
13335
13334
  // descendants views that need to be refreshed due to re-dirtying during the change detection
13336
13335
  // run, detect changes on the view again. We run change detection in `Targeted` mode to only
13337
13336
  // refresh views with the `RefreshView` flag.
13338
- while (lView[FLAGS] & (1024 /* LViewFlags.RefreshView */ | 8192 /* LViewFlags.HasChildViewsToRefresh */) ||
13339
- lView[REACTIVE_TEMPLATE_CONSUMER]?.dirty) {
13337
+ while (requiresRefreshOrTraversal(lView)) {
13340
13338
  if (retries === MAXIMUM_REFRESH_RERUNS) {
13341
13339
  throw new RuntimeError(103 /* RuntimeErrorCode.INFINITE_CHANGE_DETECTION */, ngDevMode &&
13342
13340
  'Infinite change detection while trying to refresh views. ' +
@@ -15986,19 +15984,26 @@ function ɵɵCopyDefinitionFeature(definition) {
15986
15984
  * @codeGenApi
15987
15985
  */
15988
15986
  function ɵɵHostDirectivesFeature(rawHostDirectives) {
15989
- return (definition) => {
15990
- definition.findHostDirectiveDefs = findHostDirectiveDefs;
15991
- definition.hostDirectives =
15992
- (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
15993
- return typeof dir === 'function' ?
15994
- { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
15995
- {
15996
- directive: resolveForwardRef(dir.directive),
15997
- inputs: bindingArrayToMap(dir.inputs),
15998
- outputs: bindingArrayToMap(dir.outputs)
15999
- };
16000
- });
15987
+ const feature = (definition) => {
15988
+ const resolved = (Array.isArray(rawHostDirectives) ? rawHostDirectives : rawHostDirectives()).map(dir => {
15989
+ return typeof dir === 'function' ?
15990
+ { directive: resolveForwardRef(dir), inputs: EMPTY_OBJ, outputs: EMPTY_OBJ } :
15991
+ {
15992
+ directive: resolveForwardRef(dir.directive),
15993
+ inputs: bindingArrayToMap(dir.inputs),
15994
+ outputs: bindingArrayToMap(dir.outputs)
15995
+ };
15996
+ });
15997
+ if (definition.hostDirectives === null) {
15998
+ definition.findHostDirectiveDefs = findHostDirectiveDefs;
15999
+ definition.hostDirectives = resolved;
16000
+ }
16001
+ else {
16002
+ definition.hostDirectives.unshift(...resolved);
16003
+ }
16001
16004
  };
16005
+ feature.ngInherit = true;
16006
+ return feature;
16002
16007
  }
16003
16008
  function findHostDirectiveDefs(currentDef, matchedDefs, hostDirectiveDefs) {
16004
16009
  if (currentDef.hostDirectives !== null) {
@@ -19112,6 +19117,17 @@ function isFirstElementInNgContainer(tNode) {
19112
19117
  function getNoOffsetIndex(tNode) {
19113
19118
  return tNode.index - HEADER_OFFSET;
19114
19119
  }
19120
+ /**
19121
+ * Check whether a given node exists, but is disconnected from the DOM.
19122
+ *
19123
+ * Note: we leverage the fact that we have this information available in the DOM emulation
19124
+ * layer (in Domino) for now. Longer-term solution should not rely on the DOM emulation and
19125
+ * only use internal data structures and state to compute this information.
19126
+ */
19127
+ function isDisconnectedNode(tNode, lView) {
19128
+ return !(tNode.type & 16 /* TNodeType.Projection */) && !!lView[tNode.index] &&
19129
+ !unwrapRNode(lView[tNode.index])?.isConnected;
19130
+ }
19115
19131
  /**
19116
19132
  * Locate a node in DOM tree that corresponds to a given TNode.
19117
19133
  *
@@ -19313,10 +19329,20 @@ function calcPathBetween(from, to, fromNodeName) {
19313
19329
  * instructions needs to be generated for a TNode.
19314
19330
  */
19315
19331
  function calcPathForNode(tNode, lView) {
19316
- const parentTNode = tNode.parent;
19332
+ let parentTNode = tNode.parent;
19317
19333
  let parentIndex;
19318
19334
  let parentRNode;
19319
19335
  let referenceNodeName;
19336
+ // Skip over all parent nodes that are disconnected from the DOM, such nodes
19337
+ // can not be used as anchors.
19338
+ //
19339
+ // This might happen in certain content projection-based use-cases, where
19340
+ // a content of an element is projected and used, when a parent element
19341
+ // itself remains detached from DOM. In this scenario we try to find a parent
19342
+ // element that is attached to DOM and can act as an anchor instead.
19343
+ while (parentTNode !== null && isDisconnectedNode(parentTNode, lView)) {
19344
+ parentTNode = parentTNode.parent;
19345
+ }
19320
19346
  if (parentTNode === null || !(parentTNode.type & 3 /* TNodeType.AnyRNode */)) {
19321
19347
  // If there is no parent TNode or a parent TNode does not represent an RNode
19322
19348
  // (i.e. not a DOM node), use component host element as a reference node.
@@ -19750,13 +19776,14 @@ function getLViewFromLContainer(lContainer, index) {
19750
19776
  * block (in which case view contents was re-created, thus needing insertion).
19751
19777
  */
19752
19778
  function shouldAddViewToDom(tNode, dehydratedView) {
19753
- return !dehydratedView || hasInSkipHydrationBlockFlag(tNode);
19779
+ return !dehydratedView || dehydratedView.firstChild === null ||
19780
+ hasInSkipHydrationBlockFlag(tNode);
19754
19781
  }
19755
19782
  function addLViewToLContainer(lContainer, lView, index, addToDOM = true) {
19756
19783
  const tView = lView[TVIEW];
19757
- // insert to the view tree so the new view can be change-detected
19784
+ // Insert into the view tree so the new view can be change-detected
19758
19785
  insertView(tView, lView, lContainer, index);
19759
- // insert to the view to the DOM tree
19786
+ // Insert elements that belong to this view into the DOM tree
19760
19787
  if (addToDOM) {
19761
19788
  const beforeNode = getBeforeNodeForView(index, lContainer);
19762
19789
  const renderer = lView[RENDERER];
@@ -19765,6 +19792,13 @@ function addLViewToLContainer(lContainer, lView, index, addToDOM = true) {
19765
19792
  addViewToDOM(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
19766
19793
  }
19767
19794
  }
19795
+ // When in hydration mode, reset the pointer to the first child in
19796
+ // the dehydrated view. This indicates that the view was hydrated and
19797
+ // further attaching/detaching should work with this view as normal.
19798
+ const hydrationInfo = lView[HYDRATION];
19799
+ if (hydrationInfo !== null && hydrationInfo.firstChild !== null) {
19800
+ hydrationInfo.firstChild = null;
19801
+ }
19768
19802
  }
19769
19803
  function removeLViewFromLContainer(lContainer, index) {
19770
19804
  const lView = detachView(lContainer, index);
@@ -30003,7 +30037,7 @@ const ITS_JUST_ANGULAR = true;
30003
30037
  * provideHttpClient(),
30004
30038
  * {
30005
30039
  * provide: APP_INITIALIZER,
30006
- * useFactory: initializeApp,
30040
+ * useFactory: initializeAppFactory,
30007
30041
  * multi: true,
30008
30042
  * deps: [HttpClient],
30009
30043
  * },
@@ -34299,6 +34333,7 @@ function serializeLView(lView, context) {
34299
34333
  }
34300
34334
  }
34301
34335
  }
34336
+ conditionallyAnnotateNodePath(ngh, tNode, lView);
34302
34337
  if (isLContainer(lView[i])) {
34303
34338
  // Serialize information about a template.
34304
34339
  const embeddedTView = tNode.tView;
@@ -34390,18 +34425,38 @@ function serializeLView(lView, context) {
34390
34425
  context.corruptedTextNodes.set(rNode, "ngtns" /* TextNodeMarker.Separator */);
34391
34426
  }
34392
34427
  }
34393
- if (tNode.projectionNext && tNode.projectionNext !== tNode.next &&
34394
- !isInSkipHydrationBlock(tNode.projectionNext)) {
34395
- // Check if projection next is not the same as next, in which case
34396
- // the node would not be found at creation time at runtime and we
34397
- // need to provide a location for that node.
34398
- appendSerializedNodePath(ngh, tNode.projectionNext, lView);
34399
- }
34400
34428
  }
34401
34429
  }
34402
34430
  }
34403
34431
  return ngh;
34404
34432
  }
34433
+ /**
34434
+ * Serializes node location in cases when it's needed, specifically:
34435
+ *
34436
+ * 1. If `tNode.projectionNext` is different from `tNode.next` - it means that
34437
+ * the next `tNode` after projection is different from the one in the original
34438
+ * template. Since hydration relies on `tNode.next`, this serialized info
34439
+ * if required to help runtime code find the node at the correct location.
34440
+ * 2. In certain content projection-based use-cases, it's possible that only
34441
+ * a content of a projected element is rendered. In this case, content nodes
34442
+ * require an extra annotation, since runtime logic can't rely on parent-child
34443
+ * connection to identify the location of a node.
34444
+ */
34445
+ function conditionallyAnnotateNodePath(ngh, tNode, lView) {
34446
+ // Handle case #1 described above.
34447
+ if (tNode.projectionNext && tNode.projectionNext !== tNode.next &&
34448
+ !isInSkipHydrationBlock(tNode.projectionNext)) {
34449
+ appendSerializedNodePath(ngh, tNode.projectionNext, lView);
34450
+ }
34451
+ // Handle case #2 described above.
34452
+ // Note: we only do that for the first node (i.e. when `tNode.prev === null`),
34453
+ // the rest of the nodes would rely on the current node location, so no extra
34454
+ // annotation is needed.
34455
+ if (tNode.prev === null && tNode.parent !== null && isDisconnectedNode(tNode.parent, lView) &&
34456
+ !isDisconnectedNode(tNode, lView)) {
34457
+ appendSerializedNodePath(ngh, tNode, lView);
34458
+ }
34459
+ }
34405
34460
  /**
34406
34461
  * Determines whether a component instance that is represented
34407
34462
  * by a given LView uses `ViewEncapsulation.ShadowDom`.
@@ -34473,17 +34528,6 @@ function isContentProjectedNode(tNode) {
34473
34528
  }
34474
34529
  return false;
34475
34530
  }
34476
- /**
34477
- * Check whether a given node exists, but is disconnected from the DOM.
34478
- *
34479
- * Note: we leverage the fact that we have this information available in the DOM emulation
34480
- * layer (in Domino) for now. Longer-term solution should not rely on the DOM emulation and
34481
- * only use internal data structures and state to compute this information.
34482
- */
34483
- function isDisconnectedNode(tNode, lView) {
34484
- return !(tNode.type & 16 /* TNodeType.Projection */) && !!lView[tNode.index] &&
34485
- !unwrapRNode(lView[tNode.index]).isConnected;
34486
- }
34487
34531
 
34488
34532
  /**
34489
34533
  * Indicates whether the hydration-related code was added,