@angular/core 16.0.0-next.1 → 16.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/esm2020/src/application_config.mjs +21 -0
  2. package/esm2020/src/application_init.mjs +21 -30
  3. package/esm2020/src/application_ref.mjs +31 -31
  4. package/esm2020/src/application_tokens.mjs +2 -13
  5. package/esm2020/src/change_detection/change_detection.mjs +2 -2
  6. package/esm2020/src/change_detection/constants.mjs +1 -49
  7. package/esm2020/src/core.mjs +4 -3
  8. package/esm2020/src/core_private_export.mjs +5 -7
  9. package/esm2020/src/core_render3_private_export.mjs +2 -1
  10. package/esm2020/src/debug/debug_node.mjs +1 -5
  11. package/esm2020/src/hydration/annotate.mjs +140 -0
  12. package/esm2020/src/hydration/api.mjs +120 -0
  13. package/esm2020/src/hydration/error_handling.mjs +29 -0
  14. package/esm2020/src/hydration/interfaces.mjs +10 -0
  15. package/esm2020/src/hydration/node_lookup_utils.mjs +75 -0
  16. package/esm2020/src/hydration/skip_hydration.mjs +34 -0
  17. package/esm2020/src/hydration/tokens.mjs +25 -0
  18. package/esm2020/src/hydration/utils.mjs +131 -0
  19. package/esm2020/src/linker/template_ref.mjs +4 -4
  20. package/esm2020/src/render3/component_ref.mjs +16 -9
  21. package/esm2020/src/render3/i18n/i18n_util.mjs +3 -3
  22. package/esm2020/src/render3/instructions/element.mjs +48 -6
  23. package/esm2020/src/render3/instructions/element_container.mjs +54 -9
  24. package/esm2020/src/render3/instructions/listener.mjs +3 -3
  25. package/esm2020/src/render3/instructions/shared.mjs +25 -8
  26. package/esm2020/src/render3/instructions/template.mjs +2 -2
  27. package/esm2020/src/render3/instructions/text.mjs +36 -5
  28. package/esm2020/src/render3/interfaces/node.mjs +1 -1
  29. package/esm2020/src/render3/interfaces/renderer_dom.mjs +1 -1
  30. package/esm2020/src/render3/interfaces/view.mjs +3 -2
  31. package/esm2020/src/render3/jit/directive.mjs +1 -2
  32. package/esm2020/src/render3/node_manipulation.mjs +12 -1
  33. package/esm2020/src/render3/state.mjs +45 -1
  34. package/esm2020/src/transfer_state.mjs +15 -10
  35. package/esm2020/src/util/lang.mjs +1 -11
  36. package/esm2020/src/util/ng_dev_mode.mjs +3 -1
  37. package/esm2020/src/version.mjs +1 -1
  38. package/esm2020/testing/src/logger.mjs +3 -3
  39. package/esm2020/testing/src/ng_zone_mock.mjs +3 -3
  40. package/fesm2015/core.mjs +1127 -517
  41. package/fesm2015/core.mjs.map +1 -1
  42. package/fesm2015/testing.mjs +677 -90
  43. package/fesm2015/testing.mjs.map +1 -1
  44. package/fesm2020/core.mjs +1119 -515
  45. package/fesm2020/core.mjs.map +1 -1
  46. package/fesm2020/testing.mjs +671 -90
  47. package/fesm2020/testing.mjs.map +1 -1
  48. package/index.d.ts +174 -92
  49. package/package.json +2 -2
  50. package/schematics/migrations/relative-link-resolution/bundle.js +7 -7
  51. package/schematics/migrations/router-link-with-href/bundle.js +10 -10
  52. package/schematics/ng-generate/standalone-migration/bundle.js +693 -668
  53. package/schematics/ng-generate/standalone-migration/bundle.js.map +4 -4
  54. package/testing/index.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.0.0-next.1
2
+ * @license Angular v16.0.0-next.2
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -1636,6 +1636,8 @@ function ngDevModeResetPerfCounters() {
1636
1636
  rendererAppendChild: 0,
1637
1637
  rendererInsertBefore: 0,
1638
1638
  rendererCreateComment: 0,
1639
+ hydratedNodes: 0,
1640
+ hydratedComponents: 0,
1639
1641
  };
1640
1642
  // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
1641
1643
  const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
@@ -2115,54 +2117,6 @@ var ChangeDetectionStrategy;
2115
2117
  */
2116
2118
  ChangeDetectionStrategy[ChangeDetectionStrategy["Default"] = 1] = "Default";
2117
2119
  })(ChangeDetectionStrategy || (ChangeDetectionStrategy = {}));
2118
- /**
2119
- * Defines the possible states of the default change detector.
2120
- * @see `ChangeDetectorRef`
2121
- */
2122
- var ChangeDetectorStatus;
2123
- (function (ChangeDetectorStatus) {
2124
- /**
2125
- * A state in which, after calling `detectChanges()`, the change detector
2126
- * state becomes `Checked`, and must be explicitly invoked or reactivated.
2127
- */
2128
- ChangeDetectorStatus[ChangeDetectorStatus["CheckOnce"] = 0] = "CheckOnce";
2129
- /**
2130
- * A state in which change detection is skipped until the change detector mode
2131
- * becomes `CheckOnce`.
2132
- */
2133
- ChangeDetectorStatus[ChangeDetectorStatus["Checked"] = 1] = "Checked";
2134
- /**
2135
- * A state in which change detection continues automatically until explicitly
2136
- * deactivated.
2137
- */
2138
- ChangeDetectorStatus[ChangeDetectorStatus["CheckAlways"] = 2] = "CheckAlways";
2139
- /**
2140
- * A state in which a change detector sub tree is not a part of the main tree and
2141
- * should be skipped.
2142
- */
2143
- ChangeDetectorStatus[ChangeDetectorStatus["Detached"] = 3] = "Detached";
2144
- /**
2145
- * Indicates that the change detector encountered an error checking a binding
2146
- * or calling a directive lifecycle method and is now in an inconsistent state. Change
2147
- * detectors in this state do not detect changes.
2148
- */
2149
- ChangeDetectorStatus[ChangeDetectorStatus["Errored"] = 4] = "Errored";
2150
- /**
2151
- * Indicates that the change detector has been destroyed.
2152
- */
2153
- ChangeDetectorStatus[ChangeDetectorStatus["Destroyed"] = 5] = "Destroyed";
2154
- })(ChangeDetectorStatus || (ChangeDetectorStatus = {}));
2155
- /**
2156
- * Reports whether a given strategy is currently the default for change detection.
2157
- * @param changeDetectionStrategy The strategy to check.
2158
- * @returns True if the given strategy is the current default, false otherwise.
2159
- * @see `ChangeDetectorStatus`
2160
- * @see `ChangeDetectorRef`
2161
- */
2162
- function isDefaultChangeDetectionStrategy(changeDetectionStrategy) {
2163
- return changeDetectionStrategy == null ||
2164
- changeDetectionStrategy === ChangeDetectionStrategy.Default;
2165
- }
2166
2120
 
