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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/esm2020/src/application_ref.mjs +95 -87
  2. package/esm2020/src/application_tokens.mjs +27 -21
  3. package/esm2020/src/compiler/compiler_facade_interface.mjs +1 -1
  4. package/esm2020/src/core_private_export.mjs +2 -3
  5. package/esm2020/src/di/contextual.mjs +37 -0
  6. package/esm2020/src/di/index.mjs +2 -1
  7. package/esm2020/src/di/r3_injector.mjs +1 -1
  8. package/esm2020/src/errors.mjs +1 -1
  9. package/esm2020/src/hydration/annotate.mjs +136 -5
  10. package/esm2020/src/hydration/api.mjs +9 -1
  11. package/esm2020/src/hydration/cleanup.mjs +50 -0
  12. package/esm2020/src/hydration/error_handling.mjs +11 -3
  13. package/esm2020/src/hydration/interfaces.mjs +9 -2
  14. package/esm2020/src/hydration/node_lookup_utils.mjs +22 -14
  15. package/esm2020/src/hydration/skip_hydration.mjs +16 -1
  16. package/esm2020/src/hydration/utils.mjs +82 -7
  17. package/esm2020/src/hydration/views.mjs +80 -0
  18. package/esm2020/src/linker/template_ref.mjs +17 -2
  19. package/esm2020/src/linker/view_container_ref.mjs +110 -35
  20. package/esm2020/src/render3/component_ref.mjs +2 -2
  21. package/esm2020/src/render3/definition.mjs +114 -45
  22. package/esm2020/src/render3/instructions/element.mjs +18 -8
  23. package/esm2020/src/render3/instructions/element_container.mjs +12 -13
  24. package/esm2020/src/render3/instructions/shared.mjs +53 -16
  25. package/esm2020/src/render3/instructions/template.mjs +57 -6
  26. package/esm2020/src/render3/instructions/text.mjs +1 -1
  27. package/esm2020/src/render3/interfaces/container.mjs +3 -2
  28. package/esm2020/src/render3/interfaces/type_checks.mjs +2 -2
  29. package/esm2020/src/render3/interfaces/view.mjs +1 -1
  30. package/esm2020/src/render3/jit/module.mjs +3 -2
  31. package/esm2020/src/render3/ng_module_ref.mjs +9 -5
  32. package/esm2020/src/render3/util/discovery_utils.mjs +3 -2
  33. package/esm2020/src/util/ng_dev_mode.mjs +2 -1
  34. package/esm2020/src/version.mjs +1 -1
  35. package/esm2020/src/zone/ng_zone.mjs +62 -1
  36. package/esm2020/testing/src/logger.mjs +3 -3
  37. package/esm2020/testing/src/ng_zone_mock.mjs +3 -3
  38. package/esm2020/testing/src/test_bed_compiler.mjs +4 -4
  39. package/fesm2015/core.mjs +2354 -1657
  40. package/fesm2015/core.mjs.map +1 -1
  41. package/fesm2015/testing.mjs +1910 -1415
  42. package/fesm2015/testing.mjs.map +1 -1
  43. package/fesm2020/core.mjs +2288 -1581
  44. package/fesm2020/core.mjs.map +1 -1
  45. package/fesm2020/testing.mjs +5085 -4581
  46. package/fesm2020/testing.mjs.map +1 -1
  47. package/index.d.ts +370 -400
  48. package/package.json +1 -1
  49. package/schematics/ng-generate/standalone-migration/bundle.js +198 -99
  50. package/schematics/ng-generate/standalone-migration/bundle.js.map +3 -3
  51. package/testing/index.d.ts +1 -1
package/fesm2020/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v16.0.0-next.2
2
+ * @license Angular v16.0.0-next.3
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -557,6 +557,7 @@ function ngDevModeResetPerfCounters() {
557
557
  rendererCreateComment: 0,
558
558
  hydratedNodes: 0,
559
559
  hydratedComponents: 0,
560
+ dehydratedViewsRemoved: 0,
560
561
  };
561
562
  // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
562
563
  const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
@@ -938,238 +939,847 @@ const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafe
938
939
  */
939
940
  const NG_ENV_ID = getClosureSafeProperty({ __NG_ENV_ID__: getClosureSafeProperty });
940
941
 
941
- /** Counter used to generate unique IDs for component definitions. */
942
- let componentDefCount = 0;
943
942
  /**
944
- * Create a component definition object.
945
- *
946
- *
947
- * # Example
948
- * ```
949
- * class MyDirective {
950
- * // Generated by Angular Template Compiler
951
- * // [Symbol] syntax will not be supported by TypeScript until v2.7
952
- * static ɵcmp = defineComponent({
953
- * ...
954
- * });
955
- * }
956
- * ```
957
- * @codeGenApi
958
- */
959
- function ɵɵdefineComponent(componentDefinition) {
960
- return noSideEffects(() => {
961
- // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
962
- // See the `initNgDevMode` docstring for more information.
963
- (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
964
- const type = componentDefinition.type;
965
- const standalone = componentDefinition.standalone === true;
966
- const declaredInputs = {};
967
- const def = {
968
- type: type,
969
- providersResolver: null,
970
- decls: componentDefinition.decls,
971
- vars: componentDefinition.vars,
972
- factory: null,
973
- template: componentDefinition.template || null,
974
- consts: componentDefinition.consts || null,
975
- ngContentSelectors: componentDefinition.ngContentSelectors,
976
- hostBindings: componentDefinition.hostBindings || null,
977
- hostVars: componentDefinition.hostVars || 0,
978
- hostAttrs: componentDefinition.hostAttrs || null,
979
- contentQueries: componentDefinition.contentQueries || null,
980
- declaredInputs: declaredInputs,
981
- inputs: null,
982
- outputs: null,
983
- exportAs: componentDefinition.exportAs || null,
984
- onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
985
- directiveDefs: null,
986
- pipeDefs: null,
987
- standalone,
988
- dependencies: standalone && componentDefinition.dependencies || null,
989
- getStandaloneInjector: null,
990
- selectors: componentDefinition.selectors || EMPTY_ARRAY,
991
- viewQuery: componentDefinition.viewQuery || null,
992
- features: componentDefinition.features || null,
993
- data: componentDefinition.data || {},
994
- encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
995
- id: `c${componentDefCount++}`,
996
- styles: componentDefinition.styles || EMPTY_ARRAY,
997
- _: null,
998
- setInput: null,
999
- schemas: componentDefinition.schemas || null,
1000
- tView: null,
1001
- findHostDirectiveDefs: null,
1002
- hostDirectives: null,
1003
- };
1004
- const dependencies = componentDefinition.dependencies;
1005
- const feature = componentDefinition.features;
1006
- def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
1007
- def.outputs = invertObject(componentDefinition.outputs),
1008
- feature && feature.forEach((fn) => fn(def));
1009
- def.directiveDefs = dependencies ?
1010
- (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
1011
- .map(extractDirectiveDef)
1012
- .filter(nonNull)) :
1013
- null;
1014
- def.pipeDefs = dependencies ?
1015
- (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
1016
- .map(getPipeDef$1)
1017
- .filter(nonNull)) :
1018
- null;
1019
- return def;
1020
- });
1021
- }
1022
- /**
1023
- * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
1024
- * definition, when generating a direct reference in the component file would otherwise create an
1025
- * import cycle.
1026
- *
1027
- * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
1028
- *
1029
- * @codeGenApi
1030
- */
1031
- function ɵɵsetComponentScope(type, directives, pipes) {
1032
- const def = type.ɵcmp;
1033
- def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef);
1034
- def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1);
1035
- }
1036
- function extractDirectiveDef(type) {
1037
- return getComponentDef(type) || getDirectiveDef(type);
1038
- }
1039
- function nonNull(value) {
1040
- return value !== null;
1041
- }
1042
- /**
1043
- * @codeGenApi
1044
- */
1045
- function ɵɵdefineNgModule(def) {
1046
- return noSideEffects(() => {
1047
- const res = {
1048
- type: def.type,
1049
- bootstrap: def.bootstrap || EMPTY_ARRAY,
1050
- declarations: def.declarations || EMPTY_ARRAY,
1051
- imports: def.imports || EMPTY_ARRAY,
1052
- exports: def.exports || EMPTY_ARRAY,
1053
- transitiveCompileScopes: null,
1054
- schemas: def.schemas || null,
1055
- id: def.id || null,
1056
- };
1057
- return res;
1058
- });
1059
- }
1060
- /**
1061
- * Adds the module metadata that is necessary to compute the module's transitive scope to an
1062
- * existing module definition.
943
+ * Returns an index of `classToSearch` in `className` taking token boundaries into account.
1063
944
  *
1064
- * Scope metadata of modules is not used in production builds, so calls to this function can be
1065
- * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
1066
- * to become eligible for tree-shaking as well.
945
+ * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
1067
946
  *
1068
- * @codeGenApi
947
+ * @param className A string containing classes (whitespace separated)
948
+ * @param classToSearch A class name to locate
949
+ * @param startingIndex Starting location of search
950
+ * @returns an index of the located class (or -1 if not found)
1069
951
  */
1070
- function ɵɵsetNgModuleScope(type, scope) {
1071
- return noSideEffects(() => {
1072
- const ngModuleDef = getNgModuleDef(type, true);
1073
- ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
1074
- ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
1075
- ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
1076
- });
952
+ function classIndexOf(className, classToSearch, startingIndex) {
953
+ ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
954
+ let end = className.length;
955
+ while (true) {
956
+ const foundIndex = className.indexOf(classToSearch, startingIndex);
957
+ if (foundIndex === -1)
958
+ return foundIndex;
959
+ if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
960
+ // Ensure that it has leading whitespace
961
+ const length = classToSearch.length;
962
+ if (foundIndex + length === end ||
963
+ className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
964
+ // Ensure that it has trailing whitespace
965
+ return foundIndex;
966
+ }
967
+ }
968
+ // False positive, keep searching from where we left off.
969
+ startingIndex = foundIndex + 1;
970
+ }
1077
971
  }
972
+
1078
973
  /**
1079
- * Inverts an inputs or outputs lookup such that the keys, which were the
1080
- * minified keys, are part of the values, and the values are parsed so that
1081
- * the publicName of the property is the new key
1082
- *
1083
- * e.g. for
1084
- *
1085
- * ```
1086
- * class Comp {
1087
- * @Input()
1088
- * propName1: string;
1089
- *
1090
- * @Input('publicName2')
1091
- * declaredPropName2: number;
1092
- * }
1093
- * ```
1094
- *
1095
- * will be serialized as
1096
- *
1097
- * ```
1098
- * {
1099
- * propName1: 'propName1',
1100
- * declaredPropName2: ['publicName2', 'declaredPropName2'],
1101
- * }
1102
- * ```
1103
- *
1104
- * which is than translated by the minifier as:
974
+ * Assigns all attribute values to the provided element via the inferred renderer.
1105
975
  *
1106
- * ```
1107
- * {
1108
- * minifiedPropName1: 'propName1',
1109
- * minifiedPropName2: ['publicName2', 'declaredPropName2'],
1110
- * }
1111
- * ```
976
+ * This function accepts two forms of attribute entries:
1112
977
  *
1113
- * becomes: (public name => minifiedName)
978
+ * default: (key, value):
979
+ * attrs = [key1, value1, key2, value2]
1114
980
  *
1115
- * ```
1116
- * {
1117
- * 'propName1': 'minifiedPropName1',
1118
- * 'publicName2': 'minifiedPropName2',
1119
- * }
1120
- * ```
981
+ * namespaced: (NAMESPACE_MARKER, uri, name, value)
982
+ * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
1121
983
  *
1122
- * Optionally the function can take `secondary` which will result in: (public name => declared name)
984
+ * The `attrs` array can contain a mix of both the default and namespaced entries.
985
+ * The "default" values are set without a marker, but if the function comes across
986
+ * a marker value then it will attempt to set a namespaced value. If the marker is
987
+ * not of a namespaced value then the function will quit and return the index value
988
+ * where it stopped during the iteration of the attrs array.
1123
989
  *
1124
- * ```
1125
- * {
1126
- * 'propName1': 'propName1',
1127
- * 'publicName2': 'declaredPropName2',
1128
- * }
1129
- * ```
990
+ * See [AttributeMarker] to understand what the namespace marker value is.
1130
991
  *
1131
-
992
+ * Note that this instruction does not support assigning style and class values to
993
+ * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
994
+ * are applied to an element.
995
+ * @param renderer The renderer to be used
996
+ * @param native The element that the attributes will be assigned to
997
+ * @param attrs The attribute array of values that will be assigned to the element
998
+ * @returns the index value that was last accessed in the attributes array
1132
999
  */
