@angular/core 18.0.0-next.2 → 18.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.
- package/esm2022/rxjs-interop/src/to_signal.mjs +2 -2
- package/esm2022/src/application/application_init.mjs +2 -2
- package/esm2022/src/application/application_ref.mjs +10 -15
- package/esm2022/src/application/application_tokens.mjs +3 -3
- package/esm2022/src/change_detection/scheduling/ng_zone_scheduling.mjs +20 -3
- package/esm2022/src/change_detection/scheduling/zoneless_scheduling_impl.mjs +7 -6
- package/esm2022/src/core_private_export.mjs +3 -3
- package/esm2022/src/defer/instructions.mjs +2 -2
- package/esm2022/src/di/interface/provider.mjs +1 -1
- package/esm2022/src/di/metadata.mjs +1 -1
- package/esm2022/src/hydration/annotate.mjs +35 -49
- package/esm2022/src/hydration/api.mjs +36 -13
- package/esm2022/src/hydration/cleanup.mjs +4 -18
- package/esm2022/src/hydration/i18n.mjs +378 -0
- package/esm2022/src/hydration/interfaces.mjs +2 -1
- package/esm2022/src/hydration/node_lookup_utils.mjs +24 -10
- package/esm2022/src/hydration/utils.mjs +61 -2
- package/esm2022/src/linker/component_factory.mjs +1 -1
- package/esm2022/src/linker/view_container_ref.mjs +2 -2
- package/esm2022/src/linker/view_ref.mjs +4 -4
- package/esm2022/src/metadata/directives.mjs +1 -1
- package/esm2022/src/metadata/ng_module.mjs +1 -1
- package/esm2022/src/render3/component_ref.mjs +1 -1
- package/esm2022/src/render3/i18n/i18n_apply.mjs +28 -6
- package/esm2022/src/render3/i18n/i18n_parse.mjs +2 -5
- package/esm2022/src/render3/i18n/i18n_util.mjs +6 -1
- package/esm2022/src/render3/instructions/i18n.mjs +3 -1
- package/esm2022/src/render3/util/injector_discovery_utils.mjs +12 -8
- package/esm2022/src/render3/util/view_utils.mjs +4 -14
- package/esm2022/src/util/callback_scheduler.mjs +23 -33
- package/esm2022/src/version.mjs +1 -1
- package/esm2022/src/zone/ng_zone.mjs +3 -3
- package/esm2022/testing/src/component_fixture.mjs +2 -2
- package/esm2022/testing/src/fake_async.mjs +6 -1
- package/esm2022/testing/src/logger.mjs +3 -3
- package/esm2022/testing/src/private_export.mjs +9 -0
- package/esm2022/testing/src/test_hooks.mjs +3 -3
- package/esm2022/testing/src/testing.mjs +3 -2
- package/fesm2022/core.mjs +1124 -688
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +1 -1
- package/fesm2022/rxjs-interop.mjs +2 -2
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +41 -36
- package/fesm2022/testing.mjs.map +1 -1
- package/index.d.ts +80 -33
- package/package.json +1 -1
- package/primitives/signals/index.d.ts +1 -1
- package/rxjs-interop/index.d.ts +2 -2
- package/schematics/migrations/block-template-entities/bundle.js +157 -157
- package/schematics/migrations/block-template-entities/bundle.js.map +1 -1
- package/schematics/migrations/compiler-options/bundle.js +13 -13
- package/schematics/migrations/invalid-two-way-bindings/bundle.js +158 -158
- package/schematics/migrations/invalid-two-way-bindings/bundle.js.map +1 -1
- package/schematics/migrations/transfer-state/bundle.js +13 -13
- package/schematics/ng-generate/control-flow-migration/bundle.js +189 -177
- package/schematics/ng-generate/control-flow-migration/bundle.js.map +3 -3
- package/schematics/ng-generate/standalone-migration/bundle.js +450 -467
- package/schematics/ng-generate/standalone-migration/bundle.js.map +2 -2
- package/testing/index.d.ts +7 -1
- package/esm2022/src/change_detection/flags.mjs +0 -17
package/fesm2022/core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v18.0.0-next.
|
|
2
|
+
* @license Angular v18.0.0-next.3
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -4152,16 +4152,6 @@ const profiler = function (event, instance, hookOrListener) {
|
|
|
4152
4152
|
const SVG_NAMESPACE = 'svg';
|
|
4153
4153
|
const MATH_ML_NAMESPACE = 'math';
|
|
4154
4154
|
|
|
4155
|
-
// TODO(atscott): Remove prior to v18 release. Keeping this around in case anyone internally needs
|
|
4156
|
-
// to opt out temporarily.
|
|
4157
|
-
let _ensureDirtyViewsAreAlwaysReachable = true;
|
|
4158
|
-
function getEnsureDirtyViewsAreAlwaysReachable() {
|
|
4159
|
-
return _ensureDirtyViewsAreAlwaysReachable;
|
|
4160
|
-
}
|
|
4161
|
-
function setEnsureDirtyViewsAreAlwaysReachable(v) {
|
|
4162
|
-
_ensureDirtyViewsAreAlwaysReachable = v;
|
|
4163
|
-
}
|
|
4164
|
-
|
|
4165
4155
|
/**
|
|
4166
4156
|
* For efficiency reasons we often put several different data types (`RNode`, `LView`, `LContainer`)
|
|
4167
4157
|
* in same location in `LView`. This is because we don't want to pre-allocate space for it
|
|
@@ -4329,21 +4319,12 @@ function requiresRefreshOrTraversal(lView) {
|
|
|
4329
4319
|
*/
|
|
4330
4320
|
function updateAncestorTraversalFlagsOnAttach(lView) {
|
|
4331
4321
|
lView[ENVIRONMENT].changeDetectionScheduler?.notify(1 /* NotificationType.AfterRenderHooks */);
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4322
|
+
if (lView[FLAGS] & 64 /* LViewFlags.Dirty */) {
|
|
4323
|
+
lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
4324
|
+
}
|
|
4335
4325
|
if (requiresRefreshOrTraversal(lView)) {
|
|
4336
4326
|
markAncestorsForTraversal(lView);
|
|
4337
4327
|
}
|
|
4338
|
-
else if (lView[FLAGS] & 64 /* LViewFlags.Dirty */) {
|
|
4339
|
-
if (getEnsureDirtyViewsAreAlwaysReachable()) {
|
|
4340
|
-
lView[FLAGS] |= 1024 /* LViewFlags.RefreshView */;
|
|
4341
|
-
markAncestorsForTraversal(lView);
|
|
4342
|
-
}
|
|
4343
|
-
else {
|
|
4344
|
-
lView[ENVIRONMENT].changeDetectionScheduler?.notify();
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
4328
|
}
|
|
4348
4329
|
/**
|
|
4349
4330
|
* Ensures views above the given `lView` are traversed during change detection even when they are
|
|
@@ -7983,7 +7964,7 @@ function getDocument() {
|
|
|
7983
7964
|
}
|
|
7984
7965
|
|
|
7985
7966
|
/**
|
|
7986
|
-
* A
|
|
7967
|
+
* A DI token representing a string ID, used
|
|
7987
7968
|
* primarily for prefixing application attributes and CSS styles when
|
|
7988
7969
|
* {@link ViewEncapsulation#Emulated} is being used.
|
|
7989
7970
|
*
|
|
@@ -8032,7 +8013,7 @@ const PLATFORM_ID = new InjectionToken(ngDevMode ? 'Platform ID' : '', {
|
|
|
8032
8013
|
factory: () => 'unknown', // set a default platform name, when none set explicitly
|
|
8033
8014
|
});
|
|
8034
8015
|
/**
|
|
8035
|
-
* A
|
|
8016
|
+
* A DI token that indicates the root directory of
|
|
8036
8017
|
* the application
|
|
8037
8018
|
* @publicApi
|
|
8038
8019
|
* @deprecated
|
|
@@ -8246,6 +8227,7 @@ const NUM_ROOT_NODES = 'r';
|
|
|
8246
8227
|
const TEMPLATE_ID = 'i'; // as it's also an "id"
|
|
8247
8228
|
const NODES = 'n';
|
|
8248
8229
|
const DISCONNECTED_NODES = 'd';
|
|
8230
|
+
const I18N_DATA = 'l';
|
|
8249
8231
|
|
|
8250
8232
|
/**
|
|
8251
8233
|
* The name of the key used in the TransferState collection,
|
|
@@ -8514,6 +8496,9 @@ function getNgContainerSize(hydrationInfo, index) {
|
|
|
8514
8496
|
}
|
|
8515
8497
|
return size;
|
|
8516
8498
|
}
|
|
8499
|
+
function isSerializedElementContainer(hydrationInfo, index) {
|
|
8500
|
+
return hydrationInfo.data[ELEMENT_CONTAINERS]?.[index] !== undefined;
|
|
8501
|
+
}
|
|
8517
8502
|
function getSerializedContainerViews(hydrationInfo, index) {
|
|
8518
8503
|
return hydrationInfo.data[CONTAINERS]?.[index] ?? null;
|
|
8519
8504
|
}
|
|
@@ -8529,6 +8514,18 @@ function calcSerializedContainerSize(hydrationInfo, index) {
|
|
|
8529
8514
|
}
|
|
8530
8515
|
return numNodes;
|
|
8531
8516
|
}
|
|
8517
|
+
/**
|
|
8518
|
+
* Attempt to initialize the `disconnectedNodes` field of the given
|
|
8519
|
+
* `DehydratedView`. Returns the initialized value.
|
|
8520
|
+
*/
|
|
8521
|
+
function initDisconnectedNodes(hydrationInfo) {
|
|
8522
|
+
// Check if we are processing disconnected info for the first time.
|
|
8523
|
+
if (typeof hydrationInfo.disconnectedNodes === 'undefined') {
|
|
8524
|
+
const nodeIds = hydrationInfo.data[DISCONNECTED_NODES];
|
|
8525
|
+
hydrationInfo.disconnectedNodes = nodeIds ? new Set(nodeIds) : null;
|
|
8526
|
+
}
|
|
8527
|
+
return hydrationInfo.disconnectedNodes;
|
|
8528
|
+
}
|
|
8532
8529
|
/**
|
|
8533
8530
|
* Checks whether a node is annotated as "disconnected", i.e. not present
|
|
8534
8531
|
* in the DOM at serialization time. We should not attempt hydration for
|
|
@@ -8540,7 +8537,51 @@ function isDisconnectedNode$1(hydrationInfo, index) {
|
|
|
8540
8537
|
const nodeIds = hydrationInfo.data[DISCONNECTED_NODES];
|
|
8541
8538
|
hydrationInfo.disconnectedNodes = nodeIds ? new Set(nodeIds) : null;
|
|
8542
8539
|
}
|
|
8543
|
-
return !!hydrationInfo
|
|
8540
|
+
return !!initDisconnectedNodes(hydrationInfo)?.has(index);
|
|
8541
|
+
}
|
|
8542
|
+
/**
|
|
8543
|
+
* Helper function to prepare text nodes for serialization by ensuring
|
|
8544
|
+
* that seperate logical text blocks in the DOM remain separate after
|
|
8545
|
+
* serialization.
|
|
8546
|
+
*/
|
|
8547
|
+
function processTextNodeBeforeSerialization(context, node) {
|
|
8548
|
+
// Handle cases where text nodes can be lost after DOM serialization:
|
|
8549
|
+
// 1. When there is an *empty text node* in DOM: in this case, this
|
|
8550
|
+
// node would not make it into the serialized string and as a result,
|
|
8551
|
+
// this node wouldn't be created in a browser. This would result in
|
|
8552
|
+
// a mismatch during the hydration, where the runtime logic would expect
|
|
8553
|
+
// a text node to be present in live DOM, but no text node would exist.
|
|
8554
|
+
// Example: `<span>{{ name }}</span>` when the `name` is an empty string.
|
|
8555
|
+
// This would result in `<span></span>` string after serialization and
|
|
8556
|
+
// in a browser only the `span` element would be created. To resolve that,
|
|
8557
|
+
// an extra comment node is appended in place of an empty text node and
|
|
8558
|
+
// that special comment node is replaced with an empty text node *before*
|
|
8559
|
+
// hydration.
|
|
8560
|
+
// 2. When there are 2 consecutive text nodes present in the DOM.
|
|
8561
|
+
// Example: `<div>Hello <ng-container *ngIf="true">world</ng-container></div>`.
|
|
8562
|
+
// In this scenario, the live DOM would look like this:
|
|
8563
|
+
// <div>#text('Hello ') #text('world') #comment('container')</div>
|
|
8564
|
+
// Serialized string would look like this: `<div>Hello world<!--container--></div>`.
|
|
8565
|
+
// The live DOM in a browser after that would be:
|
|
8566
|
+
// <div>#text('Hello world') #comment('container')</div>
|
|
8567
|
+
// Notice how 2 text nodes are now "merged" into one. This would cause hydration
|
|
8568
|
+
// logic to fail, since it'd expect 2 text nodes being present, not one.
|
|
8569
|
+
// To fix this, we insert a special comment node in between those text nodes, so
|
|
8570
|
+
// serialized representation is: `<div>Hello <!--ngtns-->world<!--container--></div>`.
|
|
8571
|
+
// This forces browser to create 2 text nodes separated by a comment node.
|
|
8572
|
+
// Before running a hydration process, this special comment node is removed, so the
|
|
8573
|
+
// live DOM has exactly the same state as it was before serialization.
|
|
8574
|
+
// Collect this node as required special annotation only when its
|
|
8575
|
+
// contents is empty. Otherwise, such text node would be present on
|
|
8576
|
+
// the client after server-side rendering and no special handling needed.
|
|
8577
|
+
const el = node;
|
|
8578
|
+
const corruptedTextNodes = context.corruptedTextNodes;
|
|
8579
|
+
if (el.textContent === '') {
|
|
8580
|
+
corruptedTextNodes.set(el, "ngetn" /* TextNodeMarker.EmptyNode */);
|
|
8581
|
+
}
|
|
8582
|
+
else if (el.nextSibling?.nodeType === Node.TEXT_NODE) {
|
|
8583
|
+
corruptedTextNodes.set(el, "ngtns" /* TextNodeMarker.Separator */);
|
|
8584
|
+
}
|
|
8544
8585
|
}
|
|
8545
8586
|
|
|
8546
8587
|
/**
|
|
@@ -12745,7 +12786,7 @@ function detectChangesInViewWhileDirty(lView, mode) {
|
|
|
12745
12786
|
const lastIsRefreshingViewsValue = isRefreshingViews();
|
|
12746
12787
|
try {
|
|
12747
12788
|
setIsRefreshingViews(true);
|
|
12748
|
-
detectChangesInView
|
|
12789
|
+
detectChangesInView(lView, mode);
|
|
12749
12790
|
let retries = 0;
|
|
12750
12791
|
// If after running change detection, this view still needs to be refreshed or there are
|
|
12751
12792
|
// descendants views that need to be refreshed due to re-dirtying during the change detection
|
|
@@ -12761,7 +12802,7 @@ function detectChangesInViewWhileDirty(lView, mode) {
|
|
|
12761
12802
|
retries++;
|
|
12762
12803
|
// Even if this view is detached, we still detect changes in targeted mode because this was
|
|
12763
12804
|
// the root of the change detection run.
|
|
12764
|
-
detectChangesInView
|
|
12805
|
+
detectChangesInView(lView, 1 /* ChangeDetectionMode.Targeted */);
|
|
12765
12806
|
}
|
|
12766
12807
|
}
|
|
12767
12808
|
finally {
|
|
@@ -12996,7 +13037,7 @@ function detectChangesInViewIfAttached(lView, mode) {
|
|
|
12996
13037
|
if (!viewAttachedToChangeDetector(lView)) {
|
|
12997
13038
|
return;
|
|
12998
13039
|
}
|
|
12999
|
-
detectChangesInView
|
|
13040
|
+
detectChangesInView(lView, mode);
|
|
13000
13041
|
}
|
|
13001
13042
|
/**
|
|
13002
13043
|
* Visits a view as part of change detection traversal.
|
|
@@ -13008,7 +13049,7 @@ function detectChangesInViewIfAttached(lView, mode) {
|
|
|
13008
13049
|
* The view is not refreshed, but descendants are traversed in `ChangeDetectionMode.Targeted` if the
|
|
13009
13050
|
* view HasChildViewsToRefresh flag is set.
|
|
13010
13051
|
*/
|
|
13011
|
-
function detectChangesInView
|
|
13052
|
+
function detectChangesInView(lView, mode) {
|
|
13012
13053
|
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
|
13013
13054
|
const tView = lView[TVIEW];
|
|
13014
13055
|
const flags = lView[FLAGS];
|
|
@@ -13819,108 +13860,244 @@ function shorten(input, maxLength = 50) {
|
|
|
13819
13860
|
}
|
|
13820
13861
|
|
|
13821
13862
|
/**
|
|
13822
|
-
*
|
|
13823
|
-
*
|
|
13824
|
-
*
|
|
13863
|
+
* Find a node in front of which `currentTNode` should be inserted (takes i18n into account).
|
|
13864
|
+
*
|
|
13865
|
+
* This method determines the `RNode` in front of which we should insert the `currentRNode`. This
|
|
13866
|
+
* takes `TNode.insertBeforeIndex` into account.
|
|
13867
|
+
*
|
|
13868
|
+
* @param parentTNode parent `TNode`
|
|
13869
|
+
* @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
|
|
13870
|
+
* @param lView current `LView`
|
|
13825
13871
|
*/
|
|
13826
|
-
function
|
|
13827
|
-
const
|
|
13828
|
-
const
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13872
|
+
function getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView) {
|
|
13873
|
+
const tNodeInsertBeforeIndex = currentTNode.insertBeforeIndex;
|
|
13874
|
+
const insertBeforeIndex = Array.isArray(tNodeInsertBeforeIndex) ? tNodeInsertBeforeIndex[0] : tNodeInsertBeforeIndex;
|
|
13875
|
+
if (insertBeforeIndex === null) {
|
|
13876
|
+
return getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView);
|
|
13877
|
+
}
|
|
13878
|
+
else {
|
|
13879
|
+
ngDevMode && assertIndexInRange(lView, insertBeforeIndex);
|
|
13880
|
+
return unwrapRNode(lView[insertBeforeIndex]);
|
|
13833
13881
|
}
|
|
13834
|
-
// Reset the value to an empty array to indicate that no
|
|
13835
|
-
// further processing of dehydrated views is needed for
|
|
13836
|
-
// this view container (i.e. do not trigger the lookup process
|
|
13837
|
-
// once again in case a `ViewContainerRef` is created later).
|
|
13838
|
-
lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
|
|
13839
13882
|
}
|
|
13840
13883
|
/**
|
|
13841
|
-
*
|
|
13884
|
+
* Process `TNode.insertBeforeIndex` by adding i18n text nodes.
|
|
13885
|
+
*
|
|
13886
|
+
* See `TNode.insertBeforeIndex`
|
|
13842
13887
|
*/
|
|
13843
|
-
function
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13850
|
-
|
|
13851
|
-
|
|
13852
|
-
|
|
13853
|
-
|
|
13888
|
+
function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRElement) {
|
|
13889
|
+
const tNodeInsertBeforeIndex = childTNode.insertBeforeIndex;
|
|
13890
|
+
if (Array.isArray(tNodeInsertBeforeIndex)) {
|
|
13891
|
+
// An array indicates that there are i18n nodes that need to be added as children of this
|
|
13892
|
+
// `childRNode`. These i18n nodes were created before this `childRNode` was available and so
|
|
13893
|
+
// only now can be added. The first element of the array is the normal index where we should
|
|
13894
|
+
// insert the `childRNode`. Additional elements are the extra nodes to be added as children of
|
|
13895
|
+
// `childRNode`.
|
|
13896
|
+
ngDevMode && assertDomNode(childRNode);
|
|
13897
|
+
let i18nParent = childRNode;
|
|
13898
|
+
let anchorRNode = null;
|
|
13899
|
+
if (!(childTNode.type & 3 /* TNodeType.AnyRNode */)) {
|
|
13900
|
+
anchorRNode = i18nParent;
|
|
13901
|
+
i18nParent = parentRElement;
|
|
13902
|
+
}
|
|
13903
|
+
if (i18nParent !== null && childTNode.componentOffset === -1) {
|
|
13904
|
+
for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
|
|
13905
|
+
// No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
|
|
13906
|
+
// see `assertDomNode` below.
|
|
13907
|
+
const i18nChild = lView[tNodeInsertBeforeIndex[i]];
|
|
13908
|
+
nativeInsertBefore(renderer, i18nParent, i18nChild, anchorRNode, false);
|
|
13909
|
+
}
|
|
13854
13910
|
}
|
|
13855
13911
|
}
|
|
13856
13912
|
}
|
|
13913
|
+
|
|
13857
13914
|
/**
|
|
13858
|
-
*
|
|
13859
|
-
*
|
|
13915
|
+
* Add `tNode` to `previousTNodes` list and update relevant `TNode`s in `previousTNodes` list
|
|
13916
|
+
* `tNode.insertBeforeIndex`.
|
|
13917
|
+
*
|
|
13918
|
+
* Things to keep in mind:
|
|
13919
|
+
* 1. All i18n text nodes are encoded as `TNodeType.Element` and are created eagerly by the
|
|
13920
|
+
* `ɵɵi18nStart` instruction.
|
|
13921
|
+
* 2. All `TNodeType.Placeholder` `TNodes` are elements which will be created later by
|
|
13922
|
+
* `ɵɵelementStart` instruction.
|
|
13923
|
+
* 3. `ɵɵelementStart` instruction will create `TNode`s in the ascending `TNode.index` order. (So a
|
|
13924
|
+
* smaller index `TNode` is guaranteed to be created before a larger one)
|
|
13925
|
+
*
|
|
13926
|
+
* We use the above three invariants to determine `TNode.insertBeforeIndex`.
|
|
13927
|
+
*
|
|
13928
|
+
* In an ideal world `TNode.insertBeforeIndex` would always be `TNode.next.index`. However,
|
|
13929
|
+
* this will not work because `TNode.next.index` may be larger than `TNode.index` which means that
|
|
13930
|
+
* the next node is not yet created and therefore we can't insert in front of it.
|
|
13931
|
+
*
|
|
13932
|
+
* Rule1: `TNode.insertBeforeIndex = null` if `TNode.next === null` (Initial condition, as we don't
|
|
13933
|
+
* know if there will be further `TNode`s inserted after.)
|
|
13934
|
+
* Rule2: If `previousTNode` is created after the `tNode` being inserted, then
|
|
13935
|
+
* `previousTNode.insertBeforeNode = tNode.index` (So when a new `tNode` is added we check
|
|
13936
|
+
* previous to see if we can update its `insertBeforeTNode`)
|
|
13937
|
+
*
|
|
13938
|
+
* See `TNode.insertBeforeIndex` for more context.
|
|
13939
|
+
*
|
|
13940
|
+
* @param previousTNodes A list of previous TNodes so that we can easily traverse `TNode`s in
|
|
13941
|
+
* reverse order. (If `TNode` would have `previous` this would not be necessary.)
|
|
13942
|
+
* @param newTNode A TNode to add to the `previousTNodes` list.
|
|
13860
13943
|
*/
|
|
13861
|
-
function
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13944
|
+
function addTNodeAndUpdateInsertBeforeIndex(previousTNodes, newTNode) {
|
|
13945
|
+
// Start with Rule1
|
|
13946
|
+
ngDevMode &&
|
|
13947
|
+
assertEqual(newTNode.insertBeforeIndex, null, 'We expect that insertBeforeIndex is not set');
|
|
13948
|
+
previousTNodes.push(newTNode);
|
|
13949
|
+
if (previousTNodes.length > 1) {
|
|
13950
|
+
for (let i = previousTNodes.length - 2; i >= 0; i--) {
|
|
13951
|
+
const existingTNode = previousTNodes[i];
|
|
13952
|
+
// Text nodes are created eagerly and so they don't need their `indexBeforeIndex` updated.
|
|
13953
|
+
// It is safe to ignore them.
|
|
13954
|
+
if (!isI18nText(existingTNode)) {
|
|
13955
|
+
if (isNewTNodeCreatedBefore(existingTNode, newTNode) &&
|
|
13956
|
+
getInsertBeforeIndex(existingTNode) === null) {
|
|
13957
|
+
// If it was created before us in time, (and it does not yet have `insertBeforeIndex`)
|
|
13958
|
+
// then add the `insertBeforeIndex`.
|
|
13959
|
+
setInsertBeforeIndex(existingTNode, newTNode.index);
|
|
13960
|
+
}
|
|
13961
|
+
}
|
|
13962
|
+
}
|
|
13865
13963
|
}
|
|
13866
13964
|
}
|
|
13965
|
+
function isI18nText(tNode) {
|
|
13966
|
+
return !(tNode.type & 64 /* TNodeType.Placeholder */);
|
|
13967
|
+
}
|
|
13968
|
+
function isNewTNodeCreatedBefore(existingTNode, newTNode) {
|
|
13969
|
+
return isI18nText(newTNode) || existingTNode.index > newTNode.index;
|
|
13970
|
+
}
|
|
13971
|
+
function getInsertBeforeIndex(tNode) {
|
|
13972
|
+
const index = tNode.insertBeforeIndex;
|
|
13973
|
+
return Array.isArray(index) ? index[0] : index;
|
|
13974
|
+
}
|
|
13975
|
+
function setInsertBeforeIndex(tNode, value) {
|
|
13976
|
+
const index = tNode.insertBeforeIndex;
|
|
13977
|
+
if (Array.isArray(index)) {
|
|
13978
|
+
// Array is stored if we have to insert child nodes. See `TNode.insertBeforeIndex`
|
|
13979
|
+
index[0] = value;
|
|
13980
|
+
}
|
|
13981
|
+
else {
|
|
13982
|
+
setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
|
|
13983
|
+
tNode.insertBeforeIndex = value;
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
|
|
13867
13987
|
/**
|
|
13868
|
-
*
|
|
13869
|
-
*
|
|
13870
|
-
*
|
|
13988
|
+
* Retrieve `TIcu` at a given `index`.
|
|
13989
|
+
*
|
|
13990
|
+
* The `TIcu` can be stored either directly (if it is nested ICU) OR
|
|
13991
|
+
* it is stored inside tho `TIcuContainer` if it is top level ICU.
|
|
13992
|
+
*
|
|
13993
|
+
* The reason for this is that the top level ICU need a `TNode` so that they are part of the render
|
|
13994
|
+
* tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
|
|
13995
|
+
* expressed (parent ICU may have selected a case which does not contain it.)
|
|
13996
|
+
*
|
|
13997
|
+
* @param tView Current `TView`.
|
|
13998
|
+
* @param index Index where the value should be read from.
|
|
13871
13999
|
*/
|
|
13872
|
-
function
|
|
13873
|
-
const
|
|
13874
|
-
if (
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
lView[HYDRATION].i18nNodes = undefined;
|
|
14000
|
+
function getTIcu(tView, index) {
|
|
14001
|
+
const value = tView.data[index];
|
|
14002
|
+
if (value === null || typeof value === 'string')
|
|
14003
|
+
return null;
|
|
14004
|
+
if (ngDevMode &&
|
|
14005
|
+
!(value.hasOwnProperty('tView') || value.hasOwnProperty('currentCaseLViewIndex'))) {
|
|
14006
|
+
throwError('We expect to get \'null\'|\'TIcu\'|\'TIcuContainer\', but got: ' + value);
|
|
13880
14007
|
}
|
|
14008
|
+
// Here the `value.hasOwnProperty('currentCaseLViewIndex')` is a polymorphic read as it can be
|
|
14009
|
+
// either TIcu or TIcuContainerNode. This is not ideal, but we still think it is OK because it
|
|
14010
|
+
// will be just two cases which fits into the browser inline cache (inline cache can take up to
|
|
14011
|
+
// 4)
|
|
14012
|
+
const tIcu = value.hasOwnProperty('currentCaseLViewIndex') ? value :
|
|
14013
|
+
value.value;
|
|
14014
|
+
ngDevMode && assertTIcu(tIcu);
|
|
14015
|
+
return tIcu;
|
|
13881
14016
|
}
|
|
13882
14017
|
/**
|
|
13883
|
-
*
|
|
13884
|
-
*
|
|
14018
|
+
* Store `TIcu` at a give `index`.
|
|
14019
|
+
*
|
|
14020
|
+
* The `TIcu` can be stored either directly (if it is nested ICU) OR
|
|
14021
|
+
* it is stored inside tho `TIcuContainer` if it is top level ICU.
|
|
14022
|
+
*
|
|
14023
|
+
* The reason for this is that the top level ICU need a `TNode` so that they are part of the render
|
|
14024
|
+
* tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
|
|
14025
|
+
* expressed (parent ICU may have selected a case which does not contain it.)
|
|
14026
|
+
*
|
|
14027
|
+
* @param tView Current `TView`.
|
|
14028
|
+
* @param index Index where the value should be stored at in `Tview.data`
|
|
14029
|
+
* @param tIcu The TIcu to store.
|
|
13885
14030
|
*/
|
|
13886
|
-
function
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
cleanupLView(lView[i]);
|
|
13897
|
-
}
|
|
14031
|
+
function setTIcu(tView, index, tIcu) {
|
|
14032
|
+
const tNode = tView.data[index];
|
|
14033
|
+
ngDevMode &&
|
|
14034
|
+
assertEqual(tNode === null || tNode.hasOwnProperty('tView'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
|
|
14035
|
+
if (tNode === null) {
|
|
14036
|
+
tView.data[index] = tIcu;
|
|
14037
|
+
}
|
|
14038
|
+
else {
|
|
14039
|
+
ngDevMode && assertTNodeType(tNode, 32 /* TNodeType.Icu */);
|
|
14040
|
+
tNode.value = tIcu;
|
|
13898
14041
|
}
|
|
13899
14042
|
}
|
|
13900
14043
|
/**
|
|
13901
|
-
*
|
|
13902
|
-
*
|
|
14044
|
+
* Set `TNode.insertBeforeIndex` taking the `Array` into account.
|
|
14045
|
+
*
|
|
14046
|
+
* See `TNode.insertBeforeIndex`
|
|
13903
14047
|
*/
|
|
13904
|
-
function
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
if (isLView(lNode)) {
|
|
13912
|
-
cleanupLView(lNode);
|
|
13913
|
-
}
|
|
13914
|
-
else {
|
|
13915
|
-
// Cleanup in the root component view
|
|
13916
|
-
const componentLView = lNode[HOST];
|
|
13917
|
-
cleanupLView(componentLView);
|
|
13918
|
-
// Cleanup in all views within this view container
|
|
13919
|
-
cleanupLContainer(lNode);
|
|
13920
|
-
}
|
|
13921
|
-
ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
|
|
13922
|
-
}
|
|
14048
|
+
function setTNodeInsertBeforeIndex(tNode, index) {
|
|
14049
|
+
ngDevMode && assertTNode(tNode);
|
|
14050
|
+
let insertBeforeIndex = tNode.insertBeforeIndex;
|
|
14051
|
+
if (insertBeforeIndex === null) {
|
|
14052
|
+
setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
|
|
14053
|
+
insertBeforeIndex = tNode.insertBeforeIndex =
|
|
14054
|
+
[null /* may be updated to number later */, index];
|
|
13923
14055
|
}
|
|
14056
|
+
else {
|
|
14057
|
+
assertEqual(Array.isArray(insertBeforeIndex), true, 'Expecting array here');
|
|
14058
|
+
insertBeforeIndex.push(index);
|
|
14059
|
+
}
|
|
14060
|
+
}
|
|
14061
|
+
/**
|
|
14062
|
+
* Create `TNode.type=TNodeType.Placeholder` node.
|
|
14063
|
+
*
|
|
14064
|
+
* See `TNodeType.Placeholder` for more information.
|
|
14065
|
+
*/
|
|
14066
|
+
function createTNodePlaceholder(tView, previousTNodes, index) {
|
|
14067
|
+
const tNode = createTNodeAtIndex(tView, index, 64 /* TNodeType.Placeholder */, null, null);
|
|
14068
|
+
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tNode);
|
|
14069
|
+
return tNode;
|
|
14070
|
+
}
|
|
14071
|
+
/**
|
|
14072
|
+
* Returns current ICU case.
|
|
14073
|
+
*
|
|
14074
|
+
* ICU cases are stored as index into the `TIcu.cases`.
|
|
14075
|
+
* At times it is necessary to communicate that the ICU case just switched and that next ICU update
|
|
14076
|
+
* should update all bindings regardless of the mask. In such a case the we store negative numbers
|
|
14077
|
+
* for cases which have just been switched. This function removes the negative flag.
|
|
14078
|
+
*/
|
|
14079
|
+
function getCurrentICUCaseIndex(tIcu, lView) {
|
|
14080
|
+
const currentCase = lView[tIcu.currentCaseLViewIndex];
|
|
14081
|
+
return currentCase === null ? currentCase : (currentCase < 0 ? ~currentCase : currentCase);
|
|
14082
|
+
}
|
|
14083
|
+
function getParentFromIcuCreateOpCode(mergedCode) {
|
|
14084
|
+
return mergedCode >>> 17 /* IcuCreateOpCode.SHIFT_PARENT */;
|
|
14085
|
+
}
|
|
14086
|
+
function getRefFromIcuCreateOpCode(mergedCode) {
|
|
14087
|
+
return (mergedCode & 131070 /* IcuCreateOpCode.MASK_REF */) >>> 1 /* IcuCreateOpCode.SHIFT_REF */;
|
|
14088
|
+
}
|
|
14089
|
+
function getInstructionFromIcuCreateOpCode(mergedCode) {
|
|
14090
|
+
return mergedCode & 1 /* IcuCreateOpCode.MASK_INSTRUCTION */;
|
|
14091
|
+
}
|
|
14092
|
+
function icuCreateOpCode(opCode, parentIdx, refIdx) {
|
|
14093
|
+
ngDevMode && assertGreaterThanOrEqual(parentIdx, 0, 'Missing parent index');
|
|
14094
|
+
ngDevMode && assertGreaterThan(refIdx, 0, 'Missing ref index');
|
|
14095
|
+
return opCode | parentIdx << 17 /* IcuCreateOpCode.SHIFT_PARENT */ | refIdx << 1 /* IcuCreateOpCode.SHIFT_REF */;
|
|
14096
|
+
}
|
|
14097
|
+
// Returns whether the given value corresponds to a root template message,
|
|
14098
|
+
// or a sub-template.
|
|
14099
|
+
function isRootTemplateMessage(subTemplateIndex) {
|
|
14100
|
+
return subTemplateIndex === -1;
|
|
13924
14101
|
}
|
|
13925
14102
|
|
|
13926
14103
|
/**
|
|
@@ -14013,13 +14190,22 @@ function isDisconnectedNode(tNode, lView) {
|
|
|
14013
14190
|
function locateI18nRNodeByIndex(hydrationInfo, noOffsetIndex) {
|
|
14014
14191
|
const i18nNodes = hydrationInfo.i18nNodes;
|
|
14015
14192
|
if (i18nNodes) {
|
|
14016
|
-
|
|
14017
|
-
if (native) {
|
|
14018
|
-
i18nNodes.delete(noOffsetIndex);
|
|
14019
|
-
}
|
|
14020
|
-
return native;
|
|
14193
|
+
return i18nNodes.get(noOffsetIndex);
|
|
14021
14194
|
}
|
|
14022
|
-
return
|
|
14195
|
+
return undefined;
|
|
14196
|
+
}
|
|
14197
|
+
/**
|
|
14198
|
+
* Attempt to locate an RNode by a path, if it exists.
|
|
14199
|
+
*
|
|
14200
|
+
* @param hydrationInfo The hydration annotation data
|
|
14201
|
+
* @param lView the current lView
|
|
14202
|
+
* @param noOffsetIndex the instruction index
|
|
14203
|
+
* @returns an RNode that corresponds to the instruction index or null if no path exists
|
|
14204
|
+
*/
|
|
14205
|
+
function tryLocateRNodeByPath(hydrationInfo, lView, noOffsetIndex) {
|
|
14206
|
+
const nodes = hydrationInfo.data[NODES];
|
|
14207
|
+
const path = nodes?.[noOffsetIndex];
|
|
14208
|
+
return path ? locateRNodeByPath(path, lView) : null;
|
|
14023
14209
|
}
|
|
14024
14210
|
/**
|
|
14025
14211
|
* Locate a node in DOM tree that corresponds to a given TNode.
|
|
@@ -14033,7 +14219,7 @@ function locateI18nRNodeByIndex(hydrationInfo, noOffsetIndex) {
|
|
|
14033
14219
|
function locateNextRNode(hydrationInfo, tView, lView, tNode) {
|
|
14034
14220
|
const noOffsetIndex = getNoOffsetIndex(tNode);
|
|
14035
14221
|
let native = locateI18nRNodeByIndex(hydrationInfo, noOffsetIndex);
|
|
14036
|
-
if (
|
|
14222
|
+
if (native === undefined) {
|
|
14037
14223
|
const nodes = hydrationInfo.data[NODES];
|
|
14038
14224
|
if (nodes?.[noOffsetIndex]) {
|
|
14039
14225
|
// We know the exact location of the node.
|
|
@@ -14223,7 +14409,7 @@ function calcPathBetween(from, to, fromNodeName) {
|
|
|
14223
14409
|
* Invoked at serialization time (on the server) when a set of navigation
|
|
14224
14410
|
* instructions needs to be generated for a TNode.
|
|
14225
14411
|
*/
|
|
14226
|
-
function calcPathForNode(tNode, lView) {
|
|
14412
|
+
function calcPathForNode(tNode, lView, excludedParentNodes) {
|
|
14227
14413
|
let parentTNode = tNode.parent;
|
|
14228
14414
|
let parentIndex;
|
|
14229
14415
|
let parentRNode;
|
|
@@ -14235,7 +14421,12 @@ function calcPathForNode(tNode, lView) {
|
|
|
14235
14421
|
// a content of an element is projected and used, when a parent element
|
|
14236
14422
|
// itself remains detached from DOM. In this scenario we try to find a parent
|
|
14237
14423
|
// element that is attached to DOM and can act as an anchor instead.
|
|
14238
|
-
|
|
14424
|
+
//
|
|
14425
|
+
// It can also happen that the parent node should be excluded, for example,
|
|
14426
|
+
// because it belongs to an i18n block, which requires paths which aren't
|
|
14427
|
+
// relative to other views in an i18n block.
|
|
14428
|
+
while (parentTNode !== null &&
|
|
14429
|
+
(isDisconnectedNode(parentTNode, lView) || (excludedParentNodes?.has(parentTNode.index)))) {
|
|
14239
14430
|
parentTNode = parentTNode.parent;
|
|
14240
14431
|
}
|
|
14241
14432
|
if (parentTNode === null || !(parentTNode.type & 3 /* TNodeType.AnyRNode */)) {
|
|
@@ -14286,6 +14477,457 @@ function calcPathForNode(tNode, lView) {
|
|
|
14286
14477
|
return path;
|
|
14287
14478
|
}
|
|
14288
14479
|
|
|
14480
|
+
let _isI18nHydrationSupportEnabled = false;
|
|
14481
|
+
let _prepareI18nBlockForHydrationImpl = () => {
|
|
14482
|
+
// noop unless `enablePrepareI18nBlockForHydrationImpl` is invoked.
|
|
14483
|
+
};
|
|
14484
|
+
function setIsI18nHydrationSupportEnabled(enabled) {
|
|
14485
|
+
_isI18nHydrationSupportEnabled = enabled;
|
|
14486
|
+
}
|
|
14487
|
+
function isI18nHydrationSupportEnabled() {
|
|
14488
|
+
return _isI18nHydrationSupportEnabled;
|
|
14489
|
+
}
|
|
14490
|
+
/**
|
|
14491
|
+
* Prepares an i18n block and its children, located at the given
|
|
14492
|
+
* view and instruction index, for hydration.
|
|
14493
|
+
*
|
|
14494
|
+
* @param lView lView with the i18n block
|
|
14495
|
+
* @param index index of the i18n block in the lView
|
|
14496
|
+
* @param parentTNode TNode of the parent of the i18n block
|
|
14497
|
+
* @param subTemplateIndex sub-template index, or -1 for the main template
|
|
14498
|
+
*/
|
|
14499
|
+
function prepareI18nBlockForHydration(lView, index, parentTNode, subTemplateIndex) {
|
|
14500
|
+
_prepareI18nBlockForHydrationImpl(lView, index, parentTNode, subTemplateIndex);
|
|
14501
|
+
}
|
|
14502
|
+
function enablePrepareI18nBlockForHydrationImpl() {
|
|
14503
|
+
_prepareI18nBlockForHydrationImpl = prepareI18nBlockForHydrationImpl;
|
|
14504
|
+
}
|
|
14505
|
+
function isI18nHydrationEnabled(injector) {
|
|
14506
|
+
injector = injector ?? inject(Injector);
|
|
14507
|
+
return injector.get(IS_I18N_HYDRATION_ENABLED, false);
|
|
14508
|
+
}
|
|
14509
|
+
/**
|
|
14510
|
+
* Collects, if not already cached, all of the indices in the
|
|
14511
|
+
* given TView which are children of an i18n block.
|
|
14512
|
+
*
|
|
14513
|
+
* Since i18n blocks don't introduce a parent TNode, this is necessary
|
|
14514
|
+
* in order to determine which indices in a LView are translated.
|
|
14515
|
+
*/
|
|
14516
|
+
function getOrComputeI18nChildren(tView, context) {
|
|
14517
|
+
let i18nChildren = context.i18nChildren.get(tView);
|
|
14518
|
+
if (i18nChildren === undefined) {
|
|
14519
|
+
i18nChildren = collectI18nChildren(tView);
|
|
14520
|
+
context.i18nChildren.set(tView, i18nChildren);
|
|
14521
|
+
}
|
|
14522
|
+
return i18nChildren;
|
|
14523
|
+
}
|
|
14524
|
+
function collectI18nChildren(tView) {
|
|
14525
|
+
const children = new Set();
|
|
14526
|
+
function collectI18nViews(node) {
|
|
14527
|
+
children.add(node.index);
|
|
14528
|
+
switch (node.kind) {
|
|
14529
|
+
case 1 /* I18nNodeKind.ELEMENT */:
|
|
14530
|
+
case 2 /* I18nNodeKind.PLACEHOLDER */: {
|
|
14531
|
+
for (const childNode of node.children) {
|
|
14532
|
+
collectI18nViews(childNode);
|
|
14533
|
+
}
|
|
14534
|
+
break;
|
|
14535
|
+
}
|
|
14536
|
+
case 3 /* I18nNodeKind.ICU */: {
|
|
14537
|
+
for (const caseNodes of node.cases) {
|
|
14538
|
+
for (const caseNode of caseNodes) {
|
|
14539
|
+
collectI18nViews(caseNode);
|
|
14540
|
+
}
|
|
14541
|
+
}
|
|
14542
|
+
break;
|
|
14543
|
+
}
|
|
14544
|
+
}
|
|
14545
|
+
}
|
|
14546
|
+
// Traverse through the AST of each i18n block in the LView,
|
|
14547
|
+
// and collect every instruction index.
|
|
14548
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
14549
|
+
const tI18n = tView.data[i];
|
|
14550
|
+
if (!tI18n || !tI18n.ast) {
|
|
14551
|
+
continue;
|
|
14552
|
+
}
|
|
14553
|
+
for (const node of tI18n.ast) {
|
|
14554
|
+
collectI18nViews(node);
|
|
14555
|
+
}
|
|
14556
|
+
}
|
|
14557
|
+
return children.size === 0 ? null : children;
|
|
14558
|
+
}
|
|
14559
|
+
/**
|
|
14560
|
+
* Attempts to serialize i18n data for an i18n block, located at
|
|
14561
|
+
* the given view and instruction index.
|
|
14562
|
+
*
|
|
14563
|
+
* @param lView lView with the i18n block
|
|
14564
|
+
* @param index index of the i18n block in the lView
|
|
14565
|
+
* @param context the hydration context
|
|
14566
|
+
* @returns the i18n data, or null if there is no relevant data
|
|
14567
|
+
*/
|
|
14568
|
+
function trySerializeI18nBlock(lView, index, context) {
|
|
14569
|
+
if (!context.isI18nHydrationEnabled) {
|
|
14570
|
+
return null;
|
|
14571
|
+
}
|
|
14572
|
+
const tView = lView[TVIEW];
|
|
14573
|
+
const tI18n = tView.data[index];
|
|
14574
|
+
if (!tI18n || !tI18n.ast) {
|
|
14575
|
+
return null;
|
|
14576
|
+
}
|
|
14577
|
+
const caseQueue = [];
|
|
14578
|
+
tI18n.ast.forEach(node => serializeI18nBlock(lView, caseQueue, context, node));
|
|
14579
|
+
return caseQueue.length > 0 ? caseQueue : null;
|
|
14580
|
+
}
|
|
14581
|
+
function serializeI18nBlock(lView, caseQueue, context, node) {
|
|
14582
|
+
switch (node.kind) {
|
|
14583
|
+
case 0 /* I18nNodeKind.TEXT */:
|
|
14584
|
+
const rNode = unwrapRNode(lView[node.index]);
|
|
14585
|
+
processTextNodeBeforeSerialization(context, rNode);
|
|
14586
|
+
break;
|
|
14587
|
+
case 1 /* I18nNodeKind.ELEMENT */:
|
|
14588
|
+
case 2 /* I18nNodeKind.PLACEHOLDER */:
|
|
14589
|
+
node.children.forEach(node => serializeI18nBlock(lView, caseQueue, context, node));
|
|
14590
|
+
break;
|
|
14591
|
+
case 3 /* I18nNodeKind.ICU */:
|
|
14592
|
+
const currentCase = lView[node.currentCaseLViewIndex];
|
|
14593
|
+
if (currentCase != null) {
|
|
14594
|
+
// i18n uses a negative value to signal a change to a new case, so we
|
|
14595
|
+
// need to invert it to get the proper value.
|
|
14596
|
+
const caseIdx = currentCase < 0 ? ~currentCase : currentCase;
|
|
14597
|
+
caseQueue.push(caseIdx);
|
|
14598
|
+
node.cases[caseIdx].forEach(node => serializeI18nBlock(lView, caseQueue, context, node));
|
|
14599
|
+
}
|
|
14600
|
+
break;
|
|
14601
|
+
}
|
|
14602
|
+
}
|
|
14603
|
+
function setCurrentNode(state, node) {
|
|
14604
|
+
state.currentNode = node;
|
|
14605
|
+
}
|
|
14606
|
+
/**
|
|
14607
|
+
* Marks the current RNode as the hydration root for the given
|
|
14608
|
+
* AST node.
|
|
14609
|
+
*/
|
|
14610
|
+
function appendI18nNodeToCollection(context, state, astNode) {
|
|
14611
|
+
const noOffsetIndex = astNode.index - HEADER_OFFSET;
|
|
14612
|
+
const { disconnectedNodes } = context;
|
|
14613
|
+
const currentNode = state.currentNode;
|
|
14614
|
+
if (state.isConnected) {
|
|
14615
|
+
context.i18nNodes.set(noOffsetIndex, currentNode);
|
|
14616
|
+
// We expect the node to be connected, so ensure that it
|
|
14617
|
+
// is not in the set, regardless of whether we found it,
|
|
14618
|
+
// so that the downstream error handling can provide the
|
|
14619
|
+
// proper context.
|
|
14620
|
+
disconnectedNodes.delete(noOffsetIndex);
|
|
14621
|
+
}
|
|
14622
|
+
else {
|
|
14623
|
+
disconnectedNodes.add(noOffsetIndex);
|
|
14624
|
+
}
|
|
14625
|
+
return currentNode;
|
|
14626
|
+
}
|
|
14627
|
+
/**
|
|
14628
|
+
* Skip over some sibling nodes during hydration.
|
|
14629
|
+
*
|
|
14630
|
+
* Note: we use this instead of `siblingAfter` as it's expected that
|
|
14631
|
+
* sometimes we might encounter null nodes. In those cases, we want to
|
|
14632
|
+
* defer to downstream error handling to provide proper context.
|
|
14633
|
+
*/
|
|
14634
|
+
function skipSiblingNodes(state, skip) {
|
|
14635
|
+
let currentNode = state.currentNode;
|
|
14636
|
+
for (let i = 0; i < skip; i++) {
|
|
14637
|
+
if (!currentNode) {
|
|
14638
|
+
break;
|
|
14639
|
+
}
|
|
14640
|
+
currentNode = currentNode?.nextSibling ?? null;
|
|
14641
|
+
}
|
|
14642
|
+
return currentNode;
|
|
14643
|
+
}
|
|
14644
|
+
/**
|
|
14645
|
+
* Fork the given state into a new state for hydrating children.
|
|
14646
|
+
*/
|
|
14647
|
+
function forkHydrationState(state, nextNode) {
|
|
14648
|
+
return { currentNode: nextNode, isConnected: state.isConnected };
|
|
14649
|
+
}
|
|
14650
|
+
function prepareI18nBlockForHydrationImpl(lView, index, parentTNode, subTemplateIndex) {
|
|
14651
|
+
if (!isI18nHydrationSupportEnabled()) {
|
|
14652
|
+
return;
|
|
14653
|
+
}
|
|
14654
|
+
const hydrationInfo = lView[HYDRATION];
|
|
14655
|
+
if (!hydrationInfo) {
|
|
14656
|
+
return;
|
|
14657
|
+
}
|
|
14658
|
+
const tView = lView[TVIEW];
|
|
14659
|
+
const tI18n = tView.data[index];
|
|
14660
|
+
ngDevMode &&
|
|
14661
|
+
assertDefined(tI18n, 'Expected i18n data to be present in a given TView slot during hydration');
|
|
14662
|
+
function findHydrationRoot() {
|
|
14663
|
+
if (isRootTemplateMessage(subTemplateIndex)) {
|
|
14664
|
+
// This is the root of an i18n block. In this case, our hydration root will
|
|
14665
|
+
// depend on where our parent TNode (i.e. the block with i18n applied) is
|
|
14666
|
+
// in the DOM.
|
|
14667
|
+
ngDevMode && assertDefined(parentTNode, 'Expected parent TNode while hydrating i18n root');
|
|
14668
|
+
const rootNode = locateNextRNode(hydrationInfo, tView, lView, parentTNode);
|
|
14669
|
+
// If this i18n block is attached to an <ng-container>, then we want to begin
|
|
14670
|
+
// hydrating directly with the RNode. Otherwise, for a TNode with a physical DOM
|
|
14671
|
+
// element, we want to recurse into the first child and begin there.
|
|
14672
|
+
return (parentTNode.type & 8 /* TNodeType.ElementContainer */) ? rootNode : rootNode.firstChild;
|
|
14673
|
+
}
|
|
14674
|
+
// This is a nested template in an i18n block. In this case, the entire view
|
|
14675
|
+
// is translated, and part of a dehydrated view in a container. This means that
|
|
14676
|
+
// we can simply begin hydration with the first dehydrated child.
|
|
14677
|
+
return hydrationInfo?.firstChild;
|
|
14678
|
+
}
|
|
14679
|
+
const currentNode = findHydrationRoot();
|
|
14680
|
+
ngDevMode && assertDefined(currentNode, 'Expected root i18n node during hydration');
|
|
14681
|
+
const disconnectedNodes = initDisconnectedNodes(hydrationInfo) ?? new Set();
|
|
14682
|
+
const i18nNodes = hydrationInfo.i18nNodes ??= new Map();
|
|
14683
|
+
const caseQueue = hydrationInfo.data[I18N_DATA]?.[index - HEADER_OFFSET] ?? [];
|
|
14684
|
+
const dehydratedIcuData = hydrationInfo.dehydratedIcuData ??=
|
|
14685
|
+
new Map();
|
|
14686
|
+
collectI18nNodesFromDom({ hydrationInfo, lView, i18nNodes, disconnectedNodes, caseQueue, dehydratedIcuData }, { currentNode, isConnected: true }, tI18n.ast);
|
|
14687
|
+
// Nodes from inactive ICU cases should be considered disconnected. We track them above
|
|
14688
|
+
// because they aren't (and shouldn't be) serialized. Since we may mutate or create a
|
|
14689
|
+
// new set, we need to be sure to write the expected value back to the DehydratedView.
|
|
14690
|
+
hydrationInfo.disconnectedNodes = disconnectedNodes.size === 0 ? null : disconnectedNodes;
|
|
14691
|
+
}
|
|
14692
|
+
function collectI18nNodesFromDom(context, state, nodeOrNodes) {
|
|
14693
|
+
if (Array.isArray(nodeOrNodes)) {
|
|
14694
|
+
for (const node of nodeOrNodes) {
|
|
14695
|
+
// If the node is being projected elsewhere, we need to temporarily
|
|
14696
|
+
// branch the state to that location to continue hydration.
|
|
14697
|
+
// Otherwise, we continue hydration from the current location.
|
|
14698
|
+
const targetNode = tryLocateRNodeByPath(context.hydrationInfo, context.lView, node.index - HEADER_OFFSET);
|
|
14699
|
+
const nextState = targetNode ? forkHydrationState(state, targetNode) : state;
|
|
14700
|
+
collectI18nNodesFromDom(context, nextState, node);
|
|
14701
|
+
}
|
|
14702
|
+
}
|
|
14703
|
+
else {
|
|
14704
|
+
switch (nodeOrNodes.kind) {
|
|
14705
|
+
case 0 /* I18nNodeKind.TEXT */: {
|
|
14706
|
+
// Claim a text node for hydration
|
|
14707
|
+
const currentNode = appendI18nNodeToCollection(context, state, nodeOrNodes);
|
|
14708
|
+
setCurrentNode(state, currentNode?.nextSibling ?? null);
|
|
14709
|
+
break;
|
|
14710
|
+
}
|
|
14711
|
+
case 1 /* I18nNodeKind.ELEMENT */: {
|
|
14712
|
+
// Recurse into the current element's children...
|
|
14713
|
+
collectI18nNodesFromDom(context, forkHydrationState(state, state.currentNode?.firstChild ?? null), nodeOrNodes.children);
|
|
14714
|
+
// And claim the parent element itself.
|
|
14715
|
+
const currentNode = appendI18nNodeToCollection(context, state, nodeOrNodes);
|
|
14716
|
+
setCurrentNode(state, currentNode?.nextSibling ?? null);
|
|
14717
|
+
break;
|
|
14718
|
+
}
|
|
14719
|
+
case 2 /* I18nNodeKind.PLACEHOLDER */: {
|
|
14720
|
+
const noOffsetIndex = nodeOrNodes.index - HEADER_OFFSET;
|
|
14721
|
+
const { hydrationInfo } = context;
|
|
14722
|
+
const containerSize = getNgContainerSize(hydrationInfo, noOffsetIndex);
|
|
14723
|
+
switch (nodeOrNodes.type) {
|
|
14724
|
+
case 0 /* I18nPlaceholderType.ELEMENT */: {
|
|
14725
|
+
// Hydration expects to find the head of the element.
|
|
14726
|
+
const currentNode = appendI18nNodeToCollection(context, state, nodeOrNodes);
|
|
14727
|
+
// A TNode for the node may not yet if we're hydrating during the first pass,
|
|
14728
|
+
// so use the serialized data to determine if this is an <ng-container>.
|
|
14729
|
+
if (isSerializedElementContainer(hydrationInfo, noOffsetIndex)) {
|
|
14730
|
+
// An <ng-container> doesn't have a physical DOM node, so we need to
|
|
14731
|
+
// continue hydrating from siblings.
|
|
14732
|
+
collectI18nNodesFromDom(context, state, nodeOrNodes.children);
|
|
14733
|
+
// Skip over the anchor element. It will be claimed by the
|
|
14734
|
+
// downstream container hydration.
|
|
14735
|
+
const nextNode = skipSiblingNodes(state, 1);
|
|
14736
|
+
setCurrentNode(state, nextNode);
|
|
14737
|
+
}
|
|
14738
|
+
else {
|
|
14739
|
+
// Non-container elements represent an actual node in the DOM, so we
|
|
14740
|
+
// need to continue hydration with the children, and claim the node.
|
|
14741
|
+
collectI18nNodesFromDom(context, forkHydrationState(state, state.currentNode?.firstChild ?? null), nodeOrNodes.children);
|
|
14742
|
+
setCurrentNode(state, currentNode?.nextSibling ?? null);
|
|
14743
|
+
// Elements can also be the anchor of a view container, so there may
|
|
14744
|
+
// be elements after this node that we need to skip.
|
|
14745
|
+
if (containerSize !== null) {
|
|
14746
|
+
// `+1` stands for an anchor node after all of the views in the container.
|
|
14747
|
+
const nextNode = skipSiblingNodes(state, containerSize + 1);
|
|
14748
|
+
setCurrentNode(state, nextNode);
|
|
14749
|
+
}
|
|
14750
|
+
}
|
|
14751
|
+
break;
|
|
14752
|
+
}
|
|
14753
|
+
case 1 /* I18nPlaceholderType.SUBTEMPLATE */: {
|
|
14754
|
+
ngDevMode &&
|
|
14755
|
+
assertNotEqual(containerSize, null, 'Expected a container size while hydrating i18n subtemplate');
|
|
14756
|
+
// Hydration expects to find the head of the template.
|
|
14757
|
+
appendI18nNodeToCollection(context, state, nodeOrNodes);
|
|
14758
|
+
// Skip over all of the template children, as well as the anchor
|
|
14759
|
+
// node, since the template itself will handle them instead.
|
|
14760
|
+
const nextNode = skipSiblingNodes(state, containerSize + 1);
|
|
14761
|
+
setCurrentNode(state, nextNode);
|
|
14762
|
+
break;
|
|
14763
|
+
}
|
|
14764
|
+
}
|
|
14765
|
+
break;
|
|
14766
|
+
}
|
|
14767
|
+
case 3 /* I18nNodeKind.ICU */: {
|
|
14768
|
+
// If the current node is connected, we need to pop the next case from the
|
|
14769
|
+
// queue, so that the active case is also considered connected.
|
|
14770
|
+
const selectedCase = state.isConnected ? context.caseQueue.shift() : null;
|
|
14771
|
+
const childState = { currentNode: null, isConnected: false };
|
|
14772
|
+
// We traverse through each case, even if it's not active,
|
|
14773
|
+
// so that we correctly populate disconnected nodes.
|
|
14774
|
+
for (let i = 0; i < nodeOrNodes.cases.length; i++) {
|
|
14775
|
+
collectI18nNodesFromDom(context, i === selectedCase ? state : childState, nodeOrNodes.cases[i]);
|
|
14776
|
+
}
|
|
14777
|
+
if (selectedCase !== null) {
|
|
14778
|
+
// ICUs represent a branching state, and the selected case could be different
|
|
14779
|
+
// than what it was on the server. In that case, we need to be able to clean
|
|
14780
|
+
// up the nodes from the original case. To do that, we store the selected case.
|
|
14781
|
+
context.dehydratedIcuData.set(nodeOrNodes.index, { case: selectedCase, node: nodeOrNodes });
|
|
14782
|
+
}
|
|
14783
|
+
// Hydration expects to find the ICU anchor element.
|
|
14784
|
+
const currentNode = appendI18nNodeToCollection(context, state, nodeOrNodes);
|
|
14785
|
+
setCurrentNode(state, currentNode?.nextSibling ?? null);
|
|
14786
|
+
break;
|
|
14787
|
+
}
|
|
14788
|
+
}
|
|
14789
|
+
}
|
|
14790
|
+
}
|
|
14791
|
+
let _claimDehydratedIcuCaseImpl = () => {
|
|
14792
|
+
// noop unless `enableClaimDehydratedIcuCaseImpl` is invoked
|
|
14793
|
+
};
|
|
14794
|
+
/**
|
|
14795
|
+
* Mark the case for the ICU node at the given index in the view as claimed,
|
|
14796
|
+
* allowing its nodes to be hydrated and not cleaned up.
|
|
14797
|
+
*/
|
|
14798
|
+
function claimDehydratedIcuCase(lView, icuIndex, caseIndex) {
|
|
14799
|
+
_claimDehydratedIcuCaseImpl(lView, icuIndex, caseIndex);
|
|
14800
|
+
}
|
|
14801
|
+
function enableClaimDehydratedIcuCaseImpl() {
|
|
14802
|
+
_claimDehydratedIcuCaseImpl = claimDehydratedIcuCaseImpl;
|
|
14803
|
+
}
|
|
14804
|
+
function claimDehydratedIcuCaseImpl(lView, icuIndex, caseIndex) {
|
|
14805
|
+
const dehydratedIcuDataMap = lView[HYDRATION]?.dehydratedIcuData;
|
|
14806
|
+
if (dehydratedIcuDataMap) {
|
|
14807
|
+
const dehydratedIcuData = dehydratedIcuDataMap.get(icuIndex);
|
|
14808
|
+
if (dehydratedIcuData?.case === caseIndex) {
|
|
14809
|
+
// If the case we're attempting to claim matches the dehydrated one,
|
|
14810
|
+
// we remove it from the map to mark it as "claimed."
|
|
14811
|
+
dehydratedIcuDataMap.delete(icuIndex);
|
|
14812
|
+
}
|
|
14813
|
+
}
|
|
14814
|
+
}
|
|
14815
|
+
/**
|
|
14816
|
+
* Clean up all i18n hydration data associated with the given view.
|
|
14817
|
+
*/
|
|
14818
|
+
function cleanupI18nHydrationData(lView) {
|
|
14819
|
+
const hydrationInfo = lView[HYDRATION];
|
|
14820
|
+
if (hydrationInfo) {
|
|
14821
|
+
const { i18nNodes, dehydratedIcuData: dehydratedIcuDataMap } = hydrationInfo;
|
|
14822
|
+
if (i18nNodes && dehydratedIcuDataMap) {
|
|
14823
|
+
const renderer = lView[RENDERER];
|
|
14824
|
+
for (const dehydratedIcuData of dehydratedIcuDataMap.values()) {
|
|
14825
|
+
cleanupDehydratedIcuData(renderer, i18nNodes, dehydratedIcuData);
|
|
14826
|
+
}
|
|
14827
|
+
}
|
|
14828
|
+
hydrationInfo.i18nNodes = undefined;
|
|
14829
|
+
hydrationInfo.dehydratedIcuData = undefined;
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
function cleanupDehydratedIcuData(renderer, i18nNodes, dehydratedIcuData) {
|
|
14833
|
+
for (const node of dehydratedIcuData.node.cases[dehydratedIcuData.case]) {
|
|
14834
|
+
const rNode = i18nNodes.get(node.index - HEADER_OFFSET);
|
|
14835
|
+
if (rNode) {
|
|
14836
|
+
nativeRemoveNode(renderer, rNode, false);
|
|
14837
|
+
}
|
|
14838
|
+
}
|
|
14839
|
+
}
|
|
14840
|
+
|
|
14841
|
+
/**
|
|
14842
|
+
* Removes all dehydrated views from a given LContainer:
|
|
14843
|
+
* both in internal data structure, as well as removing
|
|
14844
|
+
* corresponding DOM nodes that belong to that dehydrated view.
|
|
14845
|
+
*/
|
|
14846
|
+
function removeDehydratedViews(lContainer) {
|
|
14847
|
+
const views = lContainer[DEHYDRATED_VIEWS] ?? [];
|
|
14848
|
+
const parentLView = lContainer[PARENT];
|
|
14849
|
+
const renderer = parentLView[RENDERER];
|
|
14850
|
+
for (const view of views) {
|
|
14851
|
+
removeDehydratedView(view, renderer);
|
|
14852
|
+
ngDevMode && ngDevMode.dehydratedViewsRemoved++;
|
|
14853
|
+
}
|
|
14854
|
+
// Reset the value to an empty array to indicate that no
|
|
14855
|
+
// further processing of dehydrated views is needed for
|
|
14856
|
+
// this view container (i.e. do not trigger the lookup process
|
|
14857
|
+
// once again in case a `ViewContainerRef` is created later).
|
|
14858
|
+
lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
|
|
14859
|
+
}
|
|
14860
|
+
/**
|
|
14861
|
+
* Helper function to remove all nodes from a dehydrated view.
|
|
14862
|
+
*/
|
|
14863
|
+
function removeDehydratedView(dehydratedView, renderer) {
|
|
14864
|
+
let nodesRemoved = 0;
|
|
14865
|
+
let currentRNode = dehydratedView.firstChild;
|
|
14866
|
+
if (currentRNode) {
|
|
14867
|
+
const numNodes = dehydratedView.data[NUM_ROOT_NODES];
|
|
14868
|
+
while (nodesRemoved < numNodes) {
|
|
14869
|
+
ngDevMode && validateSiblingNodeExists(currentRNode);
|
|
14870
|
+
const nextSibling = currentRNode.nextSibling;
|
|
14871
|
+
nativeRemoveNode(renderer, currentRNode, false);
|
|
14872
|
+
currentRNode = nextSibling;
|
|
14873
|
+
nodesRemoved++;
|
|
14874
|
+
}
|
|
14875
|
+
}
|
|
14876
|
+
}
|
|
14877
|
+
/**
|
|
14878
|
+
* Walks over all views within this LContainer invokes dehydrated views
|
|
14879
|
+
* cleanup function for each one.
|
|
14880
|
+
*/
|
|
14881
|
+
function cleanupLContainer(lContainer) {
|
|
14882
|
+
removeDehydratedViews(lContainer);
|
|
14883
|
+
for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
|
|
14884
|
+
cleanupLView(lContainer[i]);
|
|
14885
|
+
}
|
|
14886
|
+
}
|
|
14887
|
+
/**
|
|
14888
|
+
* Walks over `LContainer`s and components registered within
|
|
14889
|
+
* this LView and invokes dehydrated views cleanup function for each one.
|
|
14890
|
+
*/
|
|
14891
|
+
function cleanupLView(lView) {
|
|
14892
|
+
cleanupI18nHydrationData(lView);
|
|
14893
|
+
const tView = lView[TVIEW];
|
|
14894
|
+
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
14895
|
+
if (isLContainer(lView[i])) {
|
|
14896
|
+
const lContainer = lView[i];
|
|
14897
|
+
cleanupLContainer(lContainer);
|
|
14898
|
+
}
|
|
14899
|
+
else if (isLView(lView[i])) {
|
|
14900
|
+
// This is a component, enter the `cleanupLView` recursively.
|
|
14901
|
+
cleanupLView(lView[i]);
|
|
14902
|
+
}
|
|
14903
|
+
}
|
|
14904
|
+
}
|
|
14905
|
+
/**
|
|
14906
|
+
* Walks over all views registered within the ApplicationRef and removes
|
|
14907
|
+
* all dehydrated views from all `LContainer`s along the way.
|
|
14908
|
+
*/
|
|
14909
|
+
function cleanupDehydratedViews(appRef) {
|
|
14910
|
+
const viewRefs = appRef._views;
|
|
14911
|
+
for (const viewRef of viewRefs) {
|
|
14912
|
+
const lNode = getLNodeForHydration(viewRef);
|
|
14913
|
+
// An `lView` might be `null` if a `ViewRef` represents
|
|
14914
|
+
// an embedded view (not a component view).
|
|
14915
|
+
if (lNode !== null && lNode[HOST] !== null) {
|
|
14916
|
+
if (isLView(lNode)) {
|
|
14917
|
+
cleanupLView(lNode);
|
|
14918
|
+
}
|
|
14919
|
+
else {
|
|
14920
|
+
// Cleanup in the root component view
|
|
14921
|
+
const componentLView = lNode[HOST];
|
|
14922
|
+
cleanupLView(componentLView);
|
|
14923
|
+
// Cleanup in all views within this view container
|
|
14924
|
+
cleanupLContainer(lNode);
|
|
14925
|
+
}
|
|
14926
|
+
ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
|
|
14927
|
+
}
|
|
14928
|
+
}
|
|
14929
|
+
}
|
|
14930
|
+
|
|
14289
14931
|
/**
|
|
14290
14932
|
* Given a current DOM node and a serialized information about the views
|
|
14291
14933
|
* in a container, walks over the DOM structure, collecting the list of
|
|
@@ -14562,8 +15204,8 @@ function performanceMarkFeature(feature) {
|
|
|
14562
15204
|
*
|
|
14563
15205
|
* @returns a function to cancel the scheduled callback
|
|
14564
15206
|
*/
|
|
14565
|
-
function
|
|
14566
|
-
// Note: the `
|
|
15207
|
+
function scheduleCallback(callback) {
|
|
15208
|
+
// Note: the `scheduleCallback` is used in the `NgZone` class, but we cannot use the
|
|
14567
15209
|
// `inject` function. The `NgZone` instance may be created manually, and thus the injection
|
|
14568
15210
|
// context will be unavailable. This might be enough to check whether `requestAnimationFrame` is
|
|
14569
15211
|
// available because otherwise, we'll fall back to `setTimeout`.
|
|
@@ -14571,39 +15213,29 @@ function getCallbackScheduler() {
|
|
|
14571
15213
|
let nativeRequestAnimationFrame = hasRequestAnimationFrame ? _global['requestAnimationFrame'] : null;
|
|
14572
15214
|
let nativeSetTimeout = _global['setTimeout'];
|
|
14573
15215
|
if (typeof Zone !== 'undefined') {
|
|
14574
|
-
|
|
14575
|
-
// `__zone_symbol__OriginalDelegate` key (see `attachOriginToPatched`). Given the following
|
|
14576
|
-
// example: `window.requestAnimationFrame.__zone_symbol__OriginalDelegate`; this would return an
|
|
14577
|
-
// unpatched implementation of the `requestAnimationFrame`, which isn't intercepted by the
|
|
14578
|
-
// Angular zone. We use the unpatched implementation to avoid another change detection when
|
|
14579
|
-
// coalescing tasks.
|
|
14580
|
-
const ORIGINAL_DELEGATE_SYMBOL = Zone.__symbol__('OriginalDelegate');
|
|
14581
|
-
if (nativeRequestAnimationFrame) {
|
|
15216
|
+
if (hasRequestAnimationFrame) {
|
|
14582
15217
|
nativeRequestAnimationFrame =
|
|
14583
|
-
|
|
14584
|
-
nativeRequestAnimationFrame;
|
|
15218
|
+
_global[Zone.__symbol__('requestAnimationFrame')] ?? nativeRequestAnimationFrame;
|
|
14585
15219
|
}
|
|
14586
|
-
nativeSetTimeout =
|
|
15220
|
+
nativeSetTimeout = _global[Zone.__symbol__('setTimeout')] ?? nativeSetTimeout;
|
|
14587
15221
|
}
|
|
14588
|
-
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14598
|
-
|
|
14599
|
-
|
|
14600
|
-
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14604
|
-
|
|
14605
|
-
executeCallback = false;
|
|
14606
|
-
};
|
|
15222
|
+
let executeCallback = true;
|
|
15223
|
+
nativeSetTimeout(() => {
|
|
15224
|
+
if (!executeCallback) {
|
|
15225
|
+
return;
|
|
15226
|
+
}
|
|
15227
|
+
executeCallback = false;
|
|
15228
|
+
callback();
|
|
15229
|
+
});
|
|
15230
|
+
nativeRequestAnimationFrame?.(() => {
|
|
15231
|
+
if (!executeCallback) {
|
|
15232
|
+
return;
|
|
15233
|
+
}
|
|
15234
|
+
executeCallback = false;
|
|
15235
|
+
callback();
|
|
15236
|
+
});
|
|
15237
|
+
return () => {
|
|
15238
|
+
executeCallback = false;
|
|
14607
15239
|
};
|
|
14608
15240
|
}
|
|
14609
15241
|
|
|
@@ -14761,7 +15393,7 @@ class NgZone {
|
|
|
14761
15393
|
!shouldCoalesceRunChangeDetection && shouldCoalesceEventChangeDetection;
|
|
14762
15394
|
self.shouldCoalesceRunChangeDetection = shouldCoalesceRunChangeDetection;
|
|
14763
15395
|
self.callbackScheduled = false;
|
|
14764
|
-
self.scheduleCallback =
|
|
15396
|
+
self.scheduleCallback = scheduleCallback;
|
|
14765
15397
|
forkInnerZoneWithAngularBehavior(self);
|
|
14766
15398
|
}
|
|
14767
15399
|
/**
|
|
@@ -16093,7 +16725,7 @@ function createRootComponent(componentView, rootComponentDef, rootDirectives, ho
|
|
|
16093
16725
|
function setRootNodeAttributes(hostRenderer, componentDef, hostRNode, rootSelectorOrNode) {
|
|
16094
16726
|
if (rootSelectorOrNode) {
|
|
16095
16727
|
// The placeholder will be replaced with the actual version at build time.
|
|
16096
|
-
setUpAttributes(hostRenderer, hostRNode, ['ng-version', '18.0.0-next.
|
|
16728
|
+
setUpAttributes(hostRenderer, hostRNode, ['ng-version', '18.0.0-next.3']);
|
|
16097
16729
|
}
|
|
16098
16730
|
else {
|
|
16099
16731
|
// If host element is created as a part of this function call (i.e. `rootSelectorOrNode`
|
|
@@ -16148,7 +16780,7 @@ function LifecycleHooksFeature() {
|
|
|
16148
16780
|
* (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
|
|
16149
16781
|
*
|
|
16150
16782
|
* A view container instance can contain other view containers,
|
|
16151
|
-
* creating a
|
|
16783
|
+
* creating a view hierarchy.
|
|
16152
16784
|
*
|
|
16153
16785
|
* @usageNotes
|
|
16154
16786
|
*
|
|
@@ -23672,242 +24304,6 @@ function getLocaleId() {
|
|
|
23672
24304
|
return LOCALE_ID$1;
|
|
23673
24305
|
}
|
|
23674
24306
|
|
|
23675
|
-
/**
|
|
23676
|
-
* Find a node in front of which `currentTNode` should be inserted (takes i18n into account).
|
|
23677
|
-
*
|
|
23678
|
-
* This method determines the `RNode` in front of which we should insert the `currentRNode`. This
|
|
23679
|
-
* takes `TNode.insertBeforeIndex` into account.
|
|
23680
|
-
*
|
|
23681
|
-
* @param parentTNode parent `TNode`
|
|
23682
|
-
* @param currentTNode current `TNode` (The node which we would like to insert into the DOM)
|
|
23683
|
-
* @param lView current `LView`
|
|
23684
|
-
*/
|
|
23685
|
-
function getInsertInFrontOfRNodeWithI18n(parentTNode, currentTNode, lView) {
|
|
23686
|
-
const tNodeInsertBeforeIndex = currentTNode.insertBeforeIndex;
|
|
23687
|
-
const insertBeforeIndex = Array.isArray(tNodeInsertBeforeIndex) ? tNodeInsertBeforeIndex[0] : tNodeInsertBeforeIndex;
|
|
23688
|
-
if (insertBeforeIndex === null) {
|
|
23689
|
-
return getInsertInFrontOfRNodeWithNoI18n(parentTNode, currentTNode, lView);
|
|
23690
|
-
}
|
|
23691
|
-
else {
|
|
23692
|
-
ngDevMode && assertIndexInRange(lView, insertBeforeIndex);
|
|
23693
|
-
return unwrapRNode(lView[insertBeforeIndex]);
|
|
23694
|
-
}
|
|
23695
|
-
}
|
|
23696
|
-
/**
|
|
23697
|
-
* Process `TNode.insertBeforeIndex` by adding i18n text nodes.
|
|
23698
|
-
*
|
|
23699
|
-
* See `TNode.insertBeforeIndex`
|
|
23700
|
-
*/
|
|
23701
|
-
function processI18nInsertBefore(renderer, childTNode, lView, childRNode, parentRElement) {
|
|
23702
|
-
const tNodeInsertBeforeIndex = childTNode.insertBeforeIndex;
|
|
23703
|
-
if (Array.isArray(tNodeInsertBeforeIndex)) {
|
|
23704
|
-
// An array indicates that there are i18n nodes that need to be added as children of this
|
|
23705
|
-
// `childRNode`. These i18n nodes were created before this `childRNode` was available and so
|
|
23706
|
-
// only now can be added. The first element of the array is the normal index where we should
|
|
23707
|
-
// insert the `childRNode`. Additional elements are the extra nodes to be added as children of
|
|
23708
|
-
// `childRNode`.
|
|
23709
|
-
ngDevMode && assertDomNode(childRNode);
|
|
23710
|
-
let i18nParent = childRNode;
|
|
23711
|
-
let anchorRNode = null;
|
|
23712
|
-
if (!(childTNode.type & 3 /* TNodeType.AnyRNode */)) {
|
|
23713
|
-
anchorRNode = i18nParent;
|
|
23714
|
-
i18nParent = parentRElement;
|
|
23715
|
-
}
|
|
23716
|
-
if (i18nParent !== null && childTNode.componentOffset === -1) {
|
|
23717
|
-
for (let i = 1; i < tNodeInsertBeforeIndex.length; i++) {
|
|
23718
|
-
// No need to `unwrapRNode` because all of the indexes point to i18n text nodes.
|
|
23719
|
-
// see `assertDomNode` below.
|
|
23720
|
-
const i18nChild = lView[tNodeInsertBeforeIndex[i]];
|
|
23721
|
-
nativeInsertBefore(renderer, i18nParent, i18nChild, anchorRNode, false);
|
|
23722
|
-
}
|
|
23723
|
-
}
|
|
23724
|
-
}
|
|
23725
|
-
}
|
|
23726
|
-
|
|
23727
|
-
/**
|
|
23728
|
-
* Add `tNode` to `previousTNodes` list and update relevant `TNode`s in `previousTNodes` list
|
|
23729
|
-
* `tNode.insertBeforeIndex`.
|
|
23730
|
-
*
|
|
23731
|
-
* Things to keep in mind:
|
|
23732
|
-
* 1. All i18n text nodes are encoded as `TNodeType.Element` and are created eagerly by the
|
|
23733
|
-
* `ɵɵi18nStart` instruction.
|
|
23734
|
-
* 2. All `TNodeType.Placeholder` `TNodes` are elements which will be created later by
|
|
23735
|
-
* `ɵɵelementStart` instruction.
|
|
23736
|
-
* 3. `ɵɵelementStart` instruction will create `TNode`s in the ascending `TNode.index` order. (So a
|
|
23737
|
-
* smaller index `TNode` is guaranteed to be created before a larger one)
|
|
23738
|
-
*
|
|
23739
|
-
* We use the above three invariants to determine `TNode.insertBeforeIndex`.
|
|
23740
|
-
*
|
|
23741
|
-
* In an ideal world `TNode.insertBeforeIndex` would always be `TNode.next.index`. However,
|
|
23742
|
-
* this will not work because `TNode.next.index` may be larger than `TNode.index` which means that
|
|
23743
|
-
* the next node is not yet created and therefore we can't insert in front of it.
|
|
23744
|
-
*
|
|
23745
|
-
* Rule1: `TNode.insertBeforeIndex = null` if `TNode.next === null` (Initial condition, as we don't
|
|
23746
|
-
* know if there will be further `TNode`s inserted after.)
|
|
23747
|
-
* Rule2: If `previousTNode` is created after the `tNode` being inserted, then
|
|
23748
|
-
* `previousTNode.insertBeforeNode = tNode.index` (So when a new `tNode` is added we check
|
|
23749
|
-
* previous to see if we can update its `insertBeforeTNode`)
|
|
23750
|
-
*
|
|
23751
|
-
* See `TNode.insertBeforeIndex` for more context.
|
|
23752
|
-
*
|
|
23753
|
-
* @param previousTNodes A list of previous TNodes so that we can easily traverse `TNode`s in
|
|
23754
|
-
* reverse order. (If `TNode` would have `previous` this would not be necessary.)
|
|
23755
|
-
* @param newTNode A TNode to add to the `previousTNodes` list.
|
|
23756
|
-
*/
|
|
23757
|
-
function addTNodeAndUpdateInsertBeforeIndex(previousTNodes, newTNode) {
|
|
23758
|
-
// Start with Rule1
|
|
23759
|
-
ngDevMode &&
|
|
23760
|
-
assertEqual(newTNode.insertBeforeIndex, null, 'We expect that insertBeforeIndex is not set');
|
|
23761
|
-
previousTNodes.push(newTNode);
|
|
23762
|
-
if (previousTNodes.length > 1) {
|
|
23763
|
-
for (let i = previousTNodes.length - 2; i >= 0; i--) {
|
|
23764
|
-
const existingTNode = previousTNodes[i];
|
|
23765
|
-
// Text nodes are created eagerly and so they don't need their `indexBeforeIndex` updated.
|
|
23766
|
-
// It is safe to ignore them.
|
|
23767
|
-
if (!isI18nText(existingTNode)) {
|
|
23768
|
-
if (isNewTNodeCreatedBefore(existingTNode, newTNode) &&
|
|
23769
|
-
getInsertBeforeIndex(existingTNode) === null) {
|
|
23770
|
-
// If it was created before us in time, (and it does not yet have `insertBeforeIndex`)
|
|
23771
|
-
// then add the `insertBeforeIndex`.
|
|
23772
|
-
setInsertBeforeIndex(existingTNode, newTNode.index);
|
|
23773
|
-
}
|
|
23774
|
-
}
|
|
23775
|
-
}
|
|
23776
|
-
}
|
|
23777
|
-
}
|
|
23778
|
-
function isI18nText(tNode) {
|
|
23779
|
-
return !(tNode.type & 64 /* TNodeType.Placeholder */);
|
|
23780
|
-
}
|
|
23781
|
-
function isNewTNodeCreatedBefore(existingTNode, newTNode) {
|
|
23782
|
-
return isI18nText(newTNode) || existingTNode.index > newTNode.index;
|
|
23783
|
-
}
|
|
23784
|
-
function getInsertBeforeIndex(tNode) {
|
|
23785
|
-
const index = tNode.insertBeforeIndex;
|
|
23786
|
-
return Array.isArray(index) ? index[0] : index;
|
|
23787
|
-
}
|
|
23788
|
-
function setInsertBeforeIndex(tNode, value) {
|
|
23789
|
-
const index = tNode.insertBeforeIndex;
|
|
23790
|
-
if (Array.isArray(index)) {
|
|
23791
|
-
// Array is stored if we have to insert child nodes. See `TNode.insertBeforeIndex`
|
|
23792
|
-
index[0] = value;
|
|
23793
|
-
}
|
|
23794
|
-
else {
|
|
23795
|
-
setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
|
|
23796
|
-
tNode.insertBeforeIndex = value;
|
|
23797
|
-
}
|
|
23798
|
-
}
|
|
23799
|
-
|
|
23800
|
-
/**
|
|
23801
|
-
* Retrieve `TIcu` at a given `index`.
|
|
23802
|
-
*
|
|
23803
|
-
* The `TIcu` can be stored either directly (if it is nested ICU) OR
|
|
23804
|
-
* it is stored inside tho `TIcuContainer` if it is top level ICU.
|
|
23805
|
-
*
|
|
23806
|
-
* The reason for this is that the top level ICU need a `TNode` so that they are part of the render
|
|
23807
|
-
* tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
|
|
23808
|
-
* expressed (parent ICU may have selected a case which does not contain it.)
|
|
23809
|
-
*
|
|
23810
|
-
* @param tView Current `TView`.
|
|
23811
|
-
* @param index Index where the value should be read from.
|
|
23812
|
-
*/
|
|
23813
|
-
function getTIcu(tView, index) {
|
|
23814
|
-
const value = tView.data[index];
|
|
23815
|
-
if (value === null || typeof value === 'string')
|
|
23816
|
-
return null;
|
|
23817
|
-
if (ngDevMode &&
|
|
23818
|
-
!(value.hasOwnProperty('tView') || value.hasOwnProperty('currentCaseLViewIndex'))) {
|
|
23819
|
-
throwError('We expect to get \'null\'|\'TIcu\'|\'TIcuContainer\', but got: ' + value);
|
|
23820
|
-
}
|
|
23821
|
-
// Here the `value.hasOwnProperty('currentCaseLViewIndex')` is a polymorphic read as it can be
|
|
23822
|
-
// either TIcu or TIcuContainerNode. This is not ideal, but we still think it is OK because it
|
|
23823
|
-
// will be just two cases which fits into the browser inline cache (inline cache can take up to
|
|
23824
|
-
// 4)
|
|
23825
|
-
const tIcu = value.hasOwnProperty('currentCaseLViewIndex') ? value :
|
|
23826
|
-
value.value;
|
|
23827
|
-
ngDevMode && assertTIcu(tIcu);
|
|
23828
|
-
return tIcu;
|
|
23829
|
-
}
|
|
23830
|
-
/**
|
|
23831
|
-
* Store `TIcu` at a give `index`.
|
|
23832
|
-
*
|
|
23833
|
-
* The `TIcu` can be stored either directly (if it is nested ICU) OR
|
|
23834
|
-
* it is stored inside tho `TIcuContainer` if it is top level ICU.
|
|
23835
|
-
*
|
|
23836
|
-
* The reason for this is that the top level ICU need a `TNode` so that they are part of the render
|
|
23837
|
-
* tree, but nested ICU's have no TNode, because we don't know ahead of time if the nested ICU is
|
|
23838
|
-
* expressed (parent ICU may have selected a case which does not contain it.)
|
|
23839
|
-
*
|
|
23840
|
-
* @param tView Current `TView`.
|
|
23841
|
-
* @param index Index where the value should be stored at in `Tview.data`
|
|
23842
|
-
* @param tIcu The TIcu to store.
|
|
23843
|
-
*/
|
|
23844
|
-
function setTIcu(tView, index, tIcu) {
|
|
23845
|
-
const tNode = tView.data[index];
|
|
23846
|
-
ngDevMode &&
|
|
23847
|
-
assertEqual(tNode === null || tNode.hasOwnProperty('tView'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
|
|
23848
|
-
if (tNode === null) {
|
|
23849
|
-
tView.data[index] = tIcu;
|
|
23850
|
-
}
|
|
23851
|
-
else {
|
|
23852
|
-
ngDevMode && assertTNodeType(tNode, 32 /* TNodeType.Icu */);
|
|
23853
|
-
tNode.value = tIcu;
|
|
23854
|
-
}
|
|
23855
|
-
}
|
|
23856
|
-
/**
|
|
23857
|
-
* Set `TNode.insertBeforeIndex` taking the `Array` into account.
|
|
23858
|
-
*
|
|
23859
|
-
* See `TNode.insertBeforeIndex`
|
|
23860
|
-
*/
|
|
23861
|
-
function setTNodeInsertBeforeIndex(tNode, index) {
|
|
23862
|
-
ngDevMode && assertTNode(tNode);
|
|
23863
|
-
let insertBeforeIndex = tNode.insertBeforeIndex;
|
|
23864
|
-
if (insertBeforeIndex === null) {
|
|
23865
|
-
setI18nHandling(getInsertInFrontOfRNodeWithI18n, processI18nInsertBefore);
|
|
23866
|
-
insertBeforeIndex = tNode.insertBeforeIndex =
|
|
23867
|
-
[null /* may be updated to number later */, index];
|
|
23868
|
-
}
|
|
23869
|
-
else {
|
|
23870
|
-
assertEqual(Array.isArray(insertBeforeIndex), true, 'Expecting array here');
|
|
23871
|
-
insertBeforeIndex.push(index);
|
|
23872
|
-
}
|
|
23873
|
-
}
|
|
23874
|
-
/**
|
|
23875
|
-
* Create `TNode.type=TNodeType.Placeholder` node.
|
|
23876
|
-
*
|
|
23877
|
-
* See `TNodeType.Placeholder` for more information.
|
|
23878
|
-
*/
|
|
23879
|
-
function createTNodePlaceholder(tView, previousTNodes, index) {
|
|
23880
|
-
const tNode = createTNodeAtIndex(tView, index, 64 /* TNodeType.Placeholder */, null, null);
|
|
23881
|
-
addTNodeAndUpdateInsertBeforeIndex(previousTNodes, tNode);
|
|
23882
|
-
return tNode;
|
|
23883
|
-
}
|
|
23884
|
-
/**
|
|
23885
|
-
* Returns current ICU case.
|
|
23886
|
-
*
|
|
23887
|
-
* ICU cases are stored as index into the `TIcu.cases`.
|
|
23888
|
-
* At times it is necessary to communicate that the ICU case just switched and that next ICU update
|
|
23889
|
-
* should update all bindings regardless of the mask. In such a case the we store negative numbers
|
|
23890
|
-
* for cases which have just been switched. This function removes the negative flag.
|
|
23891
|
-
*/
|
|
23892
|
-
function getCurrentICUCaseIndex(tIcu, lView) {
|
|
23893
|
-
const currentCase = lView[tIcu.currentCaseLViewIndex];
|
|
23894
|
-
return currentCase === null ? currentCase : (currentCase < 0 ? ~currentCase : currentCase);
|
|
23895
|
-
}
|
|
23896
|
-
function getParentFromIcuCreateOpCode(mergedCode) {
|
|
23897
|
-
return mergedCode >>> 17 /* IcuCreateOpCode.SHIFT_PARENT */;
|
|
23898
|
-
}
|
|
23899
|
-
function getRefFromIcuCreateOpCode(mergedCode) {
|
|
23900
|
-
return (mergedCode & 131070 /* IcuCreateOpCode.MASK_REF */) >>> 1 /* IcuCreateOpCode.SHIFT_REF */;
|
|
23901
|
-
}
|
|
23902
|
-
function getInstructionFromIcuCreateOpCode(mergedCode) {
|
|
23903
|
-
return mergedCode & 1 /* IcuCreateOpCode.MASK_INSTRUCTION */;
|
|
23904
|
-
}
|
|
23905
|
-
function icuCreateOpCode(opCode, parentIdx, refIdx) {
|
|
23906
|
-
ngDevMode && assertGreaterThanOrEqual(parentIdx, 0, 'Missing parent index');
|
|
23907
|
-
ngDevMode && assertGreaterThan(refIdx, 0, 'Missing ref index');
|
|
23908
|
-
return opCode | parentIdx << 17 /* IcuCreateOpCode.SHIFT_PARENT */ | refIdx << 1 /* IcuCreateOpCode.SHIFT_REF */;
|
|
23909
|
-
}
|
|
23910
|
-
|
|
23911
24307
|
/**
|
|
23912
24308
|
* Keep track of which input bindings in `ɵɵi18nExp` have changed.
|
|
23913
24309
|
*
|
|
@@ -23970,9 +24366,27 @@ let _locateOrCreateNode = (lView, index, textOrName, nodeType) => {
|
|
|
23970
24366
|
return createNodeWithoutHydration(lView, textOrName, nodeType);
|
|
23971
24367
|
};
|
|
23972
24368
|
function locateOrCreateNodeImpl(lView, index, textOrName, nodeType) {
|
|
23973
|
-
|
|
23974
|
-
|
|
23975
|
-
|
|
24369
|
+
const hydrationInfo = lView[HYDRATION];
|
|
24370
|
+
const noOffsetIndex = index - HEADER_OFFSET;
|
|
24371
|
+
const isNodeCreationMode = !isI18nHydrationSupportEnabled() || !hydrationInfo ||
|
|
24372
|
+
isInSkipHydrationBlock$1() || isDisconnectedNode$1(hydrationInfo, noOffsetIndex);
|
|
24373
|
+
lastNodeWasCreated(isNodeCreationMode);
|
|
24374
|
+
if (isNodeCreationMode) {
|
|
24375
|
+
return createNodeWithoutHydration(lView, textOrName, nodeType);
|
|
24376
|
+
}
|
|
24377
|
+
const native = locateI18nRNodeByIndex(hydrationInfo, noOffsetIndex);
|
|
24378
|
+
// TODO: Improve error handling
|
|
24379
|
+
//
|
|
24380
|
+
// Other hydration paths use validateMatchingNode() in order to provide
|
|
24381
|
+
// detailed information in development mode about the expected DOM.
|
|
24382
|
+
// However, not every node in an i18n block has a TNode. Instead, we
|
|
24383
|
+
// need to be able to use the AST to generate a similar message.
|
|
24384
|
+
ngDevMode && assertDefined(native, 'expected native element');
|
|
24385
|
+
ngDevMode && assertEqual(native.nodeType, nodeType, 'expected matching nodeType');
|
|
24386
|
+
ngDevMode && nodeType === Node.ELEMENT_NODE &&
|
|
24387
|
+
assertEqual(native.tagName.toLowerCase(), textOrName.toLowerCase(), 'expecting matching tagName');
|
|
24388
|
+
ngDevMode && markRNodeAsClaimedByHydration(native);
|
|
24389
|
+
return native;
|
|
23976
24390
|
}
|
|
23977
24391
|
function enableLocateOrCreateI18nNodeImpl() {
|
|
23978
24392
|
_locateOrCreateNode = locateOrCreateNodeImpl;
|
|
@@ -24264,6 +24678,7 @@ function applyIcuSwitchCase(tView, tIcu, lView, value) {
|
|
|
24264
24678
|
ngDevMode && assertDomNode(anchorRNode);
|
|
24265
24679
|
applyMutableOpCodes(tView, tIcu.create[caseIndex], lView, anchorRNode);
|
|
24266
24680
|
}
|
|
24681
|
+
claimDehydratedIcuCase(lView, tIcu.anchorIdx, caseIndex);
|
|
24267
24682
|
}
|
|
24268
24683
|
}
|
|
24269
24684
|
}
|
|
@@ -24914,9 +25329,6 @@ function countBindings(opCodes) {
|
|
|
24914
25329
|
function toMaskBit(bindingIndex) {
|
|
24915
25330
|
return 1 << Math.min(bindingIndex, 31);
|
|
24916
25331
|
}
|
|
24917
|
-
function isRootTemplateMessage(subTemplateIndex) {
|
|
24918
|
-
return subTemplateIndex === -1;
|
|
24919
|
-
}
|
|
24920
25332
|
/**
|
|
24921
25333
|
* Removes everything inside the sub-templates of a message.
|
|
24922
25334
|
*/
|
|
@@ -25420,6 +25832,7 @@ function ɵɵi18nStart(index, messageIndex, subTemplateIndex = -1) {
|
|
|
25420
25832
|
const insertInFrontOf = parentTNode && (parentTNode.type & 8 /* TNodeType.ElementContainer */) ?
|
|
25421
25833
|
lView[parentTNode.index] :
|
|
25422
25834
|
null;
|
|
25835
|
+
prepareI18nBlockForHydration(lView, adjustedIndex, parentTNode, subTemplateIndex);
|
|
25423
25836
|
applyCreateOpCodes(lView, tI18n.create, parentRNode, insertInFrontOf);
|
|
25424
25837
|
setInI18nBlock(true);
|
|
25425
25838
|
}
|
|
@@ -29951,7 +30364,7 @@ class Version {
|
|
|
29951
30364
|
/**
|
|
29952
30365
|
* @publicApi
|
|
29953
30366
|
*/
|
|
29954
|
-
const VERSION = new Version('18.0.0-next.
|
|
30367
|
+
const VERSION = new Version('18.0.0-next.3');
|
|
29955
30368
|
|
|
29956
30369
|
class Console {
|
|
29957
30370
|
log(message) {
|
|
@@ -30713,8 +31126,11 @@ function getInjectorParent(injector) {
|
|
|
30713
31126
|
else if (injector instanceof NullInjector) {
|
|
30714
31127
|
return null;
|
|
30715
31128
|
}
|
|
31129
|
+
else if (injector instanceof ChainedInjector) {
|
|
31130
|
+
return injector.parentInjector;
|
|
31131
|
+
}
|
|
30716
31132
|
else {
|
|
30717
|
-
throwError('getInjectorParent only support injectors of type R3Injector, NodeInjector, NullInjector');
|
|
31133
|
+
throwError('getInjectorParent only support injectors of type R3Injector, NodeInjector, NullInjector, ChainedInjector');
|
|
30718
31134
|
}
|
|
30719
31135
|
const parentLocation = getParentInjectorLocation(tNode, lView);
|
|
30720
31136
|
if (hasParentInjector(parentLocation)) {
|
|
@@ -30753,8 +31169,8 @@ function getModuleInjectorOfNodeInjector(injector) {
|
|
|
30753
31169
|
else {
|
|
30754
31170
|
throwError('getModuleInjectorOfNodeInjector must be called with a NodeInjector');
|
|
30755
31171
|
}
|
|
30756
|
-
const
|
|
30757
|
-
const moduleInjector =
|
|
31172
|
+
const inj = lView[INJECTOR];
|
|
31173
|
+
const moduleInjector = (inj instanceof ChainedInjector) ? inj.parentInjector : inj.parent;
|
|
30758
31174
|
if (!moduleInjector) {
|
|
30759
31175
|
throwError('NodeInjector must have some connection to the module injector tree');
|
|
30760
31176
|
}
|
|
@@ -31132,7 +31548,7 @@ function isSubscribable(obj) {
|
|
|
31132
31548
|
}
|
|
31133
31549
|
|
|
31134
31550
|
/**
|
|
31135
|
-
* A
|
|
31551
|
+
* A DI token that you can use to provide
|
|
31136
31552
|
* one or more initialization functions.
|
|
31137
31553
|
*
|
|
31138
31554
|
* The provided functions are injected at application startup and executed during
|
|
@@ -31316,7 +31732,7 @@ class ApplicationInitStatus {
|
|
|
31316
31732
|
}], () => [], null); })();
|
|
31317
31733
|
|
|
31318
31734
|
/**
|
|
31319
|
-
* A
|
|
31735
|
+
* A DI token that provides a set of callbacks to
|
|
31320
31736
|
* be called for every component that is bootstrapped.
|
|
31321
31737
|
*
|
|
31322
31738
|
* Each callback must take a `ComponentRef` instance and return nothing.
|
|
@@ -31483,6 +31899,7 @@ class ApplicationRef {
|
|
|
31483
31899
|
this._views = [];
|
|
31484
31900
|
this.internalErrorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);
|
|
31485
31901
|
this.afterRenderEffectManager = inject(AfterRenderEventManager);
|
|
31902
|
+
this.zonelessEnabled = inject(ZONELESS_ENABLED);
|
|
31486
31903
|
// Needed for ComponentFixture temporarily during migration of autoDetect behavior
|
|
31487
31904
|
// Eventually the hostView of the fixture should just attach to ApplicationRef.
|
|
31488
31905
|
this.externalTestViews = new Set();
|
|
@@ -31640,20 +32057,20 @@ class ApplicationRef {
|
|
|
31640
32057
|
const isFirstPass = runs === 0;
|
|
31641
32058
|
this.beforeRender.next(isFirstPass);
|
|
31642
32059
|
for (let { _lView, notifyErrorHandler } of this._views) {
|
|
31643
|
-
detectChangesInViewIfRequired(_lView, isFirstPass,
|
|
32060
|
+
detectChangesInViewIfRequired(_lView, notifyErrorHandler, isFirstPass, this.zonelessEnabled);
|
|
31644
32061
|
}
|
|
31645
32062
|
}
|
|
31646
32063
|
runs++;
|
|
31647
32064
|
afterRenderEffectManager.executeInternalCallbacks();
|
|
31648
32065
|
// If we have a newly dirty view after running internal callbacks, recheck the views again
|
|
31649
32066
|
// before running user-provided callbacks
|
|
31650
|
-
if ([...this.externalTestViews.keys(), ...this._views].some(({ _lView }) =>
|
|
32067
|
+
if ([...this.externalTestViews.keys(), ...this._views].some(({ _lView }) => requiresRefreshOrTraversal(_lView))) {
|
|
31651
32068
|
continue;
|
|
31652
32069
|
}
|
|
31653
32070
|
afterRenderEffectManager.execute();
|
|
31654
32071
|
// If after running all afterRender callbacks we have no more views that need to be refreshed,
|
|
31655
32072
|
// we can break out of the loop
|
|
31656
|
-
if (![...this.externalTestViews.keys(), ...this._views].some(({ _lView }) =>
|
|
32073
|
+
if (![...this.externalTestViews.keys(), ...this._views].some(({ _lView }) => requiresRefreshOrTraversal(_lView))) {
|
|
31657
32074
|
break;
|
|
31658
32075
|
}
|
|
31659
32076
|
}
|
|
@@ -31786,18 +32203,12 @@ function whenStable(applicationRef) {
|
|
|
31786
32203
|
applicationRef.onDestroy(() => whenStableStore?.delete(applicationRef));
|
|
31787
32204
|
return whenStablePromise;
|
|
31788
32205
|
}
|
|
31789
|
-
function detectChangesInViewIfRequired(lView, isFirstPass,
|
|
32206
|
+
function detectChangesInViewIfRequired(lView, notifyErrorHandler, isFirstPass, zonelessEnabled) {
|
|
31790
32207
|
// When re-checking, only check views which actually need it.
|
|
31791
|
-
if (!isFirstPass && !
|
|
32208
|
+
if (!isFirstPass && !requiresRefreshOrTraversal(lView)) {
|
|
31792
32209
|
return;
|
|
31793
32210
|
}
|
|
31794
|
-
|
|
31795
|
-
}
|
|
31796
|
-
function shouldRecheckView(view) {
|
|
31797
|
-
return requiresRefreshOrTraversal(view);
|
|
31798
|
-
}
|
|
31799
|
-
function detectChangesInView(lView, notifyErrorHandler, isFirstPass) {
|
|
31800
|
-
const mode = isFirstPass || lView[FLAGS] & 64 /* LViewFlags.Dirty */ ?
|
|
32211
|
+
const mode = (isFirstPass && !zonelessEnabled) ?
|
|
31801
32212
|
0 /* ChangeDetectionMode.Global */ :
|
|
31802
32213
|
1 /* ChangeDetectionMode.Targeted */;
|
|
31803
32214
|
detectChangesInternal(lView, notifyErrorHandler, mode);
|
|
@@ -31962,7 +32373,6 @@ class ChangeDetectionSchedulerImpl {
|
|
|
31962
32373
|
this.taskService = inject(PendingTasks);
|
|
31963
32374
|
this.pendingRenderTaskId = null;
|
|
31964
32375
|
this.shouldRefreshViews = false;
|
|
31965
|
-
this.schedule = getCallbackScheduler();
|
|
31966
32376
|
this.ngZone = inject(NgZone);
|
|
31967
32377
|
this.runningTick = false;
|
|
31968
32378
|
this.cancelScheduledCallback = null;
|
|
@@ -31985,15 +32395,17 @@ class ChangeDetectionSchedulerImpl {
|
|
|
31985
32395
|
return;
|
|
31986
32396
|
}
|
|
31987
32397
|
this.pendingRenderTaskId = this.taskService.add();
|
|
31988
|
-
|
|
32398
|
+
// TODO(atscott): This zone.root.run can maybe just be removed when we more
|
|
32399
|
+
// effectively get the unpatched versions of setTimeout and rAF (#55092)
|
|
32400
|
+
if (typeof Zone !== 'undefined' && Zone.root?.run) {
|
|
31989
32401
|
Zone.root.run(() => {
|
|
31990
|
-
this.cancelScheduledCallback =
|
|
32402
|
+
this.cancelScheduledCallback = scheduleCallback(() => {
|
|
31991
32403
|
this.tick(this.shouldRefreshViews);
|
|
31992
32404
|
});
|
|
31993
32405
|
});
|
|
31994
32406
|
}
|
|
31995
32407
|
else {
|
|
31996
|
-
this.cancelScheduledCallback =
|
|
32408
|
+
this.cancelScheduledCallback = scheduleCallback(() => {
|
|
31997
32409
|
this.tick(this.shouldRefreshViews);
|
|
31998
32410
|
});
|
|
31999
32411
|
}
|
|
@@ -32113,6 +32525,23 @@ class NgZoneChangeDetectionScheduler {
|
|
|
32113
32525
|
* with the bootstrapModule API.
|
|
32114
32526
|
*/
|
|
32115
32527
|
const PROVIDED_NG_ZONE = new InjectionToken((typeof ngDevMode === 'undefined' || ngDevMode) ? 'provideZoneChangeDetection token' : '');
|
|
32528
|
+
/**
|
|
32529
|
+
* Configures change detection scheduling when using ZoneJS.
|
|
32530
|
+
*/
|
|
32531
|
+
var SchedulingMode;
|
|
32532
|
+
(function (SchedulingMode) {
|
|
32533
|
+
/**
|
|
32534
|
+
* Change detection will run when the `NgZone.onMicrotaskEmpty` observable emits.
|
|
32535
|
+
* Change detection will also be scheduled to run whenever Angular is notified
|
|
32536
|
+
* of a change. This includes calling `ChangeDetectorRef.markForCheck`,
|
|
32537
|
+
* setting a `signal` value, and attaching a view.
|
|
32538
|
+
*/
|
|
32539
|
+
SchedulingMode[SchedulingMode["Hybrid"] = 0] = "Hybrid";
|
|
32540
|
+
/**
|
|
32541
|
+
* Change detection will only run when the `NgZone.onMicrotaskEmpty` observable emits.
|
|
32542
|
+
*/
|
|
32543
|
+
SchedulingMode[SchedulingMode["NgZoneOnly"] = 1] = "NgZoneOnly";
|
|
32544
|
+
})(SchedulingMode || (SchedulingMode = {}));
|
|
32116
32545
|
function internalProvideZoneChangeDetection({ ngZoneFactory, schedulingMode }) {
|
|
32117
32546
|
return [
|
|
32118
32547
|
{ provide: NgZone, useFactory: ngZoneFactory },
|
|
@@ -32141,11 +32570,11 @@ function internalProvideZoneChangeDetection({ ngZoneFactory, schedulingMode }) {
|
|
|
32141
32570
|
},
|
|
32142
32571
|
{ provide: INTERNAL_APPLICATION_ERROR_HANDLER, useFactory: ngZoneApplicationErrorHandlerFactory },
|
|
32143
32572
|
// Always disable scheduler whenever explicitly disabled, even if Hybrid was specified elsewhere
|
|
32144
|
-
schedulingMode ===
|
|
32573
|
+
schedulingMode === SchedulingMode.NgZoneOnly ?
|
|
32145
32574
|
{ provide: ZONELESS_SCHEDULER_DISABLED, useValue: true } :
|
|
32146
32575
|
[],
|
|
32147
32576
|
// Only provide scheduler when explicitly enabled
|
|
32148
|
-
schedulingMode ===
|
|
32577
|
+
schedulingMode === SchedulingMode.Hybrid ?
|
|
32149
32578
|
{ provide: ChangeDetectionScheduler, useExisting: ChangeDetectionSchedulerImpl } :
|
|
32150
32579
|
[],
|
|
32151
32580
|
];
|
|
@@ -32838,7 +33267,7 @@ function createViewRef(tNode, lView, isPipe) {
|
|
|
32838
33267
|
}
|
|
32839
33268
|
|
|
32840
33269
|
/**
|
|
32841
|
-
* Represents an Angular
|
|
33270
|
+
* Represents an Angular view.
|
|
32842
33271
|
*
|
|
32843
33272
|
* @see {@link ChangeDetectorRef#usage-notes Change detection usage}
|
|
32844
33273
|
*
|
|
@@ -32847,8 +33276,8 @@ function createViewRef(tNode, lView, isPipe) {
|
|
|
32847
33276
|
class ViewRef extends ChangeDetectorRef {
|
|
32848
33277
|
}
|
|
32849
33278
|
/**
|
|
32850
|
-
* Represents an Angular
|
|
32851
|
-
* An
|
|
33279
|
+
* Represents an Angular view in a view container.
|
|
33280
|
+
* An embedded view can be referenced from a component
|
|
32852
33281
|
* other than the hosting component whose template defines it, or it can be defined
|
|
32853
33282
|
* independently by a `TemplateRef`.
|
|
32854
33283
|
*
|
|
@@ -35361,226 +35790,6 @@ function getDeferBlocks(lView, deferBlocks) {
|
|
|
35361
35790
|
}
|
|
35362
35791
|
}
|
|
35363
35792
|
|
|
35364
|
-
/**
|
|
35365
|
-
* Indicates whether the hydration-related code was added,
|
|
35366
|
-
* prevents adding it multiple times.
|
|
35367
|
-
*/
|
|
35368
|
-
let isHydrationSupportEnabled = false;
|
|
35369
|
-
/**
|
|
35370
|
-
* Indicates whether support for hydrating i18n blocks is enabled.
|
|
35371
|
-
*/
|
|
35372
|
-
let _isI18nHydrationSupportEnabled = false;
|
|
35373
|
-
/**
|
|
35374
|
-
* Defines a period of time that Angular waits for the `ApplicationRef.isStable` to emit `true`.
|
|
35375
|
-
* If there was no event with the `true` value during this time, Angular reports a warning.
|
|
35376
|
-
*/
|
|
35377
|
-
const APPLICATION_IS_STABLE_TIMEOUT = 10_000;
|
|
35378
|
-
/**
|
|
35379
|
-
* Brings the necessary hydration code in tree-shakable manner.
|
|
35380
|
-
* The code is only present when the `provideClientHydration` is
|
|
35381
|
-
* invoked. Otherwise, this code is tree-shaken away during the
|
|
35382
|
-
* build optimization step.
|
|
35383
|
-
*
|
|
35384
|
-
* This technique allows us to swap implementations of methods so
|
|
35385
|
-
* tree shaking works appropriately when hydration is disabled or
|
|
35386
|
-
* enabled. It brings in the appropriate version of the method that
|
|
35387
|
-
* supports hydration only when enabled.
|
|
35388
|
-
*/
|
|
35389
|
-
function enableHydrationRuntimeSupport() {
|
|
35390
|
-
if (!isHydrationSupportEnabled) {
|
|
35391
|
-
isHydrationSupportEnabled = true;
|
|
35392
|
-
enableRetrieveHydrationInfoImpl();
|
|
35393
|
-
enableLocateOrCreateElementNodeImpl();
|
|
35394
|
-
enableLocateOrCreateTextNodeImpl();
|
|
35395
|
-
enableLocateOrCreateElementContainerNodeImpl();
|
|
35396
|
-
enableLocateOrCreateContainerAnchorImpl();
|
|
35397
|
-
enableLocateOrCreateContainerRefImpl();
|
|
35398
|
-
enableFindMatchingDehydratedViewImpl();
|
|
35399
|
-
enableApplyRootElementTransformImpl();
|
|
35400
|
-
enableLocateOrCreateI18nNodeImpl();
|
|
35401
|
-
}
|
|
35402
|
-
}
|
|
35403
|
-
/**
|
|
35404
|
-
* Outputs a message with hydration stats into a console.
|
|
35405
|
-
*/
|
|
35406
|
-
function printHydrationStats(injector) {
|
|
35407
|
-
const console = injector.get(Console);
|
|
35408
|
-
const message = `Angular hydrated ${ngDevMode.hydratedComponents} component(s) ` +
|
|
35409
|
-
`and ${ngDevMode.hydratedNodes} node(s), ` +
|
|
35410
|
-
`${ngDevMode.componentsSkippedHydration} component(s) were skipped. ` +
|
|
35411
|
-
`Learn more at https://angular.io/guide/hydration.`;
|
|
35412
|
-
// tslint:disable-next-line:no-console
|
|
35413
|
-
console.log(message);
|
|
35414
|
-
}
|
|
35415
|
-
/**
|
|
35416
|
-
* Returns a Promise that is resolved when an application becomes stable.
|
|
35417
|
-
*/
|
|
35418
|
-
function whenStableWithTimeout(appRef, injector) {
|
|
35419
|
-
const whenStablePromise = whenStable(appRef);
|
|
35420
|
-
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
35421
|
-
const timeoutTime = APPLICATION_IS_STABLE_TIMEOUT;
|
|
35422
|
-
const console = injector.get(Console);
|
|
35423
|
-
const ngZone = injector.get(NgZone);
|
|
35424
|
-
// The following call should not and does not prevent the app to become stable
|
|
35425
|
-
// We cannot use RxJS timer here because the app would remain unstable.
|
|
35426
|
-
// This also avoids an extra change detection cycle.
|
|
35427
|
-
const timeoutId = ngZone.runOutsideAngular(() => {
|
|
35428
|
-
return setTimeout(() => logWarningOnStableTimedout(timeoutTime, console), timeoutTime);
|
|
35429
|
-
});
|
|
35430
|
-
whenStablePromise.finally(() => clearTimeout(timeoutId));
|
|
35431
|
-
}
|
|
35432
|
-
return whenStablePromise;
|
|
35433
|
-
}
|
|
35434
|
-
/**
|
|
35435
|
-
* Returns a set of providers required to setup hydration support
|
|
35436
|
-
* for an application that is server side rendered. This function is
|
|
35437
|
-
* included into the `provideClientHydration` public API function from
|
|
35438
|
-
* the `platform-browser` package.
|
|
35439
|
-
*
|
|
35440
|
-
* The function sets up an internal flag that would be recognized during
|
|
35441
|
-
* the server side rendering time as well, so there is no need to
|
|
35442
|
-
* configure or change anything in NgUniversal to enable the feature.
|
|
35443
|
-
*/
|
|
35444
|
-
function withDomHydration() {
|
|
35445
|
-
return makeEnvironmentProviders([
|
|
35446
|
-
{
|
|
35447
|
-
provide: IS_HYDRATION_DOM_REUSE_ENABLED,
|
|
35448
|
-
useFactory: () => {
|
|
35449
|
-
let isEnabled = true;
|
|
35450
|
-
if (isPlatformBrowser()) {
|
|
35451
|
-
// On the client, verify that the server response contains
|
|
35452
|
-
// hydration annotations. Otherwise, keep hydration disabled.
|
|
35453
|
-
const transferState = inject(TransferState, { optional: true });
|
|
35454
|
-
isEnabled = !!transferState?.get(NGH_DATA_KEY, null);
|
|
35455
|
-
if (!isEnabled && (typeof ngDevMode !== 'undefined' && ngDevMode)) {
|
|
35456
|
-
const console = inject(Console);
|
|
35457
|
-
const message = formatRuntimeError(-505 /* RuntimeErrorCode.MISSING_HYDRATION_ANNOTATIONS */, 'Angular hydration was requested on the client, but there was no ' +
|
|
35458
|
-
'serialized information present in the server response, ' +
|
|
35459
|
-
'thus hydration was not enabled. ' +
|
|
35460
|
-
'Make sure the `provideClientHydration()` is included into the list ' +
|
|
35461
|
-
'of providers in the server part of the application configuration.');
|
|
35462
|
-
// tslint:disable-next-line:no-console
|
|
35463
|
-
console.warn(message);
|
|
35464
|
-
}
|
|
35465
|
-
}
|
|
35466
|
-
if (isEnabled) {
|
|
35467
|
-
performanceMarkFeature('NgHydration');
|
|
35468
|
-
}
|
|
35469
|
-
return isEnabled;
|
|
35470
|
-
},
|
|
35471
|
-
},
|
|
35472
|
-
{
|
|
35473
|
-
provide: ENVIRONMENT_INITIALIZER,
|
|
35474
|
-
useValue: () => {
|
|
35475
|
-
_isI18nHydrationSupportEnabled = !!inject(IS_I18N_HYDRATION_ENABLED, { optional: true });
|
|
35476
|
-
// Since this function is used across both server and client,
|
|
35477
|
-
// make sure that the runtime code is only added when invoked
|
|
35478
|
-
// on the client. Moving forward, the `isPlatformBrowser` check should
|
|
35479
|
-
// be replaced with a tree-shakable alternative (e.g. `isServer`
|
|
35480
|
-
// flag).
|
|
35481
|
-
if (isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
|
|
35482
|
-
verifySsrContentsIntegrity();
|
|
35483
|
-
enableHydrationRuntimeSupport();
|
|
35484
|
-
}
|
|
35485
|
-
},
|
|
35486
|
-
multi: true,
|
|
35487
|
-
},
|
|
35488
|
-
{
|
|
35489
|
-
provide: PRESERVE_HOST_CONTENT,
|
|
35490
|
-
useFactory: () => {
|
|
35491
|
-
// Preserve host element content only in a browser
|
|
35492
|
-
// environment and when hydration is configured properly.
|
|
35493
|
-
// On a server, an application is rendered from scratch,
|
|
35494
|
-
// so the host content needs to be empty.
|
|
35495
|
-
return isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED);
|
|
35496
|
-
}
|
|
35497
|
-
},
|
|
35498
|
-
{
|
|
35499
|
-
provide: APP_BOOTSTRAP_LISTENER,
|
|
35500
|
-
useFactory: () => {
|
|
35501
|
-
if (isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
|
|
35502
|
-
const appRef = inject(ApplicationRef);
|
|
35503
|
-
const injector = inject(Injector);
|
|
35504
|
-
return () => {
|
|
35505
|
-
// Wait until an app becomes stable and cleanup all views that
|
|
35506
|
-
// were not claimed during the application bootstrap process.
|
|
35507
|
-
// The timing is similar to when we start the serialization process
|
|
35508
|
-
// on the server.
|
|
35509
|
-
//
|
|
35510
|
-
// Note: the cleanup task *MUST* be scheduled within the Angular zone
|
|
35511
|
-
// to ensure that change detection is properly run afterward.
|
|
35512
|
-
whenStableWithTimeout(appRef, injector).then(() => {
|
|
35513
|
-
NgZone.assertInAngularZone();
|
|
35514
|
-
cleanupDehydratedViews(appRef);
|
|
35515
|
-
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
35516
|
-
printHydrationStats(injector);
|
|
35517
|
-
}
|
|
35518
|
-
});
|
|
35519
|
-
};
|
|
35520
|
-
}
|
|
35521
|
-
return () => { }; // noop
|
|
35522
|
-
},
|
|
35523
|
-
multi: true,
|
|
35524
|
-
}
|
|
35525
|
-
]);
|
|
35526
|
-
}
|
|
35527
|
-
/**
|
|
35528
|
-
* Returns a set of providers required to setup support for i18n hydration.
|
|
35529
|
-
* Requires hydration to be enabled separately.
|
|
35530
|
-
*/
|
|
35531
|
-
function withI18nHydration() {
|
|
35532
|
-
return makeEnvironmentProviders([
|
|
35533
|
-
{
|
|
35534
|
-
provide: IS_I18N_HYDRATION_ENABLED,
|
|
35535
|
-
useValue: true,
|
|
35536
|
-
},
|
|
35537
|
-
]);
|
|
35538
|
-
}
|
|
35539
|
-
/**
|
|
35540
|
-
* Returns whether i18n hydration support is enabled.
|
|
35541
|
-
*/
|
|
35542
|
-
function isI18nHydrationSupportEnabled() {
|
|
35543
|
-
return _isI18nHydrationSupportEnabled;
|
|
35544
|
-
}
|
|
35545
|
-
/**
|
|
35546
|
-
*
|
|
35547
|
-
* @param time The time in ms until the stable timedout warning message is logged
|
|
35548
|
-
*/
|
|
35549
|
-
function logWarningOnStableTimedout(time, console) {
|
|
35550
|
-
const message = `Angular hydration expected the ApplicationRef.isStable() to emit \`true\`, but it ` +
|
|
35551
|
-
`didn't happen within ${time}ms. Angular hydration logic depends on the application becoming stable ` +
|
|
35552
|
-
`as a signal to complete hydration process.`;
|
|
35553
|
-
console.warn(formatRuntimeError(-506 /* RuntimeErrorCode.HYDRATION_STABLE_TIMEDOUT */, message));
|
|
35554
|
-
}
|
|
35555
|
-
/**
|
|
35556
|
-
* Verifies whether the DOM contains a special marker added during SSR time to make sure
|
|
35557
|
-
* there is no SSR'ed contents transformations happen after SSR is completed. Typically that
|
|
35558
|
-
* happens either by CDN or during the build process as an optimization to remove comment nodes.
|
|
35559
|
-
* Hydration process requires comment nodes produced by Angular to locate correct DOM segments.
|
|
35560
|
-
* When this special marker is *not* present - throw an error and do not proceed with hydration,
|
|
35561
|
-
* since it will not be able to function correctly.
|
|
35562
|
-
*
|
|
35563
|
-
* Note: this function is invoked only on the client, so it's safe to use DOM APIs.
|
|
35564
|
-
*/
|
|
35565
|
-
function verifySsrContentsIntegrity() {
|
|
35566
|
-
const doc = getDocument();
|
|
35567
|
-
let hydrationMarker;
|
|
35568
|
-
for (const node of doc.body.childNodes) {
|
|
35569
|
-
if (node.nodeType === Node.COMMENT_NODE &&
|
|
35570
|
-
node.textContent?.trim() === SSR_CONTENT_INTEGRITY_MARKER) {
|
|
35571
|
-
hydrationMarker = node;
|
|
35572
|
-
break;
|
|
35573
|
-
}
|
|
35574
|
-
}
|
|
35575
|
-
if (!hydrationMarker) {
|
|
35576
|
-
throw new RuntimeError(-507 /* RuntimeErrorCode.MISSING_SSR_CONTENT_INTEGRITY_MARKER */, typeof ngDevMode !== 'undefined' && ngDevMode &&
|
|
35577
|
-
'Angular hydration logic detected that HTML content of this page was modified after it ' +
|
|
35578
|
-
'was produced during server side rendering. Make sure that there are no optimizations ' +
|
|
35579
|
-
'that remove comment nodes from HTML enabled on your CDN. Angular hydration ' +
|
|
35580
|
-
'relies on HTML produced by the server, including whitespaces and comment nodes.');
|
|
35581
|
-
}
|
|
35582
|
-
}
|
|
35583
|
-
|
|
35584
35793
|
/**
|
|
35585
35794
|
* A collection that tracks all serialized views (`ngh` DOM annotations)
|
|
35586
35795
|
* to avoid duplication. An attempt to add a duplicate view results in the
|
|
@@ -35691,6 +35900,8 @@ function annotateLContainerForHydration(lContainer, context) {
|
|
|
35691
35900
|
* @param doc A reference to the current Document instance.
|
|
35692
35901
|
*/
|
|
35693
35902
|
function annotateForHydration(appRef, doc) {
|
|
35903
|
+
const injector = appRef.injector;
|
|
35904
|
+
const isI18nHydrationEnabledVal = isI18nHydrationEnabled(injector);
|
|
35694
35905
|
const serializedViewCollection = new SerializedViewCollection();
|
|
35695
35906
|
const corruptedTextNodes = new Map();
|
|
35696
35907
|
const viewRefs = appRef._views;
|
|
@@ -35702,6 +35913,8 @@ function annotateForHydration(appRef, doc) {
|
|
|
35702
35913
|
const context = {
|
|
35703
35914
|
serializedViewCollection,
|
|
35704
35915
|
corruptedTextNodes,
|
|
35916
|
+
isI18nHydrationEnabled: isI18nHydrationEnabledVal,
|
|
35917
|
+
i18nChildren: new Map(),
|
|
35705
35918
|
};
|
|
35706
35919
|
if (isLContainer(lNode)) {
|
|
35707
35920
|
annotateLContainerForHydration(lNode, context);
|
|
@@ -35718,7 +35931,7 @@ function annotateForHydration(appRef, doc) {
|
|
|
35718
35931
|
// hydration logic was setup and enabled correctly. Otherwise, if a client
|
|
35719
35932
|
// hydration doesn't find a key in the transfer state - an error is produced.
|
|
35720
35933
|
const serializedViews = serializedViewCollection.getAll();
|
|
35721
|
-
const transferState =
|
|
35934
|
+
const transferState = injector.get(TransferState);
|
|
35722
35935
|
transferState.set(NGH_DATA_KEY, serializedViews);
|
|
35723
35936
|
}
|
|
35724
35937
|
/**
|
|
@@ -35799,10 +36012,10 @@ function serializeLContainer(lContainer, context) {
|
|
|
35799
36012
|
* needs to take to locate a node) and stores it in the `NODES` section of the
|
|
35800
36013
|
* current serialized view.
|
|
35801
36014
|
*/
|
|
35802
|
-
function appendSerializedNodePath(ngh, tNode, lView) {
|
|
36015
|
+
function appendSerializedNodePath(ngh, tNode, lView, excludedParentNodes) {
|
|
35803
36016
|
const noOffsetIndex = tNode.index - HEADER_OFFSET;
|
|
35804
36017
|
ngh[NODES] ??= {};
|
|
35805
|
-
ngh[NODES][noOffsetIndex] = calcPathForNode(tNode, lView);
|
|
36018
|
+
ngh[NODES][noOffsetIndex] = calcPathForNode(tNode, lView, excludedParentNodes);
|
|
35806
36019
|
}
|
|
35807
36020
|
/**
|
|
35808
36021
|
* Helper function to append information about a disconnected node.
|
|
@@ -35828,10 +36041,19 @@ function appendDisconnectedNodeIndex(ngh, tNode) {
|
|
|
35828
36041
|
function serializeLView(lView, context) {
|
|
35829
36042
|
const ngh = {};
|
|
35830
36043
|
const tView = lView[TVIEW];
|
|
36044
|
+
const i18nChildren = getOrComputeI18nChildren(tView, context);
|
|
35831
36045
|
// Iterate over DOM element references in an LView.
|
|
35832
36046
|
for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
|
|
35833
36047
|
const tNode = tView.data[i];
|
|
35834
36048
|
const noOffsetIndex = i - HEADER_OFFSET;
|
|
36049
|
+
// Attempt to serialize any i18n data for the given slot. We do this first, as i18n
|
|
36050
|
+
// has its own process for serialization.
|
|
36051
|
+
const i18nData = trySerializeI18nBlock(lView, i, context);
|
|
36052
|
+
if (i18nData) {
|
|
36053
|
+
ngh[I18N_DATA] ??= {};
|
|
36054
|
+
ngh[I18N_DATA][noOffsetIndex] = i18nData;
|
|
36055
|
+
continue;
|
|
36056
|
+
}
|
|
35835
36057
|
// Skip processing of a given slot in the following cases:
|
|
35836
36058
|
// - Local refs (e.g. <div #localRef>) take up an extra slot in LViews
|
|
35837
36059
|
// to store the same element. In this case, there is no information in
|
|
@@ -35841,6 +36063,12 @@ function serializeLView(lView, context) {
|
|
|
35841
36063
|
if (!isTNodeShape(tNode)) {
|
|
35842
36064
|
continue;
|
|
35843
36065
|
}
|
|
36066
|
+
// Skip any nodes that are in an i18n block but are considered detached (i.e. not
|
|
36067
|
+
// present in the template). These nodes are disconnected from the DOM tree, and
|
|
36068
|
+
// so we don't want to serialize any information about them.
|
|
36069
|
+
if (isDetachedByI18n(tNode)) {
|
|
36070
|
+
continue;
|
|
36071
|
+
}
|
|
35844
36072
|
// Check if a native node that represents a given TNode is disconnected from the DOM tree.
|
|
35845
36073
|
// Such nodes must be excluded from the hydration (since the hydration won't be able to
|
|
35846
36074
|
// find them), so the TNode ids are collected and used at runtime to skip the hydration.
|
|
@@ -35872,7 +36100,7 @@ function serializeLView(lView, context) {
|
|
|
35872
36100
|
appendDisconnectedNodeIndex(ngh, projectionHeadTNode);
|
|
35873
36101
|
}
|
|
35874
36102
|
else {
|
|
35875
|
-
appendSerializedNodePath(ngh, projectionHeadTNode, lView);
|
|
36103
|
+
appendSerializedNodePath(ngh, projectionHeadTNode, lView, i18nChildren);
|
|
35876
36104
|
}
|
|
35877
36105
|
}
|
|
35878
36106
|
}
|
|
@@ -35889,7 +36117,7 @@ function serializeLView(lView, context) {
|
|
|
35889
36117
|
}
|
|
35890
36118
|
}
|
|
35891
36119
|
}
|
|
35892
|
-
conditionallyAnnotateNodePath(ngh, tNode, lView);
|
|
36120
|
+
conditionallyAnnotateNodePath(ngh, tNode, lView, i18nChildren);
|
|
35893
36121
|
if (isLContainer(lView[i])) {
|
|
35894
36122
|
// Serialize information about a template.
|
|
35895
36123
|
const embeddedTView = tNode.tView;
|
|
@@ -35939,47 +36167,13 @@ function serializeLView(lView, context) {
|
|
|
35939
36167
|
}
|
|
35940
36168
|
if (nextTNode && !isInSkipHydrationBlock(nextTNode)) {
|
|
35941
36169
|
// Handle a tNode after the `<ng-content>` slot.
|
|
35942
|
-
appendSerializedNodePath(ngh, nextTNode, lView);
|
|
36170
|
+
appendSerializedNodePath(ngh, nextTNode, lView, i18nChildren);
|
|
35943
36171
|
}
|
|
35944
36172
|
}
|
|
35945
36173
|
else {
|
|
35946
|
-
// Handle cases where text nodes can be lost after DOM serialization:
|
|
35947
|
-
// 1. When there is an *empty text node* in DOM: in this case, this
|
|
35948
|
-
// node would not make it into the serialized string and as a result,
|
|
35949
|
-
// this node wouldn't be created in a browser. This would result in
|
|
35950
|
-
// a mismatch during the hydration, where the runtime logic would expect
|
|
35951
|
-
// a text node to be present in live DOM, but no text node would exist.
|
|
35952
|
-
// Example: `<span>{{ name }}</span>` when the `name` is an empty string.
|
|
35953
|
-
// This would result in `<span></span>` string after serialization and
|
|
35954
|
-
// in a browser only the `span` element would be created. To resolve that,
|
|
35955
|
-
// an extra comment node is appended in place of an empty text node and
|
|
35956
|
-
// that special comment node is replaced with an empty text node *before*
|
|
35957
|
-
// hydration.
|
|
35958
|
-
// 2. When there are 2 consecutive text nodes present in the DOM.
|
|
35959
|
-
// Example: `<div>Hello <ng-container *ngIf="true">world</ng-container></div>`.
|
|
35960
|
-
// In this scenario, the live DOM would look like this:
|
|
35961
|
-
// <div>#text('Hello ') #text('world') #comment('container')</div>
|
|
35962
|
-
// Serialized string would look like this: `<div>Hello world<!--container--></div>`.
|
|
35963
|
-
// The live DOM in a browser after that would be:
|
|
35964
|
-
// <div>#text('Hello world') #comment('container')</div>
|
|
35965
|
-
// Notice how 2 text nodes are now "merged" into one. This would cause hydration
|
|
35966
|
-
// logic to fail, since it'd expect 2 text nodes being present, not one.
|
|
35967
|
-
// To fix this, we insert a special comment node in between those text nodes, so
|
|
35968
|
-
// serialized representation is: `<div>Hello <!--ngtns-->world<!--container--></div>`.
|
|
35969
|
-
// This forces browser to create 2 text nodes separated by a comment node.
|
|
35970
|
-
// Before running a hydration process, this special comment node is removed, so the
|
|
35971
|
-
// live DOM has exactly the same state as it was before serialization.
|
|
35972
36174
|
if (tNode.type & 1 /* TNodeType.Text */) {
|
|
35973
36175
|
const rNode = unwrapRNode(lView[i]);
|
|
35974
|
-
|
|
35975
|
-
// contents is empty. Otherwise, such text node would be present on
|
|
35976
|
-
// the client after server-side rendering and no special handling needed.
|
|
35977
|
-
if (rNode.textContent === '') {
|
|
35978
|
-
context.corruptedTextNodes.set(rNode, "ngetn" /* TextNodeMarker.EmptyNode */);
|
|
35979
|
-
}
|
|
35980
|
-
else if (rNode.nextSibling?.nodeType === Node.TEXT_NODE) {
|
|
35981
|
-
context.corruptedTextNodes.set(rNode, "ngtns" /* TextNodeMarker.Separator */);
|
|
35982
|
-
}
|
|
36176
|
+
processTextNodeBeforeSerialization(context, rNode);
|
|
35983
36177
|
}
|
|
35984
36178
|
}
|
|
35985
36179
|
}
|
|
@@ -35992,17 +36186,17 @@ function serializeLView(lView, context) {
|
|
|
35992
36186
|
* 1. If `tNode.projectionNext` is different from `tNode.next` - it means that
|
|
35993
36187
|
* the next `tNode` after projection is different from the one in the original
|
|
35994
36188
|
* template. Since hydration relies on `tNode.next`, this serialized info
|
|
35995
|
-
*
|
|
36189
|
+
* is required to help runtime code find the node at the correct location.
|
|
35996
36190
|
* 2. In certain content projection-based use-cases, it's possible that only
|
|
35997
36191
|
* a content of a projected element is rendered. In this case, content nodes
|
|
35998
36192
|
* require an extra annotation, since runtime logic can't rely on parent-child
|
|
35999
36193
|
* connection to identify the location of a node.
|
|
36000
36194
|
*/
|
|
36001
|
-
function conditionallyAnnotateNodePath(ngh, tNode, lView) {
|
|
36195
|
+
function conditionallyAnnotateNodePath(ngh, tNode, lView, excludedParentNodes) {
|
|
36002
36196
|
// Handle case #1 described above.
|
|
36003
36197
|
if (tNode.projectionNext && tNode.projectionNext !== tNode.next &&
|
|
36004
36198
|
!isInSkipHydrationBlock(tNode.projectionNext)) {
|
|
36005
|
-
appendSerializedNodePath(ngh, tNode.projectionNext, lView);
|
|
36199
|
+
appendSerializedNodePath(ngh, tNode.projectionNext, lView, excludedParentNodes);
|
|
36006
36200
|
}
|
|
36007
36201
|
// Handle case #2 described above.
|
|
36008
36202
|
// Note: we only do that for the first node (i.e. when `tNode.prev === null`),
|
|
@@ -36010,7 +36204,7 @@ function conditionallyAnnotateNodePath(ngh, tNode, lView) {
|
|
|
36010
36204
|
// annotation is needed.
|
|
36011
36205
|
if (tNode.prev === null && tNode.parent !== null && isDisconnectedNode(tNode.parent, lView) &&
|
|
36012
36206
|
!isDisconnectedNode(tNode, lView)) {
|
|
36013
|
-
appendSerializedNodePath(ngh, tNode, lView);
|
|
36207
|
+
appendSerializedNodePath(ngh, tNode, lView, excludedParentNodes);
|
|
36014
36208
|
}
|
|
36015
36209
|
}
|
|
36016
36210
|
/**
|
|
@@ -36086,6 +36280,248 @@ function isContentProjectedNode(tNode) {
|
|
|
36086
36280
|
return false;
|
|
36087
36281
|
}
|
|
36088
36282
|
|
|
36283
|
+
/**
|
|
36284
|
+
* Indicates whether the hydration-related code was added,
|
|
36285
|
+
* prevents adding it multiple times.
|
|
36286
|
+
*/
|
|
36287
|
+
let isHydrationSupportEnabled = false;
|
|
36288
|
+
/**
|
|
36289
|
+
* Indicates whether the i18n-related code was added,
|
|
36290
|
+
* prevents adding it multiple times.
|
|
36291
|
+
*
|
|
36292
|
+
* Note: This merely controls whether the code is loaded,
|
|
36293
|
+
* while `setIsI18nHydrationSupportEnabled` determines
|
|
36294
|
+
* whether i18n blocks are serialized or hydrated.
|
|
36295
|
+
*/
|
|
36296
|
+
let isI18nHydrationRuntimeSupportEnabled = false;
|
|
36297
|
+
/**
|
|
36298
|
+
* Defines a period of time that Angular waits for the `ApplicationRef.isStable` to emit `true`.
|
|
36299
|
+
* If there was no event with the `true` value during this time, Angular reports a warning.
|
|
36300
|
+
*/
|
|
36301
|
+
const APPLICATION_IS_STABLE_TIMEOUT = 10_000;
|
|
36302
|
+
/**
|
|
36303
|
+
* Brings the necessary hydration code in tree-shakable manner.
|
|
36304
|
+
* The code is only present when the `provideClientHydration` is
|
|
36305
|
+
* invoked. Otherwise, this code is tree-shaken away during the
|
|
36306
|
+
* build optimization step.
|
|
36307
|
+
*
|
|
36308
|
+
* This technique allows us to swap implementations of methods so
|
|
36309
|
+
* tree shaking works appropriately when hydration is disabled or
|
|
36310
|
+
* enabled. It brings in the appropriate version of the method that
|
|
36311
|
+
* supports hydration only when enabled.
|
|
36312
|
+
*/
|
|
36313
|
+
function enableHydrationRuntimeSupport() {
|
|
36314
|
+
if (!isHydrationSupportEnabled) {
|
|
36315
|
+
isHydrationSupportEnabled = true;
|
|
36316
|
+
enableRetrieveHydrationInfoImpl();
|
|
36317
|
+
enableLocateOrCreateElementNodeImpl();
|
|
36318
|
+
enableLocateOrCreateTextNodeImpl();
|
|
36319
|
+
enableLocateOrCreateElementContainerNodeImpl();
|
|
36320
|
+
enableLocateOrCreateContainerAnchorImpl();
|
|
36321
|
+
enableLocateOrCreateContainerRefImpl();
|
|
36322
|
+
enableFindMatchingDehydratedViewImpl();
|
|
36323
|
+
enableApplyRootElementTransformImpl();
|
|
36324
|
+
}
|
|
36325
|
+
}
|
|
36326
|
+
/**
|
|
36327
|
+
* Brings the necessary i18n hydration code in tree-shakable manner.
|
|
36328
|
+
* Similar to `enableHydrationRuntimeSupport`, the code is only
|
|
36329
|
+
* present when `withI18nSupport` is invoked.
|
|
36330
|
+
*/
|
|
36331
|
+
function enableI18nHydrationRuntimeSupport() {
|
|
36332
|
+
if (!isI18nHydrationRuntimeSupportEnabled) {
|
|
36333
|
+
isI18nHydrationRuntimeSupportEnabled = true;
|
|
36334
|
+
enableLocateOrCreateI18nNodeImpl();
|
|
36335
|
+
enablePrepareI18nBlockForHydrationImpl();
|
|
36336
|
+
enableClaimDehydratedIcuCaseImpl();
|
|
36337
|
+
}
|
|
36338
|
+
}
|
|
36339
|
+
/**
|
|
36340
|
+
* Outputs a message with hydration stats into a console.
|
|
36341
|
+
*/
|
|
36342
|
+
function printHydrationStats(injector) {
|
|
36343
|
+
const console = injector.get(Console);
|
|
36344
|
+
const message = `Angular hydrated ${ngDevMode.hydratedComponents} component(s) ` +
|
|
36345
|
+
`and ${ngDevMode.hydratedNodes} node(s), ` +
|
|
36346
|
+
`${ngDevMode.componentsSkippedHydration} component(s) were skipped. ` +
|
|
36347
|
+
`Learn more at https://angular.io/guide/hydration.`;
|
|
36348
|
+
// tslint:disable-next-line:no-console
|
|
36349
|
+
console.log(message);
|
|
36350
|
+
}
|
|
36351
|
+
/**
|
|
36352
|
+
* Returns a Promise that is resolved when an application becomes stable.
|
|
36353
|
+
*/
|
|
36354
|
+
function whenStableWithTimeout(appRef, injector) {
|
|
36355
|
+
const whenStablePromise = whenStable(appRef);
|
|
36356
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
36357
|
+
const timeoutTime = APPLICATION_IS_STABLE_TIMEOUT;
|
|
36358
|
+
const console = injector.get(Console);
|
|
36359
|
+
const ngZone = injector.get(NgZone);
|
|
36360
|
+
// The following call should not and does not prevent the app to become stable
|
|
36361
|
+
// We cannot use RxJS timer here because the app would remain unstable.
|
|
36362
|
+
// This also avoids an extra change detection cycle.
|
|
36363
|
+
const timeoutId = ngZone.runOutsideAngular(() => {
|
|
36364
|
+
return setTimeout(() => logWarningOnStableTimedout(timeoutTime, console), timeoutTime);
|
|
36365
|
+
});
|
|
36366
|
+
whenStablePromise.finally(() => clearTimeout(timeoutId));
|
|
36367
|
+
}
|
|
36368
|
+
return whenStablePromise;
|
|
36369
|
+
}
|
|
36370
|
+
/**
|
|
36371
|
+
* Returns a set of providers required to setup hydration support
|
|
36372
|
+
* for an application that is server side rendered. This function is
|
|
36373
|
+
* included into the `provideClientHydration` public API function from
|
|
36374
|
+
* the `platform-browser` package.
|
|
36375
|
+
*
|
|
36376
|
+
* The function sets up an internal flag that would be recognized during
|
|
36377
|
+
* the server side rendering time as well, so there is no need to
|
|
36378
|
+
* configure or change anything in NgUniversal to enable the feature.
|
|
36379
|
+
*/
|
|
36380
|
+
function withDomHydration() {
|
|
36381
|
+
return makeEnvironmentProviders([
|
|
36382
|
+
{
|
|
36383
|
+
provide: IS_HYDRATION_DOM_REUSE_ENABLED,
|
|
36384
|
+
useFactory: () => {
|
|
36385
|
+
let isEnabled = true;
|
|
36386
|
+
if (isPlatformBrowser()) {
|
|
36387
|
+
// On the client, verify that the server response contains
|
|
36388
|
+
// hydration annotations. Otherwise, keep hydration disabled.
|
|
36389
|
+
const transferState = inject(TransferState, { optional: true });
|
|
36390
|
+
isEnabled = !!transferState?.get(NGH_DATA_KEY, null);
|
|
36391
|
+
if (!isEnabled && (typeof ngDevMode !== 'undefined' && ngDevMode)) {
|
|
36392
|
+
const console = inject(Console);
|
|
36393
|
+
const message = formatRuntimeError(-505 /* RuntimeErrorCode.MISSING_HYDRATION_ANNOTATIONS */, 'Angular hydration was requested on the client, but there was no ' +
|
|
36394
|
+
'serialized information present in the server response, ' +
|
|
36395
|
+
'thus hydration was not enabled. ' +
|
|
36396
|
+
'Make sure the `provideClientHydration()` is included into the list ' +
|
|
36397
|
+
'of providers in the server part of the application configuration.');
|
|
36398
|
+
// tslint:disable-next-line:no-console
|
|
36399
|
+
console.warn(message);
|
|
36400
|
+
}
|
|
36401
|
+
}
|
|
36402
|
+
if (isEnabled) {
|
|
36403
|
+
performanceMarkFeature('NgHydration');
|
|
36404
|
+
}
|
|
36405
|
+
return isEnabled;
|
|
36406
|
+
},
|
|
36407
|
+
},
|
|
36408
|
+
{
|
|
36409
|
+
provide: ENVIRONMENT_INITIALIZER,
|
|
36410
|
+
useValue: () => {
|
|
36411
|
+
// i18n support is enabled by calling withI18nSupport(), but there's
|
|
36412
|
+
// no way to turn it off (e.g. for tests), so we turn it off by default.
|
|
36413
|
+
setIsI18nHydrationSupportEnabled(false);
|
|
36414
|
+
// Since this function is used across both server and client,
|
|
36415
|
+
// make sure that the runtime code is only added when invoked
|
|
36416
|
+
// on the client. Moving forward, the `isPlatformBrowser` check should
|
|
36417
|
+
// be replaced with a tree-shakable alternative (e.g. `isServer`
|
|
36418
|
+
// flag).
|
|
36419
|
+
if (isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
|
|
36420
|
+
verifySsrContentsIntegrity();
|
|
36421
|
+
enableHydrationRuntimeSupport();
|
|
36422
|
+
}
|
|
36423
|
+
},
|
|
36424
|
+
multi: true,
|
|
36425
|
+
},
|
|
36426
|
+
{
|
|
36427
|
+
provide: PRESERVE_HOST_CONTENT,
|
|
36428
|
+
useFactory: () => {
|
|
36429
|
+
// Preserve host element content only in a browser
|
|
36430
|
+
// environment and when hydration is configured properly.
|
|
36431
|
+
// On a server, an application is rendered from scratch,
|
|
36432
|
+
// so the host content needs to be empty.
|
|
36433
|
+
return isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED);
|
|
36434
|
+
}
|
|
36435
|
+
},
|
|
36436
|
+
{
|
|
36437
|
+
provide: APP_BOOTSTRAP_LISTENER,
|
|
36438
|
+
useFactory: () => {
|
|
36439
|
+
if (isPlatformBrowser() && inject(IS_HYDRATION_DOM_REUSE_ENABLED)) {
|
|
36440
|
+
const appRef = inject(ApplicationRef);
|
|
36441
|
+
const injector = inject(Injector);
|
|
36442
|
+
return () => {
|
|
36443
|
+
// Wait until an app becomes stable and cleanup all views that
|
|
36444
|
+
// were not claimed during the application bootstrap process.
|
|
36445
|
+
// The timing is similar to when we start the serialization process
|
|
36446
|
+
// on the server.
|
|
36447
|
+
//
|
|
36448
|
+
// Note: the cleanup task *MUST* be scheduled within the Angular zone
|
|
36449
|
+
// to ensure that change detection is properly run afterward.
|
|
36450
|
+
whenStableWithTimeout(appRef, injector).then(() => {
|
|
36451
|
+
NgZone.assertInAngularZone();
|
|
36452
|
+
cleanupDehydratedViews(appRef);
|
|
36453
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
36454
|
+
printHydrationStats(injector);
|
|
36455
|
+
}
|
|
36456
|
+
});
|
|
36457
|
+
};
|
|
36458
|
+
}
|
|
36459
|
+
return () => { }; // noop
|
|
36460
|
+
},
|
|
36461
|
+
multi: true,
|
|
36462
|
+
}
|
|
36463
|
+
]);
|
|
36464
|
+
}
|
|
36465
|
+
/**
|
|
36466
|
+
* Returns a set of providers required to setup support for i18n hydration.
|
|
36467
|
+
* Requires hydration to be enabled separately.
|
|
36468
|
+
*/
|
|
36469
|
+
function withI18nSupport() {
|
|
36470
|
+
return [
|
|
36471
|
+
{
|
|
36472
|
+
provide: IS_I18N_HYDRATION_ENABLED,
|
|
36473
|
+
useValue: true,
|
|
36474
|
+
},
|
|
36475
|
+
{
|
|
36476
|
+
provide: ENVIRONMENT_INITIALIZER,
|
|
36477
|
+
useValue: () => {
|
|
36478
|
+
enableI18nHydrationRuntimeSupport();
|
|
36479
|
+
setIsI18nHydrationSupportEnabled(true);
|
|
36480
|
+
performanceMarkFeature('NgI18nHydration');
|
|
36481
|
+
},
|
|
36482
|
+
multi: true,
|
|
36483
|
+
},
|
|
36484
|
+
];
|
|
36485
|
+
}
|
|
36486
|
+
/**
|
|
36487
|
+
*
|
|
36488
|
+
* @param time The time in ms until the stable timedout warning message is logged
|
|
36489
|
+
*/
|
|
36490
|
+
function logWarningOnStableTimedout(time, console) {
|
|
36491
|
+
const message = `Angular hydration expected the ApplicationRef.isStable() to emit \`true\`, but it ` +
|
|
36492
|
+
`didn't happen within ${time}ms. Angular hydration logic depends on the application becoming stable ` +
|
|
36493
|
+
`as a signal to complete hydration process.`;
|
|
36494
|
+
console.warn(formatRuntimeError(-506 /* RuntimeErrorCode.HYDRATION_STABLE_TIMEDOUT */, message));
|
|
36495
|
+
}
|
|
36496
|
+
/**
|
|
36497
|
+
* Verifies whether the DOM contains a special marker added during SSR time to make sure
|
|
36498
|
+
* there is no SSR'ed contents transformations happen after SSR is completed. Typically that
|
|
36499
|
+
* happens either by CDN or during the build process as an optimization to remove comment nodes.
|
|
36500
|
+
* Hydration process requires comment nodes produced by Angular to locate correct DOM segments.
|
|
36501
|
+
* When this special marker is *not* present - throw an error and do not proceed with hydration,
|
|
36502
|
+
* since it will not be able to function correctly.
|
|
36503
|
+
*
|
|
36504
|
+
* Note: this function is invoked only on the client, so it's safe to use DOM APIs.
|
|
36505
|
+
*/
|
|
36506
|
+
function verifySsrContentsIntegrity() {
|
|
36507
|
+
const doc = getDocument();
|
|
36508
|
+
let hydrationMarker;
|
|
36509
|
+
for (const node of doc.body.childNodes) {
|
|
36510
|
+
if (node.nodeType === Node.COMMENT_NODE &&
|
|
36511
|
+
node.textContent?.trim() === SSR_CONTENT_INTEGRITY_MARKER) {
|
|
36512
|
+
hydrationMarker = node;
|
|
36513
|
+
break;
|
|
36514
|
+
}
|
|
36515
|
+
}
|
|
36516
|
+
if (!hydrationMarker) {
|
|
36517
|
+
throw new RuntimeError(-507 /* RuntimeErrorCode.MISSING_SSR_CONTENT_INTEGRITY_MARKER */, typeof ngDevMode !== 'undefined' && ngDevMode &&
|
|
36518
|
+
'Angular hydration logic detected that HTML content of this page was modified after it ' +
|
|
36519
|
+
'was produced during server side rendering. Make sure that there are no optimizations ' +
|
|
36520
|
+
'that remove comment nodes from HTML enabled on your CDN. Angular hydration ' +
|
|
36521
|
+
'relies on HTML produced by the server, including whitespaces and comment nodes.');
|
|
36522
|
+
}
|
|
36523
|
+
}
|
|
36524
|
+
|
|
36089
36525
|
/**
|
|
36090
36526
|
* Queue a state update to be performed asynchronously.
|
|
36091
36527
|
*
|
|
@@ -36632,5 +37068,5 @@ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
|
36632
37068
|
* Generated bundle index. Do not edit.
|
|
36633
37069
|
*/
|
|
36634
37070
|
|
|
36635
|
-
export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, AfterRenderPhase, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostAttributeToken, HostBinding, HostListener, INJECTOR$1 as INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, OutputEmitterRef, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertNotInReactiveContext, assertPlatform, booleanAttribute, computed, contentChild, contentChildren, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, input, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, model, numberAttribute, output, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, viewChild, viewChildren, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, CONTAINER_HEADER_OFFSET as ɵCONTAINER_HEADER_OFFSET, ChangeDetectionScheduler as ɵChangeDetectionScheduler, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_CONFIG as ɵDEFER_BLOCK_CONFIG, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, DeferBlockBehavior as ɵDeferBlockBehavior, DeferBlockState as ɵDeferBlockState, EffectScheduler as ɵEffectScheduler, IMAGE_CONFIG as ɵIMAGE_CONFIG, IMAGE_CONFIG_DEFAULTS as ɵIMAGE_CONFIG_DEFAULTS, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, ɵINPUT_SIGNAL_BRAND_WRITE_TYPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, PendingTasks as ɵPendingTasks, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, ZONELESS_ENABLED as ɵZONELESS_ENABLED, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChangesInViewIfRequired as ɵdetectChangesInViewIfRequired, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadataFn as ɵgetAsyncClassMetadataFn, getDebugNode as ɵgetDebugNode, getDeferBlocks as ɵgetDeferBlocks, getDirectives as ɵgetDirectives, getEnsureDirtyViewsAreAlwaysReachable as ɵgetEnsureDirtyViewsAreAlwaysReachable, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getOutputDestroyRef as ɵgetOutputDestroyRef, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalAfterNextRender as ɵinternalAfterNextRender, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, performanceMarkFeature as ɵperformanceMarkFeature, provideZonelessChangeDetection as ɵprovideZonelessChangeDetection, queueStateUpdate as ɵqueueStateUpdate, readHydrationInfo as ɵreadHydrationInfo, registerLocaleData as ɵregisterLocaleData, renderDeferBlockState as ɵrenderDeferBlockState, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, ɵsetClassDebugInfo, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setEnsureDirtyViewsAreAlwaysReachable as ɵsetEnsureDirtyViewsAreAlwaysReachable, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, triggerResourceLoading as ɵtriggerResourceLoading, truncateMiddle as ɵtruncateMiddle, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, ɵunwrapWritableSignal, whenStable as ɵwhenStable, withDomHydration as ɵwithDomHydration, withI18nHydration as ɵwithI18nHydration, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, InputFlags as ɵɵInputFlags, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵcontentQuerySignal, ɵɵdefer, ɵɵdeferEnableTimerScheduling, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareClassMetadataAsync, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryAdvance, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵtwoWayBindingSet, ɵɵtwoWayListener, ɵɵtwoWayProperty, ɵɵvalidateIframeAttribute, ɵɵviewQuery, ɵɵviewQuerySignal };
|
|
37071
|
+
export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, AfterRenderPhase, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostAttributeToken, HostBinding, HostListener, INJECTOR$1 as INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, OutputEmitterRef, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertNotInReactiveContext, assertPlatform, booleanAttribute, computed, contentChild, contentChildren, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, input, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, model, numberAttribute, output, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, viewChild, viewChildren, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, CONTAINER_HEADER_OFFSET as ɵCONTAINER_HEADER_OFFSET, ChangeDetectionScheduler as ɵChangeDetectionScheduler, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_CONFIG as ɵDEFER_BLOCK_CONFIG, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, DeferBlockBehavior as ɵDeferBlockBehavior, DeferBlockState as ɵDeferBlockState, EffectScheduler as ɵEffectScheduler, IMAGE_CONFIG as ɵIMAGE_CONFIG, IMAGE_CONFIG_DEFAULTS as ɵIMAGE_CONFIG_DEFAULTS, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, ɵINPUT_SIGNAL_BRAND_WRITE_TYPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, PendingTasks as ɵPendingTasks, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, SchedulingMode as ɵSchedulingMode, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, ZONELESS_ENABLED as ɵZONELESS_ENABLED, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChangesInViewIfRequired as ɵdetectChangesInViewIfRequired, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadataFn as ɵgetAsyncClassMetadataFn, getDebugNode as ɵgetDebugNode, getDeferBlocks as ɵgetDeferBlocks, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getOutputDestroyRef as ɵgetOutputDestroyRef, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalAfterNextRender as ɵinternalAfterNextRender, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, performanceMarkFeature as ɵperformanceMarkFeature, provideZonelessChangeDetection as ɵprovideZonelessChangeDetection, queueStateUpdate as ɵqueueStateUpdate, readHydrationInfo as ɵreadHydrationInfo, registerLocaleData as ɵregisterLocaleData, renderDeferBlockState as ɵrenderDeferBlockState, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, ɵsetClassDebugInfo, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, triggerResourceLoading as ɵtriggerResourceLoading, truncateMiddle as ɵtruncateMiddle, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, ɵunwrapWritableSignal, whenStable as ɵwhenStable, withDomHydration as ɵwithDomHydration, withI18nSupport as ɵwithI18nSupport, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, InputFlags as ɵɵInputFlags, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵcontentQuerySignal, ɵɵdefer, ɵɵdeferEnableTimerScheduling, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareClassMetadataAsync, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryAdvance, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵtwoWayBindingSet, ɵɵtwoWayListener, ɵɵtwoWayProperty, ɵɵvalidateIframeAttribute, ɵɵviewQuery, ɵɵviewQuerySignal };
|
|
36636
37072
|
//# sourceMappingURL=core.mjs.map
|