@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
@@ -1,10 +1,10 @@
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
  */
6
6
 
7
- import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ɵisEnvironmentProviders, ModuleWithComponentFactories, ɵconvertToBitFlags, Injector as Injector$1, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
7
+ import { getDebugNode, RendererFactory2 as RendererFactory2$1, InjectionToken as InjectionToken$1, ɵstringify, ɵReflectionCapabilities, Directive, Component, Pipe, NgModule, ɵgetInjectableDef, resolveForwardRef as resolveForwardRef$1, ɵNG_COMP_DEF, ɵRender3NgModuleRef, ApplicationInitStatus, LOCALE_ID as LOCALE_ID$1, ɵDEFAULT_LOCALE_ID, ɵsetLocaleId, ɵRender3ComponentFactory, ɵcompileComponent, ɵNG_DIR_DEF, ɵcompileDirective, ɵNG_PIPE_DEF, ɵcompilePipe, ɵNG_MOD_DEF, ɵtransitiveScopesFor, ɵpatchComponentDefWithScope, ɵNG_INJ_DEF, ɵcompileNgModuleDefs, NgZone, ɵprovideNgZoneChangeDetection, Compiler, COMPILER_OPTIONS, ɵNgModuleFactory, ɵisEnvironmentProviders, ModuleWithComponentFactories, ɵconvertToBitFlags, Injector as Injector$1, InjectFlags as InjectFlags$1, ɵsetAllowDuplicateNgModuleIdsForTest, ɵresetCompiledComponents, ɵsetUnknownElementStrictMode as ɵsetUnknownElementStrictMode$1, ɵsetUnknownPropertyStrictMode as ɵsetUnknownPropertyStrictMode$1, ɵgetUnknownElementStrictMode as ɵgetUnknownElementStrictMode$1, ɵgetUnknownPropertyStrictMode as ɵgetUnknownPropertyStrictMode$1, EnvironmentInjector as EnvironmentInjector$1, ɵflushModuleScopingQueueAsMuchAsPossible } from '@angular/core';
8
8
  import { __awaiter } from 'tslib';
9
9
  import { ResourceLoader } from '@angular/compiler';
10
10
  import { Subject, Subscription } from 'rxjs';
@@ -1638,6 +1638,7 @@ function ngDevModeResetPerfCounters() {
1638
1638
  rendererCreateComment: 0,
1639
1639
  hydratedNodes: 0,
1640
1640
  hydratedComponents: 0,
1641
+ dehydratedViewsRemoved: 0,
1641
1642
  };
1642
1643
  // Make sure to refer to ngDevMode as ['ngDevMode'] for closure.
1643
1644
  const allowNgDevModeTrue = locationString.indexOf('ngDevMode=false') === -1;