1133
- function invertObject(obj, secondary) {
1134
- if (obj == null)
1135
- return EMPTY_OBJ;
1136
- const newLookup = {};
1137
- for (const minifiedKey in obj) {
1138
- if (obj.hasOwnProperty(minifiedKey)) {
1139
- let publicName = obj[minifiedKey];
1140
- let declaredName = publicName;
1141
- if (Array.isArray(publicName)) {
1142
- declaredName = publicName[1];
1143
- publicName = publicName[0];
1000
+ function setUpAttributes(renderer, native, attrs) {
1001
+ let i = 0;
1002
+ while (i < attrs.length) {
1003
+ const value = attrs[i];
1004
+ if (typeof value === 'number') {
1005
+ // only namespaces are supported. Other value types (such as style/class
1006
+ // entries) are not supported in this function.
1007
+ if (value !== 0 /* AttributeMarker.NamespaceURI */) {
1008
+ break;
1144
1009
  }
1145
- newLookup[publicName] = minifiedKey;
1146
- if (secondary) {
1147
- (secondary[publicName] = declaredName);
1010
+ // we just landed on the marker value ... therefore
1011
+ // we should skip to the next entry
1012
+ i++;
1013
+ const namespaceURI = attrs[i++];
1014
+ const attrName = attrs[i++];
1015
+ const attrVal = attrs[i++];
1016
+ ngDevMode && ngDevMode.rendererSetAttribute++;
1017
+ renderer.setAttribute(native, attrName, attrVal, namespaceURI);
1018
+ }
1019
+ else {
1020
+ // attrName is string;
1021
+ const attrName = value;
1022
+ const attrVal = attrs[++i];
1023
+ // Standard attributes
1024
+ ngDevMode && ngDevMode.rendererSetAttribute++;
1025
+ if (isAnimationProp(attrName)) {
1026
+ renderer.setProperty(native, attrName, attrVal);
1148
1027
  }
1028
+ else {
1029
+ renderer.setAttribute(native, attrName, attrVal);
1030
+ }
1031
+ i++;
1149
1032
  }
1150
1033
  }
1151
- return newLookup;
1034
+ // another piece of code may iterate over the same attributes array. Therefore
1035
+ // it may be helpful to return the exact spot where the attributes array exited
1036
+ // whether by running into an unsupported marker or if all the static values were
1037
+ // iterated over.
1038
+ return i;
1152
1039
  }
1153
1040
  /**
1154
- * Create a directive definition object.
1155
- *
1156
- * # Example
1157
- * ```ts
1158
- * class MyDirective {
1159
- * // Generated by Angular Template Compiler
1160
- * // [Symbol] syntax will not be supported by TypeScript until v2.7
1161
- * static ɵdir = ɵɵdefineDirective({
1162
- * ...
1163
- * });
1164
- * }
1165
- * ```
1166
- *
1167
- * @codeGenApi
1041
+ * Test whether the given value is a marker that indicates that the following
1042
+ * attribute values in a `TAttributes` array are only the names of attributes,
1043
+ * and not name-value pairs.
1044
+ * @param marker The attribute marker to test.
1045
+ * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
1168
1046
  */
1169
- const ɵɵdefineDirective = ɵɵdefineComponent;
1170
- /**
1171
- * Create a pipe definition object.
1172
- *
1047
+ function isNameOnlyAttributeMarker(marker) {
1048
+ return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
1049
+ marker === 6 /* AttributeMarker.I18n */;
1050
+ }
1051
+ function isAnimationProp(name) {
1052
+ // Perf note: accessing charCodeAt to check for the first character of a string is faster as
1053
+ // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
1054
+ // charCodeAt doesn't allocate memory to return a substring.
1055
+ return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
1056
+ }
1057
+ /**
1058
+ * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
1059
+ *
1060
+ * This merge function keeps the order of attrs same.
1061
+ *
1062
+ * @param dst Location of where the merged `TAttributes` should end up.
1063
+ * @param src `TAttributes` which should be appended to `dst`
1064
+ */
1065
+ function mergeHostAttrs(dst, src) {
1066
+ if (src === null || src.length === 0) {
1067
+ // do nothing
1068
+ }
1069
+ else if (dst === null || dst.length === 0) {
1070
+ // We have source, but dst is empty, just make a copy.
1071
+ dst = src.slice();
1072
+ }
1073
+ else {
1074
+ let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
1075
+ for (let i = 0; i < src.length; i++) {
1076
+ const item = src[i];
1077
+ if (typeof item === 'number') {
1078
+ srcMarker = item;
1079
+ }
1080
+ else {
1081
+ if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
1082
+ // Case where we need to consume `key1`, `key2`, `value` items.
1083
+ }
1084
+ else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
1085
+ srcMarker === 2 /* AttributeMarker.Styles */) {
1086
+ // Case where we have to consume `key1` and `value` only.
1087
+ mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
1088
+ }
1089
+ else {
1090
+ // Case where we have to consume `key1` only.
1091
+ mergeHostAttribute(dst, srcMarker, item, null, null);
1092
+ }
1093
+ }
1094
+ }
1095
+ }
1096
+ return dst;
1097
+ }
1098
+ /**
1099
+ * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
1100
+ *
1101
+ * @param dst `TAttributes` to append to.
1102
+ * @param marker Region where the `key`/`value` should be added.
1103
+ * @param key1 Key to add to `TAttributes`
1104
+ * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
1105
+ * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
1106
+ */
1107
+ function mergeHostAttribute(dst, marker, key1, key2, value) {
1108
+ let i = 0;
1109
+ // Assume that new markers will be inserted at the end.
1110
+ let markerInsertPosition = dst.length;
1111
+ // scan until correct type.
1112
+ if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
1113
+ markerInsertPosition = -1;
1114
+ }
1115
+ else {
1116
+ while (i < dst.length) {
1117
+ const dstValue = dst[i++];
1118
+ if (typeof dstValue === 'number') {
1119
+ if (dstValue === marker) {
1120
+ markerInsertPosition = -1;
1121
+ break;
1122
+ }
1123
+ else if (dstValue > marker) {
1124
+ // We need to save this as we want the markers to be inserted in specific order.
1125
+ markerInsertPosition = i - 1;
1126
+ break;
1127
+ }
1128
+ }
1129
+ }
1130
+ }
1131
+ // search until you find place of insertion
1132
+ while (i < dst.length) {
1133
+ const item = dst[i];
1134
+ if (typeof item === 'number') {
1135
+ // since `i` started as the index after the marker, we did not find it if we are at the next
1136
+ // marker
1137
+ break;
1138
+ }
1139
+ else if (item === key1) {
1140
+ // We already have same token
1141
+ if (key2 === null) {
1142
+ if (value !== null) {
1143
+ dst[i + 1] = value;
1144
+ }
1145
+ return;
1146
+ }
1147
+ else if (key2 === dst[i + 1]) {
1148
+ dst[i + 2] = value;
1149
+ return;
1150
+ }
1151
+ }
1152
+ // Increment counter.
1153
+ i++;
1154
+ if (key2 !== null)
1155
+ i++;
1156
+ if (value !== null)
1157
+ i++;
1158
+ }
1159
+ // insert at location.
1160
+ if (markerInsertPosition !== -1) {
1161
+ dst.splice(markerInsertPosition, 0, marker);
1162
+ i = markerInsertPosition + 1;
1163
+ }
1164
+ dst.splice(i++, 0, key1);
1165
+ if (key2 !== null) {
1166
+ dst.splice(i++, 0, key2);
1167
+ }
1168
+ if (value !== null) {
1169
+ dst.splice(i++, 0, value);
1170
+ }
1171
+ }
1172
+
1173
+ const NG_TEMPLATE_SELECTOR = 'ng-template';
1174
+ /**
1175
+ * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
1176
+ *
1177
+ * @param attrs `TAttributes` to search through.
1178
+ * @param cssClassToMatch class to match (lowercase)
1179
+ * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
1180
+ * addition to the `AttributeMarker.Classes`.
1181
+ */
1182
+ function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
1183
+ // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
1184
+ // It is strange to me that sometimes the class information comes in form of `class` attribute
1185
+ // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
1186
+ // if that is the right behavior.
1187
+ ngDevMode &&
1188
+ assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
1189
+ let i = 0;
1190
+ while (i < attrs.length) {
1191
+ let item = attrs[i++];
1192
+ if (isProjectionMode && item === 'class') {
1193
+ item = attrs[i];
1194
+ if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
1195
+ return true;
1196
+ }
1197
+ }
1198
+ else if (item === 1 /* AttributeMarker.Classes */) {
1199
+ // We found the classes section. Start searching for the class.
1200
+ while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
1201
+ // while we have strings
1202
+ if (item.toLowerCase() === cssClassToMatch)
1203
+ return true;
1204
+ }
1205
+ return false;
1206
+ }
1207
+ }
1208
+ return false;
1209
+ }
1210
+ /**
1211
+ * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
1212
+ *
1213
+ * @param tNode current TNode
1214
+ */
1215
+ function isInlineTemplate(tNode) {
1216
+ return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
1217
+ }
1218
+ /**
1219
+ * Function that checks whether a given tNode matches tag-based selector and has a valid type.
1220
+ *
1221
+ * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
1222
+ * directive matching mode:
1223
+ * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
1224
+ * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
1225
+ * tag name was extracted from * syntax so we would match the same directive twice);
1226
+ * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
1227
+ * (applicable to TNodeType.Container only).
1228
+ */
1229
+ function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
1230
+ const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
1231
+ return currentSelector === tagNameToCompare;
1232
+ }
1233
+ /**
1234
+ * A utility function to match an Ivy node static data against a simple CSS selector
1235
+ *
1236
+ * @param node static data of the node to match
1237
+ * @param selector The selector to try matching against the node.
1238
+ * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
1239
+ * directive matching.
1240
+ * @returns true if node matches the selector.
1241
+ */
1242
+ function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
1243
+ ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
1244
+ let mode = 4 /* SelectorFlags.ELEMENT */;
1245
+ const nodeAttrs = tNode.attrs || [];
1246
+ // Find the index of first attribute that has no value, only a name.
1247
+ const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
1248
+ // When processing ":not" selectors, we skip to the next ":not" if the
1249
+ // current one doesn't match
1250
+ let skipToNextSelector = false;
1251
+ for (let i = 0; i < selector.length; i++) {
1252
+ const current = selector[i];
1253
+ if (typeof current === 'number') {
1254
+ // If we finish processing a :not selector and it hasn't failed, return false
1255
+ if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
1256
+ return false;
1257
+ }
1258
+ // If we are skipping to the next :not() and this mode flag is positive,
1259
+ // it's a part of the current :not() selector, and we should keep skipping
1260
+ if (skipToNextSelector && isPositive(current))
1261
+ continue;
1262
+ skipToNextSelector = false;
1263
+ mode = current | (mode & 1 /* SelectorFlags.NOT */);
1264
+ continue;
1265
+ }
1266
+ if (skipToNextSelector)
1267
+ continue;
1268
+ if (mode & 4 /* SelectorFlags.ELEMENT */) {
1269
+ mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
1270
+ if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
1271
+ current === '' && selector.length === 1) {
1272
+ if (isPositive(mode))
1273
+ return false;
1274
+ skipToNextSelector = true;
1275
+ }
1276
+ }
1277
+ else {
1278
+ const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
1279
+ // special case for matching against classes when a tNode has been instantiated with
1280
+ // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
1281
+ if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
1282
+ if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
1283
+ if (isPositive(mode))
1284
+ return false;
1285
+ skipToNextSelector = true;
1286
+ }
1287
+ continue;
1288
+ }
1289
+ const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
1290
+ const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
1291
+ if (attrIndexInNode === -1) {
1292
+ if (isPositive(mode))
1293
+ return false;
1294
+ skipToNextSelector = true;
1295
+ continue;
1296
+ }
1297
+ if (selectorAttrValue !== '') {
1298
+ let nodeAttrValue;
1299
+ if (attrIndexInNode > nameOnlyMarkerIdx) {
1300
+ nodeAttrValue = '';
1301
+ }
1302
+ else {
1303
+ ngDevMode &&
1304
+ assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
1305
+ // we lowercase the attribute value to be able to match
1306
+ // selectors without case-sensitivity
1307
+ // (selectors are already in lowercase when generated)
1308
+ nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
1309
+ }
1310
+ const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
1311
+ if (compareAgainstClassName &&
1312
+ classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
1313
+ mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
1314
+ if (isPositive(mode))
1315
+ return false;
1316
+ skipToNextSelector = true;
1317
+ }
1318
+ }
1319
+ }
1320
+ }
1321
+ return isPositive(mode) || skipToNextSelector;
1322
+ }
1323
+ function isPositive(mode) {
1324
+ return (mode & 1 /* SelectorFlags.NOT */) === 0;
1325
+ }
1326
+ /**
1327
+ * Examines the attribute's definition array for a node to find the index of the
1328
+ * attribute that matches the given `name`.
1329
+ *
1330
+ * NOTE: This will not match namespaced attributes.
1331
+ *
1332
+ * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
1333
+ * The following table summarizes which types of attributes we attempt to match:
1334
+ *
1335
+ * ===========================================================================================================
1336
+ * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
1337
+ * Attributes
1338
+ * ===========================================================================================================
1339
+ * Inline + Projection | YES | YES | NO | YES
1340
+ * -----------------------------------------------------------------------------------------------------------
1341
+ * Inline + Directive | NO | NO | YES | NO
1342
+ * -----------------------------------------------------------------------------------------------------------
1343
+ * Non-inline + Projection | YES | YES | NO | YES
1344
+ * -----------------------------------------------------------------------------------------------------------
1345
+ * Non-inline + Directive | YES | YES | NO | YES
1346
+ * ===========================================================================================================
1347
+ *
1348
+ * @param name the name of the attribute to find
1349
+ * @param attrs the attribute array to examine
1350
+ * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
1351
+ * rather than a manually expanded template node (e.g `<ng-template>`).
1352
+ * @param isProjectionMode true if we are matching against content projection otherwise we are
1353
+ * matching against directives.
1354
+ */
1355
+ function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
1356
+ if (attrs === null)
1357
+ return -1;
1358
+ let i = 0;
1359
+ if (isProjectionMode || !isInlineTemplate) {
1360
+ let bindingsMode = false;
1361
+ while (i < attrs.length) {
1362
+ const maybeAttrName = attrs[i];
1363
+ if (maybeAttrName === name) {
1364
+ return i;
1365
+ }
1366
+ else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
1367
+ bindingsMode = true;
1368
+ }
1369
+ else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
1370
+ let value = attrs[++i];
1371
+ // We should skip classes here because we have a separate mechanism for
1372
+ // matching classes in projection mode.
1373
+ while (typeof value === 'string') {
1374
+ value = attrs[++i];
1375
+ }
1376
+ continue;
1377
+ }
1378
+ else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
1379
+ // We do not care about Template attributes in this scenario.
1380
+ break;
1381
+ }
1382
+ else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
1383
+ // Skip the whole namespaced attribute and value. This is by design.
1384
+ i += 4;
1385
+ continue;
1386
+ }
1387
+ // In binding mode there are only names, rather than name-value pairs.
1388
+ i += bindingsMode ? 1 : 2;
1389
+ }
1390
+ // We did not match the attribute
1391
+ return -1;
1392
+ }
1393
+ else {
1394
+ return matchTemplateAttribute(attrs, name);
1395
+ }
1396
+ }
1397
+ function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
1398
+ for (let i = 0; i < selector.length; i++) {
1399
+ if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
1400
+ return true;
1401
+ }
1402
+ }
1403
+ return false;
1404
+ }
1405
+ function getProjectAsAttrValue(tNode) {
1406
+ const nodeAttrs = tNode.attrs;
1407
+ if (nodeAttrs != null) {
1408
+ const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
1409
+ // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
1410
+ // (attribute names are stored at even indexes)
1411
+ if ((ngProjectAsAttrIdx & 1) === 0) {
1412
+ return nodeAttrs[ngProjectAsAttrIdx + 1];
1413
+ }
1414
+ }
1415
+ return null;
1416
+ }
1417
+ function getNameOnlyMarkerIndex(nodeAttrs) {
1418
+ for (let i = 0; i < nodeAttrs.length; i++) {
1419
+ const nodeAttr = nodeAttrs[i];
1420
+ if (isNameOnlyAttributeMarker(nodeAttr)) {
1421
+ return i;
1422
+ }
1423
+ }
1424
+ return nodeAttrs.length;
1425
+ }
1426
+ function matchTemplateAttribute(attrs, name) {
1427
+ let i = attrs.indexOf(4 /* AttributeMarker.Template */);
1428
+ if (i > -1) {
1429
+ i++;
1430
+ while (i < attrs.length) {
1431
+ const attr = attrs[i];
1432
+ // Return in case we checked all template attrs and are switching to the next section in the
1433
+ // attrs array (that starts with a number that represents an attribute marker).
1434
+ if (typeof attr === 'number')
1435
+ return -1;
1436
+ if (attr === name)
1437
+ return i;
1438
+ i++;
1439
+ }
1440
+ }
1441
+ return -1;
1442
+ }
1443
+ /**
1444
+ * Checks whether a selector is inside a CssSelectorList
1445
+ * @param selector Selector to be checked.
1446
+ * @param list List in which to look for the selector.
1447
+ */
1448
+ function isSelectorInSelectorList(selector, list) {
1449
+ selectorListLoop: for (let i = 0; i < list.length; i++) {
1450
+ const currentSelectorInList = list[i];
1451
+ if (selector.length !== currentSelectorInList.length) {
1452
+ continue;
1453
+ }
1454
+ for (let j = 0; j < selector.length; j++) {
1455
+ if (selector[j] !== currentSelectorInList[j]) {
1456
+ continue selectorListLoop;
1457
+ }
1458
+ }
1459
+ return true;
1460
+ }
1461
+ return false;
1462
+ }
1463
+ function maybeWrapInNotSelector(isNegativeMode, chunk) {
1464
+ return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
1465
+ }
1466
+ function stringifyCSSSelector(selector) {
1467
+ let result = selector[0];
1468
+ let i = 1;
1469
+ let mode = 2 /* SelectorFlags.ATTRIBUTE */;
1470
+ let currentChunk = '';
1471
+ let isNegativeMode = false;
1472
+ while (i < selector.length) {
1473
+ let valueOrMarker = selector[i];
1474
+ if (typeof valueOrMarker === 'string') {
1475
+ if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
1476
+ const attrValue = selector[++i];
1477
+ currentChunk +=
1478
+ '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
1479
+ }
1480
+ else if (mode & 8 /* SelectorFlags.CLASS */) {
1481
+ currentChunk += '.' + valueOrMarker;
1482
+ }
1483
+ else if (mode & 4 /* SelectorFlags.ELEMENT */) {
1484
+ currentChunk += ' ' + valueOrMarker;
1485
+ }
1486
+ }
1487
+ else {
1488
+ //
1489
+ // Append current chunk to the final result in case we come across SelectorFlag, which
1490
+ // indicates that the previous section of a selector is over. We need to accumulate content
1491
+ // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
1492
+ // ```
1493
+ // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
1494
+ // ```
1495
+ // should be transformed to `.classA :not(.classB .classC)`.
1496
+ //
1497
+ // Note: for negative selector part, we accumulate content between flags until we find the
1498
+ // next negative flag. This is needed to support a case where `:not()` rule contains more than
1499
+ // one chunk, e.g. the following selector:
1500
+ // ```
1501
+ // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
1502
+ // ```
1503
+ // should be stringified to `:not(p.foo) :not(.bar)`
1504
+ //
1505
+ if (currentChunk !== '' && !isPositive(valueOrMarker)) {
1506
+ result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
1507
+ currentChunk = '';
1508
+ }
1509
+ mode = valueOrMarker;
1510
+ // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
1511
+ // mode is maintained for remaining chunks of a selector.
1512
+ isNegativeMode = isNegativeMode || !isPositive(mode);
1513
+ }
1514
+ i++;
1515
+ }
1516
+ if (currentChunk !== '') {
1517
+ result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
1518
+ }
1519
+ return result;
1520
+ }
1521
+ /**
1522
+ * Generates string representation of CSS selector in parsed form.
1523
+ *
1524
+ * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
1525
+ * additional parsing at runtime (for example, for directive matching). However in some cases (for
1526
+ * example, while bootstrapping a component), a string version of the selector is required to query
1527
+ * for the host element on the page. This function takes the parsed form of a selector and returns
1528
+ * its string representation.
1529
+ *
1530
+ * @param selectorList selector in parsed form
1531
+ * @returns string representation of a given selector
1532
+ */
1533
+ function stringifyCSSSelectorList(selectorList) {
1534
+ return selectorList.map(stringifyCSSSelector).join(',');
1535
+ }
1536
+ /**
1537
+ * Extracts attributes and classes information from a given CSS selector.
1538
+ *
1539
+ * This function is used while creating a component dynamically. In this case, the host element
1540
+ * (that is created dynamically) should contain attributes and classes specified in component's CSS
1541
+ * selector.
1542
+ *
1543
+ * @param selector CSS selector in parsed form (in a form of array)
1544
+ * @returns object with `attrs` and `classes` fields that contain extracted information
1545
+ */
1546
+ function extractAttrsAndClassesFromSelector(selector) {
1547
+ const attrs = [];
1548
+ const classes = [];
1549
+ let i = 1;
1550
+ let mode = 2 /* SelectorFlags.ATTRIBUTE */;
1551
+ while (i < selector.length) {
1552
+ let valueOrMarker = selector[i];
1553
+ if (typeof valueOrMarker === 'string') {
1554
+ if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
1555
+ if (valueOrMarker !== '') {
1556
+ attrs.push(valueOrMarker, selector[++i]);
1557
+ }
1558
+ }
1559
+ else if (mode === 8 /* SelectorFlags.CLASS */) {
1560
+ classes.push(valueOrMarker);
1561
+ }
1562
+ }
1563
+ else {
1564
+ // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
1565
+ // mode is maintained for remaining chunks of a selector. Since attributes and classes are
1566
+ // extracted only for "positive" part of the selector, we can stop here.
1567
+ if (!isPositive(mode))
1568
+ break;
1569
+ mode = valueOrMarker;
1570
+ }
1571
+ i++;
1572
+ }
1573
+ return { attrs, classes };
1574
+ }
1575
+
1576
+ /**
1577
+ * Create a component definition object.
1578
+ *
1579
+ *
1580
+ * # Example
1581
+ * ```
1582
+ * class MyComponent {
1583
+ * // Generated by Angular Template Compiler
1584
+ * // [Symbol] syntax will not be supported by TypeScript until v2.7
1585
+ * static ɵcmp = defineComponent({
1586
+ * ...
1587
+ * });
1588
+ * }
1589
+ * ```
1590
+ * @codeGenApi
1591
+ */
1592
+ function ɵɵdefineComponent(componentDefinition) {
1593
+ return noSideEffects(() => {
1594
+ // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
1595
+ // See the `initNgDevMode` docstring for more information.
1596
+ (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
1597
+ const baseDef = getNgDirectiveDef(componentDefinition);
1598
+ const def = {
1599
+ ...baseDef,
1600
+ decls: componentDefinition.decls,
1601
+ vars: componentDefinition.vars,
1602
+ template: componentDefinition.template,
1603
+ consts: componentDefinition.consts || null,
1604
+ ngContentSelectors: componentDefinition.ngContentSelectors,
1605
+ onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
1606
+ directiveDefs: null,
1607
+ pipeDefs: null,
1608
+ dependencies: baseDef.standalone && componentDefinition.dependencies || null,
1609
+ getStandaloneInjector: null,
1610
+ data: componentDefinition.data || {},
1611
+ encapsulation: componentDefinition.encapsulation || ViewEncapsulation$1.Emulated,
1612
+ styles: componentDefinition.styles || EMPTY_ARRAY,
1613
+ _: null,
1614
+ schemas: componentDefinition.schemas || null,
1615
+ tView: null,
1616
+ id: '',
1617
+ };
1618
+ initFeatures(def);
1619
+ const dependencies = componentDefinition.dependencies;
1620
+ def.directiveDefs = extractDefListOrFactory(dependencies, /* pipeDef */ false);
1621
+ def.pipeDefs = extractDefListOrFactory(dependencies, /* pipeDef */ true);
1622
+ def.id = getComponentId(def);
1623
+ return def;
1624
+ });
1625
+ }
1626
+ /**
1627
+ * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
1628
+ * definition, when generating a direct reference in the component file would otherwise create an
1629
+ * import cycle.
1630
+ *
1631
+ * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
1632
+ *
1633
+ * @codeGenApi
1634
+ */
1635
+ function ɵɵsetComponentScope(type, directives, pipes) {
1636
+ const def = type.ɵcmp;
1637
+ def.directiveDefs = extractDefListOrFactory(directives, /* pipeDef */ false);
1638
+ def.pipeDefs = extractDefListOrFactory(pipes, /* pipeDef */ true);
1639
+ }
1640
+ function extractDirectiveDef(type) {
1641
+ return getComponentDef(type) || getDirectiveDef(type);
1642
+ }
1643
+ function nonNull(value) {
1644
+ return value !== null;
1645
+ }
1646
+ /**
1647
+ * @codeGenApi
1648
+ */
1649
+ function ɵɵdefineNgModule(def) {
1650
+ return noSideEffects(() => {
1651
+ const res = {
1652
+ type: def.type,
1653
+ bootstrap: def.bootstrap || EMPTY_ARRAY,
1654
+ declarations: def.declarations || EMPTY_ARRAY,
1655
+ imports: def.imports || EMPTY_ARRAY,
1656
+ exports: def.exports || EMPTY_ARRAY,
1657
+ transitiveCompileScopes: null,
1658
+ schemas: def.schemas || null,
1659
+ id: def.id || null,
1660
+ };
1661
+ return res;
1662
+ });
1663
+ }
1664
+ /**
1665
+ * Adds the module metadata that is necessary to compute the module's transitive scope to an
1666
+ * existing module definition.
1667
+ *
1668
+ * Scope metadata of modules is not used in production builds, so calls to this function can be
1669
+ * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
1670
+ * to become eligible for tree-shaking as well.
1671
+ *
1672
+ * @codeGenApi
1673
+ */
1674
+ function ɵɵsetNgModuleScope(type, scope) {
1675
+ return noSideEffects(() => {
1676
+ const ngModuleDef = getNgModuleDef(type, true);
1677
+ ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
1678
+ ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
1679
+ ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
1680
+ });
1681
+ }
1682
+ /**
1683
+ * Inverts an inputs or outputs lookup such that the keys, which were the
1684
+ * minified keys, are part of the values, and the values are parsed so that
1685
+ * the publicName of the property is the new key
1686
+ *
1687
+ * e.g. for
1688
+ *
1689
+ * ```
1690
+ * class Comp {
1691
+ * @Input()
1692
+ * propName1: string;
1693
+ *
1694
+ * @Input('publicName2')
1695
+ * declaredPropName2: number;
1696
+ * }
1697
+ * ```
1698
+ *
1699
+ * will be serialized as
1700
+ *
1701
+ * ```
1702
+ * {
1703
+ * propName1: 'propName1',
1704
+ * declaredPropName2: ['publicName2', 'declaredPropName2'],
1705
+ * }
1706
+ * ```
1707
+ *
1708
+ * which is than translated by the minifier as:
1709
+ *
1710
+ * ```
1711
+ * {
1712
+ * minifiedPropName1: 'propName1',
1713
+ * minifiedPropName2: ['publicName2', 'declaredPropName2'],
1714
+ * }
1715
+ * ```
1716
+ *
1717
+ * becomes: (public name => minifiedName)
1718
+ *
1719
+ * ```
1720
+ * {
1721
+ * 'propName1': 'minifiedPropName1',
1722
+ * 'publicName2': 'minifiedPropName2',
1723
+ * }
1724
+ * ```
1725
+ *
1726
+ * Optionally the function can take `secondary` which will result in: (public name => declared name)
1727
+ *
1728
+ * ```
1729
+ * {
1730
+ * 'propName1': 'propName1',
1731
+ * 'publicName2': 'declaredPropName2',
1732
+ * }
1733
+ * ```
1734
+ *
1735
+
1736
+ */
1737
+ function invertObject(obj, secondary) {
1738
+ if (obj == null)
1739
+ return EMPTY_OBJ;
1740
+ const newLookup = {};
1741
+ for (const minifiedKey in obj) {
1742
+ if (obj.hasOwnProperty(minifiedKey)) {
1743
+ let publicName = obj[minifiedKey];
1744
+ let declaredName = publicName;
1745
+ if (Array.isArray(publicName)) {
1746
+ declaredName = publicName[1];
1747
+ publicName = publicName[0];
1748
+ }
1749
+ newLookup[publicName] = minifiedKey;
1750
+ if (secondary) {
1751
+ (secondary[publicName] = declaredName);
1752
+ }
1753
+ }
1754
+ }
1755
+ return newLookup;
1756
+ }
1757
+ /**
1758
+ * Create a directive definition object.
1759
+ *
1760
+ * # Example
1761
+ * ```ts
1762
+ * class MyDirective {
1763
+ * // Generated by Angular Template Compiler
1764
+ * // [Symbol] syntax will not be supported by TypeScript until v2.7
1765
+ * static ɵdir = ɵɵdefineDirective({
1766
+ * ...
1767
+ * });
1768
+ * }
1769
+ * ```
1770
+ *
1771
+ * @codeGenApi
1772
+ */
1773
+ function ɵɵdefineDirective(directiveDefinition) {
1774
+ return noSideEffects(() => {
1775
+ const def = getNgDirectiveDef(directiveDefinition);
1776
+ initFeatures(def);
1777
+ return def;
1778
+ });
1779
+ }
1780
+ /**
1781
+ * Create a pipe definition object.
1782
+ *
1173
1783
  * # Example
1174
1784
  * ```
1175
1785
  * class MyPipe implements PipeTransform {
@@ -1226,6 +1836,99 @@ function getNgModuleDef(type, throwNotFound) {
1226
1836
  }
1227
1837
  return ngModuleDef;
1228
1838
  }
1839
+ function getNgDirectiveDef(directiveDefinition) {
1840
+ const declaredInputs = {};
1841
+ return {
1842
+ type: directiveDefinition.type,
1843
+ providersResolver: null,
1844
+ factory: null,
1845
+ hostBindings: directiveDefinition.hostBindings || null,
1846
+ hostVars: directiveDefinition.hostVars || 0,
1847
+ hostAttrs: directiveDefinition.hostAttrs || null,
1848
+ contentQueries: directiveDefinition.contentQueries || null,
1849
+ declaredInputs,
1850
+ exportAs: directiveDefinition.exportAs || null,
1851
+ standalone: directiveDefinition.standalone === true,
1852
+ selectors: directiveDefinition.selectors || EMPTY_ARRAY,
1853
+ viewQuery: directiveDefinition.viewQuery || null,
1854
+ features: directiveDefinition.features || null,
1855
+ setInput: null,
1856
+ findHostDirectiveDefs: null,
1857
+ hostDirectives: null,
1858
+ inputs: invertObject(directiveDefinition.inputs, declaredInputs),
1859
+ outputs: invertObject(directiveDefinition.outputs),
1860
+ };
1861
+ }
1862
+ function initFeatures(definition) {
1863
+ definition.features?.forEach((fn) => fn(definition));
1864
+ }
1865
+ function extractDefListOrFactory(dependencies, pipeDef) {
1866
+ if (!dependencies) {
1867
+ return null;
1868
+ }
1869
+ const defExtractor = pipeDef ? getPipeDef$1 : extractDirectiveDef;
1870
+ return () => (typeof dependencies === 'function' ? dependencies() : dependencies)
1871
+ .map(dep => defExtractor(dep))
1872
+ .filter(nonNull);
1873
+ }
1874
+ /**
1875
+ * A map that contains the generated component IDs and type.
1876
+ */
1877
+ const GENERATED_COMP_IDS = new Map();
1878
+ /**
1879
+ * A method can returns a component ID from the component definition using a variant of DJB2 hash
1880
+ * algorithm.
1881
+ */
1882
+ function getComponentId(componentDef) {
1883
+ let hash = 0;
1884
+ // We cannot rely solely on the component selector as the same selector can be used in different
1885
+ // modules.
1886
+ //
1887
+ // `componentDef.style` is not used, due to it causing inconsistencies. Ex: when server
1888
+ // component styles has no sourcemaps and browsers do.
1889
+ //
1890
+ // Example:
1891
+ // https://github.com/angular/components/blob/d9f82c8f95309e77a6d82fd574c65871e91354c2/src/material/core/option/option.ts#L248
1892
+ // https://github.com/angular/components/blob/285f46dc2b4c5b127d356cb7c4714b221f03ce50/src/material/legacy-core/option/option.ts#L32
1893
+ const hashSelectors = [
1894
+ componentDef.selectors,
1895
+ componentDef.ngContentSelectors,
1896
+ componentDef.hostVars,
1897
+ componentDef.hostAttrs,
1898
+ componentDef.consts,
1899
+ componentDef.vars,
1900
+ componentDef.decls,
1901
+ componentDef.encapsulation,
1902
+ componentDef.standalone,
1903
+ // We cannot use 'componentDef.type.name' as the name of the symbol will change and will not
1904
+ // match in the server and browser bundles.
1905
+ Object.getOwnPropertyNames(componentDef.type.prototype),
1906
+ !!componentDef.contentQueries,
1907
+ !!componentDef.viewQuery,
1908
+ ].join('|');
1909
+ for (const char of hashSelectors) {
1910
+ hash = Math.imul(31, hash) + char.charCodeAt(0) << 0;
1911
+ }
1912
+ // Force positive number hash.
1913
+ // 2147483647 = equivalent of Integer.MAX_VALUE.
1914
+ hash += 2147483647 + 1;
1915
+ const compId = 'c' + hash;
1916
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
1917
+ if (GENERATED_COMP_IDS.has(compId)) {
1918
+ const previousCompDefType = GENERATED_COMP_IDS.get(compId);
1919
+ if (previousCompDefType !== componentDef.type) {
1920
+ // TODO: use `formatRuntimeError` to have an error code and we can later on create an error
1921
+ // guide to explain this further.
1922
+ console.warn(`Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
1923
+ .selectors)}' generated the same component ID. To fix this, you can change the selector of one of those components or add an extra host attribute to force a different ID.`);
1924
+ }
1925
+ }
1926
+ else {
1927
+ GENERATED_COMP_IDS.set(compId, componentDef.type);
1928
+ }
1929
+ }
1930
+ return compId;
1931
+ }
1229
1932
 
1230
1933
  // Below are constants for LView indices to help us look up LView members
1231
1934
  // without having to remember the specific indices.
@@ -1294,13 +1997,14 @@ const HAS_TRANSPLANTED_VIEWS = 2;
1294
1997
  const NATIVE = 7;
1295
1998
  const VIEW_REFS = 8;
1296
1999
  const MOVED_VIEWS = 9;
2000
+ const DEHYDRATED_VIEWS = 10;
1297
2001
  /**
1298
2002
  * Size of LContainer's header. Represents the index after which all views in the
1299
2003
  * container will be inserted. We need to keep a record of current views so we know
1300
2004
  * which views are already in the DOM (and don't need to be re-added) and so we can
1301
2005
  * remove views from the DOM when they are no longer required.
1302
2006
  */
1303
- const CONTAINER_HEADER_OFFSET = 10;
2007
+ const CONTAINER_HEADER_OFFSET = 11;
1304
2008
  // Note: This hack is necessary so we don't erroneously get a circular dependency
1305
2009
  // failure based on types.
1306
2010
  const unusedValueExportToPlacateAjd$3 = 1;
@@ -1329,7 +2033,7 @@ function isDirectiveHost(tNode) {
1329
2033
  return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
1330
2034
  }