2167
2121
  /**
2168
2122
  * Defines the CSS styles encapsulation policies for the {@link Component} decorator's
@@ -2598,6 +2552,7 @@ const QUERIES = 19;
2598
2552
  const ID = 20;
2599
2553
  const EMBEDDED_VIEW_INJECTOR = 21;
2600
2554
  const ON_DESTROY_HOOKS = 22;
2555
+ const HYDRATION = 23;
2601
2556
  /**
2602
2557
  * Size of LView's header. Necessary to adjust for it when setting slots.
2603
2558
  *
@@ -2605,7 +2560,7 @@ const ON_DESTROY_HOOKS = 22;
2605
2560
  * instruction index into `LView` index. All other indexes should be in the `LView` index space and
2606
2561
  * there should be no need to refer to `HEADER_OFFSET` anywhere else.
2607
2562
  */
2608
- const HEADER_OFFSET = 23;
2563
+ const HEADER_OFFSET = 24;
2609
2564
  // Note: This hack is necessary so we don't erroneously get a circular dependency
2610
2565
  // failure based on types.
2611
2566
  const unusedValueExportToPlacateAjd$3 = 1;
@@ -3056,6 +3011,7 @@ function storeLViewOnDestroy(lView, onDestroyCallback) {
3056
3011
  const instructionState = {
3057
3012
  lFrame: createLFrame(null),
3058
3013
  bindingsEnabled: true,
3014
+ skipHydrationRootTNode: null,
3059
3015
  };
3060
3016
  /**
3061
3017
  * In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
@@ -3086,6 +3042,21 @@ function decreaseElementDepthCount() {
3086
3042
  function getBindingsEnabled() {
3087
3043
  return instructionState.bindingsEnabled;
3088
3044
  }
3045
+ /**
3046
+ * Returns true if currently inside a skip hydration block.
3047
+ * @returns boolean
3048
+ */
3049
+ function isInSkipHydrationBlock() {
3050
+ return instructionState.skipHydrationRootTNode !== null;
3051
+ }
3052
+ /**
3053
+ * Returns true if this is the root TNode of the skip hydration block.
3054
+ * @param tNode the current TNode
3055
+ * @returns boolean
3056
+ */
3057
+ function isSkipHydrationRootTNode(tNode) {
3058
+ return instructionState.skipHydrationRootTNode === tNode;
3059
+ }
3089
3060
  /**
3090
3061
  * Enables directive matching on elements.
3091
3062
  *
@@ -3108,6 +3079,13 @@ function getBindingsEnabled() {
3108
3079
  function ɵɵenableBindings() {
3109
3080
  instructionState.bindingsEnabled = true;
3110
3081
  }
3082
+ /**
3083
+ * Sets a flag to specify that the TNode is in a skip hydration block.
3084
+ * @param tNode the current TNode
3085
+ */
3086
+ function enterSkipHydrationBlock(tNode) {
3087
+ instructionState.skipHydrationRootTNode = tNode;
3088
+ }
3111
3089
  /**
3112
3090
  * Disables directive matching on element.
3113
3091
  *
@@ -3130,6 +3108,12 @@ function ɵɵenableBindings() {
3130
3108
  function ɵɵdisableBindings() {
3131
3109
  instructionState.bindingsEnabled = false;
3132
3110
  }
3111
+ /**
3112
+ * Clears the root skip hydration node when leaving a skip hydration block.
3113
+ */
3114
+ function leaveSkipHydrationBlock() {
3115
+ instructionState.skipHydrationRootTNode = null;
3116
+ }
3133
3117
  /**
3134
3118
  * Return the current `LView`.
3135
3119
  */
@@ -3554,6 +3538,21 @@ function namespaceHTMLInternal() {
3554
3538
  function getNamespace$1() {
3555
3539
  return instructionState.lFrame.currentNamespace;
3556
3540
  }
3541
+ let _wasLastNodeCreated = true;
3542
+ /**
3543
+ * Retrieves a global flag that indicates whether the most recent DOM node
3544
+ * was created or hydrated.
3545
+ */
3546
+ function wasLastNodeCreated() {
3547
+ return _wasLastNodeCreated;
3548
+ }
3549
+ /**
3550
+ * Sets a global flag to indicate whether the most recent DOM node
3551
+ * was created or hydrated.
3552
+ */
3553
+ function lastNodeWasCreated(flag) {
3554
+ _wasLastNodeCreated = flag;
3555
+ }
3557
3556
 
3558
3557
  /**
3559
3558
  * Adds all directive lifecycle hooks from the given `DirectiveDef` to the given `TView`.
@@ -6609,6 +6608,17 @@ function nativeRemoveNode(renderer, rNode, isHostElement) {
6609
6608
  nativeRemoveChild(renderer, nativeParent, rNode, isHostElement);
6610
6609
  }
6611
6610
  }
6611
+ /**
6612
+ * Removes the contents of a given RElement using a given renderer.
6613
+ *
6614
+ * @param renderer A renderer to be used
6615
+ * @param rElement the native RElement to be cleared
6616
+ */
6617
+ function clearElementContents(renderer, rElement) {
6618
+ while (rElement.firstChild) {
6619
+ nativeRemoveChild(renderer, rElement, rElement.firstChild, false);
6620
+ }
6621
+ }
6612
6622
  /**
6613
6623
  * Performs the operation of `action` on the node. Typically this involves inserting or removing
6614
6624
  * nodes on the LView or projection boundary.
@@ -8594,6 +8604,331 @@ function forEachSingleProvider(providers, fn) {
8594
8604
  }
8595
8605
  }
8596
8606
 
8607
+ /**
8608
+ * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
8609
+ * primarily for prefixing application attributes and CSS styles when
8610
+ * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
8611
+ *
8612
+ * BY default, the value is randomly generated and assigned to the application by Angular.
8613
+ * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
8614
+ * the root {@link Injector} that uses this token.
8615
+ *
8616
+ * @publicApi
8617
+ */
8618
+ const APP_ID = new InjectionToken('AppId', {
8619
+ providedIn: 'root',
8620
+ factory: _appIdRandomProviderFactory,
8621
+ });
8622
+ function _appIdRandomProviderFactory() {
8623
+ return `${_randomChar()}${_randomChar()}${_randomChar()}`;
8624
+ }
8625
+ /**
8626
+ * Providers that generate a random `APP_ID_TOKEN`.
8627
+ * @publicApi
8628
+ */
8629
+ const APP_ID_RANDOM_PROVIDER = {
8630
+ provide: APP_ID,
8631
+ useFactory: _appIdRandomProviderFactory,
8632
+ deps: [],
8633
+ };
8634
+ function _randomChar() {
8635
+ return String.fromCharCode(97 + Math.floor(Math.random() * 25));
8636
+ }
8637
+ /**
8638
+ * A function that is executed when a platform is initialized.
8639
+ * @publicApi
8640
+ */
8641
+ const PLATFORM_INITIALIZER = new InjectionToken('Platform Initializer');
8642
+ /**
8643
+ * A token that indicates an opaque platform ID.
8644
+ * @publicApi
8645
+ */
8646
+ const PLATFORM_ID = new InjectionToken('Platform ID', {
8647
+ providedIn: 'platform',
8648
+ factory: () => 'unknown', // set a default platform name, when none set explicitly
8649
+ });
8650
+ /**
8651
+ * A [DI token](guide/glossary#di-token "DI token definition") that indicates the root directory of
8652
+ * the application
8653
+ * @publicApi
8654
+ */
8655
+ const PACKAGE_ROOT_URL = new InjectionToken('Application Packages Root URL');
8656
+ // We keep this token here, rather than the animations package, so that modules that only care
8657
+ // about which animations module is loaded (e.g. the CDK) can retrieve it without having to
8658
+ // include extra dependencies. See #44970 for more context.
8659
+ /**
8660
+ * A [DI token](guide/glossary#di-token "DI token definition") that indicates which animations
8661
+ * module has been loaded.
8662
+ * @publicApi
8663
+ */
8664
+ const ANIMATION_MODULE_TYPE = new InjectionToken('AnimationModuleType');
8665
+
8666
+ function escapeTransferStateContent(text) {
8667
+ const escapedText = {
8668
+ '&': '&a;',
8669
+ '"': '&q;',
8670
+ '\'': '&s;',
8671
+ '<': '&l;',
8672
+ '>': '&g;',
8673
+ };
8674
+ return text.replace(/[&"'<>]/g, s => escapedText[s]);
8675
+ }
8676
+ function unescapeTransferStateContent(text) {
8677
+ const unescapedText = {
8678
+ '&a;': '&',
8679
+ '&q;': '"',
8680
+ '&s;': '\'',
8681
+ '&l;': '<',
8682
+ '&g;': '>',
8683
+ };
8684
+ return text.replace(/&[^;]+;/g, s => unescapedText[s]);
8685
+ }
8686
+ /**
8687
+ * Create a `StateKey<T>` that can be used to store value of type T with `TransferState`.
8688
+ *
8689
+ * Example:
8690
+ *
8691
+ * ```
8692
+ * const COUNTER_KEY = makeStateKey<number>('counter');
8693
+ * let value = 10;
8694
+ *
8695
+ * transferState.set(COUNTER_KEY, value);
8696
+ * ```
8697
+ *
8698
+ * @publicApi
8699
+ */
8700
+ function makeStateKey(key) {
8701
+ return key;
8702
+ }
8703
+ function initTransferState() {
8704
+ const transferState = new TransferState();
8705
+ transferState.store = retrieveTransferredState(getDocument(), inject$1(APP_ID));
8706
+ return transferState;
8707
+ }
8708
+ /**
8709
+ * A key value store that is transferred from the application on the server side to the application
8710
+ * on the client side.
8711
+ *
8712
+ * The `TransferState` is available as an injectable token.
8713
+ * On the client, just inject this token using DI and use it, it will be lazily initialized.
8714
+ * On the server it's already included if `renderApplication` function is used. Otherwise, import
8715
+ * the `ServerTransferStateModule` module to make the `TransferState` available.
8716
+ *
8717
+ * The values in the store are serialized/deserialized using JSON.stringify/JSON.parse. So only
8718
+ * boolean, number, string, null and non-class objects will be serialized and deserialized in a
8719
+ * non-lossy manner.
8720
+ *
8721
+ * @publicApi
8722
+ */
8723
+ class TransferState {
8724
+ constructor() {
8725
+ /** @internal */
8726
+ this.store = {};
8727
+ this.onSerializeCallbacks = {};
8728
+ }
8729
+ /**
8730
+ * Get the value corresponding to a key. Return `defaultValue` if key is not found.
8731
+ */
8732
+ get(key, defaultValue) {
8733
+ return this.store[key] !== undefined ? this.store[key] : defaultValue;
8734
+ }
8735
+ /**
8736
+ * Set the value corresponding to a key.
8737
+ */
8738
+ set(key, value) {
8739
+ this.store[key] = value;
8740
+ }
8741
+ /**
8742
+ * Remove a key from the store.
8743
+ */
8744
+ remove(key) {
8745
+ delete this.store[key];
8746
+ }
8747
+ /**
8748
+ * Test whether a key exists in the store.
8749
+ */
8750
+ hasKey(key) {
8751
+ return this.store.hasOwnProperty(key);
8752
+ }
8753
+ /**
8754
+ * Indicates whether the state is empty.
8755
+ */
8756
+ get isEmpty() {
8757
+ return Object.keys(this.store).length === 0;
8758
+ }
8759
+ /**
8760
+ * Register a callback to provide the value for a key when `toJson` is called.
8761
+ */
8762
+ onSerialize(key, callback) {
8763
+ this.onSerializeCallbacks[key] = callback;
8764
+ }
8765
+ /**
8766
+ * Serialize the current state of the store to JSON.
8767
+ */
8768
+ toJson() {
8769
+ // Call the onSerialize callbacks and put those values into the store.
8770
+ for (const key in this.onSerializeCallbacks) {
8771
+ if (this.onSerializeCallbacks.hasOwnProperty(key)) {
8772
+ try {
8773
+ this.store[key] = this.onSerializeCallbacks[key]();
8774
+ }
8775
+ catch (e) {
8776
+ console.warn('Exception in onSerialize callback: ', e);
8777
+ }
8778
+ }
8779
+ }
8780
+ return JSON.stringify(this.store);
8781
+ }
8782
+ }
8783
+ /** @nocollapse */
8784
+ TransferState.ɵprov =
8785
+ /** @pureOrBreakMyCode */ ɵɵdefineInjectable({
8786
+ token: TransferState,
8787
+ providedIn: 'root',
8788
+ factory: initTransferState,
8789
+ });
8790
+ function retrieveTransferredState(doc, appId) {
8791
+ // Locate the script tag with the JSON data transferred from the server.
8792
+ // The id of the script tag is set to the Angular appId + 'state'.
8793
+ const script = doc.getElementById(appId + '-state');
8794
+ let initialState = {};
8795
+ if (script && script.textContent) {
8796
+ try {
8797
+ // Avoid using any here as it triggers lint errors in google3 (any is not allowed).
8798
+ initialState = JSON.parse(unescapeTransferStateContent(script.textContent));
8799
+ }
8800
+ catch (e) {
8801
+ console.warn('Exception while restoring TransferState for app ' + appId, e);
8802
+ }
8803
+ }
8804
+ return initialState;
8805
+ }
8806
+
8807
+ /* Represents a key in NghDom that holds information about <ng-container>s. */
8808
+ const ELEMENT_CONTAINERS = 'e';
8809
+
8810
+ /**
8811
+ * The name of the key used in the TransferState collection,
8812
+ * where hydration information is located.
8813
+ */
8814
+ const TRANSFER_STATE_TOKEN_ID = '__ɵnghData__';
8815
+ /**
8816
+ * Lookup key used to reference DOM hydration data (ngh) in `TransferState`.
8817
+ */
8818
+ const NGH_DATA_KEY = makeStateKey(TRANSFER_STATE_TOKEN_ID);
8819
+ /**
8820
+ * The name of the attribute that would be added to host component
8821
+ * nodes and contain a reference to a particular slot in transferred
8822
+ * state that contains the necessary hydration info for this component.
8823
+ */
8824
+ const NGH_ATTR_NAME = 'ngh';
8825
+ /**
8826
+ * Reference to a function that reads `ngh` attribute value from a given RNode
8827
+ * and retrieves hydration information from the TransferState using that value
8828
+ * as an index. Returns `null` by default, when hydration is not enabled.
8829
+ *
8830
+ * @param rNode Component's host element.
8831
+ * @param injector Injector that this component has access to.
8832
+ */
8833
+ let _retrieveHydrationInfoImpl = (rNode, injector) => null;
8834
+ function retrieveHydrationInfoImpl(rNode, injector) {
8835
+ var _a;
8836
+ const nghAttrValue = rNode.getAttribute(NGH_ATTR_NAME);
8837
+ if (nghAttrValue == null)
8838
+ return null;
8839
+ let data = {};
8840
+ // An element might have an empty `ngh` attribute value (e.g. `<comp ngh="" />`),
8841
+ // which means that no special annotations are required. Do not attempt to read
8842
+ // from the TransferState in this case.
8843
+ if (nghAttrValue !== '') {
8844
+ const transferState = injector.get(TransferState, null, { optional: true });
8845
+ if (transferState !== null) {
8846
+ const nghData = transferState.get(NGH_DATA_KEY, []);
8847
+ // The nghAttrValue is always a number referencing an index
8848
+ // in the hydration TransferState data.
8849
+ data = nghData[Number(nghAttrValue)];
8850
+ // If the `ngh` attribute exists and has a non-empty value,
8851
+ // the hydration info *must* be present in the TransferState.
8852
+ // If there is no data for some reasons, this is an error.
8853
+ ngDevMode && assertDefined(data, 'Unable to retrieve hydration info from the TransferState.');
8854
+ }
8855
+ }
8856
+ const dehydratedView = {
8857
+ data,
8858
+ firstChild: (_a = rNode.firstChild) !== null && _a !== void 0 ? _a : null,
8859
+ };
8860
+ // The `ngh` attribute is cleared from the DOM node now
8861
+ // that the data has been retrieved.
8862
+ rNode.removeAttribute(NGH_ATTR_NAME);
8863
+ // Note: don't check whether this node was claimed for hydration,
8864
+ // because this node might've been previously claimed while processing
8865
+ // template instructions.
8866
+ ngDevMode && markRNodeAsClaimedByHydration(rNode, /* checkIfAlreadyClaimed */ false);
8867
+ ngDevMode && ngDevMode.hydratedComponents++;
8868
+ return dehydratedView;
8869
+ }
8870
+ /**
8871
+ * Sets the implementation for the `retrieveNghInfo` function.
8872
+ */
8873
+ function enableRetrieveHydrationInfoImpl() {
8874
+ _retrieveHydrationInfoImpl = retrieveHydrationInfoImpl;
8875
+ }
8876
+ /**
8877
+ * Retrieves hydration info by reading the value from the `ngh` attribute
8878
+ * and accessing a corresponding slot in TransferState storage.
8879
+ */
8880
+ function retrieveHydrationInfo(rNode, injector) {
8881
+ return _retrieveHydrationInfoImpl(rNode, injector);
8882
+ }
8883
+ /**
8884
+ * Retrieves an instance of a component LView from a given ViewRef.
8885
+ * Returns an instance of a component LView or `null` in case of an embedded view.
8886
+ */
8887
+ function getComponentLViewForHydration(viewRef) {
8888
+ // Reading an internal field from `ViewRef` instance.
8889
+ let lView = viewRef._lView;
8890
+ const tView = lView[TVIEW];
8891
+ // A registered ViewRef might represent an instance of an
8892
+ // embedded view, in which case we do not need to annotate it.
8893
+ if (tView.type === 2 /* TViewType.Embedded */) {
8894
+ return null;
8895
+ }
8896
+ // Check if it's a root view and if so, retrieve component's
8897
+ // LView from the first slot after the header.
8898
+ if (isRootView(lView)) {
8899
+ lView = lView[HEADER_OFFSET];
8900
+ }
8901
+ return lView;
8902
+ }
8903
+ /**
8904
+ * Marks a node as "claimed" by hydration process.
8905
+ * This is needed to make assessments in tests whether
8906
+ * the hydration process handled all nodes.
8907
+ */
8908
+ function markRNodeAsClaimedByHydration(node, checkIfAlreadyClaimed = true) {
8909
+ if (!ngDevMode) {
8910
+ throw new Error('Calling `markRNodeAsClaimedByHydration` in prod mode ' +
8911
+ 'is not supported and likely a mistake.');
8912
+ }
8913
+ if (checkIfAlreadyClaimed && isRNodeClaimedForHydration(node)) {
8914
+ throw new Error('Trying to claim a node, which was claimed already.');
8915
+ }
8916
+ node.__claimed = true;
8917
+ ngDevMode.hydratedNodes++;
8918
+ }
8919
+ function isRNodeClaimedForHydration(node) {
8920
+ return !!node.__claimed;
8921
+ }
8922
+ function storeNgContainerInfo(hydrationInfo, index, firstChild) {
8923
+ var _a;
8924
+ (_a = hydrationInfo.ngContainers) !== null && _a !== void 0 ? _a : (hydrationInfo.ngContainers = {});
8925
+ hydrationInfo.ngContainers[index] = { firstChild };
8926
+ }
8927
+ function getNgContainerSize(hydrationInfo, index) {
8928
+ var _a, _b;
8929
+ return (_b = (_a = hydrationInfo.data[ELEMENT_CONTAINERS]) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : null;
8930
+ }
8931
+
8597
8932
  /**
8598
8933
  * Represents a component created by a `ComponentFactory`.
8599
8934
  * Provides access to the component instance and related objects,
@@ -8773,7 +9108,7 @@ class Version {
8773
9108
  /**
8774
9109
  * @publicApi
8775
9110
  */
8776
- const VERSION = new Version('16.0.0-next.1');
9111
+ const VERSION = new Version('16.0.0-next.2');
8777
9112
 
8778
9113
  // This default value is when checking the hierarchy for a token.
8779
9114
  //
@@ -8854,6 +9189,23 @@ class ErrorHandler {
8854
9189
  }
8855
9190
  }
8856
9191
 
9192
+ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
9193
+ /**
9194
+ * Internal token that specifies whether hydration is enabled.
9195
+ */
9196
+ const IS_HYDRATION_FEATURE_ENABLED = new InjectionToken(NG_DEV_MODE ? 'IS_HYDRATION_FEATURE_ENABLED' : '');
9197
+ // By default (in client rendering mode), we remove all the contents
9198
+ // of the host element and render an application after that.
9199
+ const PRESERVE_HOST_CONTENT_DEFAULT = false;
9200
+ /**
9201
+ * Internal token that indicates whether host element content should be
9202
+ * retained during the bootstrap.
9203
+ */
9204
+ const PRESERVE_HOST_CONTENT = new InjectionToken(NG_DEV_MODE ? 'PRESERVE_HOST_CONTENT' : '', {
9205
+ providedIn: 'root',
9206
+ factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
9207
+ });
9208
+
8857
9209
  function normalizeDebugBindingName(name) {
8858
9210
  // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
8859
9211
  name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
@@ -10505,7 +10857,7 @@ function renderChildComponents(hostLView, components) {
10505
10857
  renderComponent(hostLView, components[i]);
10506
10858
  }
10507
10859
  }
10508
- function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector, embeddedViewInjector) {
10860
+ function createLView(parentLView, tView, context, flags, host, tHostNode, rendererFactory, renderer, sanitizer, injector, embeddedViewInjector, hydrationInfo) {
10509
10861
  const lView = tView.blueprint.slice();
10510
10862
  lView[HOST] = host;
10511
10863
  lView[FLAGS] = flags | 4 /* LViewFlags.CreationMode */ | 64 /* LViewFlags.Attached */ | 8 /* LViewFlags.FirstLViewPass */;
@@ -10525,6 +10877,7 @@ function createLView(parentLView, tView, context, flags, host, tHostNode, render
10525
10877
  lView[INJECTOR$1] = injector || parentLView && parentLView[INJECTOR$1] || null;
10526
10878
  lView[T_HOST] = tHostNode;
10527
10879
  lView[ID] = getUniqueLViewId();
10880
+ lView[HYDRATION] = hydrationInfo;
10528
10881
  lView[EMBEDDED_VIEW_INJECTOR] = embeddedViewInjector;
10529
10882
  ngDevMode &&
10530
10883
  assertEqual(tView.type == 2 /* TViewType.Embedded */ ? parentLView !== null : true, true, 'Embedded views must have parentLView');
@@ -10966,10 +11319,19 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
10966
11319
  * @param rendererFactory Factory function to create renderer instance.
10967
11320
  * @param elementOrSelector Render element or CSS selector to locate the element.
10968
11321
  * @param encapsulation View Encapsulation defined for component that requests host element.
10969
- */
10970
- function locateHostElement(renderer, elementOrSelector, encapsulation) {
10971
- // When using native Shadow DOM, do not clear host element to allow native slot projection
10972
- const preserveContent = encapsulation === ViewEncapsulation.ShadowDom;
11322
+ * @param injector Root view injector instance.
11323
+ */
11324
+ function locateHostElement(renderer, elementOrSelector, encapsulation, injector) {
11325
+ // Note: we use default value for the `PRESERVE_HOST_CONTENT` here even though it's a
11326
+ // tree-shakable one (providedIn:'root'). This code path can be triggered during dynamic component
11327
+ // creation (after calling ViewContainerRef.createComponent) when an injector instance can be
11328
+ // provided. The injector instance might be disconnected from the main DI tree, thus the
11329
+ // `PRESERVE_HOST_CONTENT` woild not be able to instantiate. In this case, the default value will
11330
+ // be used.
11331
+ const preserveHostContent = injector.get(PRESERVE_HOST_CONTENT, PRESERVE_HOST_CONTENT_DEFAULT);
11332
+ // When using native Shadow DOM, do not clear host element to allow native slot
11333
+ // projection.
11334
+ const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation.ShadowDom;
10973
11335
  return renderer.selectRootElement(elementOrSelector, preserveContent);
10974
11336
  }
10975
11337
  /**
@@ -11026,7 +11388,7 @@ function createTNode(tView, tParent, type, index, value, attrs) {
11026
11388
  initialInputs: undefined,
11027
11389
  inputs: null,
11028
11390
  outputs: null,
11029
- tViews: null,
11391
+ tView: null,
11030
11392
  next: null,
11031
11393
  prev: null,
11032
11394
  projectionNext: null,
@@ -11570,7 +11932,7 @@ function addComponentLogic(lView, hostTNode, def) {
11570
11932
  // Only component views should be added to the view tree directly. Embedded views are
11571
11933
  // accessed through their containers because they may be removed / re-added later.
11572
11934
  const rendererFactory = lView[RENDERER_FACTORY];
11573
- const componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, native, hostTNode, rendererFactory, rendererFactory.createRenderer(native, def), null, null, null));
11935
+ const componentView = addToViewTree(lView, createLView(lView, tView, null, def.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, native, hostTNode, rendererFactory, rendererFactory.createRenderer(native, def), null, null, null, null));
11574
11936
  // Component view will always be created before any injected LContainers,
11575
11937
  // so this is a regular element, wrap it with the component view
11576
11938
  lView[hostTNode.index] = componentView;
@@ -11815,6 +12177,11 @@ function renderComponent(hostLView, componentHostIdx) {
11815
12177
  const componentView = getComponentLViewByIndex(componentHostIdx, hostLView);
11816
12178
  const componentTView = componentView[TVIEW];
11817
12179
  syncViewWithBlueprint(componentTView, componentView);
12180
+ const hostRNode = componentView[HOST];
12181
+ // Populate an LView with hydration info retrieved from the DOM via TransferState.
12182
+ if (hostRNode !== null && componentView[HYDRATION] === null) {
12183
+ componentView[HYDRATION] = retrieveHydrationInfo(hostRNode, componentView[INJECTOR$1]);
12184
+ }
11818
12185
  renderView(componentTView, componentView, componentView[CONTEXT]);
11819
12186
  }
11820
12187
  /**
@@ -12515,13 +12882,13 @@ class ComponentFactory extends ComponentFactory$1 {
12515
12882
  // dynamically. Default to 'div' if this component did not specify any tag name in its selector.
12516
12883
  const elementName = this.componentDef.selectors[0][0] || 'div';
12517
12884
  const hostRNode = rootSelectorOrNode ?
12518
- locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation) :
12885
+ locateHostElement(hostRenderer, rootSelectorOrNode, this.componentDef.encapsulation, rootViewInjector) :
12519
12886
  createElementNode(hostRenderer, elementName, getNamespace(elementName));
12520
12887
  const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
12521
12888
  16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
12522
12889
  // Create the root view. Uses empty TView and ContentTemplate.
12523
12890
  const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
12524
- const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null);
12891
+ const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null, null);
12525
12892
  // rootView is the parent when bootstrapping
12526
12893
  // TODO(misko): it looks like we are entering view here but we don't really need to as
12527
12894
  // `renderView` does that. However as the code is written it is needed because
@@ -12632,7 +12999,7 @@ function createRootComponentTNode(lView, rNode) {
12632
12999
  /**
12633
13000
  * Creates the root component view and the root component node.
12634
13001
  *
12635
- * @param rNode Render host element.
13002
+ * @param hostRNode Render host element.
12636
13003
  * @param rootComponentDef ComponentDef
12637
13004
  * @param rootView The parent view where the host node is stored
12638
13005
  * @param rendererFactory Factory to be used for creating child renderers.
@@ -12641,11 +13008,17 @@ function createRootComponentTNode(lView, rNode) {
12641
13008
  *
12642
13009
  * @returns Component view created
12643
13010
  */
12644
- function createRootComponentView(tNode, rNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
13011
+ function createRootComponentView(tNode, hostRNode, rootComponentDef, rootDirectives, rootView, rendererFactory, hostRenderer, sanitizer) {
12645
13012
  const tView = rootView[TVIEW];
12646
- applyRootComponentStyling(rootDirectives, tNode, rNode, hostRenderer);
12647
- const viewRenderer = rendererFactory.createRenderer(rNode, rootComponentDef);
12648
- const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, rootComponentDef.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[tNode.index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null);
13013
+ applyRootComponentStyling(rootDirectives, tNode, hostRNode, hostRenderer);
13014
+ // Hydration info is on the host element and needs to be retreived
13015
+ // and passed to the component LView.
13016
+ let hydrationInfo = null;
13017
+ if (hostRNode !== null) {
13018
+ hydrationInfo = retrieveHydrationInfo(hostRNode, rootView[INJECTOR$1]);
13019
+ }
13020
+ const viewRenderer = rendererFactory.createRenderer(hostRNode, rootComponentDef);
13021
+ const componentView = createLView(rootView, getOrCreateComponentTView(rootComponentDef), null, rootComponentDef.onPush ? 32 /* LViewFlags.Dirty */ : 16 /* LViewFlags.CheckAlways */, rootView[tNode.index], tNode, rendererFactory, viewRenderer, sanitizer || null, null, null, hydrationInfo);
12649
13022
  if (tView.firstCreatePass) {
12650
13023
  markAsComponentHost(tView, tNode, rootDirectives.length - 1);
12651
13024
  }
@@ -13807,7 +14180,7 @@ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, t
13807
14180
  const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
13808
14181
  resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13809
14182
  registerPostOrderHooks(tView, tNode);
13810
- const embeddedTView = tNode.tViews = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
14183
+ const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
13811
14184
  if (tView.queries !== null) {
13812
14185
  tView.queries.template(tView, tNode);
13813
14186
  embeddedTView.queries = tView.queries.embeddedTView(tNode);
@@ -13877,6 +14250,122 @@ function ɵɵreference(index) {
13877
14250
  return load(contextLView, HEADER_OFFSET + index);
13878
14251
  }
13879
14252
 
14253
+ /**
14254
+ * Verifies whether a given node matches an expected criteria,
14255
+ * based on internal data structure state.
14256
+ */
14257
+ function validateMatchingNode(node, nodeType, tagName, lView, tNode) {
14258
+ if (node.nodeType !== nodeType ||
14259
+ (node.nodeType === Node.ELEMENT_NODE &&
14260
+ node.tagName.toLowerCase() !== (tagName === null || tagName === void 0 ? void 0 : tagName.toLowerCase()))) {
14261
+ // TODO: improve error message and use RuntimeError instead.
14262
+ throw new Error(`Unexpected node found during hydration.`);
14263
+ }
14264
+ }
14265
+ /**
14266
+ * Verifies whether next sibling node exists.
14267
+ */
14268
+ function validateSiblingNodeExists(node) {
14269
+ if (!node.nextSibling) {
14270
+ // TODO: improve error message and use RuntimeError instead.
14271
+ throw new Error(`Unexpected state: insufficient number of sibling nodes.`);
14272
+ }
14273
+ }
14274
+
14275
+ /** Whether current TNode is a first node in an <ng-container>. */
14276
+ function isFirstElementInNgContainer(tNode) {
14277
+ var _a;
14278
+ return !tNode.prev && ((_a = tNode.parent) === null || _a === void 0 ? void 0 : _a.type) === 8 /* TNodeType.ElementContainer */;
14279
+ }
14280
+ /** Returns first element from a DOM segment that corresponds to this <ng-container>. */
14281
+ function getDehydratedNgContainer(hydrationInfo, tContainerNode) {
14282
+ var _a;
14283
+ const noOffsetIndex = tContainerNode.index - HEADER_OFFSET;
14284
+ const ngContainer = (_a = hydrationInfo.ngContainers) === null || _a === void 0 ? void 0 : _a[noOffsetIndex];
14285
+ ngDevMode &&
14286
+ assertDefined(ngContainer, 'Unexpected state: no hydration info available for a given TNode, ' +
14287
+ 'which represents an element container.');
14288
+ return ngContainer;
14289
+ }
14290
+ /**
14291
+ * Locate a node in DOM tree that corresponds to a given TNode.
14292
+ *
14293
+ * @param hydrationInfo The hydration annotation data
14294
+ * @param tView the current tView
14295
+ * @param lView the current lView
14296
+ * @param tNode the current tNode
14297
+ * @returns an RNode that represents a given tNode
14298
+ */
14299
+ function locateNextRNode(hydrationInfo, tView, lView, tNode) {
14300
+ var _a, _b;
14301
+ let native = null;
14302
+ if (tView.firstChild === tNode) {
14303
+ // We create a first node in this view, so we use a reference
14304
+ // to the first child in this DOM segment.
14305
+ native = hydrationInfo.firstChild;
14306
+ }
14307
+ else {
14308
+ // Locate a node based on a previous sibling or a parent node.
14309
+ const previousTNodeParent = tNode.prev === null;
14310
+ const previousTNode = ((_a = tNode.prev) !== null && _a !== void 0 ? _a : tNode.parent);
14311
+ ngDevMode &&
14312
+ assertDefined(previousTNode, 'Unexpected state: current TNode does not have a connection ' +
14313
+ 'to the previous node or a parent node.');
14314
+ const previousRElement = getNativeByTNode(previousTNode, lView);
14315
+ if (isFirstElementInNgContainer(tNode)) {
14316
+ const ngContainer = getDehydratedNgContainer(hydrationInfo, tNode.parent);
14317
+ native = (_b = ngContainer.firstChild) !== null && _b !== void 0 ? _b : null;
14318
+ }
14319
+ else {
14320
+ if (previousTNodeParent) {
14321
+ native = previousRElement.firstChild;
14322
+ }
14323
+ else {
14324
+ native = previousRElement.nextSibling;
14325
+ }
14326
+ }
14327
+ }
14328
+ return native;
14329
+ }
14330
+ /**
14331
+ * Skips over a specified number of nodes and returns the next sibling node after that.
14332
+ */
14333
+ function siblingAfter(skip, from) {
14334
+ let currentNode = from;
14335
+ for (let i = 0; i < skip; i++) {
14336
+ ngDevMode && validateSiblingNodeExists(currentNode);
14337
+ currentNode = currentNode.nextSibling;
14338
+ }
14339
+ return currentNode;
14340
+ }
14341
+
14342
+ /**
14343
+ * The name of an attribute that can be added to the hydration boundary node
14344
+ * (component host node) to disable hydration for the content within that boundary.
14345
+ */
14346
+ const SKIP_HYDRATION_ATTR_NAME = 'ngSkipHydration';
14347
+ /**
14348
+ * Helper function to check if a given node has the 'ngSkipHydration' attribute
14349
+ */
14350
+ function hasNgSkipHydrationAttr(tNode) {
14351
+ const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE = SKIP_HYDRATION_ATTR_NAME.toLowerCase();
14352
+ const attrs = tNode.mergedAttrs;
14353
+ if (attrs === null)
14354
+ return false;
14355
+ // only ever look at the attribute name and skip the values
14356
+ for (let i = 0; i < attrs.length; i += 2) {
14357
+ const value = attrs[i];
14358
+ // This is a marker, which means that the static attributes section is over,
14359
+ // so we can exit early.
14360
+ if (typeof value === 'number')
14361
+ return false;
14362
+ if (typeof value === 'string' && value.toLowerCase() === SKIP_HYDRATION_ATTR_NAME_LOWER_CASE) {
14363
+ return true;
14364
+ }
14365
+ }
14366
+ return false;
14367
+ }
14368
+
13880
14369
  /**
13881
14370
  * Update a property on a selected element.
13882
14371
  *
@@ -13961,14 +14450,15 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
13961
14450
  const tNode = tView.firstCreatePass ?
13962
14451
  elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex) :
13963
14452
  tView.data[adjustedIndex];
13964
- const native = lView[adjustedIndex] = createElementNode(renderer, name, getNamespace$1());
14453
+ const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name);
14454
+ lView[adjustedIndex] = native;
13965
14455
  const hasDirectives = isDirectiveHost(tNode);
13966
14456
  if (ngDevMode && tView.firstCreatePass) {
13967
14457
  validateElementIsKnown(native, lView, tNode.value, tView.schemas, hasDirectives);
13968
14458
  }
13969
14459
  setCurrentTNode(tNode, true);
13970
14460
  setupStaticAttributes(renderer, native, tNode);
13971
- if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */) {
14461
+ if ((tNode.flags & 32 /* TNodeFlags.isDetached */) !== 32 /* TNodeFlags.isDetached */ && wasLastNodeCreated()) {
13972
14462
  // In the i18n case, the translation may have removed this element, so only add it if it is not
13973
14463
  // detached. See `TNodeType.Placeholder` and `LFrame.inI18n` for more context.
13974
14464
  appendChild(tView, lView, native, tNode);
@@ -14008,6 +14498,9 @@ function ɵɵelementEnd() {
14008
14498
  }
14009
14499
  const tNode = currentTNode;
14010
14500
  ngDevMode && assertTNodeType(tNode, 3 /* TNodeType.AnyRNode */);
14501
+ if (isSkipHydrationRootTNode(tNode)) {
14502
+ leaveSkipHydrationBlock();
14503
+ }
14011
14504
  decreaseElementDepthCount();
14012
14505
  const tView = getTView();
14013
14506
  if (tView.firstCreatePass) {
@@ -14040,6 +14533,40 @@ function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
14040
14533
  ɵɵelementEnd();
14041
14534
  return ɵɵelement;
14042
14535
  }
14536
+ let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name) => {
14537
+ lastNodeWasCreated(true);
14538
+ return createElementNode(renderer, name, getNamespace$1());
14539
+ };
14540
+ /**
14541
+ * Enables hydration code path (to lookup existing elements in DOM)
14542
+ * in addition to the regular creation mode of element nodes.
14543
+ */
14544
+ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name) {
14545
+ const hydrationInfo = lView[HYDRATION];
14546
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14547
+ lastNodeWasCreated(isNodeCreationMode);
14548
+ // Regular creation mode.
14549
+ if (isNodeCreationMode) {
14550
+ return createElementNode(renderer, name, getNamespace$1());
14551
+ }
14552
+ // Hydration mode, looking up an existing element in DOM.
14553
+ const native = locateNextRNode(hydrationInfo, tView, lView, tNode);
14554
+ ngDevMode &&
14555
+ validateMatchingNode(native, Node.ELEMENT_NODE, name, lView, tNode);
14556
+ ngDevMode && markRNodeAsClaimedByHydration(native);
14557
+ // Checks if the skip hydration attribute is present during hydration so we know to
14558
+ // skip attempting to hydrate this block.
14559
+ if (hydrationInfo && hasNgSkipHydrationAttr(tNode)) {
14560
+ enterSkipHydrationBlock(tNode);
14561
+ // Since this isn't hydratable, we need to empty the node
14562
+ // so there's no duplicate content after render
14563
+ clearElementContents(renderer, native);
14564
+ }
14565
+ return native;
14566
+ }
14567
+ function enableLocateOrCreateElementNodeImpl() {
14568
+ _locateOrCreateElementNode = locateOrCreateElementNodeImpl;
14569
+ }
14043
14570
 
14044
14571
  function elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) {
14045
14572
  ngDevMode && ngDevMode.firstCreatePass++;
@@ -14085,10 +14612,12 @@ function ɵɵelementContainerStart(index, attrsIndex, localRefsIndex) {
14085
14612
  tView.data[adjustedIndex];
14086
14613
  setCurrentTNode(tNode, true);
14087
14614
  ngDevMode && ngDevMode.rendererCreateComment++;
14088
- const native = lView[adjustedIndex] =
14089
- lView[RENDERER].createComment(ngDevMode ? 'ng-container' : '');
14090
- appendChild(tView, lView, native, tNode);
14091
- attachPatchData(native, lView);
14615
+ const comment = _locateOrCreateElementContainerNode(tView, lView, tNode, index);
14616
+ lView[adjustedIndex] = comment;
14617
+ if (wasLastNodeCreated()) {
14618
+ appendChild(tView, lView, comment, tNode);
14619
+ }
14620
+ attachPatchData(comment, lView);
14092
14621
  if (isDirectiveHost(tNode)) {
14093
14622
  createDirectivesInstances(tView, lView, tNode);
14094
14623
  executeContentQueries(tView, tNode, lView);
@@ -14140,6 +14669,46 @@ function ɵɵelementContainer(index, attrsIndex, localRefsIndex) {
14140
14669
  ɵɵelementContainerEnd();
14141
14670
  return ɵɵelementContainer;
14142
14671
  }
14672
+ let _locateOrCreateElementContainerNode = (tView, lView, tNode, index) => {
14673
+ lastNodeWasCreated(true);
14674
+ return createCommentNode(lView[RENDERER], ngDevMode ? 'ng-container' : '');
14675
+ };
14676
+ /**
14677
+ * Enables hydration code path (to lookup existing elements in DOM)
14678
+ * in addition to the regular creation mode of comment nodes that
14679
+ * represent <ng-container>'s anchor.
14680
+ */
14681
+ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
14682
+ let comment;
14683
+ const hydrationInfo = lView[HYDRATION];
14684
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14685
+ lastNodeWasCreated(isNodeCreationMode);
14686
+ // Regular creation mode.
14687
+ if (isNodeCreationMode) {
14688
+ return createCommentNode(lView[RENDERER], ngDevMode ? 'ng-container' : '');
14689
+ }
14690
+ // Hydration mode, looking up existing elements in DOM.
14691
+ const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
14692
+ const ngContainerSize = getNgContainerSize(hydrationInfo, index);
14693
+ ngDevMode &&
14694
+ assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
14695
+ 'but no hydration info is available.');
14696
+ if (ngContainerSize > 0) {
14697
+ storeNgContainerInfo(hydrationInfo, index, currentRNode);
14698
+ comment = siblingAfter(ngContainerSize, currentRNode);
14699
+ }
14700
+ else {
14701
+ // If <ng-container> has no nodes,
14702
+ // the current node is an anchor (comment) node.
14703
+ comment = currentRNode;
14704
+ }
14705
+ ngDevMode && validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14706
+ ngDevMode && markRNodeAsClaimedByHydration(comment);
14707
+ return comment;
14708
+ }
14709
+ function enableLocateOrCreateElementContainerNodeImpl() {
14710
+ _locateOrCreateElementContainerNode = locateOrCreateElementContainerNode;
14711
+ }
14143
14712
 
14144
14713
  /**
14145
14714
  * Returns the current OpaqueViewState instance.
@@ -14168,16 +14737,6 @@ function isPromise(obj) {
14168
14737
  function isSubscribable(obj) {
14169
14738
  return !!obj && typeof obj.subscribe === 'function';
14170
14739
  }
14171
- /**
14172
- * Determine if the argument is an Observable
14173
- *
14174
- * Strictly this tests that the `obj` is `Subscribable`, since `Observable`
14175
- * types need additional methods, such as `lift()`. But it is adequate for our
14176
- * needs since within the Angular framework code we only ever need to use the
14177
- * `subscribe()` method, and RxJS has mechanisms to wrap `Subscribable` objects
14178
- * into `Observable` as needed.
14179
- */
14180
- const isObservable = isSubscribable;
14181
14740
 
14182
14741
  /**
14183
14742
  * Adds an event listener to the current node.
@@ -14340,7 +14899,7 @@ function listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn,
14340
14899
  const minifiedName = props[i + 1];
14341
14900
  const directiveInstance = lView[index];
14342
14901
  const output = directiveInstance[minifiedName];
14343
- if (ngDevMode && !isObservable(output)) {
14902
+ if (ngDevMode && !isSubscribable(output)) {
14344
14903
  throw new Error(`@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`);
14345
14904
  }
14346
14905
  const subscription = output.subscribe(listenerFn);
@@ -16484,11 +17043,39 @@ function ɵɵtext(index, value = '') {
16484
17043
  const tNode = tView.firstCreatePass ?
16485
17044
  getOrCreateTNode(tView, adjustedIndex, 1 /* TNodeType.Text */, value, null) :
16486
17045
  tView.data[adjustedIndex];
16487
- const textNative = lView[adjustedIndex] = createTextNode(lView[RENDERER], value);
16488
- appendChild(tView, lView, textNative, tNode);
17046
+ const textNative = _locateOrCreateTextNode(tView, lView, tNode, value);
17047
+ lView[adjustedIndex] = textNative;
17048
+ if (wasLastNodeCreated()) {
17049
+ appendChild(tView, lView, textNative, tNode);
17050
+ }
16489
17051
  // Text nodes are self closing.
16490
17052
  setCurrentTNode(tNode, false);
16491
17053
  }
17054
+ let _locateOrCreateTextNode = (tView, lView, tNode, value) => {
17055
+ lastNodeWasCreated(true);
17056
+ return createTextNode(lView[RENDERER], value);
17057
+ };
17058
+ /**
17059
+ * Enables hydration code path (to lookup existing elements in DOM)
17060
+ * in addition to the regular creation mode of text nodes.
17061
+ */
17062
+ function locateOrCreateTextNodeImpl(tView, lView, tNode, value) {
17063
+ const hydrationInfo = lView[HYDRATION];
17064
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
17065
+ lastNodeWasCreated(isNodeCreationMode);
17066
+ // Regular creation mode.
17067
+ if (isNodeCreationMode) {
17068
+ return createTextNode(lView[RENDERER], value);
17069
+ }
17070
+ // Hydration mode, looking up an existing element in DOM.
17071
+ const textNative = locateNextRNode(hydrationInfo, tView, lView, tNode);
17072
+ ngDevMode && validateMatchingNode(textNative, Node.TEXT_NODE, null, lView, tNode);
17073
+ ngDevMode && markRNodeAsClaimedByHydration(textNative);
17074
+ return textNative;
17075
+ }
17076
+ function enableLocateOrCreateTextNodeImpl() {
17077
+ _locateOrCreateTextNode = locateOrCreateTextNodeImpl;
17078
+ }
16492
17079
 
16493
17080
  /**
16494
17081
  *
@@ -18166,7 +18753,7 @@ function getTIcu(tView, index) {
18166
18753
  if (value === null || typeof value === 'string')
18167
18754
  return null;
18168
18755
  if (ngDevMode &&
18169
- !(value.hasOwnProperty('tViews') || value.hasOwnProperty('currentCaseLViewIndex'))) {
18756
+ !(value.hasOwnProperty('tView') || value.hasOwnProperty('currentCaseLViewIndex'))) {
18170
18757
  throwError('We expect to get \'null\'|\'TIcu\'|\'TIcuContainer\', but got: ' + value);
18171
18758
  }
18172
18759
  // Here the `value.hasOwnProperty('currentCaseLViewIndex')` is a polymorphic read as it can be
@@ -18195,7 +18782,7 @@ function getTIcu(tView, index) {
18195
18782
  function setTIcu(tView, index, tIcu) {
18196
18783
  const tNode = tView.data[index];
18197
18784
  ngDevMode &&
18198
- assertEqual(tNode === null || tNode.hasOwnProperty('tViews'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
18785
+ assertEqual(tNode === null || tNode.hasOwnProperty('tView'), true, 'We expect to get \'null\'|\'TIcuContainer\'');
18199
18786
  if (tNode === null) {
18200
18787
  tView.data[index] = tIcu;
18201
18788
  }
@@ -21491,8 +22078,8 @@ const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
21491
22078
  this.elementRef = elementRef;
21492
22079
  }
21493
22080
  createEmbeddedView(context, injector) {
21494
- const embeddedTView = this._declarationTContainer.tViews;
21495
- const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null);
22081
+ const embeddedTView = this._declarationTContainer.tView;
22082
+ const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null, null);
21496
22083
  const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
21497
22084
  ngDevMode && assertLContainer(declarationLContainer);
21498
22085
  embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
@@ -21521,7 +22108,7 @@ function injectTemplateRef() {
21521
22108
  */
21522
22109
  function createTemplateRef(hostTNode, hostLView) {
21523
22110
  if (hostTNode.type & 4 /* TNodeType.Container */) {
21524
- ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
22111
+ ngDevMode && assertDefined(hostTNode.tView, 'TView must be allocated');
21525
22112
  return new R3TemplateRef(hostLView, hostTNode, createElementRef(hostTNode, hostLView));
21526
22113
  }
21527
22114
  return null;