@angular/core 17.0.0-next.2 → 17.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 (47) hide show
  1. package/esm2022/src/core_render3_private_export.mjs +2 -2
  2. package/esm2022/src/hydration/annotate.mjs +9 -6
  3. package/esm2022/src/hydration/cleanup.mjs +2 -2
  4. package/esm2022/src/linker/template_ref.mjs +3 -3
  5. package/esm2022/src/linker/view_container_ref.mjs +80 -25
  6. package/esm2022/src/render3/after_render_hooks.mjs +69 -41
  7. package/esm2022/src/render3/component.mjs +4 -3
  8. package/esm2022/src/render3/di.mjs +1 -1
  9. package/esm2022/src/render3/index.mjs +2 -2
  10. package/esm2022/src/render3/instructions/all.mjs +2 -1
  11. package/esm2022/src/render3/instructions/change_detection.mjs +5 -6
  12. package/esm2022/src/render3/instructions/component_instance.mjs +23 -0
  13. package/esm2022/src/render3/instructions/control_flow.mjs +20 -4
  14. package/esm2022/src/render3/instructions/defer.mjs +100 -39
  15. package/esm2022/src/render3/instructions/shared.mjs +20 -14
  16. package/esm2022/src/render3/interfaces/defer.mjs +1 -1
  17. package/esm2022/src/render3/interfaces/injector.mjs +1 -1
  18. package/esm2022/src/render3/interfaces/node.mjs +16 -1
  19. package/esm2022/src/render3/interfaces/styling.mjs +4 -7
  20. package/esm2022/src/render3/jit/environment.mjs +2 -1
  21. package/esm2022/src/render3/node_manipulation.mjs +4 -3
  22. package/esm2022/src/render3/reactive_lview_consumer.mjs +25 -45
  23. package/esm2022/src/render3/reactivity/effect.mjs +8 -8
  24. package/esm2022/src/render3/util/injector_utils.mjs +1 -1
  25. package/esm2022/src/render3/view_manipulation.mjs +13 -2
  26. package/esm2022/src/signals/index.mjs +4 -4
  27. package/esm2022/src/signals/src/api.mjs +2 -11
  28. package/esm2022/src/signals/src/computed.mjs +43 -93
  29. package/esm2022/src/signals/src/graph.mjs +238 -162
  30. package/esm2022/src/signals/src/signal.mjs +59 -79
  31. package/esm2022/src/signals/src/watch.mjs +38 -52
  32. package/esm2022/src/signals/src/weak_ref.mjs +2 -29
  33. package/esm2022/src/util/security/trusted_type_defs.mjs +1 -1
  34. package/esm2022/src/util/security/trusted_types.mjs +1 -1
  35. package/esm2022/src/version.mjs +1 -1
  36. package/esm2022/src/zone/ng_zone.mjs +16 -1
  37. package/esm2022/testing/src/logger.mjs +3 -3
  38. package/fesm2022/core.mjs +1977 -1815
  39. package/fesm2022/core.mjs.map +1 -1
  40. package/fesm2022/rxjs-interop.mjs +1 -1
  41. package/fesm2022/testing.mjs +1 -1
  42. package/index.d.ts +143 -125
  43. package/package.json +1 -1
  44. package/rxjs-interop/index.d.ts +1 -1
  45. package/schematics/ng-generate/standalone-migration/bundle.js +192 -53
  46. package/schematics/ng-generate/standalone-migration/bundle.js.map +3 -3
  47. package/testing/index.d.ts +1 -1
package/fesm2022/core.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v17.0.0-next.2
2
+ * @license Angular v17.0.0-next.3
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2273,15 +2273,6 @@ const SIGNAL = Symbol('SIGNAL');
2273
2273
  function isSignal(value) {
2274
2274
  return typeof value === 'function' && value[SIGNAL] !== undefined;
2275
2275
  }
2276
- /**
2277
- * Converts `fn` into a marked signal function (where `isSignal(fn)` will be `true`), and
2278
- * potentially add some set of extra properties (passed as an object record `extraApi`).
2279
- */
2280
- function createSignalFromFunction(node, fn, extraApi = {}) {
2281
- fn[SIGNAL] = node;
2282
- // Copy properties from `extraApi` to `fn` to complete the desired API of the `Signal`.
2283
- return Object.assign(fn, extraApi);
2284
- }
2285
2276
  /**
2286
2277
  * The default equality function used for `signal` and `computed`, which treats objects and arrays
2287
2278
  * as never equal, and all other primitive values using identity semantics.
@@ -2302,216 +2293,265 @@ function defaultEquals(a, b) {
2302
2293
 
2303
2294
  // Required as the signals library is in a separate package, so we need to explicitly ensure the
2304
2295
  /**
2305
- * A `WeakRef`-compatible reference that fakes the API with a strong reference
2306
- * internally.
2296
+ * The currently active consumer `ReactiveNode`, if running code in a reactive context.
2297
+ *
2298
+ * Change this via `setActiveConsumer`.
2299
+ */
2300
+ let activeConsumer = null;
2301
+ let inNotificationPhase = false;
2302
+ function setActiveConsumer(consumer) {
2303
+ const prev = activeConsumer;
2304
+ activeConsumer = consumer;
2305
+ return prev;
2306
+ }
2307
+ const REACTIVE_NODE = {
2308
+ version: 0,
2309
+ dirty: false,
2310
+ producerNode: undefined,
2311
+ producerLastReadVersion: undefined,
2312
+ producerIndexOfThis: undefined,
2313
+ nextProducerIndex: 0,
2314
+ liveConsumerNode: undefined,
2315
+ liveConsumerIndexOfThis: undefined,
2316
+ consumerAllowSignalWrites: false,
2317
+ consumerIsAlwaysLive: false,
2318
+ producerMustRecompute: () => false,
2319
+ producerRecomputeValue: () => { },
2320
+ consumerMarkedDirty: () => { },
2321
+ };
2322
+ /**
2323
+ * Called by implementations when a producer's signal is read.
2307
2324
  */
2308
- class LeakyRef {
2309
- constructor(ref) {
2310
- this.ref = ref;
2325
+ function producerAccessed(node) {
2326
+ if (inNotificationPhase) {
2327
+ throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ?
2328
+ `Assertion error: signal read during notification phase` :
2329
+ '');
2311
2330
  }
2312
- deref() {
2313
- return this.ref;
2331
+ if (activeConsumer === null) {
2332
+ // Accessed outside of a reactive context, so nothing to record.
2333
+ return;
2314
2334
  }
2315
- }
2316
- // `WeakRef` is not always defined in every TS environment where Angular is compiled. Instead,
2317
- // read it off of the global context if available.
2318
- // tslint:disable-next-line: no-toplevel-property-access
2319
- let WeakRefImpl = _global['WeakRef'] ?? LeakyRef;
2320
- function newWeakRef(value) {
2321
- if (typeof ngDevMode !== 'undefined' && ngDevMode && WeakRefImpl === undefined) {
2322
- throw new Error(`Angular requires a browser which supports the 'WeakRef' API`);
2335
+ // This producer is the `idx`th dependency of `activeConsumer`.
2336
+ const idx = activeConsumer.nextProducerIndex++;
2337
+ assertConsumerNode(activeConsumer);
2338
+ if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) {
2339
+ // There's been a change in producers since the last execution of `activeConsumer`.
2340
+ // `activeConsumer.producerNode[idx]` holds a stale dependency which will be be removed and
2341
+ // replaced with `this`.
2342
+ //
2343
+ // If `activeConsumer` isn't live, then this is a no-op, since we can replace the producer in
2344
+ // `activeConsumer.producerNode` directly. However, if `activeConsumer` is live, then we need
2345
+ // to remove it from the stale producer's `liveConsumer`s.
2346
+ if (consumerIsLive(activeConsumer)) {
2347
+ const staleProducer = activeConsumer.producerNode[idx];
2348
+ producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]);
2349
+ // At this point, the only record of `staleProducer` is the reference at
2350
+ // `activeConsumer.producerNode[idx]` which will be overwritten below.
2351
+ }
2323
2352
  }
2324
- return new WeakRefImpl(value);
2325
- }
2326
- function setAlternateWeakRefImpl(impl) {
2327
- // no-op since the alternate impl is included by default by the framework. Remove once internal
2328
- // migration is complete.
2353
+ if (activeConsumer.producerNode[idx] !== node) {
2354
+ // We're a new dependency of the consumer (at `idx`).
2355
+ activeConsumer.producerNode[idx] = node;
2356
+ // If the active consumer is live, then add it as a live consumer. If not, then use 0 as a
2357
+ // placeholder value.
2358
+ activeConsumer.producerIndexOfThis[idx] =
2359
+ consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0;
2360
+ }
2361
+ activeConsumer.producerLastReadVersion[idx] = node.version;
2329
2362
  }
2330
-
2331
- // Required as the signals library is in a separate package, so we need to explicitly ensure the
2332
2363
  /**
2333
- * Counter tracking the next `ProducerId` or `ConsumerId`.
2364
+ * Ensure this producer's `version` is up-to-date.
2334
2365
  */
2335
- let _nextReactiveId = 0;
2366
+ function producerUpdateValueVersion(node) {
2367
+ if (consumerIsLive(node) && !node.dirty) {
2368
+ // A live consumer will be marked dirty by producers, so a clean state means that its version
2369
+ // is guaranteed to be up-to-date.
2370
+ return;
2371
+ }
2372
+ if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) {
2373
+ // None of our producers report a change since the last time they were read, so no
2374
+ // recomputation of our value is necessary, and we can consider ourselves clean.
2375
+ node.dirty = false;
2376
+ return;
2377
+ }
2378
+ node.producerRecomputeValue(node);
2379
+ // After recomputing the value, we're no longer dirty.
2380
+ node.dirty = false;
2381
+ }
2336
2382
  /**
2337
- * Tracks the currently active reactive consumer (or `null` if there is no active
2338
- * consumer).
2383
+ * Propagate a dirty notification to live consumers of this producer.
2339
2384
  */
2340
- let activeConsumer = null;
2385
+ function producerNotifyConsumers(node) {
2386
+ if (node.liveConsumerNode === undefined) {
2387
+ return;
2388
+ }
2389
+ // Prevent signal reads when we're updating the graph
2390
+ const prev = inNotificationPhase;
2391
+ inNotificationPhase = true;
2392
+ try {
2393
+ for (const consumer of node.liveConsumerNode) {
2394
+ if (!consumer.dirty) {
2395
+ consumerMarkDirty(consumer);
2396
+ }
2397
+ }
2398
+ }
2399
+ finally {
2400
+ inNotificationPhase = prev;
2401
+ }
2402
+ }
2341
2403
  /**
2342
- * Whether the graph is currently propagating change notifications.
2404
+ * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
2405
+ * based on the current consumer context.
2343
2406
  */