1331
2035
  function isComponentDef(def) {
1332
- return def.template !== null;
2036
+ return !!def.template;
1333
2037
  }
1334
2038
  function isRootView(target) {
1335
2039
  return (target[FLAGS] & 256 /* LViewFlags.IsRoot */) !== 0;
@@ -1786,7 +2490,7 @@ function getBindingsEnabled() {
1786
2490
  * Returns true if currently inside a skip hydration block.
1787
2491
  * @returns boolean
1788
2492
  */
1789
- function isInSkipHydrationBlock() {
2493
+ function isInSkipHydrationBlock$1() {
1790
2494
  return instructionState.skipHydrationRootTNode !== null;
1791
2495
  }
1792
2496
  /**
@@ -2704,230 +3408,30 @@ function hasClassInput(tNode) {
2704
3408
  * ```
2705
3409
  *
2706
3410
  * In the above case it is necessary to write the reconciled styling information into the
2707
- * directive's input.
2708
- *
2709
- * @param tNode
2710
- */
2711
- function hasStyleInput(tNode) {
2712
- return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
2713
- }
2714
-
2715
- function assertTNodeType(tNode, expectedTypes, message) {
2716
- assertDefined(tNode, 'should be called with a TNode');
2717
- if ((tNode.type & expectedTypes) === 0) {
2718
- throwError(message ||
2719
- `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
2720
- }
2721
- }
2722
- function assertPureTNodeType(type) {
2723
- if (!(type === 2 /* TNodeType.Element */ || //
2724
- type === 1 /* TNodeType.Text */ || //
2725
- type === 4 /* TNodeType.Container */ || //
2726
- type === 8 /* TNodeType.ElementContainer */ || //
2727
- type === 32 /* TNodeType.Icu */ || //
2728
- type === 16 /* TNodeType.Projection */ || //
2729
- type === 64 /* TNodeType.Placeholder */)) {
2730
- throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
2731
- }
2732
- }
2733
-
2734
- /**
2735
- * Assigns all attribute values to the provided element via the inferred renderer.
2736
- *
2737
- * This function accepts two forms of attribute entries:
2738
- *
2739
- * default: (key, value):
2740
- * attrs = [key1, value1, key2, value2]
2741
- *
2742
- * namespaced: (NAMESPACE_MARKER, uri, name, value)
2743
- * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
2744
- *
2745
- * The `attrs` array can contain a mix of both the default and namespaced entries.
2746
- * The "default" values are set without a marker, but if the function comes across
2747
- * a marker value then it will attempt to set a namespaced value. If the marker is
2748
- * not of a namespaced value then the function will quit and return the index value
2749
- * where it stopped during the iteration of the attrs array.
2750
- *
2751
- * See [AttributeMarker] to understand what the namespace marker value is.
2752
- *
2753
- * Note that this instruction does not support assigning style and class values to
2754
- * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
2755
- * are applied to an element.
2756
- * @param renderer The renderer to be used
2757
- * @param native The element that the attributes will be assigned to
2758
- * @param attrs The attribute array of values that will be assigned to the element
2759
- * @returns the index value that was last accessed in the attributes array
2760
- */
2761
- function setUpAttributes(renderer, native, attrs) {
2762
- let i = 0;
2763
- while (i < attrs.length) {
2764
- const value = attrs[i];
2765
- if (typeof value === 'number') {
2766
- // only namespaces are supported. Other value types (such as style/class
2767
- // entries) are not supported in this function.
2768
- if (value !== 0 /* AttributeMarker.NamespaceURI */) {
2769
- break;
2770
- }
2771
- // we just landed on the marker value ... therefore
2772
- // we should skip to the next entry
2773
- i++;
2774
- const namespaceURI = attrs[i++];
2775
- const attrName = attrs[i++];
2776
- const attrVal = attrs[i++];
2777
- ngDevMode && ngDevMode.rendererSetAttribute++;
2778
- renderer.setAttribute(native, attrName, attrVal, namespaceURI);
2779
- }
2780
- else {
2781
- // attrName is string;
2782
- const attrName = value;
2783
- const attrVal = attrs[++i];
2784
- // Standard attributes
2785
- ngDevMode && ngDevMode.rendererSetAttribute++;
2786
- if (isAnimationProp(attrName)) {
2787
- renderer.setProperty(native, attrName, attrVal);
2788
- }
2789
- else {
2790
- renderer.setAttribute(native, attrName, attrVal);
2791
- }
2792
- i++;
2793
- }
2794
- }
2795
- // another piece of code may iterate over the same attributes array. Therefore
2796
- // it may be helpful to return the exact spot where the attributes array exited
2797
- // whether by running into an unsupported marker or if all the static values were
2798
- // iterated over.
2799
- return i;
2800
- }
2801
- /**
2802
- * Test whether the given value is a marker that indicates that the following
2803
- * attribute values in a `TAttributes` array are only the names of attributes,
2804
- * and not name-value pairs.
2805
- * @param marker The attribute marker to test.
2806
- * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
2807
- */
2808
- function isNameOnlyAttributeMarker(marker) {
2809
- return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
2810
- marker === 6 /* AttributeMarker.I18n */;
2811
- }
2812
- function isAnimationProp(name) {
2813
- // Perf note: accessing charCodeAt to check for the first character of a string is faster as
2814
- // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
2815
- // charCodeAt doesn't allocate memory to return a substring.
2816
- return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
2817
- }
2818
- /**
2819
- * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
2820
- *
2821
- * This merge function keeps the order of attrs same.
2822
- *
2823
- * @param dst Location of where the merged `TAttributes` should end up.
2824
- * @param src `TAttributes` which should be appended to `dst`
2825
- */
2826
- function mergeHostAttrs(dst, src) {
2827
- if (src === null || src.length === 0) {
2828
- // do nothing
2829
- }
2830
- else if (dst === null || dst.length === 0) {
2831
- // We have source, but dst is empty, just make a copy.
2832
- dst = src.slice();
2833
- }
2834
- else {
2835
- let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
2836
- for (let i = 0; i < src.length; i++) {
2837
- const item = src[i];
2838
- if (typeof item === 'number') {
2839
- srcMarker = item;
2840
- }
2841
- else {
2842
- if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
2843
- // Case where we need to consume `key1`, `key2`, `value` items.
2844
- }
2845
- else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
2846
- srcMarker === 2 /* AttributeMarker.Styles */) {
2847
- // Case where we have to consume `key1` and `value` only.
2848
- mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
2849
- }
2850
- else {
2851
- // Case where we have to consume `key1` only.
2852
- mergeHostAttribute(dst, srcMarker, item, null, null);
2853
- }
2854
- }
2855
- }
2856
- }
2857
- return dst;
2858
- }
2859
- /**
2860
- * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
2861
- *
2862
- * @param dst `TAttributes` to append to.
2863
- * @param marker Region where the `key`/`value` should be added.
2864
- * @param key1 Key to add to `TAttributes`
2865
- * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
2866
- * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
2867
- */
2868
- function mergeHostAttribute(dst, marker, key1, key2, value) {
2869
- let i = 0;
2870
- // Assume that new markers will be inserted at the end.
2871
- let markerInsertPosition = dst.length;
2872
- // scan until correct type.
2873
- if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
2874
- markerInsertPosition = -1;
2875
- }
2876
- else {
2877
- while (i < dst.length) {
2878
- const dstValue = dst[i++];
2879
- if (typeof dstValue === 'number') {
2880
- if (dstValue === marker) {
2881
- markerInsertPosition = -1;
2882
- break;
2883
- }
2884
- else if (dstValue > marker) {
2885
- // We need to save this as we want the markers to be inserted in specific order.
2886
- markerInsertPosition = i - 1;
2887
- break;
2888
- }
2889
- }
2890
- }
2891
- }
2892
- // search until you find place of insertion
2893
- while (i < dst.length) {
2894
- const item = dst[i];
2895
- if (typeof item === 'number') {
2896
- // since `i` started as the index after the marker, we did not find it if we are at the next
2897
- // marker
2898
- break;
2899
- }
2900
- else if (item === key1) {
2901
- // We already have same token
2902
- if (key2 === null) {
2903
- if (value !== null) {
2904
- dst[i + 1] = value;
2905
- }
2906
- return;
2907
- }
2908
- else if (key2 === dst[i + 1]) {
2909
- dst[i + 2] = value;
2910
- return;
2911
- }
2912
- }
2913
- // Increment counter.
2914
- i++;
2915
- if (key2 !== null)
2916
- i++;
2917
- if (value !== null)
2918
- i++;
2919
- }
2920
- // insert at location.
2921
- if (markerInsertPosition !== -1) {
2922
- dst.splice(markerInsertPosition, 0, marker);
2923
- i = markerInsertPosition + 1;
2924
- }
2925
- dst.splice(i++, 0, key1);
2926
- if (key2 !== null) {
2927
- dst.splice(i++, 0, key2);
3411
+ * directive's input.
3412
+ *
3413
+ * @param tNode
3414
+ */
3415
+ function hasStyleInput(tNode) {
3416
+ return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
3417
+ }
3418
+
3419
+ function assertTNodeType(tNode, expectedTypes, message) {
3420
+ assertDefined(tNode, 'should be called with a TNode');
3421
+ if ((tNode.type & expectedTypes) === 0) {
3422
+ throwError(message ||
3423
+ `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
2928
3424
  }
2929
- if (value !== null) {
2930
- dst.splice(i++, 0, value);
3425
+ }
3426
+ function assertPureTNodeType(type) {
3427
+ if (!(type === 2 /* TNodeType.Element */ || //
3428
+ type === 1 /* TNodeType.Text */ || //
3429
+ type === 4 /* TNodeType.Container */ || //
3430
+ type === 8 /* TNodeType.ElementContainer */ || //
3431
+ type === 32 /* TNodeType.Icu */ || //
3432
+ type === 16 /* TNodeType.Projection */ || //
3433
+ type === 64 /* TNodeType.Placeholder */)) {
3434
+ throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
2931
3435
  }
2932
3436
  }
2933
3437
 
@@ -8239,35 +8743,41 @@ function forEachSingleProvider(providers, fn) {
8239
8743
  }
8240
8744
 
8241
8745
  /**
8242
- * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
8746
+ * A [DI token](guide/glossary#di-token "DI token definition") representing a string ID, used
8243
8747
  * primarily for prefixing application attributes and CSS styles when
8244
8748
  * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
8245
8749
  *
8246
- * BY default, the value is randomly generated and assigned to the application by Angular.
8247
- * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
8248
- * the root {@link Injector} that uses this token.
8750
+ * The token is needed in cases when multiple applications are bootstrapped on a page
8751
+ * (for example, using `bootstrapApplication` calls). In this case, ensure that those applications
8752
+ * have different `APP_ID` value setup. For example:
8753
+ *
8754
+ * ```
8755
+ * bootstrapApplication(ComponentA, {
8756
+ * providers: [
8757
+ * { provide: APP_ID, useValue: 'app-a' },
8758
+ * // ... other providers ...
8759
+ * ]
8760
+ * });
8761
+ *
8762
+ * bootstrapApplication(ComponentB, {
8763
+ * providers: [
8764
+ * { provide: APP_ID, useValue: 'app-b' },
8765
+ * // ... other providers ...
8766
+ * ]
8767
+ * });
8768
+ * ```
8769
+ *
8770
+ * By default, when there is only one application bootstrapped, you don't need to provide the
8771
+ * `APP_ID` token (the `ng` will be used as an app ID).
8249
8772
  *
8250
8773
  * @publicApi
8251
8774
  */
8252
8775
  const APP_ID = new InjectionToken('AppId', {
8253
8776
  providedIn: 'root',
8254
- factory: _appIdRandomProviderFactory,
8777
+ factory: () => DEFAULT_APP_ID,
8255
8778
  });
8256
- function _appIdRandomProviderFactory() {
8257
- return `${_randomChar()}${_randomChar()}${_randomChar()}`;
8258
- }
8259
- /**
8260
- * Providers that generate a random `APP_ID_TOKEN`.
8261
- * @publicApi
8262
- */
8263
- const APP_ID_RANDOM_PROVIDER = {
8264
- provide: APP_ID,
8265
- useFactory: _appIdRandomProviderFactory,
8266
- deps: [],
8267
- };
8268
- function _randomChar() {
8269
- return String.fromCharCode(97 + Math.floor(Math.random() * 25));
8270
- }
8779
+ /** Default value of the `APP_ID` token. */
8780
+ const DEFAULT_APP_ID = 'ng';
8271
8781
  /**
8272
8782
  * A function that is executed when a platform is initialized.
8273
8783
  * @publicApi
@@ -8438,990 +8948,637 @@ function retrieveTransferredState(doc, appId) {
8438
8948
  return initialState;
8439
8949
  }
8440
8950
 
8441
- /* Represents a key in NghDom that holds information about <ng-container>s. */
8442
- const ELEMENT_CONTAINERS = 'e';
8443
-
8444
- /**
8445
- * The name of the key used in the TransferState collection,
8446
- * where hydration information is located.
8447
- */
8448
- const TRANSFER_STATE_TOKEN_ID = '__ɵnghData__';
8449
- /**
8450
- * Lookup key used to reference DOM hydration data (ngh) in `TransferState`.
8451
- */
8452
- const NGH_DATA_KEY = makeStateKey(TRANSFER_STATE_TOKEN_ID);
8453
- /**
8454
- * The name of the attribute that would be added to host component
8455
- * nodes and contain a reference to a particular slot in transferred
8456
- * state that contains the necessary hydration info for this component.
8457
- */
8458
- const NGH_ATTR_NAME = 'ngh';
8459
- /**
8460
- * Reference to a function that reads `ngh` attribute value from a given RNode
8461
- * and retrieves hydration information from the TransferState using that value
8462
- * as an index. Returns `null` by default, when hydration is not enabled.
8463
- *
8464
- * @param rNode Component's host element.
8465
- * @param injector Injector that this component has access to.
8466
- */
8467
- let _retrieveHydrationInfoImpl = (rNode, injector) => null;
8468
- function retrieveHydrationInfoImpl(rNode, injector) {
8469
- const nghAttrValue = rNode.getAttribute(NGH_ATTR_NAME);
8470
- if (nghAttrValue == null)
8471
- return null;
8472
- let data = {};
8473
- // An element might have an empty `ngh` attribute value (e.g. `<comp ngh="" />`),
8474
- // which means that no special annotations are required. Do not attempt to read
8475
- // from the TransferState in this case.
8476
- if (nghAttrValue !== '') {
8477
- const transferState = injector.get(TransferState, null, { optional: true });
8478
- if (transferState !== null) {
8479
- const nghData = transferState.get(NGH_DATA_KEY, []);
8480
- // The nghAttrValue is always a number referencing an index
8481
- // in the hydration TransferState data.
8482
- data = nghData[Number(nghAttrValue)];
8483
- // If the `ngh` attribute exists and has a non-empty value,
8484
- // the hydration info *must* be present in the TransferState.
8485
- // If there is no data for some reasons, this is an error.
8486
- ngDevMode && assertDefined(data, 'Unable to retrieve hydration info from the TransferState.');
8487
- }
8488
- }
8489
- const dehydratedView = {
8490
- data,
8491
- firstChild: rNode.firstChild ?? null,
8492
- };
8493
- // The `ngh` attribute is cleared from the DOM node now
8494
- // that the data has been retrieved.
8495
- rNode.removeAttribute(NGH_ATTR_NAME);
8496
- // Note: don't check whether this node was claimed for hydration,
8497
- // because this node might've been previously claimed while processing
8498
- // template instructions.
8499
- ngDevMode && markRNodeAsClaimedByHydration(rNode, /* checkIfAlreadyClaimed */ false);
8500
- ngDevMode && ngDevMode.hydratedComponents++;
8501
- return dehydratedView;
8502
- }
8503
- /**
8504
- * Sets the implementation for the `retrieveNghInfo` function.
8505
- */
8506
- function enableRetrieveHydrationInfoImpl() {
8507
- _retrieveHydrationInfoImpl = retrieveHydrationInfoImpl;
8508
- }
8509
- /**
8510
- * Retrieves hydration info by reading the value from the `ngh` attribute
8511
- * and accessing a corresponding slot in TransferState storage.
8512
- */
8513
- function retrieveHydrationInfo(rNode, injector) {
8514
- return _retrieveHydrationInfoImpl(rNode, injector);
8515
- }
8516
- /**
8517
- * Retrieves an instance of a component LView from a given ViewRef.
8518
- * Returns an instance of a component LView or `null` in case of an embedded view.
8519
- */
8520
- function getComponentLViewForHydration(viewRef) {
8521
- // Reading an internal field from `ViewRef` instance.
8522
- let lView = viewRef._lView;
8523
- const tView = lView[TVIEW];
8524
- // A registered ViewRef might represent an instance of an
8525
- // embedded view, in which case we do not need to annotate it.
8526
- if (tView.type === 2 /* TViewType.Embedded */) {
8527
- return null;
8528
- }
8529
- // Check if it's a root view and if so, retrieve component's
8530
- // LView from the first slot after the header.
8531
- if (isRootView(lView)) {
8532
- lView = lView[HEADER_OFFSET];
8533
- }
8534
- return lView;
8535
- }
8536
- /**
8537
- * Marks a node as "claimed" by hydration process.
8538
- * This is needed to make assessments in tests whether
8539
- * the hydration process handled all nodes.
8540
- */
8541
- function markRNodeAsClaimedByHydration(node, checkIfAlreadyClaimed = true) {
8542
- if (!ngDevMode) {
8543
- throw new Error('Calling `markRNodeAsClaimedByHydration` in prod mode ' +
8544
- 'is not supported and likely a mistake.');
8545
- }
8546
- if (checkIfAlreadyClaimed && isRNodeClaimedForHydration(node)) {
8547
- throw new Error('Trying to claim a node, which was claimed already.');
8548
- }
8549
- node.__claimed = true;
8550
- ngDevMode.hydratedNodes++;
8551
- }
8552
- function isRNodeClaimedForHydration(node) {
8553
- return !!node.__claimed;
8554
- }
8555
- function storeNgContainerInfo(hydrationInfo, index, firstChild) {
8556
- hydrationInfo.ngContainers ?? (hydrationInfo.ngContainers = {});
8557
- hydrationInfo.ngContainers[index] = { firstChild };
8558
- }
8559
- function getNgContainerSize(hydrationInfo, index) {
8560
- return hydrationInfo.data[ELEMENT_CONTAINERS]?.[index] ?? null;
8561
- }
8562
-
8563
- /**
8564
- * Represents a component created by a `ComponentFactory`.
8565
- * Provides access to the component instance and related objects,
8566
- * and provides the means of destroying the instance.
8567
- *
8568
- * @publicApi
8569
- */
8570
- class ComponentRef$1 {
8571
- }
8572
- /**
8573
- * Base class for a factory that can create a component dynamically.
8574
- * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
8575
- * Use the resulting `ComponentFactory.create()` method to create a component of that type.
8576
- *
8577
- * @see [Dynamic Components](guide/dynamic-component-loader)
8578
- *
8579
- * @publicApi
8580
- *
8581
- * @deprecated Angular no longer requires Component factories. Please use other APIs where
8582
- * Component class can be used directly.
8583
- */
8584
- class ComponentFactory$1 {
8585
- }
8586
-
8587
- function noComponentFactoryError(component) {
8588
- const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
8589
- error[ERROR_COMPONENT] = component;
8590
- return error;
8591
- }
8592
- const ERROR_COMPONENT = 'ngComponent';
8593
- function getComponent$1(error) {
8594
- return error[ERROR_COMPONENT];
8595
- }
8596
- class _NullComponentFactoryResolver {
8597
- resolveComponentFactory(component) {
8598
- throw noComponentFactoryError(component);
8599
- }
8600
- }
8601
8951
  /**
8602
- * A simple registry that maps `Components` to generated `ComponentFactory` classes
8603
- * that can be used to create instances of components.
8604
- * Use to obtain the factory for a given component type,
8605
- * then use the factory's `create()` method to create a component of that type.
8606
- *
8607
- * Note: since v13, dynamic component creation via
8608
- * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
8609
- * does **not** require resolving component factory: component class can be used directly.
8610
- *
8611
- * @publicApi
8612
- *
8613
- * @deprecated Angular no longer requires Component factories. Please use other APIs where
8614
- * Component class can be used directly.
8952
+ * Keys within serialized view data structure to represent various
8953
+ * parts. See the `SerializedView` interface below for additional information.
8615
8954
  */
8616
- class ComponentFactoryResolver$1 {
8617
- }
8618
- ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
8955
+ const ELEMENT_CONTAINERS = 'e';
8956
+ const TEMPLATES = 't';
8957
+ const CONTAINERS = 'c';
8958
+ const NUM_ROOT_NODES = 'r';
8959
+ const TEMPLATE_ID = 'i'; // as it's also an "id"
8619
8960
 
8620
- /**
8621
- * Creates an ElementRef from the most recent node.
8622
- *
8623
- * @returns The ElementRef instance to use
8624
- */
8625
- function injectElementRef() {
8626
- return createElementRef(getCurrentTNode(), getLView());
8627
- }
8628
- /**
8629
- * Creates an ElementRef given a node.
8630
- *
8631
- * @param tNode The node for which you'd like an ElementRef
8632
- * @param lView The view to which the node belongs
8633
- * @returns The ElementRef instance to use
8634
- */
8635
- function createElementRef(tNode, lView) {
8636
- return new ElementRef(getNativeByTNode(tNode, lView));
8637
- }
8638
- /**
8639
- * A wrapper around a native element inside of a View.
8640
- *
8641
- * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
8642
- * element.
8643
- *
8644
- * @security Permitting direct access to the DOM can make your application more vulnerable to
8645
- * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
8646
- * [Security Guide](https://g.co/ng/security).
8647
- *
8648
- * @publicApi
8649
- */
8650
- // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
8651
- // i.e. users have to ask for what they need. With that, we can build better analysis tools
8652
- // and could do better codegen in the future.
8653
- class ElementRef {
8654
- constructor(nativeElement) {
8655
- this.nativeElement = nativeElement;
8656
- }
8657
- }
8658
- /**
8659
- * @internal
8660
- * @nocollapse
8961
+ /**
8962
+ * The name of the key used in the TransferState collection,
8963
+ * where hydration information is located.
8661
8964
  */
8662
- ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
8965
+ const TRANSFER_STATE_TOKEN_ID = '__ɵnghData__';
8663
8966
  /**
8664
- * Unwraps `ElementRef` and return the `nativeElement`.
8665
- *
8666
- * @param value value to unwrap
8667
- * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
8967
+ * Lookup key used to reference DOM hydration data (ngh) in `TransferState`.
8668
8968
  */
8669
- function unwrapElementRef(value) {
8670
- return value instanceof ElementRef ? value.nativeElement : value;
8671
- }
8672
-
8969
+ const NGH_DATA_KEY = makeStateKey(TRANSFER_STATE_TOKEN_ID);
8673
8970
  /**
8674
- * Creates and initializes a custom renderer that implements the `Renderer2` base class.
8675
- *
8676
- * @publicApi
8971
+ * The name of the attribute that would be added to host component
8972
+ * nodes and contain a reference to a particular slot in transferred
8973
+ * state that contains the necessary hydration info for this component.
8677
8974
  */
8678
- class RendererFactory2 {
8679
- }
8975
+ const NGH_ATTR_NAME = 'ngh';
8680
8976
  /**
8681
- * Extend this base class to implement custom rendering. By default, Angular
8682
- * renders a template into DOM. You can use custom rendering to intercept
8683
- * rendering calls, or to render to something other than DOM.
8684
- *
8685
- * Create your custom renderer using `RendererFactory2`.
8686
- *
8687
- * Use a custom renderer to bypass Angular's templating and
8688
- * make custom UI changes that can't be expressed declaratively.
8689
- * For example if you need to set a property or an attribute whose name is
8690
- * not statically known, use the `setProperty()` or
8691
- * `setAttribute()` method.
8977
+ * Reference to a function that reads `ngh` attribute value from a given RNode
8978
+ * and retrieves hydration information from the TransferState using that value
8979
+ * as an index. Returns `null` by default, when hydration is not enabled.
8692
8980
  *
8693
- * @publicApi
8981
+ * @param rNode Component's host element.
8982
+ * @param injector Injector that this component has access to.
8694
8983
  */
8695
- class Renderer2 {
8984
+ let _retrieveHydrationInfoImpl = (rNode, injector) => null;
8985
+ function retrieveHydrationInfoImpl(rNode, injector) {
8986
+ const nghAttrValue = rNode.getAttribute(NGH_ATTR_NAME);
8987
+ if (nghAttrValue == null)
8988
+ return null;
8989
+ let data = {};
8990
+ // An element might have an empty `ngh` attribute value (e.g. `<comp ngh="" />`),
8991
+ // which means that no special annotations are required. Do not attempt to read
8992
+ // from the TransferState in this case.
8993
+ if (nghAttrValue !== '') {
8994
+ const transferState = injector.get(TransferState, null, { optional: true });
8995
+ if (transferState !== null) {
8996
+ const nghData = transferState.get(NGH_DATA_KEY, []);
8997
+ // The nghAttrValue is always a number referencing an index
8998
+ // in the hydration TransferState data.
8999
+ data = nghData[Number(nghAttrValue)];
9000
+ // If the `ngh` attribute exists and has a non-empty value,
9001
+ // the hydration info *must* be present in the TransferState.
9002
+ // If there is no data for some reasons, this is an error.
9003
+ ngDevMode && assertDefined(data, 'Unable to retrieve hydration info from the TransferState.');
9004
+ }
9005
+ }
9006
+ const dehydratedView = {
9007
+ data,
9008
+ firstChild: rNode.firstChild ?? null,
9009
+ };
9010
+ // The `ngh` attribute is cleared from the DOM node now
9011
+ // that the data has been retrieved.
9012
+ rNode.removeAttribute(NGH_ATTR_NAME);
9013
+ // Note: don't check whether this node was claimed for hydration,
9014
+ // because this node might've been previously claimed while processing
9015
+ // template instructions.
9016
+ ngDevMode && markRNodeAsClaimedByHydration(rNode, /* checkIfAlreadyClaimed */ false);
9017
+ ngDevMode && ngDevMode.hydratedComponents++;
9018
+ return dehydratedView;
8696
9019
  }
8697
9020
  /**
8698
- * @internal
8699
- * @nocollapse
9021
+ * Sets the implementation for the `retrieveHydrationInfo` function.
8700
9022
  */
8701
- Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
8702
- /** Injects a Renderer2 for the current component. */
8703
- function injectRenderer2() {
8704
- // We need the Renderer to be based on the component that it's being injected into, however since
8705
- // DI happens before we've entered its view, `getLView` will return the parent view instead.
8706
- const lView = getLView();
8707
- const tNode = getCurrentTNode();
8708
- const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
8709
- return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
9023
+ function enableRetrieveHydrationInfoImpl() {
9024
+ _retrieveHydrationInfoImpl = retrieveHydrationInfoImpl;
8710
9025
  }
8711
-
8712
9026
  /**
8713
- * Sanitizer is used by the views to sanitize potentially dangerous values.
8714
- *
8715
- * @publicApi
9027
+ * Retrieves hydration info by reading the value from the `ngh` attribute
9028
+ * and accessing a corresponding slot in TransferState storage.
8716
9029
  */
8717
- class Sanitizer {
9030
+ function retrieveHydrationInfo(rNode, injector) {
9031
+ return _retrieveHydrationInfoImpl(rNode, injector);
8718
9032
  }
8719
- /** @nocollapse */
8720
- Sanitizer.ɵprov = ɵɵdefineInjectable({
8721
- token: Sanitizer,
8722
- providedIn: 'root',
8723
- factory: () => null,
8724
- });
8725
-
8726
9033
  /**
8727
- * @description Represents the version of Angular
8728
- *
8729
- * @publicApi
9034
+ * Retrieves an instance of a component LView from a given ViewRef.
9035
+ * Returns an instance of a component LView or `null` in case of an embedded view.
8730
9036
  */
8731
- class Version {
8732
- constructor(full) {
8733
- this.full = full;
8734
- this.major = full.split('.')[0];
8735
- this.minor = full.split('.')[1];
8736
- this.patch = full.split('.').slice(2).join('.');
9037
+ function getComponentLViewForHydration(viewRef) {
9038
+ // Reading an internal field from `ViewRef` instance.
9039
+ let lView = viewRef._lView;
9040
+ const tView = lView[TVIEW];
9041
+ // A registered ViewRef might represent an instance of an
9042
+ // embedded view, in which case we do not need to annotate it.
9043
+ if (tView.type === 2 /* TViewType.Embedded */) {
9044
+ return null;
8737
9045
  }
9046
+ // Check if it's a root view and if so, retrieve component's
9047
+ // LView from the first slot after the header.
9048
+ if (isRootView(lView)) {
9049
+ lView = lView[HEADER_OFFSET];
9050
+ }
9051
+ return lView;
8738
9052
  }
8739
- /**
8740
- * @publicApi
8741
- */
8742
- const VERSION = new Version('16.0.0-next.2');
8743
-
8744
- // This default value is when checking the hierarchy for a token.
8745
- //
8746
- // It means both:
8747
- // - the token is not provided by the current injector,
8748
- // - only the element injectors should be checked (ie do not check module injectors
8749
- //
8750
- // mod1
8751
- // /
8752
- // el1 mod2
8753
- // \ /
8754
- // el2
8755
- //
8756
- // When requesting el2.injector.get(token), we should check in the following order and return the
8757
- // first found value:
8758
- // - el2.injector.get(token, default)
8759
- // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
8760
- // - mod2.injector.get(token, default)
8761
- const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
8762
-
8763
- const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
8764
- function wrappedError(message, originalError) {
8765
- const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
8766
- const error = Error(msg);
8767
- error[ERROR_ORIGINAL_ERROR] = originalError;
8768
- return error;
8769
- }
8770
- function getOriginalError(error) {
8771
- return error[ERROR_ORIGINAL_ERROR];
9053
+ function getTextNodeContent(node) {
9054
+ return node.textContent?.replace(/\s/gm, '');
8772
9055
  }
8773
-
8774
9056
  /**
8775
- * Provides a hook for centralized exception handling.
8776
- *
8777
- * The default implementation of `ErrorHandler` prints error messages to the `console`. To
8778
- * intercept error handling, write a custom exception handler that replaces this default as
8779
- * appropriate for your app.
8780
- *
8781
- * @usageNotes
8782
- * ### Example
8783
- *
8784
- * ```
8785
- * class MyErrorHandler implements ErrorHandler {
8786
- * handleError(error) {
8787
- * // do something with the exception
8788
- * }
8789
- * }
8790
- *
8791
- * @NgModule({
8792
- * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
8793
- * })
8794
- * class MyModule {}
8795
- * ```
9057
+ * Restores text nodes and separators into the DOM that were lost during SSR
9058
+ * serialization. The hydration process replaces empty text nodes and text
9059
+ * nodes that are immediately adjacent to other text nodes with comment nodes
9060
+ * that this method filters on to restore those missing nodes that the
9061
+ * hydration process is expecting to be present.
8796
9062
  *
8797
- * @publicApi
9063
+ * @param node The app's root HTML Element
8798
9064
  */
8799
- class ErrorHandler {
8800
- constructor() {
8801
- /**
8802
- * @internal
8803
- */
8804
- this._console = console;
8805
- }
8806
- handleError(error) {
8807
- const originalError = this._findOriginalError(error);
8808
- this._console.error('ERROR', error);
8809
- if (originalError) {
8810
- this._console.error('ORIGINAL ERROR', originalError);
9065
+ function processTextNodeMarkersBeforeHydration(node) {
9066
+ const doc = getDocument();
9067
+ const commentNodesIterator = doc.createNodeIterator(node, NodeFilter.SHOW_COMMENT, {
9068
+ acceptNode(node) {
9069
+ const content = getTextNodeContent(node);
9070
+ const isTextNodeMarker = content === "ngetn" /* TextNodeMarker.EmptyNode */ || content === "ngtns" /* TextNodeMarker.Separator */;
9071
+ return isTextNodeMarker ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
8811
9072
  }
8812
- }
8813
- /** @internal */
8814
- _findOriginalError(error) {
8815
- let e = error && getOriginalError(error);
8816
- while (e && getOriginalError(e)) {
8817
- e = getOriginalError(e);
9073
+ });
9074
+ let currentNode;
9075
+ // We cannot modify the DOM while using the commentIterator,
9076
+ // because it throws off the iterator state.
9077
+ // So we collect all marker nodes first and then follow up with
9078
+ // applying the changes to the DOM: either inserting an empty node
9079
+ // or just removing the marker if it was used as a separator.
9080
+ const nodes = [];
9081
+ while (currentNode = commentNodesIterator.nextNode()) {
9082
+ nodes.push(currentNode);
9083
+ }
9084
+ for (const node of nodes) {
9085
+ if (node.textContent === "ngetn" /* TextNodeMarker.EmptyNode */) {
9086
+ node.replaceWith(doc.createTextNode(''));
9087
+ }
9088
+ else {
9089
+ node.remove();
8818
9090
  }
8819
- return e || null;
8820
9091
  }
8821
9092
  }
8822
-
8823
- const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
8824
- /**
8825
- * Internal token that specifies whether hydration is enabled.
8826
- */
8827
- const IS_HYDRATION_FEATURE_ENABLED = new InjectionToken(NG_DEV_MODE$1 ? 'IS_HYDRATION_FEATURE_ENABLED' : '');
8828
- // By default (in client rendering mode), we remove all the contents
8829
- // of the host element and render an application after that.
8830
- const PRESERVE_HOST_CONTENT_DEFAULT = false;
8831
9093
  /**
8832
- * Internal token that indicates whether host element content should be
8833
- * retained during the bootstrap.
9094
+ * Marks a node as "claimed" by hydration process.
9095
+ * This is needed to make assessments in tests whether
9096
+ * the hydration process handled all nodes.
8834
9097
  */
8835
- const PRESERVE_HOST_CONTENT = new InjectionToken(NG_DEV_MODE$1 ? 'PRESERVE_HOST_CONTENT' : '', {
8836
- providedIn: 'root',
8837
- factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
8838
- });
8839
-
8840
- function normalizeDebugBindingName(name) {
8841
- // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
8842
- name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
8843
- return `ng-reflect-${name}`;
8844
- }
8845
- const CAMEL_CASE_REGEXP = /([A-Z])/g;
8846
- function camelCaseToDashCase(input) {
8847
- return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
8848
- }
8849
- function normalizeDebugBindingValue(value) {
8850
- try {
8851
- // Limit the size of the value as otherwise the DOM just gets polluted.
8852
- return value != null ? value.toString().slice(0, 30) : value;
9098
+ function markRNodeAsClaimedByHydration(node, checkIfAlreadyClaimed = true) {
9099
+ if (!ngDevMode) {
9100
+ throw new Error('Calling `markRNodeAsClaimedByHydration` in prod mode ' +
9101
+ 'is not supported and likely a mistake.');
8853
9102
  }
8854
- catch (e) {
8855
- return '[ERROR] Exception while trying to serialize the value';
9103
+ if (checkIfAlreadyClaimed && isRNodeClaimedForHydration(node)) {
9104
+ throw new Error('Trying to claim a node, which was claimed already.');
8856
9105
  }
9106
+ node.__claimed = true;
9107
+ ngDevMode.hydratedNodes++;
9108
+ }
9109
+ function isRNodeClaimedForHydration(node) {
9110
+ return !!node.__claimed;
9111
+ }
9112
+ function setSegmentHead(hydrationInfo, index, node) {
9113
+ hydrationInfo.segmentHeads ?? (hydrationInfo.segmentHeads = {});
9114
+ hydrationInfo.segmentHeads[index] = node;
9115
+ }
9116
+ function getSegmentHead(hydrationInfo, index) {
9117
+ return hydrationInfo.segmentHeads?.[index] ?? null;
8857
9118
  }
8858
-
8859
9119
  /**
8860
- *
8861
- * @codeGenApi
9120
+ * Returns the size of an <ng-container>, using either the information
9121
+ * serialized in `ELEMENT_CONTAINERS` (element container size) or by
9122
+ * computing the sum of root nodes in all dehydrated views in a given
9123
+ * container (in case this `<ng-container>` was also used as a view
9124
+ * container host node, e.g. <ng-container *ngIf>).
8862
9125
  */
8863
- function ɵɵresolveWindow(element) {
8864
- return element.ownerDocument.defaultView;
9126
+ function getNgContainerSize(hydrationInfo, index) {
9127
+ const data = hydrationInfo.data;
9128
+ let size = data[ELEMENT_CONTAINERS]?.[index] ?? null;
9129
+ // If there is no serialized information available in the `ELEMENT_CONTAINERS` slot,
9130
+ // check if we have info about view containers at this location (e.g.
9131
+ // `<ng-container *ngIf>`) and use container size as a number of root nodes in this
9132
+ // element container.
9133
+ if (size === null && data[CONTAINERS]?.[index]) {
9134
+ size = calcSerializedContainerSize(hydrationInfo, index);
9135
+ }
9136
+ return size;
9137
+ }
9138
+ function getSerializedContainerViews(hydrationInfo, index) {
9139
+ return hydrationInfo.data[CONTAINERS]?.[index] ?? null;
8865
9140
  }
8866
9141
  /**
8867
- *
8868
- * @codeGenApi
9142
+ * Computes the size of a serialized container (the number of root nodes)
9143
+ * by calculating the sum of root nodes in all dehydrated views in this container.
8869
9144
  */
8870
- function ɵɵresolveDocument(element) {
8871
- return element.ownerDocument;
9145
+ function calcSerializedContainerSize(hydrationInfo, index) {
9146
+ const views = getSerializedContainerViews(hydrationInfo, index) ?? [];
9147
+ let numNodes = 0;
9148
+ for (let view of views) {
9149
+ numNodes += view[NUM_ROOT_NODES];
9150
+ }
9151
+ return numNodes;
8872
9152
  }
9153
+
8873
9154
  /**
9155
+ * Represents a component created by a `ComponentFactory`.
9156
+ * Provides access to the component instance and related objects,
9157
+ * and provides the means of destroying the instance.
8874
9158
  *
8875
- * @codeGenApi
9159
+ * @publicApi
8876
9160
  */
8877
- function ɵɵresolveBody(element) {
8878
- return element.ownerDocument.body;
9161
+ class ComponentRef$1 {
8879
9162
  }
8880
9163
  /**
8881
- * The special delimiter we use to separate property names, prefixes, and suffixes
8882
- * in property binding metadata. See storeBindingMetadata().
9164
+ * Base class for a factory that can create a component dynamically.
9165
+ * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
9166
+ * Use the resulting `ComponentFactory.create()` method to create a component of that type.
8883
9167
  *
8884
- * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
8885
- * because it is a very uncommon character that is unlikely to be part of a user's
8886
- * property names or interpolation strings. If it is in fact used in a property
8887
- * binding, DebugElement.properties will not return the correct value for that
8888
- * binding. However, there should be no runtime effect for real applications.
9168
+ * @see [Dynamic Components](guide/dynamic-component-loader)
8889
9169
  *
8890
- * This character is typically rendered as a question mark inside of a diamond.
8891
- * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
9170
+ * @publicApi
8892
9171
  *
9172
+ * @deprecated Angular no longer requires Component factories. Please use other APIs where
9173
+ * Component class can be used directly.
8893
9174
  */
8894
- const INTERPOLATION_DELIMITER = `�`;
8895
- /**
8896
- * Unwrap a value which might be behind a closure (for forward declaration reasons).
8897
- */
8898
- function maybeUnwrapFn(value) {
8899
- if (value instanceof Function) {
8900
- return value();
8901
- }
8902
- else {
8903
- return value;
8904
- }
9175
+ class ComponentFactory$1 {
8905
9176
  }
8906
9177
 
8907
- /** Verifies that a given type is a Standalone Component. */
8908
- function assertStandaloneComponentType(type) {
8909
- assertComponentDef(type);
8910
- const componentDef = getComponentDef(type);
8911
- if (!componentDef.standalone) {
8912
- throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
8913
- `but Angular expects to have a standalone component here. ` +
8914
- `Please make sure the ${stringifyForError(type)} component has ` +
8915
- `the \`standalone: true\` flag in the decorator.`);
8916
- }
8917
- }
8918
- /** Verifies whether a given type is a component */
8919
- function assertComponentDef(type) {
8920
- if (!getComponentDef(type)) {
8921
- throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
8922
- `make sure it has the \`@Component\` decorator.`);
8923
- }
8924
- }
8925
- /** Called when there are multiple component selectors that match a given node */
8926
- function throwMultipleComponentError(tNode, first, second) {
8927
- throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
8928
- `${stringifyForError(first)} and ` +
8929
- `${stringifyForError(second)}`);
9178
+ function noComponentFactoryError(component) {
9179
+ const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
9180
+ error[ERROR_COMPONENT] = component;
9181
+ return error;
8930
9182
  }
8931
- /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
8932
- function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
8933
- const field = propName ? ` for '${propName}'` : '';
8934
- let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
8935
- if (creationMode) {
8936
- msg +=
8937
- ` It seems like the view has been created after its parent and its children have been dirty checked.` +
8938
- ` Has it been created in a change detection hook?`;
8939
- }
8940
- throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
9183
+ const ERROR_COMPONENT = 'ngComponent';
9184
+ function getComponent$1(error) {
9185
+ return error[ERROR_COMPONENT];
8941
9186
  }
8942
- function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
8943
- const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
8944
- let oldValue = prefix, newValue = prefix;
8945
- for (let i = 0; i < chunks.length; i++) {
8946
- const slotIdx = rootIndex + i;
8947
- oldValue += `${lView[slotIdx]}${chunks[i]}`;
8948
- newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
9187
+ class _NullComponentFactoryResolver {
9188
+ resolveComponentFactory(component) {
9189
+ throw noComponentFactoryError(component);
8949
9190
  }
8950
- return { propName, oldValue, newValue };
8951
9191
  }
8952
9192
  /**
8953
- * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
8954
- * - property name (for property bindings or interpolations)
8955
- * - old and new values, enriched using information from metadata
9193
+ * A simple registry that maps `Components` to generated `ComponentFactory` classes
9194
+ * that can be used to create instances of components.
9195
+ * Use to obtain the factory for a given component type,
9196
+ * then use the factory's `create()` method to create a component of that type.
8956
9197
  *
8957
- * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
8958
- * function description.
9198
+ * Note: since v13, dynamic component creation via
9199
+ * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
9200
+ * does **not** require resolving component factory: component class can be used directly.
9201
+ *
9202
+ * @publicApi
9203
+ *
9204
+ * @deprecated Angular no longer requires Component factories. Please use other APIs where
9205
+ * Component class can be used directly.
8959
9206
  */
8960
- function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
8961
- const tData = lView[TVIEW].data;
8962
- const metadata = tData[bindingIndex];
8963
- if (typeof metadata === 'string') {
8964
- // metadata for property interpolation
8965
- if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
8966
- return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
8967
- }
8968
- // metadata for property binding
8969
- return { propName: metadata, oldValue, newValue };
8970
- }
8971
- // metadata is not available for this expression, check if this expression is a part of the
8972
- // property interpolation by going from the current binding index left and look for a string that
8973
- // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
8974
- // [..., 'id�Prefix � and � suffix', null, null, null, ...]
8975
- if (metadata === null) {
8976
- let idx = bindingIndex - 1;
8977
- while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
8978
- idx--;
8979
- }
8980
- const meta = tData[idx];
8981
- if (typeof meta === 'string') {
8982
- const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
8983
- // first interpolation delimiter separates property name from interpolation parts (in case of
8984
- // property interpolations), so we subtract one from total number of found delimiters
8985
- if (matches && (matches.length - 1) > bindingIndex - idx) {
8986
- return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
8987
- }
8988
- }
8989
- }
8990
- return { propName: undefined, oldValue, newValue };
9207
+ class ComponentFactoryResolver$1 {
8991
9208
  }
9209
+ ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
8992
9210
 
8993
9211
  /**
8994
- * Returns an index of `classToSearch` in `className` taking token boundaries into account.
9212
+ * Creates an ElementRef from the most recent node.
8995
9213
  *
8996
- * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
9214
+ * @returns The ElementRef instance to use
9215
+ */
9216
+ function injectElementRef() {
9217
+ return createElementRef(getCurrentTNode(), getLView());
9218
+ }
9219
+ /**
9220
+ * Creates an ElementRef given a node.
8997
9221
  *
8998
- * @param className A string containing classes (whitespace separated)
8999
- * @param classToSearch A class name to locate
9000
- * @param startingIndex Starting location of search
9001
- * @returns an index of the located class (or -1 if not found)
9222
+ * @param tNode The node for which you'd like an ElementRef
9223
+ * @param lView The view to which the node belongs
9224
+ * @returns The ElementRef instance to use
9002
9225
  */
9003
- function classIndexOf(className, classToSearch, startingIndex) {
9004
- ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
9005
- let end = className.length;
9006
- while (true) {
9007
- const foundIndex = className.indexOf(classToSearch, startingIndex);
9008
- if (foundIndex === -1)
9009
- return foundIndex;
9010
- if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
9011
- // Ensure that it has leading whitespace
9012
- const length = classToSearch.length;
9013
- if (foundIndex + length === end ||
9014
- className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
9015
- // Ensure that it has trailing whitespace
9016
- return foundIndex;
9017
- }
9018
- }
9019
- // False positive, keep searching from where we left off.
9020
- startingIndex = foundIndex + 1;
9021
- }
9226
+ function createElementRef(tNode, lView) {
9227
+ return new ElementRef(getNativeByTNode(tNode, lView));
9022
9228
  }
9023
-
9024
- const NG_TEMPLATE_SELECTOR = 'ng-template';
9025
9229
  /**
9026
- * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
9230
+ * A wrapper around a native element inside of a View.
9027
9231
  *
9028
- * @param attrs `TAttributes` to search through.
9029
- * @param cssClassToMatch class to match (lowercase)
9030
- * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
9031
- * addition to the `AttributeMarker.Classes`.
9232
+ * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
9233
+ * element.
9234
+ *
9235
+ * @security Permitting direct access to the DOM can make your application more vulnerable to
9236
+ * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
9237
+ * [Security Guide](https://g.co/ng/security).
9238
+ *
9239
+ * @publicApi
9032
9240
  */
9033
- function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
9034
- // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
9035
- // It is strange to me that sometimes the class information comes in form of `class` attribute
9036
- // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
9037
- // if that is the right behavior.
9038
- ngDevMode &&
9039
- assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
9040
- let i = 0;
9041
- while (i < attrs.length) {
9042
- let item = attrs[i++];
9043
- if (isProjectionMode && item === 'class') {
9044
- item = attrs[i];
9045
- if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
9046
- return true;
9047
- }
9048
- }
9049
- else if (item === 1 /* AttributeMarker.Classes */) {
9050
- // We found the classes section. Start searching for the class.
9051
- while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
9052
- // while we have strings
9053
- if (item.toLowerCase() === cssClassToMatch)
9054
- return true;
9055
- }
9056
- return false;
9057
- }
9241
+ // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
9242
+ // i.e. users have to ask for what they need. With that, we can build better analysis tools
9243
+ // and could do better codegen in the future.
9244
+ class ElementRef {
9245
+ constructor(nativeElement) {
9246
+ this.nativeElement = nativeElement;
9058
9247
  }
9059
- return false;
9060
9248
  }
9061
9249
  /**
9062
- * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
9250
+ * @internal
9251
+ * @nocollapse
9252
+ */
9253
+ ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
9254
+ /**
9255
+ * Unwraps `ElementRef` and return the `nativeElement`.
9256
+ *
9257
+ * @param value value to unwrap
9258
+ * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
9259
+ */
9260
+ function unwrapElementRef(value) {
9261
+ return value instanceof ElementRef ? value.nativeElement : value;
9262
+ }
9263
+
9264
+ /**
9265
+ * Creates and initializes a custom renderer that implements the `Renderer2` base class.
9266
+ *
9267
+ * @publicApi
9268
+ */
9269
+ class RendererFactory2 {
9270
+ }
9271
+ /**
9272
+ * Extend this base class to implement custom rendering. By default, Angular
9273
+ * renders a template into DOM. You can use custom rendering to intercept
9274
+ * rendering calls, or to render to something other than DOM.
9063
9275
  *
9064
- * @param tNode current TNode
9276
+ * Create your custom renderer using `RendererFactory2`.
9277
+ *
9278
+ * Use a custom renderer to bypass Angular's templating and
9279
+ * make custom UI changes that can't be expressed declaratively.
9280
+ * For example if you need to set a property or an attribute whose name is
9281
+ * not statically known, use the `setProperty()` or
9282
+ * `setAttribute()` method.
9283
+ *
9284
+ * @publicApi
9065
9285
  */
9066
- function isInlineTemplate(tNode) {
9067
- return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
9286
+ class Renderer2 {
9068
9287
  }
9069
9288
  /**
9070
- * Function that checks whether a given tNode matches tag-based selector and has a valid type.
9289
+ * @internal
9290
+ * @nocollapse
9291
+ */
9292
+ Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
9293
+ /** Injects a Renderer2 for the current component. */
9294
+ function injectRenderer2() {
9295
+ // We need the Renderer to be based on the component that it's being injected into, however since
9296
+ // DI happens before we've entered its view, `getLView` will return the parent view instead.
9297
+ const lView = getLView();
9298
+ const tNode = getCurrentTNode();
9299
+ const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
9300
+ return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
9301
+ }
9302
+
9303
+ /**
9304
+ * Sanitizer is used by the views to sanitize potentially dangerous values.
9071
9305
  *
9072
- * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
9073
- * directive matching mode:
9074
- * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
9075
- * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
9076
- * tag name was extracted from * syntax so we would match the same directive twice);
9077
- * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
9078
- * (applicable to TNodeType.Container only).
9306
+ * @publicApi
9079
9307
  */
9080
- function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
9081
- const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
9082
- return currentSelector === tagNameToCompare;
9308
+ class Sanitizer {
9083
9309
  }
9310
+ /** @nocollapse */
9311
+ Sanitizer.ɵprov = ɵɵdefineInjectable({
9312
+ token: Sanitizer,
9313
+ providedIn: 'root',
9314
+ factory: () => null,
9315
+ });
9316
+
9084
9317
  /**
9085
- * A utility function to match an Ivy node static data against a simple CSS selector
9318
+ * @description Represents the version of Angular
9086
9319
  *
9087
- * @param node static data of the node to match
9088
- * @param selector The selector to try matching against the node.
9089
- * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
9090
- * directive matching.
9091
- * @returns true if node matches the selector.
9320
+ * @publicApi
9092
9321
  */
9093
- function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
9094
- ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
9095
- let mode = 4 /* SelectorFlags.ELEMENT */;
9096
- const nodeAttrs = tNode.attrs || [];
9097
- // Find the index of first attribute that has no value, only a name.
9098
- const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
9099
- // When processing ":not" selectors, we skip to the next ":not" if the
9100
- // current one doesn't match
9101
- let skipToNextSelector = false;
9102
- for (let i = 0; i < selector.length; i++) {
9103
- const current = selector[i];
9104
- if (typeof current === 'number') {
9105
- // If we finish processing a :not selector and it hasn't failed, return false
9106
- if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
9107
- return false;
9108
- }
9109
- // If we are skipping to the next :not() and this mode flag is positive,
9110
- // it's a part of the current :not() selector, and we should keep skipping
9111
- if (skipToNextSelector && isPositive(current))
9112
- continue;
9113
- skipToNextSelector = false;
9114
- mode = current | (mode & 1 /* SelectorFlags.NOT */);
9115
- continue;
9116
- }
9117
- if (skipToNextSelector)
9118
- continue;
9119
- if (mode & 4 /* SelectorFlags.ELEMENT */) {
9120
- mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
9121
- if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
9122
- current === '' && selector.length === 1) {
9123
- if (isPositive(mode))
9124
- return false;
9125
- skipToNextSelector = true;
9126
- }
9127
- }
9128
- else {
9129
- const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
9130
- // special case for matching against classes when a tNode has been instantiated with
9131
- // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
9132
- if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
9133
- if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
9134
- if (isPositive(mode))
9135
- return false;
9136
- skipToNextSelector = true;
9137
- }
9138
- continue;
9139
- }
9140
- const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
9141
- const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
9142
- if (attrIndexInNode === -1) {
9143
- if (isPositive(mode))
9144
- return false;
9145
- skipToNextSelector = true;
9146
- continue;
9147
- }
9148
- if (selectorAttrValue !== '') {
9149
- let nodeAttrValue;
9150
- if (attrIndexInNode > nameOnlyMarkerIdx) {
9151
- nodeAttrValue = '';
9152
- }
9153
- else {
9154
- ngDevMode &&
9155
- assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
9156
- // we lowercase the attribute value to be able to match
9157
- // selectors without case-sensitivity
9158
- // (selectors are already in lowercase when generated)
9159
- nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
9160
- }
9161
- const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
9162
- if (compareAgainstClassName &&
9163
- classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
9164
- mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
9165
- if (isPositive(mode))
9166
- return false;
9167
- skipToNextSelector = true;
9168
- }
9169
- }
9170
- }
9322
+ class Version {
9323
+ constructor(full) {
9324
+ this.full = full;
9325
+ this.major = full.split('.')[0];
9326
+ this.minor = full.split('.')[1];
9327
+ this.patch = full.split('.').slice(2).join('.');
9171
9328
  }
9172
- return isPositive(mode) || skipToNextSelector;
9173
9329
  }
9174
- function isPositive(mode) {
9175
- return (mode & 1 /* SelectorFlags.NOT */) === 0;
9330
+ /**
9331
+ * @publicApi
9332
+ */
9333
+ const VERSION = new Version('16.0.0-next.3');
9334
+
9335
+ // This default value is when checking the hierarchy for a token.
9336
+ //
9337
+ // It means both:
9338
+ // - the token is not provided by the current injector,
9339
+ // - only the element injectors should be checked (ie do not check module injectors
9340
+ //
9341
+ // mod1
9342
+ // /
9343
+ // el1 mod2
9344
+ // \ /
9345
+ // el2
9346
+ //
9347
+ // When requesting el2.injector.get(token), we should check in the following order and return the
9348
+ // first found value:
9349
+ // - el2.injector.get(token, default)
9350
+ // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
9351
+ // - mod2.injector.get(token, default)
9352
+ const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
9353
+
9354
+ const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
9355
+ function wrappedError(message, originalError) {
9356
+ const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
9357
+ const error = Error(msg);
9358
+ error[ERROR_ORIGINAL_ERROR] = originalError;
9359
+ return error;
9360
+ }
9361
+ function getOriginalError(error) {
9362
+ return error[ERROR_ORIGINAL_ERROR];
9176
9363
  }
9364
+
9177
9365
  /**
9178
- * Examines the attribute's definition array for a node to find the index of the
9179
- * attribute that matches the given `name`.
9180
- *
9181
- * NOTE: This will not match namespaced attributes.
9366
+ * Provides a hook for centralized exception handling.
9182
9367
  *
9183
- * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
9184
- * The following table summarizes which types of attributes we attempt to match:
9368
+ * The default implementation of `ErrorHandler` prints error messages to the `console`. To
9369
+ * intercept error handling, write a custom exception handler that replaces this default as
9370
+ * appropriate for your app.
9185
9371
  *
9186
- * ===========================================================================================================
9187
- * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
9188
- * Attributes
9189
- * ===========================================================================================================
9190
- * Inline + Projection | YES | YES | NO | YES
9191
- * -----------------------------------------------------------------------------------------------------------
9192
- * Inline + Directive | NO | NO | YES | NO
9193
- * -----------------------------------------------------------------------------------------------------------
9194
- * Non-inline + Projection | YES | YES | NO | YES
9195
- * -----------------------------------------------------------------------------------------------------------
9196
- * Non-inline + Directive | YES | YES | NO | YES
9197
- * ===========================================================================================================
9372
+ * @usageNotes
9373
+ * ### Example
9198
9374
  *
9199
- * @param name the name of the attribute to find
9200
- * @param attrs the attribute array to examine
9201
- * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
9202
- * rather than a manually expanded template node (e.g `<ng-template>`).
9203
- * @param isProjectionMode true if we are matching against content projection otherwise we are
9204
- * matching against directives.
9205
- */
9206
- function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
9207
- if (attrs === null)
9208
- return -1;
9209
- let i = 0;
9210
- if (isProjectionMode || !isInlineTemplate) {
9211
- let bindingsMode = false;
9212
- while (i < attrs.length) {
9213
- const maybeAttrName = attrs[i];
9214
- if (maybeAttrName === name) {
9215
- return i;
9216
- }
9217
- else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
9218
- bindingsMode = true;
9219
- }
9220
- else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
9221
- let value = attrs[++i];
9222
- // We should skip classes here because we have a separate mechanism for
9223
- // matching classes in projection mode.
9224
- while (typeof value === 'string') {
9225
- value = attrs[++i];
9226
- }
9227
- continue;
9228
- }
9229
- else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
9230
- // We do not care about Template attributes in this scenario.
9231
- break;
9232
- }
9233
- else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
9234
- // Skip the whole namespaced attribute and value. This is by design.
9235
- i += 4;
9236
- continue;
9237
- }
9238
- // In binding mode there are only names, rather than name-value pairs.
9239
- i += bindingsMode ? 1 : 2;
9240
- }
9241
- // We did not match the attribute
9242
- return -1;
9243
- }
9244
- else {
9245
- return matchTemplateAttribute(attrs, name);
9375
+ * ```
9376
+ * class MyErrorHandler implements ErrorHandler {
9377
+ * handleError(error) {
9378
+ * // do something with the exception
9379
+ * }
9380
+ * }
9381
+ *
9382
+ * @NgModule({
9383
+ * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
9384
+ * })
9385
+ * class MyModule {}
9386
+ * ```
9387
+ *
9388
+ * @publicApi
9389
+ */
9390
+ class ErrorHandler {
9391
+ constructor() {
9392
+ /**
9393
+ * @internal
9394
+ */
9395
+ this._console = console;
9246
9396
  }
9247
- }
9248
- function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
9249
- for (let i = 0; i < selector.length; i++) {
9250
- if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
9251
- return true;
9397
+ handleError(error) {
9398
+ const originalError = this._findOriginalError(error);
9399
+ this._console.error('ERROR', error);
9400
+ if (originalError) {
9401
+ this._console.error('ORIGINAL ERROR', originalError);
9252
9402
  }
9253
9403
  }
9254
- return false;
9255
- }
9256
- function getProjectAsAttrValue(tNode) {
9257
- const nodeAttrs = tNode.attrs;
9258
- if (nodeAttrs != null) {
9259
- const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
9260
- // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
9261
- // (attribute names are stored at even indexes)
9262
- if ((ngProjectAsAttrIdx & 1) === 0) {
9263
- return nodeAttrs[ngProjectAsAttrIdx + 1];
9404
+ /** @internal */
9405
+ _findOriginalError(error) {
9406
+ let e = error && getOriginalError(error);
9407
+ while (e && getOriginalError(e)) {
9408
+ e = getOriginalError(e);
9264
9409
  }
9410
+ return e || null;
9265
9411
  }
9266
- return null;
9267
9412
  }
9268
- function getNameOnlyMarkerIndex(nodeAttrs) {
9269
- for (let i = 0; i < nodeAttrs.length; i++) {
9270
- const nodeAttr = nodeAttrs[i];
9271
- if (isNameOnlyAttributeMarker(nodeAttr)) {
9272
- return i;
9273
- }
9274
- }
9275
- return nodeAttrs.length;
9413
+
9414
+ const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
9415
+ /**
9416
+ * Internal token that specifies whether hydration is enabled.
9417
+ */
9418
+ const IS_HYDRATION_FEATURE_ENABLED = new InjectionToken(NG_DEV_MODE$1 ? 'IS_HYDRATION_FEATURE_ENABLED' : '');
9419
+ // By default (in client rendering mode), we remove all the contents
9420
+ // of the host element and render an application after that.
9421
+ const PRESERVE_HOST_CONTENT_DEFAULT = false;
9422
+ /**
9423
+ * Internal token that indicates whether host element content should be
9424
+ * retained during the bootstrap.
9425
+ */
9426
+ const PRESERVE_HOST_CONTENT = new InjectionToken(NG_DEV_MODE$1 ? 'PRESERVE_HOST_CONTENT' : '', {
9427
+ providedIn: 'root',
9428
+ factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
9429
+ });
9430
+
9431
+ function normalizeDebugBindingName(name) {
9432
+ // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
9433
+ name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
9434
+ return `ng-reflect-${name}`;
9276
9435
  }
9277
- function matchTemplateAttribute(attrs, name) {
9278
- let i = attrs.indexOf(4 /* AttributeMarker.Template */);
9279
- if (i > -1) {
9280
- i++;
9281
- while (i < attrs.length) {
9282
- const attr = attrs[i];
9283
- // Return in case we checked all template attrs and are switching to the next section in the
9284
- // attrs array (that starts with a number that represents an attribute marker).
9285
- if (typeof attr === 'number')
9286
- return -1;
9287
- if (attr === name)
9288
- return i;
9289
- i++;
9290
- }
9436
+ const CAMEL_CASE_REGEXP = /([A-Z])/g;
9437
+ function camelCaseToDashCase(input) {
9438
+ return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
9439
+ }
9440
+ function normalizeDebugBindingValue(value) {
9441
+ try {
9442
+ // Limit the size of the value as otherwise the DOM just gets polluted.
9443
+ return value != null ? value.toString().slice(0, 30) : value;
9444
+ }
9445
+ catch (e) {
9446
+ return '[ERROR] Exception while trying to serialize the value';
9291
9447
  }
9292
- return -1;
9293
9448
  }
9449
+
9294
9450
  /**
9295
- * Checks whether a selector is inside a CssSelectorList
9296
- * @param selector Selector to be checked.
9297
- * @param list List in which to look for the selector.
9451
+ *
9452
+ * @codeGenApi
9298
9453
  */
9299
- function isSelectorInSelectorList(selector, list) {
9300
- selectorListLoop: for (let i = 0; i < list.length; i++) {
9301
- const currentSelectorInList = list[i];
9302
- if (selector.length !== currentSelectorInList.length) {
9303
- continue;
9304
- }
9305
- for (let j = 0; j < selector.length; j++) {
9306
- if (selector[j] !== currentSelectorInList[j]) {
9307
- continue selectorListLoop;
9308
- }
9309
- }
9310
- return true;
9311
- }
9312
- return false;
9454
+ function ɵɵresolveWindow(element) {
9455
+ return element.ownerDocument.defaultView;
9313
9456
  }
9314
- function maybeWrapInNotSelector(isNegativeMode, chunk) {
9315
- return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
9457
+ /**
9458
+ *
9459
+ * @codeGenApi
9460
+ */
9461
+ function ɵɵresolveDocument(element) {
9462
+ return element.ownerDocument;
9316
9463
  }
9317
- function stringifyCSSSelector(selector) {
9318
- let result = selector[0];
9319
- let i = 1;
9320
- let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9321
- let currentChunk = '';
9322
- let isNegativeMode = false;
9323
- while (i < selector.length) {
9324
- let valueOrMarker = selector[i];
9325
- if (typeof valueOrMarker === 'string') {
9326
- if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
9327
- const attrValue = selector[++i];
9328
- currentChunk +=
9329
- '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
9330
- }
9331
- else if (mode & 8 /* SelectorFlags.CLASS */) {
9332
- currentChunk += '.' + valueOrMarker;
9333
- }
9334
- else if (mode & 4 /* SelectorFlags.ELEMENT */) {
9335
- currentChunk += ' ' + valueOrMarker;
9336
- }
9337
- }
9338
- else {
9339
- //
9340
- // Append current chunk to the final result in case we come across SelectorFlag, which
9341
- // indicates that the previous section of a selector is over. We need to accumulate content
9342
- // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
9343
- // ```
9344
- // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
9345
- // ```
9346
- // should be transformed to `.classA :not(.classB .classC)`.
9347
- //
9348
- // Note: for negative selector part, we accumulate content between flags until we find the
9349
- // next negative flag. This is needed to support a case where `:not()` rule contains more than
9350
- // one chunk, e.g. the following selector:
9351
- // ```
9352
- // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
9353
- // ```
9354
- // should be stringified to `:not(p.foo) :not(.bar)`
9355
- //
9356
- if (currentChunk !== '' && !isPositive(valueOrMarker)) {
9357
- result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9358
- currentChunk = '';
9359
- }
9360
- mode = valueOrMarker;
9361
- // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9362
- // mode is maintained for remaining chunks of a selector.
9363
- isNegativeMode = isNegativeMode || !isPositive(mode);
9364
- }
9365
- i++;
9366
- }
9367
- if (currentChunk !== '') {
9368
- result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9369
- }
9370
- return result;
9464
+ /**
9465
+ *
9466
+ * @codeGenApi
9467
+ */
9468
+ function ɵɵresolveBody(element) {
9469
+ return element.ownerDocument.body;
9371
9470
  }
9372
9471
  /**
9373
- * Generates string representation of CSS selector in parsed form.
9472
+ * The special delimiter we use to separate property names, prefixes, and suffixes
9473
+ * in property binding metadata. See storeBindingMetadata().
9374
9474
  *
9375
- * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
9376
- * additional parsing at runtime (for example, for directive matching). However in some cases (for
9377
- * example, while bootstrapping a component), a string version of the selector is required to query
9378
- * for the host element on the page. This function takes the parsed form of a selector and returns
9379
- * its string representation.
9475
+ * We intentionally use the Unicode "REPLACEMENT CHARACTER" (U+FFFD) as a delimiter
9476
+ * because it is a very uncommon character that is unlikely to be part of a user's
9477
+ * property names or interpolation strings. If it is in fact used in a property
9478
+ * binding, DebugElement.properties will not return the correct value for that
9479
+ * binding. However, there should be no runtime effect for real applications.
9480
+ *
9481
+ * This character is typically rendered as a question mark inside of a diamond.
9482
+ * See https://en.wikipedia.org/wiki/Specials_(Unicode_block)
9380
9483
  *
9381
- * @param selectorList selector in parsed form
9382
- * @returns string representation of a given selector
9383
9484
  */
9384
- function stringifyCSSSelectorList(selectorList) {
9385
- return selectorList.map(stringifyCSSSelector).join(',');
9485
+ const INTERPOLATION_DELIMITER = `�`;
9486
+ /**
9487
+ * Unwrap a value which might be behind a closure (for forward declaration reasons).
9488
+ */
9489
+ function maybeUnwrapFn(value) {
9490
+ if (value instanceof Function) {
9491
+ return value();
9492
+ }
9493
+ else {
9494
+ return value;
9495
+ }
9496
+ }
9497
+
9498
+ /** Verifies that a given type is a Standalone Component. */
9499
+ function assertStandaloneComponentType(type) {
9500
+ assertComponentDef(type);
9501
+ const componentDef = getComponentDef(type);
9502
+ if (!componentDef.standalone) {
9503
+ throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
9504
+ `but Angular expects to have a standalone component here. ` +
9505
+ `Please make sure the ${stringifyForError(type)} component has ` +
9506
+ `the \`standalone: true\` flag in the decorator.`);
9507
+ }
9508
+ }
9509
+ /** Verifies whether a given type is a component */
9510
+ function assertComponentDef(type) {
9511
+ if (!getComponentDef(type)) {
9512
+ throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
9513
+ `make sure it has the \`@Component\` decorator.`);
9514
+ }
9515
+ }
9516
+ /** Called when there are multiple component selectors that match a given node */
9517
+ function throwMultipleComponentError(tNode, first, second) {
9518
+ throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
9519
+ `${stringifyForError(first)} and ` +
9520
+ `${stringifyForError(second)}`);
9521
+ }
9522
+ /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
9523
+ function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
9524
+ const field = propName ? ` for '${propName}'` : '';
9525
+ let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
9526
+ if (creationMode) {
9527
+ msg +=
9528
+ ` It seems like the view has been created after its parent and its children have been dirty checked.` +
9529
+ ` Has it been created in a change detection hook?`;
9530
+ }
9531
+ throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
9532
+ }
9533
+ function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
9534
+ const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
9535
+ let oldValue = prefix, newValue = prefix;
9536
+ for (let i = 0; i < chunks.length; i++) {
9537
+ const slotIdx = rootIndex + i;
9538
+ oldValue += `${lView[slotIdx]}${chunks[i]}`;
9539
+ newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
9540
+ }
9541
+ return { propName, oldValue, newValue };
9386
9542
  }
9387
9543
  /**
9388
- * Extracts attributes and classes information from a given CSS selector.
9389
- *
9390
- * This function is used while creating a component dynamically. In this case, the host element
9391
- * (that is created dynamically) should contain attributes and classes specified in component's CSS
9392
- * selector.
9544
+ * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
9545
+ * - property name (for property bindings or interpolations)
9546
+ * - old and new values, enriched using information from metadata
9393
9547
  *
9394
- * @param selector CSS selector in parsed form (in a form of array)
9395
- * @returns object with `attrs` and `classes` fields that contain extracted information
9548
+ * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
9549
+ * function description.
9396
9550
  */
9397
- function extractAttrsAndClassesFromSelector(selector) {
9398
- const attrs = [];
9399
- const classes = [];
9400
- let i = 1;
9401
- let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9402
- while (i < selector.length) {
9403
- let valueOrMarker = selector[i];
9404
- if (typeof valueOrMarker === 'string') {
9405
- if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
9406
- if (valueOrMarker !== '') {
9407
- attrs.push(valueOrMarker, selector[++i]);
9408
- }
9409
- }
9410
- else if (mode === 8 /* SelectorFlags.CLASS */) {
9411
- classes.push(valueOrMarker);
9412
- }
9551
+ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
9552
+ const tData = lView[TVIEW].data;
9553
+ const metadata = tData[bindingIndex];
9554
+ if (typeof metadata === 'string') {
9555
+ // metadata for property interpolation
9556
+ if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
9557
+ return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
9413
9558
  }
9414
- else {
9415
- // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9416
- // mode is maintained for remaining chunks of a selector. Since attributes and classes are
9417
- // extracted only for "positive" part of the selector, we can stop here.
9418
- if (!isPositive(mode))
9419
- break;
9420
- mode = valueOrMarker;
9559
+ // metadata for property binding
9560
+ return { propName: metadata, oldValue, newValue };
9561
+ }
9562
+ // metadata is not available for this expression, check if this expression is a part of the
9563
+ // property interpolation by going from the current binding index left and look for a string that
9564
+ // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
9565
+ // [..., 'id�Prefix � and � suffix', null, null, null, ...]
9566
+ if (metadata === null) {
9567
+ let idx = bindingIndex - 1;
9568
+ while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
9569
+ idx--;
9570
+ }
9571
+ const meta = tData[idx];
9572
+ if (typeof meta === 'string') {
9573
+ const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
9574
+ // first interpolation delimiter separates property name from interpolation parts (in case of
9575
+ // property interpolations), so we subtract one from total number of found delimiters
9576
+ if (matches && (matches.length - 1) > bindingIndex - idx) {
9577
+ return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
9578
+ }
9421
9579
  }
9422
- i++;
9423
9580
  }
9424
- return { attrs, classes };
9581
+ return { propName: undefined, oldValue, newValue };
9425
9582
  }
9426
9583
 
9427
9584
  /** A special value which designates that a value has not changed. */
@@ -9480,6 +9637,33 @@ function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
9480
9637
  setSelectedIndex(index);
9481
9638
  }
9482
9639
 
9640
+ /**
9641
+ * Runs the given function in the context of the given `Injector`.
9642
+ *
9643
+ * Within the function's stack frame, `inject` can be used to inject dependencies from the given
9644
+ * `Injector`. Note that `inject` is only usable synchronously, and cannot be used in any
9645
+ * asynchronous callbacks or after any `await` points.
9646
+ *
9647
+ * @param injector the injector which will satisfy calls to `inject` while `fn` is executing
9648
+ * @param fn the closure to be run in the context of `injector`
9649
+ * @returns the return value of the function, if any
9650
+ * @publicApi
9651
+ */
9652
+ function runInInjectionContext(injector, fn) {
9653
+ if (injector instanceof R3Injector) {
9654
+ injector.assertNotDestroyed();
9655
+ }
9656
+ const prevInjector = setCurrentInjector(injector);
9657
+ const previousInjectImplementation = setInjectImplementation(undefined);
9658
+ try {
9659
+ return fn();
9660
+ }
9661
+ finally {
9662
+ setCurrentInjector(prevInjector);
9663
+ setInjectImplementation(previousInjectImplementation);
9664
+ }
9665
+ }
9666
+
9483
9667
  /**
9484
9668
  * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
9485
9669
  *
@@ -10918,7 +11102,7 @@ function getOrCreateComponentTView(def) {
10918
11102
  // Declaration node here is null since this function is called when we dynamically create a
10919
11103
  // component and hence there is no declaration.
10920
11104
  const declTNode = null;
10921
- return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
11105
+ return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts, def.id);
10922
11106
  }
10923
11107
  return tView;
10924
11108
  }
@@ -10935,7 +11119,7 @@ function getOrCreateComponentTView(def) {
10935
11119
  * @param schemas Schemas for this view
10936
11120
  * @param consts Constants for this view
10937
11121
  */
10938
- function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
11122
+ function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory, ssrId) {
10939
11123
  ngDevMode && ngDevMode.tView++;
10940
11124
  const bindingStartIndex = HEADER_OFFSET + decls;
10941
11125
  // This length does not yet contain host bindings from child directives because at this point,
@@ -10974,7 +11158,8 @@ function createTView(type, declTNode, templateFn, decls, vars, directives, pipes
10974
11158
  firstChild: null,
10975
11159
  schemas: schemas,
10976
11160
  consts: consts,
10977
- incompleteFirstPass: false
11161
+ incompleteFirstPass: false,
11162
+ ssrId,
10978
11163
  };
10979
11164
  if (ngDevMode) {
10980
11165
  // For performance reasons it is important that the tView retains the same shape during runtime.
@@ -10994,23 +11179,58 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
10994
11179
  /**
10995
11180
  * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
10996
11181
  *
10997
- * @param rendererFactory Factory function to create renderer instance.
11182
+ * @param renderer the renderer used to locate the element.
10998
11183
  * @param elementOrSelector Render element or CSS selector to locate the element.
10999
11184
  * @param encapsulation View Encapsulation defined for component that requests host element.
11000
11185
  * @param injector Root view injector instance.
11001
11186
  */
11002
11187
  function locateHostElement(renderer, elementOrSelector, encapsulation, injector) {
11003
11188
  // Note: we use default value for the `PRESERVE_HOST_CONTENT` here even though it's a
11004
- // tree-shakable one (providedIn:'root'). This code path can be triggered during dynamic component
11005
- // creation (after calling ViewContainerRef.createComponent) when an injector instance can be
11006
- // provided. The injector instance might be disconnected from the main DI tree, thus the
11007
- // `PRESERVE_HOST_CONTENT` woild not be able to instantiate. In this case, the default value will
11008
- // be used.
11189
+ // tree-shakable one (providedIn:'root'). This code path can be triggered during dynamic
11190
+ // component creation (after calling ViewContainerRef.createComponent) when an injector
11191
+ // instance can be provided. The injector instance might be disconnected from the main DI
11192
+ // tree, thus the `PRESERVE_HOST_CONTENT` woild not be able to instantiate. In this case, the
11193
+ // default value will be used.
11009
11194
  const preserveHostContent = injector.get(PRESERVE_HOST_CONTENT, PRESERVE_HOST_CONTENT_DEFAULT);
11010
11195
  // When using native Shadow DOM, do not clear host element to allow native slot
11011
11196
  // projection.
11012
11197
  const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation$1.ShadowDom;
11013
- return renderer.selectRootElement(elementOrSelector, preserveContent);
11198
+ const rootElement = renderer.selectRootElement(elementOrSelector, preserveContent);
11199
+ applyRootElementTransform(rootElement);
11200
+ return rootElement;
11201
+ }
11202
+ /**
11203
+ * Applies any root element transformations that are needed. If hydration is enabled,
11204
+ * this will process corrupted text nodes.
11205
+ *
11206
+ * @param rootElement the app root HTML Element
11207
+ */
11208
+ function applyRootElementTransform(rootElement) {
11209
+ _applyRootElementTransformImpl(rootElement);
11210
+ }
11211
+ /**
11212
+ * Reference to a function that applies transformations to the root HTML element
11213
+ * of an app. When hydration is enabled, this processes any corrupt text nodes
11214
+ * so they are properly hydratable on the client.
11215
+ *
11216
+ * @param rootElement the app root HTML Element
11217
+ */
11218
+ let _applyRootElementTransformImpl = (rootElement) => null;
11219
+ /**
11220
+ * Processes text node markers before hydration begins. This replaces any special comment
11221
+ * nodes that were added prior to serialization are swapped out to restore proper text
11222
+ * nodes before hydration.
11223
+ *
11224
+ * @param rootElement the app root HTML Element
11225
+ */
11226
+ function applyRootElementTransformImpl(rootElement) {
11227
+ processTextNodeMarkersBeforeHydration(rootElement);
11228
+ }
11229
+ /**
11230
+ * Sets the implementation for the `applyRootElementTransform` function.
11231
+ */
11232
+ function enableApplyRootElementTransformImpl() {
11233
+ _applyRootElementTransformImpl = applyRootElementTransformImpl;
11014
11234
  }
11015
11235
  /**
11016
11236
  * Saves context for this cleanup function in LView.cleanupInstances.
@@ -11022,9 +11242,9 @@ function locateHostElement(renderer, elementOrSelector, encapsulation, injector)
11022
11242
  function storeCleanupWithContext(tView, lView, context, cleanupFn) {
11023
11243
  const lCleanup = getOrCreateLViewCleanup(lView);
11024
11244
  // Historically the `storeCleanupWithContext` was used to register both framework-level and
11025
- // user-defined cleanup callbacks, but over time those two types of cleanups were separated. This
11026
- // dev mode checks assures that user-level cleanup callbacks are _not_ stored in data structures
11027
- // reserved for framework-specific hooks.
11245
+ // user-defined cleanup callbacks, but over time those two types of cleanups were separated.
11246
+ // This dev mode checks assures that user-level cleanup callbacks are _not_ stored in data
11247
+ // structures reserved for framework-specific hooks.
11028
11248
  ngDevMode &&
11029
11249
  assertDefined(context, 'Cleanup context is mandatory when registering framework-level destroy hooks');
11030
11250
  lCleanup.push(context);
@@ -11742,7 +11962,8 @@ function createLContainer(hostNative, currentView, native, tNode) {
11742
11962
  tNode,
11743
11963
  native,
11744
11964
  null,
11745
- null, // moved views
11965
+ null,
11966
+ null, // dehydrated views
11746
11967
  ];
11747
11968
  ngDevMode &&
11748
11969
  assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
@@ -12564,7 +12785,7 @@ class ComponentFactory extends ComponentFactory$1 {
12564
12785
  const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
12565
12786
  16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
12566
12787
  // Create the root view. Uses empty TView and ContentTemplate.
12567
- const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
12788
+ const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null, null);
12568
12789
  const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null, null);
12569
12790
  // rootView is the parent when bootstrapping
12570
12791
  // TODO(misko): it looks like we are entering view here but we don't really need to as
@@ -13849,92 +14070,15 @@ function detectChanges(component) {
13849
14070
  detectChangesInternal(view[TVIEW], view, component);
13850
14071
  }
13851
14072
 
13852
- function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
13853
- ngDevMode && assertFirstCreatePass(tView);
13854
- ngDevMode && ngDevMode.firstCreatePass++;
13855
- const tViewConsts = tView.consts;
13856
- // TODO(pk): refactor getOrCreateTNode to have the "create" only version
13857
- const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
13858
- resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
13859
- registerPostOrderHooks(tView, tNode);
13860
- const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
13861
- if (tView.queries !== null) {
13862
- tView.queries.template(tView, tNode);
13863
- embeddedTView.queries = tView.queries.embeddedTView(tNode);
13864
- }
13865
- return tNode;
13866
- }
13867
- /**
13868
- * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
13869
- *
13870
- * <ng-template #foo>
13871
- * <div></div>
13872
- * </ng-template>
13873
- *
13874
- * @param index The index of the container in the data array
13875
- * @param templateFn Inline template
13876
- * @param decls The number of nodes, local refs, and pipes for this template
13877
- * @param vars The number of bindings for this template
13878
- * @param tagName The name of the container element, if applicable
13879
- * @param attrsIndex Index of template attributes in the `consts` array.
13880
- * @param localRefs Index of the local references in the `consts` array.
13881
- * @param localRefExtractor A function which extracts local-refs values from the template.
13882
- * Defaults to the current element associated with the local-ref.
13883
- *
13884
- * @codeGenApi
13885
- */
13886
- function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
13887
- const lView = getLView();
13888
- const tView = getTView();
13889
- const adjustedIndex = index + HEADER_OFFSET;
13890
- const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
13891
- tView.data[adjustedIndex];
13892
- setCurrentTNode(tNode, false);
13893
- const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
13894
- appendChild(tView, lView, comment, tNode);
13895
- attachPatchData(comment, lView);
13896
- addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
13897
- if (isDirectiveHost(tNode)) {
13898
- createDirectivesInstances(tView, lView, tNode);
13899
- }
13900
- if (localRefsIndex != null) {
13901
- saveResolvedLocalsInData(lView, tNode, localRefExtractor);
13902
- }
13903
- }
13904
-
13905
- /** Store a value in the `data` at a given `index`. */
13906
- function store(tView, lView, index, value) {
13907
- // We don't store any static data for local variables, so the first time
13908
- // we see the template, we should store as null to avoid a sparse array
13909
- if (index >= tView.data.length) {
13910
- tView.data[index] = null;
13911
- tView.blueprint[index] = null;
13912
- }
13913
- lView[index] = value;
13914
- }
13915
- /**
13916
- * Retrieves a local reference from the current contextViewData.
13917
- *
13918
- * If the reference to retrieve is in a parent view, this instruction is used in conjunction
13919
- * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
13920
- *
13921
- * @param index The index of the local ref in contextViewData.
13922
- *
13923
- * @codeGenApi
13924
- */
13925
- function ɵɵreference(index) {
13926
- const contextLView = getContextLView();
13927
- return load(contextLView, HEADER_OFFSET + index);
13928
- }
13929
-
13930
14073
  /**
13931
14074
  * Verifies whether a given node matches an expected criteria,
13932
14075
  * based on internal data structure state.
13933
14076
  */
13934
14077
  function validateMatchingNode(node, nodeType, tagName, lView, tNode) {
14078
+ validateNodeExists(node);
13935
14079
  if (node.nodeType !== nodeType ||
13936
- (node.nodeType === Node.ELEMENT_NODE &&
13937
- node.tagName.toLowerCase() !== tagName?.toLowerCase())) {
14080
+ node.nodeType === Node.ELEMENT_NODE &&
14081
+ node.tagName.toLowerCase() !== tagName?.toLowerCase()) {
13938
14082
  // TODO: improve error message and use RuntimeError instead.
13939
14083
  throw new Error(`Unexpected node found during hydration.`);
13940
14084
  }
@@ -13943,25 +14087,23 @@ function validateMatchingNode(node, nodeType, tagName, lView, tNode) {
13943
14087
  * Verifies whether next sibling node exists.
13944
14088
  */
13945
14089
  function validateSiblingNodeExists(node) {
14090
+ validateNodeExists(node);
13946
14091
  if (!node.nextSibling) {
13947
14092
  // TODO: improve error message and use RuntimeError instead.
13948
14093
  throw new Error(`Unexpected state: insufficient number of sibling nodes.`);
13949
14094
  }
13950
14095
  }
14096
+ function validateNodeExists(node) {
14097
+ if (!node) {
14098
+ // TODO: improve error message and use RuntimeError instead.
14099
+ throw new Error(`Hydration expected an element to be present at this location.`);
14100
+ }
14101
+ }
13951
14102
 
13952
14103
  /** Whether current TNode is a first node in an <ng-container>. */
13953
14104
  function isFirstElementInNgContainer(tNode) {
13954
14105
  return !tNode.prev && tNode.parent?.type === 8 /* TNodeType.ElementContainer */;
13955
14106
  }
13956
- /** Returns first element from a DOM segment that corresponds to this <ng-container>. */
13957
- function getDehydratedNgContainer(hydrationInfo, tContainerNode) {
13958
- const noOffsetIndex = tContainerNode.index - HEADER_OFFSET;
13959
- const ngContainer = hydrationInfo.ngContainers?.[noOffsetIndex];
13960
- ngDevMode &&
13961
- assertDefined(ngContainer, 'Unexpected state: no hydration info available for a given TNode, ' +
13962
- 'which represents an element container.');
13963
- return ngContainer;
13964
- }
13965
14107
  /**
13966
14108
  * Locate a node in DOM tree that corresponds to a given TNode.
13967
14109
  *
@@ -13985,32 +14127,173 @@ function locateNextRNode(hydrationInfo, tView, lView, tNode) {
13985
14127
  ngDevMode &&
13986
14128
  assertDefined(previousTNode, 'Unexpected state: current TNode does not have a connection ' +
13987
14129
  'to the previous node or a parent node.');
13988
- const previousRElement = getNativeByTNode(previousTNode, lView);
13989
14130
  if (isFirstElementInNgContainer(tNode)) {
13990
- const ngContainer = getDehydratedNgContainer(hydrationInfo, tNode.parent);
13991
- native = ngContainer.firstChild ?? null;
14131
+ const noOffsetParentIndex = tNode.parent.index - HEADER_OFFSET;
14132
+ native = getSegmentHead(hydrationInfo, noOffsetParentIndex);
13992
14133
  }
13993
14134
  else {
14135
+ let previousRElement = getNativeByTNode(previousTNode, lView);
13994
14136
  if (previousTNodeParent) {
13995
14137
  native = previousRElement.firstChild;
13996
14138
  }
13997
14139
  else {
13998
- native = previousRElement.nextSibling;
14140
+ // If the previous node is an element, but it also has container info,
14141
+ // this means that we are processing a node like `<div #vcrTarget>`, which is
14142
+ // represented in the DOM as `<div></div>...<!--container-->`.
14143
+ // In this case, there are nodes *after* this element and we need to skip
14144
+ // all of them to reach an element that we are looking for.
14145
+ const noOffsetPrevSiblingIndex = previousTNode.index - HEADER_OFFSET;
14146
+ const segmentHead = getSegmentHead(hydrationInfo, noOffsetPrevSiblingIndex);
14147
+ if (previousTNode.type === 2 /* TNodeType.Element */ && segmentHead) {
14148
+ const numRootNodesToSkip = calcSerializedContainerSize(hydrationInfo, noOffsetPrevSiblingIndex);
14149
+ // `+1` stands for an anchor comment node after all the views in this container.
14150
+ const nodesToSkip = numRootNodesToSkip + 1;
14151
+ // First node after this segment.
14152
+ native = siblingAfter(nodesToSkip, segmentHead);
14153
+ }
14154
+ else {
14155
+ native = previousRElement.nextSibling;
14156
+ }
13999
14157
  }
14000
14158
  }
14001
14159
  }
14002
14160
  return native;
14003
14161
  }
14004
14162
  /**
14005
- * Skips over a specified number of nodes and returns the next sibling node after that.
14163
+ * Skips over a specified number of nodes and returns the next sibling node after that.
14164
+ */
14165
+ function siblingAfter(skip, from) {
14166
+ let currentNode = from;
14167
+ for (let i = 0; i < skip; i++) {
14168
+ ngDevMode && validateSiblingNodeExists(currentNode);
14169
+ currentNode = currentNode.nextSibling;
14170
+ }
14171
+ return currentNode;
14172
+ }
14173
+
14174
+ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
14175
+ ngDevMode && assertFirstCreatePass(tView);
14176
+ ngDevMode && ngDevMode.firstCreatePass++;
14177
+ const tViewConsts = tView.consts;
14178
+ let ssrId = null;
14179
+ const hydrationInfo = lView[HYDRATION];
14180
+ if (hydrationInfo) {
14181
+ const noOffsetIndex = index - HEADER_OFFSET;
14182
+ ssrId = (hydrationInfo && hydrationInfo.data[TEMPLATES]?.[noOffsetIndex]) ?? null;
14183
+ }
14184
+ // TODO(pk): refactor getOrCreateTNode to have the "create" only version
14185
+ const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
14186
+ resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
14187
+ registerPostOrderHooks(tView, tNode);
14188
+ const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, ssrId);
14189
+ if (tView.queries !== null) {
14190
+ tView.queries.template(tView, tNode);
14191
+ embeddedTView.queries = tView.queries.embeddedTView(tNode);
14192
+ }
14193
+ return tNode;
14194
+ }
14195
+ /**
14196
+ * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
14197
+ *
14198
+ * <ng-template #foo>
14199
+ * <div></div>
14200
+ * </ng-template>
14201
+ *
14202
+ * @param index The index of the container in the data array
14203
+ * @param templateFn Inline template
14204
+ * @param decls The number of nodes, local refs, and pipes for this template
14205
+ * @param vars The number of bindings for this template
14206
+ * @param tagName The name of the container element, if applicable
14207
+ * @param attrsIndex Index of template attributes in the `consts` array.
14208
+ * @param localRefs Index of the local references in the `consts` array.
14209
+ * @param localRefExtractor A function which extracts local-refs values from the template.
14210
+ * Defaults to the current element associated with the local-ref.
14211
+ *
14212
+ * @codeGenApi
14213
+ */
14214
+ function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
14215
+ const lView = getLView();
14216
+ const tView = getTView();
14217
+ const adjustedIndex = index + HEADER_OFFSET;
14218
+ const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
14219
+ tView.data[adjustedIndex];
14220
+ setCurrentTNode(tNode, false);
14221
+ const comment = _locateOrCreateContainerAnchor(tView, lView, tNode, index);
14222
+ if (wasLastNodeCreated()) {
14223
+ appendChild(tView, lView, comment, tNode);
14224
+ }
14225
+ attachPatchData(comment, lView);
14226
+ addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
14227
+ if (isDirectiveHost(tNode)) {
14228
+ createDirectivesInstances(tView, lView, tNode);
14229
+ }
14230
+ if (localRefsIndex != null) {
14231
+ saveResolvedLocalsInData(lView, tNode, localRefExtractor);
14232
+ }
14233
+ }
14234
+ let _locateOrCreateContainerAnchor = createContainerAnchorImpl;
14235
+ /**
14236
+ * Regular creation mode for LContainers and their anchor (comment) nodes.
14006
14237
  */
14007
- function siblingAfter(skip, from) {
14008
- let currentNode = from;
14009
- for (let i = 0; i < skip; i++) {
14010
- ngDevMode && validateSiblingNodeExists(currentNode);
14011
- currentNode = currentNode.nextSibling;
14238
+ function createContainerAnchorImpl(tView, lView, tNode, index) {
14239
+ lastNodeWasCreated(true);
14240
+ return lView[RENDERER].createComment(ngDevMode ? 'container' : '');
14241
+ }
14242
+ /**
14243
+ * Enables hydration code path (to lookup existing elements in DOM)
14244
+ * in addition to the regular creation mode for LContainers and their
14245
+ * anchor (comment) nodes.
14246
+ */
14247
+ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
14248
+ const hydrationInfo = lView[HYDRATION];
14249
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14250
+ lastNodeWasCreated(isNodeCreationMode);
14251
+ // Regular creation mode.
14252
+ if (isNodeCreationMode) {
14253
+ return createContainerAnchorImpl(tView, lView, tNode, index);
14012
14254
  }
14013
- return currentNode;
14255
+ // Hydration mode, looking up existing elements in DOM.
14256
+ const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
14257
+ ngDevMode && validateNodeExists(currentRNode);
14258
+ const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
14259
+ // If this container is non-empty, store the first node as a segment head,
14260
+ // otherwise, this node is an anchor and segment head doesn't exist (thus `null`).
14261
+ const segmentHead = viewContainerSize > 0 ? currentRNode : null;
14262
+ setSegmentHead(hydrationInfo, index, segmentHead);
14263
+ const comment = siblingAfter(viewContainerSize, currentRNode);
14264
+ if (ngDevMode) {
14265
+ validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14266
+ markRNodeAsClaimedByHydration(comment);
14267
+ }
14268
+ return comment;
14269
+ }
14270
+ function enableLocateOrCreateContainerAnchorImpl() {
14271
+ _locateOrCreateContainerAnchor = locateOrCreateContainerAnchorImpl;
14272
+ }
14273
+
14274
+ /** Store a value in the `data` at a given `index`. */
14275
+ function store(tView, lView, index, value) {
14276
+ // We don't store any static data for local variables, so the first time
14277
+ // we see the template, we should store as null to avoid a sparse array
14278
+ if (index >= tView.data.length) {
14279
+ tView.data[index] = null;
14280
+ tView.blueprint[index] = null;
14281
+ }
14282
+ lView[index] = value;
14283
+ }
14284
+ /**
14285
+ * Retrieves a local reference from the current contextViewData.
14286
+ *
14287
+ * If the reference to retrieve is in a parent view, this instruction is used in conjunction
14288
+ * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
14289
+ *
14290
+ * @param index The index of the local ref in contextViewData.
14291
+ *
14292
+ * @codeGenApi
14293
+ */
14294
+ function ɵɵreference(index) {
14295
+ const contextLView = getContextLView();
14296
+ return load(contextLView, HEADER_OFFSET + index);
14014
14297
  }
14015
14298
 
14016
14299
  /**
@@ -14039,6 +14322,21 @@ function hasNgSkipHydrationAttr(tNode) {
14039
14322
  }
14040
14323
  return false;
14041
14324
  }
14325
+ /**
14326
+ * Helper function that determines if a given node is within a skip hydration block
14327
+ * by navigating up the TNode tree to see if any parent nodes have skip hydration
14328
+ * attribute.
14329
+ */
14330
+ function isInSkipHydrationBlock(tNode) {
14331
+ let currentTNode = tNode.parent;
14332
+ while (currentTNode) {
14333
+ if (hasNgSkipHydrationAttr(currentTNode)) {
14334
+ return true;
14335
+ }
14336
+ currentTNode = currentTNode.parent;
14337
+ }
14338
+ return false;
14339
+ }
14042
14340
 
14043
14341
  /**
14044
14342
  * Update a property on a selected element.
@@ -14124,7 +14422,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
14124
14422
  const tNode = tView.firstCreatePass ?
14125
14423
  elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex) :
14126
14424
  tView.data[adjustedIndex];
14127
- const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name);
14425
+ const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name, index);
14128
14426
  lView[adjustedIndex] = native;
14129
14427
  const hasDirectives = isDirectiveHost(tNode);
14130
14428
  if (ngDevMode && tView.firstCreatePass) {
@@ -14207,7 +14505,7 @@ function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
14207
14505
  ɵɵelementEnd();
14208
14506
  return ɵɵelement;
14209
14507
  }
14210
- let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name) => {
14508
+ let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name, index) => {
14211
14509
  lastNodeWasCreated(true);
14212
14510
  return createElementNode(renderer, name, getNamespace$1());
14213
14511
  };
@@ -14215,9 +14513,9 @@ let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name) => {
14215
14513
  * Enables hydration code path (to lookup existing elements in DOM)
14216
14514
  * in addition to the regular creation mode of element nodes.
14217
14515
  */
14218
- function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name) {
14516
+ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, index) {
14219
14517
  const hydrationInfo = lView[HYDRATION];
14220
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14518
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14221
14519
  lastNodeWasCreated(isNodeCreationMode);
14222
14520
  // Regular creation mode.
14223
14521
  if (isNodeCreationMode) {
@@ -14225,9 +14523,19 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name) {
14225
14523
  }
14226
14524
  // Hydration mode, looking up an existing element in DOM.
14227
14525
  const native = locateNextRNode(hydrationInfo, tView, lView, tNode);
14228
- ngDevMode &&
14229
- validateMatchingNode(native, Node.ELEMENT_NODE, name, lView, tNode);
14526
+ ngDevMode && validateMatchingNode(native, Node.ELEMENT_NODE, name, lView, tNode);
14230
14527
  ngDevMode && markRNodeAsClaimedByHydration(native);
14528
+ // This element might also be an anchor of a view container.
14529
+ if (getSerializedContainerViews(hydrationInfo, index)) {
14530
+ // Important note: this element acts as an anchor, but it's **not** a part
14531
+ // of the embedded view, so we start the segment **after** this element, taking
14532
+ // a reference to the next sibling. For example, the following template:
14533
+ // `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
14534
+ // so while processing a `<div>` instruction, point to the next sibling as a
14535
+ // start of a segment.
14536
+ ngDevMode && validateNodeExists(native.nextSibling);
14537
+ setSegmentHead(hydrationInfo, index, native.nextSibling);
14538
+ }
14231
14539
  // Checks if the skip hydration attribute is present during hydration so we know to
14232
14540
  // skip attempting to hydrate this block.
14233
14541
  if (hydrationInfo && hasNgSkipHydrationAttr(tNode)) {
@@ -14355,7 +14663,7 @@ let _locateOrCreateElementContainerNode = (tView, lView, tNode, index) => {
14355
14663
  function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
14356
14664
  let comment;
14357
14665
  const hydrationInfo = lView[HYDRATION];
14358
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14666
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14359
14667
  lastNodeWasCreated(isNodeCreationMode);
14360
14668
  // Regular creation mode.
14361
14669
  if (isNodeCreationMode) {
@@ -14363,21 +14671,20 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
14363
14671
  }
14364
14672
  // Hydration mode, looking up existing elements in DOM.
14365
14673
  const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
14674
+ ngDevMode && validateNodeExists(currentRNode);
14366
14675
  const ngContainerSize = getNgContainerSize(hydrationInfo, index);
14367
14676
  ngDevMode &&
14368
14677
  assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
14369
14678
  'but no hydration info is available.');
14370
- if (ngContainerSize > 0) {
14371
- storeNgContainerInfo(hydrationInfo, index, currentRNode);
14372
- comment = siblingAfter(ngContainerSize, currentRNode);
14373
- }
14374
- else {
14375
- // If <ng-container> has no nodes,
14376
- // the current node is an anchor (comment) node.
14377
- comment = currentRNode;
14679
+ // If this container is non-empty, store the first node as a segment head,
14680
+ // otherwise, this node is an anchor and segment head doesn't exist (thus `null`).
14681
+ const segmentHead = ngContainerSize > 0 ? currentRNode : null;
14682
+ setSegmentHead(hydrationInfo, index, segmentHead);
14683
+ comment = siblingAfter(ngContainerSize, currentRNode);
14684
+ if (ngDevMode) {
14685
+ validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14686
+ markRNodeAsClaimedByHydration(comment);
14378
14687
  }
14379
- ngDevMode && validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14380
- ngDevMode && markRNodeAsClaimedByHydration(comment);
14381
14688
  return comment;
14382
14689
  }
14383
14690
  function enableLocateOrCreateElementContainerNodeImpl() {
@@ -16735,7 +17042,7 @@ let _locateOrCreateTextNode = (tView, lView, tNode, value) => {
16735
17042
  */
16736
17043
  function locateOrCreateTextNodeImpl(tView, lView, tNode, value) {
16737
17044
  const hydrationInfo = lView[HYDRATION];
16738
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
17045
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
16739
17046
  lastNodeWasCreated(isNodeCreationMode);
16740
17047
  // Regular creation mode.
16741
17048
  if (isNodeCreationMode) {
@@ -20403,7 +20710,7 @@ class NgModuleFactory$1 {
20403
20710
  * @publicApi
20404
20711
  */
20405
20712
  function createNgModule(ngModule, parentInjector) {
20406
- return new NgModuleRef(ngModule, parentInjector ?? null);
20713
+ return new NgModuleRef(ngModule, parentInjector ?? null, []);
20407
20714
  }
20408
20715
  /**
20409
20716
  * The `createNgModule` function alias for backwards-compatibility.
@@ -20413,7 +20720,7 @@ function createNgModule(ngModule, parentInjector) {
20413
20720
  */
20414
20721
  const createNgModuleRef = createNgModule;
20415
20722
  class NgModuleRef extends NgModuleRef$1 {
20416
- constructor(ngModuleType, _parent) {
20723
+ constructor(ngModuleType, _parent, additionalProviders) {
20417
20724
  super();
20418
20725
  this._parent = _parent;
20419
20726
  // tslint:disable-next-line:require-internal-with-underscore
@@ -20434,7 +20741,8 @@ class NgModuleRef extends NgModuleRef$1 {
20434
20741
  { provide: NgModuleRef$1, useValue: this }, {
20435
20742
  provide: ComponentFactoryResolver$1,
20436
20743
  useValue: this.componentFactoryResolver
20437
- }
20744
+ },
20745
+ ...additionalProviders
20438
20746
  ], stringify(ngModuleType), new Set(['environment']));
20439
20747
  // We need to resolve the injector types separately from the injector creation, because
20440
20748
  // the module might be trying to use this ref in its constructor for DI which will cause a
@@ -20463,9 +20771,12 @@ class NgModuleFactory extends NgModuleFactory$1 {
20463
20771
  this.moduleType = moduleType;
20464
20772
  }
20465
20773
  create(parentInjector) {
20466
- return new NgModuleRef(this.moduleType, parentInjector);
20774
+ return new NgModuleRef(this.moduleType, parentInjector, []);
20467
20775
  }
20468
20776
  }
20777
+ function createNgModuleRefWithProviders(moduleType, parentInjector, additionalProviders) {
20778
+ return new NgModuleRef(moduleType, parentInjector, additionalProviders);
20779
+ }
20469
20780
  class EnvironmentNgModuleRefAdapter extends NgModuleRef$1 {
20470
20781
  constructor(providers, parent, source) {
20471
20782
  super();
@@ -20913,7 +21224,8 @@ function sortListeners(a, b) {
20913
21224
  * See call site for more info.
20914
21225
  */
20915
21226
  function isDirectiveDefHack(obj) {
20916
- return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined;
21227
+ return obj.type !== undefined && obj.declaredInputs !== undefined &&
21228
+ obj.findHostDirectiveDefs !== undefined;
20917
21229
  }
20918
21230
  /**
20919
21231
  * Retrieve the component `LView` from component/element.
@@ -21750,9 +22062,24 @@ const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
21750
22062
  this._declarationTContainer = _declarationTContainer;
21751
22063
  this.elementRef = elementRef;
21752
22064
  }
22065
+ /**
22066
+ * Returns an `ssrId` associated with a TView, which was used to
22067
+ * create this instance of the `TemplateRef`.
22068
+ *
22069
+ * @internal
22070
+ */
22071
+ get ssrId() {
22072
+ return this._declarationTContainer.tView?.ssrId || null;
22073
+ }
21753
22074
  createEmbeddedView(context, injector) {
22075
+ return this.createEmbeddedViewImpl(context, injector, null);
22076
+ }
22077
+ /**
22078
+ * @internal
22079
+ */
22080
+ createEmbeddedViewImpl(context, injector, hydrationInfo) {
21754
22081
  const embeddedTView = this._declarationTContainer.tView;
21755
- const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null, null);
22082
+ const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null, hydrationInfo || null);
21756
22083
  const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
21757
22084
  ngDevMode && assertLContainer(declarationLContainer);
21758
22085
  embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
@@ -21787,6 +22114,112 @@ function createTemplateRef(hostTNode, hostLView) {
21787
22114
  return null;
21788
22115
  }
21789
22116
 
22117
+ /**
22118
+ * Removes all dehydrated views from a given LContainer:
22119
+ * both in internal data structure, as well as removing
22120
+ * corresponding DOM nodes that belong to that dehydrated view.
22121
+ */
22122
+ function removeDehydratedViews(lContainer) {
22123
+ const views = lContainer[DEHYDRATED_VIEWS] ?? [];
22124
+ const parentLView = lContainer[PARENT];
22125
+ const renderer = parentLView[RENDERER];
22126
+ for (const view of views) {
22127
+ removeDehydratedView(view, renderer);
22128
+ ngDevMode && ngDevMode.dehydratedViewsRemoved++;
22129
+ }
22130
+ // Reset the value to an empty array to indicate that no
22131
+ // further processing of dehydrated views is needed for
22132
+ // this view container (i.e. do not trigger the lookup process
22133
+ // once again in case a `ViewContainerRef` is created later).
22134
+ lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
22135
+ }
22136
+ /**
22137
+ * Helper function to remove all nodes from a dehydrated view.
22138
+ */
22139
+ function removeDehydratedView(dehydratedView, renderer) {
22140
+ let nodesRemoved = 0;
22141
+ let currentRNode = dehydratedView.firstChild;
22142
+ if (currentRNode) {
22143
+ const numNodes = dehydratedView.data[NUM_ROOT_NODES];
22144
+ while (nodesRemoved < numNodes) {
22145
+ ngDevMode && validateSiblingNodeExists(currentRNode);
22146
+ const nextSibling = currentRNode.nextSibling;
22147
+ nativeRemoveNode(renderer, currentRNode, false);
22148
+ currentRNode = nextSibling;
22149
+ nodesRemoved++;
22150
+ }
22151
+ }
22152
+ }
22153
+
22154
+ /**
22155
+ * Given a current DOM node and a serialized information about the views
22156
+ * in a container, walks over the DOM structure, collecting the list of
22157
+ * dehydrated views.
22158
+ */
22159
+ function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
22160
+ const dehydratedViews = [];
22161
+ for (const serializedView of serializedViews) {
22162
+ const view = {
22163
+ data: serializedView,
22164
+ firstChild: null,
22165
+ };
22166
+ if (serializedView[NUM_ROOT_NODES] > 0) {
22167
+ // Keep reference to the first node in this view,
22168
+ // so it can be accessed while invoking template instructions.
22169
+ view.firstChild = currentRNode;
22170
+ // Move over to the next node after this view, which can
22171
+ // either be a first node of the next view or an anchor comment
22172
+ // node after the last view in a container.
22173
+ currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
22174
+ }
22175
+ dehydratedViews.push(view);
22176
+ }
22177
+ return [currentRNode, dehydratedViews];
22178
+ }
22179
+ /**
22180
+ * Reference to a function that searches for a matching dehydrated views
22181
+ * stored on a given lContainer.
22182
+ * Returns `null` by default, when hydration is not enabled.
22183
+ */
22184
+ let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
22185
+ /**
22186
+ * Retrieves the next dehydrated view from the LContainer and verifies that
22187
+ * it matches a given template id (from the TView that was used to create this
22188
+ * instance of a view). If the id doesn't match, that means that we are in an
22189
+ * unexpected state and can not complete the reconciliation process. Thus,
22190
+ * all dehydrated views from this LContainer are removed (including corresponding
22191
+ * DOM nodes) and the rendering is performed as if there were no dehydrated views
22192
+ * in this container.
22193
+ */
22194
+ function findMatchingDehydratedViewImpl(lContainer, template) {
22195
+ const views = lContainer[DEHYDRATED_VIEWS] ?? [];
22196
+ if (!template || views.length === 0) {
22197
+ return null;
22198
+ }
22199
+ const view = views[0];
22200
+ // Verify whether the first dehydrated view in the container matches
22201
+ // the template id passed to this function (that originated from a TView
22202
+ // that was used to create an instance of an embedded or component views.
22203
+ if (view.data[TEMPLATE_ID] === template) {
22204
+ // If the template id matches - extract the first view and return it.
22205
+ return views.shift();
22206
+ }
22207
+ else {
22208
+ // Otherwise, we are at the state when reconciliation can not be completed,
22209
+ // thus we remove all dehydrated views within this container (remove them
22210
+ // from internal data structures as well as delete associated elements from
22211
+ // the DOM tree).
22212
+ removeDehydratedViews(lContainer);
22213
+ return null;
22214
+ }
22215
+ }
22216
+ function enableFindMatchingDehydratedViewImpl() {
22217
+ _findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
22218
+ }
22219
+ function findMatchingDehydratedView(lContainer, template) {
22220
+ return _findMatchingDehydratedViewImpl(lContainer, template);
22221
+ }
22222
+
21790
22223
  /**
21791
22224
  * Represents a container where one or more views can be attached to a component.
21792
22225
  *
@@ -21871,8 +22304,9 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
21871
22304
  index = indexOrOptions.index;
21872
22305
  injector = indexOrOptions.injector;
21873
22306
  }
21874
- const viewRef = templateRef.createEmbeddedView(context || {}, injector);
21875
- this.insert(viewRef, index);
22307
+ const hydrationInfo = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
22308
+ const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, hydrationInfo);
22309
+ this.insertImpl(viewRef, index, !!hydrationInfo);
21876
22310
  return viewRef;
21877
22311
  }
21878
22312
  createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
@@ -21942,11 +22376,17 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
21942
22376
  environmentInjector = result;
21943
22377
  }
21944
22378
  }
21945
- const componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, environmentInjector);
21946
- this.insert(componentRef.hostView, index);
22379
+ const componentDef = getComponentDef(componentFactory.componentType ?? {});
22380
+ const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
22381
+ const rNode = dehydratedView?.firstChild ?? null;
22382
+ const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
22383
+ this.insertImpl(componentRef.hostView, index, !!dehydratedView);
21947
22384
  return componentRef;
21948
22385
  }
21949
22386
  insert(viewRef, index) {
22387
+ return this.insertImpl(viewRef, index, false);
22388
+ }
22389
+ insertImpl(viewRef, index, skipDomInsertion) {
21950
22390
  const lView = viewRef._lView;
21951
22391
  const tView = lView[TVIEW];
21952
22392
  if (ngDevMode && viewRef.destroyed) {
@@ -21977,11 +22417,13 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
21977
22417
  const lContainer = this._lContainer;
21978
22418
  insertView(tView, lView, lContainer, adjustedIdx);
21979
22419
  // Physical operation of adding the DOM nodes.
21980
- const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
21981
- const renderer = lView[RENDERER];
21982
- const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
21983
- if (parentRNode !== null) {
21984
- addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
22420
+ if (!skipDomInsertion) {
22421
+ const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
22422
+ const renderer = lView[RENDERER];
22423
+ const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
22424
+ if (parentRNode !== null) {
22425
+ addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
22426
+ }
21985
22427
  }
21986
22428
  viewRef.attachToViewContainerRef();
21987
22429
  addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
@@ -22038,8 +22480,6 @@ function getOrCreateViewRefs(lContainer) {
22038
22480
  /**
22039
22481
  * Creates a ViewContainerRef and stores it on the injector.
22040
22482
  *
22041
- * @param ViewContainerRefToken The ViewContainerRef type
22042
- * @param ElementRefToken The ElementRef type
22043
22483
  * @param hostTNode The node that is requesting a ViewContainerRef
22044
22484
  * @param hostLView The view to which the node belongs
22045
22485
  * @returns The ViewContainerRef instance to use
@@ -22053,31 +22493,94 @@ function createContainerRef(hostTNode, hostLView) {
22053
22493
  lContainer = slotValue;
22054
22494
  }
22055
22495
  else {
22056
- let commentNode;
22057
- // If the host is an element container, the native host element is guaranteed to be a
22058
- // comment and we can reuse that comment as anchor element for the new LContainer.
22059
- // The comment node in question is already part of the DOM structure so we don't need to append
22060
- // it again.
22061
- if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
22062
- commentNode = unwrapRNode(slotValue);
22063
- }
22064
- else {
22065
- // If the host is a regular element, we have to insert a comment node manually which will
22066
- // be used as an anchor when inserting elements. In this specific case we use low-level DOM
22067
- // manipulation to insert it.
22068
- const renderer = hostLView[RENDERER];
22069
- ngDevMode && ngDevMode.rendererCreateComment++;
22070
- commentNode = renderer.createComment(ngDevMode ? 'container' : '');
22071
- const hostNative = getNativeByTNode(hostTNode, hostLView);
22072
- const parentOfHostNative = nativeParentNode(renderer, hostNative);
22073
- nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
22074
- }
22075
- hostLView[hostTNode.index] = lContainer =
22076
- createLContainer(slotValue, hostLView, commentNode, hostTNode);
22496
+ // An LContainer anchor can not be `null`, but we set it here temporarily
22497
+ // and update to the actual value later in this function (see
22498
+ // `_locateOrCreateAnchorNode`).
22499
+ lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
22500
+ hostLView[hostTNode.index] = lContainer;
22077
22501
  addToViewTree(hostLView, lContainer);
22078
22502
  }
22503
+ _locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
22079
22504
  return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
22080
22505
  }
22506
+ /**
22507
+ * Creates and inserts a comment node that acts as an anchor for a view container.
22508
+ *
22509
+ * If the host is a regular element, we have to insert a comment node manually which will
22510
+ * be used as an anchor when inserting elements. In this specific case we use low-level DOM
22511
+ * manipulation to insert it.
22512
+ */
22513
+ function insertAnchorNode(hostLView, hostTNode) {
22514
+ const renderer = hostLView[RENDERER];
22515
+ ngDevMode && ngDevMode.rendererCreateComment++;
22516
+ const commentNode = renderer.createComment(ngDevMode ? 'container' : '');
22517
+ const hostNative = getNativeByTNode(hostTNode, hostLView);
22518
+ const parentOfHostNative = nativeParentNode(renderer, hostNative);
22519
+ nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
22520
+ return commentNode;
22521
+ }
22522
+ let _locateOrCreateAnchorNode = createAnchorNode;
22523
+ /**
22524
+ * Regular creation mode: an anchor is created and
22525
+ * assigned to the `lContainer[NATIVE]` slot.
22526
+ */
22527
+ function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
22528
+ // We already have a native element (anchor) set, return.
22529
+ if (lContainer[NATIVE])
22530
+ return;
22531
+ let commentNode;
22532
+ // If the host is an element container, the native host element is guaranteed to be a
22533
+ // comment and we can reuse that comment as anchor element for the new LContainer.
22534
+ // The comment node in question is already part of the DOM structure so we don't need to append
22535
+ // it again.
22536
+ if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
22537
+ commentNode = unwrapRNode(slotValue);
22538
+ }
22539
+ else {
22540
+ commentNode = insertAnchorNode(hostLView, hostTNode);
22541
+ }
22542
+ lContainer[NATIVE] = commentNode;
22543
+ }
22544
+ /**
22545
+ * Hydration logic that looks up:
22546
+ * - an anchor node in the DOM and stores the node in `lContainer[NATIVE]`
22547
+ * - all dehydrated views in this container and puts them into `lContainer[DEHYDRATED_VIEWS]`
22548
+ */
22549
+ function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
22550
+ // We already have a native element (anchor) set and the process
22551
+ // of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
22552
+ // is not null), exit early.
22553
+ if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS])
22554
+ return;
22555
+ const hydrationInfo = hostLView[HYDRATION];
22556
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock(hostTNode);
22557
+ // Regular creation mode.
22558
+ if (isNodeCreationMode) {
22559
+ return createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
22560
+ }
22561
+ // Hydration mode, looking up an anchor node and dehydrated views in DOM.
22562
+ const index = hostTNode.index - HEADER_OFFSET;
22563
+ const currentRNode = getSegmentHead(hydrationInfo, index);
22564
+ const serializedViews = hydrationInfo.data[CONTAINERS]?.[index];
22565
+ ngDevMode &&
22566
+ assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
22567
+ 'which represents a view container.');
22568
+ const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
22569
+ if (ngDevMode) {
22570
+ validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, hostTNode);
22571
+ // Do not throw in case this node is already claimed (thus `false` as a second
22572
+ // argument). If this container is created based on an `<ng-template>`, the comment
22573
+ // node would be already claimed from the `template` instruction. If an element acts
22574
+ // as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
22575
+ // so we need to claim it here.
22576
+ markRNodeAsClaimedByHydration(commentNode, false);
22577
+ }
22578
+ lContainer[NATIVE] = commentNode;
22579
+ lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
22580
+ }
22581
+ function enableLocateOrCreateContainerRefImpl() {
22582
+ _locateOrCreateAnchorNode = locateOrCreateAnchorNode;
22583
+ }
22081
22584
 
22082
22585
  class LQuery_ {
22083
22586
  constructor(queryList) {
@@ -23078,6 +23581,7 @@ function resetCompiledComponents() {
23078
23581
  ownerNgModule = new WeakMap();
23079
23582
  verifiedNgModule = new WeakMap();
23080
23583
  moduleQueue.length = 0;
23584
+ GENERATED_COMP_IDS.clear();
23081
23585
  }
23082
23586
  /**
23083
23587
  * Computes the combined declarations of explicit declarations, as well as declarations inherited by
@@ -24839,6 +25343,63 @@ class NoopNgZone {
24839
25343
  return fn.apply(applyThis, applyArgs);
24840
25344
  }
24841
25345
  }
25346
+ /**
25347
+ * Token used to drive ApplicationRef.isStable
25348
+ *
25349
+ * TODO: This should be moved entirely to NgZone (as a breaking change) so it can be tree-shakeable
25350
+ * for `NoopNgZone` which is always just an `Observable` of `true`. Additionally, we should consider
25351
+ * whether the property on `NgZone` should be `Observable` or `Signal`.
25352
+ */
25353
+ const ZONE_IS_STABLE_OBSERVABLE = new InjectionToken(ngDevMode ? 'isStable Observable' : '', {
25354
+ providedIn: 'root',
25355
+ // TODO(atscott): Replace this with a suitable default like `new
25356
+ // BehaviorSubject(true).asObservable`. Again, long term this won't exist on ApplicationRef at
25357
+ // all but until we can remove it, we need a default value zoneless.
25358
+ factory: isStableFactory,
25359
+ });
25360
+ function isStableFactory() {
25361
+ const zone = inject(NgZone);
25362
+ let _stable = true;
25363
+ const isCurrentlyStable = new Observable((observer) => {
25364
+ _stable = zone.isStable && !zone.hasPendingMacrotasks && !zone.hasPendingMicrotasks;
25365
+ zone.runOutsideAngular(() => {
25366
+ observer.next(_stable);
25367
+ observer.complete();
25368
+ });
25369
+ });
25370
+ const isStable = new Observable((observer) => {
25371
+ // Create the subscription to onStable outside the Angular Zone so that
25372
+ // the callback is run outside the Angular Zone.
25373
+ let stableSub;
25374
+ zone.runOutsideAngular(() => {
25375
+ stableSub = zone.onStable.subscribe(() => {
25376
+ NgZone.assertNotInAngularZone();
25377
+ // Check whether there are no pending macro/micro tasks in the next tick
25378
+ // to allow for NgZone to update the state.
25379
+ scheduleMicroTask(() => {
25380
+ if (!_stable && !zone.hasPendingMacrotasks && !zone.hasPendingMicrotasks) {
25381
+ _stable = true;
25382
+ observer.next(true);
25383
+ }
25384
+ });
25385
+ });
25386
+ });
25387
+ const unstableSub = zone.onUnstable.subscribe(() => {
25388
+ NgZone.assertInAngularZone();
25389
+ if (_stable) {
25390
+ _stable = false;
25391
+ zone.runOutsideAngular(() => {
25392
+ observer.next(false);
25393
+ });
25394
+ }
25395
+ });
25396
+ return () => {
25397
+ stableSub.unsubscribe();
25398
+ unstableSub.unsubscribe();
25399
+ };
25400
+ });
25401
+ return merge$1(isCurrentlyStable, isStable.pipe(share()));
25402
+ }
24842
25403
 
24843
25404
  /**
24844
25405
  * Internal injection token that can used to access an instance of a Testability class.
@@ -25276,13 +25837,13 @@ function internalCreateApplication(config) {
25276
25837
  // Create root application injector based on a set of providers configured at the platform
25277
25838
  // bootstrap level as well as providers passed to the bootstrap call by a user.
25278
25839
  const allAppProviders = [
25279
- { provide: NgZone, useValue: ngZone },
25840
+ provideNgZoneChangeDetection(ngZone),
25280
25841
  ...(appProviders || []),
25281
25842
  ];
25282
25843
  const envInjector = createEnvironmentInjector(allAppProviders, platformInjector, 'Environment Injector');
25283
25844
  const exceptionHandler = envInjector.get(ErrorHandler, null);
25284
25845
  if (NG_DEV_MODE && !exceptionHandler) {
25285
- throw new RuntimeError(402 /* RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND */, 'No `ErrorHandler` found in the Dependency Injection tree.');
25846
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No `ErrorHandler` found in the Dependency Injection tree.');
25286
25847
  }
25287
25848
  let onErrorSubscription;
25288
25849
  ngZone.runOutsideAngular(() => {
@@ -25424,17 +25985,15 @@ class PlatformRef {
25424
25985
  // So we create a mini parent injector that just contains the new NgZone and
25425
25986
  // pass that as parent to the NgModuleFactory.
25426
25987
  const ngZone = getNgZone(options?.ngZone, getNgZoneOptions(options));
25427
- const providers = [{ provide: NgZone, useValue: ngZone }];
25428
25988
  // Note: Create ngZoneInjector within ngZone.run so that all of the instantiated services are
25429
25989
  // created within the Angular zone
25430
25990
  // Do not try to replace ngZone.run with ApplicationRef#run because ApplicationRef would then be
25431
25991
  // created outside of the Angular zone.
25432
25992
  return ngZone.run(() => {
25433
- const ngZoneInjector = Injector.create({ providers: providers, parent: this.injector, name: moduleFactory.moduleType.name });
25434
- const moduleRef = moduleFactory.create(ngZoneInjector);
25993
+ const moduleRef = createNgModuleRefWithProviders(moduleFactory.moduleType, this.injector, provideNgZoneChangeDetection(ngZone));
25435
25994
  const exceptionHandler = moduleRef.injector.get(ErrorHandler, null);
25436
- if (!exceptionHandler) {
25437
- throw new RuntimeError(402 /* RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND */, ngDevMode && 'No ErrorHandler. Is platform module (BrowserModule) included?');
25995
+ if (NG_DEV_MODE && exceptionHandler === null) {
25996
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No ErrorHandler. Is platform module (BrowserModule) included?');
25438
25997
  }
25439
25998
  ngZone.runOutsideAngular(() => {
25440
25999
  const subscription = ngZone.onError.subscribe({
@@ -25587,7 +26146,6 @@ function optionsReducer(dst, objs) {
25587
26146
  * A reference to an Angular application running on a page.
25588
26147
  *
25589
26148
  * @usageNotes
25590
- *
25591
26149
  * {@a is-stable-examples}
25592
26150
  * ### isStable examples and caveats
25593
26151
  *
@@ -25677,31 +26235,15 @@ function optionsReducer(dst, objs) {
25677
26235
  * @publicApi
25678
26236
  */
25679
26237
  class ApplicationRef {
25680
- /**
25681
- * Indicates whether this instance was destroyed.
25682
- */
25683
- get destroyed() {
25684
- return this._destroyed;
25685
- }
25686
- /**
25687
- * The `EnvironmentInjector` used to create this application.
25688
- */
25689
- get injector() {
25690
- return this._injector;
25691
- }
25692
- /** @internal */
25693
- constructor(_zone, _injector, _exceptionHandler) {
25694
- this._zone = _zone;
25695
- this._injector = _injector;
25696
- this._exceptionHandler = _exceptionHandler;
26238
+ constructor() {
25697
26239
  /** @internal */
25698
26240
  this._bootstrapListeners = [];
25699
26241
  this._runningTick = false;
25700
- this._stable = true;
25701
26242
  this._destroyed = false;
25702
26243
  this._destroyListeners = [];
25703
26244
  /** @internal */
25704
26245
  this._views = [];
26246
+ this.internalErrorHandler = inject(INTERNAL_APPLICATION_ERROR_HANDLER);
25705
26247
  /**
25706
26248
  * Get a list of component types registered to this application.
25707
26249
  * This list is populated even before the component is created.
@@ -25711,54 +26253,23 @@ class ApplicationRef {
25711
26253
  * Get a list of components registered to this application.
25712
26254
  */
25713
26255
  this.components = [];
25714
- this._onMicrotaskEmptySubscription = this._zone.onMicrotaskEmpty.subscribe({
25715
- next: () => {
25716
- this._zone.run(() => {
25717
- this.tick();
25718
- });
25719
- }
25720
- });
25721
- const isCurrentlyStable = new Observable((observer) => {
25722
- this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks &&
25723
- !this._zone.hasPendingMicrotasks;
25724
- this._zone.runOutsideAngular(() => {
25725
- observer.next(this._stable);
25726
- observer.complete();
25727
- });
25728
- });
25729
- const isStable = new Observable((observer) => {
25730
- // Create the subscription to onStable outside the Angular Zone so that
25731
- // the callback is run outside the Angular Zone.
25732
- let stableSub;
25733
- this._zone.runOutsideAngular(() => {
25734
- stableSub = this._zone.onStable.subscribe(() => {
25735
- NgZone.assertNotInAngularZone();
25736
- // Check whether there are no pending macro/micro tasks in the next tick
25737
- // to allow for NgZone to update the state.
25738
- scheduleMicroTask(() => {
25739
- if (!this._stable && !this._zone.hasPendingMacrotasks &&
25740
- !this._zone.hasPendingMicrotasks) {
25741
- this._stable = true;
25742
- observer.next(true);
25743
- }
25744
- });
25745
- });
25746
- });
25747
- const unstableSub = this._zone.onUnstable.subscribe(() => {
25748
- NgZone.assertInAngularZone();
25749
- if (this._stable) {
25750
- this._stable = false;
25751
- this._zone.runOutsideAngular(() => {
25752
- observer.next(false);
25753
- });
25754
- }
25755
- });
25756
- return () => {
25757
- stableSub.unsubscribe();
25758
- unstableSub.unsubscribe();
25759
- };
25760
- });
25761
- this.isStable = merge$1(isCurrentlyStable, isStable.pipe(share()));
26256
+ /**
26257
+ * Returns an Observable that indicates when the application is stable or unstable.
26258
+ */
26259
+ this.isStable = inject(ZONE_IS_STABLE_OBSERVABLE);
26260
+ this._injector = inject(EnvironmentInjector);
26261
+ }
26262
+ /**
26263
+ * Indicates whether this instance was destroyed.
26264
+ */
26265
+ get destroyed() {
26266
+ return this._destroyed;
26267
+ }
26268
+ /**
26269
+ * The `EnvironmentInjector` used to create this application.
26270
+ */
26271
+ get injector() {
26272
+ return this._injector;
25762
26273
  }
25763
26274
  /**
25764
26275
  * Bootstrap a component onto the element identified by its selector or, optionally, to a
@@ -25864,7 +26375,7 @@ class ApplicationRef {
25864
26375
  }
25865
26376
  catch (e) {
25866
26377
  // Attention: Don't rethrow as it could cancel subscriptions to Observables!
25867
- this._zone.runOutsideAngular(() => this._exceptionHandler.handleError(e));
26378
+ this.internalErrorHandler(e);
25868
26379
  }
25869
26380
  finally {
25870
26381
  this._runningTick = false;
@@ -25914,7 +26425,6 @@ class ApplicationRef {
25914
26425
  this._destroyListeners.forEach(listener => listener());
25915
26426
  // Destroy all registered views.
25916
26427
  this._views.slice().forEach((view) => view.destroy());
25917
- this._onMicrotaskEmptySubscription.unsubscribe();
25918
26428
  }
25919
26429
  finally {
25920
26430
  // Indicate that this instance is destroyed.
@@ -25967,12 +26477,12 @@ class ApplicationRef {
25967
26477
  }
25968
26478
  }
25969
26479
  }
25970
- ApplicationRef.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(ɵɵinject(NgZone), ɵɵinject(EnvironmentInjector), ɵɵinject(ErrorHandler)); };
26480
+ ApplicationRef.ɵfac = function ApplicationRef_Factory(t) { return new (t || ApplicationRef)(); };
25971
26481
  ApplicationRef.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: ApplicationRef, factory: ApplicationRef.ɵfac, providedIn: 'root' });
25972
26482
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(ApplicationRef, [{
25973
26483
  type: Injectable,
25974
26484
  args: [{ providedIn: 'root' }]
25975
- }], function () { return [{ type: NgZone }, { type: EnvironmentInjector }, { type: ErrorHandler }]; }, null); })();
26485
+ }], null, null); })();
25976
26486
  function remove(list, el) {
25977
26487
  const index = list.indexOf(el);
25978
26488
  if (index > -1) {
@@ -25987,6 +26497,69 @@ function _lastDefined(args) {
25987
26497
  }
25988
26498
  return undefined;
25989
26499
  }
26500
+ /**
26501
+ * `InjectionToken` used to configure how to call the `ErrorHandler`.
26502
+ *
26503
+ * `NgZone` is provided by default today so the default (and only) implementation for this
26504
+ * is calling `ErrorHandler.handleError` outside of the Angular zone.
26505
+ */
26506
+ const INTERNAL_APPLICATION_ERROR_HANDLER = new InjectionToken(NG_DEV_MODE ? 'internal error handler' : '', {
26507
+ providedIn: 'root',
26508
+ factory: () => {
26509
+ const userErrorHandler = inject(ErrorHandler);
26510
+ return userErrorHandler.handleError.bind(undefined);
26511
+ }
26512
+ });
26513
+ function ngZoneApplicationErrorHandlerFactory() {
26514
+ const zone = inject(NgZone);
26515
+ const userErrorHandler = inject(ErrorHandler);
26516
+ return (e) => zone.runOutsideAngular(() => userErrorHandler.handleError(e));
26517
+ }
26518
+ class NgZoneChangeDetectionScheduler {
26519
+ constructor() {
26520
+ this.zone = inject(NgZone);
26521
+ this.applicationRef = inject(ApplicationRef);
26522
+ }
26523
+ initialize() {
26524
+ if (this._onMicrotaskEmptySubscription) {
26525
+ return;
26526
+ }
26527
+ this._onMicrotaskEmptySubscription = this.zone.onMicrotaskEmpty.subscribe({
26528
+ next: () => {
26529
+ this.zone.run(() => {
26530
+ this.applicationRef.tick();
26531
+ });
26532
+ }
26533
+ });
26534
+ }
26535
+ ngOnDestroy() {
26536
+ this._onMicrotaskEmptySubscription?.unsubscribe();
26537
+ }
26538
+ }
26539
+ NgZoneChangeDetectionScheduler.ɵfac = function NgZoneChangeDetectionScheduler_Factory(t) { return new (t || NgZoneChangeDetectionScheduler)(); };
26540
+ NgZoneChangeDetectionScheduler.ɵprov = /*@__PURE__*/ ɵɵdefineInjectable({ token: NgZoneChangeDetectionScheduler, factory: NgZoneChangeDetectionScheduler.ɵfac, providedIn: 'root' });
26541
+ (function () { (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(NgZoneChangeDetectionScheduler, [{
26542
+ type: Injectable,
26543
+ args: [{ providedIn: 'root' }]
26544
+ }], null, null); })();
26545
+ function provideNgZoneChangeDetection(ngZone) {
26546
+ return [
26547
+ { provide: NgZone, useValue: ngZone },
26548
+ {
26549
+ provide: ENVIRONMENT_INITIALIZER,
26550
+ multi: true,
26551
+ useFactory: () => {
26552
+ const ngZoneChangeDetectionScheduler = inject(NgZoneChangeDetectionScheduler, { optional: true });
26553
+ if (NG_DEV_MODE && ngZoneChangeDetectionScheduler === null) {
26554
+ throw new RuntimeError(402 /* RuntimeErrorCode.MISSING_REQUIRED_INJECTABLE_IN_BOOTSTRAP */, 'No NgZoneChangeDetectionScheduler found in the Dependency Injection tree.');
26555
+ }
26556
+ return () => ngZoneChangeDetectionScheduler.initialize();
26557
+ },
26558
+ },
26559
+ { provide: INTERNAL_APPLICATION_ERROR_HANDLER, useFactory: ngZoneApplicationErrorHandlerFactory },
26560
+ { provide: ZONE_IS_STABLE_OBSERVABLE, useFactory: isStableFactory },
26561
+ ];
26562
+ }
25990
26563
 
25991
26564
  /**
25992
26565
  * Returns whether Angular is in development mode.
@@ -27905,6 +28478,25 @@ class SerializedViewCollection {
27905
28478
  return this.views;
27906
28479
  }
27907
28480
  }
28481
+ /**
28482
+ * Global counter that is used to generate a unique id for TViews
28483
+ * during the serialization process.
28484
+ */
28485
+ let tViewSsrId = 0;
28486
+ /**
28487
+ * Generates a unique id for a given TView and returns this id.
28488
+ * The id is also stored on this instance of a TView and reused in
28489
+ * subsequent calls.
28490
+ *
28491
+ * This id is needed to uniquely identify and pick up dehydrated views
28492
+ * at runtime.
28493
+ */
28494
+ function getSsrId(tView) {
28495
+ if (!tView.ssrId) {
28496
+ tView.ssrId = `t${tViewSsrId++}`;
28497
+ }
28498
+ return tView.ssrId;
28499
+ }
27908
28500
  /**
27909
28501
  * Computes the number of root nodes in a given view
27910
28502
  * (or child nodes in a given container if a tNode is provided).
@@ -27923,6 +28515,7 @@ function calcNumRootNodes(tView, lView, tNode) {
27923
28515
  */
27924
28516
  function annotateForHydration(appRef, doc) {
27925
28517
  const serializedViewCollection = new SerializedViewCollection();
28518
+ const corruptedTextNodes = new Map();
27926
28519
  const viewRefs = appRef._views;
27927
28520
  for (const viewRef of viewRefs) {
27928
28521
  const lView = getComponentLViewForHydration(viewRef);
@@ -27933,8 +28526,10 @@ function annotateForHydration(appRef, doc) {
27933
28526
  if (hostElement) {
27934
28527
  const context = {
27935
28528
  serializedViewCollection,
28529
+ corruptedTextNodes,
27936
28530
  };
27937
28531
  annotateHostElementForHydration(hostElement, lView, context);
28532
+ insertCorruptedTextNodeMarkers(corruptedTextNodes, doc);
27938
28533
  }
27939
28534
  }
27940
28535
  }
@@ -27944,6 +28539,45 @@ function annotateForHydration(appRef, doc) {
27944
28539
  transferState.set(NGH_DATA_KEY, allSerializedViews);
27945
28540
  }
27946
28541
  }
28542
+ /**
28543
+ * Serializes the lContainer data into a list of SerializedView objects,
28544
+ * that represent views within this lContainer.
28545
+ *
28546
+ * @param lContainer the lContainer we are serializing
28547
+ * @param context the hydration context
28548
+ * @returns an array of the `SerializedView` objects
28549
+ */
28550
+ function serializeLContainer(lContainer, context) {
28551
+ const views = [];
28552
+ for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
28553
+ let childLView = lContainer[i];
28554
+ // If this is a root view, get an LView for the underlying component,
28555
+ // because it contains information about the view to serialize.
28556
+ if (isRootView(childLView)) {
28557
+ childLView = childLView[HEADER_OFFSET];
28558
+ }
28559
+ const childTView = childLView[TVIEW];
28560
+ let template;
28561
+ let numRootNodes = 0;
28562
+ if (childTView.type === 1 /* TViewType.Component */) {
28563
+ template = childTView.ssrId;
28564
+ // This is a component view, thus it has only 1 root node: the component
28565
+ // host node itself (other nodes would be inside that host node).
28566
+ numRootNodes = 1;
28567
+ }
28568
+ else {
28569
+ template = getSsrId(childTView);
28570
+ numRootNodes = calcNumRootNodes(childTView, childLView, childTView.firstChild);
28571
+ }
28572
+ const view = {
28573
+ [TEMPLATE_ID]: template,
28574
+ [NUM_ROOT_NODES]: numRootNodes,
28575
+ ...serializeLView(lContainer[i], context),
28576
+ };
28577
+ views.push(view);
28578
+ }
28579
+ return views;
28580
+ }
27947
28581
  /**
27948
28582
  * Serializes the lView data into a SerializedView object that will later be added
27949
28583
  * to the TransferState storage and referenced using the `ngh` attribute on a host
@@ -27968,8 +28602,26 @@ function serializeLView(lView, context) {
27968
28602
  continue;
27969
28603
  }
27970
28604
  if (isLContainer(lView[i])) {
27971
- // TODO: serialization of LContainers will be added
27972
- // in followup PRs.
28605
+ // Serialize information about a template.
28606
+ const embeddedTView = tNode.tView;
28607
+ if (embeddedTView !== null) {
28608
+ ngh[TEMPLATES] ?? (ngh[TEMPLATES] = {});
28609
+ ngh[TEMPLATES][noOffsetIndex] = getSsrId(embeddedTView);
28610
+ }
28611
+ // Serialize views within this LContainer.
28612
+ const hostNode = lView[i][HOST]; // host node of this container
28613
+ // LView[i][HOST] can be of 2 different types:
28614
+ // - either a DOM node
28615
+ // - or an array that represents an LView of a component
28616
+ if (Array.isArray(hostNode)) {
28617
+ // This is a component, serialize info about it.
28618
+ const targetNode = unwrapRNode(hostNode);
28619
+ if (!targetNode.hasAttribute(SKIP_HYDRATION_ATTR_NAME)) {
28620
+ annotateHostElementForHydration(targetNode, hostNode, context);
28621
+ }
28622
+ }
28623
+ ngh[CONTAINERS] ?? (ngh[CONTAINERS] = {});
28624
+ ngh[CONTAINERS][noOffsetIndex] = serializeLContainer(lView[i], context);
27973
28625
  }
27974
28626
  else if (Array.isArray(lView[i])) {
27975
28627
  // This is a component, annotate the host node with an `ngh` attribute.
@@ -27987,6 +28639,43 @@ function serializeLView(lView, context) {
27987
28639
  ngh[ELEMENT_CONTAINERS] ?? (ngh[ELEMENT_CONTAINERS] = {});
27988
28640
  ngh[ELEMENT_CONTAINERS][noOffsetIndex] = calcNumRootNodes(tView, lView, tNode.child);
27989
28641
  }
28642
+ else {
28643
+ // Handle cases where text nodes can be lost after DOM serialization:
28644
+ // 1. When there is an *empty text node* in DOM: in this case, this
28645
+ // node would not make it into the serialized string and as a result,
28646
+ // this node wouldn't be created in a browser. This would result in
28647
+ // a mismatch during the hydration, where the runtime logic would expect
28648
+ // a text node to be present in live DOM, but no text node would exist.
28649
+ // Example: `<span>{{ name }}</span>` when the `name` is an empty string.
28650
+ // This would result in `<span></span>` string after serialization and
28651
+ // in a browser only the `span` element would be created. To resolve that,
28652
+ // an extra comment node is appended in place of an empty text node and
28653
+ // that special comment node is replaced with an empty text node *before*
28654
+ // hydration.
28655
+ // 2. When there are 2 consecutive text nodes present in the DOM.
28656
+ // Example: `<div>Hello <ng-container *ngIf="true">world</ng-container></div>`.
28657
+ // In this scenario, the live DOM would look like this:
28658
+ // <div>#text('Hello ') #text('world') #comment('container')</div>
28659
+ // Serialized string would look like this: `<div>Hello world<!--container--></div>`.
28660
+ // The live DOM in a browser after that would be:
28661
+ // <div>#text('Hello world') #comment('container')</div>
28662
+ // Notice how 2 text nodes are now "merged" into one. This would cause hydration
28663
+ // logic to fail, since it'd expect 2 text nodes being present, not one.
28664
+ // To fix this, we insert a special comment node in between those text nodes, so
28665
+ // serialized representation is: `<div>Hello <!--ngtns-->world<!--container--></div>`.
28666
+ // This forces browser to create 2 text nodes separated by a comment node.
28667
+ // Before running a hydration process, this special comment node is removed, so the
28668
+ // live DOM has exactly the same state as it was before serialization.
28669
+ if (tNode.type & 1 /* TNodeType.Text */) {
28670
+ const rNode = unwrapRNode(lView[i]);
28671
+ if (rNode.textContent?.replace(/\s/gm, '') === '') {
28672
+ context.corruptedTextNodes.set(rNode, "ngetn" /* TextNodeMarker.EmptyNode */);
28673
+ }
28674
+ else if (rNode.nextSibling?.nodeType === Node.TEXT_NODE) {
28675
+ context.corruptedTextNodes.set(rNode, "ngtns" /* TextNodeMarker.Separator */);
28676
+ }
28677
+ }
28678
+ }
27990
28679
  }
27991
28680
  }
27992
28681
  return ngh;
@@ -28004,6 +28693,20 @@ function annotateHostElementForHydration(element, lView, context) {
28004
28693
  const renderer = lView[RENDERER];
28005
28694
  renderer.setAttribute(element, NGH_ATTR_NAME, index.toString());
28006
28695
  }
28696
+ /**
28697
+ * Physically inserts the comment nodes to ensure empty text nodes and adjacent
28698
+ * text node separators are preserved after server serialization of the DOM.
28699
+ * These get swapped back for empty text nodes or separators once hydration happens
28700
+ * on the client.
28701
+ *
28702
+ * @param corruptedTextNodes The Map of text nodes to be replaced with comments
28703
+ * @param doc The document
28704
+ */
28705
+ function insertCorruptedTextNodeMarkers(corruptedTextNodes, doc) {
28706
+ for (const [textNode, marker] of corruptedTextNodes) {
28707
+ textNode.after(doc.createComment(marker));
28708
+ }
28709
+ }
28007
28710
 
28008
28711
  /**
28009
28712
  * Indicates whether the hydration-related code was added,
@@ -28028,6 +28731,10 @@ function enableHydrationRuntimeSupport() {
28028
28731
  enableLocateOrCreateElementNodeImpl();
28029
28732
  enableLocateOrCreateTextNodeImpl();
28030
28733
  enableLocateOrCreateElementContainerNodeImpl();
28734
+ enableLocateOrCreateContainerAnchorImpl();
28735
+ enableLocateOrCreateContainerRefImpl();
28736
+ enableFindMatchingDehydratedViewImpl();
28737
+ enableApplyRootElementTransformImpl();
28031
28738
  }
28032
28739
  }
28033
28740
  /**
@@ -28864,5 +29571,5 @@ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
28864
29571
  * Generated bundle index. Do not edit.
28865
29572
  */
28866
29573
 
28867
- export { ANALYZE_FOR_ENTRY_COMPONENTS, ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, 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, HostBinding, HostListener, 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, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, ReflectiveInjector, ReflectiveKey, Renderer2, RendererFactory2, RendererStyleFlags2, ResolvedReflectiveFactory, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, asNativeElements, assertPlatform, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, mergeApplicationConfig, platformCore, reflectComponentType, resolveForwardRef, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_FEATURE_ENABLED as ɵIS_HYDRATION_FEATURE_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, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, TransferState as ɵTransferState, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, _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, coerceToBoolean as ɵcoerceToBoolean, 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, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, escapeTransferStateContent as ɵescapeTransferStateContent, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, getComponentDef as ɵgetComponentDef, getDebugNode as ɵgetDebugNode, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, makeDecorator as ɵmakeDecorator, makeStateKey as ɵmakeStateKey, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, provideHydrationSupport as ɵprovideHydrationSupport, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unescapeTransferStateContent as ɵunescapeTransferStateContent, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵ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, ɵɵcontentQuery, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵ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, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵ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, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
29574
+ export { ANALYZE_FOR_ENTRY_COMPONENTS, ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, 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, HostBinding, HostListener, 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, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, ReflectiveInjector, ReflectiveKey, Renderer2, RendererFactory2, RendererStyleFlags2, ResolvedReflectiveFactory, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, asNativeElements, assertPlatform, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, mergeApplicationConfig, platformCore, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_FEATURE_ENABLED as ɵIS_HYDRATION_FEATURE_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, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, TransferState as ɵTransferState, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, _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, coerceToBoolean as ɵcoerceToBoolean, 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, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, escapeTransferStateContent as ɵescapeTransferStateContent, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, getComponentDef as ɵgetComponentDef, getDebugNode as ɵgetDebugNode, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, makeDecorator as ɵmakeDecorator, makeStateKey as ɵmakeStateKey, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, provideHydrationSupport as ɵprovideHydrationSupport, provideNgZoneChangeDetection as ɵprovideNgZoneChangeDetection, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setClassMetadata as ɵsetClassMetadata, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unescapeTransferStateContent as ɵunescapeTransferStateContent, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵ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, ɵɵcontentQuery, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵ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, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵ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, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
28868
29575
  //# sourceMappingURL=core.mjs.map