@@ -2198,244 +2199,834 @@ const NG_ELEMENT_ID = getClosureSafeProperty({ __NG_ELEMENT_ID__: getClosureSafe
2198
2199
  */
2199
2200
  const NG_ENV_ID = getClosureSafeProperty({ __NG_ENV_ID__: getClosureSafeProperty });
2200
2201
 
2201
- /** Counter used to generate unique IDs for component definitions. */
2202
- let componentDefCount = 0;
2203
2202
  /**
2204
- * Create a component definition object.
2205
- *
2206
- *
2207
- * # Example
2208
- * ```
2209
- * class MyDirective {
2210
- * // Generated by Angular Template Compiler
2211
- * // [Symbol] syntax will not be supported by TypeScript until v2.7
2212
- * static ɵcmp = defineComponent({
2213
- * ...
2214
- * });
2215
- * }
2216
- * ```
2217
- * @codeGenApi
2218
- */
2219
- function ɵɵdefineComponent(componentDefinition) {
2220
- return noSideEffects(() => {
2221
- // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
2222
- // See the `initNgDevMode` docstring for more information.
2223
- (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
2224
- const type = componentDefinition.type;
2225
- const standalone = componentDefinition.standalone === true;
2226
- const declaredInputs = {};
2227
- const def = {
2228
- type: type,
2229
- providersResolver: null,
2230
- decls: componentDefinition.decls,
2231
- vars: componentDefinition.vars,
2232
- factory: null,
2233
- template: componentDefinition.template || null,
2234
- consts: componentDefinition.consts || null,
2235
- ngContentSelectors: componentDefinition.ngContentSelectors,
2236
- hostBindings: componentDefinition.hostBindings || null,
2237
- hostVars: componentDefinition.hostVars || 0,
2238
- hostAttrs: componentDefinition.hostAttrs || null,
2239
- contentQueries: componentDefinition.contentQueries || null,
2240
- declaredInputs: declaredInputs,
2241
- inputs: null,
2242
- outputs: null,
2243
- exportAs: componentDefinition.exportAs || null,
2244
- onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush,
2245
- directiveDefs: null,
2246
- pipeDefs: null,
2247
- standalone,
2248
- dependencies: standalone && componentDefinition.dependencies || null,
2249
- getStandaloneInjector: null,
2250
- selectors: componentDefinition.selectors || EMPTY_ARRAY,
2251
- viewQuery: componentDefinition.viewQuery || null,
2252
- features: componentDefinition.features || null,
2253
- data: componentDefinition.data || {},
2254
- encapsulation: componentDefinition.encapsulation || ViewEncapsulation.Emulated,
2255
- id: `c${componentDefCount++}`,
2256
- styles: componentDefinition.styles || EMPTY_ARRAY,
2257
- _: null,
2258
- setInput: null,
2259
- schemas: componentDefinition.schemas || null,
2260
- tView: null,
2261
- findHostDirectiveDefs: null,
2262
- hostDirectives: null,
2263
- };
2264
- const dependencies = componentDefinition.dependencies;
2265
- const feature = componentDefinition.features;
2266
- def.inputs = invertObject(componentDefinition.inputs, declaredInputs),
2267
- def.outputs = invertObject(componentDefinition.outputs),
2268
- feature && feature.forEach((fn) => fn(def));
2269
- def.directiveDefs = dependencies ?
2270
- (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
2271
- .map(extractDirectiveDef)
2272
- .filter(nonNull)) :
2273
- null;
2274
- def.pipeDefs = dependencies ?
2275
- (() => (typeof dependencies === 'function' ? dependencies() : dependencies)
2276
- .map(getPipeDef$1)
2277
- .filter(nonNull)) :
2278
- null;
2279
- return def;
2280
- });
2281
- }
2282
- /**
2283
- * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
2284
- * definition, when generating a direct reference in the component file would otherwise create an
2285
- * import cycle.
2286
- *
2287
- * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
2288
- *
2289
- * @codeGenApi
2290
- */
2291
- function ɵɵsetComponentScope(type, directives, pipes) {
2292
- const def = type.ɵcmp;
2293
- def.directiveDefs = () => (typeof directives === 'function' ? directives() : directives).map(extractDirectiveDef);
2294
- def.pipeDefs = () => (typeof pipes === 'function' ? pipes() : pipes).map(getPipeDef$1);
2295
- }
2296
- function extractDirectiveDef(type) {
2297
- return getComponentDef$1(type) || getDirectiveDef(type);
2298
- }
2299
- function nonNull(value) {
2300
- return value !== null;
2301
- }
2302
- /**
2303
- * @codeGenApi
2304
- */
2305
- function ɵɵdefineNgModule(def) {
2306
- return noSideEffects(() => {
2307
- const res = {
2308
- type: def.type,
2309
- bootstrap: def.bootstrap || EMPTY_ARRAY,
2310
- declarations: def.declarations || EMPTY_ARRAY,
2311
- imports: def.imports || EMPTY_ARRAY,
2312
- exports: def.exports || EMPTY_ARRAY,
2313
- transitiveCompileScopes: null,
2314
- schemas: def.schemas || null,
2315
- id: def.id || null,
2316
- };
2317
- return res;
2318
- });
2319
- }
2320
- /**
2321
- * Adds the module metadata that is necessary to compute the module's transitive scope to an
2322
- * existing module definition.
2203
+ * Returns an index of `classToSearch` in `className` taking token boundaries into account.
2323
2204
  *
2324
- * Scope metadata of modules is not used in production builds, so calls to this function can be
2325
- * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
2326
- * to become eligible for tree-shaking as well.
2205
+ * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
2327
2206
  *
2328
- * @codeGenApi
2207
+ * @param className A string containing classes (whitespace separated)
2208
+ * @param classToSearch A class name to locate
2209
+ * @param startingIndex Starting location of search
2210
+ * @returns an index of the located class (or -1 if not found)
2329
2211
  */
2330
- function ɵɵsetNgModuleScope(type, scope) {
2331
- return noSideEffects(() => {
2332
- const ngModuleDef = getNgModuleDef(type, true);
2333
- ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
2334
- ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
2335
- ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
2336
- });
2212
+ function classIndexOf(className, classToSearch, startingIndex) {
2213
+ ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
2214
+ let end = className.length;
2215
+ while (true) {
2216
+ const foundIndex = className.indexOf(classToSearch, startingIndex);
2217
+ if (foundIndex === -1)
2218
+ return foundIndex;
2219
+ if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
2220
+ // Ensure that it has leading whitespace
2221
+ const length = classToSearch.length;
2222
+ if (foundIndex + length === end ||
2223
+ className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
2224
+ // Ensure that it has trailing whitespace
2225
+ return foundIndex;
2226
+ }
2227
+ }
2228
+ // False positive, keep searching from where we left off.
2229
+ startingIndex = foundIndex + 1;
2230
+ }
2337
2231
  }
2232
+
2338
2233
  /**
2339
- * Inverts an inputs or outputs lookup such that the keys, which were the
2340
- * minified keys, are part of the values, and the values are parsed so that
2341
- * the publicName of the property is the new key
2342
- *
2343
- * e.g. for
2344
- *
2345
- * ```
2346
- * class Comp {
2347
- * @Input()
2348
- * propName1: string;
2349
- *
2350
- * @Input('publicName2')
2351
- * declaredPropName2: number;
2352
- * }
2353
- * ```
2354
- *
2355
- * will be serialized as
2356
- *
2357
- * ```
2358
- * {
2359
- * propName1: 'propName1',
2360
- * declaredPropName2: ['publicName2', 'declaredPropName2'],
2361
- * }
2362
- * ```
2363
- *
2364
- * which is than translated by the minifier as:
2234
+ * Assigns all attribute values to the provided element via the inferred renderer.
2365
2235
  *
2366
- * ```
2367
- * {
2368
- * minifiedPropName1: 'propName1',
2369
- * minifiedPropName2: ['publicName2', 'declaredPropName2'],
2370
- * }
2371
- * ```
2236
+ * This function accepts two forms of attribute entries:
2372
2237
  *
2373
- * becomes: (public name => minifiedName)
2238
+ * default: (key, value):
2239
+ * attrs = [key1, value1, key2, value2]
2374
2240
  *
2375
- * ```
2376
- * {
2377
- * 'propName1': 'minifiedPropName1',
2378
- * 'publicName2': 'minifiedPropName2',
2379
- * }
2380
- * ```
2241
+ * namespaced: (NAMESPACE_MARKER, uri, name, value)
2242
+ * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
2381
2243
  *
2382
- * Optionally the function can take `secondary` which will result in: (public name => declared name)
2244
+ * The `attrs` array can contain a mix of both the default and namespaced entries.
2245
+ * The "default" values are set without a marker, but if the function comes across
2246
+ * a marker value then it will attempt to set a namespaced value. If the marker is
2247
+ * not of a namespaced value then the function will quit and return the index value
2248
+ * where it stopped during the iteration of the attrs array.
2383
2249
  *
2384
- * ```
2385
- * {
2386
- * 'propName1': 'propName1',
2387
- * 'publicName2': 'declaredPropName2',
2388
- * }
2389
- * ```
2250
+ * See [AttributeMarker] to understand what the namespace marker value is.
2390
2251
  *
2391
-
2252
+ * Note that this instruction does not support assigning style and class values to
2253
+ * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
2254
+ * are applied to an element.
2255
+ * @param renderer The renderer to be used
2256
+ * @param native The element that the attributes will be assigned to
2257
+ * @param attrs The attribute array of values that will be assigned to the element
2258
+ * @returns the index value that was last accessed in the attributes array
2392
2259
  */
2393
- function invertObject(obj, secondary) {
2394
- if (obj == null)
2395
- return EMPTY_OBJ;
2396
- const newLookup = {};
2397
- for (const minifiedKey in obj) {
2398
- if (obj.hasOwnProperty(minifiedKey)) {
2399
- let publicName = obj[minifiedKey];
2400
- let declaredName = publicName;
2401
- if (Array.isArray(publicName)) {
2402
- declaredName = publicName[1];
2403
- publicName = publicName[0];
2260
+ function setUpAttributes(renderer, native, attrs) {
2261
+ let i = 0;
2262
+ while (i < attrs.length) {
2263
+ const value = attrs[i];
2264
+ if (typeof value === 'number') {
2265
+ // only namespaces are supported. Other value types (such as style/class
2266
+ // entries) are not supported in this function.
2267
+ if (value !== 0 /* AttributeMarker.NamespaceURI */) {
2268
+ break;
2404
2269
  }
2405
- newLookup[publicName] = minifiedKey;
2406
- if (secondary) {
2407
- (secondary[publicName] = declaredName);
2270
+ // we just landed on the marker value ... therefore
2271
+ // we should skip to the next entry
2272
+ i++;
2273
+ const namespaceURI = attrs[i++];
2274
+ const attrName = attrs[i++];
2275
+ const attrVal = attrs[i++];
2276
+ ngDevMode && ngDevMode.rendererSetAttribute++;
2277
+ renderer.setAttribute(native, attrName, attrVal, namespaceURI);
2278
+ }
2279
+ else {
2280
+ // attrName is string;
2281
+ const attrName = value;
2282
+ const attrVal = attrs[++i];
2283
+ // Standard attributes
2284
+ ngDevMode && ngDevMode.rendererSetAttribute++;
2285
+ if (isAnimationProp(attrName)) {
2286
+ renderer.setProperty(native, attrName, attrVal);
2287
+ }
2288
+ else {
2289
+ renderer.setAttribute(native, attrName, attrVal);
2408
2290
  }
2291
+ i++;
2409
2292
  }
2410
2293
  }
2411
- return newLookup;
2294
+ // another piece of code may iterate over the same attributes array. Therefore
2295
+ // it may be helpful to return the exact spot where the attributes array exited
2296
+ // whether by running into an unsupported marker or if all the static values were
2297
+ // iterated over.
2298
+ return i;
2412
2299
  }
2413
2300
  /**
2414
- * Create a directive definition object.
2415
- *
2416
- * # Example
2417
- * ```ts
2418
- * class MyDirective {
2419
- * // Generated by Angular Template Compiler
2420
- * // [Symbol] syntax will not be supported by TypeScript until v2.7
2421
- * static ɵdir = ɵɵdefineDirective({
2422
- * ...
2423
- * });
2424
- * }
2425
- * ```
2426
- *
2427
- * @codeGenApi
2301
+ * Test whether the given value is a marker that indicates that the following
2302
+ * attribute values in a `TAttributes` array are only the names of attributes,
2303
+ * and not name-value pairs.
2304
+ * @param marker The attribute marker to test.
2305
+ * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
2428
2306
  */
2429
- const ɵɵdefineDirective = ɵɵdefineComponent;
2307
+ function isNameOnlyAttributeMarker(marker) {
2308
+ return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
2309
+ marker === 6 /* AttributeMarker.I18n */;
2310
+ }
2311
+ function isAnimationProp(name) {
2312
+ // Perf note: accessing charCodeAt to check for the first character of a string is faster as
2313
+ // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
2314
+ // charCodeAt doesn't allocate memory to return a substring.
2315
+ return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
2316
+ }
2430
2317
  /**
2431
- * Create a pipe definition object.
2318
+ * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
2432
2319
  *
2433
- * # Example
2434
- * ```
2435
- * class MyPipe implements PipeTransform {
2436
- * // Generated by Angular Template Compiler
2437
- * static ɵpipe = definePipe({
2438
- * ...
2320
+ * This merge function keeps the order of attrs same.
2321
+ *
2322
+ * @param dst Location of where the merged `TAttributes` should end up.
2323
+ * @param src `TAttributes` which should be appended to `dst`
2324
+ */
2325
+ function mergeHostAttrs(dst, src) {
2326
+ if (src === null || src.length === 0) {
2327
+ // do nothing
2328
+ }
2329
+ else if (dst === null || dst.length === 0) {
2330
+ // We have source, but dst is empty, just make a copy.
2331
+ dst = src.slice();
2332
+ }
2333
+ else {
2334
+ let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
2335
+ for (let i = 0; i < src.length; i++) {
2336
+ const item = src[i];
2337
+ if (typeof item === 'number') {
2338
+ srcMarker = item;
2339
+ }
2340
+ else {
2341
+ if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
2342
+ // Case where we need to consume `key1`, `key2`, `value` items.
2343
+ }
2344
+ else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
2345
+ srcMarker === 2 /* AttributeMarker.Styles */) {
2346
+ // Case where we have to consume `key1` and `value` only.
2347
+ mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
2348
+ }
2349
+ else {
2350
+ // Case where we have to consume `key1` only.
2351
+ mergeHostAttribute(dst, srcMarker, item, null, null);
2352
+ }
2353
+ }
2354
+ }
2355
+ }
2356
+ return dst;
2357
+ }
2358
+ /**
2359
+ * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
2360
+ *
2361
+ * @param dst `TAttributes` to append to.
2362
+ * @param marker Region where the `key`/`value` should be added.
2363
+ * @param key1 Key to add to `TAttributes`
2364
+ * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
2365
+ * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
2366
+ */
2367
+ function mergeHostAttribute(dst, marker, key1, key2, value) {
2368
+ let i = 0;
2369
+ // Assume that new markers will be inserted at the end.
2370
+ let markerInsertPosition = dst.length;
2371
+ // scan until correct type.
2372
+ if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
2373
+ markerInsertPosition = -1;
2374
+ }
2375
+ else {
2376
+ while (i < dst.length) {
2377
+ const dstValue = dst[i++];
2378
+ if (typeof dstValue === 'number') {
2379
+ if (dstValue === marker) {
2380
+ markerInsertPosition = -1;
2381
+ break;
2382
+ }
2383
+ else if (dstValue > marker) {
2384
+ // We need to save this as we want the markers to be inserted in specific order.
2385
+ markerInsertPosition = i - 1;
2386
+ break;
2387
+ }
2388
+ }
2389
+ }
2390
+ }
2391
+ // search until you find place of insertion
2392
+ while (i < dst.length) {
2393
+ const item = dst[i];
2394
+ if (typeof item === 'number') {
2395
+ // since `i` started as the index after the marker, we did not find it if we are at the next
2396
+ // marker
2397
+ break;
2398
+ }
2399
+ else if (item === key1) {
2400
+ // We already have same token
2401
+ if (key2 === null) {
2402
+ if (value !== null) {
2403
+ dst[i + 1] = value;
2404
+ }
2405
+ return;
2406
+ }
2407
+ else if (key2 === dst[i + 1]) {
2408
+ dst[i + 2] = value;
2409
+ return;
2410
+ }
2411
+ }
2412
+ // Increment counter.
2413
+ i++;
2414
+ if (key2 !== null)
2415
+ i++;
2416
+ if (value !== null)
2417
+ i++;
2418
+ }
2419
+ // insert at location.
2420
+ if (markerInsertPosition !== -1) {
2421
+ dst.splice(markerInsertPosition, 0, marker);
2422
+ i = markerInsertPosition + 1;
2423
+ }
2424
+ dst.splice(i++, 0, key1);
2425
+ if (key2 !== null) {
2426
+ dst.splice(i++, 0, key2);
2427
+ }
2428
+ if (value !== null) {
2429
+ dst.splice(i++, 0, value);
2430
+ }
2431
+ }
2432
+
2433
+ const NG_TEMPLATE_SELECTOR = 'ng-template';
2434
+ /**
2435
+ * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
2436
+ *
2437
+ * @param attrs `TAttributes` to search through.
2438
+ * @param cssClassToMatch class to match (lowercase)
2439
+ * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
2440
+ * addition to the `AttributeMarker.Classes`.
2441
+ */
2442
+ function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
2443
+ // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
2444
+ // It is strange to me that sometimes the class information comes in form of `class` attribute
2445
+ // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
2446
+ // if that is the right behavior.
2447
+ ngDevMode &&
2448
+ assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
2449
+ let i = 0;
2450
+ while (i < attrs.length) {
2451
+ let item = attrs[i++];
2452
+ if (isProjectionMode && item === 'class') {
2453
+ item = attrs[i];
2454
+ if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
2455
+ return true;
2456
+ }
2457
+ }
2458
+ else if (item === 1 /* AttributeMarker.Classes */) {
2459
+ // We found the classes section. Start searching for the class.
2460
+ while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
2461
+ // while we have strings
2462
+ if (item.toLowerCase() === cssClassToMatch)
2463
+ return true;
2464
+ }
2465
+ return false;
2466
+ }
2467
+ }
2468
+ return false;
2469
+ }
2470
+ /**
2471
+ * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
2472
+ *
2473
+ * @param tNode current TNode
2474
+ */
2475
+ function isInlineTemplate(tNode) {
2476
+ return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
2477
+ }
2478
+ /**
2479
+ * Function that checks whether a given tNode matches tag-based selector and has a valid type.
2480
+ *
2481
+ * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
2482
+ * directive matching mode:
2483
+ * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
2484
+ * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
2485
+ * tag name was extracted from * syntax so we would match the same directive twice);
2486
+ * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
2487
+ * (applicable to TNodeType.Container only).
2488
+ */
2489
+ function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
2490
+ const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
2491
+ return currentSelector === tagNameToCompare;
2492
+ }
2493
+ /**
2494
+ * A utility function to match an Ivy node static data against a simple CSS selector
2495
+ *
2496
+ * @param node static data of the node to match
2497
+ * @param selector The selector to try matching against the node.
2498
+ * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
2499
+ * directive matching.
2500
+ * @returns true if node matches the selector.
2501
+ */
2502
+ function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
2503
+ ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
2504
+ let mode = 4 /* SelectorFlags.ELEMENT */;
2505
+ const nodeAttrs = tNode.attrs || [];
2506
+ // Find the index of first attribute that has no value, only a name.
2507
+ const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
2508
+ // When processing ":not" selectors, we skip to the next ":not" if the
2509
+ // current one doesn't match
2510
+ let skipToNextSelector = false;
2511
+ for (let i = 0; i < selector.length; i++) {
2512
+ const current = selector[i];
2513
+ if (typeof current === 'number') {
2514
+ // If we finish processing a :not selector and it hasn't failed, return false
2515
+ if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
2516
+ return false;
2517
+ }
2518
+ // If we are skipping to the next :not() and this mode flag is positive,
2519
+ // it's a part of the current :not() selector, and we should keep skipping
2520
+ if (skipToNextSelector && isPositive(current))
2521
+ continue;
2522
+ skipToNextSelector = false;
2523
+ mode = current | (mode & 1 /* SelectorFlags.NOT */);
2524
+ continue;
2525
+ }
2526
+ if (skipToNextSelector)
2527
+ continue;
2528
+ if (mode & 4 /* SelectorFlags.ELEMENT */) {
2529
+ mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
2530
+ if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
2531
+ current === '' && selector.length === 1) {
2532
+ if (isPositive(mode))
2533
+ return false;
2534
+ skipToNextSelector = true;
2535
+ }
2536
+ }
2537
+ else {
2538
+ const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
2539
+ // special case for matching against classes when a tNode has been instantiated with
2540
+ // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
2541
+ if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
2542
+ if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
2543
+ if (isPositive(mode))
2544
+ return false;
2545
+ skipToNextSelector = true;
2546
+ }
2547
+ continue;
2548
+ }
2549
+ const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
2550
+ const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
2551
+ if (attrIndexInNode === -1) {
2552
+ if (isPositive(mode))
2553
+ return false;
2554
+ skipToNextSelector = true;
2555
+ continue;
2556
+ }
2557
+ if (selectorAttrValue !== '') {
2558
+ let nodeAttrValue;
2559
+ if (attrIndexInNode > nameOnlyMarkerIdx) {
2560
+ nodeAttrValue = '';
2561
+ }
2562
+ else {
2563
+ ngDevMode &&
2564
+ assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
2565
+ // we lowercase the attribute value to be able to match
2566
+ // selectors without case-sensitivity
2567
+ // (selectors are already in lowercase when generated)
2568
+ nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
2569
+ }
2570
+ const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
2571
+ if (compareAgainstClassName &&
2572
+ classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
2573
+ mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
2574
+ if (isPositive(mode))
2575
+ return false;
2576
+ skipToNextSelector = true;
2577
+ }
2578
+ }
2579
+ }
2580
+ }
2581
+ return isPositive(mode) || skipToNextSelector;
2582
+ }
2583
+ function isPositive(mode) {
2584
+ return (mode & 1 /* SelectorFlags.NOT */) === 0;
2585
+ }
2586
+ /**
2587
+ * Examines the attribute's definition array for a node to find the index of the
2588
+ * attribute that matches the given `name`.
2589
+ *
2590
+ * NOTE: This will not match namespaced attributes.
2591
+ *
2592
+ * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
2593
+ * The following table summarizes which types of attributes we attempt to match:
2594
+ *
2595
+ * ===========================================================================================================
2596
+ * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
2597
+ * Attributes
2598
+ * ===========================================================================================================
2599
+ * Inline + Projection | YES | YES | NO | YES
2600
+ * -----------------------------------------------------------------------------------------------------------
2601
+ * Inline + Directive | NO | NO | YES | NO
2602
+ * -----------------------------------------------------------------------------------------------------------
2603
+ * Non-inline + Projection | YES | YES | NO | YES
2604
+ * -----------------------------------------------------------------------------------------------------------
2605
+ * Non-inline + Directive | YES | YES | NO | YES
2606
+ * ===========================================================================================================
2607
+ *
2608
+ * @param name the name of the attribute to find
2609
+ * @param attrs the attribute array to examine
2610
+ * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
2611
+ * rather than a manually expanded template node (e.g `<ng-template>`).
2612
+ * @param isProjectionMode true if we are matching against content projection otherwise we are
2613
+ * matching against directives.
2614
+ */
2615
+ function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
2616
+ if (attrs === null)
2617
+ return -1;
2618
+ let i = 0;
2619
+ if (isProjectionMode || !isInlineTemplate) {
2620
+ let bindingsMode = false;
2621
+ while (i < attrs.length) {
2622
+ const maybeAttrName = attrs[i];
2623
+ if (maybeAttrName === name) {
2624
+ return i;
2625
+ }
2626
+ else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
2627
+ bindingsMode = true;
2628
+ }
2629
+ else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
2630
+ let value = attrs[++i];
2631
+ // We should skip classes here because we have a separate mechanism for
2632
+ // matching classes in projection mode.
2633
+ while (typeof value === 'string') {
2634
+ value = attrs[++i];
2635
+ }
2636
+ continue;
2637
+ }
2638
+ else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
2639
+ // We do not care about Template attributes in this scenario.
2640
+ break;
2641
+ }
2642
+ else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
2643
+ // Skip the whole namespaced attribute and value. This is by design.
2644
+ i += 4;
2645
+ continue;
2646
+ }
2647
+ // In binding mode there are only names, rather than name-value pairs.
2648
+ i += bindingsMode ? 1 : 2;
2649
+ }
2650
+ // We did not match the attribute
2651
+ return -1;
2652
+ }
2653
+ else {
2654
+ return matchTemplateAttribute(attrs, name);
2655
+ }
2656
+ }
2657
+ function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
2658
+ for (let i = 0; i < selector.length; i++) {
2659
+ if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
2660
+ return true;
2661
+ }
2662
+ }
2663
+ return false;
2664
+ }
2665
+ function getProjectAsAttrValue(tNode) {
2666
+ const nodeAttrs = tNode.attrs;
2667
+ if (nodeAttrs != null) {
2668
+ const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
2669
+ // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
2670
+ // (attribute names are stored at even indexes)
2671
+ if ((ngProjectAsAttrIdx & 1) === 0) {
2672
+ return nodeAttrs[ngProjectAsAttrIdx + 1];
2673
+ }
2674
+ }
2675
+ return null;
2676
+ }
2677
+ function getNameOnlyMarkerIndex(nodeAttrs) {
2678
+ for (let i = 0; i < nodeAttrs.length; i++) {
2679
+ const nodeAttr = nodeAttrs[i];
2680
+ if (isNameOnlyAttributeMarker(nodeAttr)) {
2681
+ return i;
2682
+ }
2683
+ }
2684
+ return nodeAttrs.length;
2685
+ }
2686
+ function matchTemplateAttribute(attrs, name) {
2687
+ let i = attrs.indexOf(4 /* AttributeMarker.Template */);
2688
+ if (i > -1) {
2689
+ i++;
2690
+ while (i < attrs.length) {
2691
+ const attr = attrs[i];
2692
+ // Return in case we checked all template attrs and are switching to the next section in the
2693
+ // attrs array (that starts with a number that represents an attribute marker).
2694
+ if (typeof attr === 'number')
2695
+ return -1;
2696
+ if (attr === name)
2697
+ return i;
2698
+ i++;
2699
+ }
2700
+ }
2701
+ return -1;
2702
+ }
2703
+ /**
2704
+ * Checks whether a selector is inside a CssSelectorList
2705
+ * @param selector Selector to be checked.
2706
+ * @param list List in which to look for the selector.
2707
+ */
2708
+ function isSelectorInSelectorList(selector, list) {
2709
+ selectorListLoop: for (let i = 0; i < list.length; i++) {
2710
+ const currentSelectorInList = list[i];
2711
+ if (selector.length !== currentSelectorInList.length) {
2712
+ continue;
2713
+ }
2714
+ for (let j = 0; j < selector.length; j++) {
2715
+ if (selector[j] !== currentSelectorInList[j]) {
2716
+ continue selectorListLoop;
2717
+ }
2718
+ }
2719
+ return true;
2720
+ }
2721
+ return false;
2722
+ }
2723
+ function maybeWrapInNotSelector(isNegativeMode, chunk) {
2724
+ return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
2725
+ }
2726
+ function stringifyCSSSelector(selector) {
2727
+ let result = selector[0];
2728
+ let i = 1;
2729
+ let mode = 2 /* SelectorFlags.ATTRIBUTE */;
2730
+ let currentChunk = '';
2731
+ let isNegativeMode = false;
2732
+ while (i < selector.length) {
2733
+ let valueOrMarker = selector[i];
2734
+ if (typeof valueOrMarker === 'string') {
2735
+ if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
2736
+ const attrValue = selector[++i];
2737
+ currentChunk +=
2738
+ '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
2739
+ }
2740
+ else if (mode & 8 /* SelectorFlags.CLASS */) {
2741
+ currentChunk += '.' + valueOrMarker;
2742
+ }
2743
+ else if (mode & 4 /* SelectorFlags.ELEMENT */) {
2744
+ currentChunk += ' ' + valueOrMarker;
2745
+ }
2746
+ }
2747
+ else {
2748
+ //
2749
+ // Append current chunk to the final result in case we come across SelectorFlag, which
2750
+ // indicates that the previous section of a selector is over. We need to accumulate content
2751
+ // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
2752
+ // ```
2753
+ // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
2754
+ // ```
2755
+ // should be transformed to `.classA :not(.classB .classC)`.
2756
+ //
2757
+ // Note: for negative selector part, we accumulate content between flags until we find the
2758
+ // next negative flag. This is needed to support a case where `:not()` rule contains more than
2759
+ // one chunk, e.g. the following selector:
2760
+ // ```
2761
+ // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
2762
+ // ```
2763
+ // should be stringified to `:not(p.foo) :not(.bar)`
2764
+ //
2765
+ if (currentChunk !== '' && !isPositive(valueOrMarker)) {
2766
+ result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
2767
+ currentChunk = '';
2768
+ }
2769
+ mode = valueOrMarker;
2770
+ // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
2771
+ // mode is maintained for remaining chunks of a selector.
2772
+ isNegativeMode = isNegativeMode || !isPositive(mode);
2773
+ }
2774
+ i++;
2775
+ }
2776
+ if (currentChunk !== '') {
2777
+ result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
2778
+ }
2779
+ return result;
2780
+ }
2781
+ /**
2782
+ * Generates string representation of CSS selector in parsed form.
2783
+ *
2784
+ * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
2785
+ * additional parsing at runtime (for example, for directive matching). However in some cases (for
2786
+ * example, while bootstrapping a component), a string version of the selector is required to query
2787
+ * for the host element on the page. This function takes the parsed form of a selector and returns
2788
+ * its string representation.
2789
+ *
2790
+ * @param selectorList selector in parsed form
2791
+ * @returns string representation of a given selector
2792
+ */
2793
+ function stringifyCSSSelectorList(selectorList) {
2794
+ return selectorList.map(stringifyCSSSelector).join(',');
2795
+ }
2796
+ /**
2797
+ * Extracts attributes and classes information from a given CSS selector.
2798
+ *
2799
+ * This function is used while creating a component dynamically. In this case, the host element
2800
+ * (that is created dynamically) should contain attributes and classes specified in component's CSS
2801
+ * selector.
2802
+ *
2803
+ * @param selector CSS selector in parsed form (in a form of array)
2804
+ * @returns object with `attrs` and `classes` fields that contain extracted information
2805
+ */
2806
+ function extractAttrsAndClassesFromSelector(selector) {
2807
+ const attrs = [];
2808
+ const classes = [];
2809
+ let i = 1;
2810
+ let mode = 2 /* SelectorFlags.ATTRIBUTE */;
2811
+ while (i < selector.length) {
2812
+ let valueOrMarker = selector[i];
2813
+ if (typeof valueOrMarker === 'string') {
2814
+ if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
2815
+ if (valueOrMarker !== '') {
2816
+ attrs.push(valueOrMarker, selector[++i]);
2817
+ }
2818
+ }
2819
+ else if (mode === 8 /* SelectorFlags.CLASS */) {
2820
+ classes.push(valueOrMarker);
2821
+ }
2822
+ }
2823
+ else {
2824
+ // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
2825
+ // mode is maintained for remaining chunks of a selector. Since attributes and classes are
2826
+ // extracted only for "positive" part of the selector, we can stop here.
2827
+ if (!isPositive(mode))
2828
+ break;
2829
+ mode = valueOrMarker;
2830
+ }
2831
+ i++;
2832
+ }
2833
+ return { attrs, classes };
2834
+ }
2835
+
2836
+ /**
2837
+ * Create a component definition object.
2838
+ *
2839
+ *
2840
+ * # Example
2841
+ * ```
2842
+ * class MyComponent {
2843
+ * // Generated by Angular Template Compiler
2844
+ * // [Symbol] syntax will not be supported by TypeScript until v2.7
2845
+ * static ɵcmp = defineComponent({
2846
+ * ...
2847
+ * });
2848
+ * }
2849
+ * ```
2850
+ * @codeGenApi
2851
+ */
2852
+ function ɵɵdefineComponent(componentDefinition) {
2853
+ return noSideEffects(() => {
2854
+ // Initialize ngDevMode. This must be the first statement in ɵɵdefineComponent.
2855
+ // See the `initNgDevMode` docstring for more information.
2856
+ (typeof ngDevMode === 'undefined' || ngDevMode) && initNgDevMode();
2857
+ const baseDef = getNgDirectiveDef(componentDefinition);
2858
+ const def = Object.assign(Object.assign({}, baseDef), { decls: componentDefinition.decls, vars: componentDefinition.vars, template: componentDefinition.template, consts: componentDefinition.consts || null, ngContentSelectors: componentDefinition.ngContentSelectors, onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush, directiveDefs: null, pipeDefs: null, dependencies: baseDef.standalone && componentDefinition.dependencies || null, getStandaloneInjector: null, data: componentDefinition.data || {}, encapsulation: componentDefinition.encapsulation || ViewEncapsulation.Emulated, styles: componentDefinition.styles || EMPTY_ARRAY, _: null, schemas: componentDefinition.schemas || null, tView: null, id: '' });
2859
+ initFeatures(def);
2860
+ const dependencies = componentDefinition.dependencies;
2861
+ def.directiveDefs = extractDefListOrFactory(dependencies, /* pipeDef */ false);
2862
+ def.pipeDefs = extractDefListOrFactory(dependencies, /* pipeDef */ true);
2863
+ def.id = getComponentId(def);
2864
+ return def;
2865
+ });
2866
+ }
2867
+ /**
2868
+ * Generated next to NgModules to monkey-patch directive and pipe references onto a component's
2869
+ * definition, when generating a direct reference in the component file would otherwise create an
2870
+ * import cycle.
2871
+ *
2872
+ * See [this explanation](https://hackmd.io/Odw80D0pR6yfsOjg_7XCJg?view) for more details.
2873
+ *
2874
+ * @codeGenApi
2875
+ */
2876
+ function ɵɵsetComponentScope(type, directives, pipes) {
2877
+ const def = type.ɵcmp;
2878
+ def.directiveDefs = extractDefListOrFactory(directives, /* pipeDef */ false);
2879
+ def.pipeDefs = extractDefListOrFactory(pipes, /* pipeDef */ true);
2880
+ }
2881
+ function extractDirectiveDef(type) {
2882
+ return getComponentDef$1(type) || getDirectiveDef(type);
2883
+ }
2884
+ function nonNull(value) {
2885
+ return value !== null;
2886
+ }
2887
+ /**
2888
+ * @codeGenApi
2889
+ */
2890
+ function ɵɵdefineNgModule(def) {
2891
+ return noSideEffects(() => {
2892
+ const res = {
2893
+ type: def.type,
2894
+ bootstrap: def.bootstrap || EMPTY_ARRAY,
2895
+ declarations: def.declarations || EMPTY_ARRAY,
2896
+ imports: def.imports || EMPTY_ARRAY,
2897
+ exports: def.exports || EMPTY_ARRAY,
2898
+ transitiveCompileScopes: null,
2899
+ schemas: def.schemas || null,
2900
+ id: def.id || null,
2901
+ };
2902
+ return res;
2903
+ });
2904
+ }
2905
+ /**
2906
+ * Adds the module metadata that is necessary to compute the module's transitive scope to an
2907
+ * existing module definition.
2908
+ *
2909
+ * Scope metadata of modules is not used in production builds, so calls to this function can be
2910
+ * marked pure to tree-shake it from the bundle, allowing for all referenced declarations
2911
+ * to become eligible for tree-shaking as well.
2912
+ *
2913
+ * @codeGenApi
2914
+ */
2915
+ function ɵɵsetNgModuleScope(type, scope) {
2916
+ return noSideEffects(() => {
2917
+ const ngModuleDef = getNgModuleDef(type, true);
2918
+ ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY;
2919
+ ngModuleDef.imports = scope.imports || EMPTY_ARRAY;
2920
+ ngModuleDef.exports = scope.exports || EMPTY_ARRAY;
2921
+ });
2922
+ }
2923
+ /**
2924
+ * Inverts an inputs or outputs lookup such that the keys, which were the
2925
+ * minified keys, are part of the values, and the values are parsed so that
2926
+ * the publicName of the property is the new key
2927
+ *
2928
+ * e.g. for
2929
+ *
2930
+ * ```
2931
+ * class Comp {
2932
+ * @Input()
2933
+ * propName1: string;
2934
+ *
2935
+ * @Input('publicName2')
2936
+ * declaredPropName2: number;
2937
+ * }
2938
+ * ```
2939
+ *
2940
+ * will be serialized as
2941
+ *
2942
+ * ```
2943
+ * {
2944
+ * propName1: 'propName1',
2945
+ * declaredPropName2: ['publicName2', 'declaredPropName2'],
2946
+ * }
2947
+ * ```
2948
+ *
2949
+ * which is than translated by the minifier as:
2950
+ *
2951
+ * ```
2952
+ * {
2953
+ * minifiedPropName1: 'propName1',
2954
+ * minifiedPropName2: ['publicName2', 'declaredPropName2'],
2955
+ * }
2956
+ * ```
2957
+ *
2958
+ * becomes: (public name => minifiedName)
2959
+ *
2960
+ * ```
2961
+ * {
2962
+ * 'propName1': 'minifiedPropName1',
2963
+ * 'publicName2': 'minifiedPropName2',
2964
+ * }
2965
+ * ```
2966
+ *
2967
+ * Optionally the function can take `secondary` which will result in: (public name => declared name)
2968
+ *
2969
+ * ```
2970
+ * {
2971
+ * 'propName1': 'propName1',
2972
+ * 'publicName2': 'declaredPropName2',
2973
+ * }
2974
+ * ```
2975
+ *
2976
+
2977
+ */
2978
+ function invertObject(obj, secondary) {
2979
+ if (obj == null)
2980
+ return EMPTY_OBJ;
2981
+ const newLookup = {};
2982
+ for (const minifiedKey in obj) {
2983
+ if (obj.hasOwnProperty(minifiedKey)) {
2984
+ let publicName = obj[minifiedKey];
2985
+ let declaredName = publicName;
2986
+ if (Array.isArray(publicName)) {
2987
+ declaredName = publicName[1];
2988
+ publicName = publicName[0];
2989
+ }
2990
+ newLookup[publicName] = minifiedKey;
2991
+ if (secondary) {
2992
+ (secondary[publicName] = declaredName);
2993
+ }
2994
+ }
2995
+ }
2996
+ return newLookup;
2997
+ }
2998
+ /**
2999
+ * Create a directive definition object.
3000
+ *
3001
+ * # Example
3002
+ * ```ts
3003
+ * class MyDirective {
3004
+ * // Generated by Angular Template Compiler
3005
+ * // [Symbol] syntax will not be supported by TypeScript until v2.7
3006
+ * static ɵdir = ɵɵdefineDirective({
3007
+ * ...
3008
+ * });
3009
+ * }
3010
+ * ```
3011
+ *
3012
+ * @codeGenApi
3013
+ */
3014
+ function ɵɵdefineDirective(directiveDefinition) {
3015
+ return noSideEffects(() => {
3016
+ const def = getNgDirectiveDef(directiveDefinition);
3017
+ initFeatures(def);
3018
+ return def;
3019
+ });
3020
+ }
3021
+ /**
3022
+ * Create a pipe definition object.
3023
+ *
3024
+ * # Example
3025
+ * ```
3026
+ * class MyPipe implements PipeTransform {
3027
+ * // Generated by Angular Template Compiler
3028
+ * static ɵpipe = definePipe({
3029
+ * ...
2439
3030
  * });
2440
3031
  * }
2441
3032
  * ```
@@ -2486,6 +3077,100 @@ function getNgModuleDef(type, throwNotFound) {
2486
3077
  }
2487
3078
  return ngModuleDef;
2488
3079
  }
3080
+ function getNgDirectiveDef(directiveDefinition) {
3081
+ const declaredInputs = {};
3082
+ return {
3083
+ type: directiveDefinition.type,
3084
+ providersResolver: null,
3085
+ factory: null,
3086
+ hostBindings: directiveDefinition.hostBindings || null,
3087
+ hostVars: directiveDefinition.hostVars || 0,
3088
+ hostAttrs: directiveDefinition.hostAttrs || null,
3089
+ contentQueries: directiveDefinition.contentQueries || null,
3090
+ declaredInputs,
3091
+ exportAs: directiveDefinition.exportAs || null,
3092
+ standalone: directiveDefinition.standalone === true,
3093
+ selectors: directiveDefinition.selectors || EMPTY_ARRAY,
3094
+ viewQuery: directiveDefinition.viewQuery || null,
3095
+ features: directiveDefinition.features || null,
3096
+ setInput: null,
3097
+ findHostDirectiveDefs: null,
3098
+ hostDirectives: null,
3099
+ inputs: invertObject(directiveDefinition.inputs, declaredInputs),
3100
+ outputs: invertObject(directiveDefinition.outputs),
3101
+ };
3102
+ }
3103
+ function initFeatures(definition) {
3104
+ var _a;
3105
+ (_a = definition.features) === null || _a === void 0 ? void 0 : _a.forEach((fn) => fn(definition));
3106
+ }
3107
+ function extractDefListOrFactory(dependencies, pipeDef) {
3108
+ if (!dependencies) {
3109
+ return null;
3110
+ }
3111
+ const defExtractor = pipeDef ? getPipeDef$1 : extractDirectiveDef;
3112
+ return () => (typeof dependencies === 'function' ? dependencies() : dependencies)
3113
+ .map(dep => defExtractor(dep))
3114
+ .filter(nonNull);
3115
+ }
3116
+ /**
3117
+ * A map that contains the generated component IDs and type.
3118
+ */
3119
+ const GENERATED_COMP_IDS = new Map();
3120
+ /**
3121
+ * A method can returns a component ID from the component definition using a variant of DJB2 hash
3122
+ * algorithm.
3123
+ */
3124
+ function getComponentId(componentDef) {
3125
+ let hash = 0;
3126
+ // We cannot rely solely on the component selector as the same selector can be used in different
3127
+ // modules.
3128
+ //
3129
+ // `componentDef.style` is not used, due to it causing inconsistencies. Ex: when server
3130
+ // component styles has no sourcemaps and browsers do.
3131
+ //
3132
+ // Example:
3133
+ // https://github.com/angular/components/blob/d9f82c8f95309e77a6d82fd574c65871e91354c2/src/material/core/option/option.ts#L248
3134
+ // https://github.com/angular/components/blob/285f46dc2b4c5b127d356cb7c4714b221f03ce50/src/material/legacy-core/option/option.ts#L32
3135
+ const hashSelectors = [
3136
+ componentDef.selectors,
3137
+ componentDef.ngContentSelectors,
3138
+ componentDef.hostVars,
3139
+ componentDef.hostAttrs,
3140
+ componentDef.consts,
3141
+ componentDef.vars,
3142
+ componentDef.decls,
3143
+ componentDef.encapsulation,
3144
+ componentDef.standalone,
3145
+ // We cannot use 'componentDef.type.name' as the name of the symbol will change and will not
3146
+ // match in the server and browser bundles.
3147
+ Object.getOwnPropertyNames(componentDef.type.prototype),
3148
+ !!componentDef.contentQueries,
3149
+ !!componentDef.viewQuery,
3150
+ ].join('|');
3151
+ for (const char of hashSelectors) {
3152
+ hash = Math.imul(31, hash) + char.charCodeAt(0) << 0;
3153
+ }
3154
+ // Force positive number hash.
3155
+ // 2147483647 = equivalent of Integer.MAX_VALUE.
3156
+ hash += 2147483647 + 1;
3157
+ const compId = 'c' + hash;
3158
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
3159
+ if (GENERATED_COMP_IDS.has(compId)) {
3160
+ const previousCompDefType = GENERATED_COMP_IDS.get(compId);
3161
+ if (previousCompDefType !== componentDef.type) {
3162
+ // TODO: use `formatRuntimeError` to have an error code and we can later on create an error
3163
+ // guide to explain this further.
3164
+ console.warn(`Component ID generation collision detected. Components '${previousCompDefType.name}' and '${componentDef.type.name}' with selector '${stringifyCSSSelectorList(componentDef
3165
+ .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.`);
3166
+ }
3167
+ }
3168
+ else {
3169
+ GENERATED_COMP_IDS.set(compId, componentDef.type);
3170
+ }
3171
+ }
3172
+ return compId;
3173
+ }
2489
3174
 
