@angular/core 16.0.0-rc.2 → 16.0.0-rc.4

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 (40) hide show
  1. package/esm2022/rxjs-interop/src/index.mjs +1 -1
  2. package/esm2022/rxjs-interop/src/take_until_destroyed.mjs +3 -2
  3. package/esm2022/rxjs-interop/src/to_observable.mjs +20 -19
  4. package/esm2022/rxjs-interop/src/to_signal.mjs +6 -5
  5. package/esm2022/src/application_init.mjs +9 -3
  6. package/esm2022/src/application_ref.mjs +2 -1
  7. package/esm2022/src/errors.mjs +3 -3
  8. package/esm2022/src/hydration/error_handling.mjs +13 -5
  9. package/esm2022/src/linker/template_ref.mjs +3 -2
  10. package/esm2022/src/render3/component_ref.mjs +3 -2
  11. package/esm2022/src/render3/definition.mjs +4 -5
  12. package/esm2022/src/render3/instructions/change_detection.mjs +263 -3
  13. package/esm2022/src/render3/instructions/element.mjs +2 -2
  14. package/esm2022/src/render3/instructions/element_container.mjs +2 -2
  15. package/esm2022/src/render3/instructions/render.mjs +125 -0
  16. package/esm2022/src/render3/instructions/shared.mjs +23 -405
  17. package/esm2022/src/render3/instructions/template.mjs +22 -9
  18. package/esm2022/src/render3/interfaces/container.mjs +3 -3
  19. package/esm2022/src/render3/interfaces/view.mjs +2 -2
  20. package/esm2022/src/render3/node_manipulation.mjs +4 -8
  21. package/esm2022/src/render3/util/view_utils.mjs +35 -11
  22. package/esm2022/src/render3/view_ref.mjs +2 -2
  23. package/esm2022/src/version.mjs +1 -1
  24. package/esm2022/testing/src/logger.mjs +3 -3
  25. package/esm2022/testing/src/test_bed.mjs +1 -3
  26. package/esm2022/testing/src/test_bed_common.mjs +1 -1
  27. package/fesm2022/core.mjs +647 -618
  28. package/fesm2022/core.mjs.map +1 -1
  29. package/fesm2022/rxjs-interop.mjs +29 -26
  30. package/fesm2022/rxjs-interop.mjs.map +1 -1
  31. package/fesm2022/testing.mjs +639 -618
  32. package/fesm2022/testing.mjs.map +1 -1
  33. package/index.d.ts +24 -10
  34. package/package.json +1 -1
  35. package/rxjs-interop/index.d.ts +111 -20
  36. package/schematics/migrations/guard-and-resolve-interfaces/bundle.js +13 -13
  37. package/schematics/migrations/remove-module-id/bundle.js +14 -14
  38. package/schematics/ng-generate/standalone-migration/bundle.js +371 -350
  39. package/schematics/ng-generate/standalone-migration/bundle.js.map +2 -2
  40. package/testing/index.d.ts +3 -3
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.0.0-rc.2
2
+ * @license Angular v16.0.0-rc.4
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -156,9 +156,9 @@ function formatRuntimeError(code, message) {
156
156
  // generate a link to the error details page on angular.io.
157
157
  // We also prepend `0` to non-compile-time errors.
158
158
  const fullCode = `NG0${Math.abs(code)}`;
159
- let errorMessage = `${fullCode}${message ? ': ' + message.trim() : ''}`;
159
+ let errorMessage = `${fullCode}${message ? ': ' + message : ''}`;
160
160
  if (ngDevMode && code < 0) {
161
- const addPeriodSeparator = !errorMessage.match(/[.,;!?]$/);
161
+ const addPeriodSeparator = !errorMessage.match(/[.,;!?\n]$/);
162
162
  const separator = addPeriodSeparator ? '.' : '';
163
163
  errorMessage =
164
164
  `${errorMessage}${separator} Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/${fullCode}`;
@@ -1920,10 +1920,8 @@ function getComponentId(componentDef) {
1920
1920
  if (GENERATED_COMP_IDS.has(compId)) {
1921
1921
  const previousCompDefType = GENERATED_COMP_IDS.get(compId);
1922
1922
  if (previousCompDefType !== componentDef.type) {
1923
- // TODO: use `formatRuntimeError` to have an error code and we can later on create an error
1924
- // guide to explain this further.
1925
- console.warn(`Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
1926
- .selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`);
1923
+ console.warn(formatRuntimeError(-912 /* RuntimeErrorCode.COMPONENT_ID_COLLISION */, `Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
1924
+ .selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`));
1927
1925
  }
1928
1926
  }
1929
1927
  else {
@@ -1941,7 +1939,7 @@ const TVIEW = 1;
1941
1939
  const FLAGS = 2;
1942
1940
  const PARENT = 3;
1943
1941
  const NEXT = 4;
1944
- const TRANSPLANTED_VIEWS_TO_REFRESH = 5;
1942
+ const DESCENDANT_VIEWS_TO_REFRESH = 5;
1945
1943
  const T_HOST = 6;
1946
1944
  const CLEANUP = 7;
1947
1945
  const CONTEXT = 8;
@@ -1994,7 +1992,7 @@ const TYPE = 1;
1994
1992
  * that the `MOVED_VIEWS` are transplanted and on-push.
1995
1993
  */
1996
1994
  const HAS_TRANSPLANTED_VIEWS = 2;
1997
- // PARENT, NEXT, TRANSPLANTED_VIEWS_TO_REFRESH are indices 3, 4, and 5
1995
+ // PARENT, NEXT, DESCENDANT_VIEWS_TO_REFRESH are indices 3, 4, and 5
1998
1996
  // As we already have these constants in LView, we don't need to re-create them.
1999
1997
  // T_HOST is index 6
2000
1998
  // We already have this constants in LView, we don't need to re-create it.
@@ -2996,20 +2994,44 @@ function resetPreOrderHookFlags(lView) {
2996
2994
  lView[PREORDER_HOOK_FLAGS] = 0;
2997
2995
  }
2998
2996
  /**
2999
- * Updates the `TRANSPLANTED_VIEWS_TO_REFRESH` counter on the `LContainer` as well as the parents
3000
- * whose
2997
+ * Adds the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
2998
+ * parents.
2999
+ */
3000
+ function markViewForRefresh(lView) {
3001
+ if ((lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) === 0) {
3002
+ lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
3003
+ updateViewsToRefresh(lView, 1);
3004
+ }
3005
+ }
3006
+ /**
3007
+ * Removes the `RefreshView` flag from the lView and updates DESCENDANT_VIEWS_TO_REFRESH counters of
3008
+ * parents.
3009
+ */
3010
+ function clearViewRefreshFlag(lView) {
3011
+ if (lView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
3012
+ lView[FLAGS] &= ~1024 /* LViewFlags.RefreshView */;
3013
+ updateViewsToRefresh(lView, -1);
3014
+ }
3015
+ }
3016
+ /**
3017
+ * Updates the `DESCENDANT_VIEWS_TO_REFRESH` counter on the parents of the `LView` as well as the
3018
+ * parents above that whose
3001
3019
  * 1. counter goes from 0 to 1, indicating that there is a new child that has a view to refresh
3002
3020
  * or
3003
3021
  * 2. counter goes from 1 to 0, indicating there are no more descendant views to refresh
3004
3022
  */
3005
- function updateTransplantedViewCount(lContainer, amount) {
3006
- lContainer[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
3007
- let viewOrContainer = lContainer;
3008
- let parent = lContainer[PARENT];
3023
+ function updateViewsToRefresh(lView, amount) {
3024
+ let parent = lView[PARENT];
3025
+ if (parent === null) {
3026
+ return;
3027
+ }
3028
+ parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
3029
+ let viewOrContainer = parent;
3030
+ parent = parent[PARENT];
3009
3031
  while (parent !== null &&
3010
- ((amount === 1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 1) ||
3011
- (amount === -1 && viewOrContainer[TRANSPLANTED_VIEWS_TO_REFRESH] === 0))) {
3012
- parent[TRANSPLANTED_VIEWS_TO_REFRESH] += amount;
3032
+ ((amount === 1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 1) ||
3033
+ (amount === -1 && viewOrContainer[DESCENDANT_VIEWS_TO_REFRESH] === 0))) {
3034
+ parent[DESCENDANT_VIEWS_TO_REFRESH] += amount;
3013
3035
  viewOrContainer = parent;
3014
3036
  parent = parent[PARENT];
3015
3037
  }
@@ -6853,12 +6875,8 @@ function detachMovedView(declarationContainer, lView) {
6853
6875
  const insertionLContainer = lView[PARENT];
6854
6876
  ngDevMode && assertLContainer(insertionLContainer);
6855
6877
  // If the view was marked for refresh but then detached before it was checked (where the flag
6856
- // would be cleared and the counter decremented), we need to decrement the view counter here
6857
- // instead.
6858
- if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
6859
- lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
6860
- updateTransplantedViewCount(insertionLContainer, -1);
6861
- }
6878
+ // would be cleared and the counter decremented), we need to update the status here.
6879
+ clearViewRefreshFlag(lView);
6862
6880
  movedViews.splice(declarationViewIndex, 1);
6863
6881
  }
6864
6882
  /**
@@ -9963,7 +9981,7 @@ class Version {
9963
9981
  /**
9964
9982
  * @publicApi
9965
9983
  */
9966
- const VERSION = new Version('16.0.0-rc.2');
9984
+ const VERSION = new Version('16.0.0-rc.4');
9967
9985
 
9968
9986
  // This default value is when checking the hierarchy for a token.
9969
9987
  //
@@ -10717,36 +10735,6 @@ function processHostBindingOpCodes(tView, lView) {
10717
10735
  setSelectedIndex(-1);
10718
10736
  }
10719
10737
  }
10720
- /** Refreshes all content queries declared by directives in a given view */
10721
- function refreshContentQueries(tView, lView) {
10722
- const contentQueries = tView.contentQueries;
10723
- if (contentQueries !== null) {
10724
- for (let i = 0; i < contentQueries.length; i += 2) {
10725
- const queryStartIdx = contentQueries[i];
10726
- const directiveDefIdx = contentQueries[i + 1];
10727
- if (directiveDefIdx !== -1) {
10728
- const directiveDef = tView.data[directiveDefIdx];
10729
- ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
10730
- ngDevMode &&
10731
- assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
10732
- setCurrentQueryIndex(queryStartIdx);
10733
- directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
10734
- }
10735
- }
10736
- }
10737
- }
10738
- /** Refreshes child components in the current view (update mode). */
10739
- function refreshChildComponents(hostLView, components) {
10740
- for (let i = 0; i < components.length; i++) {
10741
- refreshComponent(hostLView, components[i]);
10742
- }
10743
- }
10744
- /** Renders child components in the current view (creation mode). */
10745
- function renderChildComponents(hostLView, components) {
10746
- for (let i = 0; i < components.length; i++) {
10747
- renderComponent(hostLView, components[i]);
10748
- }
10749
- }
10750
10738
  function createLView(parentLView, tView, context, flags, host, tHostNode, environment, renderer, injector, embeddedViewInjector, hydrationInfo) {
10751
10739
  const lView = tView.blueprint.slice();
10752
10740
  lView[HOST] = host;
@@ -10863,195 +10851,6 @@ function allocExpando(tView, lView, numSlotsToAlloc, initialValue) {
10863
10851
  }
10864
10852
  return allocIdx;
10865
10853
  }
10866
- //////////////////////////
10867
- //// Render
10868
- //////////////////////////
10869
- /**
10870
- * Processes a view in the creation mode. This includes a number of steps in a specific order:
10871
- * - creating view query functions (if any);
10872
- * - executing a template function in the creation mode;
10873
- * - updating static queries (if any);
10874
- * - creating child components defined in a given view.
10875
- */
10876
- function renderView(tView, lView, context) {
10877
- ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
10878
- enterView(lView);
10879
- try {
10880
- const viewQuery = tView.viewQuery;
10881
- if (viewQuery !== null) {
10882
- executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
10883
- }
10884
- // Execute a template associated with this view, if it exists. A template function might not be
10885
- // defined for the root component views.
10886
- const templateFn = tView.template;
10887
- if (templateFn !== null) {
10888
- executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
10889
- }
10890
- // This needs to be set before children are processed to support recursive components.
10891
- // This must be set to false immediately after the first creation run because in an
10892
- // ngFor loop, all the views will be created together before update mode runs and turns
10893
- // off firstCreatePass. If we don't set it here, instances will perform directive
10894
- // matching, etc again and again.
10895
- if (tView.firstCreatePass) {
10896
- tView.firstCreatePass = false;
10897
- }
10898
- // We resolve content queries specifically marked as `static` in creation mode. Dynamic
10899
- // content queries are resolved during change detection (i.e. update mode), after embedded
10900
- // views are refreshed (see block above).
10901
- if (tView.staticContentQueries) {
10902
- refreshContentQueries(tView, lView);
10903
- }
10904
- // We must materialize query results before child components are processed
10905
- // in case a child component has projected a container. The LContainer needs
10906
- // to exist so the embedded views are properly attached by the container.
10907
- if (tView.staticViewQueries) {
10908
- executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
10909
- }
10910
- // Render child component views.
10911
- const components = tView.components;
10912
- if (components !== null) {
10913
- renderChildComponents(lView, components);
10914
- }
10915
- }
10916
- catch (error) {
10917
- // If we didn't manage to get past the first template pass due to
10918
- // an error, mark the view as corrupted so we can try to recover.
10919
- if (tView.firstCreatePass) {
10920
- tView.incompleteFirstPass = true;
10921
- tView.firstCreatePass = false;
10922
- }
10923
- throw error;
10924
- }
10925
- finally {
10926
- lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
10927
- leaveView();
10928
- }
10929
- }
10930
- /**
10931
- * Processes a view in update mode. This includes a number of steps in a specific order:
10932
- * - executing a template function in update mode;
10933
- * - executing hooks;
10934
- * - refreshing queries;
10935
- * - setting host bindings;
10936
- * - refreshing child (embedded and component) views.
10937
- */
10938
- function refreshView(tView, lView, templateFn, context) {
10939
- ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
10940
- const flags = lView[FLAGS];
10941
- if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
10942
- return;
10943
- // Check no changes mode is a dev only mode used to verify that bindings have not changed
10944
- // since they were assigned. We do not want to execute lifecycle hooks in that mode.
10945
- const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
10946
- !isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
10947
- enterView(lView);
10948
- try {
10949
- resetPreOrderHookFlags(lView);
10950
- setBindingIndex(tView.bindingStartIndex);
10951
- if (templateFn !== null) {
10952
- executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
10953
- }
10954
- const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
10955
- // execute pre-order hooks (OnInit, OnChanges, DoCheck)
10956
- // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10957
- if (!isInCheckNoChangesPass) {
10958
- if (hooksInitPhaseCompleted) {
10959
- const preOrderCheckHooks = tView.preOrderCheckHooks;
10960
- if (preOrderCheckHooks !== null) {
10961
- executeCheckHooks(lView, preOrderCheckHooks, null);
10962
- }
10963
- }
10964
- else {
10965
- const preOrderHooks = tView.preOrderHooks;
10966
- if (preOrderHooks !== null) {
10967
- executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
10968
- }
10969
- incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
10970
- }
10971
- }
10972
- // First mark transplanted views that are declared in this lView as needing a refresh at their
10973
- // insertion points. This is needed to avoid the situation where the template is defined in this
10974
- // `LView` but its declaration appears after the insertion component.
10975
- markTransplantedViewsForRefresh(lView);
10976
- refreshEmbeddedViews(lView);
10977
- // Content query results must be refreshed before content hooks are called.
10978
- if (tView.contentQueries !== null) {
10979
- refreshContentQueries(tView, lView);
10980
- }
10981
- // execute content hooks (AfterContentInit, AfterContentChecked)
10982
- // PERF WARNING: do NOT extract this to a separate function without running benchmarks
10983
- if (!isInCheckNoChangesPass) {
10984
- if (hooksInitPhaseCompleted) {
10985
- const contentCheckHooks = tView.contentCheckHooks;
10986
- if (contentCheckHooks !== null) {
10987
- executeCheckHooks(lView, contentCheckHooks);
10988
- }
10989
- }
10990
- else {
10991
- const contentHooks = tView.contentHooks;
10992
- if (contentHooks !== null) {
10993
- executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10994
- }
10995
- incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
10996
- }
10997
- }
10998
- processHostBindingOpCodes(tView, lView);
10999
- // Refresh child component views.
11000
- const components = tView.components;
11001
- if (components !== null) {
11002
- refreshChildComponents(lView, components);
11003
- }
11004
- // View queries must execute after refreshing child components because a template in this view
11005
- // could be inserted in a child component. If the view query executes before child component
11006
- // refresh, the template might not yet be inserted.
11007
- const viewQuery = tView.viewQuery;
11008
- if (viewQuery !== null) {
11009
- executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
11010
- }
11011
- // execute view hooks (AfterViewInit, AfterViewChecked)
11012
- // PERF WARNING: do NOT extract this to a separate function without running benchmarks
11013
- if (!isInCheckNoChangesPass) {
11014
- if (hooksInitPhaseCompleted) {
11015
- const viewCheckHooks = tView.viewCheckHooks;
11016
- if (viewCheckHooks !== null) {
11017
- executeCheckHooks(lView, viewCheckHooks);
11018
- }
11019
- }
11020
- else {
11021
- const viewHooks = tView.viewHooks;
11022
- if (viewHooks !== null) {
11023
- executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
11024
- }
11025
- incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
11026
- }
11027
- }
11028
- if (tView.firstUpdatePass === true) {
11029
- // We need to make sure that we only flip the flag on successful `refreshView` only
11030
- // Don't do this in `finally` block.
11031
- // If we did this in `finally` block then an exception could block the execution of styling
11032
- // instructions which in turn would be unable to insert themselves into the styling linked
11033
- // list. The result of this would be that if the exception would not be throw on subsequent CD
11034
- // the styling would be unable to process it data and reflect to the DOM.
11035
- tView.firstUpdatePass = false;
11036
- }
11037
- // Do not reset the dirty state when running in check no changes mode. We don't want components
11038
- // to behave differently depending on whether check no changes is enabled or not. For example:
11039
- // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
11040
- // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
11041
- // no changes cycle, the component would be not be dirty for the next update pass. This would
11042
- // be different in production mode where the component dirty state is not reset.
11043
- if (!isInCheckNoChangesPass) {
11044
- lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
11045
- }
11046
- if (lView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
11047
- lView[FLAGS] &= ~1024 /* LViewFlags.RefreshTransplantedView */;
11048
- updateTransplantedViewCount(lView[PARENT], -1);
11049
- }
11050
- }
11051
- finally {
11052
- leaveView();
11053
- }
11054
- }
11055
10854
  function executeTemplate(tView, lView, templateFn, rf, context) {
11056
10855
  const consumer = getReactiveLViewConsumer(lView, REACTIVE_TEMPLATE_CONSUMER);
11057
10856
  const prevSelectedIndex = getSelectedIndex();
@@ -12034,153 +11833,26 @@ function createLContainer(hostNative, currentView, native, tNode) {
12034
11833
  assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
12035
11834
  return lContainer;
12036
11835
  }
12037
- /**
12038
- * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
12039
- * them by executing an associated template function.
12040
- */
12041
- function refreshEmbeddedViews(lView) {
12042
- for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12043
- for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12044
- const embeddedLView = lContainer[i];
12045
- const embeddedTView = embeddedLView[TVIEW];
12046
- ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12047
- if (viewAttachedToChangeDetector(embeddedLView)) {
12048
- refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
11836
+ /** Refreshes all content queries declared by directives in a given view */
11837
+ function refreshContentQueries(tView, lView) {
11838
+ const contentQueries = tView.contentQueries;
11839
+ if (contentQueries !== null) {
11840
+ for (let i = 0; i < contentQueries.length; i += 2) {
11841
+ const queryStartIdx = contentQueries[i];
11842
+ const directiveDefIdx = contentQueries[i + 1];
11843
+ if (directiveDefIdx !== -1) {
11844
+ const directiveDef = tView.data[directiveDefIdx];
11845
+ ngDevMode && assertDefined(directiveDef, 'DirectiveDef not found.');
11846
+ ngDevMode &&
11847
+ assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined');
11848
+ setCurrentQueryIndex(queryStartIdx);
11849
+ directiveDef.contentQueries(2 /* RenderFlags.Update */, lView[directiveDefIdx], directiveDefIdx);
12049
11850
  }
12050
11851
  }
12051
11852
  }
12052
11853
  }
12053
11854
  /**
12054
- * Mark transplanted views as needing to be refreshed at their insertion points.
12055
- *
12056
- * @param lView The `LView` that may have transplanted views.
12057
- */
12058
- function markTransplantedViewsForRefresh(lView) {
12059
- for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12060
- if (!lContainer[HAS_TRANSPLANTED_VIEWS])
12061
- continue;
12062
- const movedViews = lContainer[MOVED_VIEWS];
12063
- ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
12064
- for (let i = 0; i < movedViews.length; i++) {
12065
- const movedLView = movedViews[i];
12066
- const insertionLContainer = movedLView[PARENT];
12067
- ngDevMode && assertLContainer(insertionLContainer);
12068
- // We don't want to increment the counter if the moved LView was already marked for
12069
- // refresh.
12070
- if ((movedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) === 0) {
12071
- updateTransplantedViewCount(insertionLContainer, 1);
12072
- }
12073
- // Note, it is possible that the `movedViews` is tracking views that are transplanted *and*
12074
- // those that aren't (declaration component === insertion component). In the latter case,
12075
- // it's fine to add the flag, as we will clear it immediately in
12076
- // `refreshEmbeddedViews` for the view currently being refreshed.
12077
- movedLView[FLAGS] |= 1024 /* LViewFlags.RefreshTransplantedView */;
12078
- }
12079
- }
12080
- }
12081
- /////////////
12082
- /**
12083
- * Refreshes components by entering the component view and processing its bindings, queries, etc.
12084
- *
12085
- * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
12086
- */
12087
- function refreshComponent(hostLView, componentHostIdx) {
12088
- ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
12089
- const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
12090
- // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12091
- if (viewAttachedToChangeDetector(componentView)) {
12092
- const tView = componentView[TVIEW];
12093
- if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
12094
- refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
12095
- }
12096
- else if (componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12097
- // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12098
- refreshContainsDirtyView(componentView);
12099
- }
12100
- }
12101
- }
12102
- /**
12103
- * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
12104
- * children or descendants of the given lView.
12105
- *
12106
- * @param lView The lView which contains descendant transplanted views that need to be refreshed.
12107
- */
12108
- function refreshContainsDirtyView(lView) {
12109
- for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12110
- for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12111
- const embeddedLView = lContainer[i];
12112
- if (viewAttachedToChangeDetector(embeddedLView)) {
12113
- if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshTransplantedView */) {
12114
- const embeddedTView = embeddedLView[TVIEW];
12115
- ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12116
- refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
12117
- }
12118
- else if (embeddedLView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12119
- refreshContainsDirtyView(embeddedLView);
12120
- }
12121
- }
12122
- }
12123
- }
12124
- const tView = lView[TVIEW];
12125
- // Refresh child component views.
12126
- const components = tView.components;
12127
- if (components !== null) {
12128
- for (let i = 0; i < components.length; i++) {
12129
- const componentView = getComponentLViewByIndex(components[i], lView);
12130
- // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12131
- if (viewAttachedToChangeDetector(componentView) &&
12132
- componentView[TRANSPLANTED_VIEWS_TO_REFRESH] > 0) {
12133
- refreshContainsDirtyView(componentView);
12134
- }
12135
- }
12136
- }
12137
- }
12138
- function renderComponent(hostLView, componentHostIdx) {
12139
- ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
12140
- const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
12141
- const componentTView = componentView[TVIEW];
12142
- syncViewWithBlueprint(componentTView, componentView);
12143
- const hostRNode = componentView[HOST];
12144
- // Populate an LView with hydration info retrieved from the DOM via TransferState.
12145
- if (hostRNode !== null && componentView[HYDRATION] === null) {
12146
- componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
12147
- }
12148
- renderView(componentTView, componentView, componentView[CONTEXT]);
12149
- }
12150
- /**
12151
- * Syncs an LView instance with its blueprint if they have gotten out of sync.
12152
- *
12153
- * Typically, blueprints and their view instances should always be in sync, so the loop here
12154
- * will be skipped. However, consider this case of two components side-by-side:
12155
- *
12156
- * App template:
12157
- * ```
12158
- * <comp></comp>
12159
- * <comp></comp>
12160
- * ```
12161
- *
12162
- * The following will happen:
12163
- * 1. App template begins processing.
12164
- * 2. First <comp> is matched as a component and its LView is created.
12165
- * 3. Second <comp> is matched as a component and its LView is created.
12166
- * 4. App template completes processing, so it's time to check child templates.
12167
- * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
12168
- * 6. Second <comp> template is checked. Its blueprint has been updated by the first
12169
- * <comp> template, but its LView was created before this update, so it is out of sync.
12170
- *
12171
- * Note that embedded views inside ngFor loops will never be out of sync because these views
12172
- * are processed as soon as they are created.
12173
- *
12174
- * @param tView The `TView` that contains the blueprint for syncing
12175
- * @param lView The view to sync
12176
- */
12177
- function syncViewWithBlueprint(tView, lView) {
12178
- for (let i = lView.length; i < tView.blueprint.length; i++) {
12179
- lView.push(tView.blueprint[i]);
12180
- }
12181
- }
12182
- /**
12183
- * Adds LView or LContainer to the end of the current view tree.
11855
+ * Adds LView or LContainer to the end of the current view tree.
12184
11856
  *
12185
11857
  * This structure will be used to traverse through nested views to remove listeners
12186
11858
  * and call onDestroy callbacks.
@@ -12207,40 +11879,6 @@ function addToViewTree(lView, lViewOrLContainer) {
12207
11879
  ///////////////////////////////
12208
11880
  //// Change detection
12209
11881
  ///////////////////////////////
12210
- function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
12211
- const rendererFactory = lView[ENVIRONMENT].rendererFactory;
12212
- // Check no changes mode is a dev only mode used to verify that bindings have not changed
12213
- // since they were assigned. We do not want to invoke renderer factory functions in that mode
12214
- // to avoid any possible side-effects.
12215
- const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
12216
- if (!checkNoChangesMode && rendererFactory.begin)
12217
- rendererFactory.begin();
12218
- try {
12219
- refreshView(tView, lView, tView.template, context);
12220
- }
12221
- catch (error) {
12222
- if (notifyErrorHandler) {
12223
- handleError(lView, error);
12224
- }
12225
- throw error;
12226
- }
12227
- finally {
12228
- if (!checkNoChangesMode && rendererFactory.end)
12229
- rendererFactory.end();
12230
- // One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
12231
- // other post-order hooks.
12232
- !checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
12233
- }
12234
- }
12235
- function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
12236
- setIsInCheckNoChangesMode(true);
12237
- try {
12238
- detectChangesInternal(tView, lView, context, notifyErrorHandler);
12239
- }
12240
- finally {
12241
- setIsInCheckNoChangesMode(false);
12242
- }
12243
- }
12244
11882
  function executeViewQueryFn(flags, viewQueryFn, component) {
12245
11883
  ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.');
12246
11884
  setCurrentQueryIndex(0);
@@ -12353,205 +11991,582 @@ function textBindingInternal(lView, index, value) {
12353
11991
  updateTextNode(lView[RENDERER], element, value);
12354
11992
  }
12355
11993
 
11994
+ function renderComponent(hostLView, componentHostIdx) {
11995
+ ngDevMode && assertEqual(isCreationMode(hostLView), true, 'Should be run in creation mode');
11996
+ const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11997
+ const componentTView = componentView[TVIEW];
11998
+ syncViewWithBlueprint(componentTView, componentView);
11999
+ const hostRNode = componentView[HOST];
12000
+ // Populate an LView with hydration info retrieved from the DOM via TransferState.
12001
+ if (hostRNode !== null && componentView[HYDRATION] === null) {
12002
+ componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
12003
+ }
12004
+ renderView(componentTView, componentView, componentView[CONTEXT]);
12005
+ }
12356
12006
  /**
12357
- * `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
12358
- * The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
12359
- * is injected in a component or directive, the callbacks run when that component or
12360
- * directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
12007
+ * Syncs an LView instance with its blueprint if they have gotten out of sync.
12361
12008
  *
12362
- * @publicApi
12009
+ * Typically, blueprints and their view instances should always be in sync, so the loop here
12010
+ * will be skipped. However, consider this case of two components side-by-side:
12011
+ *
12012
+ * App template:
12013
+ * ```
12014
+ * <comp></comp>
12015
+ * <comp></comp>
12016
+ * ```
12017
+ *
12018
+ * The following will happen:
12019
+ * 1. App template begins processing.
12020
+ * 2. First <comp> is matched as a component and its LView is created.
12021
+ * 3. Second <comp> is matched as a component and its LView is created.
12022
+ * 4. App template completes processing, so it's time to check child templates.
12023
+ * 5. First <comp> template is checked. It has a directive, so its def is pushed to blueprint.
12024
+ * 6. Second <comp> template is checked. Its blueprint has been updated by the first
12025
+ * <comp> template, but its LView was created before this update, so it is out of sync.
12026
+ *
12027
+ * Note that embedded views inside ngFor loops will never be out of sync because these views
12028
+ * are processed as soon as they are created.
12029
+ *
12030
+ * @param tView The `TView` that contains the blueprint for syncing
12031
+ * @param lView The view to sync
12363
12032
  */
12364
- class DestroyRef {
12365
- /**
12366
- * @internal
12367
- * @nocollapse
12368
- */
12369
- static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
12370
- /**
12371
- * @internal
12372
- * @nocollapse
12373
- */
12374
- static { this.__NG_ENV_ID__ = (injector) => injector; }
12033
+ function syncViewWithBlueprint(tView, lView) {
12034
+ for (let i = lView.length; i < tView.blueprint.length; i++) {
12035
+ lView.push(tView.blueprint[i]);
12036
+ }
12375
12037
  }
12376
- class NodeInjectorDestroyRef extends DestroyRef {
12377
- constructor(_lView) {
12378
- super();
12379
- this._lView = _lView;
12038
+ /**
12039
+ * Processes a view in the creation mode. This includes a number of steps in a specific order:
12040
+ * - creating view query functions (if any);
12041
+ * - executing a template function in the creation mode;
12042
+ * - updating static queries (if any);
12043
+ * - creating child components defined in a given view.
12044
+ */
12045
+ function renderView(tView, lView, context) {
12046
+ ngDevMode && assertEqual(isCreationMode(lView), true, 'Should be run in creation mode');
12047
+ enterView(lView);
12048
+ try {
12049
+ const viewQuery = tView.viewQuery;
12050
+ if (viewQuery !== null) {
12051
+ executeViewQueryFn(1 /* RenderFlags.Create */, viewQuery, context);
12052
+ }
12053
+ // Execute a template associated with this view, if it exists. A template function might not be
12054
+ // defined for the root component views.
12055
+ const templateFn = tView.template;
12056
+ if (templateFn !== null) {
12057
+ executeTemplate(tView, lView, templateFn, 1 /* RenderFlags.Create */, context);
12058
+ }
12059
+ // This needs to be set before children are processed to support recursive components.
12060
+ // This must be set to false immediately after the first creation run because in an
12061
+ // ngFor loop, all the views will be created together before update mode runs and turns
12062
+ // off firstCreatePass. If we don't set it here, instances will perform directive
12063
+ // matching, etc again and again.
12064
+ if (tView.firstCreatePass) {
12065
+ tView.firstCreatePass = false;
12066
+ }
12067
+ // We resolve content queries specifically marked as `static` in creation mode. Dynamic
12068
+ // content queries are resolved during change detection (i.e. update mode), after embedded
12069
+ // views are refreshed (see block above).
12070
+ if (tView.staticContentQueries) {
12071
+ refreshContentQueries(tView, lView);
12072
+ }
12073
+ // We must materialize query results before child components are processed
12074
+ // in case a child component has projected a container. The LContainer needs
12075
+ // to exist so the embedded views are properly attached by the container.
12076
+ if (tView.staticViewQueries) {
12077
+ executeViewQueryFn(2 /* RenderFlags.Update */, tView.viewQuery, context);
12078
+ }
12079
+ // Render child component views.
12080
+ const components = tView.components;
12081
+ if (components !== null) {
12082
+ renderChildComponents(lView, components);
12083
+ }
12084
+ }
12085
+ catch (error) {
12086
+ // If we didn't manage to get past the first template pass due to
12087
+ // an error, mark the view as corrupted so we can try to recover.
12088
+ if (tView.firstCreatePass) {
12089
+ tView.incompleteFirstPass = true;
12090
+ tView.firstCreatePass = false;
12091
+ }
12092
+ throw error;
12093
+ }
12094
+ finally {
12095
+ lView[FLAGS] &= ~4 /* LViewFlags.CreationMode */;
12096
+ leaveView();
12097
+ }
12098
+ }
12099
+ /** Renders child components in the current view (creation mode). */
12100
+ function renderChildComponents(hostLView, components) {
12101
+ for (let i = 0; i < components.length; i++) {
12102
+ renderComponent(hostLView, components[i]);
12103
+ }
12104
+ }
12105
+
12106
+ /**
12107
+ * `DestroyRef` lets you set callbacks to run for any cleanup or destruction behavior.
12108
+ * The scope of this destruction depends on where `DestroyRef` is injected. If `DestroyRef`
12109
+ * is injected in a component or directive, the callbacks run when that component or
12110
+ * directive is destroyed. Otherwise the callbacks run when a corresponding injector is destroyed.
12111
+ *
12112
+ * @publicApi
12113
+ */
12114
+ class DestroyRef {
12115
+ /**
12116
+ * @internal
12117
+ * @nocollapse
12118
+ */
12119
+ static { this.__NG_ELEMENT_ID__ = injectDestroyRef; }
12120
+ /**
12121
+ * @internal
12122
+ * @nocollapse
12123
+ */
12124
+ static { this.__NG_ENV_ID__ = (injector) => injector; }
12125
+ }
12126
+ class NodeInjectorDestroyRef extends DestroyRef {
12127
+ constructor(_lView) {
12128
+ super();
12129
+ this._lView = _lView;
12130
+ }
12131
+ onDestroy(callback) {
12132
+ storeLViewOnDestroy(this._lView, callback);
12133
+ return () => removeLViewOnDestroy(this._lView, callback);
12134
+ }
12135
+ }
12136
+ function injectDestroyRef() {
12137
+ return new NodeInjectorDestroyRef(getLView());
12138
+ }
12139
+
12140
+ /**
12141
+ * Tracks all effects registered within a given application and runs them via `flush`.
12142
+ */
12143
+ class EffectManager {
12144
+ constructor() {
12145
+ this.all = new Set();
12146
+ this.queue = new Map();
12147
+ }
12148
+ create(effectFn, destroyRef, allowSignalWrites) {
12149
+ const zone = (typeof Zone === 'undefined') ? null : Zone.current;
12150
+ const watch = new Watch(effectFn, (watch) => {
12151
+ if (!this.all.has(watch)) {
12152
+ return;
12153
+ }
12154
+ this.queue.set(watch, zone);
12155
+ }, allowSignalWrites);
12156
+ this.all.add(watch);
12157
+ // Effects start dirty.
12158
+ watch.notify();
12159
+ let unregisterOnDestroy;
12160
+ const destroy = () => {
12161
+ watch.cleanup();
12162
+ unregisterOnDestroy?.();
12163
+ this.all.delete(watch);
12164
+ this.queue.delete(watch);
12165
+ };
12166
+ unregisterOnDestroy = destroyRef?.onDestroy(destroy);
12167
+ return {
12168
+ destroy,
12169
+ };
12170
+ }
12171
+ flush() {
12172
+ if (this.queue.size === 0) {
12173
+ return;
12174
+ }
12175
+ for (const [watch, zone] of this.queue) {
12176
+ this.queue.delete(watch);
12177
+ if (zone) {
12178
+ zone.run(() => watch.run());
12179
+ }
12180
+ else {
12181
+ watch.run();
12182
+ }
12183
+ }
12184
+ }
12185
+ get isQueueEmpty() {
12186
+ return this.queue.size === 0;
12187
+ }
12188
+ /** @nocollapse */
12189
+ static { this.ɵprov = ɵɵdefineInjectable({
12190
+ token: EffectManager,
12191
+ providedIn: 'root',
12192
+ factory: () => new EffectManager(),
12193
+ }); }
12194
+ }
12195
+ /**
12196
+ * Create a global `Effect` for the given reactive function.
12197
+ *
12198
+ * @developerPreview
12199
+ */
12200
+ function effect(effectFn, options) {
12201
+ !options?.injector && assertInInjectionContext(effect);
12202
+ const injector = options?.injector ?? inject(Injector);
12203
+ const effectManager = injector.get(EffectManager);
12204
+ const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
12205
+ return effectManager.create(effectFn, destroyRef, !!options?.allowSignalWrites);
12206
+ }
12207
+
12208
+ /**
12209
+ * Compute the static styling (class/style) from `TAttributes`.
12210
+ *
12211
+ * This function should be called during `firstCreatePass` only.
12212
+ *
12213
+ * @param tNode The `TNode` into which the styling information should be loaded.
12214
+ * @param attrs `TAttributes` containing the styling information.
12215
+ * @param writeToHost Where should the resulting static styles be written?
12216
+ * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
12217
+ * - `true` Write to `TNode.styles` / `TNode.classes`
12218
+ */
12219
+ function computeStaticStyling(tNode, attrs, writeToHost) {
12220
+ ngDevMode &&
12221
+ assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
12222
+ let styles = writeToHost ? tNode.styles : null;
12223
+ let classes = writeToHost ? tNode.classes : null;
12224
+ let mode = 0;
12225
+ if (attrs !== null) {
12226
+ for (let i = 0; i < attrs.length; i++) {
12227
+ const value = attrs[i];
12228
+ if (typeof value === 'number') {
12229
+ mode = value;
12230
+ }
12231
+ else if (mode == 1 /* AttributeMarker.Classes */) {
12232
+ classes = concatStringsWithSpace(classes, value);
12233
+ }
12234
+ else if (mode == 2 /* AttributeMarker.Styles */) {
12235
+ const style = value;
12236
+ const styleValue = attrs[++i];
12237
+ styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
12238
+ }
12239
+ }
12240
+ }
12241
+ writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
12242
+ writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
12243
+ }
12244
+
12245
+ function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
12246
+ while (tNode !== null) {
12247
+ ngDevMode &&
12248
+ assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
12249
+ const lNode = lView[tNode.index];
12250
+ if (lNode !== null) {
12251
+ result.push(unwrapRNode(lNode));
12252
+ }
12253
+ // A given lNode can represent either a native node or a LContainer (when it is a host of a
12254
+ // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
12255
+ // from the views in this container.
12256
+ if (isLContainer(lNode)) {
12257
+ for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
12258
+ const lViewInAContainer = lNode[i];
12259
+ const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
12260
+ if (lViewFirstChildTNode !== null) {
12261
+ collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
12262
+ }
12263
+ }
12264
+ // When an LContainer is created, the anchor (comment) node is:
12265
+ // - (1) either reused in case of an ElementContainer (<ng-container>)
12266
+ // - (2) or a new comment node is created
12267
+ // In the first case, the anchor comment node would be added to the final
12268
+ // list by the code above (`result.push(unwrapRNode(lNode))`), but the second
12269
+ // case requires extra handling: the anchor node needs to be added to the
12270
+ // final list manually. See additional information in the `createAnchorNode`
12271
+ // function in the `view_container_ref.ts`.
12272
+ //
12273
+ // In the first case, the same reference would be stored in the `NATIVE`
12274
+ // and `HOST` slots in an LContainer. Otherwise, this is the second case and
12275
+ // we should add an element to the final list.
12276
+ if (lNode[NATIVE] !== lNode[HOST]) {
12277
+ result.push(lNode[NATIVE]);
12278
+ }
12279
+ }
12280
+ const tNodeType = tNode.type;
12281
+ if (tNodeType & 8 /* TNodeType.ElementContainer */) {
12282
+ collectNativeNodes(tView, lView, tNode.child, result);
12283
+ }
12284
+ else if (tNodeType & 32 /* TNodeType.Icu */) {
12285
+ const nextRNode = icuContainerIterate(tNode, lView);
12286
+ let rNode;
12287
+ while (rNode = nextRNode()) {
12288
+ result.push(rNode);
12289
+ }
12290
+ }
12291
+ else if (tNodeType & 16 /* TNodeType.Projection */) {
12292
+ const nodesInSlot = getProjectionNodes(lView, tNode);
12293
+ if (Array.isArray(nodesInSlot)) {
12294
+ result.push(...nodesInSlot);
12295
+ }
12296
+ else {
12297
+ const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
12298
+ ngDevMode && assertParentView(parentView);
12299
+ collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
12300
+ }
12301
+ }
12302
+ tNode = isProjection ? tNode.projectionNext : tNode.next;
12303
+ }
12304
+ return result;
12305
+ }
12306
+
12307
+ function detectChangesInternal(tView, lView, context, notifyErrorHandler = true) {
12308
+ const rendererFactory = lView[ENVIRONMENT].rendererFactory;
12309
+ // Check no changes mode is a dev only mode used to verify that bindings have not changed
12310
+ // since they were assigned. We do not want to invoke renderer factory functions in that mode
12311
+ // to avoid any possible side-effects.
12312
+ const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
12313
+ if (!checkNoChangesMode && rendererFactory.begin)
12314
+ rendererFactory.begin();
12315
+ try {
12316
+ refreshView(tView, lView, tView.template, context);
12317
+ }
12318
+ catch (error) {
12319
+ if (notifyErrorHandler) {
12320
+ handleError(lView, error);
12321
+ }
12322
+ throw error;
12323
+ }
12324
+ finally {
12325
+ if (!checkNoChangesMode && rendererFactory.end)
12326
+ rendererFactory.end();
12327
+ // One final flush of the effects queue to catch any effects created in `ngAfterViewInit` or
12328
+ // other post-order hooks.
12329
+ !checkNoChangesMode && lView[ENVIRONMENT].effectManager?.flush();
12330
+ }
12331
+ }
12332
+ function checkNoChangesInternal(tView, lView, context, notifyErrorHandler = true) {
12333
+ setIsInCheckNoChangesMode(true);
12334
+ try {
12335
+ detectChangesInternal(tView, lView, context, notifyErrorHandler);
12336
+ }
12337
+ finally {
12338
+ setIsInCheckNoChangesMode(false);
12339
+ }
12340
+ }
12341
+ /**
12342
+ * Synchronously perform change detection on a component (and possibly its sub-components).
12343
+ *
12344
+ * This function triggers change detection in a synchronous way on a component.
12345
+ *
12346
+ * @param component The component which the change detection should be performed on.
12347
+ */
12348
+ function detectChanges(component) {
12349
+ const view = getComponentViewByInstance(component);
12350
+ detectChangesInternal(view[TVIEW], view, component);
12351
+ }
12352
+ /**
12353
+ * Processes a view in update mode. This includes a number of steps in a specific order:
12354
+ * - executing a template function in update mode;
12355
+ * - executing hooks;
12356
+ * - refreshing queries;
12357
+ * - setting host bindings;
12358
+ * - refreshing child (embedded and component) views.
12359
+ */
12360
+ function refreshView(tView, lView, templateFn, context) {
12361
+ ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode');
12362
+ const flags = lView[FLAGS];
12363
+ if ((flags & 256 /* LViewFlags.Destroyed */) === 256 /* LViewFlags.Destroyed */)
12364
+ return;
12365
+ // Check no changes mode is a dev only mode used to verify that bindings have not changed
12366
+ // since they were assigned. We do not want to execute lifecycle hooks in that mode.
12367
+ const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
12368
+ !isInCheckNoChangesPass && lView[ENVIRONMENT].effectManager?.flush();
12369
+ enterView(lView);
12370
+ try {
12371
+ resetPreOrderHookFlags(lView);
12372
+ setBindingIndex(tView.bindingStartIndex);
12373
+ if (templateFn !== null) {
12374
+ executeTemplate(tView, lView, templateFn, 2 /* RenderFlags.Update */, context);
12375
+ }
12376
+ const hooksInitPhaseCompleted = (flags & 3 /* LViewFlags.InitPhaseStateMask */) === 3 /* InitPhaseState.InitPhaseCompleted */;
12377
+ // execute pre-order hooks (OnInit, OnChanges, DoCheck)
12378
+ // PERF WARNING: do NOT extract this to a separate function without running benchmarks
12379
+ if (!isInCheckNoChangesPass) {
12380
+ if (hooksInitPhaseCompleted) {
12381
+ const preOrderCheckHooks = tView.preOrderCheckHooks;
12382
+ if (preOrderCheckHooks !== null) {
12383
+ executeCheckHooks(lView, preOrderCheckHooks, null);
12384
+ }
12385
+ }
12386
+ else {
12387
+ const preOrderHooks = tView.preOrderHooks;
12388
+ if (preOrderHooks !== null) {
12389
+ executeInitAndCheckHooks(lView, preOrderHooks, 0 /* InitPhaseState.OnInitHooksToBeRun */, null);
12390
+ }
12391
+ incrementInitPhaseFlags(lView, 0 /* InitPhaseState.OnInitHooksToBeRun */);
12392
+ }
12393
+ }
12394
+ // First mark transplanted views that are declared in this lView as needing a refresh at their
12395
+ // insertion points. This is needed to avoid the situation where the template is defined in this
12396
+ // `LView` but its declaration appears after the insertion component.
12397
+ markTransplantedViewsForRefresh(lView);
12398
+ refreshEmbeddedViews(lView);
12399
+ // Content query results must be refreshed before content hooks are called.
12400
+ if (tView.contentQueries !== null) {
12401
+ refreshContentQueries(tView, lView);
12402
+ }
12403
+ // execute content hooks (AfterContentInit, AfterContentChecked)
12404
+ // PERF WARNING: do NOT extract this to a separate function without running benchmarks
12405
+ if (!isInCheckNoChangesPass) {
12406
+ if (hooksInitPhaseCompleted) {
12407
+ const contentCheckHooks = tView.contentCheckHooks;
12408
+ if (contentCheckHooks !== null) {
12409
+ executeCheckHooks(lView, contentCheckHooks);
12410
+ }
12411
+ }
12412
+ else {
12413
+ const contentHooks = tView.contentHooks;
12414
+ if (contentHooks !== null) {
12415
+ executeInitAndCheckHooks(lView, contentHooks, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
12416
+ }
12417
+ incrementInitPhaseFlags(lView, 1 /* InitPhaseState.AfterContentInitHooksToBeRun */);
12418
+ }
12419
+ }
12420
+ processHostBindingOpCodes(tView, lView);
12421
+ // Refresh child component views.
12422
+ const components = tView.components;
12423
+ if (components !== null) {
12424
+ refreshChildComponents(lView, components);
12425
+ }
12426
+ // View queries must execute after refreshing child components because a template in this view
12427
+ // could be inserted in a child component. If the view query executes before child component
12428
+ // refresh, the template might not yet be inserted.
12429
+ const viewQuery = tView.viewQuery;
12430
+ if (viewQuery !== null) {
12431
+ executeViewQueryFn(2 /* RenderFlags.Update */, viewQuery, context);
12432
+ }
12433
+ // execute view hooks (AfterViewInit, AfterViewChecked)
12434
+ // PERF WARNING: do NOT extract this to a separate function without running benchmarks
12435
+ if (!isInCheckNoChangesPass) {
12436
+ if (hooksInitPhaseCompleted) {
12437
+ const viewCheckHooks = tView.viewCheckHooks;
12438
+ if (viewCheckHooks !== null) {
12439
+ executeCheckHooks(lView, viewCheckHooks);
12440
+ }
12441
+ }
12442
+ else {
12443
+ const viewHooks = tView.viewHooks;
12444
+ if (viewHooks !== null) {
12445
+ executeInitAndCheckHooks(lView, viewHooks, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
12446
+ }
12447
+ incrementInitPhaseFlags(lView, 2 /* InitPhaseState.AfterViewInitHooksToBeRun */);
12448
+ }
12449
+ }
12450
+ if (tView.firstUpdatePass === true) {
12451
+ // We need to make sure that we only flip the flag on successful `refreshView` only
12452
+ // Don't do this in `finally` block.
12453
+ // If we did this in `finally` block then an exception could block the execution of styling
12454
+ // instructions which in turn would be unable to insert themselves into the styling linked
12455
+ // list. The result of this would be that if the exception would not be throw on subsequent CD
12456
+ // the styling would be unable to process it data and reflect to the DOM.
12457
+ tView.firstUpdatePass = false;
12458
+ }
12459
+ // Do not reset the dirty state when running in check no changes mode. We don't want components
12460
+ // to behave differently depending on whether check no changes is enabled or not. For example:
12461
+ // Marking an OnPush component as dirty from within the `ngAfterViewInit` hook in order to
12462
+ // refresh a `NgClass` binding should work. If we would reset the dirty state in the check
12463
+ // no changes cycle, the component would be not be dirty for the next update pass. This would
12464
+ // be different in production mode where the component dirty state is not reset.
12465
+ if (!isInCheckNoChangesPass) {
12466
+ lView[FLAGS] &= ~(64 /* LViewFlags.Dirty */ | 8 /* LViewFlags.FirstLViewPass */);
12467
+ }
12468
+ clearViewRefreshFlag(lView);
12380
12469
  }
12381
- onDestroy(callback) {
12382
- storeLViewOnDestroy(this._lView, callback);
12383
- return () => removeLViewOnDestroy(this._lView, callback);
12470
+ finally {
12471
+ leaveView();
12384
12472
  }
12385
12473
  }
12386
- function injectDestroyRef() {
12387
- return new NodeInjectorDestroyRef(getLView());
12388
- }
12389
-
12390
12474
  /**
12391
- * Tracks all effects registered within a given application and runs them via `flush`.
12475
+ * Goes over embedded views (ones created through ViewContainerRef APIs) and refreshes
12476
+ * them by executing an associated template function.
12392
12477
  */
12393
- class EffectManager {
12394
- constructor() {
12395
- this.all = new Set();
12396
- this.queue = new Map();
12397
- }
12398
- create(effectFn, destroyRef, allowSignalWrites) {
12399
- const zone = (typeof Zone === 'undefined') ? null : Zone.current;
12400
- const watch = new Watch(effectFn, (watch) => {
12401
- if (!this.all.has(watch)) {
12402
- return;
12403
- }
12404
- this.queue.set(watch, zone);
12405
- }, allowSignalWrites);
12406
- this.all.add(watch);
12407
- // Effects start dirty.
12408
- watch.notify();
12409
- let unregisterOnDestroy;
12410
- const destroy = () => {
12411
- watch.cleanup();
12412
- unregisterOnDestroy?.();
12413
- this.all.delete(watch);
12414
- this.queue.delete(watch);
12415
- };
12416
- unregisterOnDestroy = destroyRef?.onDestroy(destroy);
12417
- return {
12418
- destroy,
12419
- };
12420
- }
12421
- flush() {
12422
- if (this.queue.size === 0) {
12423
- return;
12424
- }
12425
- for (const [watch, zone] of this.queue) {
12426
- this.queue.delete(watch);
12427
- if (zone) {
12428
- zone.run(() => watch.run());
12429
- }
12430
- else {
12431
- watch.run();
12478
+ function refreshEmbeddedViews(lView) {
12479
+ for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12480
+ for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12481
+ const embeddedLView = lContainer[i];
12482
+ const embeddedTView = embeddedLView[TVIEW];
12483
+ ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12484
+ if (viewAttachedToChangeDetector(embeddedLView)) {
12485
+ refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
12432
12486
  }
12433
12487
  }
12434
12488
  }
12435
- get isQueueEmpty() {
12436
- return this.queue.size === 0;
12437
- }
12438
- /** @nocollapse */
12439
- static { this.ɵprov = ɵɵdefineInjectable({
12440
- token: EffectManager,
12441
- providedIn: 'root',
12442
- factory: () => new EffectManager(),
12443
- }); }
12444
12489
  }
12445
12490
  /**
12446
- * Create a global `Effect` for the given reactive function.
12491
+ * Mark transplanted views as needing to be refreshed at their insertion points.
12447
12492
  *
12448
- * @developerPreview
12493
+ * @param lView The `LView` that may have transplanted views.
12449
12494
  */
12450
- function effect(effectFn, options) {
12451
- !options?.injector && assertInInjectionContext(effect);
12452
- const injector = options?.injector ?? inject(Injector);
12453
- const effectManager = injector.get(EffectManager);
12454
- const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
12455
- return effectManager.create(effectFn, destroyRef, !!options?.allowSignalWrites);
12495
+ function markTransplantedViewsForRefresh(lView) {
12496
+ for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12497
+ if (!lContainer[HAS_TRANSPLANTED_VIEWS])
12498
+ continue;
12499
+ const movedViews = lContainer[MOVED_VIEWS];
12500
+ ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS');
12501
+ for (let i = 0; i < movedViews.length; i++) {
12502
+ const movedLView = movedViews[i];
12503
+ const insertionLContainer = movedLView[PARENT];
12504
+ ngDevMode && assertLContainer(insertionLContainer);
12505
+ markViewForRefresh(movedLView);
12506
+ }
12507
+ }
12456
12508
  }
12457
-
12458
12509
  /**
12459
- * Compute the static styling (class/style) from `TAttributes`.
12460
- *
12461
- * This function should be called during `firstCreatePass` only.
12510
+ * Refreshes components by entering the component view and processing its bindings, queries, etc.
12462
12511
  *
12463
- * @param tNode The `TNode` into which the styling information should be loaded.
12464
- * @param attrs `TAttributes` containing the styling information.
12465
- * @param writeToHost Where should the resulting static styles be written?
12466
- * - `false` Write to `TNode.stylesWithoutHost` / `TNode.classesWithoutHost`
12467
- * - `true` Write to `TNode.styles` / `TNode.classes`
12512
+ * @param componentHostIdx Element index in LView[] (adjusted for HEADER_OFFSET)
12468
12513
  */
12469
- function computeStaticStyling(tNode, attrs, writeToHost) {
12470
- ngDevMode &&
12471
- assertFirstCreatePass(getTView(), 'Expecting to be called in first template pass only');
12472
- let styles = writeToHost ? tNode.styles : null;
12473
- let classes = writeToHost ? tNode.classes : null;
12474
- let mode = 0;
12475
- if (attrs !== null) {
12476
- for (let i = 0; i < attrs.length; i++) {
12477
- const value = attrs[i];
12478
- if (typeof value === 'number') {
12479
- mode = value;
12480
- }
12481
- else if (mode == 1 /* AttributeMarker.Classes */) {
12482
- classes = concatStringsWithSpace(classes, value);
12483
- }
12484
- else if (mode == 2 /* AttributeMarker.Styles */) {
12485
- const style = value;
12486
- const styleValue = attrs[++i];
12487
- styles = concatStringsWithSpace(styles, style + ': ' + styleValue + ';');
12488
- }
12514
+ function refreshComponent(hostLView, componentHostIdx) {
12515
+ ngDevMode && assertEqual(isCreationMode(hostLView), false, 'Should be run in update mode');
12516
+ const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
12517
+ // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12518
+ if (viewAttachedToChangeDetector(componentView)) {
12519
+ const tView = componentView[TVIEW];
12520
+ if (componentView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */)) {
12521
+ refreshView(tView, componentView, tView.template, componentView[CONTEXT]);
12522
+ }
12523
+ else if (componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
12524
+ // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12525
+ refreshContainsDirtyView(componentView);
12489
12526
  }
12490
12527
  }
12491
- writeToHost ? tNode.styles = styles : tNode.stylesWithoutHost = styles;
12492
- writeToHost ? tNode.classes = classes : tNode.classesWithoutHost = classes;
12493
12528
  }
12494
-
12495
- function collectNativeNodes(tView, lView, tNode, result, isProjection = false) {
12496
- while (tNode !== null) {
12497
- ngDevMode &&
12498
- assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */ | 12 /* TNodeType.AnyContainer */ | 16 /* TNodeType.Projection */ | 32 /* TNodeType.Icu */);
12499
- const lNode = lView[tNode.index];
12500
- if (lNode !== null) {
12501
- result.push(unwrapRNode(lNode));
12502
- }
12503
- // A given lNode can represent either a native node or a LContainer (when it is a host of a
12504
- // ViewContainerRef). When we find a LContainer we need to descend into it to collect root nodes
12505
- // from the views in this container.
12506
- if (isLContainer(lNode)) {
12507
- for (let i = CONTAINER_HEADER_OFFSET; i < lNode.length; i++) {
12508
- const lViewInAContainer = lNode[i];
12509
- const lViewFirstChildTNode = lViewInAContainer[TVIEW].firstChild;
12510
- if (lViewFirstChildTNode !== null) {
12511
- collectNativeNodes(lViewInAContainer[TVIEW], lViewInAContainer, lViewFirstChildTNode, result);
12529
+ /**
12530
+ * Refreshes all transplanted views marked with `LViewFlags.RefreshTransplantedView` that are
12531
+ * children or descendants of the given lView.
12532
+ *
12533
+ * @param lView The lView which contains descendant transplanted views that need to be refreshed.
12534
+ */
12535
+ function refreshContainsDirtyView(lView) {
12536
+ for (let lContainer = getFirstLContainer(lView); lContainer !== null; lContainer = getNextLContainer(lContainer)) {
12537
+ for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
12538
+ const embeddedLView = lContainer[i];
12539
+ if (viewAttachedToChangeDetector(embeddedLView)) {
12540
+ if (embeddedLView[FLAGS] & 1024 /* LViewFlags.RefreshView */) {
12541
+ const embeddedTView = embeddedLView[TVIEW];
12542
+ ngDevMode && assertDefined(embeddedTView, 'TView must be allocated');
12543
+ refreshView(embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]);
12544
+ }
12545
+ else if (embeddedLView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
12546
+ refreshContainsDirtyView(embeddedLView);
12512
12547
  }
12513
- }
12514
- // When an LContainer is created, the anchor (comment) node is:
12515
- // - (1) either reused in case of an ElementContainer (<ng-container>)
12516
- // - (2) or a new comment node is created
12517
- // In the first case, the anchor comment node would be added to the final
12518
- // list by the code above (`result.push(unwrapRNode(lNode))`), but the second
12519
- // case requires extra handling: the anchor node needs to be added to the
12520
- // final list manually. See additional information in the `createAnchorNode`
12521
- // function in the `view_container_ref.ts`.
12522
- //
12523
- // In the first case, the same reference would be stored in the `NATIVE`
12524
- // and `HOST` slots in an LContainer. Otherwise, this is the second case and
12525
- // we should add an element to the final list.
12526
- if (lNode[NATIVE] !== lNode[HOST]) {
12527
- result.push(lNode[NATIVE]);
12528
- }
12529
- }
12530
- const tNodeType = tNode.type;
12531
- if (tNodeType & 8 /* TNodeType.ElementContainer */) {
12532
- collectNativeNodes(tView, lView, tNode.child, result);
12533
- }
12534
- else if (tNodeType & 32 /* TNodeType.Icu */) {
12535
- const nextRNode = icuContainerIterate(tNode, lView);
12536
- let rNode;
12537
- while (rNode = nextRNode()) {
12538
- result.push(rNode);
12539
12548
  }
12540
12549
  }
12541
- else if (tNodeType & 16 /* TNodeType.Projection */) {
12542
- const nodesInSlot = getProjectionNodes(lView, tNode);
12543
- if (Array.isArray(nodesInSlot)) {
12544
- result.push(...nodesInSlot);
12545
- }
12546
- else {
12547
- const parentView = getLViewParent(lView[DECLARATION_COMPONENT_VIEW]);
12548
- ngDevMode && assertParentView(parentView);
12549
- collectNativeNodes(parentView[TVIEW], parentView, nodesInSlot, result, true);
12550
+ }
12551
+ const tView = lView[TVIEW];
12552
+ // Refresh child component views.
12553
+ const components = tView.components;
12554
+ if (components !== null) {
12555
+ for (let i = 0; i < components.length; i++) {
12556
+ const componentView = getComponentLViewByIndex(components[i], lView);
12557
+ // Only attached components that are CheckAlways or OnPush and dirty should be refreshed
12558
+ if (viewAttachedToChangeDetector(componentView) &&
12559
+ componentView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
12560
+ refreshContainsDirtyView(componentView);
12550
12561
  }
12551
12562
  }
12552
- tNode = isProjection ? tNode.projectionNext : tNode.next;
12553
12563
  }
12554
- return result;
12564
+ }
12565
+ /** Refreshes child components in the current view (update mode). */
12566
+ function refreshChildComponents(hostLView, components) {
12567
+ for (let i = 0; i < components.length; i++) {
12568
+ refreshComponent(hostLView, components[i]);
12569
+ }
12555
12570
  }
12556
12571
 
12557
12572
  class ViewRef$1 {
@@ -14236,18 +14251,6 @@ function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
14236
14251
  return ɵɵattributeInterpolateV;
14237
14252
  }
14238
14253
 
14239
- /**
14240
- * Synchronously perform change detection on a component (and possibly its sub-components).
14241
- *
14242
- * This function triggers change detection in a synchronous way on a component.
14243
- *
14244
- * @param component The component which the change detection should be performed on.
14245
- */
14246
- function detectChanges(component) {
14247
- const view = getComponentViewByInstance(component);
14248
- detectChangesInternal(view[TVIEW], view, component);
14249
- }
14250
-
14251
14254
  const AT_THIS_LOCATION = '<-- AT THIS LOCATION';
14252
14255
  /**
14253
14256
  * Retrieves a user friendly string for a given TNodeType for use in
@@ -14321,9 +14324,16 @@ function validateSiblingNodeExists(node) {
14321
14324
  /**
14322
14325
  * Validates that a node exists or throws
14323
14326
  */
14324
- function validateNodeExists(node) {
14327
+ function validateNodeExists(node, lView = null, tNode = null) {
14325
14328
  if (!node) {
14326
- throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, `Hydration expected an element to be present at this location.`);
14329
+ const header = 'During hydration, Angular expected an element to be present at this location.\n\n';
14330
+ let expected = '';
14331
+ let footer = '';
14332
+ if (lView !== null && tNode !== null) {
14333
+ expected = `${describeExpectedDom(lView, tNode, false)}\n\n`;
14334
+ footer = getHydrationErrorFooter();
14335
+ }
14336
+ throw new RuntimeError(-502 /* RuntimeErrorCode.HYDRATION_MISSING_NODE */, header + expected + footer);
14327
14337
  }
14328
14338
  }
14329
14339
  /**
@@ -14380,7 +14390,7 @@ function invalidSkipHydrationHost(rNode) {
14380
14390
  'that doesn\'t act as a component host. Hydration can be ' +
14381
14391
  'skipped only on per-component basis.\n\n';
14382
14392
  const actual = `${describeDomFromNode(rNode)}\n\n`;
14383
- const footer = 'Please move the `ngSkipHydration` attribute to the component host element.';
14393
+ const footer = 'Please move the `ngSkipHydration` attribute to the component host element.\n\n';
14384
14394
  const message = header + actual + footer;
14385
14395
  return new RuntimeError(-504 /* RuntimeErrorCode.INVALID_SKIP_HYDRATION_HOST */, message);
14386
14396
  }
@@ -14565,8 +14575,9 @@ function getHydrationErrorFooter(componentClassName) {
14565
14575
  const componentInfo = componentClassName ? `the "${componentClassName}"` : 'corresponding';
14566
14576
  return `To fix this problem:\n` +
14567
14577
  ` * check ${componentInfo} component for hydration-related issues\n` +
14578
+ ` * check to see if your template has valid HTML structure\n` +
14568
14579
  ` * or skip hydration by adding the \`ngSkipHydration\` attribute ` +
14569
- `to its host node in a template`;
14580
+ `to its host node in a template\n\n`;
14570
14581
  }
14571
14582
  /**
14572
14583
  * An attribute related note for hydration errors
@@ -14926,17 +14937,11 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
14926
14937
  ngDevMode && assertFirstCreatePass(tView);
14927
14938
  ngDevMode && ngDevMode.firstCreatePass++;
14928
14939
  const tViewConsts = tView.consts;
14929
- let ssrId = null;
14930
- const hydrationInfo = lView[HYDRATION];
14931
- if (hydrationInfo) {
14932
- const noOffsetIndex = index - HEADER_OFFSET;
14933
- ssrId = hydrationInfo.data[TEMPLATES]?.[noOffsetIndex] ?? null;
14934
- }
14935
14940
  // TODO(pk): refactor getOrCreateTNode to have the "create" only version
14936
14941
  const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
14937
14942
  resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
14938
14943
  registerPostOrderHooks(tView, tNode);
14939
- const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, ssrId);
14944
+ const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, null /* ssrId */);
14940
14945
  if (tView.queries !== null) {
14941
14946
  tView.queries.template(tView, tNode);
14942
14947
  embeddedTView.queries = tView.queries.embeddedTView(tNode);
@@ -15003,9 +15008,27 @@ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
15003
15008
  if (isNodeCreationMode) {
15004
15009
  return createContainerAnchorImpl(tView, lView, tNode, index);
15005
15010
  }
15011
+ const ssrId = hydrationInfo.data[TEMPLATES]?.[index] ?? null;
15012
+ // Apply `ssrId` value to the underlying TView if it was not previously set.
15013
+ //
15014
+ // There might be situations when the same component is present in a template
15015
+ // multiple times and some instances are opted-out of using hydration via
15016
+ // `ngSkipHydration` attribute. In this scenario, at the time a TView is created,
15017
+ // the `ssrId` might be `null` (if the first component is opted-out of hydration).
15018
+ // The code below makes sure that the `ssrId` is applied to the TView if it's still
15019
+ // `null` and verifies we never try to override it with a different value.
15020
+ if (ssrId !== null && tNode.tView !== null) {
15021
+ if (tNode.tView.ssrId === null) {
15022
+ tNode.tView.ssrId = ssrId;
15023
+ }
15024
+ else {
15025
+ ngDevMode &&
15026
+ assertEqual(tNode.tView.ssrId, ssrId, 'Unexpected value of the `ssrId` for this TView');
15027
+ }
15028
+ }
15006
15029
  // Hydration mode, looking up existing elements in DOM.
15007
15030
  const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
15008
- ngDevMode && validateNodeExists(currentRNode);
15031
+ ngDevMode && validateNodeExists(currentRNode, lView, tNode);
15009
15032
  setSegmentHead(hydrationInfo, index, currentRNode);
15010
15033
  const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
15011
15034
  const comment = siblingAfter(viewContainerSize, currentRNode);
@@ -15239,7 +15262,7 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, inde
15239
15262
  // `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
15240
15263
  // so while processing a `<div>` instruction, point to the next sibling as a
15241
15264
  // start of a segment.
15242
- ngDevMode && validateNodeExists(native.nextSibling);
15265
+ ngDevMode && validateNodeExists(native.nextSibling, lView, tNode);
15243
15266
  setSegmentHead(hydrationInfo, index, native.nextSibling);
15244
15267
  }
15245
15268
  // Checks if the skip hydration attribute is present during hydration so we know to
@@ -15384,7 +15407,7 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
15384
15407
  }
15385
15408
  // Hydration mode, looking up existing elements in DOM.
15386
15409
  const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
15387
- ngDevMode && validateNodeExists(currentRNode);
15410
+ ngDevMode && validateNodeExists(currentRNode, lView, tNode);
15388
15411
  const ngContainerSize = getNgContainerSize(hydrationInfo, index);
15389
15412
  ngDevMode &&
15390
15413
  assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
@@ -25265,8 +25288,13 @@ class ApplicationInitStatus {
25265
25288
  this.resolve = res;
25266
25289
  this.reject = rej;
25267
25290
  });
25268
- // TODO: Throw RuntimeErrorCode.INVALID_MULTI_PROVIDER if appInits is not an array
25269
25291
  this.appInits = inject(APP_INITIALIZER, { optional: true }) ?? [];
25292
+ if ((typeof ngDevMode === 'undefined' || ngDevMode) && !Array.isArray(this.appInits)) {
25293
+ throw new RuntimeError(-209 /* RuntimeErrorCode.INVALID_MULTI_PROVIDER */, 'Unexpected type of the `APP_INITIALIZER` token value ' +
25294
+ `(expected an array, but got ${typeof this.appInits}). ` +
25295
+ 'Please check that the `APP_INITIALIZER` token is configured as a ' +
25296
+ '`multi: true` provider.');
25297
+ }
25270
25298
  }
25271
25299
  /** @internal */
25272
25300
  runInitializers() {
@@ -25309,7 +25337,7 @@ class ApplicationInitStatus {
25309
25337
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationInitStatus, [{
25310
25338
  type: Injectable,
25311
25339
  args: [{ providedIn: 'root' }]
25312
- }], null, null); })();
25340
+ }], function () { return []; }, null); })();
25313
25341
 
25314
25342
  class Console {
25315
25343
  log(message) {
@@ -26602,6 +26630,7 @@ function createOrReusePlatformInjector(providers = []) {
26602
26630
  const injector = createPlatformInjector(providers);
26603
26631
  _platformInjector = injector;
26604
26632
  publishDefaultGlobalUtils();
26633
+ publishSignalConfiguration();
26605
26634
  runPlatformInitializers(injector);
26606
26635
  return injector;
26607
26636
  }