2344
- let inNotificationPhase = false;
2345
- function setActiveConsumer(consumer) {
2346
- const prev = activeConsumer;
2347
- activeConsumer = consumer;
2348
- return prev;
2407
+ function producerUpdatesAllowed() {
2408
+ return activeConsumer?.consumerAllowSignalWrites !== false;
2409
+ }
2410
+ function consumerMarkDirty(node) {
2411
+ node.dirty = true;
2412
+ producerNotifyConsumers(node);
2413
+ node.consumerMarkedDirty?.(node);
2349
2414
  }
2350
2415
  /**
2351
- * A node in the reactive graph.
2352
- *
2353
- * Nodes can be producers of reactive values, consumers of other reactive values, or both.
2354
- *
2355
- * Producers are nodes that produce values, and can be depended upon by consumer nodes.
2356
- *
2357
- * Producers expose a monotonic `valueVersion` counter, and are responsible for incrementing this
2358
- * version when their value semantically changes. Some producers may produce their values lazily and
2359
- * thus at times need to be polled for potential updates to their value (and by extension their
2360
- * `valueVersion`). This is accomplished via the `onProducerUpdateValueVersion` method for
2361
- * implemented by producers, which should perform whatever calculations are necessary to ensure
2362
- * `valueVersion` is up to date.
2416
+ * Prepare this consumer to run a computation in its reactive context.
2363
2417
  *
2364
- * Consumers are nodes that depend on the values of producers and are notified when those values
2365
- * might have changed.
2366
- *
2367
- * Consumers do not wrap the reads they consume themselves, but rather can be set as the active
2368
- * reader via `setActiveConsumer`. Reads of producers that happen while a consumer is active will
2369
- * result in those producers being added as dependencies of that consumer node.
2370
- *
2371
- * The set of dependencies of a consumer is dynamic. Implementers expose a monotonically increasing
2372
- * `trackingVersion` counter, which increments whenever the consumer is about to re-run any reactive
2373
- * reads it needs and establish a new set of dependencies as a result.
2418
+ * Must be called by subclasses which represent reactive computations, before those computations
2419
+ * begin.
2420
+ */
2421
+ function consumerBeforeComputation(node) {
2422
+ node && (node.nextProducerIndex = 0);
2423
+ return setActiveConsumer(node);
2424
+ }
2425
+ /**
2426
+ * Finalize this consumer's state after a reactive computation has run.
2374
2427
  *
2375
- * Producers store the last `trackingVersion` they've seen from `Consumer`s which have read them.
2376
- * This allows a producer to identify whether its record of the dependency is current or stale, by
2377
- * comparing the consumer's `trackingVersion` to the version at which the dependency was
2378
- * last observed.
2428
+ * Must be called by subclasses which represent reactive computations, after those computations
2429
+ * have finished.
2379
2430
  */
2380
- class ReactiveNode {
2381
- constructor() {
2382
- this.id = _nextReactiveId++;
2383
- /**
2384
- * A cached weak reference to this node, which will be used in `ReactiveEdge`s.
2385
- */
2386
- this.ref = newWeakRef(this);
2387
- /**
2388
- * Edges to producers on which this node depends (in its consumer capacity).
2389
- */
2390
- this.producers = new Map();
2391
- /**
2392
- * Edges to consumers on which this node depends (in its producer capacity).
2393
- */
2394
- this.consumers = new Map();
2395
- /**
2396
- * Monotonically increasing counter representing a version of this `Consumer`'s
2397
- * dependencies.
2398
- */
2399
- this.trackingVersion = 0;
2400
- /**
2401
- * Monotonically increasing counter which increases when the value of this `Producer`
2402
- * semantically changes.
2403
- */
2404
- this.valueVersion = 0;
2431
+ function consumerAfterComputation(node, prevConsumer) {
2432
+ setActiveConsumer(prevConsumer);
2433
+ if (!node || node.producerNode === undefined || node.producerIndexOfThis === undefined ||
2434
+ node.producerLastReadVersion === undefined) {
2435
+ return;
2405
2436
  }
2406
- /**
2407
- * Polls dependencies of a consumer to determine if they have actually changed.
2408
- *
2409
- * If this returns `false`, then even though the consumer may have previously been notified of a
2410
- * change, the values of its dependencies have not actually changed and the consumer should not
2411
- * rerun any reactions.
2412
- */
2413
- consumerPollProducersForChange() {
2414
- for (const [producerId, edge] of this.producers) {
2415
- const producer = edge.producerNode.deref();
2416
- // On Safari < 16.1 deref can return null, we need to check for null also.
2417
- // See https://github.com/WebKit/WebKit/commit/44c15ba58912faab38b534fef909dd9e13e095e0
2418
- if (producer == null || edge.atTrackingVersion !== this.trackingVersion) {
2419
- // This dependency edge is stale, so remove it.
2420
- this.producers.delete(producerId);
2421
- producer?.consumers.delete(this.id);
2422
- continue;
2423
- }
2424
- if (producer.producerPollStatus(edge.seenValueVersion)) {
2425
- // One of the dependencies reports a real value change.
2426
- return true;
2427
- }
2437
+ if (consumerIsLive(node)) {
2438
+ // For live consumers, we need to remove the producer -> consumer edge for any stale producers
2439
+ // which weren't dependencies after the recomputation.
2440
+ for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
2441
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
2428
2442
  }
2429
- // No dependency reported a real value change, so the `Consumer` has also not been
2430
- // impacted.
2431
- return false;
2432
2443
  }
2433
- /**
2434
- * Notify all consumers of this producer that its value may have changed.
2435
- */
2436
- producerMayHaveChanged() {
2437
- // Prevent signal reads when we're updating the graph
2438
- const prev = inNotificationPhase;
2439
- inNotificationPhase = true;
2440
- try {
2441
- for (const [consumerId, edge] of this.consumers) {
2442
- const consumer = edge.consumerNode.deref();
2443
- // On Safari < 16.1 deref can return null, we need to check for null also.
2444
- // See https://github.com/WebKit/WebKit/commit/44c15ba58912faab38b534fef909dd9e13e095e0
2445
- if (consumer == null || consumer.trackingVersion !== edge.atTrackingVersion) {
2446
- this.consumers.delete(consumerId);
2447
- consumer?.producers.delete(this.id);
2448
- continue;
2449
- }
2450
- consumer.onConsumerDependencyMayHaveChanged();
2451
- }
2452
- }
2453
- finally {
2454
- inNotificationPhase = prev;
2455
- }
2444
+ // Truncate the producer tracking arrays.
2445
+ for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) {
2446
+ node.producerNode.pop();
2447
+ node.producerLastReadVersion.pop();
2448
+ node.producerIndexOfThis.pop();
2456
2449
  }
2457
- /**
2458
- * Mark that this producer node has been accessed in the current reactive context.
2459
- */
2460
- producerAccessed() {
2461
- if (inNotificationPhase) {
2462
- throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ?
2463
- `Assertion error: signal read during notification phase` :
2464
- '');
2465
- }
2466
- if (activeConsumer === null) {
2467
- return;
2450
+ }
2451
+ /**
2452
+ * Determine whether this consumer has any dependencies which have changed since the last time
2453
+ * they were read.
2454
+ */
2455
+ function consumerPollProducersForChange(node) {
2456
+ assertConsumerNode(node);
2457
+ // Poll producers for change.
2458
+ for (let i = 0; i < node.producerNode.length; i++) {
2459
+ const producer = node.producerNode[i];
2460
+ const seenVersion = node.producerLastReadVersion[i];
2461
+ // First check the versions. A mismatch means that the producer's value is known to have
2462
+ // changed since the last time we read it.
2463
+ if (seenVersion !== producer.version) {
2464
+ return true;
2468
2465
  }
2469
- // Either create or update the dependency `Edge` in both directions.
2470
- let edge = activeConsumer.producers.get(this.id);
2471
- if (edge === undefined) {
2472
- edge = {
2473
- consumerNode: activeConsumer.ref,
2474
- producerNode: this.ref,
2475
- seenValueVersion: this.valueVersion,
2476
- atTrackingVersion: activeConsumer.trackingVersion,
2477
- };
2478
- activeConsumer.producers.set(this.id, edge);
2479
- this.consumers.set(activeConsumer.id, edge);
2466
+ // The producer's version is the same as the last time we read it, but it might itself be
2467
+ // stale. Force the producer to recompute its version (calculating a new value if necessary).
2468
+ producerUpdateValueVersion(producer);
2469
+ // Now when we do this check, `producer.version` is guaranteed to be up to date, so if the
2470
+ // versions still match then it has not changed since the last time we read it.
2471
+ if (seenVersion !== producer.version) {
2472
+ return true;
2480
2473
  }
2481
- else {
2482
- edge.seenValueVersion = this.valueVersion;
2483
- edge.atTrackingVersion = activeConsumer.trackingVersion;
2474
+ }
2475
+ return false;
2476
+ }
2477
+ /**
2478
+ * Disconnect this consumer from the graph.
2479
+ */
2480
+ function consumerDestroy(node) {
2481
+ assertConsumerNode(node);
2482
+ if (consumerIsLive(node)) {
2483
+ // Drop all connections from the graph to this node.
2484
+ for (let i = 0; i < node.producerNode.length; i++) {
2485
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
2484
2486
  }
2485
2487
  }
2486
- /**
2487
- * Whether this consumer currently has any producers registered.
2488
- */
2489
- get hasProducers() {
2490
- return this.producers.size > 0;
2488
+ // Truncate all the arrays to drop all connection from this node to the graph.
2489
+ node.producerNode.length = node.producerLastReadVersion.length = node.producerIndexOfThis.length =
2490
+ 0;
2491
+ if (node.liveConsumerNode) {
2492
+ node.liveConsumerNode.length = node.liveConsumerIndexOfThis.length = 0;
2491
2493
  }
2492
- /**
2493
- * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates,
2494
- * based on the current consumer context.
2495
- */
2496
- get producerUpdatesAllowed() {
2497
- return activeConsumer?.consumerAllowSignalWrites !== false;
2494
+ }
2495
+ /**
2496
+ * Add `consumer` as a live consumer of this node.
2497
+ *
2498
+ * Note that this operation is potentially transitive. If this node becomes live, then it becomes
2499
+ * a live consumer of all of its current producers.
2500
+ */
2501
+ function producerAddLiveConsumer(node, consumer, indexOfThis) {
2502
+ assertProducerNode(node);
2503
+ assertConsumerNode(node);
2504
+ if (node.liveConsumerNode.length === 0) {
2505
+ // When going from 0 to 1 live consumers, we become a live consumer to our producers.
2506
+ for (let i = 0; i < node.producerNode.length; i++) {
2507
+ node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i);
2508
+ }
2498
2509
  }
2499
- /**
2500
- * Checks if a `Producer` has a current value which is different than the value
2501
- * last seen at a specific version by a `Consumer` which recorded a dependency on
2502
- * this `Producer`.
2503
- */
2504
- producerPollStatus(lastSeenValueVersion) {
2505
- // `producer.valueVersion` may be stale, but a mismatch still means that the value
2506
- // last seen by the `Consumer` is also stale.
2507
- if (this.valueVersion !== lastSeenValueVersion) {
2508
- return true;
2510
+ node.liveConsumerIndexOfThis.push(indexOfThis);
2511
+ return node.liveConsumerNode.push(consumer) - 1;
2512
+ }
2513
+ /**
2514
+ * Remove the live consumer at `idx`.
2515
+ */
2516
+ function producerRemoveLiveConsumerAtIndex(node, idx) {
2517
+ assertProducerNode(node);
2518
+ assertConsumerNode(node);
2519
+ if (node.liveConsumerNode.length === 1) {
2520
+ // When removing the last live consumer, we will no longer be live. We need to remove
2521
+ // ourselves from our producers' tracking (which may cause consumer-producers to lose
2522
+ // liveness as well).
2523
+ for (let i = 0; i < node.producerNode.length; i++) {
2524
+ producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]);
2509
2525
  }
2510
- // Trigger the `Producer` to update its `valueVersion` if necessary.
2511
- this.onProducerUpdateValueVersion();
2512
- // At this point, we can trust `producer.valueVersion`.
2513
- return this.valueVersion !== lastSeenValueVersion;
2514
2526
  }
2527
+ // Move the last value of `liveConsumers` into `idx`. Note that if there's only a single
2528
+ // live consumer, this is a no-op.
2529
+ const lastIdx = node.liveConsumerNode.length - 1;
2530
+ node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx];
2531
+ node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx];
2532
+ // Truncate the array.
2533
+ node.liveConsumerNode.length--;
2534
+ node.liveConsumerIndexOfThis.length--;
2535
+ // If the index is still valid, then we need to fix the index pointer from the producer to this
2536
+ // consumer, and update it from `lastIdx` to `idx` (accounting for the move above).
2537
+ if (idx < node.liveConsumerNode.length) {
2538
+ const idxProducer = node.liveConsumerIndexOfThis[idx];
2539
+ const consumer = node.liveConsumerNode[idx];
2540
+ assertConsumerNode(consumer);
2541
+ consumer.producerIndexOfThis[idxProducer] = idx;
2542
+ }
2543
+ }
2544
+ function consumerIsLive(node) {
2545
+ return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0;
2546
+ }
2547
+ function assertConsumerNode(node) {
2548
+ node.producerNode ??= [];
2549
+ node.producerIndexOfThis ??= [];
2550
+ node.producerLastReadVersion ??= [];
2551
+ }
2552
+ function assertProducerNode(node) {
2553
+ node.liveConsumerNode ??= [];
2554
+ node.liveConsumerIndexOfThis ??= [];
2515
2555
  }
2516
2556
 
2517
2557
  /**
@@ -2520,10 +2560,21 @@ class ReactiveNode {
2520
2560
  * @developerPreview
2521
2561
  */
2522
2562
  function computed(computation, options) {
2523
- const node = new ComputedImpl(computation, options?.equal ?? defaultEquals);
2524
- // Casting here is required for g3, as TS inference behavior is slightly different between our
2525
- // version/options and g3's.
2526
- return createSignalFromFunction(node, node.signal.bind(node));
2563
+ const node = Object.create(COMPUTED_NODE);
2564
+ node.computation = computation;
2565
+ options?.equal && (node.equal = options.equal);
2566
+ const computed = () => {
2567
+ // Check if the value needs updating before returning it.
2568
+ producerUpdateValueVersion(node);
2569
+ // Record that someone looked at this signal.
2570
+ producerAccessed(node);
2571
+ if (node.value === ERRORED) {
2572
+ throw node.error;
2573
+ }
2574
+ return node.value;
2575
+ };
2576
+ computed[SIGNAL] = node;
2577
+ return computed;
2527
2578
  }
2528
2579
  /**
2529
2580
  * A dedicated symbol used before a computed value has been calculated for the first time.
@@ -2542,108 +2593,47 @@ const COMPUTING = Symbol('COMPUTING');
2542
2593
  * Explicitly typed as `any` so we can use it as signal's value.
2543
2594
  */
2544
2595
  const ERRORED = Symbol('ERRORED');
2545
- /**
2546
- * A computation, which derives a value from a declarative reactive expression.
2547
- *
2548
- * `Computed`s are both producers and consumers of reactivity.
2549
- */
2550
- class ComputedImpl extends ReactiveNode {
2551
- constructor(computation, equal) {
2552
- super();
2553
- this.computation = computation;
2554
- this.equal = equal;
2555
- /**
2556
- * Current value of the computation.
2557
- *
2558
- * This can also be one of the special values `UNSET`, `COMPUTING`, or `ERRORED`.
2559
- */
2560
- this.value = UNSET;
2561
- /**
2562
- * If `value` is `ERRORED`, the error caught from the last computation attempt which will
2563
- * be re-thrown.
2564
- */
2565
- this.error = null;
2566
- /**
2567
- * Flag indicating that the computation is currently stale, meaning that one of the
2568
- * dependencies has notified of a potential change.
2569
- *
2570
- * It's possible that no dependency has _actually_ changed, in which case the `stale`
2571
- * state can be resolved without recomputing the value.
2572
- */
2573
- this.stale = true;
2574
- this.consumerAllowSignalWrites = false;
2575
- }
2576
- onConsumerDependencyMayHaveChanged() {
2577
- if (this.stale) {
2578
- // We've already notified consumers that this value has potentially changed.
2579
- return;
2580
- }
2581
- // Record that the currently cached value may be stale.
2582
- this.stale = true;
2583
- // Notify any consumers about the potential change.
2584
- this.producerMayHaveChanged();
2585
- }
2586
- onProducerUpdateValueVersion() {
2587
- if (!this.stale) {
2588
- // The current value and its version are already up to date.
2589
- return;
2590
- }
2591
- // The current value is stale. Check whether we need to produce a new one.
2592
- if (this.value !== UNSET && this.value !== COMPUTING &&
2593
- !this.consumerPollProducersForChange()) {
2594
- // Even though we were previously notified of a potential dependency update, all of
2595
- // our dependencies report that they have not actually changed in value, so we can
2596
- // resolve the stale state without needing to recompute the current value.
2597
- this.stale = false;
2598
- return;
2599
- }
2600
- // The current value is stale, and needs to be recomputed. It still may not change -
2601
- // that depends on whether the newly computed value is equal to the old.
2602
- this.recomputeValue();
2603
- }
2604
- recomputeValue() {
2605
- if (this.value === COMPUTING) {
2596
+ const COMPUTED_NODE = {
2597
+ ...REACTIVE_NODE,
2598
+ value: UNSET,
2599
+ dirty: true,
2600
+ error: null,
2601
+ equal: defaultEquals,
2602
+ producerMustRecompute(node) {
2603
+ // Force a recomputation if there's no current value, or if the current value is in the process
2604
+ // of being calculated (which should throw an error).
2605
+ return node.value === UNSET || node.value === COMPUTING;
2606
+ },
2607
+ producerRecomputeValue(node) {
2608
+ if (node.value === COMPUTING) {
2606
2609
  // Our computation somehow led to a cyclic read of itself.
2607
2610
  throw new Error('Detected cycle in computations.');
2608
2611
  }
2609
- const oldValue = this.value;
2610
- this.value = COMPUTING;
2611
- // As we're re-running the computation, update our dependent tracking version number.
2612
- this.trackingVersion++;
2613
- const prevConsumer = setActiveConsumer(this);
2612
+ const oldValue = node.value;
2613
+ node.value = COMPUTING;
2614
+ const prevConsumer = consumerBeforeComputation(node);
2614
2615
  let newValue;
2615
2616
  try {
2616
- newValue = this.computation();
2617
+ newValue = node.computation();
2617
2618
  }
2618
2619
  catch (err) {
2619
2620
  newValue = ERRORED;
2620
- this.error = err;
2621
+ node.error = err;
2621
2622
  }
2622
2623
  finally {
2623
- setActiveConsumer(prevConsumer);
2624
+ consumerAfterComputation(node, prevConsumer);
2624
2625
  }
2625
- this.stale = false;
2626
2626
  if (oldValue !== UNSET && oldValue !== ERRORED && newValue !== ERRORED &&
2627
- this.equal(oldValue, newValue)) {
2627
+ node.equal(oldValue, newValue)) {
2628
2628
  // No change to `valueVersion` - old and new values are
2629
2629
  // semantically equivalent.
2630
- this.value = oldValue;
2630
+ node.value = oldValue;
2631
2631
  return;
2632
2632
  }
2633
- this.value = newValue;
2634
- this.valueVersion++;
2635
- }
2636
- signal() {
2637
- // Check if the value needs updating before returning it.
2638
- this.onProducerUpdateValueVersion();
2639
- // Record that someone looked at this signal.
2640
- this.producerAccessed();
2641
- if (this.value === ERRORED) {
2642
- throw this.error;
2643
- }
2644
- return this.value;
2645
- }
2646
- }
2633
+ node.value = newValue;
2634
+ node.version++;
2635
+ },
2636
+ };
2647
2637
 
2648
2638
  function defaultThrowError() {
2649
2639
  throw new Error();
@@ -2663,88 +2653,24 @@ function setThrowInvalidWriteToSignalError(fn) {
2663
2653
  * of setting a signal.
2664
2654
  */
2665
2655
  let postSignalSetFn = null;
2666
- class WritableSignalImpl extends ReactiveNode {
2667
- constructor(value, equal) {
2668
- super();
2669
- this.value = value;
2670
- this.equal = equal;
2671
- this.consumerAllowSignalWrites = false;
2672
- }
2673
- onConsumerDependencyMayHaveChanged() {
2674
- // This never happens for writable signals as they're not consumers.
2675
- }
2676
- onProducerUpdateValueVersion() {
2677
- // Writable signal value versions are always up to date.
2678
- }
2679
- /**
2680
- * Directly update the value of the signal to a new value, which may or may not be
2681
- * equal to the previous.
2682
- *
2683
- * In the event that `newValue` is semantically equal to the current value, `set` is
2684
- * a no-op.
2685
- */
2686
- set(newValue) {
2687
- if (!this.producerUpdatesAllowed) {
2688
- throwInvalidWriteToSignalError();
2689
- }
2690
- if (!this.equal(this.value, newValue)) {
2691
- this.value = newValue;
2692
- this.valueVersion++;
2693
- this.producerMayHaveChanged();
2694
- postSignalSetFn?.();
2695
- }
2696
- }
2697
- /**
2698
- * Derive a new value for the signal from its current value using the `updater` function.
2699
- *
2700
- * This is equivalent to calling `set` on the result of running `updater` on the current
2701
- * value.
2702
- */
2703
- update(updater) {
2704
- if (!this.producerUpdatesAllowed) {
2705
- throwInvalidWriteToSignalError();
2706
- }
2707
- this.set(updater(this.value));
2708
- }
2709
- /**
2710
- * Calls `mutator` on the current value and assumes that it has been mutated.
2711
- */
2712
- mutate(mutator) {
2713
- if (!this.producerUpdatesAllowed) {
2714
- throwInvalidWriteToSignalError();
2715
- }
2716
- // Mutate bypasses equality checks as it's by definition changing the value.
2717
- mutator(this.value);
2718
- this.valueVersion++;
2719
- this.producerMayHaveChanged();
2720
- postSignalSetFn?.();
2721
- }
2722
- asReadonly() {
2723
- if (this.readonlySignal === undefined) {
2724
- this.readonlySignal = createSignalFromFunction(this, () => this.signal());
2725
- }
2726
- return this.readonlySignal;
2727
- }
2728
- signal() {
2729
- this.producerAccessed();
2730
- return this.value;
2731
- }
2732
- }
2733
2656
  /**
2734
2657
  * Create a `Signal` that can be set or updated directly.
2735
2658
  *
2736
2659
  * @developerPreview
2737
2660
  */
2738
2661
  function signal(initialValue, options) {
2739
- const signalNode = new WritableSignalImpl(initialValue, options?.equal ?? defaultEquals);
2740
- // Casting here is required for g3, as TS inference behavior is slightly different between our
2741
- // version/options and g3's.
2742
- const signalFn = createSignalFromFunction(signalNode, signalNode.signal.bind(signalNode), {
2743
- set: signalNode.set.bind(signalNode),
2744
- update: signalNode.update.bind(signalNode),
2745
- mutate: signalNode.mutate.bind(signalNode),
2746
- asReadonly: signalNode.asReadonly.bind(signalNode)
2747
- });
2662
+ const node = Object.create(SIGNAL_NODE);
2663
+ node.value = initialValue;
2664
+ options?.equal && (node.equal = options.equal);
2665
+ function signalFn() {
2666
+ producerAccessed(node);
2667
+ return node.value;
2668
+ }
2669
+ signalFn.set = signalSetFn;
2670
+ signalFn.update = signalUpdateFn;
2671
+ signalFn.mutate = signalMutateFn;
2672
+ signalFn.asReadonly = signalAsReadonlyFn;
2673
+ signalFn[SIGNAL] = node;
2748
2674
  return signalFn;
2749
2675
  }
2750
2676
  function setPostSignalSetFn(fn) {
@@ -2752,6 +2678,50 @@ function setPostSignalSetFn(fn) {
2752
2678
  postSignalSetFn = fn;
2753
2679
  return prev;
2754
2680
  }
2681
+ const SIGNAL_NODE = {
2682
+ ...REACTIVE_NODE,
2683
+ equal: defaultEquals,
2684
+ readonlyFn: undefined,
2685
+ };
2686
+ function signalValueChanged(node) {
2687
+ node.version++;
2688
+ producerNotifyConsumers(node);
2689
+ postSignalSetFn?.();
2690
+ }
2691
+ function signalSetFn(newValue) {
2692
+ const node = this[SIGNAL];
2693
+ if (!producerUpdatesAllowed()) {
2694
+ throwInvalidWriteToSignalError();
2695
+ }
2696
+ if (!node.equal(node.value, newValue)) {
2697
+ node.value = newValue;
2698
+ signalValueChanged(node);
2699
+ }
2700
+ }
2701
+ function signalUpdateFn(updater) {
2702
+ if (!producerUpdatesAllowed()) {
2703
+ throwInvalidWriteToSignalError();
2704
+ }
2705
+ signalSetFn.call(this, updater(this[SIGNAL].value));
2706
+ }
2707
+ function signalMutateFn(mutator) {
2708
+ const node = this[SIGNAL];
2709
+ if (!producerUpdatesAllowed()) {
2710
+ throwInvalidWriteToSignalError();
2711
+ }
2712
+ // Mutate bypasses equality checks as it's by definition changing the value.
2713
+ mutator(node.value);
2714
+ signalValueChanged(node);
2715
+ }
2716
+ function signalAsReadonlyFn() {
2717
+ const node = this[SIGNAL];
2718
+ if (node.readonlyFn === undefined) {
2719
+ const readonlyFn = () => this();
2720
+ readonlyFn[SIGNAL] = node;
2721
+ node.readonlyFn = readonlyFn;
2722
+ }
2723
+ return node.readonlyFn;
2724
+ }
2755
2725
 
2756
2726
  /**
2757
2727
  * Execute an arbitrary function in a non-reactive (non-tracking) context. The executed function
@@ -2771,63 +2741,53 @@ function untracked(nonReactiveReadsFn) {
2771
2741
  }
2772
2742
  }
2773
2743
 
2774
- const NOOP_CLEANUP_FN = () => { };
2775
- /**
2776
- * Watches a reactive expression and allows it to be scheduled to re-run
2777
- * when any dependencies notify of a change.
2778
- *
2779
- * `Watch` doesn't run reactive expressions itself, but relies on a consumer-
2780
- * provided scheduling operation to coordinate calling `Watch.run()`.
2781
- */
2782
- class Watch extends ReactiveNode {
2783
- constructor(watch, schedule, allowSignalWrites) {
2784
- super();
2785
- this.watch = watch;
2786
- this.schedule = schedule;
2787
- this.dirty = false;
2788
- this.cleanupFn = NOOP_CLEANUP_FN;
2789
- this.registerOnCleanup = (cleanupFn) => {
2790
- this.cleanupFn = cleanupFn;
2791
- };
2792
- this.consumerAllowSignalWrites = allowSignalWrites;
2793
- }
2794
- notify() {
2795
- if (!this.dirty) {
2796
- this.schedule(this);
2797
- }
2798
- this.dirty = true;
2799
- }
2800
- onConsumerDependencyMayHaveChanged() {
2801
- this.notify();
2744
+ function watch(fn, schedule, allowSignalWrites) {
2745
+ const node = Object.create(WATCH_NODE);
2746
+ if (allowSignalWrites) {
2747
+ node.consumerAllowSignalWrites = true;
2802
2748
  }
2803
- onProducerUpdateValueVersion() {
2804
- // Watches are not producers.
2805
- }
2806
- /**
2807
- * Execute the reactive expression in the context of this `Watch` consumer.
2808
- *
2809
- * Should be called by the user scheduling algorithm when the provided
2810
- * `schedule` hook is called by `Watch`.
2811
- */
2812
- run() {
2813
- this.dirty = false;
2814
- if (this.trackingVersion !== 0 && !this.consumerPollProducersForChange()) {
2749
+ node.fn = fn;
2750
+ node.schedule = schedule;
2751
+ const registerOnCleanup = (cleanupFn) => {
2752
+ node.cleanupFn = cleanupFn;
2753
+ };
2754
+ const run = () => {
2755
+ node.dirty = false;
2756
+ if (node.hasRun && !consumerPollProducersForChange(node)) {
2815
2757
  return;
2816
2758
  }
2817
- const prevConsumer = setActiveConsumer(this);
2818
- this.trackingVersion++;
2759
+ node.hasRun = true;
2760
+ const prevConsumer = consumerBeforeComputation(node);
2819
2761
  try {
2820
- this.cleanupFn();
2821
- this.cleanupFn = NOOP_CLEANUP_FN;
2822
- this.watch(this.registerOnCleanup);
2762
+ node.cleanupFn();
2763
+ node.cleanupFn = NOOP_CLEANUP_FN;
2764
+ node.fn(registerOnCleanup);
2823
2765
  }
2824
2766
  finally {
2825
- setActiveConsumer(prevConsumer);
2767
+ consumerAfterComputation(node, prevConsumer);
2826
2768
  }
2827
- }
2828
- cleanup() {
2829
- this.cleanupFn();
2830
- }
2769
+ };
2770
+ node.ref = {
2771
+ notify: () => consumerMarkDirty(node),
2772
+ run,
2773
+ cleanup: () => node.cleanupFn(),
2774
+ };
2775
+ return node.ref;
2776
+ }
2777
+ const NOOP_CLEANUP_FN = () => { };
2778
+ const WATCH_NODE = {
2779
+ ...REACTIVE_NODE,
2780
+ consumerIsAlwaysLive: true,
2781
+ consumerAllowSignalWrites: false,
2782
+ consumerMarkedDirty: (node) => {
2783
+ node.schedule(node.ref);
2784
+ },
2785
+ hasRun: false,
2786
+ cleanupFn: NOOP_CLEANUP_FN,
2787
+ };
2788
+
2789
+ function setAlternateWeakRefImpl(impl) {
2790
+ // TODO: remove this function
2831
2791
  }
2832
2792
 
2833
2793
  /**
@@ -4081,6 +4041,21 @@ function toTNodeTypeAsString(tNodeType) {
4081
4041
  (tNodeType & 64 /* TNodeType.Placeholder */) && (text += '|Placeholder');
4082
4042
  return text.length > 0 ? text.substring(1) : text;
4083
4043
  }
4044
+ /**
4045
+ * Helper function to detect if a given value matches a `TNode` shape.
4046
+ *
4047
+ * The logic uses the `insertBeforeIndex` and its possible values as
4048
+ * a way to differentiate a TNode shape from other types of objects
4049
+ * within the `TView.data`. This is not a perfect check, but it can
4050
+ * be a reasonable differentiator, since we control the shapes of objects
4051
+ * within `TView.data`.
4052
+ */
4053
+ function isTNodeShape(value) {
4054
+ return value != null && typeof value === 'object' &&
4055
+ (value.insertBeforeIndex === null ||
4056
+ typeof value.insertBeforeIndex === 'number' ||
4057
+ Array.isArray(value.insertBeforeIndex));
4058
+ }
4084
4059
  // Note: This hack is necessary so we don't erroneously get a circular dependency
4085
4060
  // failure based on types.
4086
4061
  const unusedValueExportToPlacateAjd$1 = 1;
@@ -8696,8 +8671,8 @@ function detachView(lContainer, removeIndex) {
8696
8671
  function destroyLView(tView, lView) {
8697
8672
  if (!(lView[FLAGS] & 256 /* LViewFlags.Destroyed */)) {
8698
8673
  const renderer = lView[RENDERER];
8699
- lView[REACTIVE_TEMPLATE_CONSUMER]?.destroy();
8700
- lView[REACTIVE_HOST_BINDING_CONSUMER]?.destroy();
8674
+ lView[REACTIVE_TEMPLATE_CONSUMER] && consumerDestroy(lView[REACTIVE_TEMPLATE_CONSUMER]);
8675
+ lView[REACTIVE_HOST_BINDING_CONSUMER] && consumerDestroy(lView[REACTIVE_HOST_BINDING_CONSUMER]);
8701
8676
  if (renderer.destroyNode) {
8702
8677
  applyView(tView, lView, renderer, 3 /* WalkTNodeTreeAction.Destroy */, null, null);
8703
8678
  }
@@ -10859,7 +10834,7 @@ class Version {
10859
10834
  /**
10860
10835
  * @publicApi
10861
10836
  */
10862
- const VERSION = new Version('17.0.0-next.2');
10837
+ const VERSION = new Version('17.0.0-next.3');
10863
10838
 
10864
10839
  // This default value is when checking the hierarchy for a token.
10865
10840
  //
@@ -11316,6 +11291,9 @@ function forkInnerZoneWithAngularBehavior(zone) {
11316
11291
  name: 'angular',
11317
11292
  properties: { 'isAngularZone': true },
11318
11293
  onInvokeTask: (delegate, current, target, task, applyThis, applyArgs) => {
11294
+ if (shouldBeIgnoredByZone(applyArgs)) {
11295
+ return delegate.invokeTask(target, task, applyThis, applyArgs);
11296
+ }
11319
11297
  try {
11320
11298
  onEnter(zone);
11321
11299
  return delegate.invokeTask(target, task, applyThis, applyArgs);
@@ -11467,6 +11445,18 @@ function isStableFactory() {
11467
11445
  });
11468
11446
  return merge$1(isCurrentlyStable, isStable.pipe(share()));
11469
11447
  }
11448
+ function shouldBeIgnoredByZone(applyArgs) {
11449
+ if (!Array.isArray(applyArgs)) {
11450
+ return false;
11451
+ }
11452
+ // We should only ever get 1 arg passed through to invokeTask.
11453
+ // Short circuit here incase that behavior changes.
11454
+ if (applyArgs.length !== 1) {
11455
+ return false;
11456
+ }
11457
+ // Prevent triggering change detection when the __ignore_ng_zone__ flag is detected.
11458
+ return applyArgs[0].data?.['__ignore_ng_zone__'] === true;
11459
+ }
11470
11460
 
11471
11461
  // Public API for Zone
11472
11462
 
@@ -11520,13 +11510,16 @@ function afterRender(callback, options) {
11520
11510
  let destroy;
11521
11511
  const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.());
11522
11512
  const manager = injector.get(AfterRenderEventManager);
11513
+ // Lazily initialize the handler implementation, if necessary. This is so that it can be
11514
+ // tree-shaken if `afterRender` and `afterNextRender` aren't used.
11515
+ const handler = manager.handler ??= new AfterRenderCallbackHandlerImpl();
11523
11516
  const ngZone = injector.get(NgZone);
11524
11517
  const instance = new AfterRenderCallback(() => ngZone.runOutsideAngular(callback));
11525
11518
  destroy = () => {
11526
- manager.unregister(instance);
11519
+ handler.unregister(instance);
11527
11520
  unregisterFn();
11528
11521
  };
11529
- manager.register(instance);
11522
+ handler.register(instance);
11530
11523
  return { destroy };
11531
11524
  }
11532
11525
  /**
@@ -11580,21 +11573,23 @@ function afterNextRender(callback, options) {
11580
11573
  let destroy;
11581
11574
  const unregisterFn = injector.get(DestroyRef).onDestroy(() => destroy?.());
11582
11575
  const manager = injector.get(AfterRenderEventManager);
11576
+ // Lazily initialize the handler implementation, if necessary. This is so that it can be
11577
+ // tree-shaken if `afterRender` and `afterNextRender` aren't used.
11578
+ const handler = manager.handler ??= new AfterRenderCallbackHandlerImpl();
11583
11579
  const ngZone = injector.get(NgZone);
11584
11580
  const instance = new AfterRenderCallback(() => {
11585
11581
  destroy?.();
11586
11582
  ngZone.runOutsideAngular(callback);
11587
11583
  });
11588
11584
  destroy = () => {
11589
- manager.unregister(instance);
11585
+ handler.unregister(instance);
11590
11586
  unregisterFn();
11591
11587
  };
11592
- manager.register(instance);
11588
+ handler.register(instance);
11593
11589
  return { destroy };
11594
11590
  }
11595
11591
  /**
11596
11592
  * A wrapper around a function to be used as an after render callback.
11597
- * @private
11598
11593
  */
11599
11594
  class AfterRenderCallback {
11600
11595
  constructor(callback) {
@@ -11605,65 +11600,87 @@ class AfterRenderCallback {
11605
11600
  }
11606
11601
  }
11607
11602
  /**
11608
- * Implements `afterRender` and `afterNextRender` callback manager logic.
11603
+ * Core functionality for `afterRender` and `afterNextRender`. Kept separate from
11604
+ * `AfterRenderEventManager` for tree-shaking.
11609
11605
  */
11610
- class AfterRenderEventManager {
11606
+ class AfterRenderCallbackHandlerImpl {
11611
11607
  constructor() {
11608
+ this.executingCallbacks = false;
11612
11609
  this.callbacks = new Set();
11613
11610
  this.deferredCallbacks = new Set();
11614
- this.renderDepth = 0;
11615
- this.runningCallbacks = false;
11616
11611
  }
11617
- /**
11618
- * Mark the beginning of a render operation (i.e. CD cycle).
11619
- * Throws if called from an `afterRender` callback.
11620
- */
11621
- begin() {
11622
- if (this.runningCallbacks) {
11612
+ validateBegin() {
11613
+ if (this.executingCallbacks) {
11623
11614
  throw new RuntimeError(102 /* RuntimeErrorCode.RECURSIVE_APPLICATION_RENDER */, ngDevMode &&
11624
11615
  'A new render operation began before the previous operation ended. ' +
11625
11616
  'Did you trigger change detection from afterRender or afterNextRender?');
11626
11617
  }
11627
- this.renderDepth++;
11628
- }
11629
- /**
11630
- * Mark the end of a render operation. Registered callbacks
11631
- * are invoked if there are no more pending operations.
11632
- */
11633
- end() {
11634
- this.renderDepth--;
11635
- if (this.renderDepth === 0) {
11636
- try {
11637
- this.runningCallbacks = true;
11638
- for (const callback of this.callbacks) {
11639
- callback.invoke();
11640
- }
11641
- }
11642
- finally {
11643
- this.runningCallbacks = false;
11644
- for (const callback of this.deferredCallbacks) {
11645
- this.callbacks.add(callback);
11646
- }
11647
- this.deferredCallbacks.clear();
11648
- }
11649
- }
11650
11618
  }
11651
11619
  register(callback) {
11652
11620
  // If we're currently running callbacks, new callbacks should be deferred
11653
11621
  // until the next render operation.
11654
- const target = this.runningCallbacks ? this.deferredCallbacks : this.callbacks;
11622
+ const target = this.executingCallbacks ? this.deferredCallbacks : this.callbacks;
11655
11623
  target.add(callback);
11656
11624
  }
11657
11625
  unregister(callback) {
11658
11626
  this.callbacks.delete(callback);
11659
11627
  this.deferredCallbacks.delete(callback);
11660
11628
  }
11661
- ngOnDestroy() {
11629
+ execute() {
11630
+ try {
11631
+ this.executingCallbacks = true;
11632
+ for (const callback of this.callbacks) {
11633
+ callback.invoke();
11634
+ }
11635
+ }
11636
+ finally {
11637
+ this.executingCallbacks = false;
11638
+ for (const callback of this.deferredCallbacks) {
11639
+ this.callbacks.add(callback);
11640
+ }
11641
+ this.deferredCallbacks.clear();
11642
+ }
11643
+ }
11644
+ destroy() {
11662
11645
  this.callbacks.clear();
11663
11646
  this.deferredCallbacks.clear();
11664
11647
  }
11665
- /** @nocollapse */
11666
- static { this.ɵprov = ɵɵdefineInjectable({
11648
+ }
11649
+ /**
11650
+ * Implements core timing for `afterRender` and `afterNextRender` events.
11651
+ * Delegates to an optional `AfterRenderCallbackHandler` for implementation.
11652
+ */
11653
+ class AfterRenderEventManager {
11654
+ constructor() {
11655
+ this.renderDepth = 0;
11656
+ /* @internal */
11657
+ this.handler = null;
11658
+ }
11659
+ /**
11660
+ * Mark the beginning of a render operation (i.e. CD cycle).
11661
+ * Throws if called while executing callbacks.
11662
+ */
11663
+ begin() {
11664
+ this.handler?.validateBegin();
11665
+ this.renderDepth++;
11666
+ }
11667
+ /**
11668
+ * Mark the end of a render operation. Callbacks will be
11669
+ * executed if there are no more pending operations.
11670
+ */
11671
+ end() {
11672
+ ngDevMode && assertGreaterThan(this.renderDepth, 0, 'renderDepth must be greater than 0');
11673
+ this.renderDepth--;
11674
+ if (this.renderDepth === 0) {
11675
+ this.handler?.execute();
11676
+ }
11677
+ }
11678
+ ngOnDestroy() {
11679
+ this.handler?.destroy();
11680
+ this.handler = null;
11681
+ }
11682
+ /** @nocollapse */
11683
+ static { this.ɵprov = ɵɵdefineInjectable({
11667
11684
  token: AfterRenderEventManager,
11668
11685
  providedIn: 'root',
11669
11686
  factory: () => new AfterRenderEventManager(),
@@ -11897,48 +11914,11 @@ function getExpressionChangedErrorDetails(lView, bindingIndex, oldValue, newValu
11897
11914
  return { propName: undefined, oldValue, newValue };
11898
11915
  }
11899
11916
 
11900
- class ReactiveLViewConsumer extends ReactiveNode {
11901
- constructor() {
11902
- super(...arguments);
11903
- this.consumerAllowSignalWrites = false;
11904
- this._lView = null;
11905
- }
11906
- set lView(lView) {
11907
- (typeof ngDevMode === 'undefined' || ngDevMode) &&
11908
- assertEqual(this._lView, null, 'Consumer already associated with a view.');
11909
- this._lView = lView;
11910
- }
11911
- onConsumerDependencyMayHaveChanged() {
11912
- (typeof ngDevMode === 'undefined' || ngDevMode) &&
11913
- assertDefined(this._lView, 'Updating a signal during template or host binding execution is not allowed.');
11914
- markViewDirty(this._lView);
11915
- }
11916
- onProducerUpdateValueVersion() {
11917
- // This type doesn't implement the producer side of a `ReactiveNode`.
11918
- }
11919
- get hasReadASignal() {
11920
- return this.hasProducers;
11921
- }
11922
- runInContext(fn, rf, ctx) {
11923
- const prevConsumer = setActiveConsumer(this);
11924
- this.trackingVersion++;
11925
- try {
11926
- fn(rf, ctx);
11927
- }
11928
- finally {
11929
- setActiveConsumer(prevConsumer);
11930
- }
11931
- }
11932
- destroy() {
11933
- // Incrementing the version means that every producer which tries to update this consumer will
11934
- // consider its record stale, and not notify.
11935
- this.trackingVersion++;
11936
- }
11937
- }
11938
11917
  let currentConsumer = null;
11939
- function getOrCreateCurrentLViewConsumer() {
11940
- currentConsumer ??= new ReactiveLViewConsumer();
11941
- return currentConsumer;
11918
+ function setLViewForConsumer(node, lView) {
11919
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
11920
+ assertEqual(node.lView, null, 'Consumer already associated with a view.');
11921
+ node.lView = lView;
11942
11922
  }
11943
11923
  /**
11944
11924
  * Create a new template consumer pointing at the specified LView.
@@ -11960,12 +11940,29 @@ function getReactiveLViewConsumer(lView, slot) {
11960
11940
  */
11961
11941
  function commitLViewConsumerIfHasProducers(lView, slot) {
11962
11942
  const consumer = getOrCreateCurrentLViewConsumer();
11963
- if (!consumer.hasReadASignal) {
11943
+ if (!consumer.producerNode?.length) {
11964
11944
  return;
11965
11945
  }
11966
11946
  lView[slot] = currentConsumer;
11967
11947
  consumer.lView = lView;
11968
- currentConsumer = new ReactiveLViewConsumer();
11948
+ currentConsumer = createLViewConsumer();
11949
+ }
11950
+ const REACTIVE_LVIEW_CONSUMER_NODE = {
11951
+ ...REACTIVE_NODE,
11952
+ consumerIsAlwaysLive: true,
11953
+ consumerMarkedDirty: (node) => {
11954
+ (typeof ngDevMode === 'undefined' || ngDevMode) &&
11955
+ assertDefined(node.lView, 'Updating a signal during template or host binding execution is not allowed.');
11956
+ markViewDirty(node.lView);
11957
+ },
11958
+ lView: null,
11959
+ };
11960
+ function createLViewConsumer() {
11961
+ return Object.create(REACTIVE_LVIEW_CONSUMER_NODE);
11962
+ }
11963
+ function getOrCreateCurrentLViewConsumer() {
11964
+ currentConsumer ??= createLViewConsumer();
11965
+ return currentConsumer;
11969
11966
  }
11970
11967
 
11971
11968
  /** A special value which designates that a value has not changed. */
@@ -12082,8 +12079,15 @@ function processHostBindingOpCodes(tView, lView) {
12082
12079
  const bindingRootIndx = hostBindingOpCodes[++i];
12083
12080
  const hostBindingFn = hostBindingOpCodes[++i];
12084
12081
  setBindingRootForHostBindings(bindingRootIndx, directiveIdx);
12085
- const context = lView[directiveIdx];
12086
- consumer.runInContext(hostBindingFn, 2 /* RenderFlags.Update */, context);
12082
+ consumer.dirty = false;
12083
+ const prevConsumer = consumerBeforeComputation(consumer);
12084
+ try {
12085
+ const context = lView[directiveIdx];
12086
+ hostBindingFn(2 /* RenderFlags.Update */, context);
12087
+ }
12088
+ finally {
12089
+ consumerAfterComputation(consumer, prevConsumer);
12090
+ }
12087
12091
  }
12088
12092
  }
12089
12093
  }
@@ -12223,17 +12227,16 @@ function executeTemplate(tView, lView, templateFn, rf, context) {
12223
12227
  }
12224
12228
  const preHookType = isUpdatePhase ? 2 /* ProfilerEvent.TemplateUpdateStart */ : 0 /* ProfilerEvent.TemplateCreateStart */;
12225
12229
  profiler(preHookType, context);
12226
- if (isUpdatePhase) {
12227
- consumer.runInContext(templateFn, rf, context);
12228
- }
12229
- else {
12230
- const prevConsumer = setActiveConsumer(null);
12231
- try {
12232
- templateFn(rf, context);
12233
- }
12234
- finally {
12235
- setActiveConsumer(prevConsumer);
12230
+ const effectiveConsumer = isUpdatePhase ? consumer : null;
12231
+ const prevConsumer = consumerBeforeComputation(effectiveConsumer);
12232
+ try {
12233
+ if (effectiveConsumer !== null) {
12234
+ effectiveConsumer.dirty = false;
12236
12235
  }
12236
+ templateFn(rf, context);
12237
+ }
12238
+ finally {
12239
+ consumerAfterComputation(effectiveConsumer, prevConsumer);
12237
12240
  }
12238
12241
  }
12239
12242
  finally {
@@ -13487,21 +13490,21 @@ class EffectManager {
13487
13490
  }
13488
13491
  create(effectFn, destroyRef, allowSignalWrites) {
13489
13492
  const zone = (typeof Zone === 'undefined') ? null : Zone.current;
13490
- const watch = new Watch(effectFn, (watch) => {
13493
+ const w = watch(effectFn, (watch) => {
13491
13494
  if (!this.all.has(watch)) {
13492
13495
  return;
13493
13496
  }
13494
13497
  this.queue.set(watch, zone);
13495
13498
  }, allowSignalWrites);
13496
- this.all.add(watch);
13499
+ this.all.add(w);
13497
13500
  // Effects start dirty.
13498
- watch.notify();
13501
+ w.notify();
13499
13502
  let unregisterOnDestroy;
13500
13503
  const destroy = () => {
13501
- watch.cleanup();
13504
+ w.cleanup();
13502
13505
  unregisterOnDestroy?.();
13503
- this.all.delete(watch);
13504
- this.queue.delete(watch);
13506
+ this.all.delete(w);
13507
+ this.queue.delete(w);
13505
13508
  };
13506
13509
  unregisterOnDestroy = destroyRef?.onDestroy(destroy);
13507
13510
  return {
@@ -13749,7 +13752,7 @@ function refreshView(tView, lView, templateFn, context) {
13749
13752
  // insertion points. This is needed to avoid the situation where the template is defined in this
13750
13753
  // `LView` but its declaration appears after the insertion component.
13751
13754
  markTransplantedViewsForRefresh(lView);
13752
- detectChangesInEmbeddedViews(lView, 2 /* ChangeDetectionMode.BugToForceRefreshAndIgnoreViewFlags */);
13755
+ detectChangesInEmbeddedViews(lView, 0 /* ChangeDetectionMode.Global */);
13753
13756
  // Content query results must be refreshed before content hooks are called.
13754
13757
  if (tView.contentQueries !== null) {
13755
13758
  refreshContentQueries(tView, lView);
@@ -13885,15 +13888,14 @@ function detectChangesInView(lView, mode) {
13885
13888
  return;
13886
13889
  }
13887
13890
  const tView = lView[TVIEW];
13888
- if ((lView[FLAGS] & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */) &&
13891
+ const flags = lView[FLAGS];
13892
+ if ((flags & (16 /* LViewFlags.CheckAlways */ | 64 /* LViewFlags.Dirty */) &&
13889
13893
  mode === 0 /* ChangeDetectionMode.Global */) ||
13890
- lView[FLAGS] & 1024 /* LViewFlags.RefreshView */ ||
13891
- mode === 2 /* ChangeDetectionMode.BugToForceRefreshAndIgnoreViewFlags */) {
13894
+ flags & 1024 /* LViewFlags.RefreshView */) {
13892
13895
  refreshView(tView, lView, tView.template, lView[CONTEXT]);
13893
13896
  }
13894
13897
  else if (lView[DESCENDANT_VIEWS_TO_REFRESH] > 0) {
13895
13898
  detectChangesInEmbeddedViews(lView, 1 /* ChangeDetectionMode.Targeted */);
13896
- const tView = lView[TVIEW];
13897
13899
  const components = tView.components;
13898
13900
  if (components !== null) {
13899
13901
  detectChangesInChildComponents(lView, components, 1 /* ChangeDetectionMode.Targeted */);
@@ -15653,14 +15655,12 @@ function getTStylingRangePrev(tStylingRange) {
15653
15655
  }
15654
15656
  function getTStylingRangePrevDuplicate(tStylingRange) {
15655
15657
  ngDevMode && assertNumber(tStylingRange, 'expected number');
15656
- return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) ==
15657
- 2 /* StylingRange.PREV_DUPLICATE */;
15658
+ return (tStylingRange & 2 /* StylingRange.PREV_DUPLICATE */) == 2 /* StylingRange.PREV_DUPLICATE */;
15658
15659
  }
15659
15660
  function setTStylingRangePrev(tStylingRange, previous) {
15660
15661
  ngDevMode && assertNumber(tStylingRange, 'expected number');
15661
15662
  ngDevMode && assertNumberInRange(previous, 0, 32767 /* StylingRange.UNSIGNED_MASK */);
15662
- return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) |
15663
- (previous << 17 /* StylingRange.PREV_SHIFT */));
15663
+ return ((tStylingRange & ~4294836224 /* StylingRange.PREV_MASK */) | (previous << 17 /* StylingRange.PREV_SHIFT */));
15664
15664
  }
15665
15665
  function setTStylingRangePrevDuplicate(tStylingRange) {
15666
15666
  ngDevMode && assertNumber(tStylingRange, 'expected number');
@@ -15678,8 +15678,7 @@ function setTStylingRangeNext(tStylingRange, next) {
15678
15678
  }
15679
15679
  function getTStylingRangeNextDuplicate(tStylingRange) {
15680
15680
  ngDevMode && assertNumber(tStylingRange, 'expected number');
15681
- return (tStylingRange & 1 /* StylingRange.NEXT_DUPLICATE */) ===
15682
- 1 /* StylingRange.NEXT_DUPLICATE */;
15681
+ return ((tStylingRange) & 1 /* StylingRange.NEXT_DUPLICATE */) === 1 /* StylingRange.NEXT_DUPLICATE */;
15683
15682
  }
15684
15683
  function setTStylingRangeNextDuplicate(tStylingRange) {
15685
15684
  ngDevMode && assertNumber(tStylingRange, 'expected number');
@@ -17480,6 +17479,26 @@ function ɵɵclassMapInterpolateV(values) {
17480
17479
  checkStylingMap(keyValueArraySet, classStringParser, interpolatedValue, true);
17481
17480
  }
17482
17481
 
17482
+ /*!
17483
+ * @license
17484
+ * Copyright Google LLC All Rights Reserved.
17485
+ *
17486
+ * Use of this source code is governed by an MIT-style license that can be
17487
+ * found in the LICENSE file at https://angular.io/license
17488
+ */
17489
+ /**
17490
+ * Instruction that returns the component instance in which the current instruction is executing.
17491
+ * This is a constant-time version of `nextContent` for the case where we know that we need the
17492
+ * component instance specifically, rather than the context of a particular template.
17493
+ *
17494
+ * @codeGenApi
17495
+ */
17496
+ function ɵɵcomponentInstance() {
17497
+ const instance = getLView()[DECLARATION_COMPONENT_VIEW][CONTEXT];
17498
+ ngDevMode && assertDefined(instance, 'Expected component instance to be defined');
17499
+ return instance;
17500
+ }
17501
+
17483
17502
  class DefaultIterableDifferFactory {
17484
17503
  constructor() { }
17485
17504
  supports(obj) {
@@ -18620,7 +18639,7 @@ function createAndRenderEmbeddedLView(declarationLView, templateTNode, context,
18620
18639
  // Embedded views follow the change detection strategy of the view they're declared in.
18621
18640
  const isSignalView = declarationLView[FLAGS] & 4096 /* LViewFlags.SignalView */;
18622
18641
  const viewFlags = isSignalView ? 4096 /* LViewFlags.SignalView */ : 16 /* LViewFlags.CheckAlways */;
18623
- const embeddedLView = createLView(declarationLView, embeddedTView, context, viewFlags, null, templateTNode, null, null, null, options?.injector ?? null, options?.hydrationInfo ?? null);
18642
+ const embeddedLView = createLView(declarationLView, embeddedTView, context, viewFlags, null, templateTNode, null, null, null, options?.injector ?? null, options?.dehydratedView ?? null);
18624
18643
  const declarationLContainer = declarationLView[templateTNode.index];
18625
18644
  ngDevMode && assertLContainer(declarationLContainer);
18626
18645
  embeddedLView[DECLARATION_LCONTAINER] = declarationLContainer;
@@ -18642,6 +18661,16 @@ function getLViewFromLContainer(lContainer, index) {
18642
18661
  }
18643
18662
  return undefined;
18644
18663
  }
18664
+ /**
18665
+ * Returns whether an elements that belong to a view should be
18666
+ * inserted into the DOM. For client-only cases, DOM elements are
18667
+ * always inserted. For hydration cases, we check whether serialized
18668
+ * info is available for a view and the view is not in a "skip hydration"
18669
+ * block (in which case view contents was re-created, thus needing insertion).
18670
+ */
18671
+ function shouldAddViewToDom(tNode, dehydratedView) {
18672
+ return !dehydratedView || hasInSkipHydrationBlockFlag(tNode);
18673
+ }
18645
18674
  function addLViewToLContainer(lContainer, lView, index, addToDOM = true) {
18646
18675
  const tView = lView[TVIEW];
18647
18676
  // insert to the view tree so the new view can be change-detected
@@ -19539,12 +19568,28 @@ class RepeaterMetadata {
19539
19568
  * - LView[HEADER_OFFSET + index + 2] - optional reference to a template function rendering an empty
19540
19569
  * block
19541
19570
  *
19571
+ * @param index Index at which to store the metadata of the repeater.
19572
+ * @param templateFn Reference to the template of the main repeater block.
19573
+ * @param decls The number of nodes, local refs, and pipes for the main block.
19574
+ * @param vars The number of bindings for the main block.
19575
+ * @param trackByFn Reference to the tracking function.
19576
+ * @param trackByUsesComponentInstance Whether the tracking function has any references to the
19577
+ * component instance. If it doesn't, we can avoid rebinding it.
19578
+ * @param emptyTemplateFn Reference to the template function of the empty block.
19579
+ * @param emptyDecls The number of nodes, local refs, and pipes for the empty block.
19580
+ * @param emptyVars The number of bindings for the empty block.
19581
+ *
19542
19582
  * @codeGenApi
19543
19583
  */
19544
- function ɵɵrepeaterCreate(index, templateFn, decls, vars, trackByFn, emptyTemplateFn, emptyDecls, emptyVars) {
19584
+ function ɵɵrepeaterCreate(index, templateFn, decls, vars, trackByFn, trackByUsesComponentInstance, emptyTemplateFn, emptyDecls, emptyVars) {
19545
19585
  const hasEmptyBlock = emptyTemplateFn !== undefined;
19546
19586
  const hostLView = getLView();
19547
- const metadata = new RepeaterMetadata(hasEmptyBlock, new DefaultIterableDiffer(trackByFn));
19587
+ const boundTrackBy = trackByUsesComponentInstance ?
19588
+ // We only want to bind when necessary, because it produces a
19589
+ // new function. For pure functions it's not necessary.
19590
+ trackByFn.bind(hostLView[DECLARATION_COMPONENT_VIEW][CONTEXT]) :
19591
+ trackByFn;
19592
+ const metadata = new RepeaterMetadata(hasEmptyBlock, new DefaultIterableDiffer(boundTrackBy));
19548
19593
  hostLView[HEADER_OFFSET + index] = metadata;
19549
19594
  ɵɵtemplate(index + 1, templateFn, decls, vars);
19550
19595
  if (hasEmptyBlock) {
@@ -19655,142 +19700,741 @@ function getExistingTNode(tView, index) {
19655
19700
  return tNode;
19656
19701
  }
19657
19702
 
19658
- const DEFER_BLOCK_STATE = 0;
19659
-
19660
- /**
19661
- * Shims for the `requestIdleCallback` and `cancelIdleCallback` functions for environments
19662
- * where those functions are not available (e.g. Node.js).
19663
- */
19664
- const _requestIdleCallback = typeof requestIdleCallback !== 'undefined' ? requestIdleCallback : setTimeout;
19665
- const _cancelIdleCallback = typeof requestIdleCallback !== 'undefined' ? cancelIdleCallback : clearTimeout;
19666
19703
  /**
19667
- * Creates runtime data structures for `{#defer}` blocks.
19668
- *
19669
- * @param index Index of the `defer` instruction.
19670
- * @param primaryTmplIndex Index of the template with the primary block content.
19671
- * @param dependencyResolverFn Function that contains dependencies for this defer block.
19672
- * @param loadingTmplIndex Index of the template with the `{:loading}` block content.
19673
- * @param placeholderTmplIndex Index of the template with the `{:placeholder}` block content.
19674
- * @param errorTmplIndex Index of the template with the `{:error}` block content.
19675
- * @param loadingConfigIndex Index in the constants array of the configuration of the `{:loading}`.
19676
- * block.
19677
- * @param placeholderConfigIndexIndex in the constants array of the configuration of the
19678
- * `{:placeholder}` block.
19679
- *
19680
- * @codeGenApi
19704
+ * Removes all dehydrated views from a given LContainer:
19705
+ * both in internal data structure, as well as removing
19706
+ * corresponding DOM nodes that belong to that dehydrated view.
19681
19707
  */
19682
- function ɵɵdefer(index, primaryTmplIndex, dependencyResolverFn, loadingTmplIndex, placeholderTmplIndex, errorTmplIndex, loadingConfigIndex, placeholderConfigIndex) {
19683
- const lView = getLView();
19684
- const tView = getTView();
19685
- const tViewConsts = tView.consts;
19686
- const adjustedIndex = index + HEADER_OFFSET;
19687
- ɵɵtemplate(index, null, 0, 0);
19688
- if (tView.firstCreatePass) {
19689
- const deferBlockConfig = {
19690
- primaryTmplIndex,
19691
- loadingTmplIndex: loadingTmplIndex ?? null,
19692
- placeholderTmplIndex: placeholderTmplIndex ?? null,
19693
- errorTmplIndex: errorTmplIndex ?? null,
19694
- placeholderBlockConfig: placeholderConfigIndex != null ?
19695
- getConstant(tViewConsts, placeholderConfigIndex) :
19696
- null,
19697
- loadingBlockConfig: loadingConfigIndex != null ?
19698
- getConstant(tViewConsts, loadingConfigIndex) :
19699
- null,
19700
- dependencyResolverFn: dependencyResolverFn ?? null,
19701
- loadingState: 0 /* DeferDependenciesLoadingState.NOT_STARTED */,
19702
- loadingPromise: null,
19703
- };
19704
- setTDeferBlockDetails(tView, adjustedIndex, deferBlockConfig);
19708
+ function removeDehydratedViews(lContainer) {
19709
+ const views = lContainer[DEHYDRATED_VIEWS] ?? [];
19710
+ const parentLView = lContainer[PARENT];
19711
+ const renderer = parentLView[RENDERER];
19712
+ for (const view of views) {
19713
+ removeDehydratedView(view, renderer);
19714
+ ngDevMode && ngDevMode.dehydratedViewsRemoved++;
19705
19715
  }
19706
- // Init instance-specific defer details and store it.
19707
- const lDetails = [];
19708
- lDetails[DEFER_BLOCK_STATE] = 0 /* DeferBlockInstanceState.INITIAL */;
19709
- setLDeferBlockDetails(lView, adjustedIndex, lDetails);
19716
+ // Reset the value to an empty array to indicate that no
19717
+ // further processing of dehydrated views is needed for
19718
+ // this view container (i.e. do not trigger the lookup process
19719
+ // once again in case a `ViewContainerRef` is created later).
19720
+ lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
19710
19721
  }
19711
19722
  /**
19712
- * Loads defer block dependencies when a trigger value becomes truthy.
19713
- * @codeGenApi
19723
+ * Helper function to remove all nodes from a dehydrated view.
19714
19724
  */
19715
- function ɵɵdeferWhen(rawValue) {
19716
- const lView = getLView();
19717
- const bindingIndex = nextBindingIndex();
19718
- if (bindingUpdated(lView, bindingIndex, rawValue)) {
19719
- const value = Boolean(rawValue); // handle truthy or falsy values
19720
- const tNode = getSelectedTNode();
19721
- const lDetails = getLDeferBlockDetails(lView, tNode);
19722
- const renderedState = lDetails[DEFER_BLOCK_STATE];
19723
- if (value === false && renderedState === 0 /* DeferBlockInstanceState.INITIAL */) {
19724
- // If nothing is rendered yet, render a placeholder (if defined).
19725
- renderPlaceholder(lView, tNode);
19726
- }
19727
- else if (value === true &&
19728
- (renderedState === 0 /* DeferBlockInstanceState.INITIAL */ ||
19729
- renderedState === 1 /* DeferBlockInstanceState.PLACEHOLDER */)) {
19730
- // The `when` condition has changed to `true`, trigger defer block loading
19731
- // if the block is either in initial (nothing is rendered) or a placeholder
19732
- // state.
19733
- triggerDeferBlock(lView, tNode);
19725
+ function removeDehydratedView(dehydratedView, renderer) {
19726
+ let nodesRemoved = 0;
19727
+ let currentRNode = dehydratedView.firstChild;
19728
+ if (currentRNode) {
19729
+ const numNodes = dehydratedView.data[NUM_ROOT_NODES];
19730
+ while (nodesRemoved < numNodes) {
19731
+ ngDevMode && validateSiblingNodeExists(currentRNode);
19732
+ const nextSibling = currentRNode.nextSibling;
19733
+ nativeRemoveNode(renderer, currentRNode, false);
19734
+ currentRNode = nextSibling;
19735
+ nodesRemoved++;
19734
19736
  }
19735
19737
  }
19736
19738
  }
19737
19739
  /**
19738
- * Prefetches the deferred content when a value becomes truthy.
19739
- * @codeGenApi
19740
+ * Walks over all views within this LContainer invokes dehydrated views
19741
+ * cleanup function for each one.
19740
19742
  */
19741
- function ɵɵdeferPrefetchWhen(rawValue) {
19742
- const lView = getLView();
19743
- const bindingIndex = nextBindingIndex();
19744
- if (bindingUpdated(lView, bindingIndex, rawValue)) {
19745
- const value = Boolean(rawValue); // handle truthy or falsy values
19746
- const tView = lView[TVIEW];
19747
- const tNode = getSelectedTNode();
19748
- const tDetails = getTDeferBlockDetails(tView, tNode);
19749
- if (value === true && tDetails.loadingState === 0 /* DeferDependenciesLoadingState.NOT_STARTED */) {
19750
- // If loading has not been started yet, trigger it now.
19751
- triggerResourceLoading(tDetails, getPrimaryBlockTNode(tView, tDetails), lView[INJECTOR$1]);
19752
- }
19743
+ function cleanupLContainer(lContainer) {
19744
+ removeDehydratedViews(lContainer);
19745
+ for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
19746
+ cleanupLView(lContainer[i]);
19753
19747
  }
19754
19748
  }
19755
19749
  /**
19756
- * Sets up handlers that represent `on idle` deferred trigger.
19757
- * @codeGenApi
19750
+ * Walks over `LContainer`s and components registered within
19751
+ * this LView and invokes dehydrated views cleanup function for each one.
19758
19752
  */
19759
- function ɵɵdeferOnIdle() {
19760
- const lView = getLView();
19761
- const tNode = getCurrentTNode();
19762
- renderPlaceholder(lView, tNode);
19763
- let id;
19764
- const removeIdleCallback = () => _cancelIdleCallback(id);
19765
- id = _requestIdleCallback(() => {
19766
- removeIdleCallback();
19767
- // The idle callback is invoked, we no longer need
19768
- // to retain a cleanup callback in an LView.
19769
- removeLViewOnDestroy(lView, removeIdleCallback);
19770
- triggerDeferBlock(lView, tNode);
19771
- });
19772
- // Store a cleanup function on LView, so that we cancel idle
19773
- // callback in case this LView was destroyed before a callback
19774
- // was invoked.
19775
- storeLViewOnDestroy(lView, removeIdleCallback);
19753
+ function cleanupLView(lView) {
19754
+ const tView = lView[TVIEW];
19755
+ for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
19756
+ if (isLContainer(lView[i])) {
19757
+ const lContainer = lView[i];
19758
+ cleanupLContainer(lContainer);
19759
+ }
19760
+ else if (isLView(lView[i])) {
19761
+ // This is a component, enter the `cleanupLView` recursively.
19762
+ cleanupLView(lView[i]);
19763
+ }
19764
+ }
19776
19765
  }
19777
19766
  /**
19778
- * Creates runtime data structures for the `prefetch on idle` deferred trigger.
19779
- * @codeGenApi
19780
- */
19781
- function ɵɵdeferPrefetchOnIdle() { } // TODO: implement runtime logic.
19782
- /**
19783
- * Creates runtime data structures for the `on immediate` deferred trigger.
19784
- * @codeGenApi
19767
+ * Walks over all views registered within the ApplicationRef and removes
19768
+ * all dehydrated views from all `LContainer`s along the way.
19785
19769
  */
19786
- function ɵɵdeferOnImmediate() { } // TODO: implement runtime logic.
19770
+ function cleanupDehydratedViews(appRef) {
19771
+ const viewRefs = appRef._views;
19772
+ for (const viewRef of viewRefs) {
19773
+ const lNode = getLNodeForHydration(viewRef);
19774
+ // An `lView` might be `null` if a `ViewRef` represents
19775
+ // an embedded view (not a component view).
19776
+ if (lNode !== null && lNode[HOST] !== null) {
19777
+ if (isLView(lNode)) {
19778
+ cleanupLView(lNode);
19779
+ }
19780
+ else {
19781
+ // Cleanup in the root component view
19782
+ const componentLView = lNode[HOST];
19783
+ cleanupLView(componentLView);
19784
+ // Cleanup in all views within this view container
19785
+ cleanupLContainer(lNode);
19786
+ }
19787
+ ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
19788
+ }
19789
+ }
19790
+ }
19791
+
19787
19792
  /**
19788
- * Creates runtime data structures for the `prefetch on immediate` deferred trigger.
19789
- * @codeGenApi
19793
+ * Given a current DOM node and a serialized information about the views
19794
+ * in a container, walks over the DOM structure, collecting the list of
19795
+ * dehydrated views.
19790
19796
  */
19791
- function ɵɵdeferPrefetchOnImmediate() { } // TODO: implement runtime logic.
19792
- /**
19793
- * Creates runtime data structures for the `on timer` deferred trigger.
19797
+ function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
19798
+ const dehydratedViews = [];
19799
+ for (const serializedView of serializedViews) {
19800
+ // Repeats a view multiple times as needed, based on the serialized information
19801
+ // (for example, for *ngFor-produced views).
19802
+ for (let i = 0; i < (serializedView[MULTIPLIER] ?? 1); i++) {
19803
+ const view = {
19804
+ data: serializedView,
19805
+ firstChild: null,
19806
+ };
19807
+ if (serializedView[NUM_ROOT_NODES] > 0) {
19808
+ // Keep reference to the first node in this view,
19809
+ // so it can be accessed while invoking template instructions.
19810
+ view.firstChild = currentRNode;
19811
+ // Move over to the next node after this view, which can
19812
+ // either be a first node of the next view or an anchor comment
19813
+ // node after the last view in a container.
19814
+ currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
19815
+ }
19816
+ dehydratedViews.push(view);
19817
+ }
19818
+ }
19819
+ return [currentRNode, dehydratedViews];
19820
+ }
19821
+ /**
19822
+ * Reference to a function that searches for a matching dehydrated views
19823
+ * stored on a given lContainer.
19824
+ * Returns `null` by default, when hydration is not enabled.
19825
+ */
19826
+ let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
19827
+ /**
19828
+ * Retrieves the next dehydrated view from the LContainer and verifies that
19829
+ * it matches a given template id (from the TView that was used to create this
19830
+ * instance of a view). If the id doesn't match, that means that we are in an
19831
+ * unexpected state and can not complete the reconciliation process. Thus,
19832
+ * all dehydrated views from this LContainer are removed (including corresponding
19833
+ * DOM nodes) and the rendering is performed as if there were no dehydrated views
19834
+ * in this container.
19835
+ */
19836
+ function findMatchingDehydratedViewImpl(lContainer, template) {
19837
+ const views = lContainer[DEHYDRATED_VIEWS] ?? [];
19838
+ if (!template || views.length === 0) {
19839
+ return null;
19840
+ }
19841
+ const view = views[0];
19842
+ // Verify whether the first dehydrated view in the container matches
19843
+ // the template id passed to this function (that originated from a TView
19844
+ // that was used to create an instance of an embedded or component views.
19845
+ if (view.data[TEMPLATE_ID] === template) {
19846
+ // If the template id matches - extract the first view and return it.
19847
+ return views.shift();
19848
+ }
19849
+ else {
19850
+ // Otherwise, we are at the state when reconciliation can not be completed,
19851
+ // thus we remove all dehydrated views within this container (remove them
19852
+ // from internal data structures as well as delete associated elements from
19853
+ // the DOM tree).
19854
+ removeDehydratedViews(lContainer);
19855
+ return null;
19856
+ }
19857
+ }
19858
+ function enableFindMatchingDehydratedViewImpl() {
19859
+ _findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
19860
+ }
19861
+ function findMatchingDehydratedView(lContainer, template) {
19862
+ return _findMatchingDehydratedViewImpl(lContainer, template);
19863
+ }
19864
+
19865
+ /**
19866
+ * Represents a container where one or more views can be attached to a component.
19867
+ *
19868
+ * Can contain *host views* (created by instantiating a
19869
+ * component with the `createComponent()` method), and *embedded views*
19870
+ * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
19871
+ *
19872
+ * A view container instance can contain other view containers,
19873
+ * creating a [view hierarchy](guide/glossary#view-hierarchy).
19874
+ *
19875
+ * @usageNotes
19876
+ *
19877
+ * The example below demonstrates how the `createComponent` function can be used
19878
+ * to create an instance of a ComponentRef dynamically and attach it to an ApplicationRef,
19879
+ * so that it gets included into change detection cycles.
19880
+ *
19881
+ * Note: the example uses standalone components, but the function can also be used for
19882
+ * non-standalone components (declared in an NgModule) as well.
19883
+ *
19884
+ * ```typescript
19885
+ * @Component({
19886
+ * standalone: true,
19887
+ * selector: 'dynamic',
19888
+ * template: `<span>This is a content of a dynamic component.</span>`,
19889
+ * })
19890
+ * class DynamicComponent {
19891
+ * vcr = inject(ViewContainerRef);
19892
+ * }
19893
+ *
19894
+ * @Component({
19895
+ * standalone: true,
19896
+ * selector: 'app',
19897
+ * template: `<main>Hi! This is the main content.</main>`,
19898
+ * })
19899
+ * class AppComponent {
19900
+ * vcr = inject(ViewContainerRef);
19901
+ *
19902
+ * ngAfterViewInit() {
19903
+ * const compRef = this.vcr.createComponent(DynamicComponent);
19904
+ * compRef.changeDetectorRef.detectChanges();
19905
+ * }
19906
+ * }
19907
+ * ```
19908
+ *
19909
+ * @see {@link ComponentRef}
19910
+ * @see {@link EmbeddedViewRef}
19911
+ *
19912
+ * @publicApi
19913
+ */
19914
+ class ViewContainerRef {
19915
+ /**
19916
+ * @internal
19917
+ * @nocollapse
19918
+ */
19919
+ static { this.__NG_ELEMENT_ID__ = injectViewContainerRef; }
19920
+ }
19921
+ /**
19922
+ * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
19923
+ * already exists, retrieves the existing ViewContainerRef.
19924
+ *
19925
+ * @returns The ViewContainerRef instance to use
19926
+ */
19927
+ function injectViewContainerRef() {
19928
+ const previousTNode = getCurrentTNode();
19929
+ return createContainerRef(previousTNode, getLView());
19930
+ }
19931
+ const VE_ViewContainerRef = ViewContainerRef;
19932
+ // TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
19933
+ // for that lands, this can be cleaned up.
19934
+ const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
19935
+ constructor(_lContainer, _hostTNode, _hostLView) {
19936
+ super();
19937
+ this._lContainer = _lContainer;
19938
+ this._hostTNode = _hostTNode;
19939
+ this._hostLView = _hostLView;
19940
+ }
19941
+ get element() {
19942
+ return createElementRef(this._hostTNode, this._hostLView);
19943
+ }
19944
+ get injector() {
19945
+ return new NodeInjector(this._hostTNode, this._hostLView);
19946
+ }
19947
+ /** @deprecated No replacement */
19948
+ get parentInjector() {
19949
+ const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
19950
+ if (hasParentInjector(parentLocation)) {
19951
+ const parentView = getParentInjectorView(parentLocation, this._hostLView);
19952
+ const injectorIndex = getParentInjectorIndex(parentLocation);
19953
+ ngDevMode && assertNodeInjector(parentView, injectorIndex);
19954
+ const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
19955
+ return new NodeInjector(parentTNode, parentView);
19956
+ }
19957
+ else {
19958
+ return new NodeInjector(null, this._hostLView);
19959
+ }
19960
+ }
19961
+ clear() {
19962
+ while (this.length > 0) {
19963
+ this.remove(this.length - 1);
19964
+ }
19965
+ }
19966
+ get(index) {
19967
+ const viewRefs = getViewRefs(this._lContainer);
19968
+ return viewRefs !== null && viewRefs[index] || null;
19969
+ }
19970
+ get length() {
19971
+ return this._lContainer.length - CONTAINER_HEADER_OFFSET;
19972
+ }
19973
+ createEmbeddedView(templateRef, context, indexOrOptions) {
19974
+ let index;
19975
+ let injector;
19976
+ if (typeof indexOrOptions === 'number') {
19977
+ index = indexOrOptions;
19978
+ }
19979
+ else if (indexOrOptions != null) {
19980
+ index = indexOrOptions.index;
19981
+ injector = indexOrOptions.injector;
19982
+ }
19983
+ const dehydratedView = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
19984
+ const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, dehydratedView);
19985
+ this.insertImpl(viewRef, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
19986
+ return viewRef;
19987
+ }
19988
+ createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
19989
+ const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
19990
+ let index;
19991
+ // This function supports 2 signatures and we need to handle options correctly for both:
19992
+ // 1. When first argument is a Component type. This signature also requires extra
19993
+ // options to be provided as object (more ergonomic option).
19994
+ // 2. First argument is a Component factory. In this case extra options are represented as
19995
+ // positional arguments. This signature is less ergonomic and will be deprecated.
19996
+ if (isComponentFactory) {
19997
+ if (ngDevMode) {
19998
+ assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
19999
+ 'and an options object as the second argument. This combination of arguments ' +
20000
+ 'is incompatible. You can either change the first argument to provide Component ' +
20001
+ 'type or change the second argument to be a number (representing an index at ' +
20002
+ 'which to insert the new component\'s host view into this container)');
20003
+ }
20004
+ index = indexOrOptions;
20005
+ }
20006
+ else {
20007
+ if (ngDevMode) {
20008
+ assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
20009
+ `Please check whether provided class has @Component decorator.`);
20010
+ assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
20011
+ 'and a number (representing an index at which to insert the new component\'s ' +
20012
+ 'host view into this container as the second argument. This combination of arguments ' +
20013
+ 'is incompatible. Please use an object as the second argument instead.');
20014
+ }
20015
+ const options = (indexOrOptions || {});
20016
+ if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
20017
+ throwError(`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`);
20018
+ }
20019
+ index = options.index;
20020
+ injector = options.injector;
20021
+ projectableNodes = options.projectableNodes;
20022
+ environmentInjector = options.environmentInjector || options.ngModuleRef;
20023
+ }
20024
+ const componentFactory = isComponentFactory ?
20025
+ componentFactoryOrType :
20026
+ new ComponentFactory(getComponentDef(componentFactoryOrType));
20027
+ const contextInjector = injector || this.parentInjector;
20028
+ // If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
20029
+ if (!environmentInjector && componentFactory.ngModule == null) {
20030
+ // For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that
20031
+ // an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an
20032
+ // `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
20033
+ // use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
20034
+ // using a provided injector first, then fall back to the parent injector of this
20035
+ // `ViewContainerRef` instance.
20036
+ //
20037
+ // For the factory-less case, it's critical to establish a connection with the module
20038
+ // injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
20039
+ // so that a component can use DI tokens provided in MgModules. For this reason, we can not
20040
+ // rely on the provided injector, since it might be detached from the DI tree (for example, if
20041
+ // it was created via `Injector.create` without specifying a parent injector, or if an
20042
+ // injector is retrieved from an `NgModuleRef` created via `createNgModule` using an
20043
+ // NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
20044
+ // injector, which is normally connected to the DI tree, which includes module injector
20045
+ // subtree.
20046
+ const _injector = isComponentFactory ? contextInjector : this.parentInjector;
20047
+ // DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
20048
+ // undefined` expression which seems to cause internal google apps to fail. This is documented
20049
+ // in the following internal bug issue: go/b/142967802
20050
+ const result = _injector.get(EnvironmentInjector, null);
20051
+ if (result) {
20052
+ environmentInjector = result;
20053
+ }
20054
+ }
20055
+ const componentDef = getComponentDef(componentFactory.componentType ?? {});
20056
+ const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
20057
+ const rNode = dehydratedView?.firstChild ?? null;
20058
+ const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
20059
+ this.insertImpl(componentRef.hostView, index, shouldAddViewToDom(this._hostTNode, dehydratedView));
20060
+ return componentRef;
20061
+ }
20062
+ insert(viewRef, index) {
20063
+ return this.insertImpl(viewRef, index, true);
20064
+ }
20065
+ insertImpl(viewRef, index, addToDOM) {
20066
+ const lView = viewRef._lView;
20067
+ if (ngDevMode && viewRef.destroyed) {
20068
+ throw new Error('Cannot insert a destroyed View in a ViewContainer!');
20069
+ }
20070
+ if (viewAttachedToContainer(lView)) {
20071
+ // If view is already attached, detach it first so we clean up references appropriately.
20072
+ const prevIdx = this.indexOf(viewRef);
20073
+ // A view might be attached either to this or a different container. The `prevIdx` for
20074
+ // those cases will be:
20075
+ // equal to -1 for views attached to this ViewContainerRef
20076
+ // >= 0 for views attached to a different ViewContainerRef
20077
+ if (prevIdx !== -1) {
20078
+ this.detach(prevIdx);
20079
+ }
20080
+ else {
20081
+ const prevLContainer = lView[PARENT];
20082
+ ngDevMode &&
20083
+ assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.');
20084
+ // We need to re-create a R3ViewContainerRef instance since those are not stored on
20085
+ // LView (nor anywhere else).
20086
+ const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
20087
+ prevVCRef.detach(prevVCRef.indexOf(viewRef));
20088
+ }
20089
+ }
20090
+ // Logical operation of adding `LView` to `LContainer`
20091
+ const adjustedIdx = this._adjustIndex(index);
20092
+ const lContainer = this._lContainer;
20093
+ addLViewToLContainer(lContainer, lView, adjustedIdx, addToDOM);
20094
+ viewRef.attachToViewContainerRef();
20095
+ addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
20096
+ return viewRef;
20097
+ }
20098
+ move(viewRef, newIndex) {
20099
+ if (ngDevMode && viewRef.destroyed) {
20100
+ throw new Error('Cannot move a destroyed View in a ViewContainer!');
20101
+ }
20102
+ return this.insert(viewRef, newIndex);
20103
+ }
20104
+ indexOf(viewRef) {
20105
+ const viewRefsArr = getViewRefs(this._lContainer);
20106
+ return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
20107
+ }
20108
+ remove(index) {
20109
+ const adjustedIdx = this._adjustIndex(index, -1);
20110
+ const detachedView = detachView(this._lContainer, adjustedIdx);
20111
+ if (detachedView) {
20112
+ // Before destroying the view, remove it from the container's array of `ViewRef`s.
20113
+ // This ensures the view container length is updated before calling
20114
+ // `destroyLView`, which could recursively call view container methods that
20115
+ // rely on an accurate container length.
20116
+ // (e.g. a method on this view container being called by a child directive's OnDestroy
20117
+ // lifecycle hook)
20118
+ removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
20119
+ destroyLView(detachedView[TVIEW], detachedView);
20120
+ }
20121
+ }
20122
+ detach(index) {
20123
+ const adjustedIdx = this._adjustIndex(index, -1);
20124
+ const view = detachView(this._lContainer, adjustedIdx);
20125
+ const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
20126
+ return wasDetached ? new ViewRef$1(view) : null;
20127
+ }
20128
+ _adjustIndex(index, shift = 0) {
20129
+ if (index == null) {
20130
+ return this.length + shift;
20131
+ }
20132
+ if (ngDevMode) {
20133
+ assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
20134
+ // +1 because it's legal to insert at the end.
20135
+ assertLessThan(index, this.length + 1 + shift, 'index');
20136
+ }
20137
+ return index;
20138
+ }
20139
+ };
20140
+ function getViewRefs(lContainer) {
20141
+ return lContainer[VIEW_REFS];
20142
+ }
20143
+ function getOrCreateViewRefs(lContainer) {
20144
+ return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = []));
20145
+ }
20146
+ /**
20147
+ * Creates a ViewContainerRef and stores it on the injector.
20148
+ *
20149
+ * @param hostTNode The node that is requesting a ViewContainerRef
20150
+ * @param hostLView The view to which the node belongs
20151
+ * @returns The ViewContainerRef instance to use
20152
+ */
20153
+ function createContainerRef(hostTNode, hostLView) {
20154
+ ngDevMode && assertTNodeType(hostTNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
20155
+ let lContainer;
20156
+ const slotValue = hostLView[hostTNode.index];
20157
+ if (isLContainer(slotValue)) {
20158
+ // If the host is a container, we don't need to create a new LContainer
20159
+ lContainer = slotValue;
20160
+ }
20161
+ else {
20162
+ // An LContainer anchor can not be `null`, but we set it here temporarily
20163
+ // and update to the actual value later in this function (see
20164
+ // `_locateOrCreateAnchorNode`).
20165
+ lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
20166
+ hostLView[hostTNode.index] = lContainer;
20167
+ addToViewTree(hostLView, lContainer);
20168
+ }
20169
+ _locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
20170
+ return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
20171
+ }
20172
+ /**
20173
+ * Creates and inserts a comment node that acts as an anchor for a view container.
20174
+ *
20175
+ * If the host is a regular element, we have to insert a comment node manually which will
20176
+ * be used as an anchor when inserting elements. In this specific case we use low-level DOM
20177
+ * manipulation to insert it.
20178
+ */
20179
+ function insertAnchorNode(hostLView, hostTNode) {
20180
+ const renderer = hostLView[RENDERER];
20181
+ ngDevMode && ngDevMode.rendererCreateComment++;
20182
+ const commentNode = renderer.createComment(ngDevMode ? 'container' : '');
20183
+ const hostNative = getNativeByTNode(hostTNode, hostLView);
20184
+ const parentOfHostNative = nativeParentNode(renderer, hostNative);
20185
+ nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
20186
+ return commentNode;
20187
+ }
20188
+ let _locateOrCreateAnchorNode = createAnchorNode;
20189
+ let _populateDehydratedViewsInContainer = (lContainer, lView, tNode) => false; // noop by default
20190
+ /**
20191
+ * Looks up dehydrated views that belong to a given LContainer and populates
20192
+ * this information into the `LContainer[DEHYDRATED_VIEWS]` slot. When running
20193
+ * in client-only mode, this function is a noop.
20194
+ *
20195
+ * @param lContainer LContainer that should be populated.
20196
+ * @returns a boolean flag that indicates whether a populating operation
20197
+ * was successful. The operation might be unsuccessful in case is has completed
20198
+ * previously, we are rendering in client-only mode or this content is located
20199
+ * in a skip hydration section.
20200
+ */
20201
+ function populateDehydratedViewsInContainer(lContainer) {
20202
+ return _populateDehydratedViewsInContainer(lContainer, getLView(), getCurrentTNode());
20203
+ }
20204
+ /**
20205
+ * Regular creation mode: an anchor is created and
20206
+ * assigned to the `lContainer[NATIVE]` slot.
20207
+ */
20208
+ function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
20209
+ // We already have a native element (anchor) set, return.
20210
+ if (lContainer[NATIVE])
20211
+ return;
20212
+ let commentNode;
20213
+ // If the host is an element container, the native host element is guaranteed to be a
20214
+ // comment and we can reuse that comment as anchor element for the new LContainer.
20215
+ // The comment node in question is already part of the DOM structure so we don't need to append
20216
+ // it again.
20217
+ if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
20218
+ commentNode = unwrapRNode(slotValue);
20219
+ }
20220
+ else {
20221
+ commentNode = insertAnchorNode(hostLView, hostTNode);
20222
+ }
20223
+ lContainer[NATIVE] = commentNode;
20224
+ }
20225
+ /**
20226
+ * Hydration logic that looks up all dehydrated views in this container
20227
+ * and puts them into `lContainer[DEHYDRATED_VIEWS]` slot.
20228
+ *
20229
+ * @returns a boolean flag that indicates whether a populating operation
20230
+ * was successful. The operation might be unsuccessful in case is has completed
20231
+ * previously, we are rendering in client-only mode or this content is located
20232
+ * in a skip hydration section.
20233
+ */
20234
+ function populateDehydratedViewsInContainerImpl(lContainer, hostLView, hostTNode) {
20235
+ // We already have a native element (anchor) set and the process
20236
+ // of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
20237
+ // is not null), exit early.
20238
+ if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS]) {
20239
+ return true;
20240
+ }
20241
+ const hydrationInfo = hostLView[HYDRATION];
20242
+ const noOffsetIndex = hostTNode.index - HEADER_OFFSET;
20243
+ // TODO(akushnir): this should really be a single condition, refactor the code
20244
+ // to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
20245
+ const skipHydration = isInSkipHydrationBlock(hostTNode) || hasInSkipHydrationBlockFlag(hostTNode);
20246
+ const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode$1(hydrationInfo, noOffsetIndex);
20247
+ // Regular creation mode.
20248
+ if (isNodeCreationMode) {
20249
+ return false;
20250
+ }
20251
+ // Hydration mode, looking up an anchor node and dehydrated views in DOM.
20252
+ const currentRNode = getSegmentHead(hydrationInfo, noOffsetIndex);
20253
+ const serializedViews = hydrationInfo.data[CONTAINERS]?.[noOffsetIndex];
20254
+ ngDevMode &&
20255
+ assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
20256
+ 'which represents a view container.');
20257
+ const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
20258
+ if (ngDevMode) {
20259
+ validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, hostTNode, true);
20260
+ // Do not throw in case this node is already claimed (thus `false` as a second
20261
+ // argument). If this container is created based on an `<ng-template>`, the comment
20262
+ // node would be already claimed from the `template` instruction. If an element acts
20263
+ // as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
20264
+ // so we need to claim it here.
20265
+ markRNodeAsClaimedByHydration(commentNode, false);
20266
+ }
20267
+ lContainer[NATIVE] = commentNode;
20268
+ lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
20269
+ return true;
20270
+ }
20271
+ function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
20272
+ if (!_populateDehydratedViewsInContainer(lContainer, hostLView, hostTNode)) {
20273
+ // Populating dehydrated views operation returned `false`, which indicates
20274
+ // that the logic was running in client-only mode, this an anchor comment
20275
+ // node should be created for this container.
20276
+ createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
20277
+ }
20278
+ }
20279
+ function enableLocateOrCreateContainerRefImpl() {
20280
+ _locateOrCreateAnchorNode = locateOrCreateAnchorNode;
20281
+ _populateDehydratedViewsInContainer = populateDehydratedViewsInContainerImpl;
20282
+ }
20283
+
20284
+ const DEFER_BLOCK_STATE = 0;
20285
+
20286
+ /**
20287
+ * Returns whether defer blocks should be triggered.
20288
+ *
20289
+ * Currently, defer blocks are not triggered on the server,
20290
+ * only placeholder content is rendered (if provided).
20291
+ */
20292
+ function shouldTriggerDeferBlock(injector) {
20293
+ return isPlatformBrowser(injector);
20294
+ }
20295
+ /**
20296
+ * Shims for the `requestIdleCallback` and `cancelIdleCallback` functions for environments
20297
+ * where those functions are not available (e.g. Node.js).
20298
+ */
20299
+ const _requestIdleCallback = typeof requestIdleCallback !== 'undefined' ? requestIdleCallback : setTimeout;
20300
+ const _cancelIdleCallback = typeof requestIdleCallback !== 'undefined' ? cancelIdleCallback : clearTimeout;
20301
+ /**
20302
+ * Creates runtime data structures for `{#defer}` blocks.
20303
+ *
20304
+ * @param index Index of the `defer` instruction.
20305
+ * @param primaryTmplIndex Index of the template with the primary block content.
20306
+ * @param dependencyResolverFn Function that contains dependencies for this defer block.
20307
+ * @param loadingTmplIndex Index of the template with the `{:loading}` block content.
20308
+ * @param placeholderTmplIndex Index of the template with the `{:placeholder}` block content.
20309
+ * @param errorTmplIndex Index of the template with the `{:error}` block content.
20310
+ * @param loadingConfigIndex Index in the constants array of the configuration of the `{:loading}`.
20311
+ * block.
20312
+ * @param placeholderConfigIndexIndex in the constants array of the configuration of the
20313
+ * `{:placeholder}` block.
20314
+ *
20315
+ * @codeGenApi
20316
+ */
20317
+ function ɵɵdefer(index, primaryTmplIndex, dependencyResolverFn, loadingTmplIndex, placeholderTmplIndex, errorTmplIndex, loadingConfigIndex, placeholderConfigIndex) {
20318
+ const lView = getLView();
20319
+ const tView = getTView();
20320
+ const tViewConsts = tView.consts;
20321
+ const adjustedIndex = index + HEADER_OFFSET;
20322
+ ɵɵtemplate(index, null, 0, 0);
20323
+ if (tView.firstCreatePass) {
20324
+ const deferBlockConfig = {
20325
+ primaryTmplIndex,
20326
+ loadingTmplIndex: loadingTmplIndex ?? null,
20327
+ placeholderTmplIndex: placeholderTmplIndex ?? null,
20328
+ errorTmplIndex: errorTmplIndex ?? null,
20329
+ placeholderBlockConfig: placeholderConfigIndex != null ?
20330
+ getConstant(tViewConsts, placeholderConfigIndex) :
20331
+ null,
20332
+ loadingBlockConfig: loadingConfigIndex != null ?
20333
+ getConstant(tViewConsts, loadingConfigIndex) :
20334
+ null,
20335
+ dependencyResolverFn: dependencyResolverFn ?? null,
20336
+ loadingState: 0 /* DeferDependenciesLoadingState.NOT_STARTED */,
20337
+ loadingPromise: null,
20338
+ };
20339
+ setTDeferBlockDetails(tView, adjustedIndex, deferBlockConfig);
20340
+ }
20341
+ // Lookup dehydrated views that belong to this LContainer.
20342
+ // In client-only mode, this operation is noop.
20343
+ const lContainer = lView[adjustedIndex];
20344
+ populateDehydratedViewsInContainer(lContainer);
20345
+ // Init instance-specific defer details and store it.
20346
+ const lDetails = [];
20347
+ lDetails[DEFER_BLOCK_STATE] = 0 /* DeferBlockInstanceState.INITIAL */;
20348
+ setLDeferBlockDetails(lView, adjustedIndex, lDetails);
20349
+ }
20350
+ /**
20351
+ * Loads defer block dependencies when a trigger value becomes truthy.
20352
+ * @codeGenApi
20353
+ */
20354
+ function ɵɵdeferWhen(rawValue) {
20355
+ const lView = getLView();
20356
+ const bindingIndex = nextBindingIndex();
20357
+ if (bindingUpdated(lView, bindingIndex, rawValue)) {
20358
+ const value = Boolean(rawValue); // handle truthy or falsy values
20359
+ const tNode = getSelectedTNode();
20360
+ const lDetails = getLDeferBlockDetails(lView, tNode);
20361
+ const renderedState = lDetails[DEFER_BLOCK_STATE];
20362
+ if (value === false && renderedState === 0 /* DeferBlockInstanceState.INITIAL */) {
20363
+ // If nothing is rendered yet, render a placeholder (if defined).
20364
+ renderPlaceholder(lView, tNode);
20365
+ }
20366
+ else if (value === true &&
20367
+ (renderedState === 0 /* DeferBlockInstanceState.INITIAL */ ||
20368
+ renderedState === 1 /* DeferBlockInstanceState.PLACEHOLDER */)) {
20369
+ // The `when` condition has changed to `true`, trigger defer block loading
20370
+ // if the block is either in initial (nothing is rendered) or a placeholder
20371
+ // state.
20372
+ triggerDeferBlock(lView, tNode);
20373
+ }
20374
+ }
20375
+ }
20376
+ /**
20377
+ * Prefetches the deferred content when a value becomes truthy.
20378
+ * @codeGenApi
20379
+ */
20380
+ function ɵɵdeferPrefetchWhen(rawValue) {
20381
+ const lView = getLView();
20382
+ const bindingIndex = nextBindingIndex();
20383
+ if (bindingUpdated(lView, bindingIndex, rawValue)) {
20384
+ const value = Boolean(rawValue); // handle truthy or falsy values
20385
+ const tView = lView[TVIEW];
20386
+ const tNode = getSelectedTNode();
20387
+ const tDetails = getTDeferBlockDetails(tView, tNode);
20388
+ if (value === true && tDetails.loadingState === 0 /* DeferDependenciesLoadingState.NOT_STARTED */) {
20389
+ // If loading has not been started yet, trigger it now.
20390
+ triggerResourceLoading(tDetails, tView, lView);
20391
+ }
20392
+ }
20393
+ }
20394
+ /**
20395
+ * Sets up handlers that represent `on idle` deferred trigger.
20396
+ * @codeGenApi
20397
+ */
20398
+ function ɵɵdeferOnIdle() {
20399
+ const lView = getLView();
20400
+ const tNode = getCurrentTNode();
20401
+ renderPlaceholder(lView, tNode);
20402
+ // Note: we pass an `lView` as a second argument to cancel an `idle`
20403
+ // callback in case an LView got destroyed before an `idle` callback
20404
+ // is invoked.
20405
+ onIdle(() => triggerDeferBlock(lView, tNode), lView);
20406
+ }
20407
+ /**
20408
+ * Creates runtime data structures for the `prefetch on idle` deferred trigger.
20409
+ * @codeGenApi
20410
+ */
20411
+ function ɵɵdeferPrefetchOnIdle() {
20412
+ const lView = getLView();
20413
+ const tNode = getCurrentTNode();
20414
+ const tView = lView[TVIEW];
20415
+ const tDetails = getTDeferBlockDetails(tView, tNode);
20416
+ if (tDetails.loadingState === 0 /* DeferDependenciesLoadingState.NOT_STARTED */) {
20417
+ // Set loading to the scheduled state, so that we don't register it again.
20418
+ tDetails.loadingState = 1 /* DeferDependenciesLoadingState.SCHEDULED */;
20419
+ // In case of prefetching, we intentionally avoid cancelling prefetching if
20420
+ // an underlying LView get destroyed (thus passing `null` as a second argument),
20421
+ // because there might be other LViews (that represent embedded views) that
20422
+ // depend on resource loading.
20423
+ onIdle(() => triggerResourceLoading(tDetails, tView, lView), null /* LView */);
20424
+ }
20425
+ }
20426
+ /**
20427
+ * Creates runtime data structures for the `on immediate` deferred trigger.
20428
+ * @codeGenApi
20429
+ */
20430
+ function ɵɵdeferOnImmediate() { } // TODO: implement runtime logic.
20431
+ /**
20432
+ * Creates runtime data structures for the `prefetch on immediate` deferred trigger.
20433
+ * @codeGenApi
20434
+ */
20435
+ function ɵɵdeferPrefetchOnImmediate() { } // TODO: implement runtime logic.
20436
+ /**
20437
+ * Creates runtime data structures for the `on timer` deferred trigger.
19794
20438
  * @param delay Amount of time to wait before loading the content.
19795
20439
  * @codeGenApi
19796
20440
  */
@@ -19836,6 +20480,35 @@ function ɵɵdeferOnViewport(target) { } // TODO: implement runtime logic.
19836
20480
  */
19837
20481
  function ɵɵdeferPrefetchOnViewport(target) { } // TODO: implement runtime logic.
19838
20482
  /********** Helper functions **********/
20483
+ /**
20484
+ * Helper function to schedule a callback to be invoked when a browser becomes idle.
20485
+ *
20486
+ * @param callback A function to be invoked when a browser becomes idle.
20487
+ * @param lView An optional LView that hosts an instance of a defer block. LView is
20488
+ * used to register a cleanup callback in case that LView got destroyed before
20489
+ * callback was invoked. In this case, an `idle` callback is never invoked. This is
20490
+ * helpful for cases when a defer block has scheduled rendering, but an underlying
20491
+ * LView got destroyed prior to th block rendering.
20492
+ */
20493
+ function onIdle(callback, lView) {
20494
+ let id;
20495
+ const removeIdleCallback = () => _cancelIdleCallback(id);
20496
+ id = _requestIdleCallback(() => {
20497
+ removeIdleCallback();
20498
+ if (lView !== null) {
20499
+ // The idle callback is invoked, we no longer need
20500
+ // to retain a cleanup callback in an LView.
20501
+ removeLViewOnDestroy(lView, removeIdleCallback);
20502
+ }
20503
+ callback();
20504
+ });
20505
+ if (lView !== null) {
20506
+ // Store a cleanup function on LView, so that we cancel idle
20507
+ // callback in case this LView is destroyed before a callback
20508
+ // is invoked.
20509
+ storeLViewOnDestroy(lView, removeIdleCallback);
20510
+ }
20511
+ }
19839
20512
  /**
19840
20513
  * Calculates a data slot index for defer block info (either static or
19841
20514
  * instance-specific), given an index of a defer instruction.
@@ -19903,27 +20576,31 @@ function renderDeferBlockState(newState, tNode, lContainer, stateTmplIndex) {
19903
20576
  // represents a `{#defer}` block, so always refer to the first one.
19904
20577
  const viewIndex = 0;
19905
20578
  removeLViewFromLContainer(lContainer, viewIndex);
19906
- const embeddedLView = createAndRenderEmbeddedLView(hostLView, tNode, null);
19907
- addLViewToLContainer(lContainer, embeddedLView, viewIndex);
20579
+ const dehydratedView = findMatchingDehydratedView(lContainer, tNode.tView.ssrId);
20580
+ const embeddedLView = createAndRenderEmbeddedLView(hostLView, tNode, null, { dehydratedView });
20581
+ addLViewToLContainer(lContainer, embeddedLView, viewIndex, shouldAddViewToDom(tNode, dehydratedView));
19908
20582
  }
19909
20583
  }
19910
20584
  /**
19911
20585
  * Trigger loading of defer block dependencies if the process hasn't started yet.
19912
20586
  *
19913
20587
  * @param tDetails Static information about this defer block.
19914
- * @param primaryBlockTNode TNode of a primary block template.
19915
- * @param injector Environment injector of the application.
20588
+ * @param tView TView of a host view.
20589
+ * @param lView LView of a host view.
19916
20590
  */
19917
- function triggerResourceLoading(tDetails, primaryBlockTNode, injector) {
19918
- const tView = primaryBlockTNode.tView;
19919
- if (tDetails.loadingState !== 0 /* DeferDependenciesLoadingState.NOT_STARTED */) {
20591
+ function triggerResourceLoading(tDetails, tView, lView) {
20592
+ const injector = lView[INJECTOR$1];
20593
+ if (!shouldTriggerDeferBlock(injector) ||
20594
+ (tDetails.loadingState !== 0 /* DeferDependenciesLoadingState.NOT_STARTED */ &&
20595
+ tDetails.loadingState !== 1 /* DeferDependenciesLoadingState.SCHEDULED */)) {
19920
20596
  // If the loading status is different from initial one, it means that
19921
20597
  // the loading of dependencies is in progress and there is nothing to do
19922
20598
  // in this function. All details can be obtained from the `tDetails` object.
19923
20599
  return;
19924
20600
  }
20601
+ const primaryBlockTNode = getPrimaryBlockTNode(tView, tDetails);
19925
20602
  // Switch from NOT_STARTED -> IN_PROGRESS state.
19926
- tDetails.loadingState = 1 /* DeferDependenciesLoadingState.IN_PROGRESS */;
20603
+ tDetails.loadingState = 2 /* DeferDependenciesLoadingState.IN_PROGRESS */;
19927
20604
  // Check if dependency function interceptor is configured.
19928
20605
  const deferDependencyInterceptor = injector.get(DEFER_BLOCK_DEPENDENCY_INTERCEPTOR, null, { optional: true });
19929
20606
  const dependenciesFn = deferDependencyInterceptor ?
@@ -19934,7 +20611,7 @@ function triggerResourceLoading(tDetails, primaryBlockTNode, injector) {
19934
20611
  // thus no dynamic `import()`s were produced.
19935
20612
  if (!dependenciesFn) {
19936
20613
  tDetails.loadingPromise = Promise.resolve().then(() => {
19937
- tDetails.loadingState = 2 /* DeferDependenciesLoadingState.COMPLETE */;
20614
+ tDetails.loadingState = 3 /* DeferDependenciesLoadingState.COMPLETE */;
19938
20615
  });
19939
20616
  return;
19940
20617
  }
@@ -19965,18 +20642,21 @@ function triggerResourceLoading(tDetails, primaryBlockTNode, injector) {
19965
20642
  // Loading is completed, we no longer need this Promise.
19966
20643
  tDetails.loadingPromise = null;
19967
20644
  if (failed) {
19968
- tDetails.loadingState = 3 /* DeferDependenciesLoadingState.FAILED */;
20645
+ tDetails.loadingState = 4 /* DeferDependenciesLoadingState.FAILED */;
19969
20646
  }
19970
20647
  else {
19971
- tDetails.loadingState = 2 /* DeferDependenciesLoadingState.COMPLETE */;
20648
+ tDetails.loadingState = 3 /* DeferDependenciesLoadingState.COMPLETE */;
19972
20649
  // Update directive and pipe registries to add newly downloaded dependencies.
20650
+ const primaryBlockTView = primaryBlockTNode.tView;
19973
20651
  if (directiveDefs.length > 0) {
19974
- tView.directiveRegistry = tView.directiveRegistry ?
19975
- [...tView.directiveRegistry, ...directiveDefs] :
20652
+ primaryBlockTView.directiveRegistry = primaryBlockTView.directiveRegistry ?
20653
+ [...primaryBlockTView.directiveRegistry, ...directiveDefs] :
19976
20654
  directiveDefs;
19977
20655
  }
19978
20656
  if (pipeDefs.length > 0) {
19979
- tView.pipeRegistry = tView.pipeRegistry ? [...tView.pipeRegistry, ...pipeDefs] : pipeDefs;
20657
+ primaryBlockTView.pipeRegistry = primaryBlockTView.pipeRegistry ?
20658
+ [...primaryBlockTView.pipeRegistry, ...pipeDefs] :
20659
+ pipeDefs;
19980
20660
  }
19981
20661
  }
19982
20662
  });
@@ -20000,12 +20680,12 @@ function renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer) {
20000
20680
  ngDevMode &&
20001
20681
  assertDefined(tDetails.loadingPromise, 'Expected loading Promise to exist on this defer block');
20002
20682
  tDetails.loadingPromise.then(() => {
20003
- if (tDetails.loadingState === 2 /* DeferDependenciesLoadingState.COMPLETE */) {
20683
+ if (tDetails.loadingState === 3 /* DeferDependenciesLoadingState.COMPLETE */) {
20004
20684
  ngDevMode && assertDeferredDependenciesLoaded(tDetails);
20005
20685
  // Everything is loaded, show the primary block content
20006
20686
  renderDeferBlockState(3 /* DeferBlockInstanceState.COMPLETE */, tNode, lContainer, tDetails.primaryTmplIndex);
20007
20687
  }
20008
- else if (tDetails.loadingState === 3 /* DeferDependenciesLoadingState.FAILED */) {
20688
+ else if (tDetails.loadingState === 4 /* DeferDependenciesLoadingState.FAILED */) {
20009
20689
  renderDeferBlockState(4 /* DeferBlockInstanceState.ERROR */, tNode, lContainer, tDetails.errorTmplIndex);
20010
20690
  }
20011
20691
  });
@@ -20023,28 +20703,32 @@ function getPrimaryBlockTNode(tView, tDetails) {
20023
20703
  function triggerDeferBlock(lView, tNode) {
20024
20704
  const tView = lView[TVIEW];
20025
20705
  const lContainer = lView[tNode.index];
20706
+ const injector = lView[INJECTOR$1];
20026
20707
  ngDevMode && assertLContainer(lContainer);
20708
+ if (!shouldTriggerDeferBlock(injector))
20709
+ return;
20027
20710
  const tDetails = getTDeferBlockDetails(tView, tNode);
20028
20711
  // Condition is triggered, try to render loading state and start downloading.
20029
20712
  // Note: if a block is in a loading, completed or an error state, this call would be a noop.
20030
20713
  renderDeferBlockState(2 /* DeferBlockInstanceState.LOADING */, tNode, lContainer, tDetails.loadingTmplIndex);
20031
20714
  switch (tDetails.loadingState) {
20032
20715
  case 0 /* DeferDependenciesLoadingState.NOT_STARTED */:
20033
- triggerResourceLoading(tDetails, getPrimaryBlockTNode(lView[TVIEW], tDetails), lView[INJECTOR$1]);
20716
+ case 1 /* DeferDependenciesLoadingState.SCHEDULED */:
20717
+ triggerResourceLoading(tDetails, lView[TVIEW], lView);
20034
20718
  // The `loadingState` might have changed to "loading".
20035
20719
  if (tDetails.loadingState ===
20036
- 1 /* DeferDependenciesLoadingState.IN_PROGRESS */) {
20720
+ 2 /* DeferDependenciesLoadingState.IN_PROGRESS */) {
20037
20721
  renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
20038
20722
  }
20039
20723
  break;
20040
- case 1 /* DeferDependenciesLoadingState.IN_PROGRESS */:
20724
+ case 2 /* DeferDependenciesLoadingState.IN_PROGRESS */:
20041
20725
  renderDeferStateAfterResourceLoading(tDetails, tNode, lContainer);
20042
20726
  break;
20043
- case 2 /* DeferDependenciesLoadingState.COMPLETE */:
20727
+ case 3 /* DeferDependenciesLoadingState.COMPLETE */:
20044
20728
  ngDevMode && assertDeferredDependenciesLoaded(tDetails);
20045
20729
  renderDeferBlockState(3 /* DeferBlockInstanceState.COMPLETE */, tNode, lContainer, tDetails.primaryTmplIndex);
20046
20730
  break;
20047
- case 3 /* DeferDependenciesLoadingState.FAILED */:
20731
+ case 4 /* DeferDependenciesLoadingState.FAILED */:
20048
20732
  renderDeferBlockState(4 /* DeferBlockInstanceState.ERROR */, tNode, lContainer, tDetails.errorTmplIndex);
20049
20733
  break;
20050
20734
  default:
@@ -20059,7 +20743,7 @@ function triggerDeferBlock(lView, tNode) {
20059
20743
  * block in completed state.
20060
20744
  */
20061
20745
  function assertDeferredDependenciesLoaded(tDetails) {
20062
- assertEqual(tDetails.loadingState, 2 /* DeferDependenciesLoadingState.COMPLETE */, 'Expecting all deferred dependencies to be loaded.');
20746
+ assertEqual(tDetails.loadingState, 3 /* DeferDependenciesLoadingState.COMPLETE */, 'Expecting all deferred dependencies to be loaded.');
20063
20747
  }
20064
20748
  /**
20065
20749
  * **INTERNAL**, avoid referencing it in application code.
@@ -25363,265 +26047,55 @@ function setClassMetadata(type, decorators, ctorParameters, propDecorators) {
25363
26047
  * If the value hasn't been saved, calls the pure function to store and return the
25364
26048
  * value. If it has been saved, returns the saved value.
25365
26049
  *
25366
- * @param slotOffset the offset from binding root to the reserved slot
25367
- * @param pureFn Function that returns a value
25368
- * @param thisArg Optional calling context of pureFn
25369
- * @returns value
25370
- *
25371
- * @codeGenApi
25372
- */
25373
- function ɵɵpureFunction0(slotOffset, pureFn, thisArg) {
25374
- const bindingIndex = getBindingRoot() + slotOffset;
25375
- const lView = getLView();
25376
- return lView[bindingIndex] === NO_CHANGE ?
25377
- updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
25378
- getBinding(lView, bindingIndex);
25379
- }
25380
- /**
25381
- * If the value of the provided exp has changed, calls the pure function to return
25382
- * an updated value. Or if the value has not changed, returns cached value.
25383
- *
25384
- * @param slotOffset the offset from binding root to the reserved slot
25385
- * @param pureFn Function that returns an updated value
25386
- * @param exp Updated expression value
25387
- * @param thisArg Optional calling context of pureFn
25388
- * @returns Updated or cached value
25389
- *
25390
- * @codeGenApi
25391
- */
25392
- function ɵɵpureFunction1(slotOffset, pureFn, exp, thisArg) {
25393
- return pureFunction1Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp, thisArg);
25394
- }
25395
- /**
25396
- * If the value of any provided exp has changed, calls the pure function to return
25397
- * an updated value. Or if no values have changed, returns cached value.
25398
- *
25399
- * @param slotOffset the offset from binding root to the reserved slot
25400
- * @param pureFn
25401
- * @param exp1
25402
- * @param exp2
25403
- * @param thisArg Optional calling context of pureFn
25404
- * @returns Updated or cached value
25405
- *
25406
- * @codeGenApi
25407
- */
25408
- function ɵɵpureFunction2(slotOffset, pureFn, exp1, exp2, thisArg) {
25409
- return pureFunction2Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, thisArg);
25410
- }
25411
- /**
25412
- * If the value of any provided exp has changed, calls the pure function to return
25413
- * an updated value. Or if no values have changed, returns cached value.
25414
- *
25415
- * @param slotOffset the offset from binding root to the reserved slot
25416
- * @param pureFn
25417
- * @param exp1
25418
- * @param exp2
25419
- * @param exp3
25420
- * @param thisArg Optional calling context of pureFn
25421
- * @returns Updated or cached value
25422
- *
25423
- * @codeGenApi
25424
- */
25425
- function ɵɵpureFunction3(slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
25426
- return pureFunction3Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, thisArg);
25427
- }
25428
- /**
25429
- * If the value of any provided exp has changed, calls the pure function to return
25430
- * an updated value. Or if no values have changed, returns cached value.
25431
- *
25432
- * @param slotOffset the offset from binding root to the reserved slot
25433
- * @param pureFn
25434
- * @param exp1
25435
- * @param exp2
25436
- * @param exp3
25437
- * @param exp4
25438
- * @param thisArg Optional calling context of pureFn
25439
- * @returns Updated or cached value
25440
- *
25441
- * @codeGenApi
25442
- */
25443
- function ɵɵpureFunction4(slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
25444
- return pureFunction4Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg);
25445
- }
25446
- /**
25447
- * If the value of any provided exp has changed, calls the pure function to return
25448
- * an updated value. Or if no values have changed, returns cached value.
25449
- *
25450
- * @param slotOffset the offset from binding root to the reserved slot
25451
- * @param pureFn
25452
- * @param exp1
25453
- * @param exp2
25454
- * @param exp3
25455
- * @param exp4
25456
- * @param exp5
25457
- * @param thisArg Optional calling context of pureFn
25458
- * @returns Updated or cached value
25459
- *
25460
- * @codeGenApi
25461
- */
25462
- function ɵɵpureFunction5(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, thisArg) {
25463
- const bindingIndex = getBindingRoot() + slotOffset;
25464
- const lView = getLView();
25465
- const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
25466
- return bindingUpdated(lView, bindingIndex + 4, exp5) || different ?
25467
- updateBinding(lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
25468
- pureFn(exp1, exp2, exp3, exp4, exp5)) :
25469
- getBinding(lView, bindingIndex + 5);
25470
- }
25471
- /**
25472
- * If the value of any provided exp has changed, calls the pure function to return
25473
- * an updated value. Or if no values have changed, returns cached value.
25474
- *
25475
- * @param slotOffset the offset from binding root to the reserved slot
25476
- * @param pureFn
25477
- * @param exp1
25478
- * @param exp2
25479
- * @param exp3
25480
- * @param exp4
25481
- * @param exp5
25482
- * @param exp6
25483
- * @param thisArg Optional calling context of pureFn
25484
- * @returns Updated or cached value
25485
- *
25486
- * @codeGenApi
25487
- */
25488
- function ɵɵpureFunction6(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, thisArg) {
25489
- const bindingIndex = getBindingRoot() + slotOffset;
25490
- const lView = getLView();
25491
- const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
25492
- return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ?
25493
- updateBinding(lView, bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
25494
- pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
25495
- getBinding(lView, bindingIndex + 6);
25496
- }
25497
- /**
25498
- * If the value of any provided exp has changed, calls the pure function to return
25499
- * an updated value. Or if no values have changed, returns cached value.
25500
- *
25501
- * @param slotOffset the offset from binding root to the reserved slot
25502
- * @param pureFn
25503
- * @param exp1
25504
- * @param exp2
25505
- * @param exp3
25506
- * @param exp4
25507
- * @param exp5
25508
- * @param exp6
25509
- * @param exp7
25510
- * @param thisArg Optional calling context of pureFn
25511
- * @returns Updated or cached value
25512
- *
25513
- * @codeGenApi
25514
- */
25515
- function ɵɵpureFunction7(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, thisArg) {
25516
- const bindingIndex = getBindingRoot() + slotOffset;
25517
- const lView = getLView();
25518
- let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
25519
- return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ?
25520
- updateBinding(lView, bindingIndex + 7, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
25521
- pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
25522
- getBinding(lView, bindingIndex + 7);
25523
- }
25524
- /**
25525
- * If the value of any provided exp has changed, calls the pure function to return
25526
- * an updated value. Or if no values have changed, returns cached value.
25527
- *
25528
- * @param slotOffset the offset from binding root to the reserved slot
25529
- * @param pureFn
25530
- * @param exp1
25531
- * @param exp2
25532
- * @param exp3
25533
- * @param exp4
25534
- * @param exp5
25535
- * @param exp6
25536
- * @param exp7
25537
- * @param exp8
25538
- * @param thisArg Optional calling context of pureFn
25539
- * @returns Updated or cached value
25540
- *
25541
- * @codeGenApi
25542
- */
25543
- function ɵɵpureFunction8(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, thisArg) {
25544
- const bindingIndex = getBindingRoot() + slotOffset;
25545
- const lView = getLView();
25546
- const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
25547
- return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
25548
- updateBinding(lView, bindingIndex + 8, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
25549
- pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
25550
- getBinding(lView, bindingIndex + 8);
25551
- }
25552
- /**
25553
- * pureFunction instruction that can support any number of bindings.
25554
- *
25555
- * If the value of any provided exp has changed, calls the pure function to return
25556
- * an updated value. Or if no values have changed, returns cached value.
25557
- *
25558
- * @param slotOffset the offset from binding root to the reserved slot
25559
- * @param pureFn A pure function that takes binding values and builds an object or array
25560
- * containing those values.
25561
- * @param exps An array of binding values
26050
+ * @param slotOffset the offset from binding root to the reserved slot
26051
+ * @param pureFn Function that returns a value
25562
26052
  * @param thisArg Optional calling context of pureFn
25563
- * @returns Updated or cached value
26053
+ * @returns value
25564
26054
  *
25565
26055
  * @codeGenApi
25566
26056
  */
25567
- function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) {
25568
- return pureFunctionVInternal(getLView(), getBindingRoot(), slotOffset, pureFn, exps, thisArg);
25569
- }
25570
- /**
25571
- * Results of a pure function invocation are stored in LView in a dedicated slot that is initialized
25572
- * to NO_CHANGE. In rare situations a pure pipe might throw an exception on the very first
25573
- * invocation and not produce any valid results. In this case LView would keep holding the NO_CHANGE
25574
- * value. The NO_CHANGE is not something that we can use in expressions / bindings thus we convert
25575
- * it to `undefined`.
25576
- */
25577
- function getPureFunctionReturnValue(lView, returnValueIndex) {
25578
- ngDevMode && assertIndexInRange(lView, returnValueIndex);
25579
- const lastReturnValue = lView[returnValueIndex];
25580
- return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
26057
+ function ɵɵpureFunction0(slotOffset, pureFn, thisArg) {
26058
+ const bindingIndex = getBindingRoot() + slotOffset;
26059
+ const lView = getLView();
26060
+ return lView[bindingIndex] === NO_CHANGE ?
26061
+ updateBinding(lView, bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
26062
+ getBinding(lView, bindingIndex);
25581
26063
  }
25582
26064
  /**
25583
26065
  * If the value of the provided exp has changed, calls the pure function to return
25584
26066
  * an updated value. Or if the value has not changed, returns cached value.
25585
26067
  *
25586
- * @param lView LView in which the function is being executed.
25587
- * @param bindingRoot Binding root index.
25588
26068
  * @param slotOffset the offset from binding root to the reserved slot
25589
26069
  * @param pureFn Function that returns an updated value
25590
26070
  * @param exp Updated expression value
25591
26071
  * @param thisArg Optional calling context of pureFn
25592
26072
  * @returns Updated or cached value
26073
+ *
26074
+ * @codeGenApi
25593
26075
  */
25594
- function pureFunction1Internal(lView, bindingRoot, slotOffset, pureFn, exp, thisArg) {
25595
- const bindingIndex = bindingRoot + slotOffset;
25596
- return bindingUpdated(lView, bindingIndex, exp) ?
25597
- updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
25598
- getPureFunctionReturnValue(lView, bindingIndex + 1);
26076
+ function ɵɵpureFunction1(slotOffset, pureFn, exp, thisArg) {
26077
+ return pureFunction1Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp, thisArg);
25599
26078
  }
25600
26079
  /**
25601
26080
  * If the value of any provided exp has changed, calls the pure function to return
25602
26081
  * an updated value. Or if no values have changed, returns cached value.
25603
26082
  *
25604
- * @param lView LView in which the function is being executed.
25605
- * @param bindingRoot Binding root index.
25606
26083
  * @param slotOffset the offset from binding root to the reserved slot
25607
26084
  * @param pureFn
25608
26085
  * @param exp1
25609
26086
  * @param exp2
25610
26087
  * @param thisArg Optional calling context of pureFn
25611
26088
  * @returns Updated or cached value
26089
+ *
26090
+ * @codeGenApi
25612
26091
  */
25613
- function pureFunction2Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, thisArg) {
25614
- const bindingIndex = bindingRoot + slotOffset;
25615
- return bindingUpdated2(lView, bindingIndex, exp1, exp2) ?
25616
- updateBinding(lView, bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
25617
- getPureFunctionReturnValue(lView, bindingIndex + 2);
26092
+ function ɵɵpureFunction2(slotOffset, pureFn, exp1, exp2, thisArg) {
26093
+ return pureFunction2Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, thisArg);
25618
26094
  }
25619
26095
  /**
25620
26096
  * If the value of any provided exp has changed, calls the pure function to return
25621
26097
  * an updated value. Or if no values have changed, returns cached value.
25622
26098
  *
25623
- * @param lView LView in which the function is being executed.
25624
- * @param bindingRoot Binding root index.
25625
26099
  * @param slotOffset the offset from binding root to the reserved slot
25626
26100
  * @param pureFn
25627
26101
  * @param exp1
@@ -25629,19 +26103,16 @@ function pureFunction2Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp
25629
26103
  * @param exp3
25630
26104
  * @param thisArg Optional calling context of pureFn
25631
26105
  * @returns Updated or cached value
26106
+ *
26107
+ * @codeGenApi
25632
26108
  */
25633
- function pureFunction3Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
25634
- const bindingIndex = bindingRoot + slotOffset;
25635
- return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ?
25636
- updateBinding(lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
25637
- getPureFunctionReturnValue(lView, bindingIndex + 3);
26109
+ function ɵɵpureFunction3(slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
26110
+ return pureFunction3Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, thisArg);
25638
26111
  }
25639
26112
  /**
25640
26113
  * If the value of any provided exp has changed, calls the pure function to return
25641
26114
  * an updated value. Or if no values have changed, returns cached value.
25642
26115
  *
25643
- * @param lView LView in which the function is being executed.
25644
- * @param bindingRoot Binding root index.
25645
26116
  * @param slotOffset the offset from binding root to the reserved slot
25646
26117
  * @param pureFn
25647
26118
  * @param exp1
@@ -25651,1017 +26122,704 @@ function pureFunction3Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp
25651
26122
  * @param thisArg Optional calling context of pureFn
25652
26123
  * @returns Updated or cached value
25653
26124
  *
25654
- */
25655
- function pureFunction4Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
25656
- const bindingIndex = bindingRoot + slotOffset;
25657
- return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ?
25658
- updateBinding(lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
25659
- getPureFunctionReturnValue(lView, bindingIndex + 4);
25660
- }
25661
- /**
25662
- * pureFunction instruction that can support any number of bindings.
25663
- *
25664
- * If the value of any provided exp has changed, calls the pure function to return
25665
- * an updated value. Or if no values have changed, returns cached value.
25666
- *
25667
- * @param lView LView in which the function is being executed.
25668
- * @param bindingRoot Binding root index.
25669
- * @param slotOffset the offset from binding root to the reserved slot
25670
- * @param pureFn A pure function that takes binding values and builds an object or array
25671
- * containing those values.
25672
- * @param exps An array of binding values
25673
- * @param thisArg Optional calling context of pureFn
25674
- * @returns Updated or cached value
25675
- */
25676
- function pureFunctionVInternal(lView, bindingRoot, slotOffset, pureFn, exps, thisArg) {
25677
- let bindingIndex = bindingRoot + slotOffset;
25678
- let different = false;
25679
- for (let i = 0; i < exps.length; i++) {
25680
- bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true);
25681
- }
25682
- return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) :
25683
- getPureFunctionReturnValue(lView, bindingIndex);
25684
- }
25685
-
25686
- /**
25687
- * Create a pipe.
25688
- *
25689
- * @param index Pipe index where the pipe will be stored.
25690
- * @param pipeName The name of the pipe
25691
- * @returns T the instance of the pipe.
25692
- *
25693
- * @codeGenApi
25694
- */
25695
- function ɵɵpipe(index, pipeName) {
25696
- const tView = getTView();
25697
- let pipeDef;
25698
- const adjustedIndex = index + HEADER_OFFSET;
25699
- if (tView.firstCreatePass) {
25700
- // The `getPipeDef` throws if a pipe with a given name is not found
25701
- // (so we use non-null assertion below).
25702
- pipeDef = getPipeDef(pipeName, tView.pipeRegistry);
25703
- tView.data[adjustedIndex] = pipeDef;
25704
- if (pipeDef.onDestroy) {
25705
- (tView.destroyHooks ??= []).push(adjustedIndex, pipeDef.onDestroy);
25706
- }
25707
- }
25708
- else {
25709
- pipeDef = tView.data[adjustedIndex];
25710
- }
25711
- const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true));
25712
- let previousInjectorProfilerContext;
25713
- if (ngDevMode) {
25714
- previousInjectorProfilerContext = setInjectorProfilerContext({
25715
- injector: new NodeInjector(getCurrentTNode(), getLView()),
25716
- token: pipeDef.type
25717
- });
25718
- }
25719
- const previousInjectImplementation = setInjectImplementation(ɵɵdirectiveInject);
25720
- try {
25721
- // DI for pipes is supposed to behave like directives when placed on a component
25722
- // host node, which means that we have to disable access to `viewProviders`.
25723
- const previousIncludeViewProviders = setIncludeViewProviders(false);
25724
- const pipeInstance = pipeFactory();
25725
- setIncludeViewProviders(previousIncludeViewProviders);
25726
- store(tView, getLView(), adjustedIndex, pipeInstance);
25727
- return pipeInstance;
25728
- }
25729
- finally {
25730
- // we have to restore the injector implementation in finally, just in case the creation of the
25731
- // pipe throws an error.
25732
- setInjectImplementation(previousInjectImplementation);
25733
- ngDevMode && setInjectorProfilerContext(previousInjectorProfilerContext);
25734
- }
25735
- }
25736
- /**
25737
- * Searches the pipe registry for a pipe with the given name. If one is found,
25738
- * returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved.
25739
- *
25740
- * @param name Name of pipe to resolve
25741
- * @param registry Full list of available pipes
25742
- * @returns Matching PipeDef
25743
- */
25744
- function getPipeDef(name, registry) {
25745
- if (registry) {
25746
- if (ngDevMode) {
25747
- const pipes = registry.filter(pipe => pipe.name === name);
25748
- // TODO: Throw an error in the next major
25749
- if (pipes.length > 1) {
25750
- console.warn(formatRuntimeError(313 /* RuntimeErrorCode.MULTIPLE_MATCHING_PIPES */, getMultipleMatchingPipesMessage(name)));
25751
- }
25752
- }
25753
- for (let i = registry.length - 1; i >= 0; i--) {
25754
- const pipeDef = registry[i];
25755
- if (name === pipeDef.name) {
25756
- return pipeDef;
25757
- }
25758
- }
25759
- }
25760
- if (ngDevMode) {
25761
- throw new RuntimeError(-302 /* RuntimeErrorCode.PIPE_NOT_FOUND */, getPipeNotFoundErrorMessage(name));
25762
- }
25763
- }
25764
- /**
25765
- * Generates a helpful error message for the user when multiple pipes match the name.
25766
- *
25767
- * @param name Name of the pipe
25768
- * @returns The error message
25769
- */
25770
- function getMultipleMatchingPipesMessage(name) {
25771
- const lView = getLView();
25772
- const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
25773
- const context = declarationLView[CONTEXT];
25774
- const hostIsStandalone = isHostComponentStandalone(lView);
25775
- const componentInfoMessage = context ? ` in the '${context.constructor.name}' component` : '';
25776
- const verifyMessage = `check ${hostIsStandalone ? '\'@Component.imports\' of this component' :
25777
- 'the imports of this module'}`;
25778
- const errorMessage = `Multiple pipes match the name \`${name}\`${componentInfoMessage}. ${verifyMessage}`;
25779
- return errorMessage;
25780
- }
25781
- /**
25782
- * Generates a helpful error message for the user when a pipe is not found.
25783
- *
25784
- * @param name Name of the missing pipe
25785
- * @returns The error message
25786
- */
25787
- function getPipeNotFoundErrorMessage(name) {
25788
- const lView = getLView();
25789
- const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
25790
- const context = declarationLView[CONTEXT];
25791
- const hostIsStandalone = isHostComponentStandalone(lView);
25792
- const componentInfoMessage = context ? ` in the '${context.constructor.name}' component` : '';
25793
- const verifyMessage = `Verify that it is ${hostIsStandalone ? 'included in the \'@Component.imports\' of this component' :
25794
- 'declared or imported in this module'}`;
25795
- const errorMessage = `The pipe '${name}' could not be found${componentInfoMessage}. ${verifyMessage}`;
25796
- return errorMessage;
25797
- }
25798
- /**
25799
- * Invokes a pipe with 1 arguments.
25800
- *
25801
- * This instruction acts as a guard to {@link PipeTransform#transform} invoking
25802
- * the pipe only when an input to the pipe changes.
25803
- *
25804
- * @param index Pipe index where the pipe was stored on creation.
25805
- * @param slotOffset the offset in the reserved slot space
25806
- * @param v1 1st argument to {@link PipeTransform#transform}.
25807
- *
25808
- * @codeGenApi
25809
- */
25810
- function ɵɵpipeBind1(index, slotOffset, v1) {
25811
- const adjustedIndex = index + HEADER_OFFSET;
25812
- const lView = getLView();
25813
- const pipeInstance = load(lView, adjustedIndex);
25814
- return isPure(lView, adjustedIndex) ?
25815
- pureFunction1Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
25816
- pipeInstance.transform(v1);
25817
- }
25818
- /**
25819
- * Invokes a pipe with 2 arguments.
25820
- *
25821
- * This instruction acts as a guard to {@link PipeTransform#transform} invoking
25822
- * the pipe only when an input to the pipe changes.
25823
- *
25824
- * @param index Pipe index where the pipe was stored on creation.
25825
- * @param slotOffset the offset in the reserved slot space
25826
- * @param v1 1st argument to {@link PipeTransform#transform}.
25827
- * @param v2 2nd argument to {@link PipeTransform#transform}.
25828
- *
25829
- * @codeGenApi
25830
- */
25831
- function ɵɵpipeBind2(index, slotOffset, v1, v2) {
25832
- const adjustedIndex = index + HEADER_OFFSET;
25833
- const lView = getLView();
25834
- const pipeInstance = load(lView, adjustedIndex);
25835
- return isPure(lView, adjustedIndex) ?
25836
- pureFunction2Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
25837
- pipeInstance.transform(v1, v2);
25838
- }
25839
- /**
25840
- * Invokes a pipe with 3 arguments.
25841
- *
25842
- * This instruction acts as a guard to {@link PipeTransform#transform} invoking
25843
- * the pipe only when an input to the pipe changes.
25844
- *
25845
- * @param index Pipe index where the pipe was stored on creation.
25846
- * @param slotOffset the offset in the reserved slot space
25847
- * @param v1 1st argument to {@link PipeTransform#transform}.
25848
- * @param v2 2nd argument to {@link PipeTransform#transform}.
25849
- * @param v3 4rd argument to {@link PipeTransform#transform}.
25850
- *
25851
26125
  * @codeGenApi
25852
26126
  */
25853
- function ɵɵpipeBind3(index, slotOffset, v1, v2, v3) {
25854
- const adjustedIndex = index + HEADER_OFFSET;
25855
- const lView = getLView();
25856
- const pipeInstance = load(lView, adjustedIndex);
25857
- return isPure(lView, adjustedIndex) ?
25858
- pureFunction3Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) :
25859
- pipeInstance.transform(v1, v2, v3);
26127
+ function ɵɵpureFunction4(slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
26128
+ return pureFunction4Internal(getLView(), getBindingRoot(), slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg);
25860
26129
  }
25861
26130
  /**
25862
- * Invokes a pipe with 4 arguments.
25863
- *
25864
- * This instruction acts as a guard to {@link PipeTransform#transform} invoking
25865
- * the pipe only when an input to the pipe changes.
26131
+ * If the value of any provided exp has changed, calls the pure function to return
26132
+ * an updated value. Or if no values have changed, returns cached value.
25866
26133
  *
25867
- * @param index Pipe index where the pipe was stored on creation.
25868
- * @param slotOffset the offset in the reserved slot space
25869
- * @param v1 1st argument to {@link PipeTransform#transform}.
25870
- * @param v2 2nd argument to {@link PipeTransform#transform}.
25871
- * @param v3 3rd argument to {@link PipeTransform#transform}.
25872
- * @param v4 4th argument to {@link PipeTransform#transform}.
26134
+ * @param slotOffset the offset from binding root to the reserved slot
26135
+ * @param pureFn
26136
+ * @param exp1
26137
+ * @param exp2
26138
+ * @param exp3
26139
+ * @param exp4
26140
+ * @param exp5
26141
+ * @param thisArg Optional calling context of pureFn
26142
+ * @returns Updated or cached value
25873
26143
  *
25874
26144
  * @codeGenApi
25875
26145
  */
25876
- function ɵɵpipeBind4(index, slotOffset, v1, v2, v3, v4) {
25877
- const adjustedIndex = index + HEADER_OFFSET;
26146
+ function ɵɵpureFunction5(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, thisArg) {
26147
+ const bindingIndex = getBindingRoot() + slotOffset;
25878
26148
  const lView = getLView();
25879
- const pipeInstance = load(lView, adjustedIndex);
25880
- return isPure(lView, adjustedIndex) ? pureFunction4Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
25881
- pipeInstance.transform(v1, v2, v3, v4);
26149
+ const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
26150
+ return bindingUpdated(lView, bindingIndex + 4, exp5) || different ?
26151
+ updateBinding(lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
26152
+ pureFn(exp1, exp2, exp3, exp4, exp5)) :
26153
+ getBinding(lView, bindingIndex + 5);
25882
26154
  }
25883
26155
  /**
25884
- * Invokes a pipe with variable number of arguments.
25885
- *
25886
- * This instruction acts as a guard to {@link PipeTransform#transform} invoking
25887
- * the pipe only when an input to the pipe changes.
26156
+ * If the value of any provided exp has changed, calls the pure function to return
26157
+ * an updated value. Or if no values have changed, returns cached value.
25888
26158
  *
25889
- * @param index Pipe index where the pipe was stored on creation.
25890
- * @param slotOffset the offset in the reserved slot space
25891
- * @param values Array of arguments to pass to {@link PipeTransform#transform} method.
26159
+ * @param slotOffset the offset from binding root to the reserved slot
26160
+ * @param pureFn
26161
+ * @param exp1
26162
+ * @param exp2
26163
+ * @param exp3
26164
+ * @param exp4
26165
+ * @param exp5
26166
+ * @param exp6
26167
+ * @param thisArg Optional calling context of pureFn
26168
+ * @returns Updated or cached value
25892
26169
  *
25893
26170
  * @codeGenApi
25894
26171
  */
25895
- function ɵɵpipeBindV(index, slotOffset, values) {
25896
- const adjustedIndex = index + HEADER_OFFSET;
26172
+ function ɵɵpureFunction6(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, thisArg) {
26173
+ const bindingIndex = getBindingRoot() + slotOffset;
25897
26174
  const lView = getLView();
25898
- const pipeInstance = load(lView, adjustedIndex);
25899
- return isPure(lView, adjustedIndex) ?
25900
- pureFunctionVInternal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) :
25901
- pipeInstance.transform.apply(pipeInstance, values);
25902
- }
25903
- function isPure(lView, index) {
25904
- return lView[TVIEW].data[index].pure;
25905
- }
25906
-
25907
- function symbolIterator() {
25908
- // @ts-expect-error accessing a private member
25909
- return this._results[Symbol.iterator]();
26175
+ const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
26176
+ return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ?
26177
+ updateBinding(lView, bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
26178
+ pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
26179
+ getBinding(lView, bindingIndex + 6);
25910
26180
  }
25911
26181
  /**
25912
- * An unmodifiable list of items that Angular keeps up to date when the state
25913
- * of the application changes.
25914
- *
25915
- * The type of object that {@link ViewChildren}, {@link ContentChildren}, and {@link QueryList}
25916
- * provide.
25917
- *
25918
- * Implements an iterable interface, therefore it can be used in both ES6
25919
- * javascript `for (var i of items)` loops as well as in Angular templates with
25920
- * `*ngFor="let i of myList"`.
25921
- *
25922
- * Changes can be observed by subscribing to the changes `Observable`.
25923
- *
25924
- * NOTE: In the future this class will implement an `Observable` interface.
26182
+ * If the value of any provided exp has changed, calls the pure function to return
26183
+ * an updated value. Or if no values have changed, returns cached value.
25925
26184
  *
25926
- * @usageNotes
25927
- * ### Example
25928
- * ```typescript
25929
- * @Component({...})
25930
- * class Container {
25931
- * @ViewChildren(Item) items:QueryList<Item>;
25932
- * }
25933
- * ```
26185
+ * @param slotOffset the offset from binding root to the reserved slot
26186
+ * @param pureFn
26187
+ * @param exp1
26188
+ * @param exp2
26189
+ * @param exp3
26190
+ * @param exp4
26191
+ * @param exp5
26192
+ * @param exp6
26193
+ * @param exp7
26194
+ * @param thisArg Optional calling context of pureFn
26195
+ * @returns Updated or cached value
25934
26196
  *
25935
- * @publicApi
26197
+ * @codeGenApi
25936
26198
  */
25937
- class QueryList {
25938
- static { Symbol.iterator; }
25939
- /**
25940
- * Returns `Observable` of `QueryList` notifying the subscriber of changes.
25941
- */
25942
- get changes() {
25943
- return this._changes || (this._changes = new EventEmitter());
25944
- }
25945
- /**
25946
- * @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
25947
- * has occurred. Or if it should fire when query is recomputed. (recomputing could resolve in
25948
- * the same result)
25949
- */
25950
- constructor(_emitDistinctChangesOnly = false) {
25951
- this._emitDistinctChangesOnly = _emitDistinctChangesOnly;
25952
- this.dirty = true;
25953
- this._results = [];
25954
- this._changesDetected = false;
25955
- this._changes = null;
25956
- this.length = 0;
25957
- this.first = undefined;
25958
- this.last = undefined;
25959
- // This function should be declared on the prototype, but doing so there will cause the class
25960
- // declaration to have side-effects and become not tree-shakable. For this reason we do it in
25961
- // the constructor.
25962
- // [Symbol.iterator](): Iterator<T> { ... }
25963
- const proto = QueryList.prototype;
25964
- if (!proto[Symbol.iterator])
25965
- proto[Symbol.iterator] = symbolIterator;
25966
- }
25967
- /**
25968
- * Returns the QueryList entry at `index`.
25969
- */
25970
- get(index) {
25971
- return this._results[index];
25972
- }
25973
- /**
25974
- * See
25975
- * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
25976
- */
25977
- map(fn) {
25978
- return this._results.map(fn);
25979
- }
25980
- filter(fn) {
25981
- return this._results.filter(fn);
25982
- }
25983
- /**
25984
- * See
25985
- * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
25986
- */
25987
- find(fn) {
25988
- return this._results.find(fn);
25989
- }
25990
- /**
25991
- * See
25992
- * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
25993
- */
25994
- reduce(fn, init) {
25995
- return this._results.reduce(fn, init);
25996
- }
25997
- /**
25998
- * See
25999
- * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
26000
- */
26001
- forEach(fn) {
26002
- this._results.forEach(fn);
26003
- }
26004
- /**
26005
- * See
26006
- * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
26007
- */
26008
- some(fn) {
26009
- return this._results.some(fn);
26010
- }
26011
- /**
26012
- * Returns a copy of the internal results list as an Array.
26013
- */
26014
- toArray() {
26015
- return this._results.slice();
26016
- }
26017
- toString() {
26018
- return this._results.toString();
26019
- }
26020
- /**
26021
- * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that
26022
- * on change detection, it will not notify of changes to the queries, unless a new change
26023
- * occurs.
26024
- *
26025
- * @param resultsTree The query results to store
26026
- * @param identityAccessor Optional function for extracting stable object identity from a value
26027
- * in the array. This function is executed for each element of the query result list while
26028
- * comparing current query list with the new one (provided as a first argument of the `reset`
26029
- * function) to detect if the lists are different. If the function is not provided, elements
26030
- * are compared as is (without any pre-processing).
26031
- */
26032
- reset(resultsTree, identityAccessor) {
26033
- // Cast to `QueryListInternal` so that we can mutate fields which are readonly for the usage of
26034
- // QueryList (but not for QueryList itself.)
26035
- const self = this;
26036
- self.dirty = false;
26037
- const newResultFlat = flatten(resultsTree);
26038
- if (this._changesDetected = !arrayEquals(self._results, newResultFlat, identityAccessor)) {
26039
- self._results = newResultFlat;
26040
- self.length = newResultFlat.length;
26041
- self.last = newResultFlat[this.length - 1];
26042
- self.first = newResultFlat[0];
26043
- }
26044
- }
26045
- /**
26046
- * Triggers a change event by emitting on the `changes` {@link EventEmitter}.
26047
- */
26048
- notifyOnChanges() {
26049
- if (this._changes && (this._changesDetected || !this._emitDistinctChangesOnly))
26050
- this._changes.emit(this);
26051
- }
26052
- /** internal */
26053
- setDirty() {
26054
- this.dirty = true;
26055
- }
26056
- /** internal */
26057
- destroy() {
26058
- this.changes.complete();
26059
- this.changes.unsubscribe();
26060
- }
26199
+ function ɵɵpureFunction7(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, thisArg) {
26200
+ const bindingIndex = getBindingRoot() + slotOffset;
26201
+ const lView = getLView();
26202
+ let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
26203
+ return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ?
26204
+ updateBinding(lView, bindingIndex + 7, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
26205
+ pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
26206
+ getBinding(lView, bindingIndex + 7);
26207
+ }
26208
+ /**
26209
+ * If the value of any provided exp has changed, calls the pure function to return
26210
+ * an updated value. Or if no values have changed, returns cached value.
26211
+ *
26212
+ * @param slotOffset the offset from binding root to the reserved slot
26213
+ * @param pureFn
26214
+ * @param exp1
26215
+ * @param exp2
26216
+ * @param exp3
26217
+ * @param exp4
26218
+ * @param exp5
26219
+ * @param exp6
26220
+ * @param exp7
26221
+ * @param exp8
26222
+ * @param thisArg Optional calling context of pureFn
26223
+ * @returns Updated or cached value
26224
+ *
26225
+ * @codeGenApi
26226
+ */
26227
+ function ɵɵpureFunction8(slotOffset, pureFn, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, thisArg) {
26228
+ const bindingIndex = getBindingRoot() + slotOffset;
26229
+ const lView = getLView();
26230
+ const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4);
26231
+ return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
26232
+ updateBinding(lView, bindingIndex + 8, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
26233
+ pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
26234
+ getBinding(lView, bindingIndex + 8);
26061
26235
  }
26062
-
26063
26236
  /**
26064
- * Represents an embedded template that can be used to instantiate embedded views.
26065
- * To instantiate embedded views based on a template, use the `ViewContainerRef`
26066
- * method `createEmbeddedView()`.
26237
+ * pureFunction instruction that can support any number of bindings.
26067
26238
  *
26068
- * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
26069
- * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
26070
- * is injected into the constructor of the directive,
26071
- * using the `TemplateRef` token.
26239
+ * If the value of any provided exp has changed, calls the pure function to return
26240
+ * an updated value. Or if no values have changed, returns cached value.
26072
26241
  *
26073
- * You can also use a `Query` to find a `TemplateRef` associated with
26074
- * a component or a directive.
26242
+ * @param slotOffset the offset from binding root to the reserved slot
26243
+ * @param pureFn A pure function that takes binding values and builds an object or array
26244
+ * containing those values.
26245
+ * @param exps An array of binding values
26246
+ * @param thisArg Optional calling context of pureFn
26247
+ * @returns Updated or cached value
26075
26248
  *
26076
- * @see {@link ViewContainerRef}
26077
- * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
26249
+ * @codeGenApi
26250
+ */
26251
+ function ɵɵpureFunctionV(slotOffset, pureFn, exps, thisArg) {
26252
+ return pureFunctionVInternal(getLView(), getBindingRoot(), slotOffset, pureFn, exps, thisArg);
26253
+ }
26254
+ /**
26255
+ * Results of a pure function invocation are stored in LView in a dedicated slot that is initialized
26256
+ * to NO_CHANGE. In rare situations a pure pipe might throw an exception on the very first
26257
+ * invocation and not produce any valid results. In this case LView would keep holding the NO_CHANGE
26258
+ * value. The NO_CHANGE is not something that we can use in expressions / bindings thus we convert
26259
+ * it to `undefined`.
26260
+ */
26261
+ function getPureFunctionReturnValue(lView, returnValueIndex) {
26262
+ ngDevMode && assertIndexInRange(lView, returnValueIndex);
26263
+ const lastReturnValue = lView[returnValueIndex];
26264
+ return lastReturnValue === NO_CHANGE ? undefined : lastReturnValue;
26265
+ }
26266
+ /**
26267
+ * If the value of the provided exp has changed, calls the pure function to return
26268
+ * an updated value. Or if the value has not changed, returns cached value.
26078
26269
  *
26079
- * @publicApi
26270
+ * @param lView LView in which the function is being executed.
26271
+ * @param bindingRoot Binding root index.
26272
+ * @param slotOffset the offset from binding root to the reserved slot
26273
+ * @param pureFn Function that returns an updated value
26274
+ * @param exp Updated expression value
26275
+ * @param thisArg Optional calling context of pureFn
26276
+ * @returns Updated or cached value
26080
26277
  */
26081
- class TemplateRef {
26082
- /**
26083
- * @internal
26084
- * @nocollapse
26085
- */
26086
- static { this.__NG_ELEMENT_ID__ = injectTemplateRef; }
26278
+ function pureFunction1Internal(lView, bindingRoot, slotOffset, pureFn, exp, thisArg) {
26279
+ const bindingIndex = bindingRoot + slotOffset;
26280
+ return bindingUpdated(lView, bindingIndex, exp) ?
26281
+ updateBinding(lView, bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
26282
+ getPureFunctionReturnValue(lView, bindingIndex + 1);
26087
26283
  }
26088
- const ViewEngineTemplateRef = TemplateRef;
26089
- // TODO(alxhub): combine interface and implementation. Currently this is challenging since something
26090
- // in g3 depends on them being separate.
26091
- const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
26092
- constructor(_declarationLView, _declarationTContainer, elementRef) {
26093
- super();
26094
- this._declarationLView = _declarationLView;
26095
- this._declarationTContainer = _declarationTContainer;
26096
- this.elementRef = elementRef;
26097
- }
26098
- /**
26099
- * Returns an `ssrId` associated with a TView, which was used to
26100
- * create this instance of the `TemplateRef`.
26101
- *
26102
- * @internal
26103
- */
26104
- get ssrId() {
26105
- return this._declarationTContainer.tView?.ssrId || null;
26106
- }
26107
- createEmbeddedView(context, injector) {
26108
- return this.createEmbeddedViewImpl(context, injector);
26109
- }
26110
- /**
26111
- * @internal
26112
- */
26113
- createEmbeddedViewImpl(context, injector, hydrationInfo) {
26114
- const embeddedLView = createAndRenderEmbeddedLView(this._declarationLView, this._declarationTContainer, context, { injector, hydrationInfo });
26115
- return new ViewRef$1(embeddedLView);
26116
- }
26117
- };
26118
26284
  /**
26119
- * Creates a TemplateRef given a node.
26285
+ * If the value of any provided exp has changed, calls the pure function to return
26286
+ * an updated value. Or if no values have changed, returns cached value.
26120
26287
  *
26121
- * @returns The TemplateRef instance to use
26288
+ * @param lView LView in which the function is being executed.
26289
+ * @param bindingRoot Binding root index.
26290
+ * @param slotOffset the offset from binding root to the reserved slot
26291
+ * @param pureFn
26292
+ * @param exp1
26293
+ * @param exp2
26294
+ * @param thisArg Optional calling context of pureFn
26295
+ * @returns Updated or cached value
26122
26296
  */
26123
- function injectTemplateRef() {
26124
- return createTemplateRef(getCurrentTNode(), getLView());
26297
+ function pureFunction2Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, thisArg) {
26298
+ const bindingIndex = bindingRoot + slotOffset;
26299
+ return bindingUpdated2(lView, bindingIndex, exp1, exp2) ?
26300
+ updateBinding(lView, bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
26301
+ getPureFunctionReturnValue(lView, bindingIndex + 2);
26125
26302
  }
26126
26303
  /**
26127
- * Creates a TemplateRef and stores it on the injector.
26304
+ * If the value of any provided exp has changed, calls the pure function to return
26305
+ * an updated value. Or if no values have changed, returns cached value.
26128
26306
  *
26129
- * @param hostTNode The node on which a TemplateRef is requested
26130
- * @param hostLView The `LView` to which the node belongs
26131
- * @returns The TemplateRef instance or null if we can't create a TemplateRef on a given node type
26307
+ * @param lView LView in which the function is being executed.
26308
+ * @param bindingRoot Binding root index.
26309
+ * @param slotOffset the offset from binding root to the reserved slot
26310
+ * @param pureFn
26311
+ * @param exp1
26312
+ * @param exp2
26313
+ * @param exp3
26314
+ * @param thisArg Optional calling context of pureFn
26315
+ * @returns Updated or cached value
26132
26316
  */
26133
- function createTemplateRef(hostTNode, hostLView) {
26134
- if (hostTNode.type & 4 /* TNodeType.Container */) {
26135
- ngDevMode && assertDefined(hostTNode.tView, 'TView must be allocated');
26136
- return new R3TemplateRef(hostLView, hostTNode, createElementRef(hostTNode, hostLView));
26317
+ function pureFunction3Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, thisArg) {
26318
+ const bindingIndex = bindingRoot + slotOffset;
26319
+ return bindingUpdated3(lView, bindingIndex, exp1, exp2, exp3) ?
26320
+ updateBinding(lView, bindingIndex + 3, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
26321
+ getPureFunctionReturnValue(lView, bindingIndex + 3);
26322
+ }
26323
+ /**
26324
+ * If the value of any provided exp has changed, calls the pure function to return
26325
+ * an updated value. Or if no values have changed, returns cached value.
26326
+ *
26327
+ * @param lView LView in which the function is being executed.
26328
+ * @param bindingRoot Binding root index.
26329
+ * @param slotOffset the offset from binding root to the reserved slot
26330
+ * @param pureFn
26331
+ * @param exp1
26332
+ * @param exp2
26333
+ * @param exp3
26334
+ * @param exp4
26335
+ * @param thisArg Optional calling context of pureFn
26336
+ * @returns Updated or cached value
26337
+ *
26338
+ */
26339
+ function pureFunction4Internal(lView, bindingRoot, slotOffset, pureFn, exp1, exp2, exp3, exp4, thisArg) {
26340
+ const bindingIndex = bindingRoot + slotOffset;
26341
+ return bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4) ?
26342
+ updateBinding(lView, bindingIndex + 4, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
26343
+ getPureFunctionReturnValue(lView, bindingIndex + 4);
26344
+ }
26345
+ /**
26346
+ * pureFunction instruction that can support any number of bindings.
26347
+ *
26348
+ * If the value of any provided exp has changed, calls the pure function to return
26349
+ * an updated value. Or if no values have changed, returns cached value.
26350
+ *
26351
+ * @param lView LView in which the function is being executed.
26352
+ * @param bindingRoot Binding root index.
26353
+ * @param slotOffset the offset from binding root to the reserved slot
26354
+ * @param pureFn A pure function that takes binding values and builds an object or array
26355
+ * containing those values.
26356
+ * @param exps An array of binding values
26357
+ * @param thisArg Optional calling context of pureFn
26358
+ * @returns Updated or cached value
26359
+ */
26360
+ function pureFunctionVInternal(lView, bindingRoot, slotOffset, pureFn, exps, thisArg) {
26361
+ let bindingIndex = bindingRoot + slotOffset;
26362
+ let different = false;
26363
+ for (let i = 0; i < exps.length; i++) {
26364
+ bindingUpdated(lView, bindingIndex++, exps[i]) && (different = true);
26137
26365
  }
26138
- return null;
26366
+ return different ? updateBinding(lView, bindingIndex, pureFn.apply(thisArg, exps)) :
26367
+ getPureFunctionReturnValue(lView, bindingIndex);
26139
26368
  }
26140
26369
 
26141
26370
  /**
26142
- * Removes all dehydrated views from a given LContainer:
26143
- * both in internal data structure, as well as removing
26144
- * corresponding DOM nodes that belong to that dehydrated view.
26371
+ * Create a pipe.
26372
+ *
26373
+ * @param index Pipe index where the pipe will be stored.
26374
+ * @param pipeName The name of the pipe
26375
+ * @returns T the instance of the pipe.
26376
+ *
26377
+ * @codeGenApi
26145
26378
  */
26146
- function removeDehydratedViews(lContainer) {
26147
- const views = lContainer[DEHYDRATED_VIEWS] ?? [];
26148
- const parentLView = lContainer[PARENT];
26149
- const renderer = parentLView[RENDERER];
26150
- for (const view of views) {
26151
- removeDehydratedView(view, renderer);
26152
- ngDevMode && ngDevMode.dehydratedViewsRemoved++;
26379
+ function ɵɵpipe(index, pipeName) {
26380
+ const tView = getTView();
26381
+ let pipeDef;
26382
+ const adjustedIndex = index + HEADER_OFFSET;
26383
+ if (tView.firstCreatePass) {
26384
+ // The `getPipeDef` throws if a pipe with a given name is not found
26385
+ // (so we use non-null assertion below).
26386
+ pipeDef = getPipeDef(pipeName, tView.pipeRegistry);
26387
+ tView.data[adjustedIndex] = pipeDef;
26388
+ if (pipeDef.onDestroy) {
26389
+ (tView.destroyHooks ??= []).push(adjustedIndex, pipeDef.onDestroy);
26390
+ }
26391
+ }
26392
+ else {
26393
+ pipeDef = tView.data[adjustedIndex];
26394
+ }
26395
+ const pipeFactory = pipeDef.factory || (pipeDef.factory = getFactoryDef(pipeDef.type, true));
26396
+ let previousInjectorProfilerContext;
26397
+ if (ngDevMode) {
26398
+ previousInjectorProfilerContext = setInjectorProfilerContext({
26399
+ injector: new NodeInjector(getCurrentTNode(), getLView()),
26400
+ token: pipeDef.type
26401
+ });
26402
+ }
26403
+ const previousInjectImplementation = setInjectImplementation(ɵɵdirectiveInject);
26404
+ try {
26405
+ // DI for pipes is supposed to behave like directives when placed on a component
26406
+ // host node, which means that we have to disable access to `viewProviders`.
26407
+ const previousIncludeViewProviders = setIncludeViewProviders(false);
26408
+ const pipeInstance = pipeFactory();
26409
+ setIncludeViewProviders(previousIncludeViewProviders);
26410
+ store(tView, getLView(), adjustedIndex, pipeInstance);
26411
+ return pipeInstance;
26412
+ }
26413
+ finally {
26414
+ // we have to restore the injector implementation in finally, just in case the creation of the
26415
+ // pipe throws an error.
26416
+ setInjectImplementation(previousInjectImplementation);
26417
+ ngDevMode && setInjectorProfilerContext(previousInjectorProfilerContext);
26153
26418
  }
26154
- // Reset the value to an empty array to indicate that no
26155
- // further processing of dehydrated views is needed for
26156
- // this view container (i.e. do not trigger the lookup process
26157
- // once again in case a `ViewContainerRef` is created later).
26158
- lContainer[DEHYDRATED_VIEWS] = EMPTY_ARRAY;
26159
26419
  }
26160
26420
  /**
26161
- * Helper function to remove all nodes from a dehydrated view.
26421
+ * Searches the pipe registry for a pipe with the given name. If one is found,
26422
+ * returns the pipe. Otherwise, an error is thrown because the pipe cannot be resolved.
26423
+ *
26424
+ * @param name Name of pipe to resolve
26425
+ * @param registry Full list of available pipes
26426
+ * @returns Matching PipeDef
26162
26427
  */
26163
- function removeDehydratedView(dehydratedView, renderer) {
26164
- let nodesRemoved = 0;
26165
- let currentRNode = dehydratedView.firstChild;
26166
- if (currentRNode) {
26167
- const numNodes = dehydratedView.data[NUM_ROOT_NODES];
26168
- while (nodesRemoved < numNodes) {
26169
- ngDevMode && validateSiblingNodeExists(currentRNode);
26170
- const nextSibling = currentRNode.nextSibling;
26171
- nativeRemoveNode(renderer, currentRNode, false);
26172
- currentRNode = nextSibling;
26173
- nodesRemoved++;
26428
+ function getPipeDef(name, registry) {
26429
+ if (registry) {
26430
+ if (ngDevMode) {
26431
+ const pipes = registry.filter(pipe => pipe.name === name);
26432
+ // TODO: Throw an error in the next major
26433
+ if (pipes.length > 1) {
26434
+ console.warn(formatRuntimeError(313 /* RuntimeErrorCode.MULTIPLE_MATCHING_PIPES */, getMultipleMatchingPipesMessage(name)));
26435
+ }
26436
+ }
26437
+ for (let i = registry.length - 1; i >= 0; i--) {
26438
+ const pipeDef = registry[i];
26439
+ if (name === pipeDef.name) {
26440
+ return pipeDef;
26441
+ }
26174
26442
  }
26175
26443
  }
26444
+ if (ngDevMode) {
26445
+ throw new RuntimeError(-302 /* RuntimeErrorCode.PIPE_NOT_FOUND */, getPipeNotFoundErrorMessage(name));
26446
+ }
26176
26447
  }
26177
26448
  /**
26178
- * Walks over all views within this LContainer invokes dehydrated views
26179
- * cleanup function for each one.
26449
+ * Generates a helpful error message for the user when multiple pipes match the name.
26450
+ *
26451
+ * @param name Name of the pipe
26452
+ * @returns The error message
26180
26453
  */
26181
- function cleanupLContainer(lContainer) {
26182
- removeDehydratedViews(lContainer);
26183
- for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) {
26184
- cleanupLView(lContainer[i]);
26185
- }
26454
+ function getMultipleMatchingPipesMessage(name) {
26455
+ const lView = getLView();
26456
+ const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
26457
+ const context = declarationLView[CONTEXT];
26458
+ const hostIsStandalone = isHostComponentStandalone(lView);
26459
+ const componentInfoMessage = context ? ` in the '${context.constructor.name}' component` : '';
26460
+ const verifyMessage = `check ${hostIsStandalone ? '\'@Component.imports\' of this component' :
26461
+ 'the imports of this module'}`;
26462
+ const errorMessage = `Multiple pipes match the name \`${name}\`${componentInfoMessage}. ${verifyMessage}`;
26463
+ return errorMessage;
26186
26464
  }
26187
26465
  /**
26188
- * Walks over `LContainer`s and components registered within
26189
- * this LView and invokes dehydrated views cleanup function for each one.
26466
+ * Generates a helpful error message for the user when a pipe is not found.
26467
+ *
26468
+ * @param name Name of the missing pipe
26469
+ * @returns The error message
26190
26470
  */
26191
- function cleanupLView(lView) {
26192
- const tView = lView[TVIEW];
26193
- for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
26194
- if (isLContainer(lView[i])) {
26195
- const lContainer = lView[i];
26196
- cleanupLContainer(lContainer);
26197
- }
26198
- else if (Array.isArray(lView[i])) {
26199
- // This is a component, enter the `cleanupLView` recursively.
26200
- cleanupLView(lView[i]);
26201
- }
26202
- }
26471
+ function getPipeNotFoundErrorMessage(name) {
26472
+ const lView = getLView();
26473
+ const declarationLView = lView[DECLARATION_COMPONENT_VIEW];
26474
+ const context = declarationLView[CONTEXT];
26475
+ const hostIsStandalone = isHostComponentStandalone(lView);
26476
+ const componentInfoMessage = context ? ` in the '${context.constructor.name}' component` : '';
26477
+ const verifyMessage = `Verify that it is ${hostIsStandalone ? 'included in the \'@Component.imports\' of this component' :
26478
+ 'declared or imported in this module'}`;
26479
+ const errorMessage = `The pipe '${name}' could not be found${componentInfoMessage}. ${verifyMessage}`;
26480
+ return errorMessage;
26203
26481
  }
26204
26482
  /**
26205
- * Walks over all views registered within the ApplicationRef and removes
26206
- * all dehydrated views from all `LContainer`s along the way.
26483
+ * Invokes a pipe with 1 arguments.
26484
+ *
26485
+ * This instruction acts as a guard to {@link PipeTransform#transform} invoking
26486
+ * the pipe only when an input to the pipe changes.
26487
+ *
26488
+ * @param index Pipe index where the pipe was stored on creation.
26489
+ * @param slotOffset the offset in the reserved slot space
26490
+ * @param v1 1st argument to {@link PipeTransform#transform}.
26491
+ *
26492
+ * @codeGenApi
26207
26493
  */
26208
- function cleanupDehydratedViews(appRef) {
26209
- const viewRefs = appRef._views;
26210
- for (const viewRef of viewRefs) {
26211
- const lNode = getLNodeForHydration(viewRef);
26212
- // An `lView` might be `null` if a `ViewRef` represents
26213
- // an embedded view (not a component view).
26214
- if (lNode !== null && lNode[HOST] !== null) {
26215
- if (isLView(lNode)) {
26216
- cleanupLView(lNode);
26217
- }
26218
- else {
26219
- // Cleanup in the root component view
26220
- const componentLView = lNode[HOST];
26221
- cleanupLView(componentLView);
26222
- // Cleanup in all views within this view container
26223
- cleanupLContainer(lNode);
26224
- }
26225
- ngDevMode && ngDevMode.dehydratedViewsCleanupRuns++;
26226
- }
26227
- }
26494
+ function ɵɵpipeBind1(index, slotOffset, v1) {
26495
+ const adjustedIndex = index + HEADER_OFFSET;
26496
+ const lView = getLView();
26497
+ const pipeInstance = load(lView, adjustedIndex);
26498
+ return isPure(lView, adjustedIndex) ?
26499
+ pureFunction1Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) :
26500
+ pipeInstance.transform(v1);
26228
26501
  }
26229
-
26230
26502
  /**
26231
- * Given a current DOM node and a serialized information about the views
26232
- * in a container, walks over the DOM structure, collecting the list of
26233
- * dehydrated views.
26503
+ * Invokes a pipe with 2 arguments.
26504
+ *
26505
+ * This instruction acts as a guard to {@link PipeTransform#transform} invoking
26506
+ * the pipe only when an input to the pipe changes.
26507
+ *
26508
+ * @param index Pipe index where the pipe was stored on creation.
26509
+ * @param slotOffset the offset in the reserved slot space
26510
+ * @param v1 1st argument to {@link PipeTransform#transform}.
26511
+ * @param v2 2nd argument to {@link PipeTransform#transform}.
26512
+ *
26513
+ * @codeGenApi
26234
26514
  */
26235
- function locateDehydratedViewsInContainer(currentRNode, serializedViews) {
26236
- const dehydratedViews = [];
26237
- for (const serializedView of serializedViews) {
26238
- // Repeats a view multiple times as needed, based on the serialized information
26239
- // (for example, for *ngFor-produced views).
26240
- for (let i = 0; i < (serializedView[MULTIPLIER] ?? 1); i++) {
26241
- const view = {
26242
- data: serializedView,
26243
- firstChild: null,
26244
- };
26245
- if (serializedView[NUM_ROOT_NODES] > 0) {
26246
- // Keep reference to the first node in this view,
26247
- // so it can be accessed while invoking template instructions.
26248
- view.firstChild = currentRNode;
26249
- // Move over to the next node after this view, which can
26250
- // either be a first node of the next view or an anchor comment
26251
- // node after the last view in a container.
26252
- currentRNode = siblingAfter(serializedView[NUM_ROOT_NODES], currentRNode);
26253
- }
26254
- dehydratedViews.push(view);
26255
- }
26256
- }
26257
- return [currentRNode, dehydratedViews];
26515
+ function ɵɵpipeBind2(index, slotOffset, v1, v2) {
26516
+ const adjustedIndex = index + HEADER_OFFSET;
26517
+ const lView = getLView();
26518
+ const pipeInstance = load(lView, adjustedIndex);
26519
+ return isPure(lView, adjustedIndex) ?
26520
+ pureFunction2Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
26521
+ pipeInstance.transform(v1, v2);
26258
26522
  }
26259
26523
  /**
26260
- * Reference to a function that searches for a matching dehydrated views
26261
- * stored on a given lContainer.
26262
- * Returns `null` by default, when hydration is not enabled.
26524
+ * Invokes a pipe with 3 arguments.
26525
+ *
26526
+ * This instruction acts as a guard to {@link PipeTransform#transform} invoking
26527
+ * the pipe only when an input to the pipe changes.
26528
+ *
26529
+ * @param index Pipe index where the pipe was stored on creation.
26530
+ * @param slotOffset the offset in the reserved slot space
26531
+ * @param v1 1st argument to {@link PipeTransform#transform}.
26532
+ * @param v2 2nd argument to {@link PipeTransform#transform}.
26533
+ * @param v3 4rd argument to {@link PipeTransform#transform}.
26534
+ *
26535
+ * @codeGenApi
26263
26536
  */
26264
- let _findMatchingDehydratedViewImpl = (lContainer, template) => null;
26537
+ function ɵɵpipeBind3(index, slotOffset, v1, v2, v3) {
26538
+ const adjustedIndex = index + HEADER_OFFSET;
26539
+ const lView = getLView();
26540
+ const pipeInstance = load(lView, adjustedIndex);
26541
+ return isPure(lView, adjustedIndex) ?
26542
+ pureFunction3Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) :
26543
+ pipeInstance.transform(v1, v2, v3);
26544
+ }
26265
26545
  /**
26266
- * Retrieves the next dehydrated view from the LContainer and verifies that
26267
- * it matches a given template id (from the TView that was used to create this
26268
- * instance of a view). If the id doesn't match, that means that we are in an
26269
- * unexpected state and can not complete the reconciliation process. Thus,
26270
- * all dehydrated views from this LContainer are removed (including corresponding
26271
- * DOM nodes) and the rendering is performed as if there were no dehydrated views
26272
- * in this container.
26546
+ * Invokes a pipe with 4 arguments.
26547
+ *
26548
+ * This instruction acts as a guard to {@link PipeTransform#transform} invoking
26549
+ * the pipe only when an input to the pipe changes.
26550
+ *
26551
+ * @param index Pipe index where the pipe was stored on creation.
26552
+ * @param slotOffset the offset in the reserved slot space
26553
+ * @param v1 1st argument to {@link PipeTransform#transform}.
26554
+ * @param v2 2nd argument to {@link PipeTransform#transform}.
26555
+ * @param v3 3rd argument to {@link PipeTransform#transform}.
26556
+ * @param v4 4th argument to {@link PipeTransform#transform}.
26557
+ *
26558
+ * @codeGenApi
26273
26559
  */
26274
- function findMatchingDehydratedViewImpl(lContainer, template) {
26275
- const views = lContainer[DEHYDRATED_VIEWS] ?? [];
26276
- if (!template || views.length === 0) {
26277
- return null;
26278
- }
26279
- const view = views[0];
26280
- // Verify whether the first dehydrated view in the container matches
26281
- // the template id passed to this function (that originated from a TView
26282
- // that was used to create an instance of an embedded or component views.
26283
- if (view.data[TEMPLATE_ID] === template) {
26284
- // If the template id matches - extract the first view and return it.
26285
- return views.shift();
26286
- }
26287
- else {
26288
- // Otherwise, we are at the state when reconciliation can not be completed,
26289
- // thus we remove all dehydrated views within this container (remove them
26290
- // from internal data structures as well as delete associated elements from
26291
- // the DOM tree).
26292
- removeDehydratedViews(lContainer);
26293
- return null;
26294
- }
26560
+ function ɵɵpipeBind4(index, slotOffset, v1, v2, v3, v4) {
26561
+ const adjustedIndex = index + HEADER_OFFSET;
26562
+ const lView = getLView();
26563
+ const pipeInstance = load(lView, adjustedIndex);
26564
+ return isPure(lView, adjustedIndex) ? pureFunction4Internal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
26565
+ pipeInstance.transform(v1, v2, v3, v4);
26295
26566
  }
26296
- function enableFindMatchingDehydratedViewImpl() {
26297
- _findMatchingDehydratedViewImpl = findMatchingDehydratedViewImpl;
26567
+ /**
26568
+ * Invokes a pipe with variable number of arguments.
26569
+ *
26570
+ * This instruction acts as a guard to {@link PipeTransform#transform} invoking
26571
+ * the pipe only when an input to the pipe changes.
26572
+ *
26573
+ * @param index Pipe index where the pipe was stored on creation.
26574
+ * @param slotOffset the offset in the reserved slot space
26575
+ * @param values Array of arguments to pass to {@link PipeTransform#transform} method.
26576
+ *
26577
+ * @codeGenApi
26578
+ */
26579
+ function ɵɵpipeBindV(index, slotOffset, values) {
26580
+ const adjustedIndex = index + HEADER_OFFSET;
26581
+ const lView = getLView();
26582
+ const pipeInstance = load(lView, adjustedIndex);
26583
+ return isPure(lView, adjustedIndex) ?
26584
+ pureFunctionVInternal(lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) :
26585
+ pipeInstance.transform.apply(pipeInstance, values);
26298
26586
  }
26299
- function findMatchingDehydratedView(lContainer, template) {
26300
- return _findMatchingDehydratedViewImpl(lContainer, template);
26587
+ function isPure(lView, index) {
26588
+ return lView[TVIEW].data[index].pure;
26301
26589
  }
26302
26590
 
26591
+ function symbolIterator() {
26592
+ // @ts-expect-error accessing a private member
26593
+ return this._results[Symbol.iterator]();
26594
+ }
26303
26595
  /**
26304
- * Represents a container where one or more views can be attached to a component.
26596
+ * An unmodifiable list of items that Angular keeps up to date when the state
26597
+ * of the application changes.
26305
26598
  *
26306
- * Can contain *host views* (created by instantiating a
26307
- * component with the `createComponent()` method), and *embedded views*
26308
- * (created by instantiating a `TemplateRef` with the `createEmbeddedView()` method).
26599
+ * The type of object that {@link ViewChildren}, {@link ContentChildren}, and {@link QueryList}
26600
+ * provide.
26309
26601
  *
26310
- * A view container instance can contain other view containers,
26311
- * creating a [view hierarchy](guide/glossary#view-hierarchy).
26602
+ * Implements an iterable interface, therefore it can be used in both ES6
26603
+ * javascript `for (var i of items)` loops as well as in Angular templates with
26604
+ * `*ngFor="let i of myList"`.
26312
26605
  *
26313
- * @see {@link ComponentRef}
26314
- * @see {@link EmbeddedViewRef}
26606
+ * Changes can be observed by subscribing to the changes `Observable`.
26607
+ *
26608
+ * NOTE: In the future this class will implement an `Observable` interface.
26609
+ *
26610
+ * @usageNotes
26611
+ * ### Example
26612
+ * ```typescript
26613
+ * @Component({...})
26614
+ * class Container {
26615
+ * @ViewChildren(Item) items:QueryList<Item>;
26616
+ * }
26617
+ * ```
26315
26618
  *
26316
26619
  * @publicApi
26317
26620
  */
26318
- class ViewContainerRef {
26621
+ class QueryList {
26622
+ static { Symbol.iterator; }
26319
26623
  /**
26320
- * @internal
26321
- * @nocollapse
26624
+ * Returns `Observable` of `QueryList` notifying the subscriber of changes.
26322
26625
  */
26323
- static { this.__NG_ELEMENT_ID__ = injectViewContainerRef; }
26324
- }
26325
- /**
26326
- * Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
26327
- * already exists, retrieves the existing ViewContainerRef.
26328
- *
26329
- * @returns The ViewContainerRef instance to use
26330
- */
26331
- function injectViewContainerRef() {
26332
- const previousTNode = getCurrentTNode();
26333
- return createContainerRef(previousTNode, getLView());
26334
- }
26335
- const VE_ViewContainerRef = ViewContainerRef;
26336
- // TODO(alxhub): cleaning up this indirection triggers a subtle bug in Closure in g3. Once the fix
26337
- // for that lands, this can be cleaned up.
26338
- const R3ViewContainerRef = class ViewContainerRef extends VE_ViewContainerRef {
26339
- constructor(_lContainer, _hostTNode, _hostLView) {
26340
- super();
26341
- this._lContainer = _lContainer;
26342
- this._hostTNode = _hostTNode;
26343
- this._hostLView = _hostLView;
26344
- }
26345
- get element() {
26346
- return createElementRef(this._hostTNode, this._hostLView);
26347
- }
26348
- get injector() {
26349
- return new NodeInjector(this._hostTNode, this._hostLView);
26350
- }
26351
- /** @deprecated No replacement */
26352
- get parentInjector() {
26353
- const parentLocation = getParentInjectorLocation(this._hostTNode, this._hostLView);
26354
- if (hasParentInjector(parentLocation)) {
26355
- const parentView = getParentInjectorView(parentLocation, this._hostLView);
26356
- const injectorIndex = getParentInjectorIndex(parentLocation);
26357
- ngDevMode && assertNodeInjector(parentView, injectorIndex);
26358
- const parentTNode = parentView[TVIEW].data[injectorIndex + 8 /* NodeInjectorOffset.TNODE */];
26359
- return new NodeInjector(parentTNode, parentView);
26360
- }
26361
- else {
26362
- return new NodeInjector(null, this._hostLView);
26363
- }
26626
+ get changes() {
26627
+ return this._changes || (this._changes = new EventEmitter());
26364
26628
  }
26365
- clear() {
26366
- while (this.length > 0) {
26367
- this.remove(this.length - 1);
26368
- }
26629
+ /**
26630
+ * @param emitDistinctChangesOnly Whether `QueryList.changes` should fire only when actual change
26631
+ * has occurred. Or if it should fire when query is recomputed. (recomputing could resolve in
26632
+ * the same result)
26633
+ */
26634
+ constructor(_emitDistinctChangesOnly = false) {
26635
+ this._emitDistinctChangesOnly = _emitDistinctChangesOnly;
26636
+ this.dirty = true;
26637
+ this._results = [];
26638
+ this._changesDetected = false;
26639
+ this._changes = null;
26640
+ this.length = 0;
26641
+ this.first = undefined;
26642
+ this.last = undefined;
26643
+ // This function should be declared on the prototype, but doing so there will cause the class
26644
+ // declaration to have side-effects and become not tree-shakable. For this reason we do it in
26645
+ // the constructor.
26646
+ // [Symbol.iterator](): Iterator<T> { ... }
26647
+ const proto = QueryList.prototype;
26648
+ if (!proto[Symbol.iterator])
26649
+ proto[Symbol.iterator] = symbolIterator;
26369
26650
  }
26651
+ /**
26652
+ * Returns the QueryList entry at `index`.
26653
+ */
26370
26654
  get(index) {
26371
- const viewRefs = getViewRefs(this._lContainer);
26372
- return viewRefs !== null && viewRefs[index] || null;
26373
- }
26374
- get length() {
26375
- return this._lContainer.length - CONTAINER_HEADER_OFFSET;
26655
+ return this._results[index];
26376
26656
  }
26377
- createEmbeddedView(templateRef, context, indexOrOptions) {
26378
- let index;
26379
- let injector;
26380
- if (typeof indexOrOptions === 'number') {
26381
- index = indexOrOptions;
26382
- }
26383
- else if (indexOrOptions != null) {
26384
- index = indexOrOptions.index;
26385
- injector = indexOrOptions.injector;
26386
- }
26387
- const hydrationInfo = findMatchingDehydratedView(this._lContainer, templateRef.ssrId);
26388
- const viewRef = templateRef.createEmbeddedViewImpl(context || {}, injector, hydrationInfo);
26389
- // If there is a matching dehydrated view, but the host TNode is located in the skip
26390
- // hydration block, this means that the content was detached (as a part of the skip
26391
- // hydration logic) and it needs to be appended into the DOM.
26392
- const skipDomInsertion = !!hydrationInfo && !hasInSkipHydrationBlockFlag(this._hostTNode);
26393
- this.insertImpl(viewRef, index, skipDomInsertion);
26394
- return viewRef;
26657
+ /**
26658
+ * See
26659
+ * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
26660
+ */
26661
+ map(fn) {
26662
+ return this._results.map(fn);
26395
26663
  }
26396
- createComponent(componentFactoryOrType, indexOrOptions, injector, projectableNodes, environmentInjector) {
26397
- const isComponentFactory = componentFactoryOrType && !isType(componentFactoryOrType);
26398
- let index;
26399
- // This function supports 2 signatures and we need to handle options correctly for both:
26400
- // 1. When first argument is a Component type. This signature also requires extra
26401
- // options to be provided as object (more ergonomic option).
26402
- // 2. First argument is a Component factory. In this case extra options are represented as
26403
- // positional arguments. This signature is less ergonomic and will be deprecated.
26404
- if (isComponentFactory) {
26405
- if (ngDevMode) {
26406
- assertEqual(typeof indexOrOptions !== 'object', true, 'It looks like Component factory was provided as the first argument ' +
26407
- 'and an options object as the second argument. This combination of arguments ' +
26408
- 'is incompatible. You can either change the first argument to provide Component ' +
26409
- 'type or change the second argument to be a number (representing an index at ' +
26410
- 'which to insert the new component\'s host view into this container)');
26411
- }
26412
- index = indexOrOptions;
26413
- }
26414
- else {
26415
- if (ngDevMode) {
26416
- assertDefined(getComponentDef(componentFactoryOrType), `Provided Component class doesn't contain Component definition. ` +
26417
- `Please check whether provided class has @Component decorator.`);
26418
- assertEqual(typeof indexOrOptions !== 'number', true, 'It looks like Component type was provided as the first argument ' +
26419
- 'and a number (representing an index at which to insert the new component\'s ' +
26420
- 'host view into this container as the second argument. This combination of arguments ' +
26421
- 'is incompatible. Please use an object as the second argument instead.');
26422
- }
26423
- const options = (indexOrOptions || {});
26424
- if (ngDevMode && options.environmentInjector && options.ngModuleRef) {
26425
- throwError(`Cannot pass both environmentInjector and ngModuleRef options to createComponent().`);
26426
- }
26427
- index = options.index;
26428
- injector = options.injector;
26429
- projectableNodes = options.projectableNodes;
26430
- environmentInjector = options.environmentInjector || options.ngModuleRef;
26431
- }
26432
- const componentFactory = isComponentFactory ?
26433
- componentFactoryOrType :
26434
- new ComponentFactory(getComponentDef(componentFactoryOrType));
26435
- const contextInjector = injector || this.parentInjector;
26436
- // If an `NgModuleRef` is not provided explicitly, try retrieving it from the DI tree.
26437
- if (!environmentInjector && componentFactory.ngModule == null) {
26438
- // For the `ComponentFactory` case, entering this logic is very unlikely, since we expect that
26439
- // an instance of a `ComponentFactory`, resolved via `ComponentFactoryResolver` would have an
26440
- // `ngModule` field. This is possible in some test scenarios and potentially in some JIT-based
26441
- // use-cases. For the `ComponentFactory` case we preserve backwards-compatibility and try
26442
- // using a provided injector first, then fall back to the parent injector of this
26443
- // `ViewContainerRef` instance.
26444
- //
26445
- // For the factory-less case, it's critical to establish a connection with the module
26446
- // injector tree (by retrieving an instance of an `NgModuleRef` and accessing its injector),
26447
- // so that a component can use DI tokens provided in MgModules. For this reason, we can not
26448
- // rely on the provided injector, since it might be detached from the DI tree (for example, if
26449
- // it was created via `Injector.create` without specifying a parent injector, or if an
26450
- // injector is retrieved from an `NgModuleRef` created via `createNgModule` using an
26451
- // NgModule outside of a module tree). Instead, we always use `ViewContainerRef`'s parent
26452
- // injector, which is normally connected to the DI tree, which includes module injector
26453
- // subtree.
26454
- const _injector = isComponentFactory ? contextInjector : this.parentInjector;
26455
- // DO NOT REFACTOR. The code here used to have a `injector.get(NgModuleRef, null) ||
26456
- // undefined` expression which seems to cause internal google apps to fail. This is documented
26457
- // in the following internal bug issue: go/b/142967802
26458
- const result = _injector.get(EnvironmentInjector, null);
26459
- if (result) {
26460
- environmentInjector = result;
26461
- }
26462
- }
26463
- const componentDef = getComponentDef(componentFactory.componentType ?? {});
26464
- const dehydratedView = findMatchingDehydratedView(this._lContainer, componentDef?.id ?? null);
26465
- const rNode = dehydratedView?.firstChild ?? null;
26466
- const componentRef = componentFactory.create(contextInjector, projectableNodes, rNode, environmentInjector);
26467
- // If there is a matching dehydrated view, but the host TNode is located in the skip
26468
- // hydration block, this means that the content was detached (as a part of the skip
26469
- // hydration logic) and it needs to be appended into the DOM.
26470
- const skipDomInsertion = !!dehydratedView && !hasInSkipHydrationBlockFlag(this._hostTNode);
26471
- this.insertImpl(componentRef.hostView, index, skipDomInsertion);
26472
- return componentRef;
26664
+ filter(fn) {
26665
+ return this._results.filter(fn);
26473
26666
  }
26474
- insert(viewRef, index) {
26475
- return this.insertImpl(viewRef, index, false);
26667
+ /**
26668
+ * See
26669
+ * [Array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
26670
+ */
26671
+ find(fn) {
26672
+ return this._results.find(fn);
26476
26673
  }
26477
- insertImpl(viewRef, index, skipDomInsertion) {
26478
- const lView = viewRef._lView;
26479
- const tView = lView[TVIEW];
26480
- if (ngDevMode && viewRef.destroyed) {
26481
- throw new Error('Cannot insert a destroyed View in a ViewContainer!');
26482
- }
26483
- if (viewAttachedToContainer(lView)) {
26484
- // If view is already attached, detach it first so we clean up references appropriately.
26485
- const prevIdx = this.indexOf(viewRef);
26486
- // A view might be attached either to this or a different container. The `prevIdx` for
26487
- // those cases will be:
26488
- // equal to -1 for views attached to this ViewContainerRef
26489
- // >= 0 for views attached to a different ViewContainerRef
26490
- if (prevIdx !== -1) {
26491
- this.detach(prevIdx);
26492
- }
26493
- else {
26494
- const prevLContainer = lView[PARENT];
26495
- ngDevMode &&
26496
- assertEqual(isLContainer(prevLContainer), true, 'An attached view should have its PARENT point to a container.');
26497
- // We need to re-create a R3ViewContainerRef instance since those are not stored on
26498
- // LView (nor anywhere else).
26499
- const prevVCRef = new R3ViewContainerRef(prevLContainer, prevLContainer[T_HOST], prevLContainer[PARENT]);
26500
- prevVCRef.detach(prevVCRef.indexOf(viewRef));
26501
- }
26502
- }
26503
- // Logical operation of adding `LView` to `LContainer`
26504
- const adjustedIdx = this._adjustIndex(index);
26505
- const lContainer = this._lContainer;
26506
- addLViewToLContainer(lContainer, lView, adjustedIdx, !skipDomInsertion);
26507
- viewRef.attachToViewContainerRef();
26508
- addToArray(getOrCreateViewRefs(lContainer), adjustedIdx, viewRef);
26509
- return viewRef;
26674
+ /**
26675
+ * See
26676
+ * [Array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
26677
+ */
26678
+ reduce(fn, init) {
26679
+ return this._results.reduce(fn, init);
26510
26680
  }
26511
- move(viewRef, newIndex) {
26512
- if (ngDevMode && viewRef.destroyed) {
26513
- throw new Error('Cannot move a destroyed View in a ViewContainer!');
26514
- }
26515
- return this.insert(viewRef, newIndex);
26681
+ /**
26682
+ * See
26683
+ * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
26684
+ */
26685
+ forEach(fn) {
26686
+ this._results.forEach(fn);
26516
26687
  }
26517
- indexOf(viewRef) {
26518
- const viewRefsArr = getViewRefs(this._lContainer);
26519
- return viewRefsArr !== null ? viewRefsArr.indexOf(viewRef) : -1;
26688
+ /**
26689
+ * See
26690
+ * [Array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
26691
+ */
26692
+ some(fn) {
26693
+ return this._results.some(fn);
26520
26694
  }
26521
- remove(index) {
26522
- const adjustedIdx = this._adjustIndex(index, -1);
26523
- const detachedView = detachView(this._lContainer, adjustedIdx);
26524
- if (detachedView) {
26525
- // Before destroying the view, remove it from the container's array of `ViewRef`s.
26526
- // This ensures the view container length is updated before calling
26527
- // `destroyLView`, which could recursively call view container methods that
26528
- // rely on an accurate container length.
26529
- // (e.g. a method on this view container being called by a child directive's OnDestroy
26530
- // lifecycle hook)
26531
- removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx);
26532
- destroyLView(detachedView[TVIEW], detachedView);
26533
- }
26695
+ /**
26696
+ * Returns a copy of the internal results list as an Array.
26697
+ */
26698
+ toArray() {
26699
+ return this._results.slice();
26534
26700
  }
26535
- detach(index) {
26536
- const adjustedIdx = this._adjustIndex(index, -1);
26537
- const view = detachView(this._lContainer, adjustedIdx);
26538
- const wasDetached = view && removeFromArray(getOrCreateViewRefs(this._lContainer), adjustedIdx) != null;
26539
- return wasDetached ? new ViewRef$1(view) : null;
26701
+ toString() {
26702
+ return this._results.toString();
26540
26703
  }
26541
- _adjustIndex(index, shift = 0) {
26542
- if (index == null) {
26543
- return this.length + shift;
26544
- }
26545
- if (ngDevMode) {
26546
- assertGreaterThan(index, -1, `ViewRef index must be positive, got ${index}`);
26547
- // +1 because it's legal to insert at the end.
26548
- assertLessThan(index, this.length + 1 + shift, 'index');
26704
+ /**
26705
+ * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that
26706
+ * on change detection, it will not notify of changes to the queries, unless a new change
26707
+ * occurs.
26708
+ *
26709
+ * @param resultsTree The query results to store
26710
+ * @param identityAccessor Optional function for extracting stable object identity from a value
26711
+ * in the array. This function is executed for each element of the query result list while
26712
+ * comparing current query list with the new one (provided as a first argument of the `reset`
26713
+ * function) to detect if the lists are different. If the function is not provided, elements
26714
+ * are compared as is (without any pre-processing).
26715
+ */
26716
+ reset(resultsTree, identityAccessor) {
26717
+ // Cast to `QueryListInternal` so that we can mutate fields which are readonly for the usage of
26718
+ // QueryList (but not for QueryList itself.)
26719
+ const self = this;
26720
+ self.dirty = false;
26721
+ const newResultFlat = flatten(resultsTree);
26722
+ if (this._changesDetected = !arrayEquals(self._results, newResultFlat, identityAccessor)) {
26723
+ self._results = newResultFlat;
26724
+ self.length = newResultFlat.length;
26725
+ self.last = newResultFlat[this.length - 1];
26726
+ self.first = newResultFlat[0];
26549
26727
  }
26550
- return index;
26551
26728
  }
26552
- };
26553
- function getViewRefs(lContainer) {
26554
- return lContainer[VIEW_REFS];
26555
- }
26556
- function getOrCreateViewRefs(lContainer) {
26557
- return (lContainer[VIEW_REFS] || (lContainer[VIEW_REFS] = []));
26558
- }
26559
- /**
26560
- * Creates a ViewContainerRef and stores it on the injector.
26561
- *
26562
- * @param hostTNode The node that is requesting a ViewContainerRef
26563
- * @param hostLView The view to which the node belongs
26564
- * @returns The ViewContainerRef instance to use
26565
- */
26566
- function createContainerRef(hostTNode, hostLView) {
26567
- ngDevMode && assertTNodeType(hostTNode, 12 /* TNodeType.AnyContainer */ | 3 /* TNodeType.AnyRNode */);
26568
- let lContainer;
26569
- const slotValue = hostLView[hostTNode.index];
26570
- if (isLContainer(slotValue)) {
26571
- // If the host is a container, we don't need to create a new LContainer
26572
- lContainer = slotValue;
26729
+ /**
26730
+ * Triggers a change event by emitting on the `changes` {@link EventEmitter}.
26731
+ */
26732
+ notifyOnChanges() {
26733
+ if (this._changes && (this._changesDetected || !this._emitDistinctChangesOnly))
26734
+ this._changes.emit(this);
26573
26735
  }
26574
- else {
26575
- // An LContainer anchor can not be `null`, but we set it here temporarily
26576
- // and update to the actual value later in this function (see
26577
- // `_locateOrCreateAnchorNode`).
26578
- lContainer = createLContainer(slotValue, hostLView, null, hostTNode);
26579
- hostLView[hostTNode.index] = lContainer;
26580
- addToViewTree(hostLView, lContainer);
26736
+ /** internal */
26737
+ setDirty() {
26738
+ this.dirty = true;
26739
+ }
26740
+ /** internal */
26741
+ destroy() {
26742
+ this.changes.complete();
26743
+ this.changes.unsubscribe();
26581
26744
  }
26582
- _locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue);
26583
- return new R3ViewContainerRef(lContainer, hostTNode, hostLView);
26584
26745
  }
26746
+
26585
26747
  /**
26586
- * Creates and inserts a comment node that acts as an anchor for a view container.
26748
+ * Represents an embedded template that can be used to instantiate embedded views.
26749
+ * To instantiate embedded views based on a template, use the `ViewContainerRef`
26750
+ * method `createEmbeddedView()`.
26587
26751
  *
26588
- * If the host is a regular element, we have to insert a comment node manually which will
26589
- * be used as an anchor when inserting elements. In this specific case we use low-level DOM
26590
- * manipulation to insert it.
26752
+ * Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
26753
+ * element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
26754
+ * is injected into the constructor of the directive,
26755
+ * using the `TemplateRef` token.
26756
+ *
26757
+ * You can also use a `Query` to find a `TemplateRef` associated with
26758
+ * a component or a directive.
26759
+ *
26760
+ * @see {@link ViewContainerRef}
26761
+ * @see [Navigate the Component Tree with DI](guide/dependency-injection-navtree)
26762
+ *
26763
+ * @publicApi
26591
26764
  */
26592
- function insertAnchorNode(hostLView, hostTNode) {
26593
- const renderer = hostLView[RENDERER];
26594
- ngDevMode && ngDevMode.rendererCreateComment++;
26595
- const commentNode = renderer.createComment(ngDevMode ? 'container' : '');
26596
- const hostNative = getNativeByTNode(hostTNode, hostLView);
26597
- const parentOfHostNative = nativeParentNode(renderer, hostNative);
26598
- nativeInsertBefore(renderer, parentOfHostNative, commentNode, nativeNextSibling(renderer, hostNative), false);
26599
- return commentNode;
26765
+ class TemplateRef {
26766
+ /**
26767
+ * @internal
26768
+ * @nocollapse
26769
+ */
26770
+ static { this.__NG_ELEMENT_ID__ = injectTemplateRef; }
26600
26771
  }
26601
- let _locateOrCreateAnchorNode = createAnchorNode;
26602
- /**
26603
- * Regular creation mode: an anchor is created and
26604
- * assigned to the `lContainer[NATIVE]` slot.
26605
- */
26606
- function createAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
26607
- // We already have a native element (anchor) set, return.
26608
- if (lContainer[NATIVE])
26609
- return;
26610
- let commentNode;
26611
- // If the host is an element container, the native host element is guaranteed to be a
26612
- // comment and we can reuse that comment as anchor element for the new LContainer.
26613
- // The comment node in question is already part of the DOM structure so we don't need to append
26614
- // it again.
26615
- if (hostTNode.type & 8 /* TNodeType.ElementContainer */) {
26616
- commentNode = unwrapRNode(slotValue);
26772
+ const ViewEngineTemplateRef = TemplateRef;
26773
+ // TODO(alxhub): combine interface and implementation. Currently this is challenging since something
26774
+ // in g3 depends on them being separate.
26775
+ const R3TemplateRef = class TemplateRef extends ViewEngineTemplateRef {
26776
+ constructor(_declarationLView, _declarationTContainer, elementRef) {
26777
+ super();
26778
+ this._declarationLView = _declarationLView;
26779
+ this._declarationTContainer = _declarationTContainer;
26780
+ this.elementRef = elementRef;
26617
26781
  }
26618
- else {
26619
- commentNode = insertAnchorNode(hostLView, hostTNode);
26782
+ /**
26783
+ * Returns an `ssrId` associated with a TView, which was used to
26784
+ * create this instance of the `TemplateRef`.
26785
+ *
26786
+ * @internal
26787
+ */
26788
+ get ssrId() {
26789
+ return this._declarationTContainer.tView?.ssrId || null;
26620
26790
  }
26621
- lContainer[NATIVE] = commentNode;
26791
+ createEmbeddedView(context, injector) {
26792
+ return this.createEmbeddedViewImpl(context, injector);
26793
+ }
26794
+ /**
26795
+ * @internal
26796
+ */
26797
+ createEmbeddedViewImpl(context, injector, dehydratedView) {
26798
+ const embeddedLView = createAndRenderEmbeddedLView(this._declarationLView, this._declarationTContainer, context, { injector, dehydratedView });
26799
+ return new ViewRef$1(embeddedLView);
26800
+ }
26801
+ };
26802
+ /**
26803
+ * Creates a TemplateRef given a node.
26804
+ *
26805
+ * @returns The TemplateRef instance to use
26806
+ */
26807
+ function injectTemplateRef() {
26808
+ return createTemplateRef(getCurrentTNode(), getLView());
26622
26809
  }
26623
26810
  /**
26624
- * Hydration logic that looks up:
26625
- * - an anchor node in the DOM and stores the node in `lContainer[NATIVE]`
26626
- * - all dehydrated views in this container and puts them into `lContainer[DEHYDRATED_VIEWS]`
26811
+ * Creates a TemplateRef and stores it on the injector.
26812
+ *
26813
+ * @param hostTNode The node on which a TemplateRef is requested
26814
+ * @param hostLView The `LView` to which the node belongs
26815
+ * @returns The TemplateRef instance or null if we can't create a TemplateRef on a given node type
26627
26816
  */
26628
- function locateOrCreateAnchorNode(lContainer, hostLView, hostTNode, slotValue) {
26629
- // We already have a native element (anchor) set and the process
26630
- // of finding dehydrated views happened (so the `lContainer[DEHYDRATED_VIEWS]`
26631
- // is not null), exit early.
26632
- if (lContainer[NATIVE] && lContainer[DEHYDRATED_VIEWS])
26633
- return;
26634
- const hydrationInfo = hostLView[HYDRATION];
26635
- const noOffsetIndex = hostTNode.index - HEADER_OFFSET;
26636
- // TODO(akushnir): this should really be a single condition, refactor the code
26637
- // to use `hasInSkipHydrationBlockFlag` logic inside `isInSkipHydrationBlock`.
26638
- const skipHydration = isInSkipHydrationBlock(hostTNode) || hasInSkipHydrationBlockFlag(hostTNode);
26639
- const isNodeCreationMode = !hydrationInfo || skipHydration || isDisconnectedNode$1(hydrationInfo, noOffsetIndex);
26640
- // Regular creation mode.
26641
- if (isNodeCreationMode) {
26642
- return createAnchorNode(lContainer, hostLView, hostTNode, slotValue);
26643
- }
26644
- // Hydration mode, looking up an anchor node and dehydrated views in DOM.
26645
- const currentRNode = getSegmentHead(hydrationInfo, noOffsetIndex);
26646
- const serializedViews = hydrationInfo.data[CONTAINERS]?.[noOffsetIndex];
26647
- ngDevMode &&
26648
- assertDefined(serializedViews, 'Unexpected state: no hydration info available for a given TNode, ' +
26649
- 'which represents a view container.');
26650
- const [commentNode, dehydratedViews] = locateDehydratedViewsInContainer(currentRNode, serializedViews);
26651
- if (ngDevMode) {
26652
- validateMatchingNode(commentNode, Node.COMMENT_NODE, null, hostLView, hostTNode, true);
26653
- // Do not throw in case this node is already claimed (thus `false` as a second
26654
- // argument). If this container is created based on an `<ng-template>`, the comment
26655
- // node would be already claimed from the `template` instruction. If an element acts
26656
- // as an anchor (e.g. <div #vcRef>), a separate comment node would be created/located,
26657
- // so we need to claim it here.
26658
- markRNodeAsClaimedByHydration(commentNode, false);
26817
+ function createTemplateRef(hostTNode, hostLView) {
26818
+ if (hostTNode.type & 4 /* TNodeType.Container */) {
26819
+ ngDevMode && assertDefined(hostTNode.tView, 'TView must be allocated');
26820
+ return new R3TemplateRef(hostLView, hostTNode, createElementRef(hostTNode, hostLView));
26659
26821
  }
26660
- lContainer[NATIVE] = commentNode;
26661
- lContainer[DEHYDRATED_VIEWS] = dehydratedViews;
26662
- }
26663
- function enableLocateOrCreateContainerRefImpl() {
26664
- _locateOrCreateAnchorNode = locateOrCreateAnchorNode;
26822
+ return null;
26665
26823
  }
26666
26824
 
26667
26825
  class LQuery_ {
@@ -27279,6 +27437,7 @@ const angularCoreEnv = (() => ({
27279
27437
  'ɵɵrepeaterCreate': ɵɵrepeaterCreate,
27280
27438
  'ɵɵrepeaterTrackByIndex': ɵɵrepeaterTrackByIndex,
27281
27439
  'ɵɵrepeaterTrackByIdentity': ɵɵrepeaterTrackByIdentity,
27440
+ 'ɵɵcomponentInstance': ɵɵcomponentInstance,
27282
27441
  'ɵɵtext': ɵɵtext,
27283
27442
  'ɵɵtextInterpolate': ɵɵtextInterpolate,
27284
27443
  'ɵɵtextInterpolate1': ɵɵtextInterpolate1,
@@ -31891,11 +32050,13 @@ function serializeLView(lView, context) {
31891
32050
  for (let i = HEADER_OFFSET; i < tView.bindingStartIndex; i++) {
31892
32051
  const tNode = tView.data[i];
31893
32052
  const noOffsetIndex = i - HEADER_OFFSET;
31894
- // Local refs (e.g. <div #localRef>) take up an extra slot in LViews
31895
- // to store the same element. In this case, there is no information in
31896
- // a corresponding slot in TNode data structure. If that's the case, just
31897
- // skip this slot and move to the next one.
31898
- if (!tNode) {
32053
+ // Skip processing of a given slot in the following cases:
32054
+ // - Local refs (e.g. <div #localRef>) take up an extra slot in LViews
32055
+ // to store the same element. In this case, there is no information in
32056
+ // a corresponding slot in TNode data structure.
32057
+ // - When a slot contains something other than a TNode. For example, there
32058
+ // might be some metadata information about a defer block or a control flow block.
32059
+ if (!isTNodeShape(tNode)) {
31899
32060
  continue;
31900
32061
  }
31901
32062
  // Check if a native node that represents a given TNode is disconnected from the DOM tree.
@@ -32494,17 +32655,18 @@ function ɵɵngDeclarePipe(decl) {
32494
32655
  * const applicationRef = await bootstrapApplication(RootComponent);
32495
32656
  *
32496
32657
  * // Locate a DOM node that would be used as a host.
32497
- * const host = document.getElementById('hello-component-host');
32658
+ * const hostElement = document.getElementById('hello-component-host');
32498
32659
  *
32499
32660
  * // Get an `EnvironmentInjector` instance from the `ApplicationRef`.
32500
32661
  * const environmentInjector = applicationRef.injector;
32501
32662
  *
32502
32663
  * // We can now create a `ComponentRef` instance.
32503
- * const componentRef = createComponent(HelloComponent, {host, environmentInjector});
32664
+ * const componentRef = createComponent(HelloComponent, {hostElement, environmentInjector});
32504
32665
  *
32505
32666
  * // Last step is to register the newly created ref using the `ApplicationRef` instance
32506
32667
  * // to include the component view into change detection cycles.
32507
32668
  * applicationRef.attachView(componentRef.hostView);
32669
+ * componentRef.changeDetectorRef.detectChanges();
32508
32670
  * ```
32509
32671
  *
32510
32672
  * @param component Component class reference.
@@ -32647,5 +32809,5 @@ if (typeof ngDevMode !== 'undefined' && ngDevMode) {
32647
32809
  * Generated bundle index. Do not edit.
32648
32810
  */
32649
32811
 
32650
- export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertPlatform, booleanAttribute, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, numberAttribute, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, ENABLED_SSR_FEATURES as ɵENABLED_SSR_FEATURES, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, InitialRenderPendingTasks as ɵInitialRenderPendingTasks, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadata as ɵgetAsyncClassMetadata, getDebugNode as ɵgetDebugNode, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, withDomHydration as ɵwithDomHydration, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵconditional, ɵɵcontentQuery, ɵɵdefer, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
32812
+ export { ANIMATION_MODULE_TYPE, APP_BOOTSTRAP_LISTENER, APP_ID, APP_INITIALIZER, ApplicationInitStatus, ApplicationModule, ApplicationRef, Attribute, COMPILER_OPTIONS, CSP_NONCE, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, ChangeDetectorRef, Compiler, CompilerFactory, Component, ComponentFactory$1 as ComponentFactory, ComponentFactoryResolver$1 as ComponentFactoryResolver, ComponentRef$1 as ComponentRef, ContentChild, ContentChildren, DEFAULT_CURRENCY_CODE, DebugElement, DebugEventListener, DebugNode, DefaultIterableDiffer, DestroyRef, Directive, ENVIRONMENT_INITIALIZER, ElementRef, EmbeddedViewRef, EnvironmentInjector, ErrorHandler, EventEmitter, Host, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, InjectionToken, Injector, Input, IterableDiffers, KeyValueDiffers, LOCALE_ID, MissingTranslationStrategy, ModuleWithComponentFactories, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory$1 as NgModuleFactory, NgModuleRef$1 as NgModuleRef, NgProbeToken, NgZone, Optional, Output, PACKAGE_ROOT_URL, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, PlatformRef, Query, QueryList, Renderer2, RendererFactory2, RendererStyleFlags2, Sanitizer, SecurityContext, Self, SimpleChange, SkipSelf, TRANSLATIONS, TRANSLATIONS_FORMAT, TemplateRef, Testability, TestabilityRegistry, TransferState, Type, VERSION, Version, ViewChild, ViewChildren, ViewContainerRef, ViewEncapsulation$1 as ViewEncapsulation, ViewRef, afterNextRender, afterRender, asNativeElements, assertInInjectionContext, assertPlatform, booleanAttribute, computed, createComponent, createEnvironmentInjector, createNgModule, createNgModuleRef, createPlatform, createPlatformFactory, defineInjectable, destroyPlatform, effect, enableProdMode, forwardRef, getDebugNode, getModuleFactory, getNgModuleById, getPlatform, importProvidersFrom, inject, isDevMode, isSignal, isStandalone, makeEnvironmentProviders, makeStateKey, mergeApplicationConfig, numberAttribute, platformCore, provideZoneChangeDetection, reflectComponentType, resolveForwardRef, runInInjectionContext, setTestabilityGetter, signal, untracked, ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, AfterRenderEventManager as ɵAfterRenderEventManager, ComponentFactory$1 as ɵComponentFactory, Console as ɵConsole, DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID, DEFER_BLOCK_DEPENDENCY_INTERCEPTOR as ɵDEFER_BLOCK_DEPENDENCY_INTERCEPTOR, ENABLED_SSR_FEATURES as ɵENABLED_SSR_FEATURES, INJECTOR_SCOPE as ɵINJECTOR_SCOPE, IS_HYDRATION_DOM_REUSE_ENABLED as ɵIS_HYDRATION_DOM_REUSE_ENABLED, InitialRenderPendingTasks as ɵInitialRenderPendingTasks, LContext as ɵLContext, LifecycleHooksFeature as ɵLifecycleHooksFeature, LocaleDataIndex as ɵLocaleDataIndex, NG_COMP_DEF as ɵNG_COMP_DEF, NG_DIR_DEF as ɵNG_DIR_DEF, NG_ELEMENT_ID as ɵNG_ELEMENT_ID, NG_INJ_DEF as ɵNG_INJ_DEF, NG_MOD_DEF as ɵNG_MOD_DEF, NG_PIPE_DEF as ɵNG_PIPE_DEF, NG_PROV_DEF as ɵNG_PROV_DEF, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR, NO_CHANGE as ɵNO_CHANGE, NgModuleFactory as ɵNgModuleFactory, NoopNgZone as ɵNoopNgZone, ReflectionCapabilities as ɵReflectionCapabilities, ComponentFactory as ɵRender3ComponentFactory, ComponentRef as ɵRender3ComponentRef, NgModuleRef as ɵRender3NgModuleRef, RuntimeError as ɵRuntimeError, SSR_CONTENT_INTEGRITY_MARKER as ɵSSR_CONTENT_INTEGRITY_MARKER, TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER, USE_RUNTIME_DEPS_TRACKER_FOR_JIT as ɵUSE_RUNTIME_DEPS_TRACKER_FOR_JIT, ViewRef$1 as ɵViewRef, XSS_SECURITY_URL as ɵXSS_SECURITY_URL, _sanitizeHtml as ɵ_sanitizeHtml, _sanitizeUrl as ɵ_sanitizeUrl, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, annotateForHydration as ɵannotateForHydration, bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, compileNgModuleFactory as ɵcompileNgModuleFactory, compilePipe as ɵcompilePipe, convertToBitFlags as ɵconvertToBitFlags, createInjector as ɵcreateInjector, defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers, depsTracker as ɵdepsTracker, detectChanges as ɵdetectChanges, devModeEqual as ɵdevModeEqual, findLocaleData as ɵfindLocaleData, flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, formatRuntimeError as ɵformatRuntimeError, generateStandaloneInDeclarationsError as ɵgenerateStandaloneInDeclarationsError, getAsyncClassMetadata as ɵgetAsyncClassMetadata, getDebugNode as ɵgetDebugNode, getDirectives as ɵgetDirectives, getHostElement as ɵgetHostElement, getInjectableDef as ɵgetInjectableDef, getLContext as ɵgetLContext, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, getSanitizationBypassType as ɵgetSanitizationBypassType, ɵgetUnknownElementStrictMode, ɵgetUnknownPropertyStrictMode, _global as ɵglobal, injectChangeDetectorRef as ɵinjectChangeDetectorRef, internalCreateApplication as ɵinternalCreateApplication, isBoundToModule as ɵisBoundToModule, isComponentDefPendingResolution as ɵisComponentDefPendingResolution, isEnvironmentProviders as ɵisEnvironmentProviders, isInjectable as ɵisInjectable, isNgModule as ɵisNgModule, isPromise as ɵisPromise, isSubscribable as ɵisSubscribable, noSideEffects as ɵnoSideEffects, patchComponentDefWithScope as ɵpatchComponentDefWithScope, publishDefaultGlobalUtils$1 as ɵpublishDefaultGlobalUtils, publishGlobalUtil as ɵpublishGlobalUtil, registerLocaleData as ɵregisterLocaleData, resetCompiledComponents as ɵresetCompiledComponents, resetJitOptions as ɵresetJitOptions, resolveComponentResources as ɵresolveComponentResources, restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue, setAllowDuplicateNgModuleIdsForTest as ɵsetAllowDuplicateNgModuleIdsForTest, setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl, setClassMetadata as ɵsetClassMetadata, setClassMetadataAsync as ɵsetClassMetadataAsync, setCurrentInjector as ɵsetCurrentInjector, setDocument as ɵsetDocument, setInjectorProfilerContext as ɵsetInjectorProfilerContext, setLocaleId as ɵsetLocaleId, ɵsetUnknownElementStrictMode, ɵsetUnknownPropertyStrictMode, store as ɵstore, stringify as ɵstringify, transitiveScopesFor as ɵtransitiveScopesFor, unregisterAllLocaleData as ɵunregisterLocaleData, unwrapSafeValue as ɵunwrapSafeValue, withDomHydration as ɵwithDomHydration, ɵɵCopyDefinitionFeature, FactoryTarget as ɵɵFactoryTarget, ɵɵHostDirectivesFeature, ɵɵInheritDefinitionFeature, ɵɵInputTransformsFeature, ɵɵNgOnChangesFeature, ɵɵProvidersFeature, ɵɵStandaloneFeature, ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, ɵɵattributeInterpolate3, ɵɵattributeInterpolate4, ɵɵattributeInterpolate5, ɵɵattributeInterpolate6, ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, ɵɵclassMap, ɵɵclassMapInterpolate1, ɵɵclassMapInterpolate2, ɵɵclassMapInterpolate3, ɵɵclassMapInterpolate4, ɵɵclassMapInterpolate5, ɵɵclassMapInterpolate6, ɵɵclassMapInterpolate7, ɵɵclassMapInterpolate8, ɵɵclassMapInterpolateV, ɵɵclassProp, ɵɵcomponentInstance, ɵɵconditional, ɵɵcontentQuery, ɵɵdefer, ɵɵdeferOnHover, ɵɵdeferOnIdle, ɵɵdeferOnImmediate, ɵɵdeferOnInteraction, ɵɵdeferOnTimer, ɵɵdeferOnViewport, ɵɵdeferPrefetchOnHover, ɵɵdeferPrefetchOnIdle, ɵɵdeferPrefetchOnImmediate, ɵɵdeferPrefetchOnInteraction, ɵɵdeferPrefetchOnTimer, ɵɵdeferPrefetchOnViewport, ɵɵdeferPrefetchWhen, ɵɵdeferWhen, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵdefinePipe, ɵɵdirectiveInject, ɵɵdisableBindings, ɵɵelement, ɵɵelementContainer, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵenableBindings, ɵɵgetComponentDepsFactory, ɵɵgetCurrentView, ɵɵgetInheritedFactory, ɵɵhostProperty, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart, ɵɵinject, ɵɵinjectAttribute, ɵɵinvalidFactory, ɵɵinvalidFactoryDep, ɵɵlistener, ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, ɵɵnextContext, ɵɵngDeclareClassMetadata, ɵɵngDeclareComponent, ɵɵngDeclareDirective, ɵɵngDeclareFactory, ɵɵngDeclareInjectable, ɵɵngDeclareInjector, ɵɵngDeclareNgModule, ɵɵngDeclarePipe, ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, ɵɵprojection, ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, ɵɵpropertyInterpolate2, ɵɵpropertyInterpolate3, ɵɵpropertyInterpolate4, ɵɵpropertyInterpolate5, ɵɵpropertyInterpolate6, ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, ɵɵpureFunction0, ɵɵpureFunction1, ɵɵpureFunction2, ɵɵpureFunction3, ɵɵpureFunction4, ɵɵpureFunction5, ɵɵpureFunction6, ɵɵpureFunction7, ɵɵpureFunction8, ɵɵpureFunctionV, ɵɵqueryRefresh, ɵɵreference, registerNgModuleType as ɵɵregisterNgModuleType, ɵɵrepeater, ɵɵrepeaterCreate, ɵɵrepeaterTrackByIdentity, ɵɵrepeaterTrackByIndex, ɵɵresetView, ɵɵresolveBody, ɵɵresolveDocument, ɵɵresolveWindow, ɵɵrestoreView, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵsetComponentScope, ɵɵsetNgModuleScope, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, ɵɵstyleMapInterpolate3, ɵɵstyleMapInterpolate4, ɵɵstyleMapInterpolate5, ɵɵstyleMapInterpolate6, ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, ɵɵstylePropInterpolate3, ɵɵstylePropInterpolate4, ɵɵstylePropInterpolate5, ɵɵstylePropInterpolate6, ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, ɵɵsyntheticHostListener, ɵɵsyntheticHostProperty, ɵɵtemplate, ɵɵtemplateRefExtractor, ɵɵtext, ɵɵtextInterpolate, ɵɵtextInterpolate1, ɵɵtextInterpolate2, ɵɵtextInterpolate3, ɵɵtextInterpolate4, ɵɵtextInterpolate5, ɵɵtextInterpolate6, ɵɵtextInterpolate7, ɵɵtextInterpolate8, ɵɵtextInterpolateV, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, ɵɵvalidateIframeAttribute, ɵɵviewQuery };
32651
32813
  //# sourceMappingURL=core.mjs.map