2490
3175
  /**
2491
3176
  * Special location which allows easy identification of type. If we have an array which was
@@ -2514,13 +3199,14 @@ const HAS_TRANSPLANTED_VIEWS = 2;
2514
3199
  const NATIVE = 7;
2515
3200
  const VIEW_REFS = 8;
2516
3201
  const MOVED_VIEWS = 9;
3202
+ const DEHYDRATED_VIEWS = 10;
2517
3203
  /**
2518
3204
  * Size of LContainer's header. Represents the index after which all views in the
2519
3205
  * container will be inserted. We need to keep a record of current views so we know
2520
3206
  * which views are already in the DOM (and don't need to be re-added) and so we can
2521
3207
  * remove views from the DOM when they are no longer required.
2522
3208
  */
2523
- const CONTAINER_HEADER_OFFSET = 10;
3209
+ const CONTAINER_HEADER_OFFSET = 11;
2524
3210
  // Note: This hack is necessary so we don't erroneously get a circular dependency
2525
3211
  // failure based on types.
2526
3212
  const unusedValueExportToPlacateAjd$4 = 1;
@@ -2589,7 +3275,7 @@ function isDirectiveHost(tNode) {
2589
3275
  return (tNode.flags & 1 /* TNodeFlags.isDirectiveHost */) === 1 /* TNodeFlags.isDirectiveHost */;
2590
3276
  }
2591
3277
  function isComponentDef(def) {
2592
- return def.template !== null;
3278
+ return !!def.template;
2593
3279
  }
2594
3280
  function isRootView(target) {
2595
3281
  return (target[FLAGS] & 256 /* LViewFlags.IsRoot */) !== 0;
@@ -3046,7 +3732,7 @@ function getBindingsEnabled() {
3046
3732
  * Returns true if currently inside a skip hydration block.
3047
3733
  * @returns boolean
3048
3734
  */
3049
- function isInSkipHydrationBlock() {
3735
+ function isInSkipHydrationBlock$1() {
3050
3736
  return instructionState.skipHydrationRootTNode !== null;
3051
3737
  }
3052
3738
  /**
@@ -3948,246 +4634,46 @@ function hasClassInput(tNode) {
3948
4634
  return (tNode.flags & 8 /* TNodeFlags.hasClassInput */) !== 0;
3949
4635
  }
3950
4636
  /**
3951
- * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
3952
- *
3953
- * ```
3954
- * <div my-dir [style]="exp"></div>
3955
- * ```
3956
- * and
3957
- * ```
3958
- * @Directive({
3959
- * })
3960
- * class MyDirective {
3961
- * @Input()
3962
- * class: string;
3963
- * }
3964
- * ```
3965
- *
3966
- * In the above case it is necessary to write the reconciled styling information into the
3967
- * directive's input.
3968
- *
3969
- * @param tNode
3970
- */
3971
- function hasStyleInput(tNode) {
3972
- return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
3973
- }
3974
-
3975
- function assertTNodeType(tNode, expectedTypes, message) {
3976
- assertDefined(tNode, 'should be called with a TNode');
3977
- if ((tNode.type & expectedTypes) === 0) {
3978
- throwError(message ||
3979
- `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
3980
- }
3981
- }
3982
- function assertPureTNodeType(type) {
3983
- if (!(type === 2 /* TNodeType.Element */ || //
3984
- type === 1 /* TNodeType.Text */ || //
3985
- type === 4 /* TNodeType.Container */ || //
3986
- type === 8 /* TNodeType.ElementContainer */ || //
3987
- type === 32 /* TNodeType.Icu */ || //
3988
- type === 16 /* TNodeType.Projection */ || //
3989
- type === 64 /* TNodeType.Placeholder */)) {
3990
- throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
3991
- }
3992
- }
3993
-
3994
- /**
3995
- * Assigns all attribute values to the provided element via the inferred renderer.
3996
- *
3997
- * This function accepts two forms of attribute entries:
3998
- *
3999
- * default: (key, value):
4000
- * attrs = [key1, value1, key2, value2]
4001
- *
4002
- * namespaced: (NAMESPACE_MARKER, uri, name, value)
4003
- * attrs = [NAMESPACE_MARKER, uri, name, value, NAMESPACE_MARKER, uri, name, value]
4004
- *
4005
- * The `attrs` array can contain a mix of both the default and namespaced entries.
4006
- * The "default" values are set without a marker, but if the function comes across
4007
- * a marker value then it will attempt to set a namespaced value. If the marker is
4008
- * not of a namespaced value then the function will quit and return the index value
4009
- * where it stopped during the iteration of the attrs array.
4010
- *
4011
- * See [AttributeMarker] to understand what the namespace marker value is.
4012
- *
4013
- * Note that this instruction does not support assigning style and class values to
4014
- * an element. See `elementStart` and `elementHostAttrs` to learn how styling values
4015
- * are applied to an element.
4016
- * @param renderer The renderer to be used
4017
- * @param native The element that the attributes will be assigned to
4018
- * @param attrs The attribute array of values that will be assigned to the element
4019
- * @returns the index value that was last accessed in the attributes array
4020
- */
4021
- function setUpAttributes(renderer, native, attrs) {
4022
- let i = 0;
4023
- while (i < attrs.length) {
4024
- const value = attrs[i];
4025
- if (typeof value === 'number') {
4026
- // only namespaces are supported. Other value types (such as style/class
4027
- // entries) are not supported in this function.
4028
- if (value !== 0 /* AttributeMarker.NamespaceURI */) {
4029
- break;
4030
- }
4031
- // we just landed on the marker value ... therefore
4032
- // we should skip to the next entry
4033
- i++;
4034
- const namespaceURI = attrs[i++];
4035
- const attrName = attrs[i++];
4036
- const attrVal = attrs[i++];
4037
- ngDevMode && ngDevMode.rendererSetAttribute++;
4038
- renderer.setAttribute(native, attrName, attrVal, namespaceURI);
4039
- }
4040
- else {
4041
- // attrName is string;
4042
- const attrName = value;
4043
- const attrVal = attrs[++i];
4044
- // Standard attributes
4045
- ngDevMode && ngDevMode.rendererSetAttribute++;
4046
- if (isAnimationProp(attrName)) {
4047
- renderer.setProperty(native, attrName, attrVal);
4048
- }
4049
- else {
4050
- renderer.setAttribute(native, attrName, attrVal);
4051
- }
4052
- i++;
4053
- }
4054
- }
4055
- // another piece of code may iterate over the same attributes array. Therefore
4056
- // it may be helpful to return the exact spot where the attributes array exited
4057
- // whether by running into an unsupported marker or if all the static values were
4058
- // iterated over.
4059
- return i;
4060
- }
4061
- /**
4062
- * Test whether the given value is a marker that indicates that the following
4063
- * attribute values in a `TAttributes` array are only the names of attributes,
4064
- * and not name-value pairs.
4065
- * @param marker The attribute marker to test.
4066
- * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`).
4067
- */
4068
- function isNameOnlyAttributeMarker(marker) {
4069
- return marker === 3 /* AttributeMarker.Bindings */ || marker === 4 /* AttributeMarker.Template */ ||
4070
- marker === 6 /* AttributeMarker.I18n */;
4071
- }
4072
- function isAnimationProp(name) {
4073
- // Perf note: accessing charCodeAt to check for the first character of a string is faster as
4074
- // compared to accessing a character at index 0 (ex. name[0]). The main reason for this is that
4075
- // charCodeAt doesn't allocate memory to return a substring.
4076
- return name.charCodeAt(0) === 64 /* CharCode.AT_SIGN */;
4077
- }
4078
- /**
4079
- * Merges `src` `TAttributes` into `dst` `TAttributes` removing any duplicates in the process.
4080
- *
4081
- * This merge function keeps the order of attrs same.
4082
- *
4083
- * @param dst Location of where the merged `TAttributes` should end up.
4084
- * @param src `TAttributes` which should be appended to `dst`
4085
- */
4086
- function mergeHostAttrs(dst, src) {
4087
- if (src === null || src.length === 0) {
4088
- // do nothing
4089
- }
4090
- else if (dst === null || dst.length === 0) {
4091
- // We have source, but dst is empty, just make a copy.
4092
- dst = src.slice();
4093
- }
4094
- else {
4095
- let srcMarker = -1 /* AttributeMarker.ImplicitAttributes */;
4096
- for (let i = 0; i < src.length; i++) {
4097
- const item = src[i];
4098
- if (typeof item === 'number') {
4099
- srcMarker = item;
4100
- }
4101
- else {
4102
- if (srcMarker === 0 /* AttributeMarker.NamespaceURI */) {
4103
- // Case where we need to consume `key1`, `key2`, `value` items.
4104
- }
4105
- else if (srcMarker === -1 /* AttributeMarker.ImplicitAttributes */ ||
4106
- srcMarker === 2 /* AttributeMarker.Styles */) {
4107
- // Case where we have to consume `key1` and `value` only.
4108
- mergeHostAttribute(dst, srcMarker, item, null, src[++i]);
4109
- }
4110
- else {
4111
- // Case where we have to consume `key1` only.
4112
- mergeHostAttribute(dst, srcMarker, item, null, null);
4113
- }
4114
- }
4115
- }
4116
- }
4117
- return dst;
4118
- }
4119
- /**
4120
- * Append `key`/`value` to existing `TAttributes` taking region marker and duplicates into account.
4637
+ * Returns `true` if the `TNode` has a directive which has `@Input()` for `style` binding.
4121
4638
  *
4122
- * @param dst `TAttributes` to append to.
4123
- * @param marker Region where the `key`/`value` should be added.
4124
- * @param key1 Key to add to `TAttributes`
4125
- * @param key2 Key to add to `TAttributes` (in case of `AttributeMarker.NamespaceURI`)
4126
- * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class.
4639
+ * ```
4640
+ * <div my-dir [style]="exp"></div>
4641
+ * ```
4642
+ * and
4643
+ * ```
4644
+ * @Directive({
4645
+ * })
4646
+ * class MyDirective {
4647
+ * @Input()
4648
+ * class: string;
4649
+ * }
4650
+ * ```
4651
+ *
4652
+ * In the above case it is necessary to write the reconciled styling information into the
4653
+ * directive's input.
4654
+ *
4655
+ * @param tNode
4127
4656
  */
4128
- function mergeHostAttribute(dst, marker, key1, key2, value) {
4129
- let i = 0;
4130
- // Assume that new markers will be inserted at the end.
4131
- let markerInsertPosition = dst.length;
4132
- // scan until correct type.
4133
- if (marker === -1 /* AttributeMarker.ImplicitAttributes */) {
4134
- markerInsertPosition = -1;
4135
- }
4136
- else {
4137
- while (i < dst.length) {
4138
- const dstValue = dst[i++];
4139
- if (typeof dstValue === 'number') {
4140
- if (dstValue === marker) {
4141
- markerInsertPosition = -1;
4142
- break;
4143
- }
4144
- else if (dstValue > marker) {
4145
- // We need to save this as we want the markers to be inserted in specific order.
4146
- markerInsertPosition = i - 1;
4147
- break;
4148
- }
4149
- }
4150
- }
4151
- }
4152
- // search until you find place of insertion
4153
- while (i < dst.length) {
4154
- const item = dst[i];
4155
- if (typeof item === 'number') {
4156
- // since `i` started as the index after the marker, we did not find it if we are at the next
4157
- // marker
4158
- break;
4159
- }
4160
- else if (item === key1) {
4161
- // We already have same token
4162
- if (key2 === null) {
4163
- if (value !== null) {
4164
- dst[i + 1] = value;
4165
- }
4166
- return;
4167
- }
4168
- else if (key2 === dst[i + 1]) {
4169
- dst[i + 2] = value;
4170
- return;
4171
- }
4172
- }
4173
- // Increment counter.
4174
- i++;
4175
- if (key2 !== null)
4176
- i++;
4177
- if (value !== null)
4178
- i++;
4179
- }
4180
- // insert at location.
4181
- if (markerInsertPosition !== -1) {
4182
- dst.splice(markerInsertPosition, 0, marker);
4183
- i = markerInsertPosition + 1;
4184
- }
4185
- dst.splice(i++, 0, key1);
4186
- if (key2 !== null) {
4187
- dst.splice(i++, 0, key2);
4657
+ function hasStyleInput(tNode) {
4658
+ return (tNode.flags & 16 /* TNodeFlags.hasStyleInput */) !== 0;
4659
+ }
4660
+
4661
+ function assertTNodeType(tNode, expectedTypes, message) {
4662
+ assertDefined(tNode, 'should be called with a TNode');
4663
+ if ((tNode.type & expectedTypes) === 0) {
4664
+ throwError(message ||
4665
+ `Expected [${toTNodeTypeAsString(expectedTypes)}] but got ${toTNodeTypeAsString(tNode.type)}.`);
4188
4666
  }
4189
- if (value !== null) {
4190
- dst.splice(i++, 0, value);
4667
+ }
4668
+ function assertPureTNodeType(type) {
4669
+ if (!(type === 2 /* TNodeType.Element */ || //
4670
+ type === 1 /* TNodeType.Text */ || //
4671
+ type === 4 /* TNodeType.Container */ || //
4672
+ type === 8 /* TNodeType.ElementContainer */ || //
4673
+ type === 32 /* TNodeType.Icu */ || //
4674
+ type === 16 /* TNodeType.Projection */ || //
4675
+ type === 64 /* TNodeType.Placeholder */)) {
4676
+ throwError(`Expected TNodeType to have only a single type selected, but got ${toTNodeTypeAsString(type)}.`);
4191
4677
  }
4192
4678
  }
4193
4679
 
@@ -8605,35 +9091,41 @@ function forEachSingleProvider(providers, fn) {
8605
9091
  }
8606
9092
 
8607
9093
  /**
8608
- * A [DI token](guide/glossary#di-token "DI token definition") representing a unique string ID, used
9094
+ * A [DI token](guide/glossary#di-token "DI token definition") representing a string ID, used
8609
9095
  * primarily for prefixing application attributes and CSS styles when
8610
9096
  * {@link ViewEncapsulation#Emulated ViewEncapsulation.Emulated} is being used.
8611
9097
  *
8612
- * BY default, the value is randomly generated and assigned to the application by Angular.
8613
- * To provide a custom ID value, use a DI provider <!-- TODO: provider --> to configure
8614
- * the root {@link Injector} that uses this token.
9098
+ * The token is needed in cases when multiple applications are bootstrapped on a page
9099
+ * (for example, using `bootstrapApplication` calls). In this case, ensure that those applications
9100
+ * have different `APP_ID` value setup. For example:
9101
+ *
9102
+ * ```
9103
+ * bootstrapApplication(ComponentA, {
9104
+ * providers: [
9105
+ * { provide: APP_ID, useValue: 'app-a' },
9106
+ * // ... other providers ...
9107
+ * ]
9108
+ * });
9109
+ *
9110
+ * bootstrapApplication(ComponentB, {
9111
+ * providers: [
9112
+ * { provide: APP_ID, useValue: 'app-b' },
9113
+ * // ... other providers ...
9114
+ * ]
9115
+ * });
9116
+ * ```
9117
+ *
9118
+ * By default, when there is only one application bootstrapped, you don't need to provide the
9119
+ * `APP_ID` token (the `ng` will be used as an app ID).
8615
9120
  *
8616
9121
  * @publicApi
8617
9122
  */
8618
9123
  const APP_ID = new InjectionToken('AppId', {
8619
9124
  providedIn: 'root',
8620
- factory: _appIdRandomProviderFactory,
9125
+ factory: () => DEFAULT_APP_ID,
8621
9126
  });
8622
- function _appIdRandomProviderFactory() {
8623
- return `${_randomChar()}${_randomChar()}${_randomChar()}`;
8624
- }
8625
- /**
8626
- * Providers that generate a random `APP_ID_TOKEN`.
8627
- * @publicApi
8628
- */
8629
- const APP_ID_RANDOM_PROVIDER = {
8630
- provide: APP_ID,
8631
- useFactory: _appIdRandomProviderFactory,
8632
- deps: [],
8633
- };
8634
- function _randomChar() {
8635
- return String.fromCharCode(97 + Math.floor(Math.random() * 25));
8636
- }
9127
+ /** Default value of the `APP_ID` token. */
9128
+ const DEFAULT_APP_ID = 'ng';
8637
9129
  /**
8638
9130
  * A function that is executed when a platform is initialized.
8639
9131
  * @publicApi
@@ -8804,8 +9296,15 @@ function retrieveTransferredState(doc, appId) {
8804
9296
  return initialState;
8805
9297
  }
8806
9298
 
8807
- /* Represents a key in NghDom that holds information about <ng-container>s. */
9299
+ /**
9300
+ * Keys within serialized view data structure to represent various
9301
+ * parts. See the `SerializedView` interface below for additional information.
9302
+ */
8808
9303
  const ELEMENT_CONTAINERS = 'e';
9304
+ const TEMPLATES = 't';
9305
+ const CONTAINERS = 'c';
9306
+ const NUM_ROOT_NODES = 'r';
9307
+ const TEMPLATE_ID = 'i'; // as it's also an "id"
8809
9308
 
8810
9309
  /**
8811
9310
  * The name of the key used in the TransferState collection,
@@ -8868,7 +9367,7 @@ function retrieveHydrationInfoImpl(rNode, injector) {
8868
9367
  return dehydratedView;
8869
9368
  }
8870
9369
  /**
8871
- * Sets the implementation for the `retrieveNghInfo` function.
9370
+ * Sets the implementation for the `retrieveHydrationInfo` function.
8872
9371
  */
8873
9372
  function enableRetrieveHydrationInfoImpl() {
8874
9373
  _retrieveHydrationInfoImpl = retrieveHydrationInfoImpl;
@@ -8900,6 +9399,47 @@ function getComponentLViewForHydration(viewRef) {
8900
9399
  }
8901
9400
  return lView;
8902
9401
  }
9402
+ function getTextNodeContent(node) {
9403
+ var _a;
9404
+ return (_a = node.textContent) === null || _a === void 0 ? void 0 : _a.replace(/\s/gm, '');
9405
+ }
9406
+ /**
9407
+ * Restores text nodes and separators into the DOM that were lost during SSR
9408
+ * serialization. The hydration process replaces empty text nodes and text
9409
+ * nodes that are immediately adjacent to other text nodes with comment nodes
9410
+ * that this method filters on to restore those missing nodes that the
9411
+ * hydration process is expecting to be present.
9412
+ *
9413
+ * @param node The app's root HTML Element
9414
+ */
9415
+ function processTextNodeMarkersBeforeHydration(node) {
9416
+ const doc = getDocument();
9417
+ const commentNodesIterator = doc.createNodeIterator(node, NodeFilter.SHOW_COMMENT, {
9418
+ acceptNode(node) {
9419
+ const content = getTextNodeContent(node);
9420
+ const isTextNodeMarker = content === "ngetn" /* TextNodeMarker.EmptyNode */ || content === "ngtns" /* TextNodeMarker.Separator */;
9421
+ return isTextNodeMarker ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
9422
+ }
9423
+ });
9424
+ let currentNode;
9425
+ // We cannot modify the DOM while using the commentIterator,
9426
+ // because it throws off the iterator state.
9427
+ // So we collect all marker nodes first and then follow up with
9428
+ // applying the changes to the DOM: either inserting an empty node
9429
+ // or just removing the marker if it was used as a separator.
9430
+ const nodes = [];
9431
+ while (currentNode = commentNodesIterator.nextNode()) {
9432
+ nodes.push(currentNode);
9433
+ }
9434
+ for (const node of nodes) {
9435
+ if (node.textContent === "ngetn" /* TextNodeMarker.EmptyNode */) {
9436
+ node.replaceWith(doc.createTextNode(''));
9437
+ }
9438
+ else {
9439
+ node.remove();
9440
+ }
9441
+ }
9442
+ }
8903
9443
  /**
8904
9444
  * Marks a node as "claimed" by hydration process.
8905
9445
  * This is needed to make assessments in tests whether
@@ -8912,837 +9452,440 @@ function markRNodeAsClaimedByHydration(node, checkIfAlreadyClaimed = true) {
8912
9452
  }
8913
9453
  if (checkIfAlreadyClaimed && isRNodeClaimedForHydration(node)) {
8914
9454
  throw new Error('Trying to claim a node, which was claimed already.');
8915
- }
8916
- node.__claimed = true;
8917
- ngDevMode.hydratedNodes++;
8918
- }
8919
- function isRNodeClaimedForHydration(node) {
8920
- return !!node.__claimed;
8921
- }
8922
- function storeNgContainerInfo(hydrationInfo, index, firstChild) {
8923
- var _a;
8924
- (_a = hydrationInfo.ngContainers) !== null && _a !== void 0 ? _a : (hydrationInfo.ngContainers = {});
8925
- hydrationInfo.ngContainers[index] = { firstChild };
8926
- }
8927
- function getNgContainerSize(hydrationInfo, index) {
8928
- var _a, _b;
8929
- return (_b = (_a = hydrationInfo.data[ELEMENT_CONTAINERS]) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : null;
8930
- }
8931
-
8932
- /**
8933
- * Represents a component created by a `ComponentFactory`.
8934
- * Provides access to the component instance and related objects,
8935
- * and provides the means of destroying the instance.
8936
- *
8937
- * @publicApi
8938
- */
8939
- class ComponentRef$1 {
8940
- }
8941
- /**
8942
- * Base class for a factory that can create a component dynamically.
8943
- * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
8944
- * Use the resulting `ComponentFactory.create()` method to create a component of that type.
8945
- *
8946
- * @see [Dynamic Components](guide/dynamic-component-loader)
8947
- *
8948
- * @publicApi
8949
- *
8950
- * @deprecated Angular no longer requires Component factories. Please use other APIs where
8951
- * Component class can be used directly.
8952
- */
8953
- class ComponentFactory$1 {
8954
- }
8955
-
8956
- function noComponentFactoryError(component) {
8957
- const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
8958
- error[ERROR_COMPONENT] = component;
8959
- return error;
8960
- }
8961
- const ERROR_COMPONENT = 'ngComponent';
8962
- function getComponent$1(error) {
8963
- return error[ERROR_COMPONENT];
8964
- }
8965
- class _NullComponentFactoryResolver {
8966
- resolveComponentFactory(component) {
8967
- throw noComponentFactoryError(component);
8968
- }
8969
- }
8970
- /**
8971
- * A simple registry that maps `Components` to generated `ComponentFactory` classes
8972
- * that can be used to create instances of components.
8973
- * Use to obtain the factory for a given component type,
8974
- * then use the factory's `create()` method to create a component of that type.
8975
- *
8976
- * Note: since v13, dynamic component creation via
8977
- * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
8978
- * does **not** require resolving component factory: component class can be used directly.
8979
- *
8980
- * @publicApi
8981
- *
8982
- * @deprecated Angular no longer requires Component factories. Please use other APIs where
8983
- * Component class can be used directly.
8984
- */
8985
- class ComponentFactoryResolver$1 {
8986
- }
8987
- ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
8988
-
8989
- /**
8990
- * Creates an ElementRef from the most recent node.
8991
- *
8992
- * @returns The ElementRef instance to use
8993
- */
8994
- function injectElementRef() {
8995
- return createElementRef(getCurrentTNode(), getLView());
8996
- }
8997
- /**
8998
- * Creates an ElementRef given a node.
8999
- *
9000
- * @param tNode The node for which you'd like an ElementRef
9001
- * @param lView The view to which the node belongs
9002
- * @returns The ElementRef instance to use
9003
- */
9004
- function createElementRef(tNode, lView) {
9005
- return new ElementRef(getNativeByTNode(tNode, lView));
9006
- }
9007
- /**
9008
- * A wrapper around a native element inside of a View.
9009
- *
9010
- * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
9011
- * element.
9012
- *
9013
- * @security Permitting direct access to the DOM can make your application more vulnerable to
9014
- * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
9015
- * [Security Guide](https://g.co/ng/security).
9016
- *
9017
- * @publicApi
9018
- */
9019
- // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
9020
- // i.e. users have to ask for what they need. With that, we can build better analysis tools
9021
- // and could do better codegen in the future.
9022
- class ElementRef {
9023
- constructor(nativeElement) {
9024
- this.nativeElement = nativeElement;
9025
- }
9026
- }
9027
- /**
9028
- * @internal
9029
- * @nocollapse
9030
- */
9031
- ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
9032
- /**
9033
- * Unwraps `ElementRef` and return the `nativeElement`.
9034
- *
9035
- * @param value value to unwrap
9036
- * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
9037
- */
9038
- function unwrapElementRef(value) {
9039
- return value instanceof ElementRef ? value.nativeElement : value;
9455
+ }
9456
+ node.__claimed = true;
9457
+ ngDevMode.hydratedNodes++;
9040
9458
  }
9041
-
9042
- /**
9043
- * Creates and initializes a custom renderer that implements the `Renderer2` base class.
9044
- *
9045
- * @publicApi
9046
- */
9047
- class RendererFactory2 {
9459
+ function isRNodeClaimedForHydration(node) {
9460
+ return !!node.__claimed;
9461
+ }
9462
+ function setSegmentHead(hydrationInfo, index, node) {
9463
+ var _a;
9464
+ (_a = hydrationInfo.segmentHeads) !== null && _a !== void 0 ? _a : (hydrationInfo.segmentHeads = {});
9465
+ hydrationInfo.segmentHeads[index] = node;
9466
+ }
9467
+ function getSegmentHead(hydrationInfo, index) {
9468
+ var _a, _b;
9469
+ return (_b = (_a = hydrationInfo.segmentHeads) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : null;
9048
9470
  }
9049
9471
  /**
9050
- * Extend this base class to implement custom rendering. By default, Angular
9051
- * renders a template into DOM. You can use custom rendering to intercept
9052
- * rendering calls, or to render to something other than DOM.
9053
- *
9054
- * Create your custom renderer using `RendererFactory2`.
9055
- *
9056
- * Use a custom renderer to bypass Angular's templating and
9057
- * make custom UI changes that can't be expressed declaratively.
9058
- * For example if you need to set a property or an attribute whose name is
9059
- * not statically known, use the `setProperty()` or
9060
- * `setAttribute()` method.
9061
- *
9062
- * @publicApi
9472
+ * Returns the size of an <ng-container>, using either the information
9473
+ * serialized in `ELEMENT_CONTAINERS` (element container size) or by
9474
+ * computing the sum of root nodes in all dehydrated views in a given
9475
+ * container (in case this `<ng-container>` was also used as a view
9476
+ * container host node, e.g. <ng-container *ngIf>).
9063
9477
  */
9064
- class Renderer2 {
9478
+ function getNgContainerSize(hydrationInfo, index) {
9479
+ var _a, _b, _c;
9480
+ const data = hydrationInfo.data;
9481
+ let size = (_b = (_a = data[ELEMENT_CONTAINERS]) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : null;
9482
+ // If there is no serialized information available in the `ELEMENT_CONTAINERS` slot,
9483
+ // check if we have info about view containers at this location (e.g.
9484
+ // `<ng-container *ngIf>`) and use container size as a number of root nodes in this
9485
+ // element container.
9486
+ if (size === null && ((_c = data[CONTAINERS]) === null || _c === void 0 ? void 0 : _c[index])) {
9487
+ size = calcSerializedContainerSize(hydrationInfo, index);
9488
+ }
9489
+ return size;
9490
+ }
9491
+ function getSerializedContainerViews(hydrationInfo, index) {
9492
+ var _a, _b;
9493
+ return (_b = (_a = hydrationInfo.data[CONTAINERS]) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : null;
9065
9494
  }
9066
9495
  /**
9067
- * @internal
9068
- * @nocollapse
9496
+ * Computes the size of a serialized container (the number of root nodes)
9497
+ * by calculating the sum of root nodes in all dehydrated views in this container.
9069
9498
  */
9070
- Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
9071
- /** Injects a Renderer2 for the current component. */
9072
- function injectRenderer2() {
9073
- // We need the Renderer to be based on the component that it's being injected into, however since
9074
- // DI happens before we've entered its view, `getLView` will return the parent view instead.
9075
- const lView = getLView();
9076
- const tNode = getCurrentTNode();
9077
- const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
9078
- return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
9499
+ function calcSerializedContainerSize(hydrationInfo, index) {
9500
+ var _a;
9501
+ const views = (_a = getSerializedContainerViews(hydrationInfo, index)) !== null && _a !== void 0 ? _a : [];
9502
+ let numNodes = 0;
9503
+ for (let view of views) {
9504
+ numNodes += view[NUM_ROOT_NODES];
9505
+ }
9506
+ return numNodes;
9079
9507
  }
9080
9508
 
9081
9509
  /**
9082
- * Sanitizer is used by the views to sanitize potentially dangerous values.
9510
+ * Represents a component created by a `ComponentFactory`.
9511
+ * Provides access to the component instance and related objects,
9512
+ * and provides the means of destroying the instance.
9083
9513
  *
9084
9514
  * @publicApi
9085
9515
  */
9086
- class Sanitizer {
9516
+ class ComponentRef$1 {
9087
9517
  }
9088
- /** @nocollapse */
9089
- Sanitizer.ɵprov = ɵɵdefineInjectable({
9090
- token: Sanitizer,
9091
- providedIn: 'root',
9092
- factory: () => null,
9093
- });
9094
-
9095
9518
  /**
9096
- * @description Represents the version of Angular
9519
+ * Base class for a factory that can create a component dynamically.
9520
+ * Instantiate a factory for a given type of component with `resolveComponentFactory()`.
9521
+ * Use the resulting `ComponentFactory.create()` method to create a component of that type.
9522
+ *
9523
+ * @see [Dynamic Components](guide/dynamic-component-loader)
9097
9524
  *
9098
9525
  * @publicApi
9526
+ *
9527
+ * @deprecated Angular no longer requires Component factories. Please use other APIs where
9528
+ * Component class can be used directly.
9099
9529
  */
9100
- class Version {
9101
- constructor(full) {
9102
- this.full = full;
9103
- this.major = full.split('.')[0];
9104
- this.minor = full.split('.')[1];
9105
- this.patch = full.split('.').slice(2).join('.');
9106
- }
9530
+ class ComponentFactory$1 {
9107
9531
  }
9108
- /**
9109
- * @publicApi
9110
- */
9111
- const VERSION = new Version('16.0.0-next.2');
9112
-
9113
- // This default value is when checking the hierarchy for a token.
9114
- //
9115
- // It means both:
9116
- // - the token is not provided by the current injector,
9117
- // - only the element injectors should be checked (ie do not check module injectors
9118
- //
9119
- // mod1
9120
- // /
9121
- // el1 mod2
9122
- // \ /
9123
- // el2
9124
- //
9125
- // When requesting el2.injector.get(token), we should check in the following order and return the
9126
- // first found value:
9127
- // - el2.injector.get(token, default)
9128
- // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
9129
- // - mod2.injector.get(token, default)
9130
- const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
9131
9532
 
9132
- const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
9133
- function wrappedError(message, originalError) {
9134
- const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
9135
- const error = Error(msg);
9136
- error[ERROR_ORIGINAL_ERROR] = originalError;
9533
+ function noComponentFactoryError(component) {
9534
+ const error = Error(`No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`);
9535
+ error[ERROR_COMPONENT] = component;
9137
9536
  return error;
9138
9537
  }
9139
- function getOriginalError(error) {
9140
- return error[ERROR_ORIGINAL_ERROR];
9538
+ const ERROR_COMPONENT = 'ngComponent';
9539
+ function getComponent$1(error) {
9540
+ return error[ERROR_COMPONENT];
9541
+ }
9542
+ class _NullComponentFactoryResolver {
9543
+ resolveComponentFactory(component) {
9544
+ throw noComponentFactoryError(component);
9545
+ }
9141
9546
  }
9142
-
9143
9547
  /**
9144
- * Provides a hook for centralized exception handling.
9145
- *
9146
- * The default implementation of `ErrorHandler` prints error messages to the `console`. To
9147
- * intercept error handling, write a custom exception handler that replaces this default as
9148
- * appropriate for your app.
9149
- *
9150
- * @usageNotes
9151
- * ### Example
9152
- *
9153
- * ```
9154
- * class MyErrorHandler implements ErrorHandler {
9155
- * handleError(error) {
9156
- * // do something with the exception
9157
- * }
9158
- * }
9548
+ * A simple registry that maps `Components` to generated `ComponentFactory` classes
9549
+ * that can be used to create instances of components.
9550
+ * Use to obtain the factory for a given component type,
9551
+ * then use the factory's `create()` method to create a component of that type.
9159
9552
  *
9160
- * @NgModule({
9161
- * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
9162
- * })
9163
- * class MyModule {}
9164
- * ```
9553
+ * Note: since v13, dynamic component creation via
9554
+ * [`ViewContainerRef.createComponent`](api/core/ViewContainerRef#createComponent)
9555
+ * does **not** require resolving component factory: component class can be used directly.
9165
9556
  *
9166
9557
  * @publicApi
9558
+ *
9559
+ * @deprecated Angular no longer requires Component factories. Please use other APIs where
9560
+ * Component class can be used directly.
9167
9561
  */
9168
- class ErrorHandler {
9169
- constructor() {
9170
- /**
9171
- * @internal
9172
- */
9173
- this._console = console;
9174
- }
9175
- handleError(error) {
9176
- const originalError = this._findOriginalError(error);
9177
- this._console.error('ERROR', error);
9178
- if (originalError) {
9179
- this._console.error('ORIGINAL ERROR', originalError);
9180
- }
9181
- }
9182
- /** @internal */
9183
- _findOriginalError(error) {
9184
- let e = error && getOriginalError(error);
9185
- while (e && getOriginalError(e)) {
9186
- e = getOriginalError(e);
9187
- }
9188
- return e || null;
9189
- }
9562
+ class ComponentFactoryResolver$1 {
9190
9563
  }
9564
+ ComponentFactoryResolver$1.NULL = ( /* @__PURE__ */new _NullComponentFactoryResolver());
9191
9565
 
9192
- const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
9193
- /**
9194
- * Internal token that specifies whether hydration is enabled.
9195
- */
9196
- const IS_HYDRATION_FEATURE_ENABLED = new InjectionToken(NG_DEV_MODE ? 'IS_HYDRATION_FEATURE_ENABLED' : '');
9197
- // By default (in client rendering mode), we remove all the contents
9198
- // of the host element and render an application after that.
9199
- const PRESERVE_HOST_CONTENT_DEFAULT = false;
9200
9566
  /**
9201
- * Internal token that indicates whether host element content should be
9202
- * retained during the bootstrap.
9567
+ * Creates an ElementRef from the most recent node.
9568
+ *
9569
+ * @returns The ElementRef instance to use
9203
9570
  */
9204
- const PRESERVE_HOST_CONTENT = new InjectionToken(NG_DEV_MODE ? 'PRESERVE_HOST_CONTENT' : '', {
9205
- providedIn: 'root',
9206
- factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
9207
- });
9208
-
9209
- function normalizeDebugBindingName(name) {
9210
- // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
9211
- name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
9212
- return `ng-reflect-${name}`;
9213
- }
9214
- const CAMEL_CASE_REGEXP = /([A-Z])/g;
9215
- function camelCaseToDashCase(input) {
9216
- return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
9217
- }
9218
- function normalizeDebugBindingValue(value) {
9219
- try {
9220
- // Limit the size of the value as otherwise the DOM just gets polluted.
9221
- return value != null ? value.toString().slice(0, 30) : value;
9222
- }
9223
- catch (e) {
9224
- return '[ERROR] Exception while trying to serialize the value';
9225
- }
9226
- }
9227
-
9228
- /** Verifies that a given type is a Standalone Component. */
9229
- function assertStandaloneComponentType(type) {
9230
- assertComponentDef(type);
9231
- const componentDef = getComponentDef$1(type);
9232
- if (!componentDef.standalone) {
9233
- throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
9234
- `but Angular expects to have a standalone component here. ` +
9235
- `Please make sure the ${stringifyForError(type)} component has ` +
9236
- `the \`standalone: true\` flag in the decorator.`);
9237
- }
9238
- }
9239
- /** Verifies whether a given type is a component */
9240
- function assertComponentDef(type) {
9241
- if (!getComponentDef$1(type)) {
9242
- throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
9243
- `make sure it has the \`@Component\` decorator.`);
9244
- }
9245
- }
9246
- /** Called when there are multiple component selectors that match a given node */
9247
- function throwMultipleComponentError(tNode, first, second) {
9248
- throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
9249
- `${stringifyForError(first)} and ` +
9250
- `${stringifyForError(second)}`);
9251
- }
9252
- /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
9253
- function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
9254
- const field = propName ? ` for '${propName}'` : '';
9255
- let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
9256
- if (creationMode) {
9257
- msg +=
9258
- ` It seems like the view has been created after its parent and its children have been dirty checked.` +
9259
- ` Has it been created in a change detection hook?`;
9260
- }
9261
- throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
9571
+ function injectElementRef() {
9572
+ return createElementRef(getCurrentTNode(), getLView());
9262
9573
  }
9263
- function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
9264
- const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
9265
- let oldValue = prefix, newValue = prefix;
9266
- for (let i = 0; i < chunks.length; i++) {
9267
- const slotIdx = rootIndex + i;
9268
- oldValue += `${lView[slotIdx]}${chunks[i]}`;
9269
- newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
9270
- }
9271
- return { propName, oldValue, newValue };
9574
+ /**
9575
+ * Creates an ElementRef given a node.
9576
+ *
9577
+ * @param tNode The node for which you'd like an ElementRef
9578
+ * @param lView The view to which the node belongs
9579
+ * @returns The ElementRef instance to use
9580
+ */
9581
+ function createElementRef(tNode, lView) {
9582
+ return new ElementRef(getNativeByTNode(tNode, lView));
9272
9583
  }
9273
9584
  /**
9274
- * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
9275
- * - property name (for property bindings or interpolations)
9276
- * - old and new values, enriched using information from metadata
9585
+ * A wrapper around a native element inside of a View.
9277
9586
  *
9278
- * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
9279
- * function description.
9587
+ * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
9588
+ * element.
9589
+ *
9590
+ * @security Permitting direct access to the DOM can make your application more vulnerable to
9591
+ * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
9592
+ * [Security Guide](https://g.co/ng/security).
9593
+ *
9594
+ * @publicApi
9280
9595
  */
9281
- function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
9282
- const tData = lView[TVIEW].data;
9283
- const metadata = tData[bindingIndex];
9284
- if (typeof metadata === 'string') {
9285
- // metadata for property interpolation
9286
- if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
9287
- return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
9288
- }
9289
- // metadata for property binding
9290
- return { propName: metadata, oldValue, newValue };
9291
- }
9292
- // metadata is not available for this expression, check if this expression is a part of the
9293
- // property interpolation by going from the current binding index left and look for a string that
9294
- // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
9295
- // [..., 'id�Prefix � and � suffix', null, null, null, ...]
9296
- if (metadata === null) {
9297
- let idx = bindingIndex - 1;
9298
- while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
9299
- idx--;
9300
- }
9301
- const meta = tData[idx];
9302
- if (typeof meta === 'string') {
9303
- const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
9304
- // first interpolation delimiter separates property name from interpolation parts (in case of
9305
- // property interpolations), so we subtract one from total number of found delimiters
9306
- if (matches && (matches.length - 1) > bindingIndex - idx) {
9307
- return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
9308
- }
9309
- }
9596
+ // Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
9597
+ // i.e. users have to ask for what they need. With that, we can build better analysis tools
9598
+ // and could do better codegen in the future.
9599
+ class ElementRef {
9600
+ constructor(nativeElement) {
9601
+ this.nativeElement = nativeElement;
9310
9602
  }
9311
- return { propName: undefined, oldValue, newValue };
9312
9603
  }
9313
-
9314
9604
  /**
9315
- * Returns an index of `classToSearch` in `className` taking token boundaries into account.
9316
- *
9317
- * `classIndexOf('AB A', 'A', 0)` will be 3 (not 0 since `AB!==A`)
9605
+ * @internal
9606
+ * @nocollapse
9607
+ */
9608
+ ElementRef.__NG_ELEMENT_ID__ = injectElementRef;
9609
+ /**
9610
+ * Unwraps `ElementRef` and return the `nativeElement`.
9318
9611
  *
9319
- * @param className A string containing classes (whitespace separated)
9320
- * @param classToSearch A class name to locate
9321
- * @param startingIndex Starting location of search
9322
- * @returns an index of the located class (or -1 if not found)
9612
+ * @param value value to unwrap
9613
+ * @returns `nativeElement` if `ElementRef` otherwise returns value as is.
9323
9614
  */
9324
- function classIndexOf(className, classToSearch, startingIndex) {
9325
- ngDevMode && assertNotEqual(classToSearch, '', 'can not look for "" string.');
9326
- let end = className.length;
9327
- while (true) {
9328
- const foundIndex = className.indexOf(classToSearch, startingIndex);
9329
- if (foundIndex === -1)
9330
- return foundIndex;
9331
- if (foundIndex === 0 || className.charCodeAt(foundIndex - 1) <= 32 /* CharCode.SPACE */) {
9332
- // Ensure that it has leading whitespace
9333
- const length = classToSearch.length;
9334
- if (foundIndex + length === end ||
9335
- className.charCodeAt(foundIndex + length) <= 32 /* CharCode.SPACE */) {
9336
- // Ensure that it has trailing whitespace
9337
- return foundIndex;
9338
- }
9339
- }
9340
- // False positive, keep searching from where we left off.
9341
- startingIndex = foundIndex + 1;
9342
- }
9615
+ function unwrapElementRef(value) {
9616
+ return value instanceof ElementRef ? value.nativeElement : value;
9343
9617
  }
9344
9618
 
9345
- const NG_TEMPLATE_SELECTOR = 'ng-template';
9346
9619
  /**
9347
- * Search the `TAttributes` to see if it contains `cssClassToMatch` (case insensitive)
9620
+ * Creates and initializes a custom renderer that implements the `Renderer2` base class.
9348
9621
  *
9349
- * @param attrs `TAttributes` to search through.
9350
- * @param cssClassToMatch class to match (lowercase)
9351
- * @param isProjectionMode Whether or not class matching should look into the attribute `class` in
9352
- * addition to the `AttributeMarker.Classes`.
9622
+ * @publicApi
9353
9623
  */
9354
- function isCssClassMatching(attrs, cssClassToMatch, isProjectionMode) {
9355
- // TODO(misko): The fact that this function needs to know about `isProjectionMode` seems suspect.
9356
- // It is strange to me that sometimes the class information comes in form of `class` attribute
9357
- // and sometimes in form of `AttributeMarker.Classes`. Some investigation is needed to determine
9358
- // if that is the right behavior.
9359
- ngDevMode &&
9360
- assertEqual(cssClassToMatch, cssClassToMatch.toLowerCase(), 'Class name expected to be lowercase.');
9361
- let i = 0;
9362
- while (i < attrs.length) {
9363
- let item = attrs[i++];
9364
- if (isProjectionMode && item === 'class') {
9365
- item = attrs[i];
9366
- if (classIndexOf(item.toLowerCase(), cssClassToMatch, 0) !== -1) {
9367
- return true;
9368
- }
9369
- }
9370
- else if (item === 1 /* AttributeMarker.Classes */) {
9371
- // We found the classes section. Start searching for the class.
9372
- while (i < attrs.length && typeof (item = attrs[i++]) == 'string') {
9373
- // while we have strings
9374
- if (item.toLowerCase() === cssClassToMatch)
9375
- return true;
9376
- }
9377
- return false;
9378
- }
9379
- }
9380
- return false;
9624
+ class RendererFactory2 {
9381
9625
  }
9382
9626
  /**
9383
- * Checks whether the `tNode` represents an inline template (e.g. `*ngFor`).
9627
+ * Extend this base class to implement custom rendering. By default, Angular
9628
+ * renders a template into DOM. You can use custom rendering to intercept
9629
+ * rendering calls, or to render to something other than DOM.
9384
9630
  *
9385
- * @param tNode current TNode
9631
+ * Create your custom renderer using `RendererFactory2`.
9632
+ *
9633
+ * Use a custom renderer to bypass Angular's templating and
9634
+ * make custom UI changes that can't be expressed declaratively.
9635
+ * For example if you need to set a property or an attribute whose name is
9636
+ * not statically known, use the `setProperty()` or
9637
+ * `setAttribute()` method.
9638
+ *
9639
+ * @publicApi
9386
9640
  */
9387
- function isInlineTemplate(tNode) {
9388
- return tNode.type === 4 /* TNodeType.Container */ && tNode.value !== NG_TEMPLATE_SELECTOR;
9641
+ class Renderer2 {
9389
9642
  }
9390
9643
  /**
9391
- * Function that checks whether a given tNode matches tag-based selector and has a valid type.
9392
- *
9393
- * Matching can be performed in 2 modes: projection mode (when we project nodes) and regular
9394
- * directive matching mode:
9395
- * - in the "directive matching" mode we do _not_ take TContainer's tagName into account if it is
9396
- * different from NG_TEMPLATE_SELECTOR (value different from NG_TEMPLATE_SELECTOR indicates that a
9397
- * tag name was extracted from * syntax so we would match the same directive twice);
9398
- * - in the "projection" mode, we use a tag name potentially extracted from the * syntax processing
9399
- * (applicable to TNodeType.Container only).
9644
+ * @internal
9645
+ * @nocollapse
9400
9646
  */
9401
- function hasTagAndTypeMatch(tNode, currentSelector, isProjectionMode) {
9402
- const tagNameToCompare = tNode.type === 4 /* TNodeType.Container */ && !isProjectionMode ? NG_TEMPLATE_SELECTOR : tNode.value;
9403
- return currentSelector === tagNameToCompare;
9647
+ Renderer2.__NG_ELEMENT_ID__ = () => injectRenderer2();
9648
+ /** Injects a Renderer2 for the current component. */
9649
+ function injectRenderer2() {
9650
+ // We need the Renderer to be based on the component that it's being injected into, however since
9651
+ // DI happens before we've entered its view, `getLView` will return the parent view instead.
9652
+ const lView = getLView();
9653
+ const tNode = getCurrentTNode();
9654
+ const nodeAtIndex = getComponentLViewByIndex(tNode.index, lView);
9655
+ return (isLView(nodeAtIndex) ? nodeAtIndex : lView)[RENDERER];
9404
9656
  }
9657
+
9405
9658
  /**
9406
- * A utility function to match an Ivy node static data against a simple CSS selector
9659
+ * Sanitizer is used by the views to sanitize potentially dangerous values.
9407
9660
  *
9408
- * @param node static data of the node to match
9409
- * @param selector The selector to try matching against the node.
9410
- * @param isProjectionMode if `true` we are matching for content projection, otherwise we are doing
9411
- * directive matching.
9412
- * @returns true if node matches the selector.
9661
+ * @publicApi
9413
9662
  */
9414
- function isNodeMatchingSelector(tNode, selector, isProjectionMode) {
9415
- ngDevMode && assertDefined(selector[0], 'Selector should have a tag name');
9416
- let mode = 4 /* SelectorFlags.ELEMENT */;
9417
- const nodeAttrs = tNode.attrs || [];
9418
- // Find the index of first attribute that has no value, only a name.
9419
- const nameOnlyMarkerIdx = getNameOnlyMarkerIndex(nodeAttrs);
9420
- // When processing ":not" selectors, we skip to the next ":not" if the
9421
- // current one doesn't match
9422
- let skipToNextSelector = false;
9423
- for (let i = 0; i < selector.length; i++) {
9424
- const current = selector[i];
9425
- if (typeof current === 'number') {
9426
- // If we finish processing a :not selector and it hasn't failed, return false
9427
- if (!skipToNextSelector && !isPositive(mode) && !isPositive(current)) {
9428
- return false;
9429
- }
9430
- // If we are skipping to the next :not() and this mode flag is positive,
9431
- // it's a part of the current :not() selector, and we should keep skipping
9432
- if (skipToNextSelector && isPositive(current))
9433
- continue;
9434
- skipToNextSelector = false;
9435
- mode = current | (mode & 1 /* SelectorFlags.NOT */);
9436
- continue;
9437
- }
9438
- if (skipToNextSelector)
9439
- continue;
9440
- if (mode & 4 /* SelectorFlags.ELEMENT */) {
9441
- mode = 2 /* SelectorFlags.ATTRIBUTE */ | mode & 1 /* SelectorFlags.NOT */;
9442
- if (current !== '' && !hasTagAndTypeMatch(tNode, current, isProjectionMode) ||
9443
- current === '' && selector.length === 1) {
9444
- if (isPositive(mode))
9445
- return false;
9446
- skipToNextSelector = true;
9447
- }
9448
- }
9449
- else {
9450
- const selectorAttrValue = mode & 8 /* SelectorFlags.CLASS */ ? current : selector[++i];
9451
- // special case for matching against classes when a tNode has been instantiated with
9452
- // class and style values as separate attribute values (e.g. ['title', CLASS, 'foo'])
9453
- if ((mode & 8 /* SelectorFlags.CLASS */) && tNode.attrs !== null) {
9454
- if (!isCssClassMatching(tNode.attrs, selectorAttrValue, isProjectionMode)) {
9455
- if (isPositive(mode))
9456
- return false;
9457
- skipToNextSelector = true;
9458
- }
9459
- continue;
9460
- }
9461
- const attrName = (mode & 8 /* SelectorFlags.CLASS */) ? 'class' : current;
9462
- const attrIndexInNode = findAttrIndexInNode(attrName, nodeAttrs, isInlineTemplate(tNode), isProjectionMode);
9463
- if (attrIndexInNode === -1) {
9464
- if (isPositive(mode))
9465
- return false;
9466
- skipToNextSelector = true;
9467
- continue;
9468
- }
9469
- if (selectorAttrValue !== '') {
9470
- let nodeAttrValue;
9471
- if (attrIndexInNode > nameOnlyMarkerIdx) {
9472
- nodeAttrValue = '';
9473
- }
9474
- else {
9475
- ngDevMode &&
9476
- assertNotEqual(nodeAttrs[attrIndexInNode], 0 /* AttributeMarker.NamespaceURI */, 'We do not match directives on namespaced attributes');
9477
- // we lowercase the attribute value to be able to match
9478
- // selectors without case-sensitivity
9479
- // (selectors are already in lowercase when generated)
9480
- nodeAttrValue = nodeAttrs[attrIndexInNode + 1].toLowerCase();
9481
- }
9482
- const compareAgainstClassName = mode & 8 /* SelectorFlags.CLASS */ ? nodeAttrValue : null;
9483
- if (compareAgainstClassName &&
9484
- classIndexOf(compareAgainstClassName, selectorAttrValue, 0) !== -1 ||
9485
- mode & 2 /* SelectorFlags.ATTRIBUTE */ && selectorAttrValue !== nodeAttrValue) {
9486
- if (isPositive(mode))
9487
- return false;
9488
- skipToNextSelector = true;
9489
- }
9490
- }
9491
- }
9663
+ class Sanitizer {
9664
+ }
9665
+ /** @nocollapse */
9666
+ Sanitizer.ɵprov = ɵɵdefineInjectable({
9667
+ token: Sanitizer,
9668
+ providedIn: 'root',
9669
+ factory: () => null,
9670
+ });
9671
+
9672
+ /**
9673
+ * @description Represents the version of Angular
9674
+ *
9675
+ * @publicApi
9676
+ */
9677
+ class Version {
9678
+ constructor(full) {
9679
+ this.full = full;
9680
+ this.major = full.split('.')[0];
9681
+ this.minor = full.split('.')[1];
9682
+ this.patch = full.split('.').slice(2).join('.');
9492
9683
  }
9493
- return isPositive(mode) || skipToNextSelector;
9494
9684
  }
9495
- function isPositive(mode) {
9496
- return (mode & 1 /* SelectorFlags.NOT */) === 0;
9685
+ /**
9686
+ * @publicApi
9687
+ */
9688
+ const VERSION = new Version('16.0.0-next.3');
9689
+
9690
+ // This default value is when checking the hierarchy for a token.
9691
+ //
9692
+ // It means both:
9693
+ // - the token is not provided by the current injector,
9694
+ // - only the element injectors should be checked (ie do not check module injectors
9695
+ //
9696
+ // mod1
9697
+ // /
9698
+ // el1 mod2
9699
+ // \ /
9700
+ // el2
9701
+ //
9702
+ // When requesting el2.injector.get(token), we should check in the following order and return the
9703
+ // first found value:
9704
+ // - el2.injector.get(token, default)
9705
+ // - el1.injector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR) -> do not check the module
9706
+ // - mod2.injector.get(token, default)
9707
+ const NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR = {};
9708
+
9709
+ const ERROR_ORIGINAL_ERROR = 'ngOriginalError';
9710
+ function wrappedError(message, originalError) {
9711
+ const msg = `${message} caused by: ${originalError instanceof Error ? originalError.message : originalError}`;
9712
+ const error = Error(msg);
9713
+ error[ERROR_ORIGINAL_ERROR] = originalError;
9714
+ return error;
9715
+ }
9716
+ function getOriginalError(error) {
9717
+ return error[ERROR_ORIGINAL_ERROR];
9497
9718
  }
9719
+
9498
9720
  /**
9499
- * Examines the attribute's definition array for a node to find the index of the
9500
- * attribute that matches the given `name`.
9721
+ * Provides a hook for centralized exception handling.
9501
9722
  *
9502
- * NOTE: This will not match namespaced attributes.
9723
+ * The default implementation of `ErrorHandler` prints error messages to the `console`. To
9724
+ * intercept error handling, write a custom exception handler that replaces this default as
9725
+ * appropriate for your app.
9503
9726
  *
9504
- * Attribute matching depends upon `isInlineTemplate` and `isProjectionMode`.
9505
- * The following table summarizes which types of attributes we attempt to match:
9727
+ * @usageNotes
9728
+ * ### Example
9506
9729
  *
9507
- * ===========================================================================================================
9508
- * Modes | Normal Attributes | Bindings Attributes | Template Attributes | I18n
9509
- * Attributes
9510
- * ===========================================================================================================
9511
- * Inline + Projection | YES | YES | NO | YES
9512
- * -----------------------------------------------------------------------------------------------------------
9513
- * Inline + Directive | NO | NO | YES | NO
9514
- * -----------------------------------------------------------------------------------------------------------
9515
- * Non-inline + Projection | YES | YES | NO | YES
9516
- * -----------------------------------------------------------------------------------------------------------
9517
- * Non-inline + Directive | YES | YES | NO | YES
9518
- * ===========================================================================================================
9730
+ * ```
9731
+ * class MyErrorHandler implements ErrorHandler {
9732
+ * handleError(error) {
9733
+ * // do something with the exception
9734
+ * }
9735
+ * }
9519
9736
  *
9520
- * @param name the name of the attribute to find
9521
- * @param attrs the attribute array to examine
9522
- * @param isInlineTemplate true if the node being matched is an inline template (e.g. `*ngFor`)
9523
- * rather than a manually expanded template node (e.g `<ng-template>`).
9524
- * @param isProjectionMode true if we are matching against content projection otherwise we are
9525
- * matching against directives.
9737
+ * @NgModule({
9738
+ * providers: [{provide: ErrorHandler, useClass: MyErrorHandler}]
9739
+ * })
9740
+ * class MyModule {}
9741
+ * ```
9742
+ *
9743
+ * @publicApi
9526
9744
  */
9527
- function findAttrIndexInNode(name, attrs, isInlineTemplate, isProjectionMode) {
9528
- if (attrs === null)
9529
- return -1;
9530
- let i = 0;
9531
- if (isProjectionMode || !isInlineTemplate) {
9532
- let bindingsMode = false;
9533
- while (i < attrs.length) {
9534
- const maybeAttrName = attrs[i];
9535
- if (maybeAttrName === name) {
9536
- return i;
9537
- }
9538
- else if (maybeAttrName === 3 /* AttributeMarker.Bindings */ || maybeAttrName === 6 /* AttributeMarker.I18n */) {
9539
- bindingsMode = true;
9540
- }
9541
- else if (maybeAttrName === 1 /* AttributeMarker.Classes */ || maybeAttrName === 2 /* AttributeMarker.Styles */) {
9542
- let value = attrs[++i];
9543
- // We should skip classes here because we have a separate mechanism for
9544
- // matching classes in projection mode.
9545
- while (typeof value === 'string') {
9546
- value = attrs[++i];
9547
- }
9548
- continue;
9549
- }
9550
- else if (maybeAttrName === 4 /* AttributeMarker.Template */) {
9551
- // We do not care about Template attributes in this scenario.
9552
- break;
9553
- }
9554
- else if (maybeAttrName === 0 /* AttributeMarker.NamespaceURI */) {
9555
- // Skip the whole namespaced attribute and value. This is by design.
9556
- i += 4;
9557
- continue;
9558
- }
9559
- // In binding mode there are only names, rather than name-value pairs.
9560
- i += bindingsMode ? 1 : 2;
9561
- }
9562
- // We did not match the attribute
9563
- return -1;
9564
- }
9565
- else {
9566
- return matchTemplateAttribute(attrs, name);
9745
+ class ErrorHandler {
9746
+ constructor() {
9747
+ /**
9748
+ * @internal
9749
+ */
9750
+ this._console = console;
9567
9751
  }
9568
- }
9569
- function isNodeMatchingSelectorList(tNode, selector, isProjectionMode = false) {
9570
- for (let i = 0; i < selector.length; i++) {
9571
- if (isNodeMatchingSelector(tNode, selector[i], isProjectionMode)) {
9572
- return true;
9752
+ handleError(error) {
9753
+ const originalError = this._findOriginalError(error);
9754
+ this._console.error('ERROR', error);
9755
+ if (originalError) {
9756
+ this._console.error('ORIGINAL ERROR', originalError);
9573
9757
  }
9574
9758
  }
9575
- return false;
9576
- }
9577
- function getProjectAsAttrValue(tNode) {
9578
- const nodeAttrs = tNode.attrs;
9579
- if (nodeAttrs != null) {
9580
- const ngProjectAsAttrIdx = nodeAttrs.indexOf(5 /* AttributeMarker.ProjectAs */);
9581
- // only check for ngProjectAs in attribute names, don't accidentally match attribute's value
9582
- // (attribute names are stored at even indexes)
9583
- if ((ngProjectAsAttrIdx & 1) === 0) {
9584
- return nodeAttrs[ngProjectAsAttrIdx + 1];
9759
+ /** @internal */
9760
+ _findOriginalError(error) {
9761
+ let e = error && getOriginalError(error);
9762
+ while (e && getOriginalError(e)) {
9763
+ e = getOriginalError(e);
9585
9764
  }
9765
+ return e || null;
9586
9766
  }
9587
- return null;
9588
9767
  }
9589
- function getNameOnlyMarkerIndex(nodeAttrs) {
9590
- for (let i = 0; i < nodeAttrs.length; i++) {
9591
- const nodeAttr = nodeAttrs[i];
9592
- if (isNameOnlyAttributeMarker(nodeAttr)) {
9593
- return i;
9594
- }
9768
+
9769
+ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
9770
+ /**
9771
+ * Internal token that specifies whether hydration is enabled.
9772
+ */
9773
+ const IS_HYDRATION_FEATURE_ENABLED = new InjectionToken(NG_DEV_MODE ? 'IS_HYDRATION_FEATURE_ENABLED' : '');
9774
+ // By default (in client rendering mode), we remove all the contents
9775
+ // of the host element and render an application after that.
9776
+ const PRESERVE_HOST_CONTENT_DEFAULT = false;
9777
+ /**
9778
+ * Internal token that indicates whether host element content should be
9779
+ * retained during the bootstrap.
9780
+ */
9781
+ const PRESERVE_HOST_CONTENT = new InjectionToken(NG_DEV_MODE ? 'PRESERVE_HOST_CONTENT' : '', {
9782
+ providedIn: 'root',
9783
+ factory: () => PRESERVE_HOST_CONTENT_DEFAULT,
9784
+ });
9785
+
9786
+ function normalizeDebugBindingName(name) {
9787
+ // Attribute names with `$` (eg `x-y$`) are valid per spec, but unsupported by some browsers
9788
+ name = camelCaseToDashCase(name.replace(/[$@]/g, '_'));
9789
+ return `ng-reflect-${name}`;
9790
+ }
9791
+ const CAMEL_CASE_REGEXP = /([A-Z])/g;
9792
+ function camelCaseToDashCase(input) {
9793
+ return input.replace(CAMEL_CASE_REGEXP, (...m) => '-' + m[1].toLowerCase());
9794
+ }
9795
+ function normalizeDebugBindingValue(value) {
9796
+ try {
9797
+ // Limit the size of the value as otherwise the DOM just gets polluted.
9798
+ return value != null ? value.toString().slice(0, 30) : value;
9799
+ }
9800
+ catch (e) {
9801
+ return '[ERROR] Exception while trying to serialize the value';
9595
9802
  }
9596
- return nodeAttrs.length;
9597
9803
  }
9598
- function matchTemplateAttribute(attrs, name) {
9599
- let i = attrs.indexOf(4 /* AttributeMarker.Template */);
9600
- if (i > -1) {
9601
- i++;
9602
- while (i < attrs.length) {
9603
- const attr = attrs[i];
9604
- // Return in case we checked all template attrs and are switching to the next section in the
9605
- // attrs array (that starts with a number that represents an attribute marker).
9606
- if (typeof attr === 'number')
9607
- return -1;
9608
- if (attr === name)
9609
- return i;
9610
- i++;
9611
- }
9804
+
9805
+ /** Verifies that a given type is a Standalone Component. */
9806
+ function assertStandaloneComponentType(type) {
9807
+ assertComponentDef(type);
9808
+ const componentDef = getComponentDef$1(type);
9809
+ if (!componentDef.standalone) {
9810
+ throw new RuntimeError(907 /* RuntimeErrorCode.TYPE_IS_NOT_STANDALONE */, `The ${stringifyForError(type)} component is not marked as standalone, ` +
9811
+ `but Angular expects to have a standalone component here. ` +
9812
+ `Please make sure the ${stringifyForError(type)} component has ` +
9813
+ `the \`standalone: true\` flag in the decorator.`);
9612
9814
  }
9613
- return -1;
9614
9815
  }
9615
- /**
9616
- * Checks whether a selector is inside a CssSelectorList
9617
- * @param selector Selector to be checked.
9618
- * @param list List in which to look for the selector.
9619
- */
9620
- function isSelectorInSelectorList(selector, list) {
9621
- selectorListLoop: for (let i = 0; i < list.length; i++) {
9622
- const currentSelectorInList = list[i];
9623
- if (selector.length !== currentSelectorInList.length) {
9624
- continue;
9625
- }
9626
- for (let j = 0; j < selector.length; j++) {
9627
- if (selector[j] !== currentSelectorInList[j]) {
9628
- continue selectorListLoop;
9629
- }
9630
- }
9631
- return true;
9816
+ /** Verifies whether a given type is a component */
9817
+ function assertComponentDef(type) {
9818
+ if (!getComponentDef$1(type)) {
9819
+ throw new RuntimeError(906 /* RuntimeErrorCode.MISSING_GENERATED_DEF */, `The ${stringifyForError(type)} is not an Angular component, ` +
9820
+ `make sure it has the \`@Component\` decorator.`);
9632
9821
  }
9633
- return false;
9634
9822
  }
9635
- function maybeWrapInNotSelector(isNegativeMode, chunk) {
9636
- return isNegativeMode ? ':not(' + chunk.trim() + ')' : chunk;
9823
+ /** Called when there are multiple component selectors that match a given node */
9824
+ function throwMultipleComponentError(tNode, first, second) {
9825
+ throw new RuntimeError(-300 /* RuntimeErrorCode.MULTIPLE_COMPONENTS_MATCH */, `Multiple components match node with tagname ${tNode.value}: ` +
9826
+ `${stringifyForError(first)} and ` +
9827
+ `${stringifyForError(second)}`);
9637
9828
  }
9638
- function stringifyCSSSelector(selector) {
9639
- let result = selector[0];
9640
- let i = 1;
9641
- let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9642
- let currentChunk = '';
9643
- let isNegativeMode = false;
9644
- while (i < selector.length) {
9645
- let valueOrMarker = selector[i];
9646
- if (typeof valueOrMarker === 'string') {
9647
- if (mode & 2 /* SelectorFlags.ATTRIBUTE */) {
9648
- const attrValue = selector[++i];
9649
- currentChunk +=
9650
- '[' + valueOrMarker + (attrValue.length > 0 ? '="' + attrValue + '"' : '') + ']';
9651
- }
9652
- else if (mode & 8 /* SelectorFlags.CLASS */) {
9653
- currentChunk += '.' + valueOrMarker;
9654
- }
9655
- else if (mode & 4 /* SelectorFlags.ELEMENT */) {
9656
- currentChunk += ' ' + valueOrMarker;
9657
- }
9658
- }
9659
- else {
9660
- //
9661
- // Append current chunk to the final result in case we come across SelectorFlag, which
9662
- // indicates that the previous section of a selector is over. We need to accumulate content
9663
- // between flags to make sure we wrap the chunk later in :not() selector if needed, e.g.
9664
- // ```
9665
- // ['', Flags.CLASS, '.classA', Flags.CLASS | Flags.NOT, '.classB', '.classC']
9666
- // ```
9667
- // should be transformed to `.classA :not(.classB .classC)`.
9668
- //
9669
- // Note: for negative selector part, we accumulate content between flags until we find the
9670
- // next negative flag. This is needed to support a case where `:not()` rule contains more than
9671
- // one chunk, e.g. the following selector:
9672
- // ```
9673
- // ['', Flags.ELEMENT | Flags.NOT, 'p', Flags.CLASS, 'foo', Flags.CLASS | Flags.NOT, 'bar']
9674
- // ```
9675
- // should be stringified to `:not(p.foo) :not(.bar)`
9676
- //
9677
- if (currentChunk !== '' && !isPositive(valueOrMarker)) {
9678
- result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9679
- currentChunk = '';
9680
- }
9681
- mode = valueOrMarker;
9682
- // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9683
- // mode is maintained for remaining chunks of a selector.
9684
- isNegativeMode = isNegativeMode || !isPositive(mode);
9685
- }
9686
- i++;
9687
- }
9688
- if (currentChunk !== '') {
9689
- result += maybeWrapInNotSelector(isNegativeMode, currentChunk);
9829
+ /** Throws an ExpressionChangedAfterChecked error if checkNoChanges mode is on. */
9830
+ function throwErrorIfNoChangesMode(creationMode, oldValue, currValue, propName) {
9831
+ const field = propName ? ` for '${propName}'` : '';
9832
+ let msg = `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`;
9833
+ if (creationMode) {
9834
+ msg +=
9835
+ ` It seems like the view has been created after its parent and its children have been dirty checked.` +
9836
+ ` Has it been created in a change detection hook?`;
9690
9837
  }
9691
- return result;
9838
+ throw new RuntimeError(-100 /* RuntimeErrorCode.EXPRESSION_CHANGED_AFTER_CHECKED */, msg);
9692
9839
  }
9693
- /**
9694
- * Generates string representation of CSS selector in parsed form.
9695
- *
9696
- * ComponentDef and DirectiveDef are generated with the selector in parsed form to avoid doing
9697
- * additional parsing at runtime (for example, for directive matching). However in some cases (for
9698
- * example, while bootstrapping a component), a string version of the selector is required to query
9699
- * for the host element on the page. This function takes the parsed form of a selector and returns
9700
- * its string representation.
9701
- *
9702
- * @param selectorList selector in parsed form
9703
- * @returns string representation of a given selector
9704
- */
9705
- function stringifyCSSSelectorList(selectorList) {
9706
- return selectorList.map(stringifyCSSSelector).join(',');
9840
+ function constructDetailsForInterpolation(lView, rootIndex, expressionIndex, meta, changedValue) {
9841
+ const [propName, prefix, ...chunks] = meta.split(INTERPOLATION_DELIMITER);
9842
+ let oldValue = prefix, newValue = prefix;
9843
+ for (let i = 0; i < chunks.length; i++) {
9844
+ const slotIdx = rootIndex + i;
9845
+ oldValue += `${lView[slotIdx]}${chunks[i]}`;
9846
+ newValue += `${slotIdx === expressionIndex ? changedValue : lView[slotIdx]}${chunks[i]}`;
9847
+ }
9848
+ return { propName, oldValue, newValue };
9707
9849
  }
9708
9850
  /**
9709
- * Extracts attributes and classes information from a given CSS selector.
9710
- *
9711
- * This function is used while creating a component dynamically. In this case, the host element
9712
- * (that is created dynamically) should contain attributes and classes specified in component's CSS
9713
- * selector.
9851
+ * Constructs an object that contains details for the ExpressionChangedAfterItHasBeenCheckedError:
9852
+ * - property name (for property bindings or interpolations)
9853
+ * - old and new values, enriched using information from metadata
9714
9854
  *
9715
- * @param selector CSS selector in parsed form (in a form of array)
9716
- * @returns object with `attrs` and `classes` fields that contain extracted information
9855
+ * More information on the metadata storage format can be found in `storePropertyBindingMetadata`
9856
+ * function description.
9717
9857
  */
9718
- function extractAttrsAndClassesFromSelector(selector) {
9719
- const attrs = [];
9720
- const classes = [];
9721
- let i = 1;
9722
- let mode = 2 /* SelectorFlags.ATTRIBUTE */;
9723
- while (i < selector.length) {
9724
- let valueOrMarker = selector[i];
9725
- if (typeof valueOrMarker === 'string') {
9726
- if (mode === 2 /* SelectorFlags.ATTRIBUTE */) {
9727
- if (valueOrMarker !== '') {
9728
- attrs.push(valueOrMarker, selector[++i]);
9729
- }
9730
- }
9731
- else if (mode === 8 /* SelectorFlags.CLASS */) {
9732
- classes.push(valueOrMarker);
9733
- }
9858
+ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValue) {
9859
+ const tData = lView[TVIEW].data;
9860
+ const metadata = tData[bindingIndex];
9861
+ if (typeof metadata === 'string') {
9862
+ // metadata for property interpolation
9863
+ if (metadata.indexOf(INTERPOLATION_DELIMITER) > -1) {
9864
+ return constructDetailsForInterpolation(lView, bindingIndex, bindingIndex, metadata, newValue);
9734
9865
  }
9735
- else {
9736
- // According to CssSelector spec, once we come across `SelectorFlags.NOT` flag, the negative
9737
- // mode is maintained for remaining chunks of a selector. Since attributes and classes are
9738
- // extracted only for "positive" part of the selector, we can stop here.
9739
- if (!isPositive(mode))
9740
- break;
9741
- mode = valueOrMarker;
9866
+ // metadata for property binding
9867
+ return { propName: metadata, oldValue, newValue };
9868
+ }
9869
+ // metadata is not available for this expression, check if this expression is a part of the
9870
+ // property interpolation by going from the current binding index left and look for a string that
9871
+ // contains INTERPOLATION_DELIMITER, the layout in tView.data for this case will look like this:
9872
+ // [..., 'id�Prefix � and � suffix', null, null, null, ...]
9873
+ if (metadata === null) {
9874
+ let idx = bindingIndex - 1;
9875
+ while (typeof tData[idx] !== 'string' && tData[idx + 1] === null) {
9876
+ idx--;
9877
+ }
9878
+ const meta = tData[idx];
9879
+ if (typeof meta === 'string') {
9880
+ const matches = meta.match(new RegExp(INTERPOLATION_DELIMITER, 'g'));
9881
+ // first interpolation delimiter separates property name from interpolation parts (in case of
9882
+ // property interpolations), so we subtract one from total number of found delimiters
9883
+ if (matches && (matches.length - 1) > bindingIndex - idx) {
9884
+ return constructDetailsForInterpolation(lView, idx, bindingIndex, meta, newValue);
9885
+ }
9742
9886
  }
9743
- i++;
9744
9887
  }
9745
- return { attrs, classes };
9888
+ return { propName: undefined, oldValue, newValue };
9746
9889
  }
9747
9890
 
9748
9891
  /** A special value which designates that a value has not changed. */
@@ -9801,6 +9944,33 @@ function selectIndexInternal(tView, lView, index, checkNoChangesMode) {
9801
9944
  setSelectedIndex(index);
9802
9945
  }
9803
9946
 
9947
+ /**
9948
+ * Runs the given function in the context of the given `Injector`.
9949
+ *
9950
+ * Within the function's stack frame, `inject` can be used to inject dependencies from the given
9951
+ * `Injector`. Note that `inject` is only usable synchronously, and cannot be used in any
9952
+ * asynchronous callbacks or after any `await` points.
9953
+ *
9954
+ * @param injector the injector which will satisfy calls to `inject` while `fn` is executing
9955
+ * @param fn the closure to be run in the context of `injector`
9956
+ * @returns the return value of the function, if any
9957
+ * @publicApi
9958
+ */
9959
+ function runInInjectionContext(injector, fn) {
9960
+ if (injector instanceof R3Injector) {
9961
+ injector.assertNotDestroyed();
9962
+ }
9963
+ const prevInjector = setCurrentInjector(injector);
9964
+ const previousInjectImplementation = setInjectImplementation(undefined);
9965
+ try {
9966
+ return fn();
9967
+ }
9968
+ finally {
9969
+ setCurrentInjector(prevInjector);
9970
+ setInjectImplementation(previousInjectImplementation);
9971
+ }
9972
+ }
9973
+
9804
9974
  /**
9805
9975
  * A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
9806
9976
  *
@@ -11240,7 +11410,7 @@ function getOrCreateComponentTView(def) {
11240
11410
  // Declaration node here is null since this function is called when we dynamically create a
11241
11411
  // component and hence there is no declaration.
11242
11412
  const declTNode = null;
11243
- return def.tView = createTView(1 /* TViewType.Component */, declTNode, def.template, def.decls, def.vars, def.directiveDefs, def.pipeDefs, def.viewQuery, def.schemas, def.consts);
11413
+ 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);
11244
11414
  }
11245
11415
  return tView;
11246
11416
  }
@@ -11257,7 +11427,7 @@ function getOrCreateComponentTView(def) {
11257
11427
  * @param schemas Schemas for this view
11258
11428
  * @param consts Constants for this view
11259
11429
  */
11260
- function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory) {
11430
+ function createTView(type, declTNode, templateFn, decls, vars, directives, pipes, viewQuery, schemas, constsOrFactory, ssrId) {
11261
11431
  ngDevMode && ngDevMode.tView++;
11262
11432
  const bindingStartIndex = HEADER_OFFSET + decls;
11263
11433
  // This length does not yet contain host bindings from child directives because at this point,
@@ -11296,7 +11466,8 @@ function createTView(type, declTNode, templateFn, decls, vars, directives, pipes
11296
11466
  firstChild: null,
11297
11467
  schemas: schemas,
11298
11468
  consts: consts,
11299
- incompleteFirstPass: false
11469
+ incompleteFirstPass: false,
11470
+ ssrId,
11300
11471
  };
11301
11472
  if (ngDevMode) {
11302
11473
  // For performance reasons it is important that the tView retains the same shape during runtime.
@@ -11316,23 +11487,58 @@ function createViewBlueprint(bindingStartIndex, initialViewLength) {
11316
11487
  /**
11317
11488
  * Locates the host native element, used for bootstrapping existing nodes into rendering pipeline.
11318
11489
  *
11319
- * @param rendererFactory Factory function to create renderer instance.
11490
+ * @param renderer the renderer used to locate the element.
11320
11491
  * @param elementOrSelector Render element or CSS selector to locate the element.
11321
11492
  * @param encapsulation View Encapsulation defined for component that requests host element.
11322
11493
  * @param injector Root view injector instance.
11323
11494
  */
11324
11495
  function locateHostElement(renderer, elementOrSelector, encapsulation, injector) {
11325
11496
  // Note: we use default value for the `PRESERVE_HOST_CONTENT` here even though it's a
11326
- // tree-shakable one (providedIn:'root'). This code path can be triggered during dynamic component
11327
- // creation (after calling ViewContainerRef.createComponent) when an injector instance can be
11328
- // provided. The injector instance might be disconnected from the main DI tree, thus the
11329
- // `PRESERVE_HOST_CONTENT` woild not be able to instantiate. In this case, the default value will
11330
- // be used.
11497
+ // tree-shakable one (providedIn:'root'). This code path can be triggered during dynamic
11498
+ // component creation (after calling ViewContainerRef.createComponent) when an injector
11499
+ // instance can be provided. The injector instance might be disconnected from the main DI
11500
+ // tree, thus the `PRESERVE_HOST_CONTENT` woild not be able to instantiate. In this case, the
11501
+ // default value will be used.
11331
11502
  const preserveHostContent = injector.get(PRESERVE_HOST_CONTENT, PRESERVE_HOST_CONTENT_DEFAULT);
11332
11503
  // When using native Shadow DOM, do not clear host element to allow native slot
11333
11504
  // projection.
11334
11505
  const preserveContent = preserveHostContent || encapsulation === ViewEncapsulation.ShadowDom;
11335
- return renderer.selectRootElement(elementOrSelector, preserveContent);
11506
+ const rootElement = renderer.selectRootElement(elementOrSelector, preserveContent);
11507
+ applyRootElementTransform(rootElement);
11508
+ return rootElement;
11509
+ }
11510
+ /**
11511
+ * Applies any root element transformations that are needed. If hydration is enabled,
11512
+ * this will process corrupted text nodes.
11513
+ *
11514
+ * @param rootElement the app root HTML Element
11515
+ */
11516
+ function applyRootElementTransform(rootElement) {
11517
+ _applyRootElementTransformImpl(rootElement);
11518
+ }
11519
+ /**
11520
+ * Reference to a function that applies transformations to the root HTML element
11521
+ * of an app. When hydration is enabled, this processes any corrupt text nodes
11522
+ * so they are properly hydratable on the client.
11523
+ *
11524
+ * @param rootElement the app root HTML Element
11525
+ */
11526
+ let _applyRootElementTransformImpl = (rootElement) => null;
11527
+ /**
11528
+ * Processes text node markers before hydration begins. This replaces any special comment
11529
+ * nodes that were added prior to serialization are swapped out to restore proper text
11530
+ * nodes before hydration.
11531
+ *
11532
+ * @param rootElement the app root HTML Element
11533
+ */
11534
+ function applyRootElementTransformImpl(rootElement) {
11535
+ processTextNodeMarkersBeforeHydration(rootElement);
11536
+ }
11537
+ /**
11538
+ * Sets the implementation for the `applyRootElementTransform` function.
11539
+ */
11540
+ function enableApplyRootElementTransformImpl() {
11541
+ _applyRootElementTransformImpl = applyRootElementTransformImpl;
11336
11542
  }
11337
11543
  /**
11338
11544
  * Saves context for this cleanup function in LView.cleanupInstances.
@@ -11344,9 +11550,9 @@ function locateHostElement(renderer, elementOrSelector, encapsulation, injector)
11344
11550
  function storeCleanupWithContext(tView, lView, context, cleanupFn) {
11345
11551
  const lCleanup = getOrCreateLViewCleanup(lView);
11346
11552
  // Historically the `storeCleanupWithContext` was used to register both framework-level and
11347
- // user-defined cleanup callbacks, but over time those two types of cleanups were separated. This
11348
- // dev mode checks assures that user-level cleanup callbacks are _not_ stored in data structures
11349
- // reserved for framework-specific hooks.
11553
+ // user-defined cleanup callbacks, but over time those two types of cleanups were separated.
11554
+ // This dev mode checks assures that user-level cleanup callbacks are _not_ stored in data
11555
+ // structures reserved for framework-specific hooks.
11350
11556
  ngDevMode &&
11351
11557
  assertDefined(context, 'Cleanup context is mandatory when registering framework-level destroy hooks');
11352
11558
  lCleanup.push(context);
@@ -12065,7 +12271,8 @@ function createLContainer(hostNative, currentView, native, tNode) {
12065
12271
  tNode,
12066
12272
  native,
12067
12273
  null,
12068
- null, // moved views
12274
+ null,
12275
+ null, // dehydrated views
12069
12276
  ];
12070
12277
  ngDevMode &&
12071
12278
  assertEqual(lContainer.length, CONTAINER_HEADER_OFFSET, 'Should allocate correct number of slots for LContainer header.');
@@ -12887,7 +13094,7 @@ class ComponentFactory extends ComponentFactory$1 {
12887
13094
  const rootFlags = this.componentDef.onPush ? 32 /* LViewFlags.Dirty */ | 256 /* LViewFlags.IsRoot */ :
12888
13095
  16 /* LViewFlags.CheckAlways */ | 256 /* LViewFlags.IsRoot */;
12889
13096
  // Create the root view. Uses empty TView and ContentTemplate.
12890
- const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null);
13097
+ const rootTView = createTView(0 /* TViewType.Root */, null, null, 1, 0, null, null, null, null, null, null);
12891
13098
  const rootLView = createLView(null, rootTView, null, rootFlags, null, null, rendererFactory, hostRenderer, sanitizer, rootViewInjector, null, null);
12892
13099
  // rootView is the parent when bootstrapping
12893
13100
  // TODO(misko): it looks like we are entering view here but we don't really need to as
@@ -14135,119 +14342,41 @@ function ɵɵattributeInterpolate8(attrName, prefix, v0, i0, v1, i1, v2, i2, v3,
14135
14342
  * 'suffix']);
14136
14343
  * ```
14137
14344
  *
14138
- * @param attrName The name of the attribute to update.
14139
- * @param values The collection of values and the strings in-between those values, beginning with
14140
- * a string prefix and ending with a string suffix.
14141
- * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
14142
- * @param sanitizer An optional sanitizer function
14143
- * @returns itself, so that it may be chained.
14144
- * @codeGenApi
14145
- */
14146
- function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
14147
- const lView = getLView();
14148
- const interpolated = interpolationV(lView, values);
14149
- if (interpolated !== NO_CHANGE) {
14150
- const tNode = getSelectedTNode();
14151
- elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
14152
- if (ngDevMode) {
14153
- const interpolationInBetween = [values[0]]; // prefix
14154
- for (let i = 2; i < values.length; i += 2) {
14155
- interpolationInBetween.push(values[i]);
14156
- }
14157
- storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
14158
- }
14159
- }
14160
- return ɵɵattributeInterpolateV;
14161
- }
14162
-
14163
- /**
14164
- * Synchronously perform change detection on a component (and possibly its sub-components).
14165
- *
14166
- * This function triggers change detection in a synchronous way on a component.
14167
- *
14168
- * @param component The component which the change detection should be performed on.
14169
- */
14170
- function detectChanges(component) {
14171
- const view = getComponentViewByInstance(component);
14172
- detectChangesInternal(view[TVIEW], view, component);
14173
- }
14174
-
14175
- function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
14176
- ngDevMode && assertFirstCreatePass(tView);
14177
- ngDevMode && ngDevMode.firstCreatePass++;
14178
- const tViewConsts = tView.consts;
14179
- // TODO(pk): refactor getOrCreateTNode to have the "create" only version
14180
- const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
14181
- resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
14182
- registerPostOrderHooks(tView, tNode);
14183
- const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts);
14184
- if (tView.queries !== null) {
14185
- tView.queries.template(tView, tNode);
14186
- embeddedTView.queries = tView.queries.embeddedTView(tNode);
14187
- }
14188
- return tNode;
14189
- }
14190
- /**
14191
- * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
14192
- *
14193
- * <ng-template #foo>
14194
- * <div></div>
14195
- * </ng-template>
14196
- *
14197
- * @param index The index of the container in the data array
14198
- * @param templateFn Inline template
14199
- * @param decls The number of nodes, local refs, and pipes for this template
14200
- * @param vars The number of bindings for this template
14201
- * @param tagName The name of the container element, if applicable
14202
- * @param attrsIndex Index of template attributes in the `consts` array.
14203
- * @param localRefs Index of the local references in the `consts` array.
14204
- * @param localRefExtractor A function which extracts local-refs values from the template.
14205
- * Defaults to the current element associated with the local-ref.
14206
- *
14345
+ * @param attrName The name of the attribute to update.
14346
+ * @param values The collection of values and the strings in-between those values, beginning with
14347
+ * a string prefix and ending with a string suffix.
14348
+ * (e.g. `['prefix', value0, '-', value1, '-', value2, ..., value99, 'suffix']`)
14349
+ * @param sanitizer An optional sanitizer function
14350
+ * @returns itself, so that it may be chained.
14207
14351
  * @codeGenApi
14208
14352
  */
14209
- function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
14353
+ function ɵɵattributeInterpolateV(attrName, values, sanitizer, namespace) {
14210
14354
  const lView = getLView();
14211
- const tView = getTView();
14212
- const adjustedIndex = index + HEADER_OFFSET;
14213
- const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
14214
- tView.data[adjustedIndex];
14215
- setCurrentTNode(tNode, false);
14216
- const comment = lView[RENDERER].createComment(ngDevMode ? 'container' : '');
14217
- appendChild(tView, lView, comment, tNode);
14218
- attachPatchData(comment, lView);
14219
- addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
14220
- if (isDirectiveHost(tNode)) {
14221
- createDirectivesInstances(tView, lView, tNode);
14222
- }
14223
- if (localRefsIndex != null) {
14224
- saveResolvedLocalsInData(lView, tNode, localRefExtractor);
14355
+ const interpolated = interpolationV(lView, values);
14356
+ if (interpolated !== NO_CHANGE) {
14357
+ const tNode = getSelectedTNode();
14358
+ elementAttributeInternal(tNode, lView, attrName, interpolated, sanitizer, namespace);
14359
+ if (ngDevMode) {
14360
+ const interpolationInBetween = [values[0]]; // prefix
14361
+ for (let i = 2; i < values.length; i += 2) {
14362
+ interpolationInBetween.push(values[i]);
14363
+ }
14364
+ storePropertyBindingMetadata(getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - interpolationInBetween.length + 1, ...interpolationInBetween);
14365
+ }
14225
14366
  }
14367
+ return ɵɵattributeInterpolateV;
14226
14368
  }
14227
14369
 
14228
- /** Store a value in the `data` at a given `index`. */
14229
- function store(tView, lView, index, value) {
14230
- // We don't store any static data for local variables, so the first time
14231
- // we see the template, we should store as null to avoid a sparse array
14232
- if (index >= tView.data.length) {
14233
- tView.data[index] = null;
14234
- tView.blueprint[index] = null;
14235
- }
14236
- lView[index] = value;
14237
- }
14238
14370
  /**
14239
- * Retrieves a local reference from the current contextViewData.
14240
- *
14241
- * If the reference to retrieve is in a parent view, this instruction is used in conjunction
14242
- * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
14371
+ * Synchronously perform change detection on a component (and possibly its sub-components).
14243
14372
  *
14244
- * @param index The index of the local ref in contextViewData.
14373
+ * This function triggers change detection in a synchronous way on a component.
14245
14374
  *
14246
- * @codeGenApi
14375
+ * @param component The component which the change detection should be performed on.
14247
14376
  */
14248
- function ɵɵreference(index) {
14249
- const contextLView = getContextLView();
14250
- return load(contextLView, HEADER_OFFSET + index);
14377
+ function detectChanges(component) {
14378
+ const view = getComponentViewByInstance(component);
14379
+ detectChangesInternal(view[TVIEW], view, component);
14251
14380
  }
14252
14381
 
14253
14382
  /**
@@ -14255,9 +14384,10 @@ function ɵɵreference(index) {
14255
14384
  * based on internal data structure state.
14256
14385
  */
14257
14386
  function validateMatchingNode(node, nodeType, tagName, lView, tNode) {
14387
+ validateNodeExists(node);
14258
14388
  if (node.nodeType !== nodeType ||
14259
- (node.nodeType === Node.ELEMENT_NODE &&
14260
- node.tagName.toLowerCase() !== (tagName === null || tagName === void 0 ? void 0 : tagName.toLowerCase()))) {
14389
+ node.nodeType === Node.ELEMENT_NODE &&
14390
+ node.tagName.toLowerCase() !== (tagName === null || tagName === void 0 ? void 0 : tagName.toLowerCase())) {
14261
14391
  // TODO: improve error message and use RuntimeError instead.
14262
14392
  throw new Error(`Unexpected node found during hydration.`);
14263
14393
  }
@@ -14266,27 +14396,24 @@ function validateMatchingNode(node, nodeType, tagName, lView, tNode) {
14266
14396
  * Verifies whether next sibling node exists.
14267
14397
  */
14268
14398
  function validateSiblingNodeExists(node) {
14399
+ validateNodeExists(node);
14269
14400
  if (!node.nextSibling) {
14270
14401
  // TODO: improve error message and use RuntimeError instead.
14271
14402
  throw new Error(`Unexpected state: insufficient number of sibling nodes.`);
14272
14403
  }
14273
14404
  }
14405
+ function validateNodeExists(node) {
14406
+ if (!node) {
14407
+ // TODO: improve error message and use RuntimeError instead.
14408
+ throw new Error(`Hydration expected an element to be present at this location.`);
14409
+ }
14410
+ }
14274
14411
 
14275
14412
  /** Whether current TNode is a first node in an <ng-container>. */
14276
14413
  function isFirstElementInNgContainer(tNode) {
14277
14414
  var _a;
14278
14415
  return !tNode.prev && ((_a = tNode.parent) === null || _a === void 0 ? void 0 : _a.type) === 8 /* TNodeType.ElementContainer */;
14279
14416
  }
14280
- /** Returns first element from a DOM segment that corresponds to this <ng-container>. */
14281
- function getDehydratedNgContainer(hydrationInfo, tContainerNode) {
14282
- var _a;
14283
- const noOffsetIndex = tContainerNode.index - HEADER_OFFSET;
14284
- const ngContainer = (_a = hydrationInfo.ngContainers) === null || _a === void 0 ? void 0 : _a[noOffsetIndex];
14285
- ngDevMode &&
14286
- assertDefined(ngContainer, 'Unexpected state: no hydration info available for a given TNode, ' +
14287
- 'which represents an element container.');
14288
- return ngContainer;
14289
- }
14290
14417
  /**
14291
14418
  * Locate a node in DOM tree that corresponds to a given TNode.
14292
14419
  *
@@ -14297,7 +14424,7 @@ function getDehydratedNgContainer(hydrationInfo, tContainerNode) {
14297
14424
  * @returns an RNode that represents a given tNode
14298
14425
  */
14299
14426
  function locateNextRNode(hydrationInfo, tView, lView, tNode) {
14300
- var _a, _b;
14427
+ var _a;
14301
14428
  let native = null;
14302
14429
  if (tView.firstChild === tNode) {
14303
14430
  // We create a first node in this view, so we use a reference
@@ -14311,17 +14438,33 @@ function locateNextRNode(hydrationInfo, tView, lView, tNode) {
14311
14438
  ngDevMode &&
14312
14439
  assertDefined(previousTNode, 'Unexpected state: current TNode does not have a connection ' +
14313
14440
  'to the previous node or a parent node.');
14314
- const previousRElement = getNativeByTNode(previousTNode, lView);
14315
14441
  if (isFirstElementInNgContainer(tNode)) {
14316
- const ngContainer = getDehydratedNgContainer(hydrationInfo, tNode.parent);
14317
- native = (_b = ngContainer.firstChild) !== null && _b !== void 0 ? _b : null;
14442
+ const noOffsetParentIndex = tNode.parent.index - HEADER_OFFSET;
14443
+ native = getSegmentHead(hydrationInfo, noOffsetParentIndex);
14318
14444
  }
14319
14445
  else {
14446
+ let previousRElement = getNativeByTNode(previousTNode, lView);
14320
14447
  if (previousTNodeParent) {
14321
14448
  native = previousRElement.firstChild;
14322
14449
  }
14323
14450
  else {
14324
- native = previousRElement.nextSibling;
14451
+ // If the previous node is an element, but it also has container info,
14452
+ // this means that we are processing a node like `<div #vcrTarget>`, which is
14453
+ // represented in the DOM as `<div></div>...<!--container-->`.
14454
+ // In this case, there are nodes *after* this element and we need to skip
14455
+ // all of them to reach an element that we are looking for.
14456
+ const noOffsetPrevSiblingIndex = previousTNode.index - HEADER_OFFSET;
14457
+ const segmentHead = getSegmentHead(hydrationInfo, noOffsetPrevSiblingIndex);
14458
+ if (previousTNode.type === 2 /* TNodeType.Element */ && segmentHead) {
14459
+ const numRootNodesToSkip = calcSerializedContainerSize(hydrationInfo, noOffsetPrevSiblingIndex);
14460
+ // `+1` stands for an anchor comment node after all the views in this container.
14461
+ const nodesToSkip = numRootNodesToSkip + 1;
14462
+ // First node after this segment.
14463
+ native = siblingAfter(nodesToSkip, segmentHead);
14464
+ }
14465
+ else {
14466
+ native = previousRElement.nextSibling;
14467
+ }
14325
14468
  }
14326
14469
  }
14327
14470
  }
@@ -14339,6 +14482,132 @@ function siblingAfter(skip, from) {
14339
14482
  return currentNode;
14340
14483
  }
14341
14484
 
14485
+ function templateFirstCreatePass(index, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) {
14486
+ var _a, _b;
14487
+ ngDevMode && assertFirstCreatePass(tView);
14488
+ ngDevMode && ngDevMode.firstCreatePass++;
14489
+ const tViewConsts = tView.consts;
14490
+ let ssrId = null;
14491
+ const hydrationInfo = lView[HYDRATION];
14492
+ if (hydrationInfo) {
14493
+ const noOffsetIndex = index - HEADER_OFFSET;
14494
+ ssrId = (_b = (hydrationInfo && ((_a = hydrationInfo.data[TEMPLATES]) === null || _a === void 0 ? void 0 : _a[noOffsetIndex]))) !== null && _b !== void 0 ? _b : null;
14495
+ }
14496
+ // TODO(pk): refactor getOrCreateTNode to have the "create" only version
14497
+ const tNode = getOrCreateTNode(tView, index, 4 /* TNodeType.Container */, tagName || null, getConstant(tViewConsts, attrsIndex));
14498
+ resolveDirectives(tView, lView, tNode, getConstant(tViewConsts, localRefsIndex));
14499
+ registerPostOrderHooks(tView, tNode);
14500
+ const embeddedTView = tNode.tView = createTView(2 /* TViewType.Embedded */, tNode, templateFn, decls, vars, tView.directiveRegistry, tView.pipeRegistry, null, tView.schemas, tViewConsts, ssrId);
14501
+ if (tView.queries !== null) {
14502
+ tView.queries.template(tView, tNode);
14503
+ embeddedTView.queries = tView.queries.embeddedTView(tNode);
14504
+ }
14505
+ return tNode;
14506
+ }
14507
+ /**
14508
+ * Creates an LContainer for an ng-template (dynamically-inserted view), e.g.
14509
+ *
14510
+ * <ng-template #foo>
14511
+ * <div></div>
14512
+ * </ng-template>
14513
+ *
14514
+ * @param index The index of the container in the data array
14515
+ * @param templateFn Inline template
14516
+ * @param decls The number of nodes, local refs, and pipes for this template
14517
+ * @param vars The number of bindings for this template
14518
+ * @param tagName The name of the container element, if applicable
14519
+ * @param attrsIndex Index of template attributes in the `consts` array.
14520
+ * @param localRefs Index of the local references in the `consts` array.
14521
+ * @param localRefExtractor A function which extracts local-refs values from the template.
14522
+ * Defaults to the current element associated with the local-ref.
14523
+ *
14524
+ * @codeGenApi
14525
+ */
14526
+ function ɵɵtemplate(index, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex, localRefExtractor) {
14527
+ const lView = getLView();
14528
+ const tView = getTView();
14529
+ const adjustedIndex = index + HEADER_OFFSET;
14530
+ const tNode = tView.firstCreatePass ? templateFirstCreatePass(adjustedIndex, tView, lView, templateFn, decls, vars, tagName, attrsIndex, localRefsIndex) :
14531
+ tView.data[adjustedIndex];
14532
+ setCurrentTNode(tNode, false);
14533
+ const comment = _locateOrCreateContainerAnchor(tView, lView, tNode, index);
14534
+ if (wasLastNodeCreated()) {
14535
+ appendChild(tView, lView, comment, tNode);
14536
+ }
14537
+ attachPatchData(comment, lView);
14538
+ addToViewTree(lView, lView[adjustedIndex] = createLContainer(comment, lView, comment, tNode));
14539
+ if (isDirectiveHost(tNode)) {
14540
+ createDirectivesInstances(tView, lView, tNode);
14541
+ }
14542
+ if (localRefsIndex != null) {
14543
+ saveResolvedLocalsInData(lView, tNode, localRefExtractor);
14544
+ }
14545
+ }
14546
+ let _locateOrCreateContainerAnchor = createContainerAnchorImpl;
14547
+ /**
14548
+ * Regular creation mode for LContainers and their anchor (comment) nodes.
14549
+ */
14550
+ function createContainerAnchorImpl(tView, lView, tNode, index) {
14551
+ lastNodeWasCreated(true);
14552
+ return lView[RENDERER].createComment(ngDevMode ? 'container' : '');
14553
+ }
14554
+ /**
14555
+ * Enables hydration code path (to lookup existing elements in DOM)
14556
+ * in addition to the regular creation mode for LContainers and their
14557
+ * anchor (comment) nodes.
14558
+ */
14559
+ function locateOrCreateContainerAnchorImpl(tView, lView, tNode, index) {
14560
+ const hydrationInfo = lView[HYDRATION];
14561
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14562
+ lastNodeWasCreated(isNodeCreationMode);
14563
+ // Regular creation mode.
14564
+ if (isNodeCreationMode) {
14565
+ return createContainerAnchorImpl(tView, lView, tNode, index);
14566
+ }
14567
+ // Hydration mode, looking up existing elements in DOM.
14568
+ const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
14569
+ ngDevMode && validateNodeExists(currentRNode);
14570
+ const viewContainerSize = calcSerializedContainerSize(hydrationInfo, index);
14571
+ // If this container is non-empty, store the first node as a segment head,
14572
+ // otherwise, this node is an anchor and segment head doesn't exist (thus `null`).
14573
+ const segmentHead = viewContainerSize > 0 ? currentRNode : null;
14574
+ setSegmentHead(hydrationInfo, index, segmentHead);
14575
+ const comment = siblingAfter(viewContainerSize, currentRNode);
14576
+ if (ngDevMode) {
14577
+ validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14578
+ markRNodeAsClaimedByHydration(comment);
14579
+ }
14580
+ return comment;
14581
+ }
14582
+ function enableLocateOrCreateContainerAnchorImpl() {
14583
+ _locateOrCreateContainerAnchor = locateOrCreateContainerAnchorImpl;
14584
+ }
14585
+
14586
+ /** Store a value in the `data` at a given `index`. */
14587
+ function store(tView, lView, index, value) {
14588
+ // We don't store any static data for local variables, so the first time
14589
+ // we see the template, we should store as null to avoid a sparse array
14590
+ if (index >= tView.data.length) {
14591
+ tView.data[index] = null;
14592
+ tView.blueprint[index] = null;
14593
+ }
14594
+ lView[index] = value;
14595
+ }
14596
+ /**
14597
+ * Retrieves a local reference from the current contextViewData.
14598
+ *
14599
+ * If the reference to retrieve is in a parent view, this instruction is used in conjunction
14600
+ * with a nextContext() call, which walks up the tree and updates the contextViewData instance.
14601
+ *
14602
+ * @param index The index of the local ref in contextViewData.
14603
+ *
14604
+ * @codeGenApi
14605
+ */
14606
+ function ɵɵreference(index) {
14607
+ const contextLView = getContextLView();
14608
+ return load(contextLView, HEADER_OFFSET + index);
14609
+ }
14610
+
14342
14611
  /**
14343
14612
  * The name of an attribute that can be added to the hydration boundary node
14344
14613
  * (component host node) to disable hydration for the content within that boundary.
@@ -14365,6 +14634,21 @@ function hasNgSkipHydrationAttr(tNode) {
14365
14634
  }
14366
14635
  return false;
14367
14636
  }
14637
+ /**
14638
+ * Helper function that determines if a given node is within a skip hydration block
14639
+ * by navigating up the TNode tree to see if any parent nodes have skip hydration
14640
+ * attribute.
14641
+ */
14642
+ function isInSkipHydrationBlock(tNode) {
14643
+ let currentTNode = tNode.parent;
14644
+ while (currentTNode) {
14645
+ if (hasNgSkipHydrationAttr(currentTNode)) {
14646
+ return true;
14647
+ }
14648
+ currentTNode = currentTNode.parent;
14649
+ }
14650
+ return false;
14651
+ }
14368
14652
 
14369
14653
  /**
14370
14654
  * Update a property on a selected element.
@@ -14450,7 +14734,7 @@ function ɵɵelementStart(index, name, attrsIndex, localRefsIndex) {
14450
14734
  const tNode = tView.firstCreatePass ?
14451
14735
  elementStartFirstCreatePass(adjustedIndex, tView, lView, name, attrsIndex, localRefsIndex) :
14452
14736
  tView.data[adjustedIndex];
14453
- const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name);
14737
+ const native = _locateOrCreateElementNode(tView, lView, tNode, renderer, name, index);
14454
14738
  lView[adjustedIndex] = native;
14455
14739
  const hasDirectives = isDirectiveHost(tNode);
14456
14740
  if (ngDevMode && tView.firstCreatePass) {
@@ -14533,7 +14817,7 @@ function ɵɵelement(index, name, attrsIndex, localRefsIndex) {
14533
14817
  ɵɵelementEnd();
14534
14818
  return ɵɵelement;
14535
14819
  }
14536
- let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name) => {
14820
+ let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name, index) => {
14537
14821
  lastNodeWasCreated(true);
14538
14822
  return createElementNode(renderer, name, getNamespace$1());
14539
14823
  };
@@ -14541,9 +14825,9 @@ let _locateOrCreateElementNode = (tView, lView, tNode, renderer, name) => {
14541
14825
  * Enables hydration code path (to lookup existing elements in DOM)
14542
14826
  * in addition to the regular creation mode of element nodes.
14543
14827
  */
14544
- function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name) {
14828
+ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name, index) {
14545
14829
  const hydrationInfo = lView[HYDRATION];
14546
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14830
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14547
14831
  lastNodeWasCreated(isNodeCreationMode);
14548
14832
  // Regular creation mode.
14549
14833
  if (isNodeCreationMode) {
@@ -14551,9 +14835,19 @@ function locateOrCreateElementNodeImpl(tView, lView, tNode, renderer, name) {
14551
14835
  }
14552
14836
  // Hydration mode, looking up an existing element in DOM.
14553
14837
  const native = locateNextRNode(hydrationInfo, tView, lView, tNode);
14554
- ngDevMode &&
14555
- validateMatchingNode(native, Node.ELEMENT_NODE, name, lView, tNode);
14838
+ ngDevMode && validateMatchingNode(native, Node.ELEMENT_NODE, name, lView, tNode);
14556
14839
  ngDevMode && markRNodeAsClaimedByHydration(native);
14840
+ // This element might also be an anchor of a view container.
14841
+ if (getSerializedContainerViews(hydrationInfo, index)) {
14842
+ // Important note: this element acts as an anchor, but it's **not** a part
14843
+ // of the embedded view, so we start the segment **after** this element, taking
14844
+ // a reference to the next sibling. For example, the following template:
14845
+ // `<div #vcrTarget>` is represented in the DOM as `<div></div>...<!--container-->`,
14846
+ // so while processing a `<div>` instruction, point to the next sibling as a
14847
+ // start of a segment.
14848
+ ngDevMode && validateNodeExists(native.nextSibling);
14849
+ setSegmentHead(hydrationInfo, index, native.nextSibling);
14850
+ }
14557
14851
  // Checks if the skip hydration attribute is present during hydration so we know to
14558
14852
  // skip attempting to hydrate this block.
14559
14853
  if (hydrationInfo && hasNgSkipHydrationAttr(tNode)) {
@@ -14681,7 +14975,7 @@ let _locateOrCreateElementContainerNode = (tView, lView, tNode, index) => {
14681
14975
  function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
14682
14976
  let comment;
14683
14977
  const hydrationInfo = lView[HYDRATION];
14684
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
14978
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
14685
14979
  lastNodeWasCreated(isNodeCreationMode);
14686
14980
  // Regular creation mode.
14687
14981
  if (isNodeCreationMode) {
@@ -14689,21 +14983,20 @@ function locateOrCreateElementContainerNode(tView, lView, tNode, index) {
14689
14983
  }
14690
14984
  // Hydration mode, looking up existing elements in DOM.
14691
14985
  const currentRNode = locateNextRNode(hydrationInfo, tView, lView, tNode);
14986
+ ngDevMode && validateNodeExists(currentRNode);
14692
14987
  const ngContainerSize = getNgContainerSize(hydrationInfo, index);
14693
14988
  ngDevMode &&
14694
14989
  assertNumber(ngContainerSize, 'Unexpected state: hydrating an <ng-container>, ' +
14695
14990
  'but no hydration info is available.');
14696
- if (ngContainerSize > 0) {
14697
- storeNgContainerInfo(hydrationInfo, index, currentRNode);
14698
- comment = siblingAfter(ngContainerSize, currentRNode);
14699
- }
14700
- else {
14701
- // If <ng-container> has no nodes,
14702
- // the current node is an anchor (comment) node.
14703
- comment = currentRNode;
14991
+ // If this container is non-empty, store the first node as a segment head,
14992
+ // otherwise, this node is an anchor and segment head doesn't exist (thus `null`).
14993
+ const segmentHead = ngContainerSize > 0 ? currentRNode : null;
14994
+ setSegmentHead(hydrationInfo, index, segmentHead);
14995
+ comment = siblingAfter(ngContainerSize, currentRNode);
14996
+ if (ngDevMode) {
14997
+ validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14998
+ markRNodeAsClaimedByHydration(comment);
14704
14999
  }
14705
- ngDevMode && validateMatchingNode(comment, Node.COMMENT_NODE, null, lView, tNode);
14706
- ngDevMode && markRNodeAsClaimedByHydration(comment);
14707
15000
  return comment;
14708
15001
  }
14709
15002
  function enableLocateOrCreateElementContainerNodeImpl() {
@@ -17061,7 +17354,7 @@ let _locateOrCreateTextNode = (tView, lView, tNode, value) => {
17061
17354
  */
17062
17355
  function locateOrCreateTextNodeImpl(tView, lView, tNode, value) {
17063
17356
  const hydrationInfo = lView[HYDRATION];
17064
- const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock();
17357
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock$1();
17065
17358
  lastNodeWasCreated(isNodeCreationMode);
17066
17359
  // Regular creation mode.
17067
17360
  if (isNodeCreationMode) {
@@ -20729,7 +21022,7 @@ class NgModuleFactory$1 {
20729
21022
  * @publicApi
20730
21023
  */
20731
21024
  function createNgModule(ngModule, parentInjector) {
20732
- return new NgModuleRef(ngModule, parentInjector !== null && parentInjector !== void 0 ? parentInjector : null);
21025
+ return new NgModuleRef(ngModule, parentInjector !== null && parentInjector !== void 0 ? parentInjector : null, []);
20733
21026
  }
20734
21027
  /**
20735
21028
  * The `createNgModule` function alias for backwards-compatibility.
@@ -20739,7 +21032,7 @@ function createNgModule(ngModule, parentInjector) {
20739
21032
  */
20740
21033
  const createNgModuleRef = createNgModule;
20741
21034
  class NgModuleRef extends NgModuleRef$1 {
20742
- constructor(ngModuleType, _parent) {
21035
+ constructor(ngModuleType, _parent, additionalProviders) {
20743
21036
  super();
20744
21037
  this._parent = _parent;
20745
21038
  // tslint:disable-next-line:require-internal-with-underscore
@@ -20760,7 +21053,8 @@ class NgModuleRef extends NgModuleRef$1 {
20760
21053
  { provide: NgModuleRef$1, useValue: this }, {
20761
21054
  provide: ComponentFactoryResolver$1,
20762
21055
  useValue: this.componentFactoryResolver
20763
- }
21056
+ },
21057
+ ...additionalProviders
20764
21058
  ], stringify(ngModuleType), new Set(['environment']));
20765
21059
  // We need to resolve the injector types separately from the injector creation, because
20766
21060
  // the module might be trying to use this ref in its constructor for DI which will cause a
@@ -20789,9 +21083,12 @@ class NgModuleFactory extends NgModuleFactory$1 {
20789
21083
  this.moduleType = moduleType;
20790
21084
  }
20791
21085
  create(parentInjector) {
20792
- return new NgModuleRef(this.moduleType, parentInjector);
21086
+ return new NgModuleRef(this.moduleType, parentInjector, []);
20793
21087
  }
20794
21088
  }
21089
+ function createNgModuleRefWithProviders(moduleType, parentInjector, additionalProviders) {
21090
+ return new NgModuleRef(moduleType, parentInjector, additionalProviders);
21091
+ }
20795
21092
  class EnvironmentNgModuleRefAdapter extends NgModuleRef$1 {
20796
21093
  constructor(providers, parent, source) {
20797
21094
  super();
@@ -21239,7 +21536,8 @@ function sortListeners(a, b) {
21239
21536
  * See call site for more info.
21240
21537
  */
21241
21538
  function isDirectiveDefHack(obj) {
21242
- return obj.type !== undefined && obj.template !== undefined && obj.declaredInputs !== undefined;
21539
+ return obj.type !== undefined && obj.declaredInputs !== undefined &&
21540
+ obj.findHostDirectiveDefs !== undefined;
21243
21541
  }
21244
21542
  /**
21245
21543
  * Retrieve the component `LView` from component/element.
@@ -22077,9 +22375,25 @@ const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
22077
22375
  this._declarationTContainer = _declarationTContainer;
22078
22376
  this.elementRef = elementRef;
22079
22377
  }
22378
+ /**
22379
+ * Returns an `ssrId` associated with a TView, which was used to
22380
+ * create this instance of the `TemplateRef`.
22381
+ *
22382
+ * @internal
22383
+ */
22384
+ get ssrId() {
22385
+ var _a;
22386
+ return ((_a = this._declarationTContainer.tView) === null || _a === void 0 ? void 0 : _a.ssrId) || null;
22387
+ }
22080
22388
  createEmbeddedView(context, injector) {
22389
+ return this.createEmbeddedViewImpl(context, injector, null);
22390
+ }
22391
+ /**
22392
+ * @internal
22393
+ */
22394
+ createEmbeddedViewImpl(context, injector, hydrationInfo) {
22081
22395
  const embeddedTView = this._declarationTContainer.tView;
22082
- const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null, null);
22396
+ const embeddedLView = createLView(this._declarationLView, embeddedTView, context, 16 /* LViewFlags.CheckAlways */, null, embeddedTView.declTNode, null, null, null, null, injector || null, hydrationInfo || null);
22083
22397
  const declarationLContainer = this._declarationLView[this._declarationTContainer.index];
22084
22398
  ngDevMode && assertLContainer(declarationLContainer);
22085
22399
  embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
@@ -22114,6 +22428,114 @@ function createTemplateRef(hostTNode, hostLView) {
22114
22428
  return null;
22115
22429
  }
22116
22430
 
22431
+ /**
22432
+ * Removes all dehydrated views from a given LContainer:
22433
+ * both in internal data structure, as well as removing
22434
+ * corresponding DOM nodes that belong to that dehydrated view.
22435
+ */
22436
+ function removeDehydratedViews(lContainer) {
22437
+ var _a;
22438
+ const views = (_a = lContainer[DEHYDRATED_VIEWS]) !== null && _a !== void 0 ? _a : [];
22439
+ const parentLView = lContainer[PARENT];
22440
+ const renderer = parentLView[RENDERER];
22441
+ for (const view of views) {
22442
+ removeDehydratedView(view, renderer);
22443
+ ngDevMode && ngDevMode.dehydratedViewsRemoved++;
22444
+ }
22445
+ // Reset the value to an empty array to indicate that no
22446
+ // further processing of dehydrated views is needed for
22447
+ // this view container (i.e. do not trigger the lookup process
22448
+ // once again in case a `ViewContainerRef` is created later).
22449
+ lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
22450
+ }
22451
+ /**
22452
+ * Helper function to remove all nodes from a dehydrated view.
22453
+ */
22454
+ function removeDehydratedView(dehydratedView, renderer) {
22455
+ let nodesRemoved = 0;
22456
+ let currentRNode = dehydratedView.firstChild;
22457
+ if (currentRNode) {
22458
+ const numNodes = dehydratedView.data[NUM_ROOT_NODES];
22459
+ while (nodesRemoved < numNodes) {
22460
+ ngDevMode && validateSiblingNodeExists(currentRNode);
22461
+ const nextSibling = currentRNode.nextSibling;
22462
+ nativeRemoveNode(renderer, currentRNode, false);
22463
+ currentRNode = nextSibling;
22464
+ nodesRemoved++;
22465
+ }
22466
+ }
22467
+ }
22468
+
22469
+ /**
22470
+ * Given a current DOM node and a serialized information about the views
22471
+ * in a container, walks over the DOM structure, collecting the list of
22472
+ * dehydrated views.
22473
+ */
22474
+ function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
22475
+ const dehydratedViews = [];
22476
+ for (const serializedView of serializedViews) {
22477
+ const view = {
22478
+ data: serializedView,
22479
+ firstChild: null,
22480
+ };
22481
+ if (serializedView[NUM_ROOT_NODES] > 0) {
22482
+ // Keep reference to the first node in this view,
22483
+ // so it can be accessed while invoking template instructions.
22484
+ view.firstChild = currentRNode;
22485
+ // Move over to the next node after this view, which can
22486
+ // either be a first node of the next view or an anchor comment
22487
+ // node after the last view in a container.
22488
+ currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
22489
+ }
22490
+ dehydratedViews.push(view);
22491
+ }
22492
+ return [currentRNode, dehydratedViews];
22493
+ }
22494
+ /**
22495
+ * Reference to a function that searches for a matching dehydrated views
22496
+ * stored on a given lContainer.
22497
+ * Returns `null` by default, when hydration is not enabled.
22498
+ */
22499
+ let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
22500
+ /**
22501
+ * Retrieves the next dehydrated view from the LContainer and verifies that
22502
+ * it matches a given template id (from the TView that was used to create this
22503
+ * instance of a view). If the id doesn't match, that means that we are in an
22504
+ * unexpected state and can not complete the reconciliation process. Thus,
22505
+ * all dehydrated views from this LContainer are removed (including corresponding
22506
+ * DOM nodes) and the rendering is performed as if there were no dehydrated views
22507
+ * in this container.
22508
+ */
22509
+ function findMatchingDehydratedViewImpl(lContainer, template) {
22510
+ var _a;
22511
+ const views = (_a = lContainer[DEHYDRATED_VIEWS]) !== null && _a !== void 0 ? _a : [];
22512
+ if (!template || views.length === 0) {
22513
+ return null;
22514
+ }
22515
+ const view = views[0];
22516
+ // Verify whether the first dehydrated view in the container matches
22517
+ // the template id passed to this function (that originated from a TView
22518
+ // that was used to create an instance of an embedded or component views.
22519
+ if (view.data[TEMPLATE_ID] === template) {
22520
+ // If the template id matches - extract the first view and return it.
22521
+ return views.shift();
22522
+ }
22523
+ else {
22524
+ // Otherwise, we are at the state when reconciliation can not be completed,
22525
+ // thus we remove all dehydrated views within this container (remove them
22526
+ // from internal data structures as well as delete associated elements from
22527
+ // the DOM tree).
22528
+ removeDehydratedViews(lContainer);
22529
+ return null;
22530
+ }
22531
+ }
22532
+ function enableFindMatchingDehydratedViewImpl() {
22533
+ _findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
22534
+ }
22535
+ function findMatchingDehydratedView(lContainer, template) {
22536
+ return _findMatchingDehydratedViewImpl(lContainer, template);
22537
+ }
22538
+
22117
22539
  /**
22118
22540
  * Represents a container where one or more views can be attached to a component.
22119
22541
  *
@@ -22198,11 +22620,13 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
22198
22620
  index = indexOrOptions.index;
22199
22621
  injector = indexOrOptions.injector;
22200
22622
  }
22201
- const viewRef = templateRef.createEmbeddedView(context || {}, injector);
22202
- this.insert(viewRef, index);
22623
+ const hydrationInfo = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
22624
+ const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, hydrationInfo);
22625
+ this.insertImpl(viewRef, index, !!hydrationInfo);
22203
22626
  return viewRef;
22204
22627
  }
22205
22628
  createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
22629
+ var _a, _b, _c;
22206
22630
  const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
22207
22631
  let index;
22208
22632
  // This function supports 2 signatures and we need to handle options correctly for both:
@@ -22269,11 +22693,17 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
22269
22693
  environmentInjector = result;
22270
22694
  }
22271
22695
  }
22272
- const componentRef = componentFactory.create(contextInjector, projectableNodes, undefined, environmentInjector);
22273
- this.insert(componentRef.hostView, index);
22696
+ const componentDef = getComponentDef$1((_a = componentFactory.componentType) !== null && _a !== void 0 ? _a : {});
22697
+ const dehydratedView = findMatchingDehydratedView(this._lContainer, (_b = componentDef === null || componentDef === void 0 ? void 0 : componentDef.id) !== null && _b !== void 0 ? _b : null);
22698
+ const rNode = (_c = dehydratedView === null || dehydratedView === void 0 ? void 0 : dehydratedView.firstChild) !== null && _c !== void 0 ? _c : null;
22699
+ const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
22700
+ this.insertImpl(componentRef.hostView, index, !!dehydratedView);
22274
22701
  return componentRef;
22275
22702
  }
22276
22703
  insert(viewRef, index) {
22704
+ return this.insertImpl(viewRef, index, false);
22705
+ }
22706
+ insertImpl(viewRef, index, skipDomInsertion) {
22277
22707
  const lView = viewRef._lView;
22278
22708
  const tView = lView[TVIEW];
22279
22709
  if (ngDevMode && viewRef.destroyed) {
@@ -22304,11 +22734,13 @@ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
22304
22734
  const lContainer = this._lContainer;
22305
22735
  insertView(tView, lView, lContainer, adjustedIdx);
22306
22736
  // Physical operation of adding the DOM nodes.
22307
- const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
22308
- const renderer = lView[RENDERER];
22309
- const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
22310
- if (parentRNode !== null) {
22311
- addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
22737
+ if (!skipDomInsertion) {
22738
+ const beforeNode = getBeforeNodeForView(adjustedIdx, lContainer);
22739
+ const renderer = lView[RENDERER];
22740
+ const parentRNode = nativeParentNode(renderer, lContainer[NATIVE]);
22741
+ if (parentRNode !== null) {
22742
+ addViewToContainer(tView, lContainer[T_HOST], renderer, lView, parentRNode, beforeNode);
22743
+ }
22312
22744
  }
22313
22745
  viewRef.attachToViewContainerRef();
22314
22746
  addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
@@ -22365,8 +22797,6 @@ function getOrCreateViewRefs(lContainer) {
22365
22797
  /**
22366
22798
  * Creates a ViewContainerRef and stores it on the injector.
22367
22799
  *
22368
- * @param ViewContainerRefToken The ViewContainerRef type
22369
- * @param ElementRefToken The ElementRef type
22370
22800
  * @param hostTNode The node that is requesting a ViewContainerRef
22371
22801
  * @param hostLView The view to which the node belongs
22372
22802
  * @returns The ViewContainerRef instance to use
@@ -22380,31 +22810,95 @@ function createContainerRef(hostTNode, hostLView) {
22380
22810
  lContainer = slotValue;
22381
22811
  }
22382
22812
  else {
22383
- let commentNode;
22384
- // If the host is an element container, the native host element is guaranteed to be a
22385
- // comment and we can reuse that comment as anchor element for the new LContainer.
22386
- // The comment node in question is already part of the DOM structure so we don't need to append
22387
- // it again.
22388
- if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
22389
- commentNode = unwrapRNode(slotValue);
22390
- }
22391
- else {
22392
- // If the host is a regular element, we have to insert a comment node manually which will
22393
- // be used as an anchor when inserting elements. In this specific case we use low-level DOM
22394
- // manipulation to insert it.
22395
- const renderer = hostLView[RENDERER];
22396
- ngDevMode && ngDevMode.rendererCreateComment++;
22397
- commentNode = renderer.createComment(ngDevMode ? 'container' : '');
22398
- const hostNative = getNativeByTNode(hostTNode, hostLView);
22399
- const parentOfHostNative = nativeParentNode(renderer, hostNative);
22400
- nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
22401
- }
22402
- hostLView[hostTNode.index] = lContainer =
22403
- createLContainer(slotValue, hostLView, commentNode, hostTNode);
22813
+ // An LContainer anchor can not be `null`, but we set it here temporarily
22814
+ // and update to the actual value later in this function (see
22815
+ // `_locateOrCreateAnchorNode`).
22816
+ lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
22817
+ hostLView[hostTNode.index] = lContainer;
22404
22818
  addToViewTree(hostLView, lContainer);
22405
22819
  }
22820
+ _locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
22406
22821
  return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
22407
22822
  }
22823
+ /**
22824
+ * Creates and inserts a comment node that acts as an anchor for a view container.
22825
+ *
22826
+ * If the host is a regular element, we have to insert a comment node manually which will
22827
+ * be used as an anchor when inserting elements. In this specific case we use low-level DOM
22828
+ * manipulation to insert it.
22829
+ */
22830
+ function insertAnchorNode(hostLView, hostTNode) {
22831
+ const renderer = hostLView[RENDERER];
22832
+ ngDevMode && ngDevMode.rendererCreateComment++;
22833
+ const commentNode = renderer.createComment(ngDevMode ? 'container' : '');
22834
+ const hostNative = getNativeByTNode(hostTNode, hostLView);
22835
+ const parentOfHostNative = nativeParentNode(renderer, hostNative);
22836
+ nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
22837
+ return commentNode;
22838
+ }
22839
+ let _locateOrCreateAnchorNode = createAnchorNode;
22840
+ /**
22841
+ * Regular creation mode: an anchor is created and
22842
+ * assigned to the `lContainer[NATIVE]` slot.
22843
+ */
22844
+ function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
22845
+ // We already have a native element (anchor) set, return.
22846
+ if (lContainer[NATIVE])
22847
+ return;
22848
+ let commentNode;
22849
+ // If the host is an element container, the native host element is guaranteed to be a
22850
+ // comment and we can reuse that comment as anchor element for the new LContainer.
22851
+ // The comment node in question is already part of the DOM structure so we don't need to append
22852
+ // it again.
22853
+ if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
22854
+ commentNode = unwrapRNode(slotValue);
22855
+ }
22856
+ else {
22857
+ commentNode = insertAnchorNode(hostLView, hostTNode);
22858
+ }
22859
+ lContainer[NATIVE] = commentNode;
22860
+ }
22861
+ /**
22862
+ * Hydration logic that looks up:
22863
+ * - an anchor node in the DOM and stores the node in `lContainer[NATIVE]`
22864
+ * - all dehydrated views in this container and puts them into `lContainer[DEHYDRATED_VIEWS]`
22865
+ */
22866
+ function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
22867
+ var _a;
22868
+ // We already have a native element (anchor) set and the process
22869
+ // of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
22870
+ // is not null), exit early.
22871
+ if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS])
22872
+ return;
22873
+ const hydrationInfo = hostLView[HYDRATION];
22874
+ const isNodeCreationMode = !hydrationInfo || isInSkipHydrationBlock(hostTNode);
22875
+ // Regular creation mode.
22876
+ if (isNodeCreationMode) {
22877
+ return createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
22878
+ }
22879
+ // Hydration mode, looking up an anchor node and dehydrated views in DOM.
22880
+ const index = hostTNode.index - HEADER_OFFSET;
22881
+ const currentRNode = getSegmentHead(hydrationInfo, index);
22882
+ const serializedViews = (_a = hydrationInfo.data[CONTAINERS]) === null || _a === void 0 ? void 0 : _a[index];
22883
+ ngDevMode &&
22884
+ assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
22885
+ 'which represents a view container.');
22886
+ const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
22887
+ if (ngDevMode) {
22888
+ validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, hostTNode);
22889
+ // Do not throw in case this node is already claimed (thus `false` as a second
22890
+ // argument). If this container is created based on an `<ng-template>`, the comment
22891
+ // node would be already claimed from the `template` instruction. If an element acts
22892
+ // as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
22893
+ // so we need to claim it here.
22894
+ markRNodeAsClaimedByHydration(commentNode, false);
22895
+ }
22896
+ lContainer[NATIVE] = commentNode;
22897
+ lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
22898
+ }
22899
+ function enableLocateOrCreateContainerRefImpl() {
22900
+ _locateOrCreateAnchorNode = locateOrCreateAnchorNode;
22901
+ }
22408
22902
 
22409
22903
  class LQuery_ {
22410
22904
  constructor(queryList) {
@@ -23382,6 +23876,7 @@ function resetCompiledComponents() {
23382
23876
  ownerNgModule = new WeakMap();
23383
23877
  verifiedNgModule = new WeakMap();
23384
23878
  moduleQueue.length = 0;
23879
+ GENERATED_COMP_IDS.clear();
23385
23880
  }
23386
23881
  /**
23387
23882
  * Computes the combined declarations of explicit declarations, as well as declarations inherited by
@@ -23972,7 +24467,7 @@ class TestBedCompiler {
23972
24467
  // every component.
23973
24468
  this.componentToModuleScope.clear();
23974
24469
  const parentInjector = this.platform.injector;
23975
- this.testModuleRef = new ɵRender3NgModuleRef(this.testModuleType, parentInjector);
24470
+ this.testModuleRef = new ɵRender3NgModuleRef(this.testModuleType, parentInjector, []);
23976
24471
  // ApplicationInitStatus.runInitializers() is marked @internal to core.
23977
24472
  // Cast it to any before accessing it.
23978
24473
  this.testModuleRef.injector.get(ApplicationInitStatus).runInitializers();
@@ -24400,7 +24895,7 @@ class TestBedCompiler {
24400
24895
  });
24401
24896
  const ngZone = new NgZone({ enableLongStackTrace: true });
24402
24897
  const providers = [
24403
- { provide: NgZone, useValue: ngZone },
24898
+ ɵprovideNgZoneChangeDetection(ngZone),
24404
24899
  { provide: Compiler, useFactory: () => new R3TestCompiler(this) },
24405
24900
  ...this.providers,
24406
24901
  ...this.providerOverrides,